struct bufarea * getfilentry(uint32_t block, int len) { struct bufarea *bp; struct file_entry *fp; int err; if (len > fsbsize) { (void) printf(gettext("File entry at %x is too long " "(%d bytes)\n"), block, len); len = fsbsize; } bp = getdatablk((daddr_t)(block + part_start), fsbsize); if (bp->b_errs) { bp->b_flags &= ~B_INUSE; return (NULL); } /* LINTED */ fp = (struct file_entry *)bp->b_un.b_buf; err = verifytag(&fp->fe_tag, block, &fp->fe_tag, UD_FILE_ENTRY); if (err) { (void) printf(gettext("Tag error %s or bad file entry, " "tag=%d\n"), tagerrs[err], fp->fe_tag.tag_id); bp->b_flags &= ~B_INUSE; return (NULL); } return (bp); }
/* * Scan each entry in an ea block. */ int eascan(struct inodesc *idesc, struct ufs2_dinode *dp) { #if 1 return (0); #else struct bufarea *bp; u_int dsize, n; u_char *cp; long blksiz; char dbuf[DIRBLKSIZ]; printf("Inode %ju extsize %ju\n", (intmax_t)idesc->id_number, (intmax_t)dp->di_extsize); if (dp->di_extsize == 0) return 0; if (dp->di_extsize <= sblock.fs_fsize) blksiz = sblock.fs_fsize; else blksiz = sblock.fs_bsize; printf("blksiz = %ju\n", (intmax_t)blksiz); bp = getdatablk(dp->di_extb[0], blksiz); cp = (u_char *)bp->b_un.b_buf; for (n = 0; n < blksiz; n++) { printf("%02x", cp[n]); if ((n & 31) == 31) printf("\n"); } return (STOP); #endif }
/* * Get a directory block. * Insure that it is held until another is requested. */ static struct bufarea * getdirblk(ufs2_daddr_t blkno, long size) { if (pdirbp != 0) pdirbp->b_flags &= ~B_INUSE; pdirbp = getdatablk(blkno, size, BT_DIRDATA); return (pdirbp); }
/* * Recursively print a list of indirect blocks. */ static void printindir(ufs2_daddr_t blk, int level, char *bufp) { struct bufarea buf, *bp; char tempbuf[32]; /* enough to print an ufs2_daddr_t */ int i, j, cpl, charssofar; ufs2_daddr_t blkno; if (blk == 0) return; printf("%jd (%d) =>\n", (intmax_t)blk, level); if (level == 0) { /* for the final indirect level, don't use the cache */ bp = &buf; bp->b_un.b_buf = bufp; bp->b_prev = bp->b_next = bp; initbarea(bp); getblk(bp, blk, sblock.fs_bsize); } else bp = getdatablk(blk, sblock.fs_bsize); cpl = charsperline(); for (i = charssofar = 0; i < NINDIR(&sblock); i++) { if (sblock.fs_magic == FS_UFS1_MAGIC) blkno = bp->b_un.b_indir1[i]; else blkno = bp->b_un.b_indir2[i]; if (blkno == 0) continue; j = sprintf(tempbuf, "%jd", (intmax_t)blkno); if (level == 0) { charssofar += j; if (charssofar >= cpl - 2) { putchar('\n'); charssofar = j; } } fputs(tempbuf, stdout); if (level == 0) { printf(", "); charssofar += 2; } else { printf(" =>\n"); printindir(blkno, level - 1, bufp); printf("\n"); charssofar = 0; } } if (level == 0) putchar('\n'); return; }
/* * Recursively print a list of indirect blocks. */ static int printindir(ufs_daddr_t blk, int level, char *bufp) { struct bufarea buf, *bp; char tempbuf[32]; /* enough to print an ufs_daddr_t */ int i, j, cpl, charssofar; ufs_daddr_t blkno; if (level == 0) { /* for the final indirect level, don't use the cache */ bp = &buf; bp->b_un.b_buf = bufp; bp->b_prev = bp->b_next = bp; initbarea(bp); getblk(bp, blk, sblock.fs_bsize); } else bp = getdatablk(blk, sblock.fs_bsize); cpl = charsperline(); for (i = charssofar = 0; i < NINDIR(&sblock); i++) { blkno = bp->b_un.b_indir[i]; if (blkno == 0) { if (level == 0) putchar('\n'); return 0; } j = sprintf(tempbuf, "%d", blkno); if (level == 0) { charssofar += j; if (charssofar >= cpl - 2) { putchar('\n'); charssofar = j; } } fputs(tempbuf, stdout); if (level == 0) { printf(", "); charssofar += 2; } else { printf(" =>\n"); if (printindir(blkno, level - 1, bufp) == 0) return 0; } } if (level == 0) putchar('\n'); return 1; }
/* * General purpose interface for reading inodes. */ struct ufs1_dinode * ginode(ufs1_ino_t inumber) { ufs_daddr_t iblk; if (inumber < ROOTINO || inumber > maxino) errx(EEXIT, "bad inode number %d to ginode", inumber); if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { iblk = ino_to_fsba(&sblock, inumber); if (pbp != 0) pbp->b_flags &= ~B_INUSE; pbp = getdatablk(iblk, sblock.fs_bsize); startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); } return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); }
/* * General purpose interface for reading inodes. */ union dinode * ginode(ino_t inumber) { ufs2_daddr_t iblk; if (inumber < ROOTINO || inumber > maxino) errx(EEXIT, "bad inode number %ju to ginode", (uintmax_t)inumber); if (startinum == 0 || inumber < startinum || inumber >= startinum + INOPB(&sblock)) { iblk = ino_to_fsba(&sblock, inumber); if (pbp != NULL) pbp->b_flags &= ~B_INUSE; pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES); startinum = rounddown(inumber, INOPB(&sblock)); } if (sblock.fs_magic == FS_UFS1_MAGIC) return ((union dinode *) &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]); return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]); }
static int iblock(struct inodesc *idesc, long ilevel, quad_t isize) { ufs_daddr_t *ap; ufs_daddr_t *aplim; struct bufarea *bp; int i, n, (*func)(), nif; quad_t sizepb; char buf[BUFSIZ]; char pathbuf[MAXPATHLEN + 1]; struct ufs1_dinode *dp; if (idesc->id_type == ADDR) { func = idesc->id_func; if (((n = (*func)(idesc)) & KEEPON) == 0) return (n); } else func = dirscan; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) return (SKIP); bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); ilevel--; for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) sizepb *= NINDIR(&sblock); nif = howmany(isize , sizepb); if (nif > NINDIR(&sblock)) nif = NINDIR(&sblock); if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { if (*ap == 0) continue; sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", (u_long)idesc->id_number); if (dofix(idesc, buf)) { *ap = 0; dirty(bp); } } flush(fswritefd, bp); } aplim = &bp->b_un.b_indir[nif]; for (ap = bp->b_un.b_indir; ap < aplim; ap++) { if (*ap) { idesc->id_blkno = *ap; if (ilevel == 0) n = (*func)(idesc); else n = iblock(idesc, ilevel, isize); if (n & STOP) { bp->b_flags &= ~B_INUSE; return (n); } } else { if (idesc->id_type == DATA && isize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); dp->di_size -= isize; isize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); bp->b_flags &= ~B_INUSE; return(STOP); } } } isize -= sizepb; } bp->b_flags &= ~B_INUSE; return (KEEPON); }
static int iblock(struct inodesc *idesc, long ilevel, off_t isize, int type) { struct bufarea *bp; int i, n, (*func)(struct inodesc *), nif; off_t sizepb; char buf[BUFSIZ]; char pathbuf[MAXPATHLEN + 1]; union dinode *dp; if (idesc->id_type != DATA) { func = idesc->id_func; if (((n = (*func)(idesc)) & KEEPON) == 0) return (n); } else func = dirscan; if (chkrange(idesc->id_blkno, idesc->id_numfrags)) return (SKIP); bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type); ilevel--; for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) sizepb *= NINDIR(&sblock); if (howmany(isize, sizepb) > NINDIR(&sblock)) nif = NINDIR(&sblock); else nif = howmany(isize, sizepb); if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { for (i = nif; i < NINDIR(&sblock); i++) { if (IBLK(bp, i) == 0) continue; (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", (u_long)idesc->id_number); if (preen) { pfatal("%s", buf); } else if (dofix(idesc, buf)) { IBLK_SET(bp, i, 0); dirty(bp); } } flush(fswritefd, bp); } for (i = 0; i < nif; i++) { if (ilevel == 0) idesc->id_lbn++; if (IBLK(bp, i)) { idesc->id_blkno = IBLK(bp, i); if (ilevel == 0) n = (*func)(idesc); else n = iblock(idesc, ilevel, isize, type); if (n & STOP) { bp->b_flags &= ~B_INUSE; return (n); } } else { if (idesc->id_type == DATA && isize > 0) { /* An empty block in a directory XXX */ getpathname(pathbuf, idesc->id_number, idesc->id_number); pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); DIP_SET(dp, di_size, DIP(dp, di_size) - isize); isize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); rerun = 1; inodirty(); bp->b_flags &= ~B_INUSE; return(STOP); } } } isize -= sizepb; } bp->b_flags &= ~B_INUSE; return (KEEPON); }
void pass5(void) { int c; struct m_ext2fs *fs = &sblock; daddr_t dbase, dmax; daddr_t d; long i, j; struct inodesc idesc[3]; struct bufarea *ino_bitmap = NULL, *blk_bitmap = NULL; char *ibmap, *bbmap; u_int32_t cs_ndir, cs_nbfree, cs_nifree; char msg[255]; cs_ndir = 0; cs_nbfree = 0; cs_nifree = 0; ibmap = malloc(fs->e2fs_bsize); bbmap = malloc(fs->e2fs_bsize); if (ibmap == NULL || bbmap == NULL) { errexit("out of memory\n"); } for (c = 0; c < fs->e2fs_ncg; c++) { u_int32_t nbfree = 0; u_int32_t nifree = 0; u_int32_t ndirs = 0; nbfree = 0; nifree = fs->e2fs.e2fs_ipg; ndirs = 0; if (blk_bitmap == NULL) { blk_bitmap = getdatablk(fs2h32(fs->e2fs_gd[c].ext2bgd_b_bitmap), fs->e2fs_bsize); } else { getblk(blk_bitmap, fs2h32(fs->e2fs_gd[c].ext2bgd_b_bitmap), fs->e2fs_bsize); } if (ino_bitmap == NULL) { ino_bitmap = getdatablk(fs2h32(fs->e2fs_gd[c].ext2bgd_i_bitmap), fs->e2fs_bsize); } else { getblk(ino_bitmap, fs2h32(fs->e2fs_gd[c].ext2bgd_i_bitmap), fs->e2fs_bsize); } memset(bbmap, 0, fs->e2fs_bsize); memset(ibmap, 0, fs->e2fs_bsize); memset(&idesc[0], 0, sizeof idesc); for (i = 0; i < 3; i++) { idesc[i].id_type = ADDR; } j = fs->e2fs.e2fs_ipg * c + 1; for (i = 0; i < fs->e2fs.e2fs_ipg; j++, i++) { if ((j < EXT2_FIRSTINO) && (j != EXT2_ROOTINO)) { setbit(ibmap, i); nifree--; continue; } if (j > fs->e2fs.e2fs_icount) { setbit(ibmap, i); continue; } switch (statemap[j]) { case USTATE: break; case DSTATE: case DCLEAR: case DFOUND: ndirs++; /* fall through */ case FSTATE: case FCLEAR: nifree--; setbit(ibmap, i); break; default: errexit("BAD STATE %d FOR INODE I=%ld\n", statemap[j], j); } } /* fill in unused par of the inode map */ for (i = fs->e2fs.e2fs_ipg / NBBY; i < fs->e2fs_bsize; i++) ibmap[i] = 0xff; dbase = c * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock; dmax = (c+1) * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock; for (i = 0, d = dbase; d < dmax; d ++, i ++) { if (testbmap(d) || d >= sblock.e2fs.e2fs_bcount) { setbit(bbmap, i); continue; } else { nbfree++; } } cs_nbfree += nbfree; cs_nifree += nifree; cs_ndir += ndirs; if (debug && (fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree || fs2h16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree || fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs)) { printf("summary info for cg %d is %d, %d, %d," "should be %d, %d, %d\n", c, fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree), fs2h16(fs->e2fs_gd[c].ext2bgd_nifree), fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs), nbfree, nifree, ndirs); } (void)snprintf(msg, sizeof(msg), "SUMMARY INFORMATIONS WRONG FOR CG #%d", c); if ((fs2h16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree || fs2h16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree || fs2h16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs) && dofix(&idesc[0], msg)) { fs->e2fs_gd[c].ext2bgd_nbfree = h2fs16(nbfree); fs->e2fs_gd[c].ext2bgd_nifree = h2fs16(nifree); fs->e2fs_gd[c].ext2bgd_ndirs = h2fs16(ndirs); sbdirty(); } if (debug && memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize)) { printf("blk_bitmap:\n"); print_bmap(blk_bitmap->b_un.b_buf, fs->e2fs_bsize); printf("bbmap:\n"); print_bmap(bbmap, fs->e2fs_bsize); } (void)snprintf(msg, sizeof(msg), "BLK(S) MISSING IN BIT MAPS #%d", c); if (memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize) && dofix(&idesc[1], msg)) { memcpy(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize); dirty(blk_bitmap); } if (debug && memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize)) { printf("ino_bitmap:\n"); print_bmap(ino_bitmap->b_un.b_buf, fs->e2fs_bsize); printf("ibmap:\n"); print_bmap(ibmap, fs->e2fs_bsize); } (void)snprintf(msg, sizeof(msg), "INODE(S) MISSING IN BIT MAPS #%d", c); if (memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize) && dofix(&idesc[1], msg)) { memcpy(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize); dirty(ino_bitmap); } } if (debug && (fs->e2fs.e2fs_fbcount != cs_nbfree || fs->e2fs.e2fs_ficount != cs_nifree)) { printf("summary info bad in superblock: %d, %d should be %d, %d\n", fs->e2fs.e2fs_fbcount, fs->e2fs.e2fs_ficount, cs_nbfree, cs_nifree); } if ((fs->e2fs.e2fs_fbcount != cs_nbfree || fs->e2fs.e2fs_ficount != cs_nifree) && dofix(&idesc[0], "SUPERBLK SUMMARY INFORMATION BAD")) { fs->e2fs.e2fs_fbcount = cs_nbfree; fs->e2fs.e2fs_ficount = cs_nifree; sbdirty(); } free(ibmap); free(bbmap); }