#ifndef lint static char sccsID[] = "@(#)getfree.c 1.3 90/10/25 22:05:42"; #endif /* Read data from BSD filesystem free blocks Copyright (c) 1988, 1990 Timothy R. Eliseo. All rights reserved. Permission is granted to use but not to sell this software provided that the above message is not removed and that any modification is noted. */ #include #include #include #include /* on some systems */ #include #include #ifndef offsetof /* ANSI C would define this in */ #define offsetof(s_name, m_name) (size_t)&(((s_name *)0)->m_name) #endif main(argc, argv) char *argv[]; { int fsfd; /* file descriptor of the filesystem */ struct fs fs; /* filesystem header (superblock) */ struct cg cg; /* cylinder group header */ u_char *freelist, /* pointer to cg free list */ *dp; static u_char data[MAXBSIZE]; /* a block of data */ if (argc < 2) { fprintf(stderr, "Usage: %s ...\n", argv[0]); exit(1); } /* open the filesystem */ if ((fsfd = open(argv[1], O_RDONLY)) < 0) { perror(argv[1]); exit(2); } /* read the superblock */ lseek(fsfd, SBLOCK * DEV_BSIZE, L_SET); read(fsfd, &fs, sizeof fs); if (fs.fs_magic != FS_MAGIC) { fprintf(stderr, "Invalid magic number %lx in superblock\n", fs.fs_magic); exit(3); } /* allocate a buffer for the maximum size of a cylinder group free list */ freelist = (u_char *)malloc(fs.fs_bsize - offsetof(struct cg, cg_free[0])); argc--; /* past the program name */ argv++; /* loop for each cylinder group # on the command line */ while (--argc) { int cgn; long cgs, frn; cgn = atoi(*++argv); /* cylinder group number */ cgs = cgbase(&fs, cgn); /* the base of the cylinder group in frags */ /* read the cg header */ lseek(fsfd, (long)cgtod(&fs, cgn) << fs.fs_fshift, L_SET); read(fsfd, &cg, offsetof(struct cg, cg_free[0])); if (cg.cg_magic != CG_MAGIC) { fprintf(stderr, "Invalid magic number %lx in cylinder group %d\n", cg.cg_magic, cgn); exit(3); } /* read the free list, located right after the fixed size header info */ read(fsfd, freelist, (cg.cg_ndblk + 7) / 8); /* loop for each free block */ for (frn = 0; frn < cg.cg_ndblk; frn++) { if (freelist[frn / NBBY] >> frn % NBBY & 1) { /* block free? */ /* read the block's data */ lseek(fsfd, (long)(cgs + frn) << fs.fs_fshift, L_SET); read(fsfd, data, fs.fs_fsize); /* write the data only if it's not filled with a repeated byte */ for (dp = data + 1; dp < data + fs.fs_fsize; dp++) if (data[0] != *dp) break; if (dp != data + fs.fs_fsize) write(1, data, fs.fs_fsize); } /* if free */ } /* for each block */ } /* for each cg */ return 0; }