From d6903eccf9c0aa567962fe7ec6ec9972fcf92944 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Mon, 1 Oct 2001 15:38:14 -0600 Subject: [PATCH] Update findsuper to support > 2GB device sizes. Add extra validity checks over just ext2 magic detection. Add progress meter. --- misc/findsuper.c | 128 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 93 insertions(+), 35 deletions(-) diff --git a/misc/findsuper.c b/misc/findsuper.c index 35bf9b9..f1e2315 100644 --- a/misc/findsuper.c +++ b/misc/findsuper.c @@ -30,8 +30,6 @@ * as far as I can tell, so the date is more interesting IMHO and certainly * marks which superblocks are backup ones. * - * This still doesn't handle disks >2G. - * * I wanted to add msdos support, but I couldn't make heads or tails * of the kernel include files to find anything I could look for in msdos. * @@ -54,23 +52,30 @@ * Steve * ssd@nevets.oau.org * ssd@mae.engr.ucf.edu - * + * + * Additional notes by Andreas Dilger : + * - fixed to support > 2G devices by using lseek64 + * - add reliability checking for the superblock to avoid random garbage + * - add adaptive progress meter + * + * It _should_ also handle signals and tell you the ending block, so + * that you can resume at a later time, but it doesn't yet... + * + * Note that gpart does not appear to find all superblocks that aren't aligned + * with the start of a possible partition, so it is not useful in systems + * with LVM or similar setups which don't use fat partition alignment. */ /* * Documentation addendum added by Andreas dwguest@win.tue.nl/aeb@cwi.nl * * The program findsuper is a utility that scans a disk and finds - * copies of ext2 superblocks (by checking for the ext2 signature; it - * will occasionally find other blocks that by coincidence have this - * signature - often these can be recognised by their ridiculous - * dates). + * copies of ext2 superblocks (by checking for the ext2 signature * * For each superblock found, it prints the offset in bytes, the - * offset in 1024-byte blocks, the size of ext2 partition in 1024-byte - * blocks, the filesystem blocksize (given as log(blocksize)-10, so - * that 0 means 1024), the block group number (0 for older ext2 - * systems), and a timestamp (s_mtime). + * offset in 1024-byte blocks, the size of ext2 partition in fs + * blocks, the filesystem blocksize (in bytes), the block group number + * (always 0 for older ext2 systems), and a timestamp (s_mtime). * * This program can be used to retrieve partitions that have been * lost. The superblock for block group 0 is found 1 block (2 @@ -85,23 +90,35 @@ * */ +#define _FILE_OFFSET_BITS 64 #include #include +#include +#include +#include +#include #include #include "ext2fs/ext2_fs.h" #include "nls-enable.h" +#undef DEBUG + +#ifdef DEBUG +#define WHY(fmt, arg...) { printf("\r%Ld: " fmt, sk, ##arg) ; continue; } +#else +#define WHY(fmt, arg...) { continue; } +#endif -main(int argc, char *argv[]) +int main(int argc, char *argv[]) { - int i; int skiprate=512; /* one sector */ - long sk=0; /* limited to 2G filesystems!! */ - FILE *f; + loff_t sk=0, skl=0; + int fd; char *s; - time_t tm; + time_t tm, last = time(0); + loff_t interval = 1024 * 1024; struct ext2_super_block ext2; /* interesting fields: EXT2_SUPER_MAGIC @@ -114,45 +131,86 @@ main(int argc, char *argv[]) #endif if (argc<2) { fprintf(stderr, - _("Usage: findsuper device [skiprate [start]]\n")); + _("Usage: findsuper device [skipbytes [startkb]]\n")); exit(1); } if (argc>2) - skiprate=atoi(argv[2]); - if (skiprate<512) { + skiprate = strtol(argv[2], &s, 0); + if (s == argv[2]) { + fprintf(stderr,_("skiprate should be a number, not %s\n"), s); + exit(1); + } + if (skiprate & 0x1ff) { fprintf(stderr, - _("Do you really want to skip less than a sector??\n")); + _("skipbytes must be a multiple of the sector size\n")); exit(2); } if (argc>3) - sk=atol(argv[3]); - if (sk<0) { - fprintf(stderr,_("Have to start at 0 or greater,not %ld\n"),sk); + sk = skl = strtoll(argv[3], &s, 0) << 10; + if (s == argv[3]) { + fprintf(stderr,_("startkb should be a number, not %s\n"), s); + exit(1); + } + if (sk < 0) { + fprintf(stderr,_("startkb should be positive, not %Ld\n"), sk); exit(1); } - f=fopen(argv[1],"r"); - if (!f) { + fd = open(argv[1], O_RDONLY); + if (fd < 0) { perror(argv[1]); exit(1); } /* Now, go looking for the superblock ! */ - printf(" thisoff block fs_blk_sz blksz grp last_mount\n"); - for (;!feof(f) && (i=fseek(f,sk,SEEK_SET))!= -1; sk+=skiprate){ - if (i=fread(&ext2,sizeof(ext2),1, f)!=1) { - perror(_("read failed")); + printf(_("starting at %Ld, with %d byte increments\n"), sk, skiprate); + printf(_(" thisoff block fs_blk_sz blksz grp last_mount\n")); + for (; lseek64(fd, sk, SEEK_SET) != -1 && + read(fd, &ext2, 512) == 512; sk += skiprate) { + + if (sk && !(sk & (interval - 1))) { + time_t now, diff; + + now = time(0); + diff = now - last; + + if (diff > 0) { + s = ctime(&now); + s[24] = 0; + printf("\r%14Ld: %8LdkB/s @ %s", sk, + (((sk - skl)) / diff) >> 10, s); + fflush(stdout); + } + if (diff < 5) + interval <<= 1; + else if (diff > 20) + interval >>= 1; + last = now; + skl = sk; } if (ext2.s_magic != EXT2_SUPER_MAGIC) continue; - + if (ext2.s_log_block_size > 4) + WHY("log block size > 4 (%d)\n", ext2.s_log_block_size); + if (ext2.s_r_blocks_count > ext2.s_blocks_count) + WHY("r_blocks_count > blocks_count (%d > %d)\n", + ext2.s_r_blocks_count, ext2.s_blocks_count); + if (ext2.s_free_blocks_count > ext2.s_blocks_count) + WHY("free_blocks_count > blocks_count\n (%d > %d)\n", + ext2.s_free_blocks_count, ext2.s_blocks_count); + if (ext2.s_free_inodes_count > ext2.s_inodes_count) + WHY("free_inodes_count > inodes_count (%d > %d)\n", + ext2.s_free_inodes_count, ext2.s_inodes_count); + tm = ext2.s_mtime; s=ctime(&tm); s[24]=0; - printf("%9ld %9ld %9ld %5ld %4d %s\n", sk, - sk/1024, ext2.s_blocks_count, - ext2.s_log_block_size, + printf("\r%14Ld %9Ld %9d %5d %4d %s\n", + sk, sk >> 10, ext2.s_blocks_count, + 1 << (ext2.s_log_block_size + 10), ext2.s_block_group_nr, s); } - printf(_("Failed on %d at %ld\n"), i, sk); - fclose(f); + printf(_("\n%14Ld: finished with errno %d\n"), sk, errno); + close(fd); + + return errno; } -- 1.8.3.1