pass2.c revision 23799
12311Sjkh/*
22311Sjkh * Copyright (c) 1980, 1986, 1993
32311Sjkh *	The Regents of the University of California.  All rights reserved.
42311Sjkh *
52311Sjkh * Redistribution and use in source and binary forms, with or without
62311Sjkh * modification, are permitted provided that the following conditions
72311Sjkh * are met:
82311Sjkh * 1. Redistributions of source code must retain the above copyright
92311Sjkh *    notice, this list of conditions and the following disclaimer.
102311Sjkh * 2. Redistributions in binary form must reproduce the above copyright
112311Sjkh *    notice, this list of conditions and the following disclaimer in the
122311Sjkh *    documentation and/or other materials provided with the distribution.
132311Sjkh * 3. All advertising materials mentioning features or use of this software
142311Sjkh *    must display the following acknowledgement:
152311Sjkh *	This product includes software developed by the University of
165176Sache *	California, Berkeley and its contributors.
172311Sjkh * 4. Neither the name of the University nor the names of its contributors
182311Sjkh *    may be used to endorse or promote products derived from this software
192311Sjkh *    without specific prior written permission.
208857Srgrimes *
212311Sjkh * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
222311Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
232311Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
242311Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
252311Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
262311Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
272311Sjkh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
282311Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
292311Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
302311Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
312311Sjkh * SUCH DAMAGE.
322311Sjkh */
332311Sjkh
342311Sjkh#ifndef lint
352311Sjkhstatic const char sccsid[] = "@(#)pass2.c	8.9 (Berkeley) 4/28/95";
362311Sjkh#endif /* not lint */
372311Sjkh
382311Sjkh#include <sys/param.h>
392311Sjkh#include <sys/time.h>
402311Sjkh
412311Sjkh#include <ufs/ufs/dinode.h>
422311Sjkh#include <ufs/ufs/dir.h>
432311Sjkh#include <ufs/ffs/fs.h>
442311Sjkh
452311Sjkh#include <err.h>
462311Sjkh#include <string.h>
472311Sjkh
482311Sjkh#include "fsck.h"
492311Sjkh
502311Sjkh#define MINDIRSIZE	(sizeof (struct dirtemplate))
512311Sjkh
522311Sjkhstatic int blksort __P((const void *, const void *));
532311Sjkhstatic int pass2check __P((struct inodesc *));
542311Sjkh
552311Sjkhvoid
562311Sjkhpass2()
572311Sjkh{
582311Sjkh	register struct dinode *dp;
592311Sjkh	register struct inoinfo **inpp, *inp;
602311Sjkh	struct inoinfo **inpend;
612311Sjkh	struct inodesc curino;
622311Sjkh	struct dinode dino;
632311Sjkh	char pathbuf[MAXPATHLEN + 1];
642311Sjkh
652311Sjkh	switch (statemap[ROOTINO]) {
662311Sjkh
672311Sjkh	case USTATE:
682311Sjkh		pfatal("ROOT INODE UNALLOCATED");
692311Sjkh		if (reply("ALLOCATE") == 0)
702311Sjkh			exit(EEXIT);
712311Sjkh		if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
722311Sjkh			errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
732311Sjkh		break;
742311Sjkh
752311Sjkh	case DCLEAR:
762311Sjkh		pfatal("DUPS/BAD IN ROOT INODE");
772311Sjkh		if (reply("REALLOCATE")) {
782311Sjkh			freeino(ROOTINO);
792311Sjkh			if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
802311Sjkh				errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
812311Sjkh			break;
822311Sjkh		}
832311Sjkh		if (reply("CONTINUE") == 0)
842311Sjkh			exit(EEXIT);
852311Sjkh		break;
862311Sjkh
872311Sjkh	case FSTATE:
882311Sjkh	case FCLEAR:
892311Sjkh		pfatal("ROOT INODE NOT DIRECTORY");
902311Sjkh		if (reply("REALLOCATE")) {
912311Sjkh			freeino(ROOTINO);
922311Sjkh			if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
932311Sjkh				errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
942311Sjkh			break;
952311Sjkh		}
962311Sjkh		if (reply("FIX") == 0)
972311Sjkh			exit(EEXIT);
982311Sjkh		dp = ginode(ROOTINO);
992311Sjkh		dp->di_mode &= ~IFMT;
1002311Sjkh		dp->di_mode |= IFDIR;
1012311Sjkh		inodirty();
1022311Sjkh		break;
1032311Sjkh
1042311Sjkh	case DSTATE:
1052311Sjkh		break;
1062311Sjkh
1072311Sjkh	default:
1082311Sjkh		errx(EEXIT, "BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
1092311Sjkh	}
1102311Sjkh	statemap[ROOTINO] = DFOUND;
1112311Sjkh	if (newinofmt) {
1122311Sjkh		statemap[WINO] = FSTATE;
1132311Sjkh		typemap[WINO] = DT_WHT;
1142311Sjkh	}
1152311Sjkh	/*
1162311Sjkh	 * Sort the directory list into disk block order.
1172311Sjkh	 */
1182311Sjkh	qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
1192311Sjkh	/*
1202311Sjkh	 * Check the integrity of each directory.
1212311Sjkh	 */
1222311Sjkh	memset(&curino, 0, sizeof(struct inodesc));
1232311Sjkh	curino.id_type = DATA;
1242311Sjkh	curino.id_func = pass2check;
1252311Sjkh	dp = &dino;
1262311Sjkh	inpend = &inpsort[inplast];
1272311Sjkh	for (inpp = inpsort; inpp < inpend; inpp++) {
1282311Sjkh		inp = *inpp;
1292311Sjkh		if (inp->i_isize == 0)
1302311Sjkh			continue;
1312311Sjkh		if (inp->i_isize < MINDIRSIZE) {
1322311Sjkh			direrror(inp->i_number, "DIRECTORY TOO SHORT");
1338857Srgrimes			inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
1342311Sjkh			if (reply("FIX") == 1) {
1352311Sjkh				dp = ginode(inp->i_number);
1362311Sjkh				dp->di_size = inp->i_isize;
1372311Sjkh				inodirty();
1382311Sjkh				dp = &dino;
1392311Sjkh			}
1402311Sjkh		} else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
1412311Sjkh			getpathname(pathbuf, inp->i_number, inp->i_number);
1422311Sjkh			pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
1432311Sjkh				pathbuf, inp->i_isize, DIRBLKSIZ);
1442311Sjkh			if (preen)
1452311Sjkh				printf(" (ADJUSTED)\n");
1462311Sjkh			inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
1472311Sjkh			if (preen || reply("ADJUST") == 1) {
1482311Sjkh				dp = ginode(inp->i_number);
1492311Sjkh				dp->di_size = roundup(inp->i_isize, DIRBLKSIZ);
1502311Sjkh				inodirty();
1512311Sjkh				dp = &dino;
1522311Sjkh			}
1532311Sjkh		}
1542311Sjkh		memset(&dino, 0, sizeof(struct dinode));
1552311Sjkh		dino.di_mode = IFDIR;
1562311Sjkh		dp->di_size = inp->i_isize;
1572311Sjkh		memmove(&dp->di_db[0], &inp->i_blks[0], (size_t)inp->i_numblks);
1582311Sjkh		curino.id_number = inp->i_number;
1592311Sjkh		curino.id_parent = inp->i_parent;
1602311Sjkh		(void)ckinode(dp, &curino);
1612311Sjkh	}
1622311Sjkh	/*
1632311Sjkh	 * Now that the parents of all directories have been found,
1642311Sjkh	 * make another pass to verify the value of `..'
1652311Sjkh	 */
1662311Sjkh	for (inpp = inpsort; inpp < inpend; inpp++) {
1672311Sjkh		inp = *inpp;
1682311Sjkh		if (inp->i_parent == 0 || inp->i_isize == 0)
1692311Sjkh			continue;
1702311Sjkh		if (statemap[inp->i_parent] == DFOUND &&
1712311Sjkh		    statemap[inp->i_number] == DSTATE)
1722311Sjkh			statemap[inp->i_number] = DFOUND;
1732311Sjkh		if (inp->i_dotdot == inp->i_parent ||
1742311Sjkh		    inp->i_dotdot == (ino_t)-1)
1752311Sjkh			continue;
1762311Sjkh		if (inp->i_dotdot == 0) {
1772311Sjkh			inp->i_dotdot = inp->i_parent;
1782311Sjkh			fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
1792311Sjkh			if (reply("FIX") == 0)
1802311Sjkh				continue;
1812311Sjkh			(void)makeentry(inp->i_number, inp->i_parent, "..");
1822311Sjkh			lncntp[inp->i_parent]--;
1832311Sjkh			continue;
1842311Sjkh		}
1852311Sjkh		fileerror(inp->i_parent, inp->i_number,
1862311Sjkh		    "BAD INODE NUMBER FOR '..'");
1872311Sjkh		if (reply("FIX") == 0)
1882311Sjkh			continue;
1892311Sjkh		lncntp[inp->i_dotdot]++;
1902311Sjkh		lncntp[inp->i_parent]--;
1912311Sjkh		inp->i_dotdot = inp->i_parent;
1922311Sjkh		(void)changeino(inp->i_number, "..", inp->i_parent);
1932311Sjkh	}
1942311Sjkh	/*
1952311Sjkh	 * Mark all the directories that can be found from the root.
1962311Sjkh	 */
1972311Sjkh	propagate();
1982311Sjkh}
1992311Sjkh
2002311Sjkhstatic int
2012311Sjkhpass2check(idesc)
2022311Sjkh	struct inodesc *idesc;
2032311Sjkh{
2042311Sjkh	register struct direct *dirp = idesc->id_dirp;
2052311Sjkh	register struct inoinfo *inp;
2062311Sjkh	int n, entrysize, ret = 0;
2072311Sjkh	struct dinode *dp;
2082311Sjkh	char *errmsg;
2092311Sjkh	struct direct proto;
2102311Sjkh	char namebuf[MAXPATHLEN + 1];
2112311Sjkh	char pathbuf[MAXPATHLEN + 1];
2122311Sjkh
2132311Sjkh	/*
2142311Sjkh	 * If converting, set directory entry type.
2152311Sjkh	 */
2162311Sjkh	if (doinglevel2 && dirp->d_ino > 0 && dirp->d_ino < maxino) {
2172311Sjkh		dirp->d_type = typemap[dirp->d_ino];
2182311Sjkh		ret |= ALTERED;
2192311Sjkh	}
2202311Sjkh	/*
2212311Sjkh	 * check for "."
2222311Sjkh	 */
2232311Sjkh	if (idesc->id_entryno != 0)
2242311Sjkh		goto chk1;
2252311Sjkh	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
2262311Sjkh		if (dirp->d_ino != idesc->id_number) {
2272311Sjkh			direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
2282311Sjkh			dirp->d_ino = idesc->id_number;
2292311Sjkh			if (reply("FIX") == 1)
2302311Sjkh				ret |= ALTERED;
2312311Sjkh		}
2322311Sjkh		if (newinofmt && dirp->d_type != DT_DIR) {
2332311Sjkh			direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
2342311Sjkh			dirp->d_type = DT_DIR;
2352311Sjkh			if (reply("FIX") == 1)
2362311Sjkh				ret |= ALTERED;
2372311Sjkh		}
2382311Sjkh		goto chk1;
2392311Sjkh	}
2402311Sjkh	direrror(idesc->id_number, "MISSING '.'");
2412311Sjkh	proto.d_ino = idesc->id_number;
2422311Sjkh	if (newinofmt)
2432311Sjkh		proto.d_type = DT_DIR;
2442311Sjkh	else
2452311Sjkh		proto.d_type = 0;
2462311Sjkh	proto.d_namlen = 1;
2472311Sjkh	(void)strcpy(proto.d_name, ".");
2482311Sjkh#	if BYTE_ORDER == LITTLE_ENDIAN
2492311Sjkh		if (!newinofmt) {
2502311Sjkh			u_char tmp;
2512311Sjkh
2522311Sjkh			tmp = proto.d_type;
2532311Sjkh			proto.d_type = proto.d_namlen;
2542311Sjkh			proto.d_namlen = tmp;
2552311Sjkh		}
2562311Sjkh#	endif
2572311Sjkh	entrysize = DIRSIZ(0, &proto);
2582311Sjkh	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
2592311Sjkh		pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
2602311Sjkh			dirp->d_name);
2612311Sjkh	} else if (dirp->d_reclen < entrysize) {
2622311Sjkh		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
2632311Sjkh	} else if (dirp->d_reclen < 2 * entrysize) {
2642311Sjkh		proto.d_reclen = dirp->d_reclen;
2652311Sjkh		memmove(dirp, &proto, (size_t)entrysize);
2662311Sjkh		if (reply("FIX") == 1)
2672311Sjkh			ret |= ALTERED;
2682311Sjkh	} else {
2692311Sjkh		n = dirp->d_reclen - entrysize;
2702311Sjkh		proto.d_reclen = entrysize;
2712311Sjkh		memmove(dirp, &proto, (size_t)entrysize);
2722311Sjkh		idesc->id_entryno++;
2732311Sjkh		lncntp[dirp->d_ino]--;
2742311Sjkh		dirp = (struct direct *)((char *)(dirp) + entrysize);
2752311Sjkh		memset(dirp, 0, (size_t)n);
2762311Sjkh		dirp->d_reclen = n;
2772311Sjkh		if (reply("FIX") == 1)
2782311Sjkh			ret |= ALTERED;
2792311Sjkh	}
2802311Sjkhchk1:
2812311Sjkh	if (idesc->id_entryno > 1)
2822311Sjkh		goto chk2;
2832311Sjkh	inp = getinoinfo(idesc->id_number);
2842311Sjkh	proto.d_ino = inp->i_parent;
2852311Sjkh	if (newinofmt)
2862311Sjkh		proto.d_type = DT_DIR;
2872311Sjkh	else
2882311Sjkh		proto.d_type = 0;
2892311Sjkh	proto.d_namlen = 2;
2902311Sjkh	(void)strcpy(proto.d_name, "..");
2912311Sjkh#	if BYTE_ORDER == LITTLE_ENDIAN
2922311Sjkh		if (!newinofmt) {
2932311Sjkh			u_char tmp;
2942311Sjkh
2952311Sjkh			tmp = proto.d_type;
2962311Sjkh			proto.d_type = proto.d_namlen;
2972311Sjkh			proto.d_namlen = tmp;
2982311Sjkh		}
2992311Sjkh#	endif
3002311Sjkh	entrysize = DIRSIZ(0, &proto);
3012311Sjkh	if (idesc->id_entryno == 0) {
3022311Sjkh		n = DIRSIZ(0, dirp);
3032311Sjkh		if (dirp->d_reclen < n + entrysize)
3042311Sjkh			goto chk2;
3052311Sjkh		proto.d_reclen = dirp->d_reclen - n;
3062311Sjkh		dirp->d_reclen = n;
3072311Sjkh		idesc->id_entryno++;
3082311Sjkh		lncntp[dirp->d_ino]--;
3092311Sjkh		dirp = (struct direct *)((char *)(dirp) + n);
3102311Sjkh		memset(dirp, 0, (size_t)proto.d_reclen);
3112311Sjkh		dirp->d_reclen = proto.d_reclen;
3122311Sjkh	}
3132311Sjkh	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
3142311Sjkh		inp->i_dotdot = dirp->d_ino;
3152311Sjkh		if (newinofmt && dirp->d_type != DT_DIR) {
3162311Sjkh			direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
3172311Sjkh			dirp->d_type = DT_DIR;
3182311Sjkh			if (reply("FIX") == 1)
3192311Sjkh				ret |= ALTERED;
3202311Sjkh		}
3212311Sjkh		goto chk2;
3222311Sjkh	}
3232311Sjkh	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
3242311Sjkh		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
3252311Sjkh		pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
3262311Sjkh			dirp->d_name);
3272311Sjkh		inp->i_dotdot = (ino_t)-1;
3282311Sjkh	} else if (dirp->d_reclen < entrysize) {
3292311Sjkh		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
3302311Sjkh		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
3312311Sjkh		inp->i_dotdot = (ino_t)-1;
3325176Sache	} else if (inp->i_parent != 0) {
3332311Sjkh		/*
3342311Sjkh		 * We know the parent, so fix now.
3352311Sjkh		 */
3362311Sjkh		inp->i_dotdot = inp->i_parent;
3372311Sjkh		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
3382311Sjkh		proto.d_reclen = dirp->d_reclen;
3392311Sjkh		memmove(dirp, &proto, (size_t)entrysize);
3402311Sjkh		if (reply("FIX") == 1)
3412311Sjkh			ret |= ALTERED;
3422311Sjkh	}
3432311Sjkh	idesc->id_entryno++;
3442311Sjkh	if (dirp->d_ino != 0)
3452311Sjkh		lncntp[dirp->d_ino]--;
3462311Sjkh	return (ret|KEEPON);
3472311Sjkhchk2:
3482311Sjkh	if (dirp->d_ino == 0)
3492311Sjkh		return (ret|KEEPON);
3502311Sjkh	if (dirp->d_namlen <= 2 &&
3512311Sjkh	    dirp->d_name[0] == '.' &&
3522311Sjkh	    idesc->id_entryno >= 2) {
3532311Sjkh		if (dirp->d_namlen == 1) {
3542311Sjkh			direrror(idesc->id_number, "EXTRA '.' ENTRY");
3552311Sjkh			dirp->d_ino = 0;
3562311Sjkh			if (reply("FIX") == 1)
3572311Sjkh				ret |= ALTERED;
3582311Sjkh			return (KEEPON | ret);
3592311Sjkh		}
3602311Sjkh		if (dirp->d_name[1] == '.') {
3612311Sjkh			direrror(idesc->id_number, "EXTRA '..' ENTRY");
3625176Sache			dirp->d_ino = 0;
3632311Sjkh			if (reply("FIX") == 1)
3642311Sjkh				ret |= ALTERED;
3652311Sjkh			return (KEEPON | ret);
3662311Sjkh		}
3675176Sache	}
3685176Sache	idesc->id_entryno++;
3692311Sjkh	n = 0;
3702311Sjkh	if (dirp->d_ino > maxino) {
3712311Sjkh		fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
3722311Sjkh		n = reply("REMOVE");
3732311Sjkh	} else if (newinofmt &&
3742311Sjkh		   ((dirp->d_ino == WINO && dirp->d_type != DT_WHT) ||
3752311Sjkh		    (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) {
3762311Sjkh		fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
3772311Sjkh		dirp->d_ino = WINO;
3782311Sjkh		dirp->d_type = DT_WHT;
3792311Sjkh		if (reply("FIX") == 1)
3802311Sjkh			ret |= ALTERED;
3812311Sjkh	} else {
3822311Sjkhagain:
3832311Sjkh		switch (statemap[dirp->d_ino]) {
3842311Sjkh		case USTATE:
3852311Sjkh			if (idesc->id_entryno <= 2)
3862311Sjkh				break;
3872311Sjkh			fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
3882311Sjkh			n = reply("REMOVE");
3892311Sjkh			break;
3902311Sjkh
3912311Sjkh		case DCLEAR:
3922311Sjkh		case FCLEAR:
3932311Sjkh			if (idesc->id_entryno <= 2)
3942311Sjkh				break;
3952311Sjkh			if (statemap[dirp->d_ino] == FCLEAR)
3962311Sjkh				errmsg = "DUP/BAD";
3972311Sjkh			else if (!preen)
3982311Sjkh				errmsg = "ZERO LENGTH DIRECTORY";
3992311Sjkh			else {
4002311Sjkh				n = 1;
4012311Sjkh				break;
4022311Sjkh			}
4032311Sjkh			fileerror(idesc->id_number, dirp->d_ino, errmsg);
4042311Sjkh			if ((n = reply("REMOVE")) == 1)
4052311Sjkh				break;
4062311Sjkh			dp = ginode(dirp->d_ino);
4072311Sjkh			statemap[dirp->d_ino] =
4082311Sjkh			    (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
4092311Sjkh			lncntp[dirp->d_ino] = dp->di_nlink;
4102311Sjkh			goto again;
4112311Sjkh
4122311Sjkh		case DSTATE:
4132311Sjkh			if (statemap[idesc->id_number] == DFOUND)
4142311Sjkh				statemap[dirp->d_ino] = DFOUND;
4152311Sjkh			/* fall through */
4162311Sjkh
4172311Sjkh		case DFOUND:
4182311Sjkh			inp = getinoinfo(dirp->d_ino);
4192311Sjkh			if (inp->i_parent != 0 && idesc->id_entryno > 2) {
4202311Sjkh				getpathname(pathbuf, idesc->id_number,
4212311Sjkh				    idesc->id_number);
4222311Sjkh				getpathname(namebuf, dirp->d_ino, dirp->d_ino);
4232311Sjkh				pwarn("%s %s %s\n", pathbuf,
4242311Sjkh				    "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
4252311Sjkh				    namebuf);
4262311Sjkh				if (preen)
4272311Sjkh					printf(" (IGNORED)\n");
4282311Sjkh				else if ((n = reply("REMOVE")) == 1)
4292311Sjkh					break;
4302311Sjkh			}
4312311Sjkh			if (idesc->id_entryno > 2)
4322311Sjkh				inp->i_parent = idesc->id_number;
4332311Sjkh			/* fall through */
4342311Sjkh
4352311Sjkh		case FSTATE:
4365176Sache			if (newinofmt && dirp->d_type != typemap[dirp->d_ino]) {
4375176Sache				fileerror(idesc->id_number, dirp->d_ino,
4382311Sjkh				    "BAD TYPE VALUE");
4392311Sjkh				dirp->d_type = typemap[dirp->d_ino];
4402311Sjkh				if (reply("FIX") == 1)
4412311Sjkh					ret |= ALTERED;
4422311Sjkh			}
4432311Sjkh			lncntp[dirp->d_ino]--;
4442311Sjkh			break;
4452311Sjkh
4465176Sache		default:
4475176Sache			errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
4485176Sache			    statemap[dirp->d_ino], dirp->d_ino);
4495176Sache		}
4502311Sjkh	}
4512311Sjkh	if (n == 0)
4522311Sjkh		return (ret|KEEPON);
4532311Sjkh	dirp->d_ino = 0;
4542311Sjkh	return (ret|KEEPON|ALTERED);
4552311Sjkh}
4562311Sjkh
4572311Sjkh/*
4582311Sjkh * Routine to sort disk blocks.
4592311Sjkh */
4602311Sjkhstatic int
4612311Sjkhblksort(arg1, arg2)
4622311Sjkh	const void *arg1, *arg2;
4632311Sjkh{
4642311Sjkh
4652311Sjkh	return ((*(struct inoinfo **)arg1)->i_blks[0] -
4662311Sjkh		(*(struct inoinfo **)arg2)->i_blks[0]);
4672311Sjkh}
4682311Sjkh