Esempio n. 1
0
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);
		}
	}
}
Esempio n. 2
0
/*
 * 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--;
}
Esempio n. 3
0
/*
 * 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--;
}
Esempio n. 4
0
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();
	}
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
/*
 * 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;
	}
}