Ejemplo n.º 1
0
Archivo: pass1.c Proyecto: cse451/os161
/*
 * Check the directory entry in SFD. INDEX is its offset, and PATH is
 * its name; these are used for printing messages.
 */
static
int
pass1_direntry(const char *path, uint32_t index, struct sfs_dir *sfd)
{
	int dchanged = 0;
	uint32_t nblocks;

	nblocks = sb_totalblocks();

	if (sfd->sfd_ino == SFS_NOINO) {
		if (sfd->sfd_name[0] != 0) {
			setbadness(EXIT_RECOV);
			warnx("Directory %s entry %lu has name but no file",
			      path, (unsigned long) index);
			sfd->sfd_name[0] = 0;
			dchanged = 1;
		}
	}
	else if (sfd->sfd_ino >= nblocks) {
		setbadness(EXIT_RECOV);
		warnx("Directory %s entry %lu has out of range "
		      "inode (cleared)",
		      path, (unsigned long) index);
		sfd->sfd_ino = SFS_NOINO;
		sfd->sfd_name[0] = 0;
		dchanged = 1;
	}
	else {
		if (sfd->sfd_name[0] == 0) {
			/* XXX: what happens if FSCK.n.m already exists? */
			snprintf(sfd->sfd_name, sizeof(sfd->sfd_name),
				 "FSCK.%lu.%lu",
				 (unsigned long) sfd->sfd_ino,
				 (unsigned long) uniqueid());
			setbadness(EXIT_RECOV);
			warnx("Directory %s entry %lu has file but "
			      "no name (fixed: %s)",
			      path, (unsigned long) index,
			      sfd->sfd_name);
			dchanged = 1;
		}
		if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) {
			setbadness(EXIT_RECOV);
			warnx("Directory %s entry %lu not "
			      "null-terminated (fixed)",
			      path, (unsigned long) index);
			dchanged = 1;
		}
		if (checkbadstring(sfd->sfd_name)) {
			setbadness(EXIT_RECOV);
			warnx("Directory %s entry %lu contains invalid "
			      "characters (fixed)",
			      path, (unsigned long) index);
			dchanged = 1;
		}
	}
	return dchanged;
}
Ejemplo n.º 2
0
static
void
dirwrite(const struct sfs_inode *sfi, struct sfs_dir *d, int nd)
{
	const unsigned atonce = SFS_BLOCKSIZE/sizeof(struct sfs_dir);
	unsigned nblocks = SFS_ROUNDUP(nd, atonce) / atonce;
	unsigned i, j, bad;

	for (i=0; i<nblocks; i++) {
		uint32_t block = dobmap(sfi, i);
		if (block!=0) {
			for (j=0; j<atonce; j++) {
				swapdir(&d[i*atonce+j]);
			}
			diskwrite(d + i*atonce, block);
		}
		else {
			for (j=bad=0; j<atonce; j++) {
				if (d[i*atonce+j].sfd_ino != SFS_NOINO ||
				    d[i*atonce+j].sfd_name[0] != 0) {
					bad = 1;
				}
			}
			if (bad) {
				warnx("Cannot write to missing block in "
				      "sparse directory (ERROR)");
				setbadness(EXIT_UNRECOV);
			}
		}
	}
}
Ejemplo n.º 3
0
static
void
adjust_filelinks(void)
{
	struct sfs_inode sfi;
	int i;

	for (i=0; i<ninodes; i++) {
		if (inodes[i].linkcount==0) {
			/* directory */
			continue;
		}
		diskread(&sfi, inodes[i].ino);
		swapinode(&sfi);
		assert(sfi.sfi_type == SFS_TYPE_FILE);
		if (sfi.sfi_linkcount != inodes[i].linkcount) {
			warnx("File %lu link count %lu should be %lu (fixed)",
			      (unsigned long) inodes[i].ino,
			      (unsigned long) sfi.sfi_linkcount,
			      (unsigned long) inodes[i].linkcount);
			sfi.sfi_linkcount = inodes[i].linkcount;
			setbadness(EXIT_RECOV);
			swapinode(&sfi);
			diskwrite(&sfi, inodes[i].ino);
		}
		count_files++;
	}
}
Ejemplo n.º 4
0
static
void
check_root_dir(void)
{
	struct sfs_inode sfi;
	diskread(&sfi, SFS_ROOT_LOCATION);
	swapinode(&sfi);

	switch (sfi.sfi_type) {
	    case SFS_TYPE_DIR:
		break;
	    case SFS_TYPE_FILE:
		warnx("Root directory inode is a regular file (fixed)");
		goto fix;
	    default:
		warnx("Root directory inode has invalid type %lu (fixed)",
		      (unsigned long) sfi.sfi_type);
	    fix:
		setbadness(EXIT_RECOV);
		sfi.sfi_type = SFS_TYPE_DIR;
		swapinode(&sfi);
		diskwrite(&sfi, SFS_ROOT_LOCATION);
		break;
	}

	check_dir(SFS_ROOT_LOCATION, SFS_ROOT_LOCATION, "");
}
Ejemplo n.º 5
0
Archivo: inode.c Proyecto: cse451/os161
/*
 * Correct link counts. This is effectively pass3. (FUTURE: change the
 * name accordingly.)
 */
void
inode_adjust_filelinks(void)
{
	struct sfs_dinode sfi;
	unsigned i;

	for (i=0; i<ninodes; i++) {
		if (inodes[i].type == SFS_TYPE_DIR) {
			/* directory */
			continue;
		}
		assert(inodes[i].type == SFS_TYPE_FILE);

		/* because we've seen it, there must be at least one link */
		assert(inodes[i].linkcount > 0);

		sfs_readinode(inodes[i].ino, &sfi);
		assert(sfi.sfi_type == SFS_TYPE_FILE);

		if (sfi.sfi_linkcount != inodes[i].linkcount) {
			warnx("File %lu link count %lu should be %lu (fixed)",
			      (unsigned long) inodes[i].ino,
			      (unsigned long) sfi.sfi_linkcount,
			      (unsigned long) inodes[i].linkcount);
			sfi.sfi_linkcount = inodes[i].linkcount;
			setbadness(EXIT_RECOV);
			sfs_writeinode(inodes[i].ino, &sfi);
		}
	}
}
Ejemplo n.º 6
0
Archivo: pass1.c Proyecto: cse451/os161
/*
 * Check the root directory, and implicitly everything under it.
 */
static
void
pass1_rootdir(void)
{
	struct sfs_dinode sfi;
	char path[SFS_VOLNAME_SIZE + 2];

	sfs_readinode(SFS_ROOT_LOCATION, &sfi);

	switch (sfi.sfi_type) {
	    case SFS_TYPE_DIR:
		break;
	    case SFS_TYPE_FILE:
		warnx("Root directory inode is a regular file (fixed)");
		goto fix;
	    default:
		warnx("Root directory inode has invalid type %lu (fixed)",
		      (unsigned long) sfi.sfi_type);
	    fix:
		setbadness(EXIT_RECOV);
		sfi.sfi_type = SFS_TYPE_DIR;
		sfs_writeinode(SFS_ROOT_LOCATION, &sfi);
		break;
	}

	snprintf(path, sizeof(path), "%s:", sb_volname());
	pass1_dir(SFS_ROOT_LOCATION, path);
}
Ejemplo n.º 7
0
Archivo: pass1.c Proyecto: cse451/os161
/*
 * Do the pass1 inode-level checks on inode INO, which has already
 * been loaded into SFI. Note that sfi_type has already been
 * validated.
 *
 * Returns nonzero if SFI has been modified and needs to be written
 * back.
 */
static
int
pass1_inode(uint32_t ino, struct sfs_dinode *sfi, int alreadychanged)
{
	int changed = alreadychanged;
	int isdir = sfi->sfi_type == SFS_TYPE_DIR;

	if (inode_add(ino, sfi->sfi_type)) {
		/* Already been here. */
		assert(changed == 0);
		return 1;
	}

	bitmap_blockinuse(ino, B_INODE, ino);

	if (checkzeroed(sfi->sfi_waste, sizeof(sfi->sfi_waste))) {
		warnx("Inode %lu: sfi_waste section not zeroed (fixed)",
		      (unsigned long) ino);
		setbadness(EXIT_RECOV);
		changed = 1;
	}

	if (check_inode_blocks(ino, sfi, isdir)) {
		changed = 1;
	}

	if (changed) {
		sfs_writeinode(ino, sfi);
	}
	return 0;
}
Ejemplo n.º 8
0
static
void
check_sb(void)
{
	struct sfs_super sp;
	uint32_t i;
	int schanged=0;

	diskread(&sp, SFS_SB_LOCATION);
	swapsb(&sp);
	if (sp.sp_magic != SFS_MAGIC) {
		errx(EXIT_UNRECOV, "Not an sfs filesystem");
	}

	assert(nblocks==0);
	assert(bitblocks==0);
	nblocks = sp.sp_nblocks;
	bitblocks = SFS_BITBLOCKS(nblocks);
	assert(nblocks>0);
	assert(bitblocks>0);

	bitmap_init(bitblocks);
	for (i=nblocks; i<bitblocks*SFS_BLOCKBITS; i++) {
		bitmap_mark(i, B_PASTEND, 0);
	}

	if (checknullstring(sp.sp_volname, sizeof(sp.sp_volname))) {
		warnx("Volume name not null-terminated (fixed)");
		setbadness(EXIT_RECOV);
		schanged = 1;
	}
	if (checkbadstring(sp.sp_volname)) {
		warnx("Volume name contains illegal characters (fixed)");
		setbadness(EXIT_RECOV);
		schanged = 1;
	}

	if (schanged) {
		swapsb(&sp);
		diskwrite(&sp, SFS_SB_LOCATION);
	}

	bitmap_mark(SFS_SB_LOCATION, B_SUPERBLOCK, 0);
	for (i=0; i<bitblocks; i++) {
		bitmap_mark(SFS_MAP_LOCATION+i, B_BITBLOCK, i);
	}
}
Ejemplo n.º 9
0
static
int
check_dir_entry(const char *pathsofar, uint32_t index, struct sfs_dir *sfd)
{
	int dchanged = 0;

	if (sfd->sfd_ino == SFS_NOINO) {
		if (sfd->sfd_name[0] != 0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s entry %lu has name but no file",
			      pathsofar, (unsigned long) index);
			sfd->sfd_name[0] = 0;
			dchanged = 1;
		}
	}
	else {
		if (sfd->sfd_name[0] == 0) {
			snprintf(sfd->sfd_name, sizeof(sfd->sfd_name),
				 "FSCK.%lu.%lu",
				 (unsigned long) sfd->sfd_ino,
				 (unsigned long) uniquecounter++);
			setbadness(EXIT_RECOV);
			warnx("Directory /%s entry %lu has file but "
			      "no name (fixed: %s)",
			      pathsofar, (unsigned long) index,
			      sfd->sfd_name);
			dchanged = 1;
		}
		if (checknullstring(sfd->sfd_name, sizeof(sfd->sfd_name))) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s entry %lu not "
			      "null-terminated (fixed)",
			      pathsofar, (unsigned long) index);
			dchanged = 1;
		}
		if (checkbadstring(sfd->sfd_name)) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s entry %lu contains invalid "
			      "characters (fixed)",
			      pathsofar, (unsigned long) index);
			dchanged = 1;
		}
	}
	return dchanged;
}
Ejemplo n.º 10
0
static
void
bitmap_mark(uint32_t block, blockusage_t how, uint32_t howdesc)
{
	unsigned index = block/8;
	uint8_t mask = ((uint8_t)1)<<(block%8);

	if (how == B_TOFREE) {
		if (tofreedata[index] & mask) {
			/* already marked to free once, ignore */
			return;
		}
		if (bitmapdata[index] & mask) {
			/* block is used elsewhere, ignore */
			return;
		}
		tofreedata[index] |= mask;
		return;
	}

	if (tofreedata[index] & mask) {
		/* really using the block, don't free it */
		tofreedata[index] &= ~mask;
	}

	if (bitmapdata[index] & mask) {
		warnx("Block %lu (used as %s) already in use! (NOT FIXED)",
		      (unsigned long) block, blockusagestr(how, howdesc));
		setbadness(EXIT_UNRECOV);
	}

	bitmapdata[index] |= mask;

	if (how != B_PASTEND) {
		count_blocks++;
	}
}
Ejemplo n.º 11
0
/* returns nonzero if inode modified */
static
int
check_inode_blocks(uint32_t ino, struct sfs_inode *sfi, int isdir)
{
	uint32_t size, block, nblocks, badcount;

	badcount = 0;

	size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);
	nblocks = size/SFS_BLOCKSIZE;

	for (block=0; block<SFS_NDIRECT; block++) {
		if (block < nblocks) {
			if (sfi->sfi_direct[block] != 0) {
				bitmap_mark(sfi->sfi_direct[block],
					    isdir ? B_DIRDATA : B_DATA, ino);
			}
		}
		else {
			if (sfi->sfi_direct[block] != 0) {
				badcount++;
				bitmap_mark(sfi->sfi_direct[block],
					    B_TOFREE, 0);
			}
		}
	}

#ifdef SFS_NIDIRECT
	for (i=0; i<SFS_NIDIRECT; i++) {
		check_indirect_block(ino, &sfi->sfi_indirect[i],
				     &block, nblocks, &badcount, isdir, 1);
	}
#else
	check_indirect_block(ino, &sfi->sfi_indirect,
			     &block, nblocks, &badcount, isdir, 1);
#endif

#ifdef SFS_NDIDIRECT
	for (i=0; i<SFS_NDIDIRECT; i++) {
		check_indirect_block(ino, &sfi->sfi_dindirect[i],
				     &block, nblocks, &badcount, isdir, 2);
	}
#else
#ifdef HAS_DIDIRECT
	check_indirect_block(ino, &sfi->sfi_dindirect,
			     &block, nblocks, &badcount, isdir, 2);
#endif
#endif

#ifdef SFS_NTIDIRECT
	for (i=0; i<SFS_NTIDIRECT; i++) {
		check_indirect_block(ino, &sfi->sfi_tindirect[i],
				     &block, nblocks, &badcount, isdir, 3);
	}
#else
#ifdef HAS_TIDIRECT
	check_indirect_block(ino, &sfi->sfi_tindirect,
			     &block, nblocks, &badcount, isdir, 3);
#endif
#endif

	if (badcount > 0) {
		warnx("Inode %lu: %lu blocks after EOF (freed)",
		     (unsigned long) ino, (unsigned long) badcount);
		setbadness(EXIT_RECOV);
		return 1;
	}

	return 0;
}
Ejemplo n.º 12
0
static
void
check_bitmap(void)
{
	uint8_t bits[SFS_BLOCKSIZE], *found, *tofree, tmp;
	uint32_t alloccount=0, freecount=0, i, j;
	int bchanged;

	for (i=0; i<bitblocks; i++) {
		diskread(bits, SFS_MAP_LOCATION+i);
		swapbits(bits);
		found = bitmapdata + i*SFS_BLOCKSIZE;
		tofree = tofreedata + i*SFS_BLOCKSIZE;
		bchanged = 0;

		for (j=0; j<SFS_BLOCKSIZE; j++) {
			/* we shouldn't have blocks marked both ways */
			assert((found[j] & tofree[j])==0);

			if (bits[j]==found[j]) {
				continue;
			}

			if (bits[j]==(found[j] | tofree[j])) {
				bits[j] = found[j];
				bchanged = 1;
				continue;
			}

			/* free the ones we're freeing */
			bits[j] &= ~tofree[j];

			/* are we short any? */
			if ((bits[j] & found[j]) != found[j]) {
				tmp = found[j] & ~bits[j];
				alloccount += countbits(tmp);
				if (tmp != 0) {
					reportbits(i, j, tmp, "free");
				}
			}

			/* do we have any extra? */
			if ((bits[j] & found[j]) != bits[j]) {
				tmp = bits[j] & ~found[j];
				freecount += countbits(tmp);
				if (tmp != 0) {
					reportbits(i, j, tmp, "allocated");
				}
			}

			bits[j] = found[j];
			bchanged = 1;
		}

		if (bchanged) {
			swapbits(bits);
			diskwrite(bits, SFS_MAP_LOCATION+i);
		}
	}

	if (alloccount > 0) {
		warnx("%lu blocks erroneously shown free in bitmap (fixed)",
		      (unsigned long) alloccount);
		setbadness(EXIT_RECOV);
	}
	if (freecount > 0) {
		warnx("%lu blocks erroneously shown used in bitmap (fixed)",
		      (unsigned long) freecount);
		setbadness(EXIT_RECOV);
	}
}
Ejemplo n.º 13
0
Archivo: pass1.c Proyecto: cse451/os161
/*
 * Check the blocks belonging to inode INO, whose inode has already
 * been loaded into SFI. ISDIR is a shortcut telling us if the inode
 * is a directory.
 *
 * Returns nonzero if SFI has been modified and needs to be written
 * back.
 */
static
int
check_inode_blocks(uint32_t ino, struct sfs_dinode *sfi, int isdir)
{
	struct ibstate ibs;
	uint32_t size, datablock;
	int changed;
	int i;

	size = SFS_ROUNDUP(sfi->sfi_size, SFS_BLOCKSIZE);

	ibs.ino = ino;
	/*ibs.curfileblock = 0;*/
	ibs.fileblocks = size/SFS_BLOCKSIZE;
	ibs.volblocks = sb_totalblocks();
	ibs.pasteofcount = 0;
	ibs.usagetype = isdir ? B_DIRDATA : B_DATA;

	changed = 0;

	for (ibs.curfileblock=0; ibs.curfileblock<NUM_D; ibs.curfileblock++) {
		datablock = GET_D(sfi, ibs.curfileblock);
		if (datablock >= ibs.volblocks) {
			warnx("Inode %lu: direct block pointer for "
			      "block %lu outside of volume "
			      "(cleared)\n",
			      (unsigned long)ibs.ino,
			      (unsigned long)ibs.curfileblock);
			SET_D(sfi, ibs.curfileblock) = 0;
			changed = 1;
		}
		else if (datablock > 0) {
			if (ibs.curfileblock < ibs.fileblocks) {
				bitmap_blockinuse(datablock, ibs.usagetype,
						  ibs.ino);
			}
			else {
				ibs.pasteofcount++;
				changed = 1;
				bitmap_blockfree(datablock);
				SET_D(sfi, ibs.curfileblock) = 0;
			}
		}
	}

	for (i=0; i<NUM_I; i++) {
		check_indirect_block(&ibs, &SET_I(sfi, i), &changed, 1);
	}
	for (i=0; i<NUM_II; i++) {
		check_indirect_block(&ibs, &SET_II(sfi, i), &changed, 2);
	}
	for (i=0; i<NUM_III; i++) {
		check_indirect_block(&ibs, &SET_III(sfi, i), &changed, 3);
	}

	if (ibs.pasteofcount > 0) {
		warnx("Inode %lu: %u blocks after EOF (freed)",
		     (unsigned long) ibs.ino, ibs.pasteofcount);
		setbadness(EXIT_RECOV);
	}

	return changed;
}
Ejemplo n.º 14
0
Archivo: pass1.c Proyecto: cse451/os161
/*
 * Check a directory. INO is the inode number; PATHSOFAR is the path
 * to this directory. This traverses the volume directory tree
 * recursively.
 */
static
void
pass1_dir(uint32_t ino, const char *pathsofar)
{
	struct sfs_dinode sfi;
	struct sfs_dir *direntries;
	uint32_t ndirentries, i;
	int ichanged=0, dchanged=0;

	sfs_readinode(ino, &sfi);

	if (sfi.sfi_size % sizeof(struct sfs_dir) != 0) {
		setbadness(EXIT_RECOV);
		warnx("Directory %s has illegal size %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_size);
		sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size,
					   sizeof(struct sfs_dir));
		ichanged = 1;
	}
	count_dirs++;

	if (pass1_inode(ino, &sfi, ichanged)) {
		/* been here before; crosslinked dir, sort it out in pass 2 */
		return;
	}

	ndirentries = sfi.sfi_size/sizeof(struct sfs_dir);
	direntries = domalloc(sfi.sfi_size);

	sfs_readdir(&sfi, direntries, ndirentries);

	for (i=0; i<ndirentries; i++) {
		if (pass1_direntry(pathsofar, i, &direntries[i])) {
			dchanged = 1;
		}
	}

	for (i=0; i<ndirentries; i++) {
		if (direntries[i].sfd_ino == SFS_NOINO) {
			/* nothing */
		}
		else if (!strcmp(direntries[i].sfd_name, ".")) {
			/* nothing */
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			/* nothing */
		}
		else {
			char path[strlen(pathsofar)+SFS_NAMELEN+1];
			struct sfs_dinode subsfi;
			uint32_t subino;

			subino = direntries[i].sfd_ino;
			sfs_readinode(subino, &subsfi);
			snprintf(path, sizeof(path), "%s/%s",
				 pathsofar, direntries[i].sfd_name);

			switch (subsfi.sfi_type) {
			    case SFS_TYPE_FILE:
				if (pass1_inode(subino, &subsfi, 0)) {
					/* been here before */
					break;
				}
				count_files++;
				break;
			    case SFS_TYPE_DIR:
				pass1_dir(subino, path);
				break;
			    default:
				setbadness(EXIT_RECOV);
				warnx("Object %s: Invalid inode type "
				      "(removed)", path);
				direntries[i].sfd_ino = SFS_NOINO;
				direntries[i].sfd_name[0] = 0;
				dchanged = 1;
				break;
			}
		}
	}

	if (dchanged) {
		sfs_writedir(&sfi, direntries, ndirentries);
	}

	free(direntries);
}
Ejemplo n.º 15
0
static
int
check_dir(uint32_t ino, uint32_t parentino, const char *pathsofar)
{
	struct sfs_inode sfi;
	struct sfs_dir *direntries;
	int *sortvector;
	uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
	int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0;

	diskread(&sfi, ino);
	swapinode(&sfi);

	if (remember_dir(ino, pathsofar)) {
		/* crosslinked dir */
		return 1;
	}

	bitmap_mark(ino, B_INODE, ino);
	count_dirs++;

	if (sfi.sfi_size % sizeof(struct sfs_dir) != 0) {
		setbadness(EXIT_RECOV);
		warnx("Directory /%s has illegal size %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_size);
		sfi.sfi_size = SFS_ROUNDUP(sfi.sfi_size,
					   sizeof(struct sfs_dir));
		ichanged = 1;
	}

	if (check_inode_blocks(ino, &sfi, 1)) {
		ichanged = 1;
	}

	ndirentries = sfi.sfi_size/sizeof(struct sfs_dir);
	maxdirentries = SFS_ROUNDUP(ndirentries,
				    SFS_BLOCKSIZE/sizeof(struct sfs_dir));
	dirsize = maxdirentries * sizeof(struct sfs_dir);
	direntries = domalloc(dirsize);
	sortvector = domalloc(ndirentries * sizeof(int));

	dirread(&sfi, direntries, ndirentries);
	for (i=ndirentries; i<maxdirentries; i++) {
		direntries[i].sfd_ino = SFS_NOINO;
		bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
	}

	for (i=0; i<ndirentries; i++) {
		if (check_dir_entry(pathsofar, i, &direntries[i])) {
			dchanged = 1;
		}
		sortvector[i] = i;
	}

	sortdir(sortvector, direntries, ndirentries);

	/* don't use ndirentries-1 here in case ndirentries == 0 */
	for (i=0; i+1<ndirentries; i++) {
		struct sfs_dir *d1 = &direntries[sortvector[i]];
		struct sfs_dir *d2 = &direntries[sortvector[i+1]];
		assert(d1 != d2);

		if (d1->sfd_ino == SFS_NOINO) {
			continue;
		}

		if (!strcmp(d1->sfd_name, d2->sfd_name)) {
			if (d1->sfd_ino == d2->sfd_ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Duplicate entries for "
				      "%s (merged)",
				      pathsofar, d1->sfd_name);
				d1->sfd_ino = SFS_NOINO;
				d1->sfd_name[0] = 0;
			}
			else {
				snprintf(d1->sfd_name, sizeof(d1->sfd_name),
					 "FSCK.%lu.%lu",
					 (unsigned long) d1->sfd_ino,
					 (unsigned long) uniquecounter++);
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Duplicate names %s "
				      "(one renamed: %s)",
				      pathsofar, d2->sfd_name, d1->sfd_name);
			}
			dchanged = 1;
		}
	}

	for (i=0; i<ndirentries; i++) {
		if (!strcmp(direntries[i].sfd_name, ".")) {
			if (direntries[i].sfd_ino != ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Incorrect `.' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = ino;
				dchanged = 1;
			}
			assert(dotseen==0); /* due to duplicate checking */
			dotseen = 1;
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			if (direntries[i].sfd_ino != parentino) {
				setbadness(EXIT_RECOV);
				warnx("Directory /%s: Incorrect `..' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = parentino;
				dchanged = 1;
			}
			assert(dotdotseen==0); /* due to duplicate checking */
			dotdotseen = 1;
		}
	}

	if (!dotseen) {
		if (dir_tryadd(direntries, ndirentries, ".", ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `.' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (dir_tryadd(direntries, maxdirentries, ".", ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `.' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory /%s: No `.' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	if (!dotdotseen) {
		if (dir_tryadd(direntries, ndirentries, "..", parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `..' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (dir_tryadd(direntries, maxdirentries, "..",
				    parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory /%s: No `..' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory /%s: No `..' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	subdircount=0;
	for (i=0; i<ndirentries; i++) {
		if (!strcmp(direntries[i].sfd_name, ".")) {
			/* nothing */
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			/* nothing */
		}
		else if (direntries[i].sfd_ino == SFS_NOINO) {
			/* nothing */
		}
		else {
			char path[strlen(pathsofar)+SFS_NAMELEN+1];
			struct sfs_inode subsfi;

			diskread(&subsfi, direntries[i].sfd_ino);
			swapinode(&subsfi);
			snprintf(path, sizeof(path), "%s/%s",
				 pathsofar, direntries[i].sfd_name);

			switch (subsfi.sfi_type) {
			    case SFS_TYPE_FILE:
				if (check_inode_blocks(direntries[i].sfd_ino,
						       &subsfi, 0)) {
					swapinode(&subsfi);
					diskwrite(&subsfi,
						  direntries[i].sfd_ino);
				}
				observe_filelink(direntries[i].sfd_ino);
				break;
			    case SFS_TYPE_DIR:
				if (check_dir(direntries[i].sfd_ino,
					      ino,
					      path)) {
					setbadness(EXIT_RECOV);
					warnx("Directory /%s: Crosslink to "
					      "other directory (removed)",
					      path);
					direntries[i].sfd_ino = SFS_NOINO;
					direntries[i].sfd_name[0] = 0;
					dchanged = 1;
				}
				else {
					subdircount++;
				}
				break;
			    default:
				setbadness(EXIT_RECOV);
				warnx("Object /%s: Invalid inode type "
				      "(removed)", path);
				direntries[i].sfd_ino = SFS_NOINO;
				direntries[i].sfd_name[0] = 0;
				dchanged = 1;
				break;
			}
		}
	}

	if (sfi.sfi_linkcount != subdircount+2) {
		setbadness(EXIT_RECOV);
		warnx("Directory /%s: Link count %lu should be %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_linkcount,
		      (unsigned long) subdircount+2);
		sfi.sfi_linkcount = subdircount+2;
		ichanged = 1;
	}

	if (dchanged) {
		dirwrite(&sfi, direntries, ndirentries);
	}

	if (ichanged) {
		swapinode(&sfi);
		diskwrite(&sfi, ino);
	}

	free(direntries);
	free(sortvector);

	return 0;
}
Ejemplo n.º 16
0
Archivo: pass2.c Proyecto: cse451/os161
/*
 * Process a directory. INO is the inode number; PARENTINO is the
 * parent's inode number; PATHSOFAR is the path to this directory.
 *
 * Recursively checks its subdirs.
 *
 * In the FUTURE we might want to improve the handling of crosslinked
 * directories so it picks the parent that the .. entry points to,
 * instead of the first entry we recursively find. Beware of course
 * that the .. entry might not point to anywhere valid at all...
 */
static
int
pass2_dir(uint32_t ino, uint32_t parentino, const char *pathsofar)
{
	struct sfs_dinode sfi;
	struct sfs_dir *direntries;
	int *sortvector;
	uint32_t dirsize, ndirentries, maxdirentries, subdircount, i;
	int ichanged=0, dchanged=0, dotseen=0, dotdotseen=0;

	if (inode_visitdir(ino)) {
		/* crosslinked dir; tell parent to remove the entry */
		return 1;
	}

	/* Load the inode. */
	sfs_readinode(ino, &sfi);

	/*
	 * Load the directory. If there is any leftover room in the
	 * last block, allocate space for it in case we want to insert
	 * entries.
	 */

	ndirentries = sfi.sfi_size/sizeof(struct sfs_dir);
	maxdirentries = SFS_ROUNDUP(ndirentries,
				    SFS_BLOCKSIZE/sizeof(struct sfs_dir));
	dirsize = maxdirentries * sizeof(struct sfs_dir);
	direntries = domalloc(dirsize);

	sortvector = domalloc(ndirentries * sizeof(int));

	sfs_readdir(&sfi, direntries, ndirentries);
	for (i=ndirentries; i<maxdirentries; i++) {
		direntries[i].sfd_ino = SFS_NOINO;
		bzero(direntries[i].sfd_name, sizeof(direntries[i].sfd_name));
	}

	/*
	 * Sort by name and check for duplicate names.
	 */

	sfsdir_sort(direntries, ndirentries, sortvector);

	/* don't use ndirentries-1 here, in case ndirentries == 0 */
	for (i=0; i+1<ndirentries; i++) {
		struct sfs_dir *d1 = &direntries[sortvector[i]];
		struct sfs_dir *d2 = &direntries[sortvector[i+1]];
		assert(d1 != d2);

		if (d1->sfd_ino == SFS_NOINO || d2->sfd_ino == SFS_NOINO) {
			/* sfsdir_sort puts these last */
			continue;
		}

		if (!strcmp(d1->sfd_name, d2->sfd_name)) {
			if (d1->sfd_ino == d2->sfd_ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory %s: Duplicate entries for "
				      "%s (merged)",
				      pathsofar, d1->sfd_name);
				d1->sfd_ino = SFS_NOINO;
				d1->sfd_name[0] = 0;
			}
			else {
				/* XXX: what if FSCK.n.m already exists? */
				snprintf(d1->sfd_name, sizeof(d1->sfd_name),
					 "FSCK.%lu.%lu",
					 (unsigned long) d1->sfd_ino,
					 (unsigned long) uniqueid());
				setbadness(EXIT_RECOV);
				warnx("Directory %s: Duplicate names %s "
				      "(one renamed: %s)",
				      pathsofar, d2->sfd_name, d1->sfd_name);
			}
			dchanged = 1;
		}
	}

	/*
	 * Look for the . and .. entries.
	 */

	for (i=0; i<ndirentries; i++) {
		if (!strcmp(direntries[i].sfd_name, ".")) {
			if (direntries[i].sfd_ino != ino) {
				setbadness(EXIT_RECOV);
				warnx("Directory %s: Incorrect `.' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = ino;
				dchanged = 1;
			}
			/* duplicates are checked above -> only one . here */
			assert(dotseen==0);
			dotseen = 1;
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			if (direntries[i].sfd_ino != parentino) {
				setbadness(EXIT_RECOV);
				warnx("Directory %s: Incorrect `..' entry "
				      "(fixed)", pathsofar);
				direntries[i].sfd_ino = parentino;
				dchanged = 1;
			}
			/* duplicates are checked above -> only one .. here */
			assert(dotdotseen==0);
			dotdotseen = 1;
		}
	}

	/*
	 * If no . entry, try to insert one.
	 */

	if (!dotseen) {
		if (sfsdir_tryadd(direntries, ndirentries, ".", ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory %s: No `.' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (sfsdir_tryadd(direntries, maxdirentries, ".",
				       ino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory %s: No `.' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory %s: No `.' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	/*
	 * If no .. entry, try to insert one.
	 */

	if (!dotdotseen) {
		if (sfsdir_tryadd(direntries, ndirentries, "..",
				  parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory %s: No `..' entry (added)",
			      pathsofar);
			dchanged = 1;
		}
		else if (sfsdir_tryadd(direntries, maxdirentries, "..",
				    parentino)==0) {
			setbadness(EXIT_RECOV);
			warnx("Directory %s: No `..' entry (added)",
			      pathsofar);
			ndirentries++;
			dchanged = 1;
			sfi.sfi_size += sizeof(struct sfs_dir);
			ichanged = 1;
		}
		else {
			setbadness(EXIT_UNRECOV);
			warnx("Directory %s: No `..' entry (NOT FIXED)",
			      pathsofar);
		}
	}

	/*
	 * Now load each inode in the directory.
	 *
	 * For regular files, count the number of links we see; for
	 * directories, recurse. Count the number of subdirs seen
	 * so we can correct our own link count if necessary.
	 */

	subdircount=0;
	for (i=0; i<ndirentries; i++) {
		if (direntries[i].sfd_ino == SFS_NOINO) {
			/* nothing */
		}
		else if (!strcmp(direntries[i].sfd_name, ".")) {
			/* nothing */
		}
		else if (!strcmp(direntries[i].sfd_name, "..")) {
			/* nothing */
		}
		else {
			char path[strlen(pathsofar)+SFS_NAMELEN+1];
			struct sfs_dinode subsfi;

			sfs_readinode(direntries[i].sfd_ino, &subsfi);
			snprintf(path, sizeof(path), "%s/%s",
				 pathsofar, direntries[i].sfd_name);

			switch (subsfi.sfi_type) {
			    case SFS_TYPE_FILE:
				inode_addlink(direntries[i].sfd_ino);
				break;
			    case SFS_TYPE_DIR:
				if (pass2_dir(direntries[i].sfd_ino,
					      ino,
					      path)) {
					setbadness(EXIT_RECOV);
					warnx("Directory %s: Crosslink to "
					      "other directory (removed)",
					      path);
					direntries[i].sfd_ino = SFS_NOINO;
					direntries[i].sfd_name[0] = 0;
					dchanged = 1;
				}
				else {
					subdircount++;
				}
				break;
			    default:
				setbadness(EXIT_RECOV);
				warnx("Object %s: Invalid inode type "
				      "(removed)", path);
				direntries[i].sfd_ino = SFS_NOINO;
				direntries[i].sfd_name[0] = 0;
				dchanged = 1;
				break;
			}
		}
	}

	/*
	 * Fix up the link count if needed.
	 */

	if (sfi.sfi_linkcount != subdircount+2) {
		setbadness(EXIT_RECOV);
		warnx("Directory %s: Link count %lu should be %lu (fixed)",
		      pathsofar, (unsigned long) sfi.sfi_linkcount,
		      (unsigned long) subdircount+2);
		sfi.sfi_linkcount = subdircount+2;
		ichanged = 1;
	}

	/*
	 * Write back anything that changed, clean up, and return.
	 */

	if (dchanged) {
		sfs_writedir(&sfi, direntries, ndirentries);
	}

	if (ichanged) {
		sfs_writeinode(ino, &sfi);
	}

	free(direntries);
	free(sortvector);

	return 0;
}
Ejemplo n.º 17
0
/*
 * Traverse an indirect block, recording blocks that are in use,
 * dropping any entries that are past EOF, and clearing any entries
 * that point outside the volume.
 *
 * XXX: this should be extended to be able to recover from crosslinked
 * blocks. Currently it just complains in freemap.c and sets
 * EXIT_UNRECOV.
 *
 * The traversal is recursive; the state is maintained in IBS (as
 * described above). IENTRY is a pointer to the entry in the parent
 * indirect block (or the inode) that names the block we're currently
 * scanning. IECHANGEDP should be set to 1 if *IENTRY is changed.
 * INDIRECTION is the indirection level of this block (1, 2, or 3).
 */
static
void
check_indirect_block(struct ibstate *ibs, uint32_t *ientry, int *iechangedp,
		     int indirection)
{
	uint32_t entries[SFS_DBPERIDB];
	uint32_t i, ct;
	uint32_t coveredblocks;
	int localchanged = 0;
	int j;

	if (*ientry > 0 && *ientry < ibs->volblocks) {
		sfs_readindirect(*ientry, entries);
		freemap_blockinuse(*ientry, B_IBLOCK, ibs->ino);
	}
	else {
		if (*ientry >= ibs->volblocks) {
			setbadness(EXIT_RECOV);
			warnx("Inode %lu: indirect block pointer (level %d) "
			      "for block %lu outside of volume: %lu "
			      "(cleared)\n",
			      (unsigned long)ibs->ino, indirection,
			      (unsigned long)ibs->curfileblock,
			      (unsigned long)*ientry);
			*ientry = 0;
			*iechangedp = 1;
		}
		coveredblocks = 1;
		for (j=0; j<indirection; j++) {
			coveredblocks *= SFS_DBPERIDB;
		}
		ibs->curfileblock += coveredblocks;
		return;
	}

	if (indirection > 1) {
		for (i=0; i<SFS_DBPERIDB; i++) {
			check_indirect_block(ibs, &entries[i], &localchanged,
					     indirection-1);
		}
	}
	else {
		assert(indirection==1);

		for (i=0; i<SFS_DBPERIDB; i++) {
			if (entries[i] >= ibs->volblocks) {
				setbadness(EXIT_RECOV);
				warnx("Inode %lu: direct block pointer for "
				      "block %lu outside of volume: %lu "
				      "(cleared)\n",
				      (unsigned long)ibs->ino,
				      (unsigned long)ibs->curfileblock,
				      (unsigned long)entries[i]);
				entries[i] = 0;
				localchanged = 1;
			}
			else if (entries[i] != 0) {
				if (ibs->curfileblock < ibs->fileblocks) {
					freemap_blockinuse(entries[i],
							  ibs->usagetype,
							  ibs->ino);
				}
				else {
					setbadness(EXIT_RECOV);
					ibs->pasteofcount++;
					freemap_blockfree(entries[i]);
					entries[i] = 0;
					localchanged = 1;
				}
			}
			ibs->curfileblock++;
		}
	}

	ct=0;
	for (i=ct=0; i<SFS_DBPERIDB; i++) {
		if (entries[i]!=0) ct++;
	}
	if (ct==0) {
		if (*ientry != 0) {
			setbadness(EXIT_RECOV);
			/* this is not necessarily correct */
			/*ibs->pasteofcount++;*/
			*iechangedp = 1;
			freemap_blockfree(*ientry);
			*ientry = 0;
		}
	}
	else {
		assert(*ientry != 0);
		if (localchanged) {
			sfs_writeindirect(*ientry, entries);
		}
	}
}