pass2.c revision 23675
1251538Srpaulo/*
2251538Srpaulo * Copyright (c) 1980, 1986, 1993
3251538Srpaulo *	The Regents of the University of California.  All rights reserved.
4251538Srpaulo *
5264912Skevlo * Redistribution and use in source and binary forms, with or without
6292176Savos * modification, are permitted provided that the following conditions
7251538Srpaulo * are met:
8251538Srpaulo * 1. Redistributions of source code must retain the above copyright
9251538Srpaulo *    notice, this list of conditions and the following disclaimer.
10251538Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
11251538Srpaulo *    notice, this list of conditions and the following disclaimer in the
12251538Srpaulo *    documentation and/or other materials provided with the distribution.
13251538Srpaulo * 3. All advertising materials mentioning features or use of this software
14251538Srpaulo *    must display the following acknowledgement:
15251538Srpaulo *	This product includes software developed by the University of
16251538Srpaulo *	California, Berkeley and its contributors.
17251538Srpaulo * 4. Neither the name of the University nor the names of its contributors
18251538Srpaulo *    may be used to endorse or promote products derived from this software
19251538Srpaulo *    without specific prior written permission.
20251538Srpaulo *
21251538Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22251538Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23251538Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24251538Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25264912Skevlo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26251538Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27251538Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28288353Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29288353Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30251538Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31251538Srpaulo * SUCH DAMAGE.
32251538Srpaulo */
33251538Srpaulo
34251538Srpaulo#ifndef lint
35291902Skevlostatic const char sccsid[] = "@(#)pass2.c	8.9 (Berkeley) 4/28/95";
36251538Srpaulo#endif /* not lint */
37251538Srpaulo
38251538Srpaulo#include <sys/param.h>
39251538Srpaulo#include <sys/time.h>
40251538Srpaulo
41251538Srpaulo#include <ufs/ufs/dinode.h>
42251538Srpaulo#include <ufs/ufs/dir.h>
43251538Srpaulo#include <ufs/ffs/fs.h>
44251538Srpaulo#include <stdio.h>
45251538Srpaulo#include <stdlib.h>
46251538Srpaulo#include <err.h>
47251538Srpaulo#include <string.h>
48251538Srpaulo
49251538Srpaulo#include "fsck.h"
50251538Srpaulo
51251538Srpaulo#define MINDIRSIZE	(sizeof (struct dirtemplate))
52251538Srpaulo
53251538Srpaulostatic int blksort __P((const void *, const void *));
54257176Sglebiusstatic int pass2check __P((struct inodesc *));
55251538Srpaulo
56251538Srpaulovoid
57251538Srpaulopass2()
58251538Srpaulo{
59251538Srpaulo	register struct dinode *dp;
60251538Srpaulo	register struct inoinfo **inpp, *inp;
61251538Srpaulo	struct inoinfo **inpend;
62251538Srpaulo	struct inodesc curino;
63251538Srpaulo	struct dinode dino;
64251538Srpaulo	char pathbuf[MAXPATHLEN + 1];
65251538Srpaulo
66251538Srpaulo	switch (statemap[ROOTINO]) {
67251538Srpaulo
68288088Sadrian	case USTATE:
69251538Srpaulo		pfatal("ROOT INODE UNALLOCATED");
70251538Srpaulo		if (reply("ALLOCATE") == 0)
71251538Srpaulo			exit(EEXIT);
72251538Srpaulo		if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
73251538Srpaulo			errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
74251538Srpaulo		break;
75291902Skevlo
76251538Srpaulo	case DCLEAR:
77251538Srpaulo		pfatal("DUPS/BAD IN ROOT INODE");
78251538Srpaulo		if (reply("REALLOCATE")) {
79251538Srpaulo			freeino(ROOTINO);
80251538Srpaulo			if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
81251538Srpaulo				errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
82289167Sadrian			break;
83251538Srpaulo		}
84251538Srpaulo		if (reply("CONTINUE") == 0)
85251538Srpaulo			exit(EEXIT);
86251538Srpaulo		break;
87251538Srpaulo
88276701Shselasky	case FSTATE:
89251538Srpaulo	case FCLEAR:
90251538Srpaulo		pfatal("ROOT INODE NOT DIRECTORY");
91251538Srpaulo		if (reply("REALLOCATE")) {
92288088Sadrian			freeino(ROOTINO);
93251538Srpaulo			if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO)
94251538Srpaulo				errx(EEXIT, "CANNOT ALLOCATE ROOT INODE");
95251596Srpaulo			break;
96251538Srpaulo		}
97264912Skevlo		if (reply("FIX") == 0)
98264912Skevlo			exit(EEXIT);
99264912Skevlo		dp = ginode(ROOTINO);
100251538Srpaulo		dp->di_mode &= ~IFMT;
101251538Srpaulo		dp->di_mode |= IFDIR;
102251538Srpaulo		inodirty();
103251538Srpaulo		break;
104266721Skevlo
105251538Srpaulo	case DSTATE:
106251538Srpaulo		break;
107251538Srpaulo
108251538Srpaulo	default:
109251538Srpaulo		errx(EEXIT, "BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]);
110251538Srpaulo	}
111251538Srpaulo	statemap[ROOTINO] = DFOUND;
112251538Srpaulo	if (newinofmt) {
113251538Srpaulo		statemap[WINO] = FSTATE;
114251538Srpaulo		typemap[WINO] = DT_WHT;
115251538Srpaulo	}
116251538Srpaulo	/*
117251538Srpaulo	 * Sort the directory list into disk block order.
118251538Srpaulo	 */
119251538Srpaulo	qsort((char *)inpsort, (size_t)inplast, sizeof *inpsort, blksort);
120251538Srpaulo	/*
121252196Skevlo	 * Check the integrity of each directory.
122251538Srpaulo	 */
123251538Srpaulo	memset(&curino, 0, sizeof(struct inodesc));
124251538Srpaulo	curino.id_type = DATA;
125251538Srpaulo	curino.id_func = pass2check;
126251538Srpaulo	dp = &dino;
127251538Srpaulo	inpend = &inpsort[inplast];
128251538Srpaulo	for (inpp = inpsort; inpp < inpend; inpp++) {
129251538Srpaulo		inp = *inpp;
130251538Srpaulo		if (inp->i_isize == 0)
131251538Srpaulo			continue;
132251538Srpaulo		if (inp->i_isize < MINDIRSIZE) {
133251538Srpaulo			direrror(inp->i_number, "DIRECTORY TOO SHORT");
134251538Srpaulo			inp->i_isize = roundup(MINDIRSIZE, DIRBLKSIZ);
135251538Srpaulo			if (reply("FIX") == 1) {
136251538Srpaulo				dp = ginode(inp->i_number);
137251538Srpaulo				dp->di_size = inp->i_isize;
138251538Srpaulo				inodirty();
139251538Srpaulo				dp = &dino;
140251538Srpaulo			}
141251538Srpaulo		} else if ((inp->i_isize & (DIRBLKSIZ - 1)) != 0) {
142251538Srpaulo			getpathname(pathbuf, inp->i_number, inp->i_number);
143251538Srpaulo			pwarn("DIRECTORY %s: LENGTH %d NOT MULTIPLE OF %d",
144251538Srpaulo				pathbuf, inp->i_isize, DIRBLKSIZ);
145282119Skevlo			if (preen)
146251538Srpaulo				printf(" (ADJUSTED)\n");
147251538Srpaulo			inp->i_isize = roundup(inp->i_isize, DIRBLKSIZ);
148251538Srpaulo			if (preen || reply("ADJUST") == 1) {
149251538Srpaulo				dp = ginode(inp->i_number);
150272410Shselasky				dp->di_size = roundup(inp->i_isize, DIRBLKSIZ);
151251538Srpaulo				inodirty();
152251538Srpaulo				dp = &dino;
153251538Srpaulo			}
154251538Srpaulo		}
155251538Srpaulo		memset(&dino, 0, sizeof(struct dinode));
156251538Srpaulo		dino.di_mode = IFDIR;
157251538Srpaulo		dp->di_size = inp->i_isize;
158251538Srpaulo		memmove(&dp->di_db[0], &inp->i_blks[0], (size_t)inp->i_numblks);
159251538Srpaulo		curino.id_number = inp->i_number;
160264912Skevlo		curino.id_parent = inp->i_parent;
161273589Skevlo		(void)ckinode(dp, &curino);
162270191Skevlo	}
163273589Skevlo	/*
164264912Skevlo	 * Now that the parents of all directories have been found,
165264912Skevlo	 * make another pass to verify the value of `..'
166264912Skevlo	 */
167251538Srpaulo	for (inpp = inpsort; inpp < inpend; inpp++) {
168251538Srpaulo		inp = *inpp;
169251538Srpaulo		if (inp->i_parent == 0 || inp->i_isize == 0)
170251538Srpaulo			continue;
171251538Srpaulo		if (statemap[inp->i_parent] == DFOUND &&
172251538Srpaulo		    statemap[inp->i_number] == DSTATE)
173251538Srpaulo			statemap[inp->i_number] = DFOUND;
174251538Srpaulo		if (inp->i_dotdot == inp->i_parent ||
175251538Srpaulo		    inp->i_dotdot == (ino_t)-1)
176251538Srpaulo			continue;
177288353Sadrian		if (inp->i_dotdot == 0) {
178287197Sglebius			inp->i_dotdot = inp->i_parent;
179287197Sglebius			fileerror(inp->i_parent, inp->i_number, "MISSING '..'");
180251538Srpaulo			if (reply("FIX") == 0)
181251538Srpaulo				continue;
182251538Srpaulo			(void)makeentry(inp->i_number, inp->i_parent, "..");
183251538Srpaulo			lncntp[inp->i_parent]--;
184251538Srpaulo			continue;
185292207Savos		}
186292207Savos		fileerror(inp->i_parent, inp->i_number,
187292207Savos		    "BAD INODE NUMBER FOR '..'");
188292207Savos		if (reply("FIX") == 0)
189292207Savos			continue;
190292167Savos		lncntp[inp->i_dotdot]++;
191292167Savos		lncntp[inp->i_parent]--;
192292207Savos		inp->i_dotdot = inp->i_parent;
193292207Savos		(void)changeino(inp->i_number, "..", inp->i_parent);
194289891Savos	}
195289891Savos	/*
196281069Srpaulo	 * Mark all the directories that can be found from the root.
197251538Srpaulo	 */
198251538Srpaulo	propagate();
199251538Srpaulo}
200251538Srpaulo
201251538Srpaulostatic int
202289066Skevlopass2check(idesc)
203289066Skevlo	struct inodesc *idesc;
204251538Srpaulo{
205251538Srpaulo	register struct direct *dirp = idesc->id_dirp;
206291698Savos	register struct inoinfo *inp;
207251538Srpaulo	int n, entrysize, ret = 0;
208291698Savos	struct dinode *dp;
209291698Savos	char *errmsg;
210291698Savos	struct direct proto;
211291698Savos	char namebuf[MAXPATHLEN + 1];
212251538Srpaulo	char pathbuf[MAXPATHLEN + 1];
213251538Srpaulo
214251538Srpaulo	/*
215251538Srpaulo	 * If converting, set directory entry type.
216281069Srpaulo	 */
217251538Srpaulo	if (doinglevel2 && dirp->d_ino > 0 && dirp->d_ino < maxino) {
218292174Savos		dirp->d_type = typemap[dirp->d_ino];
219292174Savos		ret |= ALTERED;
220292174Savos	}
221264912Skevlo	/*
222264912Skevlo	 * check for "."
223281069Srpaulo	 */
224264912Skevlo	if (idesc->id_entryno != 0)
225251538Srpaulo		goto chk1;
226281069Srpaulo	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) {
227251538Srpaulo		if (dirp->d_ino != idesc->id_number) {
228291264Savos			direrror(idesc->id_number, "BAD INODE NUMBER FOR '.'");
229291264Savos			dirp->d_ino = idesc->id_number;
230291264Savos			if (reply("FIX") == 1)
231291264Savos				ret |= ALTERED;
232291264Savos		}
233291264Savos		if (newinofmt && dirp->d_type != DT_DIR) {
234291264Savos			direrror(idesc->id_number, "BAD TYPE VALUE FOR '.'");
235291264Savos			dirp->d_type = DT_DIR;
236291264Savos			if (reply("FIX") == 1)
237291698Savos				ret |= ALTERED;
238251538Srpaulo		}
239291264Savos		goto chk1;
240291264Savos	}
241251538Srpaulo	direrror(idesc->id_number, "MISSING '.'");
242290631Savos	proto.d_ino = idesc->id_number;
243290631Savos	if (newinofmt)
244290631Savos		proto.d_type = DT_DIR;
245290631Savos	else
246290631Savos		proto.d_type = 0;
247290631Savos	proto.d_namlen = 1;
248290631Savos	(void)strcpy(proto.d_name, ".");
249292175Savos#	if BYTE_ORDER == LITTLE_ENDIAN
250292175Savos		if (!newinofmt) {
251292175Savos			u_char tmp;
252292175Savos
253292175Savos			tmp = proto.d_type;
254292175Savos			proto.d_type = proto.d_namlen;
255292175Savos			proto.d_namlen = tmp;
256292175Savos		}
257292175Savos#	endif
258292175Savos	entrysize = DIRSIZ(0, &proto);
259292175Savos	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) {
260290651Savos		pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
261290631Savos			dirp->d_name);
262290631Savos	} else if (dirp->d_reclen < entrysize) {
263292203Savos		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
264251538Srpaulo	} else if (dirp->d_reclen < 2 * entrysize) {
265289811Savos		proto.d_reclen = dirp->d_reclen;
266290651Savos		memmove(dirp, &proto, (size_t)entrysize);
267290651Savos		if (reply("FIX") == 1)
268290651Savos			ret |= ALTERED;
269281069Srpaulo	} else {
270251538Srpaulo		n = dirp->d_reclen - entrysize;
271251538Srpaulo		proto.d_reclen = entrysize;
272251538Srpaulo		memmove(dirp, &proto, (size_t)entrysize);
273251538Srpaulo		idesc->id_entryno++;
274264912Skevlo		lncntp[dirp->d_ino]--;
275290630Savos		dirp = (struct direct *)((char *)(dirp) + entrysize);
276251538Srpaulo		memset(dirp, 0, (size_t)n);
277251538Srpaulo		dirp->d_reclen = n;
278292221Savos		if (reply("FIX") == 1)
279292221Savos			ret |= ALTERED;
280292221Savos	}
281292221Savoschk1:
282290630Savos	if (idesc->id_entryno > 1)
283290630Savos		goto chk2;
284287197Sglebius	inp = getinoinfo(idesc->id_number);
285287197Sglebius	proto.d_ino = inp->i_parent;
286287197Sglebius	if (newinofmt)
287264912Skevlo		proto.d_type = DT_DIR;
288264912Skevlo	else
289251538Srpaulo		proto.d_type = 0;
290251538Srpaulo	proto.d_namlen = 2;
291264912Skevlo	(void)strcpy(proto.d_name, "..");
292281069Srpaulo#	if BYTE_ORDER == LITTLE_ENDIAN
293251538Srpaulo		if (!newinofmt) {
294251538Srpaulo			u_char tmp;
295291902Skevlo
296291698Savos			tmp = proto.d_type;
297251538Srpaulo			proto.d_type = proto.d_namlen;
298251538Srpaulo			proto.d_namlen = tmp;
299251538Srpaulo		}
300292175Savos#	endif
301292175Savos	entrysize = DIRSIZ(0, &proto);
302251538Srpaulo	if (idesc->id_entryno == 0) {
303251538Srpaulo		n = DIRSIZ(0, dirp);
304251538Srpaulo		if (dirp->d_reclen < n + entrysize)
305281069Srpaulo			goto chk2;
306251538Srpaulo		proto.d_reclen = dirp->d_reclen - n;
307251538Srpaulo		dirp->d_reclen = n;
308281069Srpaulo		idesc->id_entryno++;
309251538Srpaulo		lncntp[dirp->d_ino]--;
310264912Skevlo		dirp = (struct direct *)((char *)(dirp) + n);
311281069Srpaulo		memset(dirp, 0, (size_t)proto.d_reclen);
312264912Skevlo		dirp->d_reclen = proto.d_reclen;
313251538Srpaulo	}
314281069Srpaulo	if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) {
315251538Srpaulo		inp->i_dotdot = dirp->d_ino;
316290048Savos		if (newinofmt && dirp->d_type != DT_DIR) {
317290048Savos			direrror(idesc->id_number, "BAD TYPE VALUE FOR '..'");
318251538Srpaulo			dirp->d_type = DT_DIR;
319251538Srpaulo			if (reply("FIX") == 1)
320251538Srpaulo				ret |= ALTERED;
321292014Savos		}
322290564Savos		goto chk2;
323290564Savos	}
324289066Skevlo	if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) {
325292167Savos		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
326292167Savos		pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
327292167Savos			dirp->d_name);
328292167Savos		inp->i_dotdot = (ino_t)-1;
329251538Srpaulo	} else if (dirp->d_reclen < entrysize) {
330281069Srpaulo		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
331251538Srpaulo		pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
332251538Srpaulo		inp->i_dotdot = (ino_t)-1;
333251538Srpaulo	} else if (inp->i_parent != 0) {
334291698Savos		/*
335287197Sglebius		 * We know the parent, so fix now.
336251538Srpaulo		 */
337251538Srpaulo		inp->i_dotdot = inp->i_parent;
338251538Srpaulo		fileerror(inp->i_parent, idesc->id_number, "MISSING '..'");
339266472Shselasky		proto.d_reclen = dirp->d_reclen;
340251538Srpaulo		memmove(dirp, &proto, (size_t)entrysize);
341251538Srpaulo		if (reply("FIX") == 1)
342251538Srpaulo			ret |= ALTERED;
343251538Srpaulo	}
344251538Srpaulo	idesc->id_entryno++;
345251538Srpaulo	if (dirp->d_ino != 0)
346251538Srpaulo		lncntp[dirp->d_ino]--;
347251538Srpaulo	return (ret|KEEPON);
348251538Srpaulochk2:
349251538Srpaulo	if (dirp->d_ino == 0)
350251538Srpaulo		return (ret|KEEPON);
351251538Srpaulo	if (dirp->d_namlen <= 2 &&
352251538Srpaulo	    dirp->d_name[0] == '.' &&
353251538Srpaulo	    idesc->id_entryno >= 2) {
354251538Srpaulo		if (dirp->d_namlen == 1) {
355251538Srpaulo			direrror(idesc->id_number, "EXTRA '.' ENTRY");
356251538Srpaulo			dirp->d_ino = 0;
357251538Srpaulo			if (reply("FIX") == 1)
358251538Srpaulo				ret |= ALTERED;
359251538Srpaulo			return (KEEPON | ret);
360251538Srpaulo		}
361251538Srpaulo		if (dirp->d_name[1] == '.') {
362251538Srpaulo			direrror(idesc->id_number, "EXTRA '..' ENTRY");
363251538Srpaulo			dirp->d_ino = 0;
364251538Srpaulo			if (reply("FIX") == 1)
365251538Srpaulo				ret |= ALTERED;
366251538Srpaulo			return (KEEPON | ret);
367251538Srpaulo		}
368251538Srpaulo	}
369251538Srpaulo	idesc->id_entryno++;
370251538Srpaulo	n = 0;
371251538Srpaulo	if (dirp->d_ino > maxino) {
372251538Srpaulo		fileerror(idesc->id_number, dirp->d_ino, "I OUT OF RANGE");
373251538Srpaulo		n = reply("REMOVE");
374251538Srpaulo	} else if (newinofmt &&
375251538Srpaulo		   ((dirp->d_ino == WINO && dirp->d_type != DT_WHT) ||
376251538Srpaulo		    (dirp->d_ino != WINO && dirp->d_type == DT_WHT))) {
377251538Srpaulo		fileerror(idesc->id_number, dirp->d_ino, "BAD WHITEOUT ENTRY");
378251538Srpaulo		dirp->d_ino = WINO;
379251538Srpaulo		dirp->d_type = DT_WHT;
380251538Srpaulo		if (reply("FIX") == 1)
381251538Srpaulo			ret |= ALTERED;
382251538Srpaulo	} else {
383251538Srpauloagain:
384251538Srpaulo		switch (statemap[dirp->d_ino]) {
385251538Srpaulo		case USTATE:
386251538Srpaulo			if (idesc->id_entryno <= 2)
387251538Srpaulo				break;
388251538Srpaulo			fileerror(idesc->id_number, dirp->d_ino, "UNALLOCATED");
389251538Srpaulo			n = reply("REMOVE");
390251538Srpaulo			break;
391251538Srpaulo
392251538Srpaulo		case DCLEAR:
393251538Srpaulo		case FCLEAR:
394251538Srpaulo			if (idesc->id_entryno <= 2)
395251538Srpaulo				break;
396251538Srpaulo			if (statemap[dirp->d_ino] == FCLEAR)
397251538Srpaulo				errmsg = "DUP/BAD";
398251538Srpaulo			else if (!preen)
399251538Srpaulo				errmsg = "ZERO LENGTH DIRECTORY";
400251538Srpaulo			else {
401251538Srpaulo				n = 1;
402251538Srpaulo				break;
403251538Srpaulo			}
404251538Srpaulo			fileerror(idesc->id_number, dirp->d_ino, errmsg);
405251538Srpaulo			if ((n = reply("REMOVE")) == 1)
406251538Srpaulo				break;
407251538Srpaulo			dp = ginode(dirp->d_ino);
408251538Srpaulo			statemap[dirp->d_ino] =
409251538Srpaulo			    (dp->di_mode & IFMT) == IFDIR ? DSTATE : FSTATE;
410251538Srpaulo			lncntp[dirp->d_ino] = dp->di_nlink;
411292014Savos			goto again;
412292014Savos
413292014Savos		case DSTATE:
414292014Savos			if (statemap[idesc->id_number] == DFOUND)
415292014Savos				statemap[dirp->d_ino] = DFOUND;
416292014Savos			/* fall through */
417292014Savos
418292014Savos		case DFOUND:
419292014Savos			inp = getinoinfo(dirp->d_ino);
420292014Savos			if (inp->i_parent != 0 && idesc->id_entryno > 2) {
421251538Srpaulo				getpathname(pathbuf, idesc->id_number,
422251538Srpaulo				    idesc->id_number);
423251538Srpaulo				getpathname(namebuf, dirp->d_ino, dirp->d_ino);
424251538Srpaulo				pwarn("%s %s %s\n", pathbuf,
425251538Srpaulo				    "IS AN EXTRANEOUS HARD LINK TO DIRECTORY",
426251538Srpaulo				    namebuf);
427251538Srpaulo				if (preen)
428251538Srpaulo					printf(" (IGNORED)\n");
429251538Srpaulo				else if ((n = reply("REMOVE")) == 1)
430251538Srpaulo					break;
431251538Srpaulo			}
432251538Srpaulo			if (idesc->id_entryno > 2)
433251538Srpaulo				inp->i_parent = idesc->id_number;
434251538Srpaulo			/* fall through */
435251538Srpaulo
436251538Srpaulo		case FSTATE:
437251538Srpaulo			if (newinofmt && dirp->d_type != typemap[dirp->d_ino]) {
438251538Srpaulo				fileerror(idesc->id_number, dirp->d_ino,
439251538Srpaulo				    "BAD TYPE VALUE");
440251538Srpaulo				dirp->d_type = typemap[dirp->d_ino];
441287197Sglebius				if (reply("FIX") == 1)
442293339Savos					ret |= ALTERED;
443251538Srpaulo			}
444251538Srpaulo			lncntp[dirp->d_ino]--;
445251538Srpaulo			break;
446251538Srpaulo
447251538Srpaulo		default:
448264912Skevlo			errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
449264912Skevlo			    statemap[dirp->d_ino], dirp->d_ino);
450251538Srpaulo		}
451251538Srpaulo	}
452251538Srpaulo	if (n == 0)
453292174Savos		return (ret|KEEPON);
454292167Savos	dirp->d_ino = 0;
455251538Srpaulo	return (ret|KEEPON|ALTERED);
456287197Sglebius}
457251538Srpaulo
458291902Skevlo/*
459291902Skevlo * Routine to sort disk blocks.
460291902Skevlo */
461251538Srpaulostatic int
462251538Srpauloblksort(arg1, arg2)
463251538Srpaulo	const void *arg1, *arg2;
464251538Srpaulo{
465251538Srpaulo
466251538Srpaulo	return ((*(struct inoinfo **)arg1)->i_blks[0] -
467251538Srpaulo		(*(struct inoinfo **)arg2)->i_blks[0]);
468251538Srpaulo}
469251538Srpaulo