dir.c revision 23796
195719Sbenno/*
295719Sbenno * Copyright (c) 1980, 1986, 1993
395719Sbenno *	The Regents of the University of California.  All rights reserved.
4139825Simp *
595719Sbenno * Redistribution and use in source and binary forms, with or without
695719Sbenno * modification, are permitted provided that the following conditions
795719Sbenno * are met:
895719Sbenno * 1. Redistributions of source code must retain the above copyright
995719Sbenno *    notice, this list of conditions and the following disclaimer.
1095719Sbenno * 2. Redistributions in binary form must reproduce the above copyright
1195719Sbenno *    notice, this list of conditions and the following disclaimer in the
1295719Sbenno *    documentation and/or other materials provided with the distribution.
1395719Sbenno * 3. All advertising materials mentioning features or use of this software
1495719Sbenno *    must display the following acknowledgement:
1595719Sbenno *	This product includes software developed by the University of
1695719Sbenno *	California, Berkeley and its contributors.
1795719Sbenno * 4. Neither the name of the University nor the names of its contributors
1895719Sbenno *    may be used to endorse or promote products derived from this software
1995719Sbenno *    without specific prior written permission.
2095719Sbenno *
2195719Sbenno * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2295719Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2395719Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2495719Sbenno * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2595719Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2695719Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2795719Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2895719Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2995719Sbenno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3095719Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3195719Sbenno * SUCH DAMAGE.
3295719Sbenno */
3395719Sbenno
3495719Sbenno#ifndef lint
3595719Sbennostatic const char sccsid[] = "@(#)dir.c	8.8 (Berkeley) 4/28/95";
3695719Sbenno#endif /* not lint */
3795719Sbenno
3895719Sbenno#include <sys/param.h>
39174599Smarcel#include <sys/time.h>
4095719Sbenno
4195719Sbenno#include <ufs/ufs/dinode.h>
42293641Snwhitehorn#include <ufs/ufs/dir.h>
43293641Snwhitehorn#include <ufs/ffs/fs.h>
44293641Snwhitehorn
45293641Snwhitehorn#include <err.h>
46293641Snwhitehorn#include <string.h>
47293641Snwhitehorn
4895719Sbenno#include "fsck.h"
4995719Sbenno
50209975Snwhitehornchar	*lfname = "lost+found";
51209975Snwhitehornint	lfmode = 01777;
52209975Snwhitehornstruct	dirtemplate emptydir = { 0, DIRBLKSIZ };
53209975Snwhitehornstruct	dirtemplate dirhead = {
54209975Snwhitehorn	0, 12, DT_DIR, 1, ".",
55212722Snwhitehorn	0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
56212722Snwhitehorn};
57212722Snwhitehornstruct	odirtemplate odirhead = {
58212722Snwhitehorn	0, 12, 1, ".",
59222620Snwhitehorn	0, DIRBLKSIZ - 12, 2, ".."
60222620Snwhitehorn};
61209975Snwhitehorn
62209975Snwhitehornstatic int chgino __P((struct inodesc *));
63209975Snwhitehornstatic int dircheck __P((struct inodesc *, struct direct *));
64209975Snwhitehornstatic int expanddir __P((struct dinode *dp, char *name));
65209975Snwhitehornstatic void freedir __P((ino_t ino, ino_t parent));
66209975Snwhitehornstatic struct direct *fsck_readdir __P((struct inodesc *));
67222620Snwhitehornstatic struct bufarea *getdirblk __P((ufs_daddr_t blkno, long size));
68279751Snwhitehornstatic int lftempname __P((char *bufp, ino_t ino));
69222620Snwhitehornstatic int mkentry __P((struct inodesc *));
70209975Snwhitehorn
71212722Snwhitehorn/*
72212722Snwhitehorn * Propagate connected state through the tree.
73212722Snwhitehorn */
74222620Snwhitehornvoid
75209975Snwhitehornpropagate()
76222620Snwhitehorn{
77222620Snwhitehorn	register struct inoinfo **inpp, *inp;
78222620Snwhitehorn	struct inoinfo **inpend;
79209975Snwhitehorn	long change;
80209975Snwhitehorn
81212722Snwhitehorn	inpend = &inpsort[inplast];
8295719Sbenno	do {
83212722Snwhitehorn		change = 0;
84222620Snwhitehorn		for (inpp = inpsort; inpp < inpend; inpp++) {
85222620Snwhitehorn			inp = *inpp;
86212722Snwhitehorn			if (inp->i_parent == 0)
8795719Sbenno				continue;
88212722Snwhitehorn			if (statemap[inp->i_parent] == DFOUND &&
89212722Snwhitehorn			    statemap[inp->i_number] == DSTATE) {
90212722Snwhitehorn				statemap[inp->i_number] = DFOUND;
91212722Snwhitehorn				change++;
92279751Snwhitehorn			}
93222620Snwhitehorn		}
9495719Sbenno	} while (change > 0);
95222620Snwhitehorn}
96279751Snwhitehorn
97222620Snwhitehorn/*
98212722Snwhitehorn * Scan each entry in a directory block.
99222620Snwhitehorn */
100212722Snwhitehornint
101222620Snwhitehorndirscan(idesc)
102222620Snwhitehorn	register struct inodesc *idesc;
103279751Snwhitehorn{
104222620Snwhitehorn	register struct direct *dp;
105222620Snwhitehorn	register struct bufarea *bp;
106212722Snwhitehorn	int dsize, n;
107125441Sgrehan	long blksiz;
108125441Sgrehan	char dbuf[DIRBLKSIZ];
109125441Sgrehan
110188860Snwhitehorn	if (idesc->id_type != DATA)
111209975Snwhitehorn		errx(EEXIT, "wrong type to dirscan %d", idesc->id_type);
112125441Sgrehan	if (idesc->id_entryno == 0 &&
113125441Sgrehan	    (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
114125441Sgrehan		idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
115125441Sgrehan	blksiz = idesc->id_numfrags * sblock.fs_fsize;
116125441Sgrehan	if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
117125441Sgrehan		idesc->id_filesize -= blksiz;
118230123Snwhitehorn		return (SKIP);
119230123Snwhitehorn	}
120230123Snwhitehorn	idesc->id_loc = 0;
121125441Sgrehan	for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
122125441Sgrehan		dsize = dp->d_reclen;
123125441Sgrehan		memmove(dbuf, dp, (size_t)dsize);
124125441Sgrehan#		if (BYTE_ORDER == LITTLE_ENDIAN)
125125441Sgrehan			if (!newinofmt) {
126209975Snwhitehorn				struct direct *tdp = (struct direct *)dbuf;
127125441Sgrehan				u_char tmp;
128209975Snwhitehorn
129230123Snwhitehorn				tmp = tdp->d_namlen;
130125441Sgrehan				tdp->d_namlen = tdp->d_type;
131125441Sgrehan				tdp->d_type = tmp;
132125441Sgrehan			}
133125441Sgrehan#		endif
134209975Snwhitehorn		idesc->id_dirp = (struct direct *)dbuf;
135209975Snwhitehorn		if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
136209975Snwhitehorn#			if (BYTE_ORDER == LITTLE_ENDIAN)
137209975Snwhitehorn				if (!newinofmt && !doinglevel2) {
138209975Snwhitehorn					struct direct *tdp;
139209975Snwhitehorn					u_char tmp;
140125441Sgrehan
141209975Snwhitehorn					tdp = (struct direct *)dbuf;
142209975Snwhitehorn					tmp = tdp->d_namlen;
143209975Snwhitehorn					tdp->d_namlen = tdp->d_type;
144209975Snwhitehorn					tdp->d_type = tmp;
145209975Snwhitehorn				}
146209975Snwhitehorn#			endif
147209975Snwhitehorn			bp = getdirblk(idesc->id_blkno, blksiz);
148209975Snwhitehorn			memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
149209975Snwhitehorn			    (size_t)dsize);
150209975Snwhitehorn			dirty(bp);
151209975Snwhitehorn			sbdirty();
152209975Snwhitehorn		}
153209975Snwhitehorn		if (n & STOP)
154209975Snwhitehorn			return (n);
155209975Snwhitehorn	}
156209975Snwhitehorn	return (idesc->id_filesize > 0 ? KEEPON : STOP);
157209975Snwhitehorn}
158209975Snwhitehorn
159209975Snwhitehorn/*
160209975Snwhitehorn * get next entry in a directory.
161209975Snwhitehorn */
162209975Snwhitehornstatic struct direct *
163209975Snwhitehornfsck_readdir(idesc)
164209975Snwhitehorn	register struct inodesc *idesc;
165209975Snwhitehorn{
166209975Snwhitehorn	register struct direct *dp, *ndp;
167209975Snwhitehorn	register struct bufarea *bp;
168209975Snwhitehorn	long size, blksiz, fix, dploc;
169209975Snwhitehorn
170209975Snwhitehorn	blksiz = idesc->id_numfrags * sblock.fs_fsize;
171209975Snwhitehorn	bp = getdirblk(idesc->id_blkno, blksiz);
172209975Snwhitehorn	if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
173209975Snwhitehorn	    idesc->id_loc < blksiz) {
174209975Snwhitehorn		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
175209975Snwhitehorn		if (dircheck(idesc, dp))
176209975Snwhitehorn			goto dpok;
177209975Snwhitehorn		if (idesc->id_fix == IGNORE)
178209975Snwhitehorn			return (0);
179125441Sgrehan		fix = dofix(idesc, "DIRECTORY CORRUPTED");
180125441Sgrehan		bp = getdirblk(idesc->id_blkno, blksiz);
181188860Snwhitehorn		dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
182209975Snwhitehorn		dp->d_reclen = DIRBLKSIZ;
183209975Snwhitehorn		dp->d_ino = 0;
184209975Snwhitehorn		dp->d_type = 0;
185209975Snwhitehorn		dp->d_namlen = 0;
186209975Snwhitehorn		dp->d_name[0] = '\0';
187209975Snwhitehorn		if (fix)
188223485Snwhitehorn			dirty(bp);
189223485Snwhitehorn		idesc->id_loc += DIRBLKSIZ;
19095719Sbenno		idesc->id_filesize -= DIRBLKSIZ;
191125441Sgrehan		return (dp);
192223485Snwhitehorn	}
193223485Snwhitehorndpok:
194223485Snwhitehorn	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
195223485Snwhitehorn		return NULL;
196223485Snwhitehorn	dploc = idesc->id_loc;
197125441Sgrehan	dp = (struct direct *)(bp->b_un.b_buf + dploc);
198209975Snwhitehorn	idesc->id_loc += dp->d_reclen;
199209975Snwhitehorn	idesc->id_filesize -= dp->d_reclen;
200209975Snwhitehorn	if ((idesc->id_loc % DIRBLKSIZ) == 0)
201209975Snwhitehorn		return (dp);
202209975Snwhitehorn	ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
203125441Sgrehan	if (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
204209975Snwhitehorn	    dircheck(idesc, ndp) == 0) {
205209975Snwhitehorn		size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
206209975Snwhitehorn		idesc->id_loc += size;
207125441Sgrehan		idesc->id_filesize -= size;
208125441Sgrehan		if (idesc->id_fix == IGNORE)
209125441Sgrehan			return (0);
210230123Snwhitehorn		fix = dofix(idesc, "DIRECTORY CORRUPTED");
211209975Snwhitehorn		bp = getdirblk(idesc->id_blkno, blksiz);
212209975Snwhitehorn		dp = (struct direct *)(bp->b_un.b_buf + dploc);
213209975Snwhitehorn		dp->d_reclen += size;
214209975Snwhitehorn		if (fix)
215209975Snwhitehorn			dirty(bp);
216209975Snwhitehorn	}
217209975Snwhitehorn	return (dp);
218209975Snwhitehorn}
219209975Snwhitehorn
220209975Snwhitehorn/*
221209975Snwhitehorn * Verify that a directory entry is valid.
222209975Snwhitehorn * This is a superset of the checks made in the kernel.
223209975Snwhitehorn */
224209975Snwhitehornstatic int
225209975Snwhitehorndircheck(idesc, dp)
226209975Snwhitehorn	struct inodesc *idesc;
227209975Snwhitehorn	register struct direct *dp;
228209975Snwhitehorn{
229209975Snwhitehorn	register int size;
230209975Snwhitehorn	register char *cp;
231209975Snwhitehorn	u_char namlen, type;
232209975Snwhitehorn	int spaceleft;
233209975Snwhitehorn
234209975Snwhitehorn	spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
235209975Snwhitehorn	if (dp->d_ino >= maxino ||
236209975Snwhitehorn	    dp->d_reclen == 0 ||
237209975Snwhitehorn	    dp->d_reclen > spaceleft ||
238209975Snwhitehorn	    (dp->d_reclen & 0x3) != 0)
239209975Snwhitehorn		return (0);
240209975Snwhitehorn	if (dp->d_ino == 0)
241209975Snwhitehorn		return (1);
242209975Snwhitehorn	size = DIRSIZ(!newinofmt, dp);
243125441Sgrehan#	if (BYTE_ORDER == LITTLE_ENDIAN)
244230123Snwhitehorn		if (!newinofmt) {
245125441Sgrehan			type = dp->d_namlen;
246230123Snwhitehorn			namlen = dp->d_type;
247230123Snwhitehorn		} else {
248230123Snwhitehorn			namlen = dp->d_namlen;
249125441Sgrehan			type = dp->d_type;
250125441Sgrehan		}
251230123Snwhitehorn#	else
252230123Snwhitehorn		namlen = dp->d_namlen;
253125441Sgrehan		type = dp->d_type;
254125441Sgrehan#	endif
255125441Sgrehan	if (dp->d_reclen < size ||
256209975Snwhitehorn	    idesc->id_filesize < size ||
257209975Snwhitehorn	    namlen > MAXNAMLEN ||
258209975Snwhitehorn	    type > 15)
259209975Snwhitehorn		return (0);
260209975Snwhitehorn	for (cp = dp->d_name, size = 0; size < namlen; size++)
261209975Snwhitehorn		if (*cp == '\0' || (*cp++ == '/'))
262209975Snwhitehorn			return (0);
263212722Snwhitehorn	if (*cp != '\0')
264209975Snwhitehorn		return (0);
265209975Snwhitehorn	return (1);
266209975Snwhitehorn}
267209975Snwhitehorn
268209975Snwhitehornvoid
269209975Snwhitehorndirerror(ino, errmesg)
270230123Snwhitehorn	ino_t ino;
271230123Snwhitehorn	char *errmesg;
272230123Snwhitehorn{
273230123Snwhitehorn
274125441Sgrehan	fileerror(ino, ino, errmesg);
275230123Snwhitehorn}
276230123Snwhitehorn
277125441Sgrehanvoid
278230123Snwhitehornfileerror(cwd, ino, errmesg)
27995719Sbenno	ino_t cwd, ino;
280242723Sjhibbits	char *errmesg;
281242723Sjhibbits{
282242723Sjhibbits	register struct dinode *dp;
283242723Sjhibbits	char pathbuf[MAXPATHLEN + 1];
284242723Sjhibbits
285242723Sjhibbits	pwarn("%s ", errmesg);
286242723Sjhibbits	pinode(ino);
287242723Sjhibbits	printf("\n");
288242723Sjhibbits	getpathname(pathbuf, cwd, ino);
289242723Sjhibbits	if (ino < ROOTINO || ino > maxino) {
290242723Sjhibbits		pfatal("NAME=%s\n", pathbuf);
291242723Sjhibbits		return;
292242723Sjhibbits	}
29395719Sbenno	dp = ginode(ino);
294178628Smarcel	if (ftypeok(dp))
295178628Smarcel		pfatal("%s=%s\n",
296198400Snwhitehorn		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE", pathbuf);
297198400Snwhitehorn	else
298198400Snwhitehorn		pfatal("NAME=%s\n", pathbuf);
299132571Sgrehan}
300277561Snwhitehorn
301178628Smarcelvoid
302209975Snwhitehornadjust(idesc, lcnt)
303209975Snwhitehorn	register struct inodesc *idesc;
304209975Snwhitehorn	int lcnt;
305209975Snwhitehorn{
306209975Snwhitehorn	register struct dinode *dp;
307209975Snwhitehorn
308277498Snwhitehorn	dp = ginode(idesc->id_number);
309277498Snwhitehorn	if (dp->di_nlink == lcnt) {
310277498Snwhitehorn		if (linkup(idesc->id_number, (ino_t)0) == 0)
311277498Snwhitehorn			clri(idesc, "UNREF", 0);
312277498Snwhitehorn	} else {
313209975Snwhitehorn		pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
314277498Snwhitehorn			((dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"));
315277561Snwhitehorn		pinode(idesc->id_number);
316198400Snwhitehorn		printf(" COUNT %d SHOULD BE %d",
317198400Snwhitehorn			dp->di_nlink, dp->di_nlink - lcnt);
318277335Snwhitehorn		if (preen) {
319178628Smarcel			if (lcnt < 0) {
320277335Snwhitehorn				printf("\n");
321277335Snwhitehorn				pfatal("LINK COUNT INCREASING");
322277335Snwhitehorn			}
323218824Snwhitehorn			printf(" (ADJUSTED)\n");
324209975Snwhitehorn		}
325227386Snwhitehorn		if (preen || reply("ADJUST") == 1) {
326218824Snwhitehorn			dp->di_nlink -= lcnt;
327209975Snwhitehorn			inodirty();
328218824Snwhitehorn		}
329209975Snwhitehorn	}
330209975Snwhitehorn}
331261309Sjhibbits
332261309Sjhibbitsstatic int
333261309Sjhibbitsmkentry(idesc)
334261309Sjhibbits	struct inodesc *idesc;
335261309Sjhibbits{
336261309Sjhibbits	register struct direct *dirp = idesc->id_dirp;
337261309Sjhibbits	struct direct newent;
338261309Sjhibbits	int newlen, oldlen;
339261309Sjhibbits
340261309Sjhibbits	newent.d_namlen = strlen(idesc->id_name);
341261309Sjhibbits	newlen = DIRSIZ(0, &newent);
342261309Sjhibbits	if (dirp->d_ino != 0)
343218824Snwhitehorn		oldlen = DIRSIZ(0, dirp);
344209975Snwhitehorn	else
345261309Sjhibbits		oldlen = 0;
346178628Smarcel	if (dirp->d_reclen - oldlen < newlen)
347178628Smarcel		return (KEEPON);
348178628Smarcel	newent.d_reclen = dirp->d_reclen - oldlen;
349178628Smarcel	dirp->d_reclen = oldlen;
350132571Sgrehan	dirp = (struct direct *)(((char *)dirp) + oldlen);
351132571Sgrehan	dirp->d_ino = idesc->id_parent;	/* ino to be entered is in id_parent */
35295719Sbenno	dirp->d_reclen = newent.d_reclen;
353277498Snwhitehorn	if (newinofmt)
35495719Sbenno		dirp->d_type = typemap[idesc->id_parent];
355178628Smarcel	else
356277561Snwhitehorn		dirp->d_type = 0;
357277498Snwhitehorn	dirp->d_namlen = newent.d_namlen;
35896773Sbenno	memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1);
359125441Sgrehan#	if (BYTE_ORDER == LITTLE_ENDIAN)
360188860Snwhitehorn		/*
361188860Snwhitehorn		 * If the entry was split, dirscan() will only reverse the byte
362279751Snwhitehorn		 * order of the original entry, and not the new one, before
363277498Snwhitehorn		 * writing it back out.  So, we reverse the byte order here if
364279189Snwhitehorn		 * necessary.
365277498Snwhitehorn		 */
366277561Snwhitehorn		if (oldlen != 0 && !newinofmt && !doinglevel2) {
36795719Sbenno			u_char tmp;
36895719Sbenno
369230123Snwhitehorn			tmp = dirp->d_namlen;
370230123Snwhitehorn			dirp->d_namlen = dirp->d_type;
371230123Snwhitehorn			dirp->d_type = tmp;
372230123Snwhitehorn		}
373230123Snwhitehorn#	endif
374277561Snwhitehorn	return (ALTERED|STOP);
375277498Snwhitehorn}
376230123Snwhitehorn
377230123Snwhitehornstatic int
378230123Snwhitehornchgino(idesc)
379230123Snwhitehorn	struct inodesc *idesc;
380230123Snwhitehorn{
381230123Snwhitehorn	register struct direct *dirp = idesc->id_dirp;
382230123Snwhitehorn
383230123Snwhitehorn	if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
384277498Snwhitehorn		return (KEEPON);
385230123Snwhitehorn	dirp->d_ino = idesc->id_parent;
386230123Snwhitehorn	if (newinofmt)
387230123Snwhitehorn		dirp->d_type = typemap[idesc->id_parent];
388230123Snwhitehorn	else
389230123Snwhitehorn		dirp->d_type = 0;
390230123Snwhitehorn	return (ALTERED|STOP);
391277498Snwhitehorn}
392277498Snwhitehorn
393277498Snwhitehornint
394277498Snwhitehornlinkup(orphan, parentdir)
395277498Snwhitehorn	ino_t orphan;
396277498Snwhitehorn	ino_t parentdir;
397230123Snwhitehorn{
398277498Snwhitehorn	register struct dinode *dp;
399277498Snwhitehorn	int lostdir;
400277498Snwhitehorn	ino_t oldlfdir;
401277498Snwhitehorn	struct inodesc idesc;
402277498Snwhitehorn	char tempname[BUFSIZ];
403277498Snwhitehorn
404277498Snwhitehorn	memset(&idesc, 0, sizeof(struct inodesc));
405277498Snwhitehorn	dp = ginode(orphan);
406277498Snwhitehorn	lostdir = (dp->di_mode & IFMT) == IFDIR;
407277498Snwhitehorn	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
408277498Snwhitehorn	pinode(orphan);
409277561Snwhitehorn	if (preen && dp->di_size == 0)
410230123Snwhitehorn		return (0);
411230123Snwhitehorn	if (preen)
412230123Snwhitehorn		printf(" (RECONNECTED)\n");
413230123Snwhitehorn	else
414230123Snwhitehorn		if (reply("RECONNECT") == 0)
415230123Snwhitehorn			return (0);
416230123Snwhitehorn	if (lfdir == 0) {
417230123Snwhitehorn		dp = ginode(ROOTINO);
418230123Snwhitehorn		idesc.id_name = lfname;
419230123Snwhitehorn		idesc.id_type = DATA;
420230123Snwhitehorn		idesc.id_func = findino;
421230123Snwhitehorn		idesc.id_number = ROOTINO;
422230123Snwhitehorn		if ((ckinode(dp, &idesc) & FOUND) != 0) {
423230123Snwhitehorn			lfdir = idesc.id_parent;
424230123Snwhitehorn		} else {
425230123Snwhitehorn			pwarn("NO lost+found DIRECTORY");
426230123Snwhitehorn			if (preen || reply("CREATE")) {
427230123Snwhitehorn				lfdir = allocdir(ROOTINO, (ino_t)0, lfmode);
428230123Snwhitehorn				if (lfdir != 0) {
429230123Snwhitehorn					if (makeentry(ROOTINO, lfdir, lfname) != 0) {
430230123Snwhitehorn						if (preen)
431230123Snwhitehorn							printf(" (CREATED)\n");
432230123Snwhitehorn					} else {
433230123Snwhitehorn						freedir(lfdir, ROOTINO);
434230123Snwhitehorn						lfdir = 0;
435230123Snwhitehorn						if (preen)
436230123Snwhitehorn							printf("\n");
437230123Snwhitehorn					}
438230123Snwhitehorn				}
439230123Snwhitehorn			}
440230123Snwhitehorn		}
441230123Snwhitehorn		if (lfdir == 0) {
442230123Snwhitehorn			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
443230123Snwhitehorn			printf("\n\n");
444230123Snwhitehorn			return (0);
445230123Snwhitehorn		}
446230123Snwhitehorn	}
447230123Snwhitehorn	dp = ginode(lfdir);
448230123Snwhitehorn	if ((dp->di_mode & IFMT) != IFDIR) {
449230123Snwhitehorn		pfatal("lost+found IS NOT A DIRECTORY");
450230123Snwhitehorn		if (reply("REALLOCATE") == 0)
451230123Snwhitehorn			return (0);
452230123Snwhitehorn		oldlfdir = lfdir;
453230123Snwhitehorn		if ((lfdir = allocdir(ROOTINO, (ino_t)0, lfmode)) == 0) {
454230123Snwhitehorn			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
455230123Snwhitehorn			return (0);
456230123Snwhitehorn		}
457230123Snwhitehorn		if ((changeino(ROOTINO, lfname, lfdir) & ALTERED) == 0) {
458230123Snwhitehorn			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
459230123Snwhitehorn			return (0);
460230123Snwhitehorn		}
461230123Snwhitehorn		inodirty();
462230123Snwhitehorn		idesc.id_type = ADDR;
463230123Snwhitehorn		idesc.id_func = pass4check;
464230123Snwhitehorn		idesc.id_number = oldlfdir;
465230123Snwhitehorn		adjust(&idesc, lncntp[oldlfdir] + 1);
466230123Snwhitehorn		lncntp[oldlfdir] = 0;
467230123Snwhitehorn		dp = ginode(lfdir);
468230123Snwhitehorn	}
469230123Snwhitehorn	if (statemap[lfdir] != DFOUND) {
470230123Snwhitehorn		pfatal("SORRY. NO lost+found DIRECTORY\n\n");
471230123Snwhitehorn		return (0);
472230123Snwhitehorn	}
473230123Snwhitehorn	(void)lftempname(tempname, orphan);
474277334Snwhitehorn	if (makeentry(lfdir, orphan, tempname) == 0) {
475230123Snwhitehorn		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
476230123Snwhitehorn		printf("\n\n");
477230123Snwhitehorn		return (0);
478230123Snwhitehorn	}
479230123Snwhitehorn	lncntp[orphan]--;
480230123Snwhitehorn	if (lostdir) {
481230123Snwhitehorn		if ((changeino(orphan, "..", lfdir) & ALTERED) == 0 &&
482230123Snwhitehorn		    parentdir != (ino_t)-1)
483230123Snwhitehorn			(void)makeentry(orphan, lfdir, "..");
484230123Snwhitehorn		dp = ginode(lfdir);
485230123Snwhitehorn		dp->di_nlink++;
486230123Snwhitehorn		inodirty();
487230123Snwhitehorn		lncntp[lfdir]++;
488230123Snwhitehorn		pwarn("DIR I=%lu CONNECTED. ", orphan);
489230123Snwhitehorn		if (parentdir != (ino_t)-1) {
490230123Snwhitehorn			printf("PARENT WAS I=%lu\n", parentdir);
491230123Snwhitehorn			/*
492230123Snwhitehorn			 * The parent directory, because of the ordering
493230123Snwhitehorn			 * guarantees, has had the link count incremented
494230123Snwhitehorn			 * for the child, but no entry was made.  This
495230123Snwhitehorn			 * fixes the parent link count so that fsck does
496230123Snwhitehorn			 * not need to be rerun.
497230123Snwhitehorn			 */
498230123Snwhitehorn			lncntp[parentdir]++;
499230123Snwhitehorn
500230123Snwhitehorn		}
501230123Snwhitehorn		if (preen == 0)
502230123Snwhitehorn			printf("\n");
503230123Snwhitehorn	}
504230123Snwhitehorn	return (1);
505230123Snwhitehorn}
506230123Snwhitehorn
507230123Snwhitehorn/*
508230123Snwhitehorn * fix an entry in a directory.
509230123Snwhitehorn */
510230123Snwhitehornint
511230123Snwhitehornchangeino(dir, name, newnum)
512230123Snwhitehorn	ino_t dir;
513230123Snwhitehorn	char *name;
514230123Snwhitehorn	ino_t newnum;
515230123Snwhitehorn{
516230123Snwhitehorn	struct inodesc idesc;
517230123Snwhitehorn
518230123Snwhitehorn	memset(&idesc, 0, sizeof(struct inodesc));
519230123Snwhitehorn	idesc.id_type = DATA;
520230123Snwhitehorn	idesc.id_func = chgino;
521230123Snwhitehorn	idesc.id_number = dir;
522230123Snwhitehorn	idesc.id_fix = DONTKNOW;
523230123Snwhitehorn	idesc.id_name = name;
524230123Snwhitehorn	idesc.id_parent = newnum;	/* new value for name */
525230123Snwhitehorn	return (ckinode(ginode(dir), &idesc));
526230123Snwhitehorn}
527230123Snwhitehorn
52895719Sbenno/*
52995719Sbenno * make an entry in a directory
530277561Snwhitehorn */
53196773Sbennoint
532125441Sgrehanmakeentry(parent, ino, name)
533125441Sgrehan	ino_t parent, ino;
534209975Snwhitehorn	char *name;
535209975Snwhitehorn{
536209975Snwhitehorn	struct dinode *dp;
537209975Snwhitehorn	struct inodesc idesc;
538209975Snwhitehorn	char pathbuf[MAXPATHLEN + 1];
539125441Sgrehan
540125441Sgrehan	if (parent < ROOTINO || parent >= maxino ||
541209975Snwhitehorn	    ino < ROOTINO || ino >= maxino)
542209975Snwhitehorn		return (0);
543125441Sgrehan	memset(&idesc, 0, sizeof(struct inodesc));
544125441Sgrehan	idesc.id_type = DATA;
545125441Sgrehan	idesc.id_func = mkentry;
546188860Snwhitehorn	idesc.id_number = parent;
547277498Snwhitehorn	idesc.id_parent = ino;	/* this is the inode to enter */
548277498Snwhitehorn	idesc.id_fix = DONTKNOW;
549277498Snwhitehorn	idesc.id_name = name;
550277498Snwhitehorn	dp = ginode(parent);
551277498Snwhitehorn	if (dp->di_size % DIRBLKSIZ) {
552277498Snwhitehorn		dp->di_size = roundup(dp->di_size, DIRBLKSIZ);
553277498Snwhitehorn		inodirty();
554277498Snwhitehorn	}
555277498Snwhitehorn	if ((ckinode(dp, &idesc) & ALTERED) != 0)
556277498Snwhitehorn		return (1);
557188951Snwhitehorn	getpathname(pathbuf, parent, parent);
558188860Snwhitehorn	dp = ginode(parent);
559188860Snwhitehorn	if (expanddir(dp, pathbuf) == 0)
560188860Snwhitehorn		return (0);
561188860Snwhitehorn	return (ckinode(dp, &idesc) & ALTERED);
562125441Sgrehan}
563125441Sgrehan
564277498Snwhitehorn/*
565277561Snwhitehorn * Attempt to expand the size of a directory
56695719Sbenno */
56795719Sbennostatic int
56895719Sbennoexpanddir(dp, name)
569277498Snwhitehorn	register struct dinode *dp;
57095719Sbenno	char *name;
571277561Snwhitehorn{
57296773Sbenno	ufs_daddr_t lastbn, newblk;
573125441Sgrehan	register struct bufarea *bp;
574125441Sgrehan	char *cp, firstblk[DIRBLKSIZ];
575209975Snwhitehorn
576209975Snwhitehorn	lastbn = lblkno(&sblock, dp->di_size);
577209975Snwhitehorn	if (lastbn >= NDADDR - 1 || dp->di_db[lastbn] == 0 || dp->di_size == 0)
578209975Snwhitehorn		return (0);
579209975Snwhitehorn	if ((newblk = allocblk(sblock.fs_frag)) == 0)
580125441Sgrehan		return (0);
581125441Sgrehan	dp->di_db[lastbn + 1] = dp->di_db[lastbn];
582125441Sgrehan	dp->di_db[lastbn] = newblk;
583125441Sgrehan	dp->di_size += sblock.fs_bsize;
584125441Sgrehan	dp->di_blocks += btodb(sblock.fs_bsize);
585125441Sgrehan	bp = getdirblk(dp->di_db[lastbn + 1],
586277498Snwhitehorn		(long)dblksize(&sblock, dp, lastbn + 1));
587277498Snwhitehorn	if (bp->b_errs)
588277498Snwhitehorn		goto bad;
589277498Snwhitehorn	memmove(firstblk, bp->b_un.b_buf, DIRBLKSIZ);
590277498Snwhitehorn	bp = getdirblk(newblk, sblock.fs_bsize);
591277498Snwhitehorn	if (bp->b_errs)
592277561Snwhitehorn		goto bad;
59395719Sbenno	memmove(bp->b_un.b_buf, firstblk, DIRBLKSIZ);
59495719Sbenno	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
59595719Sbenno	     cp < &bp->b_un.b_buf[sblock.fs_bsize];
59695719Sbenno	     cp += DIRBLKSIZ)
59795719Sbenno		memmove(cp, &emptydir, sizeof emptydir);
598188951Snwhitehorn	dirty(bp);
599188860Snwhitehorn	bp = getdirblk(dp->di_db[lastbn + 1],
600188860Snwhitehorn		(long)dblksize(&sblock, dp, lastbn + 1));
601188860Snwhitehorn	if (bp->b_errs)
602188860Snwhitehorn		goto bad;
603125441Sgrehan	memmove(bp->b_un.b_buf, &emptydir, sizeof emptydir);
604209975Snwhitehorn	pwarn("NO SPACE LEFT IN %s", name);
605209975Snwhitehorn	if (preen)
606209975Snwhitehorn		printf(" (EXPANDED)\n");
607209975Snwhitehorn	else if (reply("EXPAND") == 0)
608209975Snwhitehorn		goto bad;
609209975Snwhitehorn	dirty(bp);
610209975Snwhitehorn	inodirty();
611209975Snwhitehorn	return (1);
612209975Snwhitehornbad:
613209975Snwhitehorn	dp->di_db[lastbn] = dp->di_db[lastbn + 1];
614125441Sgrehan	dp->di_db[lastbn + 1] = 0;
615125441Sgrehan	dp->di_size -= sblock.fs_bsize;
616209975Snwhitehorn	dp->di_blocks -= btodb(sblock.fs_bsize);
617209975Snwhitehorn	freeblk(newblk, sblock.fs_frag);
618125441Sgrehan	return (0);
619132571Sgrehan}
620258800Snwhitehorn
621132571Sgrehan/*
622132571Sgrehan * allocate a new directory
623132571Sgrehan */
624132571Sgrehanino_t
625266136Sjhibbitsallocdir(parent, request, mode)
626132571Sgrehan	ino_t parent, request;
627132571Sgrehan	int mode;
628132571Sgrehan{
629209975Snwhitehorn	ino_t ino;
630132571Sgrehan	char *cp;
631132571Sgrehan	struct dinode *dp;
632132571Sgrehan	register struct bufarea *bp;
633132571Sgrehan	struct dirtemplate *dirp;
634209975Snwhitehorn
635209975Snwhitehorn	ino = allocino(request, IFDIR|mode);
636209975Snwhitehorn	if (newinofmt)
637209975Snwhitehorn		dirp = &dirhead;
638209975Snwhitehorn	else
639209975Snwhitehorn		dirp = (struct dirtemplate *)&odirhead;
640209975Snwhitehorn	dirp->dot_ino = ino;
641209975Snwhitehorn	dirp->dotdot_ino = parent;
642209975Snwhitehorn	dp = ginode(ino);
643209975Snwhitehorn	bp = getdirblk(dp->di_db[0], sblock.fs_fsize);
644209975Snwhitehorn	if (bp->b_errs) {
645209975Snwhitehorn		freeino(ino);
646209975Snwhitehorn		return (0);
647209975Snwhitehorn	}
648191039Snwhitehorn	memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
649132571Sgrehan	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
650132571Sgrehan	     cp < &bp->b_un.b_buf[sblock.fs_fsize];
651125441Sgrehan	     cp += DIRBLKSIZ)
65295719Sbenno		memmove(cp, &emptydir, sizeof emptydir);
65395719Sbenno	dirty(bp);
654125441Sgrehan	dp->di_nlink = 2;
655125441Sgrehan	inodirty();
656125441Sgrehan	if (ino == ROOTINO) {
65795719Sbenno		lncntp[ino] = dp->di_nlink;
658188860Snwhitehorn		cacheino(dp, ino);
659188860Snwhitehorn		return(ino);
660209975Snwhitehorn	}
661209975Snwhitehorn	if (statemap[parent] != DSTATE && statemap[parent] != DFOUND) {
662209975Snwhitehorn		freeino(ino);
663212722Snwhitehorn		return (0);
664209975Snwhitehorn	}
665209975Snwhitehorn	cacheino(dp, ino);
666277498Snwhitehorn	statemap[ino] = statemap[parent];
667188860Snwhitehorn	if (statemap[ino] == DSTATE) {
668188860Snwhitehorn		lncntp[ino] = dp->di_nlink;
669188860Snwhitehorn		lncntp[parent]++;
670188860Snwhitehorn	}
671188860Snwhitehorn	dp = ginode(parent);
672188860Snwhitehorn	dp->di_nlink++;
673188860Snwhitehorn	inodirty();
674188860Snwhitehorn	return (ino);
675188860Snwhitehorn}
676188860Snwhitehorn
677188860Snwhitehorn/*
678279750Snwhitehorn * free a directory inode
679188860Snwhitehorn */
680188860Snwhitehornstatic void
681188860Snwhitehornfreedir(ino, parent)
682188860Snwhitehorn	ino_t ino, parent;
683188860Snwhitehorn{
684188860Snwhitehorn	struct dinode *dp;
685209975Snwhitehorn
686209975Snwhitehorn	if (ino != parent) {
687209975Snwhitehorn		dp = ginode(parent);
688209975Snwhitehorn		dp->di_nlink--;
689209975Snwhitehorn		inodirty();
690209975Snwhitehorn	}
691209975Snwhitehorn	freeino(ino);
692188860Snwhitehorn}
693188860Snwhitehorn
694188860Snwhitehorn/*
695188860Snwhitehorn * generate a temporary name for the lost+found directory.
696188860Snwhitehorn */
697188860Snwhitehornstatic int
698188860Snwhitehornlftempname(bufp, ino)
699188860Snwhitehorn	char *bufp;
700277498Snwhitehorn	ino_t ino;
701188860Snwhitehorn{
702188860Snwhitehorn	register ino_t in;
703188860Snwhitehorn	register char *cp;
704188860Snwhitehorn	int namlen;
705188860Snwhitehorn
706188860Snwhitehorn	cp = bufp + 2;
707188860Snwhitehorn	for (in = maxino; in > 0; in /= 10)
708125441Sgrehan		cp++;
709125441Sgrehan	*--cp = 0;
710125441Sgrehan	namlen = cp - bufp;
711125441Sgrehan	in = ino;
712209975Snwhitehorn	while (cp > bufp) {
713209975Snwhitehorn		*--cp = (in % 10) + '0';
714209975Snwhitehorn		in /= 10;
715212722Snwhitehorn	}
716209975Snwhitehorn	*cp = '#';
717209975Snwhitehorn	return (namlen);
71895719Sbenno}
71995719Sbenno
72095719Sbenno/*
72195719Sbenno * Get a directory block.
722125441Sgrehan * Insure that it is held until another is requested.
723125441Sgrehan */
72499032Sbennostatic struct bufarea *
72595719Sbennogetdirblk(blkno, size)
726277334Snwhitehorn	ufs_daddr_t blkno;
727209975Snwhitehorn	long size;
728218824Snwhitehorn{
729209975Snwhitehorn
730209975Snwhitehorn	if (pdirbp != 0)
731209975Snwhitehorn		pdirbp->b_flags &= ~B_INUSE;
73296773Sbenno	pdirbp = getdatablk(blkno, size);
73395719Sbenno	return (pdirbp);
734125441Sgrehan}
735125441Sgrehan