void clri(struct inodesc *idesc, const char *type, int flag) { union dinode *dp; dp = ginode(idesc->id_number); if (flag == 1) { pwarn("%s %s", type, (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"); pinode(idesc->id_number); } if (preen || reply("CLEAR") == 1) { if (preen) printf(" (CLEARED)\n"); n_files--; if (bkgrdflag == 0) { (void)ckinode(dp, idesc); inoinfo(idesc->id_number)->ino_state = USTATE; clearinode(dp); inodirty(); } else { cmd.value = idesc->id_number; cmd.size = -DIP(dp, di_nlink); if (debug) printf("adjrefcnt ino %ld amt %lld\n", (long)cmd.value, (long long)cmd.size); if (sysctl(adjrefcnt, MIBSIZE, 0, 0, &cmd, sizeof cmd) == -1) rwerror("ADJUST INODE", cmd.value); } } }
/* * deallocate an inode */ void freeino(ufs1_ino_t ino) { struct inodesc idesc; struct ufs1_dinode *dp; memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = ADDR; idesc.id_func = pass4check; idesc.id_number = ino; dp = ginode(ino); ckinode(dp, &idesc); clearinode(dp); inodirty(); inoinfo(ino)->ino_state = USTATE; n_files--; }
/* * deallocate an inode */ void freeino(ino_t ino) { struct inodesc idesc; struct uvnode *vp; memset(&idesc, 0, sizeof(struct inodesc)); idesc.id_type = ADDR; idesc.id_func = pass4check; idesc.id_number = ino; vp = vget(fs, ino); (void) ckinode(VTOD(vp), &idesc); clearinode(ino); statemap[ino] = USTATE; vnode_destroy(vp); n_files--; }
void clri(struct inodesc *idesc, char *type, int flag) { struct ufs1_dinode *dp; dp = ginode(idesc->id_number); if (flag == 1) { pwarn("%s %s", type, (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); pinode(idesc->id_number); } if (preen || reply("CLEAR") == 1) { if (preen) printf(" (CLEARED)\n"); n_files--; ckinode(dp, idesc); clearinode(dp); inoinfo(idesc->id_number)->ino_state = USTATE; inodirty(); } }
void clri(struct inodesc * idesc, const char *type, int flag) { struct uvnode *vp; vp = vget(fs, idesc->id_number); if (flag & 0x1) { pwarn("%s %s", type, (VTOI(vp)->i_ffs1_mode & IFMT) == IFDIR ? "DIR" : "FILE"); pinode(idesc->id_number); } if ((flag & 0x2) || preen || reply("CLEAR") == 1) { if (preen && flag != 2) printf(" (CLEARED)\n"); n_files--; (void) ckinode(VTOD(vp), idesc); clearinode(idesc->id_number); statemap[idesc->id_number] = USTATE; vnode_destroy(vp); return; } return; }
/* * Perform checks on an inode and setup/track the state of the inode * in maps (statemap[], lncntp[]) for future reference and validation. * Initiate the calls to ckinode and in turn pass1check() to handle * further validation. */ static void verify_inode(fsck_ino_t inumber, struct inodesc *idesc, fsck_ino_t maxinumber) { int j, clear, flags; int isdir; char *err; fsck_ino_t shadow, attrinode; daddr32_t ndb; struct dinode *dp; struct inoinfo *iip; dp = getnextinode(inumber); if ((dp->di_mode & IFMT) == 0) { /* mode and type of file is not set */ if ((memcmp((void *)dp->di_db, (void *)zino.di_db, NDADDR * sizeof (daddr32_t)) != 0) || (memcmp((void *)dp->di_ib, (void *)zino.di_ib, NIADDR * sizeof (daddr32_t)) != 0) || (dp->di_mode != 0) || (dp->di_size != 0)) { pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber); if (reply("CLEAR") == 1) { dp = ginode(inumber); clearinode(dp); inodirty(); } else { iscorrupt = 1; } } statemap[inumber] = USTATE; return; } isdir = ((dp->di_mode & IFMT) == IFDIR) || ((dp->di_mode & IFMT) == IFATTRDIR); lastino = inumber; if (dp->di_size > (u_offset_t)UFS_MAXOFFSET_T) { pfatal("NEGATIVE SIZE %lld I=%d", (longlong_t)dp->di_size, inumber); goto bogus; } /* * A more precise test of the type is done later on. Just get * rid of the blatantly-wrong ones before we do any * significant work. */ if ((dp->di_mode & IFMT) == IFMT) { pfatal("BAD MODE 0%o I=%d", dp->di_mode & IFMT, inumber); if (reply("BAD MODE: MAKE IT A FILE") == 1) { statemap[inumber] = FSTATE; dp = ginode(inumber); dp->di_mode = IFREG | 0600; inodirty(); truncino(inumber, sblock.fs_fsize, TI_NOPARENT); dp = getnextrefresh(); } else { iscorrupt = 1; } } ndb = howmany(dp->di_size, (u_offset_t)sblock.fs_bsize); if (ndb < 0) { /* extra space to distinguish from previous pfatal() */ pfatal("NEGATIVE SIZE %lld I=%d", (longlong_t)dp->di_size, inumber); goto bogus; } if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR) { if (dp->di_size != 0) { pfatal("SPECIAL FILE WITH NON-ZERO LENGTH %lld I=%d", (longlong_t)dp->di_size, inumber); goto bogus; } for (j = 0; j < NDADDR; j++) { /* * It's a device, so all the block pointers * should be zero except for di_ordev. * di_ordev is overlayed on the block array, * but where varies between big and little * endian, so make sure that the only non-zero * element is the correct one. There can be * a device whose ordev is zero, so we can't * check for the reverse. */ if (dp->di_db[j] != 0 && &dp->di_db[j] != &dp->di_ordev) { if (debug) { (void) printf( "spec file di_db[%d] has %d\n", j, dp->di_db[j]); } pfatal( "SPECIAL FILE WITH NON-ZERO FRAGMENT LIST I=%d", inumber); goto bogus; } } for (j = 0; j < NIADDR; j++) { if (dp->di_ib[j] != 0) { if (debug) (void) printf( "special has %d at ib[%d]\n", dp->di_ib[j], j); pfatal( "SPECIAL FILE WITH NON-ZERO FRAGMENT LIST I=%d", inumber); goto bogus; } } } else { /* * This assignment is mostly here to appease lint, but * doesn't hurt. */ err = "Internal error: unexpected variant of having " "blocks past end of file I=%d"; clear = 0; /* * If it's not a device, it has to follow the * rules for files. In particular, no blocks after * the last one that di_size says is in use. */ for (j = ndb; j < NDADDR; j++) { if (dp->di_db[j] != 0) { if (debug) { (void) printf("bad file direct " "addr[%d]: block 0x%x " "format: 0%o\n", j, dp->di_db[j], dp->di_mode & IFMT); } err = "FILE WITH FRAGMENTS PAST END I=%d"; clear = 1; break; } } /* * Find last indirect pointer that should be in use, * and make sure any after it are clear. */ if (!clear) { for (j = 0, ndb -= NDADDR; ndb > 0; j++) { ndb /= NINDIR(&sblock); } for (; j < NIADDR; j++) { if (dp->di_ib[j] != 0) { if (debug) { (void) printf("bad file " "indirect addr: block %d\n", dp->di_ib[j]); } err = "FILE WITH FRAGMENTS PAST END I=%d"; clear = 2; break; } } } if (clear) { /* * The discarded blocks will be garbage- * collected in pass5. If we're told not to * discard them, it's just lost blocks, which * isn't worth setting iscorrupt for. */ pwarn(err, inumber); if (preen || reply("DISCARD EXCESS FRAGMENTS") == 1) { dp = ginode(inumber); if (clear == 1) { for (; j < NDADDR; j++) dp->di_db[j] = 0; j = 0; } for (; j < NIADDR; j++) dp->di_ib[j] = 0; inodirty(); dp = getnextrefresh(); if (preen) (void) printf(" (TRUNCATED)"); } } } if (ftypeok(dp) == 0) { pfatal("UNKNOWN FILE TYPE 0%o I=%d", dp->di_mode, inumber); goto bogus; } n_files++; TRACK_LNCNTP(inumber, lncntp[inumber] = dp->di_nlink); /* * We can't do anything about it right now, so note that its * processing is being delayed. Otherwise, we'd be changing * the block allocations out from under ourselves, which causes * no end of confusion. */ flags = statemap[inumber] & INDELAYD; /* * if errorlocked or logging, then open deleted files will * manifest as di_nlink <= 0 and di_mode != 0 * so skip them; they're ok. * Also skip anything already marked to be cleared. */ if (dp->di_nlink <= 0 && !((errorlocked || islog) && dp->di_mode == 0) && !(flags & INCLEAR)) { flags |= INZLINK; if (debug) (void) printf( "marking i=%d INZLINK; nlink %d, mode 0%o, islog %d\n", inumber, dp->di_nlink, dp->di_mode, islog); } switch (dp->di_mode & IFMT) { case IFDIR: case IFATTRDIR: if (dp->di_size == 0) { /* * INCLEAR means it will be ignored by passes 2 & 3. */ if ((dp->di_mode & IFMT) == IFDIR) (void) printf("ZERO-LENGTH DIR I=%d\n", inumber); else (void) printf("ZERO-LENGTH ATTRDIR I=%d\n", inumber); add_orphan_dir(inumber); flags |= INCLEAR; flags &= ~INZLINK; /* It will be cleared anyway */ } statemap[inumber] = DSTATE | flags; cacheino(dp, inumber); countdirs++; break; case IFSHAD: if (dp->di_size == 0) { (void) printf("ZERO-LENGTH SHADOW I=%d\n", inumber); flags |= INCLEAR; flags &= ~INZLINK; /* It will be cleared anyway */ } statemap[inumber] = SSTATE | flags; cacheacl(dp, inumber); break; default: statemap[inumber] = FSTATE | flags; } badblk = 0; dupblk = 0; idesc->id_number = inumber; idesc->id_fix = DONTKNOW; if (dp->di_size > (u_offset_t)MAXOFF_T) { largefile_count++; } (void) ckinode(dp, idesc, CKI_TRAVERSE); if (isdir && (idesc->id_firsthole >= 0)) check_dirholes(inumber, idesc); if (dp->di_blocks != idesc->id_entryno) { /* * The kernel releases any blocks it finds in the lists, * ignoring the block count itself. So, a bad count is * not grounds for setting iscorrupt. */ pwarn("INCORRECT DISK BLOCK COUNT I=%u (%d should be %d)", inumber, (uint32_t)dp->di_blocks, idesc->id_entryno); if (!preen && (reply("CORRECT") == 0)) return; dp = ginode(inumber); dp->di_blocks = idesc->id_entryno; iip = getinoinfo(inumber); if (iip != NULL) iip->i_isize = dp->di_size; inodirty(); if (preen) (void) printf(" (CORRECTED)\n"); } if (isdir && (dp->di_blocks == 0)) { /* * INCLEAR will cause passes 2 and 3 to skip it. */ (void) printf("DIR WITH ZERO BLOCKS I=%d\n", inumber); statemap[inumber] = DCLEAR; add_orphan_dir(inumber); } /* * Check that the ACL is on a valid file type */ shadow = dp->di_shadow; if (shadow != 0) { if (acltypeok(dp) == 0) { clear_attr_acl(inumber, -1, "NON-ZERO ACL REFERENCE, I=%d\n"); } else if ((shadow <= UFSROOTINO) || (shadow > maxinumber)) { clear_attr_acl(inumber, -1, "BAD ACL REFERENCE I=%d\n"); } else { registershadowclient(shadow, inumber, &shadowclientinfo); } } attrinode = dp->di_oeftflag; if (attrinode != 0) { if ((attrinode <= UFSROOTINO) || (attrinode > maxinumber)) { clear_attr_acl(attrinode, inumber, "BAD ATTRIBUTE REFERENCE TO I=%d FROM I=%d\n"); } else { dp = ginode(attrinode); if ((dp->di_mode & IFMT) != IFATTRDIR) { clear_attr_acl(attrinode, inumber, "BAD ATTRIBUTE DIR REF TO I=%d FROM I=%d\n"); } else if (dp->di_size == 0) { clear_attr_acl(attrinode, inumber, "REFERENCE TO ZERO-LENGTH ATTRIBUTE DIR I=%d from I=%d\n"); } else { registershadowclient(attrinode, inumber, &attrclientinfo); } } } return; /* * If we got here, we've not had the chance to see if a * directory has holes, but we know the directory's bad, * so it's safe to always return false (no holes found). * * Also, a pfatal() is always done before jumping here, so * we know we're not in preen mode. */ bogus: if (isdir) { /* * INCLEAR makes passes 2 & 3 skip it. */ statemap[inumber] = DCLEAR; add_orphan_dir(inumber); cacheino(dp, inumber); } else { statemap[inumber] = FCLEAR; } if (reply("CLEAR") == 1) { (void) tdelete((void *)inumber, &limbo_dirs, ino_t_cmp); freeino(inumber, TI_PARENT); inodirty(); } else { iscorrupt = 1; } }