statemap[inp->i_child->i_number] == DSTATE)
statemap[inp->i_child->i_number] != state)
static struct bufarea *getdirblk __P((daddr_t, long));static int lftempname __P((char *, ino_t));static int mkentry __P((struct inodesc *));static int chgino __P((struct  inodesc *));/* * Propagate connected state through the tree. */voidpropagate(){	register struct inoinfo **inpp, *inp, *pinp;	struct inoinfo **inpend;	/*	 * Create a list of children for each directory.	 */	inpend = &inpsort[inplast];	for (inpp = inpsort; inpp < inpend; inpp++) {		inp = *inpp;		if (inp->i_parent == 0 ||		    inp->i_number == ROOTINO)			continue;		pinp = getinoinfo(inp->i_parent);		inp->i_parentp = pinp;		inp->i_sibling = pinp->i_child;		pinp->i_child = inp;	}	inp = getinoinfo(ROOTINO);	while (inp) {		statemap[inp->i_number] = DFOUND;		if (inp->i_child &&		    statemap[inp->i_child->i_number] == DSTATE)			inp = inp->i_child;		else if (inp->i_sibling)			inp = inp->i_sibling;		else			inp = inp->i_parentp;	}}/* * Scan each entry in a directory block. */intdirscan(idesc)	register struct inodesc *idesc;{	register struct direct *dp;	register struct bufarea *bp;	int dsize, n;	long blksiz;	char dbuf[DIRBLKSIZ];	if (idesc->id_type != DATA)		errexit("wrong type to dirscan %d\n", idesc->id_type);	if (idesc->id_entryno == 0 &&	    (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)		idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);	blksiz = idesc->id_numfrags * sblock.fs_fsize;	if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {		idesc->id_filesize -= blksiz;		return (SKIP);	}	idesc->id_loc = 0;	for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {		dsize = dp->d_reclen;		memcpy(dbuf, dp, (size_t)dsize);#		if (BYTE_ORDER == LITTLE_ENDIAN)			if (!newinofmt) {				struct direct *tdp = (struct direct *)dbuf;				u_char tmp;				tmp = tdp->d_namlen;				tdp->d_namlen = tdp->d_type;				tdp->d_type = tmp;			}#		endif		idesc->id_dirp = (struct direct *)dbuf;		if ((n = (*idesc->id_func)(idesc)) & ALTERED) {#			if (BYTE_ORDER == LITTLE_ENDIAN)				if (!newinofmt && !doinglevel2) {					struct direct *tdp;					u_char tmp;					tdp = (struct direct *)dbuf;					tmp = tdp->d_namlen;					tdp->d_namlen = tdp->d_type;					tdp->d_type = tmp;				}#			endif			bp = getdirblk(idesc->id_blkno, blksiz);			memcpy(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,			    (size_t)dsize);			dirty(bp);			sbdirty();		}		if (n & STOP) 			return (n);	}	return (idesc->id_filesize > 0 ? KEEPON : STOP);}/* * get next entry in a directory. */static struct direct *fsck_readdir(idesc)	register struct inodesc *idesc;{	register struct direct *dp, *ndp;	register struct bufarea *bp;	long size, blksiz, fix, dploc;	blksiz = idesc->id_numfrags * sblock.fs_fsize;	bp = getdirblk(idesc->id_blkno, blksiz);	if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&	    idesc->id_loc < blksiz) {		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);		if (dircheck(idesc, dp))			goto dpok;		if (idesc->id_fix == IGNORE)			return (0);		fix = dofix(idesc, "DIRECTORY CORRUPTED");		bp = getdirblk(idesc->id_blkno, blksiz);		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);		dp->d_reclen = DIRBLKSIZ;		dp->d_ino = 0;		dp->d_type = 0;		dp->d_namlen = 0;		dp->d_name[0] = '\0';		if (fix)			dirty(bp);		idesc->id_loc += DIRBLKSIZ;		idesc->id_filesize -= DIRBLKSIZ;		return (dp);	}dpok:	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)		return NULL;	dploc = idesc->id_loc;	dp = (struct direct *)(bp->b_un.b_buf + dploc);	idesc->id_loc += dp->d_reclen;	idesc->id_filesize -= dp->d_reclen;	if ((idesc->id_loc % DIRBLKSIZ) == 0)		return (dp);	ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);	if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&	    dircheck(idesc, ndp) == 0) {		size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);		idesc->id_loc += size;		idesc->id_filesize -= size;		if (idesc->id_fix == IGNORE)			return (0);		fix = dofix(idesc, "DIRECTORY CORRUPTED");		bp = getdirblk(idesc->id_blkno, blksiz);		dp = (struct direct *)(bp->b_un.b_buf + dploc);		dp->d_reclen += size;		if (fix)			dirty(bp);	}	return (dp);}/* * Verify that a directory entry is valid. * This is a superset of the checks made in the kernel. */intdircheck(idesc, dp)	struct inodesc *idesc;	register struct direct *dp;{	register int size;	register char *cp;	u_char namlen, type;	int spaceleft;	spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);	if (dp->d_ino >= maxino ||	    dp->d_reclen == 0 ||	    dp->d_reclen > spaceleft ||	    (dp->d_reclen & 0x3) != 0)		return (0);	if (dp->d_ino == 0)		return (1);	size = DIRSIZ(!newinofmt, dp);#	if (BYTE_ORDER == LITTLE_ENDIAN)		if (!newinofmt) {			type = dp->d_namlen;			namlen = dp->d_type;		} else {			namlen = dp->d_namlen;			type = dp->d_type;		}#	else		namlen = dp->d_namlen;		type = dp->d_type;#	endif	if (dp->d_reclen < size ||	    idesc->id_filesize < size ||	    namlen > MAXNAMLEN ||	    type > 15)		return (0);	for (cp = dp->d_name, size = 0; size < namlen; size++)		if (*cp == '\0' || (*cp++ == '/'))			return (0);	if (*cp != '\0')		return (0);	return (1);}voiddirerror(ino, errmesg)	ino_t ino;	char *errmesg;{	fileerror(ino, ino, errmesg);}voidfileerror(cwd, ino, errmesg)	ino_t cwd, ino;	char *errmesg;{	register struct dinode *dp;	char pathbuf[MAXPATHLEN + 1];	pwarn("%s ", errmesg);	pinode(ino);	printf("\n");	getpathname(pathbuf, cwd, ino);	if (ino < ROOTINO || ino > maxino) {		pfatal("NAME=%s\n", pathbuf);		return;	}	dp = ginode(ino);	if (ftypeok(dp))		pfatal("%s=%s\n",		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);	else		pfatal("NAME=%s\n", pathbuf);}voidadjust(idesc, lcnt)	register struct inodesc *idesc;	short lcnt;{	register struct dinode *dp;	dp = ginode(idesc->id_number);	if (dp->di_nlink == lcnt) {		if (linkup(idesc->id_number, (ino_t)0) == 0)			clri(idesc, "UNREF", 0);	} else {		pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :			((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));		pinode(idesc->id_number);		printf(" COUNT %d SHOULD BE %d",			dp->di_nlink, dp->di_nlink - lcnt);		if (preen || usedsoftdep) {			if (lcnt < 0) {				printf("\n");				pfatal("LINK COUNT INCREASING");			}			if (preen)				printf(" (ADJUSTED)\n");		}		if (preen || reply("ADJUST") == 1) {			dp->di_nlink -= lcnt;			inodirty();		}	}}static intmkentry(idesc)	struct inodesc *idesc;{	register struct direct *dirp = idesc->id_dirp;	struct direct newent;	int newlen, oldlen;	newent.d_namlen = strlen(idesc->id_name);	newlen = DIRSIZ(0, &newent);	if (dirp->d_ino != 0)		oldlen = DIRSIZ(0, dirp);	else		oldlen = 0;	if (dirp->d_reclen - oldlen < newlen)		return (KEEPON);	newent.d_reclen = dirp->d_reclen - oldlen;	dirp->d_reclen = oldlen;	dirp = (struct direct *)(((char *)dirp) + oldlen);	dirp->d_ino = idesc->id_parent;	/* ino to be entered is in id_parent */	dirp->d_reclen = newent.d_reclen;	if (newinofmt)		dirp->d_type = typemap[idesc->id_parent];	else		dirp->d_type = 0;	dirp->d_namlen = newent.d_namlen;	memcpy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);#	if (BYTE_ORDER == LITTLE_ENDIAN)		/*		 * If the entry was split, dirscan() will only reverse the byte		 * order of the original entry, and not the new one, before		 * writing it back out.  So, we reverse the byte order here if		 * necessary.		 */		if (oldlen != 0 && !newinofmt && !doinglevel2) {			u_char tmp;			tmp = dirp->d_namlen;			dirp->d_namlen = dirp->d_type;			dirp->d_type = tmp;		}#	endif	return (ALTERED|STOP);}static intchgino(idesc)	struct inodesc *idesc;{	register struct direct *dirp = idesc->id_dirp;	if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))		return (KEEPON);	dirp->d_ino = idesc->id_parent;	if (newinofmt)		dirp->d_type = typemap[idesc->id_parent];	else		dirp->d_type = 0;	return (ALTERED|STOP);}intlinkup(orphan, parentdir)	ino_t orphan;	ino_t parentdir;{	register struct dinode *dp;	int lostdir;	ino_t oldlfdir;	struct inodesc idesc;	char tempname[BUFSIZ];	memset(&idesc, 0, sizeof(struct inodesc));	dp = ginode(orphan);	lostdir = (dp->di_mode & IFMT) == IFDIR;	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");	pinode(orphan);	if ((preen || usedsoftdep) && dp->di_size == 0)		return (0);	if (preen)		printf(" (RECONNECTED)\n");	else		if (reply("RECONNECT") == 0)			return (0);	if (parentdir != 0)		lncntp[parentdir]++;	if (lfdir == 0) {		dp = ginode(ROOTINO);		idesc.id_name = lfname;		idesc.id_type = DATA;		idesc.id_func = findino;		idesc.id_number = ROOTINO;		if ((ckinode(dp, &idesc) & FOUND) != 0) {			lfdir = idesc.id_parent;		} else {			pwarn("NO lost+found DIRECTORY");			if (preen || reply("CREATE")) {				lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);				if (lfdir != 0) {					if (makeentry(ROOTINO, lfdir, lfname) != 0) {						if (preen)							printf(" (CREATED)\n");					} else {						freedir(lfdir, ROOTINO);						lfdir = 0;						if (preen)							printf("\n");					}				}			}		}		if (lfdir == 0) {			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");			printf("\n\n");			return (0);		}	}	dp = ginode(lfdir);	if ((dp->di_mode & IFMT) != IFDIR) {		pfatal("lost+found IS NOT A DIRECTORY");		if (reply("REALLOCATE") == 0)			return (0);		oldlfdir = lfdir;		if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");			return (0);		}		if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");			return (0);		}		inodirty();		idesc.id_type = ADDR;		idesc.id_func = pass4check;		idesc.id_number = oldlfdir;		adjust(&idesc, lncntp[oldlfdir] + 1);		lncntp[oldlfdir] = 0;		dp = ginode(lfdir);	}	if (statemap[lfdir] != DFOUND) {		pfatal("SORRY. NO lost+found DIRECTORY\n\n");		return (0);	}	(void)lftempname(tempname, orphan);	if (makeentry(lfdir, orphan, tempname) == 0) {		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");		printf("\n\n");		return (0);	}	lncntp[orphan]--;	if (lostdir) {		if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&		    parentdir != (ino_t)-1)			(void)makeentry(orphan, lfdir, "..");		dp = ginode(lfdir);		dp->di_nlink++;		inodirty();		lncntp[lfdir]++;		pwarn("DIR I=%u CONNECTED. ", orphan);		if (parentdir != (ino_t)-1) {			printf("PARENT WAS I=%u\n", parentdir);			/*			 * The parent directory, because of the ordering			 * guarantees, has had the link count incremented			 * for the child, but no entry was made.  This			 * fixes the parent link count so that fsck does			 * not need to be rerun.			 */			lncntp[parentdir]++;		}		if (preen == 0)			printf("\n");	}	return (1);}/* * fix an entry in a directory. */intchangeino(dir, name, newnum)	ino_t dir;	char *name;	ino_t newnum;{	struct inodesc idesc;	memset(&idesc, 0, sizeof(struct inodesc));	idesc.id_type = DATA;	idesc.id_func = chgino;	idesc.id_number = dir;	idesc.id_fix = DONTKNOW;	idesc.id_name = name;	idesc.id_parent = newnum;	/* new value for name */	return (ckinode(ginode(dir), &idesc));}/* * make an entry in a directory */intmakeentry(parent, ino, name)	ino_t parent, ino;	char *name;{	struct dinode *dp;	struct inodesc idesc;	char pathbuf[MAXPATHLEN + 1];		if (parent < ROOTINO || parent >= maxino ||	    ino < ROOTINO || ino >= maxino)		return (0);	memset(&idesc, 0, sizeof(struct inodesc));	idesc.id_type = DATA;	idesc.id_func = mkentry;	idesc.id_number = parent;	idesc.id_parent = ino;	/* this is the inode to enter */	idesc.id_fix = DONTKNOW;	idesc.id_name = name;	dp = ginode(parent);	if (dp->di_size % DIRBLKSIZ) {		dp->di_size = roundup(dp->di_size, DIRBLKSIZ);		inodirty();	}	if ((ckinode(dp, &idesc) & ALTERED) != 0)		return (1);	getpathname(pathbuf, parent, parent);	dp = ginode(parent);	if (expanddir(dp, pathbuf) == 0)		return (0);	return (ckinode(dp, &idesc) & ALTERED);}/* * Attempt to expand the size of a directory */static intexpanddir(dp, name)	register struct dinode *dp;	char *name;{	daddr_t lastbn, newblk;	register struct bufarea *bp;	char *cp, firstblk[DIRBLKSIZ];	lastbn = lblkno(&sblock, dp->di_size);	if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)		return (0);	if ((newblk = allocblk(sblock.fs_frag)) == 0)		return (0);	dp->di_db[lastbn + 1] = dp->di_db[lastbn];	dp->di_db[lastbn] = newblk;	dp->di_size += sblock.fs_bsize;	dp->di_blocks += btodb(sblock.fs_bsize);	bp = getdirblk(dp->di_db[lastbn + 1],		(long)dblksize(&sblock, dp, lastbn + 1));	if (bp->b_errs)		goto bad;	memcpy(firstblk, bp->b_un.b_buf, DIRBLKSIZ);	bp = getdirblk(newblk, sblock.fs_bsize);	if (bp->b_errs)		goto bad;	memcpy(bp->b_un.b_buf, firstblk, DIRBLKSIZ);	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];	     cp < &bp->b_un.b_buf[sblock.fs_bsize];	     cp += DIRBLKSIZ)		memcpy(cp, &emptydir, sizeof emptydir);	dirty(bp);	bp = getdirblk(dp->di_db[lastbn + 1],		(long)dblksize(&sblock, dp, lastbn + 1));	if (bp->b_errs)		goto bad;	memcpy(bp->b_un.b_buf, &emptydir, sizeof emptydir);	pwarn("NO SPACE LEFT IN %s", name);	if (preen)		printf(" (EXPANDED)\n");	else if (reply("EXPAND") == 0)		goto bad;	dirty(bp);	inodirty();	return (1);bad:	dp->di_db[lastbn] = dp->di_db[lastbn + 1];	dp->di_db[lastbn + 1] = 0;	dp->di_size -= sblock.fs_bsize;	dp->di_blocks -= btodb(sblock.fs_bsize);	freeblk(newblk, sblock.fs_frag);	return (0);}/* * allocate a new directory */intallocdir(parent, request, mode)	ino_t parent, request;	int mode;{	ino_t ino;	char *cp;	struct dinode *dp;	register struct bufarea *bp;	struct dirtemplate *dirp;	ino = allocino(request, IFDIR|mode);	if (newinofmt)		dirp = &dirhead;	else		dirp = (struct dirtemplate *)&odirhead;	dirp->dot_ino = ino;	dirp->dotdot_ino = parent;	dp = ginode(ino);	bp = getdirblk(dp->di_db[0], sblock.fs_fsize);	if (bp->b_errs) {		freeino(ino);		return (0);	}	memcpy(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];	     cp < &bp->b_un.b_buf[sblock.fs_fsize];	     cp += DIRBLKSIZ)		memcpy(cp, &emptydir, sizeof emptydir);	dirty(bp);	dp->di_nlink = 2;	inodirty();	if (ino == ROOTINO) {		lncntp[ino] = dp->di_nlink;		cacheino(dp, ino);		return(ino);	}	if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {		freeino(ino);		return (0);	}	cacheino(dp, ino);	statemap[ino] = statemap[parent];	if (statemap[ino] == DSTATE) {		lncntp[ino] = dp->di_nlink;		lncntp[parent]++;	}	dp = ginode(parent);	dp->di_nlink++;	inodirty();	return (ino);}/* * free a directory inode */static voidfreedir(ino, parent)	ino_t ino, parent;{	struct dinode *dp;	if (ino != parent) {		dp = ginode(parent);		dp->di_nlink--;		inodirty();	}	freeino(ino);}/* * generate a temporary name for the lost+found directory. */static intlftempname(bufp, ino)	char *bufp;	ino_t ino;{	register ino_t in;	register char *cp;	int namlen;	cp = bufp + 2;	for (in = maxino; in > 0; in /= 10)		cp++;	*--cp = 0;	namlen = cp - bufp;	in = ino;	while (cp > bufp) {		*--cp = (in % 10) + '0';		in /= 10;	}	*cp = '#';	return (namlen);}/* * Get a directory block. * Insure that it is held until another is requested. */static struct bufarea *getdirblk(blkno, size)	daddr_t blkno;	long size;{	if (pdirbp != 0)		pdirbp->b_flags &= ~B_INUSE;	pdirbp = getdatablk(blkno, size);	return (pdirbp);}