xref: /csrg-svn/sbin/fsck/dir.c (revision 16259)
1*16259Smckusick #ifndef lint
2*16259Smckusick static char version[] = "@(#)dir.c	3.1 (Berkeley) 03/31/84";
3*16259Smckusick #endif
4*16259Smckusick 
5*16259Smckusick #include <sys/param.h>
6*16259Smckusick #include <sys/inode.h>
7*16259Smckusick #include <sys/fs.h>
8*16259Smckusick #define KERNEL
9*16259Smckusick #include <sys/dir.h>
10*16259Smckusick #undef KERNEL
11*16259Smckusick #include "fsck.h"
12*16259Smckusick 
13*16259Smckusick #define MINDIRSIZE	(sizeof (struct dirtemplate))
14*16259Smckusick 
15*16259Smckusick char	*endpathname = &pathname[BUFSIZ - 2];
16*16259Smckusick char	*lfname = "lost+found";
17*16259Smckusick 
18*16259Smckusick DIRECT	*fsck_readdir();
19*16259Smckusick 
20*16259Smckusick descend(parentino, inumber)
21*16259Smckusick 	struct inodesc *parentino;
22*16259Smckusick 	ino_t inumber;
23*16259Smckusick {
24*16259Smckusick 	register DINODE *dp;
25*16259Smckusick 	struct inodesc curino;
26*16259Smckusick 
27*16259Smckusick 	bzero((char *)&curino, sizeof(struct inodesc));
28*16259Smckusick 	statemap[inumber] = FSTATE;
29*16259Smckusick 	if ((dp = ginode(inumber)) == NULL)
30*16259Smckusick 		return;
31*16259Smckusick 	if (dp->di_size == 0) {
32*16259Smckusick 		direrr(inumber, "ZERO LENGTH DIRECTORY");
33*16259Smckusick 		if (reply("REMOVE") == 1)
34*16259Smckusick 			statemap[inumber] = CLEAR;
35*16259Smckusick 		return;
36*16259Smckusick 	}
37*16259Smckusick 	if (dp->di_size < MINDIRSIZE) {
38*16259Smckusick 		direrr(inumber, "DIRECTORY TOO SHORT");
39*16259Smckusick 		dp->di_size = MINDIRSIZE;
40*16259Smckusick 		if (reply("FIX") == 1)
41*16259Smckusick 			inodirty();
42*16259Smckusick 	}
43*16259Smckusick 	curino.id_type = DATA;
44*16259Smckusick 	curino.id_func = parentino->id_func;
45*16259Smckusick 	curino.id_parent = parentino->id_number;
46*16259Smckusick 	curino.id_number = inumber;
47*16259Smckusick 	curino.id_filesize = dp->di_size;
48*16259Smckusick 	(void)ckinode(dp, &curino);
49*16259Smckusick }
50*16259Smckusick 
51*16259Smckusick dirscan(idesc)
52*16259Smckusick 	register struct inodesc *idesc;
53*16259Smckusick {
54*16259Smckusick 	register DIRECT *dp;
55*16259Smckusick 	int dsize, n;
56*16259Smckusick 	long blksiz;
57*16259Smckusick 	char dbuf[DIRBLKSIZ];
58*16259Smckusick 
59*16259Smckusick 	if (idesc->id_type != DATA)
60*16259Smckusick 		errexit("wrong type to dirscan %d\n", idesc->id_type);
61*16259Smckusick 	blksiz = idesc->id_numfrags * sblock.fs_fsize;
62*16259Smckusick 	if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
63*16259Smckusick 		idesc->id_filesize -= blksiz;
64*16259Smckusick 		return (SKIP);
65*16259Smckusick 	}
66*16259Smckusick 	idesc->id_loc = 0;
67*16259Smckusick 	for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
68*16259Smckusick 		dsize = dp->d_reclen;
69*16259Smckusick 		bcopy((char *)dp, dbuf, dsize);
70*16259Smckusick 		idesc->id_dirp = (DIRECT *)dbuf;
71*16259Smckusick 		if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
72*16259Smckusick 			if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) {
73*16259Smckusick 				bcopy(dbuf, (char *)dp, dsize);
74*16259Smckusick 				dirty(&fileblk);
75*16259Smckusick 				sbdirty();
76*16259Smckusick 			} else
77*16259Smckusick 				n &= ~ALTERED;
78*16259Smckusick 		}
79*16259Smckusick 		if (n & STOP)
80*16259Smckusick 			return (n);
81*16259Smckusick 	}
82*16259Smckusick 	return (idesc->id_filesize > 0 ? KEEPON : STOP);
83*16259Smckusick }
84*16259Smckusick 
85*16259Smckusick /*
86*16259Smckusick  * get next entry in a directory.
87*16259Smckusick  */
88*16259Smckusick DIRECT *
89*16259Smckusick fsck_readdir(idesc)
90*16259Smckusick 	register struct inodesc *idesc;
91*16259Smckusick {
92*16259Smckusick 	register DIRECT *dp, *ndp;
93*16259Smckusick 	long size, blksiz;
94*16259Smckusick 
95*16259Smckusick 	blksiz = idesc->id_numfrags * sblock.fs_fsize;
96*16259Smckusick 	if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) {
97*16259Smckusick 		idesc->id_filesize -= blksiz - idesc->id_loc;
98*16259Smckusick 		return NULL;
99*16259Smckusick 	}
100*16259Smckusick 	if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
101*16259Smckusick 	    idesc->id_loc < blksiz) {
102*16259Smckusick 		dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
103*16259Smckusick 		if (dircheck(idesc, dp))
104*16259Smckusick 			goto dpok;
105*16259Smckusick 		idesc->id_loc += DIRBLKSIZ;
106*16259Smckusick 		idesc->id_filesize -= DIRBLKSIZ;
107*16259Smckusick 		dp->d_reclen = DIRBLKSIZ;
108*16259Smckusick 		dp->d_ino = 0;
109*16259Smckusick 		dp->d_namlen = 0;
110*16259Smckusick 		dp->d_name[0] = '\0';
111*16259Smckusick 		if (dofix(idesc))
112*16259Smckusick 			dirty(&fileblk);
113*16259Smckusick 		return (dp);
114*16259Smckusick 	}
115*16259Smckusick dpok:
116*16259Smckusick 	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
117*16259Smckusick 		return NULL;
118*16259Smckusick 	dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
119*16259Smckusick 	idesc->id_loc += dp->d_reclen;
120*16259Smckusick 	idesc->id_filesize -= dp->d_reclen;
121*16259Smckusick 	if ((idesc->id_loc % DIRBLKSIZ) == 0)
122*16259Smckusick 		return (dp);
123*16259Smckusick 	ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
124*16259Smckusick 	if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
125*16259Smckusick 	    dircheck(idesc, ndp) == 0) {
126*16259Smckusick 		size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
127*16259Smckusick 		dp->d_reclen += size;
128*16259Smckusick 		idesc->id_loc += size;
129*16259Smckusick 		idesc->id_filesize -= size;
130*16259Smckusick 		if (dofix(idesc))
131*16259Smckusick 			dirty(&fileblk);
132*16259Smckusick 	}
133*16259Smckusick 	return (dp);
134*16259Smckusick }
135*16259Smckusick 
136*16259Smckusick /*
137*16259Smckusick  * Verify that a directory entry is valid.
138*16259Smckusick  * This is a superset of the checks made in the kernel.
139*16259Smckusick  */
140*16259Smckusick dircheck(idesc, dp)
141*16259Smckusick 	struct inodesc *idesc;
142*16259Smckusick 	register DIRECT *dp;
143*16259Smckusick {
144*16259Smckusick 	register int size;
145*16259Smckusick 	register char *cp;
146*16259Smckusick 	int spaceleft;
147*16259Smckusick 
148*16259Smckusick 	size = DIRSIZ(dp);
149*16259Smckusick 	spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
150*16259Smckusick 	if (dp->d_ino < imax &&
151*16259Smckusick 	    dp->d_reclen != 0 &&
152*16259Smckusick 	    dp->d_reclen <= spaceleft &&
153*16259Smckusick 	    (dp->d_reclen & 0x3) == 0 &&
154*16259Smckusick 	    dp->d_reclen >= size &&
155*16259Smckusick 	    idesc->id_filesize >= size &&
156*16259Smckusick 	    dp->d_namlen <= MAXNAMLEN) {
157*16259Smckusick 		if (dp->d_ino == 0)
158*16259Smckusick 			return (1);
159*16259Smckusick 		for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
160*16259Smckusick 			if (*cp == 0 || (*cp++ & 0200))
161*16259Smckusick 				return (0);
162*16259Smckusick 		if (*cp == 0)
163*16259Smckusick 			return (1);
164*16259Smckusick 	}
165*16259Smckusick 	return (0);
166*16259Smckusick }
167*16259Smckusick 
168*16259Smckusick direrr(ino, s)
169*16259Smckusick 	ino_t ino;
170*16259Smckusick 	char *s;
171*16259Smckusick {
172*16259Smckusick 	register DINODE *dp;
173*16259Smckusick 
174*16259Smckusick 	pwarn("%s ", s);
175*16259Smckusick 	pinode(ino);
176*16259Smckusick 	printf("\n");
177*16259Smckusick 	if ((dp = ginode(ino)) != NULL && ftypeok(dp))
178*16259Smckusick 		pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname);
179*16259Smckusick 	else
180*16259Smckusick 		pfatal("NAME=%s\n", pathname);
181*16259Smckusick }
182*16259Smckusick 
183*16259Smckusick adjust(idesc, lcnt)
184*16259Smckusick 	register struct inodesc *idesc;
185*16259Smckusick 	short lcnt;
186*16259Smckusick {
187*16259Smckusick 	register DINODE *dp;
188*16259Smckusick 
189*16259Smckusick 	if ((dp = ginode(idesc->id_number)) == NULL)
190*16259Smckusick 		return;
191*16259Smckusick 	if (dp->di_nlink == lcnt) {
192*16259Smckusick 		if (linkup(idesc->id_number, (ino_t)0) == 0)
193*16259Smckusick 			clri(idesc, "UNREF", 0);
194*16259Smckusick 	}
195*16259Smckusick 	else {
196*16259Smckusick 		pwarn("LINK COUNT %s",
197*16259Smckusick 			(lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE"));
198*16259Smckusick 		pinode(idesc->id_number);
199*16259Smckusick 		printf(" COUNT %d SHOULD BE %d",
200*16259Smckusick 			dp->di_nlink, dp->di_nlink-lcnt);
201*16259Smckusick 		if (preen) {
202*16259Smckusick 			if (lcnt < 0) {
203*16259Smckusick 				printf("\n");
204*16259Smckusick 				preendie();
205*16259Smckusick 			}
206*16259Smckusick 			printf(" (ADJUSTED)\n");
207*16259Smckusick 		}
208*16259Smckusick 		if (preen || reply("ADJUST") == 1) {
209*16259Smckusick 			dp->di_nlink -= lcnt;
210*16259Smckusick 			inodirty();
211*16259Smckusick 		}
212*16259Smckusick 	}
213*16259Smckusick }
214*16259Smckusick 
215*16259Smckusick mkentry(idesc)
216*16259Smckusick 	struct inodesc *idesc;
217*16259Smckusick {
218*16259Smckusick 	register DIRECT *dirp = idesc->id_dirp;
219*16259Smckusick 	DIRECT newent;
220*16259Smckusick 	int newlen, oldlen;
221*16259Smckusick 
222*16259Smckusick 	newent.d_namlen = 11;
223*16259Smckusick 	newlen = DIRSIZ(&newent);
224*16259Smckusick 	if (dirp->d_ino != 0)
225*16259Smckusick 		oldlen = DIRSIZ(dirp);
226*16259Smckusick 	else
227*16259Smckusick 		oldlen = 0;
228*16259Smckusick 	if (dirp->d_reclen - oldlen < newlen)
229*16259Smckusick 		return (KEEPON);
230*16259Smckusick 	newent.d_reclen = dirp->d_reclen - oldlen;
231*16259Smckusick 	dirp->d_reclen = oldlen;
232*16259Smckusick 	dirp = (struct direct *)(((char *)dirp) + oldlen);
233*16259Smckusick 	dirp->d_ino = idesc->id_parent;	/* ino to be entered is in id_parent */
234*16259Smckusick 	dirp->d_reclen = newent.d_reclen;
235*16259Smckusick 	dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent);
236*16259Smckusick 	return (ALTERED|STOP);
237*16259Smckusick }
238*16259Smckusick 
239*16259Smckusick chgdd(idesc)
240*16259Smckusick 	struct inodesc *idesc;
241*16259Smckusick {
242*16259Smckusick 	register DIRECT *dirp = idesc->id_dirp;
243*16259Smckusick 
244*16259Smckusick 	if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
245*16259Smckusick 	dirp->d_name[2] == 0) {
246*16259Smckusick 		dirp->d_ino = lfdir;
247*16259Smckusick 		return (ALTERED|STOP);
248*16259Smckusick 	}
249*16259Smckusick 	return (KEEPON);
250*16259Smckusick }
251*16259Smckusick 
252*16259Smckusick linkup(orphan, pdir)
253*16259Smckusick 	ino_t orphan;
254*16259Smckusick 	ino_t pdir;
255*16259Smckusick {
256*16259Smckusick 	register DINODE *dp;
257*16259Smckusick 	int lostdir, len;
258*16259Smckusick 	struct inodesc idesc;
259*16259Smckusick 
260*16259Smckusick 	bzero((char *)&idesc, sizeof(struct inodesc));
261*16259Smckusick 	if ((dp = ginode(orphan)) == NULL)
262*16259Smckusick 		return (0);
263*16259Smckusick 	lostdir = DIRCT;
264*16259Smckusick 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
265*16259Smckusick 	pinode(orphan);
266*16259Smckusick 	if (preen && dp->di_size == 0)
267*16259Smckusick 		return (0);
268*16259Smckusick 	if (preen)
269*16259Smckusick 		printf(" (RECONNECTED)\n");
270*16259Smckusick 	else
271*16259Smckusick 		if (reply("RECONNECT") == 0)
272*16259Smckusick 			return (0);
273*16259Smckusick 	pathp = pathname;
274*16259Smckusick 	*pathp++ = '/';
275*16259Smckusick 	*pathp = '\0';
276*16259Smckusick 	if (lfdir == 0) {
277*16259Smckusick 		if ((dp = ginode(ROOTINO)) == NULL)
278*16259Smckusick 			return (0);
279*16259Smckusick 		srchname = lfname;
280*16259Smckusick 		idesc.id_type = DATA;
281*16259Smckusick 		idesc.id_func = findino;
282*16259Smckusick 		idesc.id_number = ROOTINO;
283*16259Smckusick 		idesc.id_filesize = dp->di_size;
284*16259Smckusick 		(void)ckinode(dp, &idesc);
285*16259Smckusick 		if ((lfdir = idesc.id_parent) == 0) {
286*16259Smckusick 			pfatal("SORRY. NO lost+found DIRECTORY");
287*16259Smckusick 			printf("\n\n");
288*16259Smckusick 			return (0);
289*16259Smckusick 		}
290*16259Smckusick 	}
291*16259Smckusick 	if ((dp = ginode(lfdir)) == NULL ||
292*16259Smckusick 	     !DIRCT || statemap[lfdir] != FSTATE) {
293*16259Smckusick 		pfatal("SORRY. NO lost+found DIRECTORY");
294*16259Smckusick 		printf("\n\n");
295*16259Smckusick 		return (0);
296*16259Smckusick 	}
297*16259Smckusick 	if (fragoff(&sblock, dp->di_size)) {
298*16259Smckusick 		dp->di_size = fragroundup(&sblock, dp->di_size);
299*16259Smckusick 		inodirty();
300*16259Smckusick 	}
301*16259Smckusick 	len = strlen(lfname);
302*16259Smckusick 	bcopy(lfname, pathp, len + 1);
303*16259Smckusick 	pathp += len;
304*16259Smckusick 	idesc.id_type = DATA;
305*16259Smckusick 	idesc.id_func = mkentry;
306*16259Smckusick 	idesc.id_number = lfdir;
307*16259Smckusick 	idesc.id_filesize = dp->di_size;
308*16259Smckusick 	idesc.id_parent = orphan;	/* this is the inode to enter */
309*16259Smckusick 	idesc.id_fix = DONTKNOW;
310*16259Smckusick 	if ((ckinode(dp, &idesc) & ALTERED) == 0) {
311*16259Smckusick 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
312*16259Smckusick 		printf("\n\n");
313*16259Smckusick 		return (0);
314*16259Smckusick 	}
315*16259Smckusick 	lncntp[orphan]--;
316*16259Smckusick 	*pathp++ = '/';
317*16259Smckusick 	pathp += lftempname(pathp, orphan);
318*16259Smckusick 	if (lostdir) {
319*16259Smckusick 		dp = ginode(orphan);
320*16259Smckusick 		idesc.id_type = DATA;
321*16259Smckusick 		idesc.id_func = chgdd;
322*16259Smckusick 		idesc.id_number = orphan;
323*16259Smckusick 		idesc.id_filesize = dp->di_size;
324*16259Smckusick 		idesc.id_fix = DONTKNOW;
325*16259Smckusick 		(void)ckinode(dp, &idesc);
326*16259Smckusick 		if ((dp = ginode(lfdir)) != NULL) {
327*16259Smckusick 			dp->di_nlink++;
328*16259Smckusick 			inodirty();
329*16259Smckusick 			lncntp[lfdir]++;
330*16259Smckusick 		}
331*16259Smckusick 		pwarn("DIR I=%u CONNECTED. ", orphan);
332*16259Smckusick 		printf("PARENT WAS I=%u\n", pdir);
333*16259Smckusick 		if (preen == 0)
334*16259Smckusick 			printf("\n");
335*16259Smckusick 	}
336*16259Smckusick 	return (1);
337*16259Smckusick }
338*16259Smckusick 
339*16259Smckusick /*
340*16259Smckusick  * generate a temporary name for the lost+found directory.
341*16259Smckusick  */
342*16259Smckusick lftempname(bufp, ino)
343*16259Smckusick 	char *bufp;
344*16259Smckusick 	ino_t ino;
345*16259Smckusick {
346*16259Smckusick 	register ino_t in;
347*16259Smckusick 	register char *cp;
348*16259Smckusick 	int namlen;
349*16259Smckusick 
350*16259Smckusick 	cp = bufp + 2;
351*16259Smckusick 	for (in = imax; in > 0; in /= 10)
352*16259Smckusick 		cp++;
353*16259Smckusick 	*--cp = 0;
354*16259Smckusick 	namlen = cp - bufp;
355*16259Smckusick 	in = ino;
356*16259Smckusick 	while (cp > bufp) {
357*16259Smckusick 		*--cp = (in % 10) + '0';
358*16259Smckusick 		in /= 10;
359*16259Smckusick 	}
360*16259Smckusick 	*cp = '#';
361*16259Smckusick 	return (namlen);
362*16259Smckusick }
363