xref: /freebsd/sbin/fsck_ffs/dir.c (revision e4a905d1e0d94ddb8e15de50d37e67f13e058047)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
48fae3551SRodney W. Grimes  * Copyright (c) 1980, 1986, 1993
58fae3551SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
68fae3551SRodney W. Grimes  *
78fae3551SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes  * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes  * are met:
108fae3551SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes  *    without specific prior written permission.
188fae3551SRodney W. Grimes  *
198fae3551SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes  * SUCH DAMAGE.
308fae3551SRodney W. Grimes  */
318fae3551SRodney W. Grimes 
326b100474SJulian Elischer #if 0
33c69284caSDavid E. O'Brien #ifndef lint
34780a5c1eSPeter Wemm static const char sccsid[] = "@(#)dir.c	8.8 (Berkeley) 4/28/95";
358fae3551SRodney W. Grimes #endif /* not lint */
36c69284caSDavid E. O'Brien #endif
37c69284caSDavid E. O'Brien #include <sys/cdefs.h>
38c69284caSDavid E. O'Brien __FBSDID("$FreeBSD$");
398fae3551SRodney W. Grimes 
408fae3551SRodney W. Grimes #include <sys/param.h>
41d33e92f9SJulian Elischer #include <sys/time.h>
4213eb765fSBaptiste Daroussin #include <sys/types.h>
437578c6abSKirk McKusick #include <sys/sysctl.h>
44780a5c1eSPeter Wemm 
458fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
468fae3551SRodney W. Grimes #include <ufs/ufs/dir.h>
478fae3551SRodney W. Grimes #include <ufs/ffs/fs.h>
4804aba254SBruce Evans 
49780a5c1eSPeter Wemm #include <err.h>
508fae3551SRodney W. Grimes #include <string.h>
51780a5c1eSPeter Wemm 
528fae3551SRodney W. Grimes #include "fsck.h"
538fae3551SRodney W. Grimes 
547703a6ffSScott Long static struct	dirtemplate emptydir = {
557578c6abSKirk McKusick 	0, DIRBLKSIZ, DT_UNKNOWN, 0, "",
567578c6abSKirk McKusick 	0, 0, DT_UNKNOWN, 0, ""
577578c6abSKirk McKusick };
587703a6ffSScott Long static struct	dirtemplate dirhead = {
598fae3551SRodney W. Grimes 	0, 12, DT_DIR, 1, ".",
608fae3551SRodney W. Grimes 	0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
618fae3551SRodney W. Grimes };
628fae3551SRodney W. Grimes 
63b70cd7eeSWarner Losh static int chgino(struct inodesc *);
64bfc5d3f9SKirk McKusick static int dircheck(struct inodesc *, struct bufarea *, struct direct *);
655cc52631SKirk McKusick static int expanddir(struct inode *ip, char *name);
66b70cd7eeSWarner Losh static struct direct *fsck_readdir(struct inodesc *);
671c85e6a3SKirk McKusick static struct bufarea *getdirblk(ufs2_daddr_t blkno, long size);
68b70cd7eeSWarner Losh static int lftempname(char *bufp, ino_t ino);
69b70cd7eeSWarner Losh static int mkentry(struct inodesc *);
708fae3551SRodney W. Grimes 
718fae3551SRodney W. Grimes /*
728fae3551SRodney W. Grimes  * Propagate connected state through the tree.
738fae3551SRodney W. Grimes  */
7431f4ab50SBruce Evans void
75b70cd7eeSWarner Losh propagate(void)
768fae3551SRodney W. Grimes {
773d438ad6SDavid E. O'Brien 	struct inoinfo **inpp, *inp;
788fae3551SRodney W. Grimes 	struct inoinfo **inpend;
798fae3551SRodney W. Grimes 	long change;
808fae3551SRodney W. Grimes 
818fae3551SRodney W. Grimes 	inpend = &inpsort[inplast];
828fae3551SRodney W. Grimes 	do {
838fae3551SRodney W. Grimes 		change = 0;
848fae3551SRodney W. Grimes 		for (inpp = inpsort; inpp < inpend; inpp++) {
858fae3551SRodney W. Grimes 			inp = *inpp;
868fae3551SRodney W. Grimes 			if (inp->i_parent == 0)
878fae3551SRodney W. Grimes 				continue;
88d33e92f9SJulian Elischer 			if (inoinfo(inp->i_parent)->ino_state == DFOUND &&
89af6726e6SDon Lewis 			    INO_IS_DUNFOUND(inp->i_number)) {
90d33e92f9SJulian Elischer 				inoinfo(inp->i_number)->ino_state = DFOUND;
91fe5e6e2cSKirk McKusick 				check_dirdepth(inp);
928fae3551SRodney W. Grimes 				change++;
938fae3551SRodney W. Grimes 			}
948fae3551SRodney W. Grimes 		}
958fae3551SRodney W. Grimes 	} while (change > 0);
968fae3551SRodney W. Grimes }
978fae3551SRodney W. Grimes 
988fae3551SRodney W. Grimes /*
99fe5e6e2cSKirk McKusick  * Check that the recorded depth of the directory is correct.
100fe5e6e2cSKirk McKusick  */
101fe5e6e2cSKirk McKusick void
102fe5e6e2cSKirk McKusick check_dirdepth(struct inoinfo *inp)
103fe5e6e2cSKirk McKusick {
104fe5e6e2cSKirk McKusick 	struct inoinfo *parentinp;
105fe5e6e2cSKirk McKusick 	struct inode ip;
106fe5e6e2cSKirk McKusick 	union dinode *dp;
107fe5e6e2cSKirk McKusick 	int saveresolved;
108*e4a905d1SKirk McKusick 	size_t size;
109fe5e6e2cSKirk McKusick 	static int updateasked, dirdepthupdate;
110fe5e6e2cSKirk McKusick 
111fe5e6e2cSKirk McKusick 	if ((parentinp = getinoinfo(inp->i_parent)) == NULL) {
112fe5e6e2cSKirk McKusick 		pfatal("check_dirdepth: UNKNOWN PARENT DIR");
113fe5e6e2cSKirk McKusick 		return;
114fe5e6e2cSKirk McKusick 	}
115fe5e6e2cSKirk McKusick 	/*
116fe5e6e2cSKirk McKusick 	 * If depth is correct, nothing to do.
117fe5e6e2cSKirk McKusick 	 */
118fe5e6e2cSKirk McKusick 	if (parentinp->i_depth + 1 == inp->i_depth)
119fe5e6e2cSKirk McKusick 		return;
120fe5e6e2cSKirk McKusick 	/*
121fe5e6e2cSKirk McKusick 	 * Only the root inode should have depth of 0, so if any other
122fe5e6e2cSKirk McKusick 	 * directory has a depth of 0 then this is an old filesystem
123fe5e6e2cSKirk McKusick 	 * that has not been tracking directory depth. Ask just once
124fe5e6e2cSKirk McKusick 	 * whether it should start tracking directory depth.
125fe5e6e2cSKirk McKusick 	 */
126fe5e6e2cSKirk McKusick 	if (inp->i_depth == 0 && updateasked == 0) {
127fe5e6e2cSKirk McKusick 		updateasked = 1;
128fe5e6e2cSKirk McKusick 		if (preen) {
129fe5e6e2cSKirk McKusick 			pwarn("UPDATING FILESYSTEM TO TRACK DIRECTORY DEPTH");
130fe5e6e2cSKirk McKusick 			dirdepthupdate = 1;
131fe5e6e2cSKirk McKusick 		} else {
132fe5e6e2cSKirk McKusick 			/*
133fe5e6e2cSKirk McKusick 			 * The file system can be marked clean even if
134fe5e6e2cSKirk McKusick 			 * a directory does not have the right depth.
135fe5e6e2cSKirk McKusick 			 * Hence, resolved should not be cleared when
136fe5e6e2cSKirk McKusick 			 * the filesystem does not update directory depths.
137fe5e6e2cSKirk McKusick 			 */
138fe5e6e2cSKirk McKusick 			saveresolved = resolved;
139fe5e6e2cSKirk McKusick 			dirdepthupdate =
140fe5e6e2cSKirk McKusick 			    reply("UPDATE FILESYSTEM TO TRACK DIRECTORY DEPTH");
141fe5e6e2cSKirk McKusick 			resolved = saveresolved;
142fe5e6e2cSKirk McKusick 		}
143fe5e6e2cSKirk McKusick 	}
144fe5e6e2cSKirk McKusick 	/*
145*e4a905d1SKirk McKusick 	 * If we are not converting or we are running in no-write mode
146*e4a905d1SKirk McKusick 	 * there is nothing more to do.
147fe5e6e2cSKirk McKusick 	 */
148*e4a905d1SKirk McKusick 	if ((inp->i_depth == 0 && dirdepthupdate == 0) ||
149*e4a905d1SKirk McKusick 	    (fswritefd < 0 && bkgrdflag == 0))
150fe5e6e2cSKirk McKusick 		return;
151fe5e6e2cSKirk McKusick 	/*
152fe5e6e2cSKirk McKusick 	 * Individual directory at wrong depth. Report it and correct if
153fe5e6e2cSKirk McKusick 	 * in preen mode or ask if in interactive mode. Note that if a
154fe5e6e2cSKirk McKusick 	 * directory is renamed to a new location that is at a different
155fe5e6e2cSKirk McKusick 	 * level in the tree, its depth will be recalculated, but none of
156fe5e6e2cSKirk McKusick 	 * the directories that it contains will be updated. Thus it is
157fe5e6e2cSKirk McKusick 	 * not unexpected to find directories with incorrect depths. No
158fe5e6e2cSKirk McKusick 	 * operational harm will come from this though new directory
159fe5e6e2cSKirk McKusick 	 * placement in the subtree may not be as optimal until the depths
160fe5e6e2cSKirk McKusick 	 * of the affected directories are corrected.
161fe5e6e2cSKirk McKusick 	 *
162fe5e6e2cSKirk McKusick 	 * To avoid much spurious output on otherwise clean filesystems
163fe5e6e2cSKirk McKusick 	 * we only generate detailed output when the debug flag is given.
164fe5e6e2cSKirk McKusick 	 */
165fe5e6e2cSKirk McKusick 	ginode(inp->i_number, &ip);
166fe5e6e2cSKirk McKusick 	dp = ip.i_dp;
167fe5e6e2cSKirk McKusick 	if (inp->i_depth != 0 && debug) {
168fe5e6e2cSKirk McKusick 		pwarn("DIRECTORY");
169fe5e6e2cSKirk McKusick 		prtinode(&ip);
170fe5e6e2cSKirk McKusick 		printf(" DEPTH %d SHOULD BE %d", inp->i_depth,
171fe5e6e2cSKirk McKusick 		    parentinp->i_depth + 1);
172fe5e6e2cSKirk McKusick 		if (preen == 0 && reply("ADJUST") == 0) {
173fe5e6e2cSKirk McKusick 			irelse(&ip);
174fe5e6e2cSKirk McKusick 			return;
175fe5e6e2cSKirk McKusick 		}
176fe5e6e2cSKirk McKusick 		if (preen)
177fe5e6e2cSKirk McKusick 			printf(" (ADJUSTED)\n");
178fe5e6e2cSKirk McKusick 	}
179fe5e6e2cSKirk McKusick 	inp->i_depth = parentinp->i_depth + 1;
180*e4a905d1SKirk McKusick 	if (bkgrdflag == 0) {
181fe5e6e2cSKirk McKusick 		DIP_SET(dp, di_dirdepth, inp->i_depth);
182fe5e6e2cSKirk McKusick 		inodirty(&ip);
183*e4a905d1SKirk McKusick 	} else {
184*e4a905d1SKirk McKusick 		cmd.value = inp->i_number;
185*e4a905d1SKirk McKusick 		cmd.size = (int64_t)inp->i_depth - DIP(dp, di_dirdepth);
186*e4a905d1SKirk McKusick 		if (debug)
187*e4a905d1SKirk McKusick 			printf("adjdepth ino %ld amt %jd\n", (long)cmd.value,
188*e4a905d1SKirk McKusick 			    (intmax_t)cmd.size);
189*e4a905d1SKirk McKusick 		size = MIBSIZE;
190*e4a905d1SKirk McKusick 		if (sysctlnametomib("vfs.ffs.adjdepth", adjdepth, &size) < 0 ||
191*e4a905d1SKirk McKusick 		    sysctl(adjdepth, MIBSIZE, 0, 0, &cmd, sizeof cmd) == -1)
192*e4a905d1SKirk McKusick 			rwerror("ADJUST INODE DEPTH", cmd.value);
193*e4a905d1SKirk McKusick 	}
194fe5e6e2cSKirk McKusick 	irelse(&ip);
195fe5e6e2cSKirk McKusick }
196fe5e6e2cSKirk McKusick 
197fe5e6e2cSKirk McKusick /*
1988fae3551SRodney W. Grimes  * Scan each entry in a directory block.
1998fae3551SRodney W. Grimes  */
20031f4ab50SBruce Evans int
201b70cd7eeSWarner Losh dirscan(struct inodesc *idesc)
2028fae3551SRodney W. Grimes {
2033d438ad6SDavid E. O'Brien 	struct direct *dp;
2043d438ad6SDavid E. O'Brien 	struct bufarea *bp;
2057578c6abSKirk McKusick 	u_int dsize, n;
2068fae3551SRodney W. Grimes 	long blksiz;
2078fae3551SRodney W. Grimes 	char dbuf[DIRBLKSIZ];
2088fae3551SRodney W. Grimes 
2098fae3551SRodney W. Grimes 	if (idesc->id_type != DATA)
210780a5c1eSPeter Wemm 		errx(EEXIT, "wrong type to dirscan %d", idesc->id_type);
2118fae3551SRodney W. Grimes 	if (idesc->id_entryno == 0 &&
2128fae3551SRodney W. Grimes 	    (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
2138fae3551SRodney W. Grimes 		idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
2148fae3551SRodney W. Grimes 	blksiz = idesc->id_numfrags * sblock.fs_fsize;
2158fae3551SRodney W. Grimes 	if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
2168fae3551SRodney W. Grimes 		idesc->id_filesize -= blksiz;
2178fae3551SRodney W. Grimes 		return (SKIP);
2188fae3551SRodney W. Grimes 	}
2198fae3551SRodney W. Grimes 	idesc->id_loc = 0;
2208fae3551SRodney W. Grimes 	for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
2218fae3551SRodney W. Grimes 		dsize = dp->d_reclen;
222d33e92f9SJulian Elischer 		if (dsize > sizeof(dbuf))
223d33e92f9SJulian Elischer 			dsize = sizeof(dbuf);
224780a5c1eSPeter Wemm 		memmove(dbuf, dp, (size_t)dsize);
2258fae3551SRodney W. Grimes 		idesc->id_dirp = (struct direct *)dbuf;
2268fae3551SRodney W. Grimes 		if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
2278fae3551SRodney W. Grimes 			bp = getdirblk(idesc->id_blkno, blksiz);
2285cc52631SKirk McKusick 			if (bp->b_errs != 0)
2295cc52631SKirk McKusick 				return (STOP);
230780a5c1eSPeter Wemm 			memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
2318fae3551SRodney W. Grimes 			    (size_t)dsize);
2328fae3551SRodney W. Grimes 			dirty(bp);
2338fae3551SRodney W. Grimes 			sbdirty();
2348fae3551SRodney W. Grimes 		}
2358fae3551SRodney W. Grimes 		if (n & STOP)
2368fae3551SRodney W. Grimes 			return (n);
2378fae3551SRodney W. Grimes 	}
2388fae3551SRodney W. Grimes 	return (idesc->id_filesize > 0 ? KEEPON : STOP);
2398fae3551SRodney W. Grimes }
2408fae3551SRodney W. Grimes 
2418fae3551SRodney W. Grimes /*
242bfc5d3f9SKirk McKusick  * Get and verify the next entry in a directory.
243bfc5d3f9SKirk McKusick  * We also verify that if there is another entry in the block that it is
244bfc5d3f9SKirk McKusick  * valid, so if it is not valid it can be subsumed into the current entry.
2458fae3551SRodney W. Grimes  */
246780a5c1eSPeter Wemm static struct direct *
247b70cd7eeSWarner Losh fsck_readdir(struct inodesc *idesc)
2488fae3551SRodney W. Grimes {
2493d438ad6SDavid E. O'Brien 	struct direct *dp, *ndp;
2503d438ad6SDavid E. O'Brien 	struct bufarea *bp;
251bfc5d3f9SKirk McKusick 	long size, blksiz, subsume_ndp;
2528fae3551SRodney W. Grimes 
253bfc5d3f9SKirk McKusick 	subsume_ndp = 0;
2548fae3551SRodney W. Grimes 	blksiz = idesc->id_numfrags * sblock.fs_fsize;
2558fae3551SRodney W. Grimes 	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
256bfc5d3f9SKirk McKusick 		return (NULL);
257bfc5d3f9SKirk McKusick 	bp = getdirblk(idesc->id_blkno, blksiz);
2585cc52631SKirk McKusick 	if (bp->b_errs != 0)
2595cc52631SKirk McKusick 		return (NULL);
260bfc5d3f9SKirk McKusick 	dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
261bfc5d3f9SKirk McKusick 	/*
262bfc5d3f9SKirk McKusick 	 * Only need to check current entry if it is the first in the
263bfc5d3f9SKirk McKusick 	 * the block, as later entries will have been checked in the
264bfc5d3f9SKirk McKusick 	 * previous call to this function.
265bfc5d3f9SKirk McKusick 	 */
266bfc5d3f9SKirk McKusick 	if (idesc->id_loc % DIRBLKSIZ != 0 || dircheck(idesc, bp, dp) != 0) {
267bfc5d3f9SKirk McKusick 		/*
268bfc5d3f9SKirk McKusick 		 * Current entry is good, update to point at next.
269bfc5d3f9SKirk McKusick 		 */
2708fae3551SRodney W. Grimes 		idesc->id_loc += dp->d_reclen;
2718fae3551SRodney W. Grimes 		idesc->id_filesize -= dp->d_reclen;
272bfc5d3f9SKirk McKusick 		/*
273bfc5d3f9SKirk McKusick 		 * If at end of directory block, just return this entry.
274bfc5d3f9SKirk McKusick 		 */
275bfc5d3f9SKirk McKusick 		if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz ||
276bfc5d3f9SKirk McKusick 		    idesc->id_loc % DIRBLKSIZ == 0)
2778fae3551SRodney W. Grimes 			return (dp);
278bfc5d3f9SKirk McKusick 		/*
279bfc5d3f9SKirk McKusick 		 * If the next entry good, return this entry.
280bfc5d3f9SKirk McKusick 		 */
2818fae3551SRodney W. Grimes 		ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
282bfc5d3f9SKirk McKusick 		if (dircheck(idesc, bp, ndp) != 0)
283bfc5d3f9SKirk McKusick 			return (dp);
284bfc5d3f9SKirk McKusick 		/*
285bfc5d3f9SKirk McKusick 		 * The next entry is bad, so subsume it and the remainder
286bfc5d3f9SKirk McKusick 		 * of this directory block into this entry.
287bfc5d3f9SKirk McKusick 		 */
288bfc5d3f9SKirk McKusick 		subsume_ndp = 1;
289bfc5d3f9SKirk McKusick 	}
290bfc5d3f9SKirk McKusick 	/*
291bfc5d3f9SKirk McKusick 	 * Current or next entry is bad. Zap current entry or
292bfc5d3f9SKirk McKusick 	 * subsume next entry into current entry as appropriate.
293bfc5d3f9SKirk McKusick 	 */
2948fae3551SRodney W. Grimes 	size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
2958fae3551SRodney W. Grimes 	idesc->id_loc += size;
2968fae3551SRodney W. Grimes 	idesc->id_filesize -= size;
297780a5c1eSPeter Wemm 	if (idesc->id_fix == IGNORE)
298bfc5d3f9SKirk McKusick 		return (NULL);
299bfc5d3f9SKirk McKusick 	if (subsume_ndp) {
300bfc5d3f9SKirk McKusick 		memset(ndp, 0, size);
3018fae3551SRodney W. Grimes 		dp->d_reclen += size;
302bfc5d3f9SKirk McKusick 	} else {
303bfc5d3f9SKirk McKusick 		memset(dp, 0, size);
304bfc5d3f9SKirk McKusick 		dp->d_reclen = size;
3050061238fSKirk McKusick 	}
306bfc5d3f9SKirk McKusick 	if (dofix(idesc, "DIRECTORY CORRUPTED"))
307bfc5d3f9SKirk McKusick 		dirty(bp);
3088fae3551SRodney W. Grimes 	return (dp);
3098fae3551SRodney W. Grimes }
3108fae3551SRodney W. Grimes 
3118fae3551SRodney W. Grimes /*
3128fae3551SRodney W. Grimes  * Verify that a directory entry is valid.
3138fae3551SRodney W. Grimes  * This is a superset of the checks made in the kernel.
3140061238fSKirk McKusick  * Also optionally clears padding and unused directory space.
3150061238fSKirk McKusick  *
316bfc5d3f9SKirk McKusick  * Returns 0 if the entry is bad, 1 if the entry is good.
3178fae3551SRodney W. Grimes  */
318780a5c1eSPeter Wemm static int
319bfc5d3f9SKirk McKusick dircheck(struct inodesc *idesc, struct bufarea *bp, struct direct *dp)
3208fae3551SRodney W. Grimes {
321c69284caSDavid E. O'Brien 	size_t size;
3223d438ad6SDavid E. O'Brien 	char *cp;
323fdc61a88SXin LI 	u_int8_t namlen;
3240061238fSKirk McKusick 	int spaceleft, modified, unused;
3258fae3551SRodney W. Grimes 
3268fae3551SRodney W. Grimes 	spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
327bfc5d3f9SKirk McKusick 	size = DIRSIZ(0, dp);
328d33e92f9SJulian Elischer 	if (dp->d_reclen == 0 ||
329780a5c1eSPeter Wemm 	    dp->d_reclen > spaceleft ||
330bfc5d3f9SKirk McKusick 	    dp->d_reclen < size ||
331bfc5d3f9SKirk McKusick 	    idesc->id_filesize < size ||
3320061238fSKirk McKusick 	    (dp->d_reclen & (DIR_ROUNDUP - 1)) != 0)
333142d8d2fSKirk McKusick 		goto bad;
334bfc5d3f9SKirk McKusick 	modified = 0;
3350061238fSKirk McKusick 	if (dp->d_ino == 0) {
336bfc5d3f9SKirk McKusick 		if (!zflag || fswritefd < 0)
337bfc5d3f9SKirk McKusick 			return (1);
3380061238fSKirk McKusick 		/*
339bfc5d3f9SKirk McKusick 		 * Special case of an unused directory entry. Normally only
340bfc5d3f9SKirk McKusick 		 * occurs at the beginning of a directory block when the block
341bfc5d3f9SKirk McKusick 		 * contains no entries. Other than the first entry in a
342bfc5d3f9SKirk McKusick 		 * directory block, the kernel coalesces unused space with
343bfc5d3f9SKirk McKusick 		 * the previous entry by extending its d_reclen. However,
344bfc5d3f9SKirk McKusick 		 * when cleaning up a directory, fsck may set d_ino to zero
345bfc5d3f9SKirk McKusick 		 * in the middle of a directory block. If we're clearing out
346bfc5d3f9SKirk McKusick 		 * directory cruft (-z flag), then make sure that all directory
347bfc5d3f9SKirk McKusick 		 * space in entries with d_ino == 0 gets fully cleared.
3480061238fSKirk McKusick 		 */
3490061238fSKirk McKusick 		if (dp->d_type != 0) {
3500061238fSKirk McKusick 			dp->d_type = 0;
3510061238fSKirk McKusick 			modified = 1;
3520061238fSKirk McKusick 		}
3530061238fSKirk McKusick 		if (dp->d_namlen != 0) {
3540061238fSKirk McKusick 			dp->d_namlen = 0;
3550061238fSKirk McKusick 			modified = 1;
3560061238fSKirk McKusick 		}
357bfc5d3f9SKirk McKusick 		unused = dp->d_reclen - __offsetof(struct direct, d_name);
358bfc5d3f9SKirk McKusick 		for (cp = dp->d_name; unused > 0; unused--, cp++) {
359bfc5d3f9SKirk McKusick 			if (*cp != '\0') {
360bfc5d3f9SKirk McKusick 				*cp = '\0';
3610061238fSKirk McKusick 				modified = 1;
3620061238fSKirk McKusick 			}
3630061238fSKirk McKusick 		}
364bfc5d3f9SKirk McKusick 		if (modified)
365bfc5d3f9SKirk McKusick 			dirty(bp);
366bfc5d3f9SKirk McKusick 		return (1);
3670061238fSKirk McKusick 	}
368bfc5d3f9SKirk McKusick 	/*
369bfc5d3f9SKirk McKusick 	 * The d_type field should not be tested here. A bad type is an error
370bfc5d3f9SKirk McKusick 	 * in the entry itself but is not a corruption of the directory
371bfc5d3f9SKirk McKusick 	 * structure itself. So blowing away all the remaining entries in the
372bfc5d3f9SKirk McKusick 	 * directory block is inappropriate. Rather the type error should be
373bfc5d3f9SKirk McKusick 	 * checked in pass1 and fixed there.
374bfc5d3f9SKirk McKusick 	 *
375bfc5d3f9SKirk McKusick 	 * The name validation should also be done in pass1 although the
376bfc5d3f9SKirk McKusick 	 * check to see if the name is longer than fits in the space
377bfc5d3f9SKirk McKusick 	 * allocated for it (i.e., the *cp != '\0' fails after exiting the
378bfc5d3f9SKirk McKusick 	 * loop below) then it really is a structural error that requires
379bfc5d3f9SKirk McKusick 	 * the stronger action taken here.
380bfc5d3f9SKirk McKusick 	 */
3818fae3551SRodney W. Grimes 	namlen = dp->d_namlen;
382bfc5d3f9SKirk McKusick 	if (namlen == 0 || dp->d_type > 15)
383142d8d2fSKirk McKusick 		goto bad;
384bfc5d3f9SKirk McKusick 	for (cp = dp->d_name, size = 0; size < namlen; size++) {
385bfc5d3f9SKirk McKusick 		if (*cp == '\0' || *cp++ == '/')
386142d8d2fSKirk McKusick 			goto bad;
387bfc5d3f9SKirk McKusick 	}
388780a5c1eSPeter Wemm 	if (*cp != '\0')
389142d8d2fSKirk McKusick 		goto bad;
3900061238fSKirk McKusick 	if (zflag && fswritefd >= 0) {
3910061238fSKirk McKusick 		/*
3920061238fSKirk McKusick 		 * Clear unused directory entry space, including the d_name
3930061238fSKirk McKusick 		 * padding.
3940061238fSKirk McKusick 		 */
3950061238fSKirk McKusick 		/* First figure the number of pad bytes. */
3960061238fSKirk McKusick 		unused = roundup2(namlen + 1, DIR_ROUNDUP) - (namlen + 1);
3970061238fSKirk McKusick 
3980061238fSKirk McKusick 		/* Add in the free space to the end of the record. */
3990061238fSKirk McKusick 		unused += dp->d_reclen - DIRSIZ(0, dp);
4000061238fSKirk McKusick 
4010061238fSKirk McKusick 		/*
4020061238fSKirk McKusick 		 * Now clear out the unused space, keeping track if we actually
4030061238fSKirk McKusick 		 * changed anything.
4040061238fSKirk McKusick 		 */
4050061238fSKirk McKusick 		for (cp = &dp->d_name[namlen + 1]; unused > 0; unused--, cp++) {
4060061238fSKirk McKusick 			if (*cp != '\0') {
4070061238fSKirk McKusick 				*cp = '\0';
4080061238fSKirk McKusick 				modified = 1;
4090061238fSKirk McKusick 			}
4100061238fSKirk McKusick 		}
4110061238fSKirk McKusick 
412bfc5d3f9SKirk McKusick 		if (modified)
413bfc5d3f9SKirk McKusick 			dirty(bp);
4140061238fSKirk McKusick 	}
4158fae3551SRodney W. Grimes 	return (1);
4160061238fSKirk McKusick 
417142d8d2fSKirk McKusick bad:
418142d8d2fSKirk McKusick 	if (debug)
419142d8d2fSKirk McKusick 		printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n",
420142d8d2fSKirk McKusick 		    dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type,
421142d8d2fSKirk McKusick 		    dp->d_name);
422142d8d2fSKirk McKusick 	return (0);
4238fae3551SRodney W. Grimes }
4248fae3551SRodney W. Grimes 
42531f4ab50SBruce Evans void
426599304a4SPoul-Henning Kamp direrror(ino_t ino, const char *errmesg)
4278fae3551SRodney W. Grimes {
4288fae3551SRodney W. Grimes 
4298fae3551SRodney W. Grimes 	fileerror(ino, ino, errmesg);
4308fae3551SRodney W. Grimes }
4318fae3551SRodney W. Grimes 
43231f4ab50SBruce Evans void
433599304a4SPoul-Henning Kamp fileerror(ino_t cwd, ino_t ino, const char *errmesg)
4348fae3551SRodney W. Grimes {
4355cc52631SKirk McKusick 	struct inode ip;
4361c85e6a3SKirk McKusick 	union dinode *dp;
4378fae3551SRodney W. Grimes 	char pathbuf[MAXPATHLEN + 1];
4388fae3551SRodney W. Grimes 
4398fae3551SRodney W. Grimes 	pwarn("%s ", errmesg);
4401dc349abSEd Maste 	if (ino < UFS_ROOTINO || ino > maxino) {
4419fc5d538SKirk McKusick 		pfatal("out-of-range inode number %ju", (uintmax_t)ino);
4428fae3551SRodney W. Grimes 		return;
4438fae3551SRodney W. Grimes 	}
4445cc52631SKirk McKusick 	ginode(ino, &ip);
4455cc52631SKirk McKusick 	dp = ip.i_dp;
4465cc52631SKirk McKusick 	prtinode(&ip);
4479fc5d538SKirk McKusick 	printf("\n");
4489fc5d538SKirk McKusick 	getpathname(pathbuf, cwd, ino);
4498fae3551SRodney W. Grimes 	if (ftypeok(dp))
4508fae3551SRodney W. Grimes 		pfatal("%s=%s\n",
451d8ba45e2SEd Maste 		    (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE",
4521c85e6a3SKirk McKusick 		    pathbuf);
4538fae3551SRodney W. Grimes 	else
4548fae3551SRodney W. Grimes 		pfatal("NAME=%s\n", pathbuf);
4555cc52631SKirk McKusick 	irelse(&ip);
4568fae3551SRodney W. Grimes }
4578fae3551SRodney W. Grimes 
45831f4ab50SBruce Evans void
459b70cd7eeSWarner Losh adjust(struct inodesc *idesc, int lcnt)
4608fae3551SRodney W. Grimes {
4615cc52631SKirk McKusick 	struct inode ip;
4621c85e6a3SKirk McKusick 	union dinode *dp;
463d33e92f9SJulian Elischer 	int saveresolved;
4648fae3551SRodney W. Grimes 
4655cc52631SKirk McKusick 	ginode(idesc->id_number, &ip);
4665cc52631SKirk McKusick 	dp = ip.i_dp;
4671c85e6a3SKirk McKusick 	if (DIP(dp, di_nlink) == lcnt) {
468d33e92f9SJulian Elischer 		/*
469d33e92f9SJulian Elischer 		 * If we have not hit any unresolved problems, are running
470d33e92f9SJulian Elischer 		 * in preen mode, and are on a file system using soft updates,
471d33e92f9SJulian Elischer 		 * then just toss any partially allocated files.
472d33e92f9SJulian Elischer 		 */
4737578c6abSKirk McKusick 		if (resolved && (preen || bkgrdflag) && usedsoftdep) {
474d33e92f9SJulian Elischer 			clri(idesc, "UNREF", 1);
4755cc52631SKirk McKusick 			irelse(&ip);
476d33e92f9SJulian Elischer 			return;
4778fae3551SRodney W. Grimes 		} else {
478d33e92f9SJulian Elischer 			/*
479d33e92f9SJulian Elischer 			 * The file system can be marked clean even if
480d33e92f9SJulian Elischer 			 * a file is not linked up, but is cleared.
481d33e92f9SJulian Elischer 			 * Hence, resolved should not be cleared when
482d33e92f9SJulian Elischer 			 * linkup is answered no, but clri is answered yes.
483d33e92f9SJulian Elischer 			 */
484d33e92f9SJulian Elischer 			saveresolved = resolved;
485d33e92f9SJulian Elischer 			if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) {
486d33e92f9SJulian Elischer 				resolved = saveresolved;
487d33e92f9SJulian Elischer 				clri(idesc, "UNREF", 0);
4885cc52631SKirk McKusick 				irelse(&ip);
489d33e92f9SJulian Elischer 				return;
490d33e92f9SJulian Elischer 			}
491d33e92f9SJulian Elischer 			/*
492d33e92f9SJulian Elischer 			 * Account for the new reference created by linkup().
493d33e92f9SJulian Elischer 			 */
494d33e92f9SJulian Elischer 			lcnt--;
495d33e92f9SJulian Elischer 		}
496d33e92f9SJulian Elischer 	}
497d33e92f9SJulian Elischer 	if (lcnt != 0) {
4988fae3551SRodney W. Grimes 		pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
499d8ba45e2SEd Maste 			((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"));
5005cc52631SKirk McKusick 		prtinode(&ip);
5018fae3551SRodney W. Grimes 		printf(" COUNT %d SHOULD BE %d",
5021c85e6a3SKirk McKusick 			DIP(dp, di_nlink), DIP(dp, di_nlink) - lcnt);
503b1897c19SJulian Elischer 		if (preen || usedsoftdep) {
5048fae3551SRodney W. Grimes 			if (lcnt < 0) {
5058fae3551SRodney W. Grimes 				printf("\n");
5068fae3551SRodney W. Grimes 				pfatal("LINK COUNT INCREASING");
5078fae3551SRodney W. Grimes 			}
508b1897c19SJulian Elischer 			if (preen)
5098fae3551SRodney W. Grimes 				printf(" (ADJUSTED)\n");
5108fae3551SRodney W. Grimes 		}
5118fae3551SRodney W. Grimes 		if (preen || reply("ADJUST") == 1) {
5127578c6abSKirk McKusick 			if (bkgrdflag == 0) {
513c3b2344bSScott Long 				DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - lcnt);
5145cc52631SKirk McKusick 				inodirty(&ip);
5157578c6abSKirk McKusick 			} else {
5167578c6abSKirk McKusick 				cmd.value = idesc->id_number;
5177578c6abSKirk McKusick 				cmd.size = -lcnt;
5187578c6abSKirk McKusick 				if (debug)
519599304a4SPoul-Henning Kamp 					printf("adjrefcnt ino %ld amt %lld\n",
520599304a4SPoul-Henning Kamp 					    (long)cmd.value,
521599304a4SPoul-Henning Kamp 					    (long long)cmd.size);
5227578c6abSKirk McKusick 				if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
5237578c6abSKirk McKusick 				    &cmd, sizeof cmd) == -1)
524*e4a905d1SKirk McKusick 					rwerror("ADJUST INODE LINK COUNT",
525*e4a905d1SKirk McKusick 					    cmd.value);
5267578c6abSKirk McKusick 			}
5278fae3551SRodney W. Grimes 		}
5288fae3551SRodney W. Grimes 	}
5295cc52631SKirk McKusick 	irelse(&ip);
5308fae3551SRodney W. Grimes }
5318fae3551SRodney W. Grimes 
532780a5c1eSPeter Wemm static int
533b70cd7eeSWarner Losh mkentry(struct inodesc *idesc)
5348fae3551SRodney W. Grimes {
5353d438ad6SDavid E. O'Brien 	struct direct *dirp = idesc->id_dirp;
5368fae3551SRodney W. Grimes 	struct direct newent;
5378fae3551SRodney W. Grimes 	int newlen, oldlen;
5388fae3551SRodney W. Grimes 
5398fae3551SRodney W. Grimes 	newent.d_namlen = strlen(idesc->id_name);
5408fae3551SRodney W. Grimes 	newlen = DIRSIZ(0, &newent);
5418fae3551SRodney W. Grimes 	if (dirp->d_ino != 0)
5428fae3551SRodney W. Grimes 		oldlen = DIRSIZ(0, dirp);
5438fae3551SRodney W. Grimes 	else
5448fae3551SRodney W. Grimes 		oldlen = 0;
5458fae3551SRodney W. Grimes 	if (dirp->d_reclen - oldlen < newlen)
5468fae3551SRodney W. Grimes 		return (KEEPON);
5478fae3551SRodney W. Grimes 	newent.d_reclen = dirp->d_reclen - oldlen;
5488fae3551SRodney W. Grimes 	dirp->d_reclen = oldlen;
5498fae3551SRodney W. Grimes 	dirp = (struct direct *)(((char *)dirp) + oldlen);
5508fae3551SRodney W. Grimes 	dirp->d_ino = idesc->id_parent;	/* ino to be entered is in id_parent */
551780a5c1eSPeter Wemm 	dirp->d_reclen = newent.d_reclen;
552d33e92f9SJulian Elischer 	dirp->d_type = inoinfo(idesc->id_parent)->ino_type;
5539fef3122SDavid Greenman 	dirp->d_namlen = newent.d_namlen;
554780a5c1eSPeter Wemm 	memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1);
5558fae3551SRodney W. Grimes 	return (ALTERED|STOP);
5568fae3551SRodney W. Grimes }
5578fae3551SRodney W. Grimes 
558780a5c1eSPeter Wemm static int
559b70cd7eeSWarner Losh chgino(struct inodesc *idesc)
5608fae3551SRodney W. Grimes {
5613d438ad6SDavid E. O'Brien 	struct direct *dirp = idesc->id_dirp;
5628fae3551SRodney W. Grimes 
563780a5c1eSPeter Wemm 	if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
5648fae3551SRodney W. Grimes 		return (KEEPON);
5658fae3551SRodney W. Grimes 	dirp->d_ino = idesc->id_parent;
566d33e92f9SJulian Elischer 	dirp->d_type = inoinfo(idesc->id_parent)->ino_type;
5678fae3551SRodney W. Grimes 	return (ALTERED|STOP);
5688fae3551SRodney W. Grimes }
5698fae3551SRodney W. Grimes 
57031f4ab50SBruce Evans int
571b70cd7eeSWarner Losh linkup(ino_t orphan, ino_t parentdir, char *name)
5728fae3551SRodney W. Grimes {
5735cc52631SKirk McKusick 	struct inode ip;
5741c85e6a3SKirk McKusick 	union dinode *dp;
575fe5e6e2cSKirk McKusick 	int lostdir, depth;
5768fae3551SRodney W. Grimes 	ino_t oldlfdir;
577f4fc3895SKirk McKusick 	struct inoinfo *inp;
5788fae3551SRodney W. Grimes 	struct inodesc idesc;
5798fae3551SRodney W. Grimes 	char tempname[BUFSIZ];
5808fae3551SRodney W. Grimes 
581780a5c1eSPeter Wemm 	memset(&idesc, 0, sizeof(struct inodesc));
5825cc52631SKirk McKusick 	ginode(orphan, &ip);
5835cc52631SKirk McKusick 	dp = ip.i_dp;
584d8ba45e2SEd Maste 	lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR;
5858fae3551SRodney W. Grimes 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
5865cc52631SKirk McKusick 	prtinode(&ip);
5879fc5d538SKirk McKusick 	printf("\n");
5885cc52631SKirk McKusick 	if (preen && DIP(dp, di_size) == 0) {
5895cc52631SKirk McKusick 		irelse(&ip);
5908fae3551SRodney W. Grimes 		return (0);
5915cc52631SKirk McKusick 	}
5925cc52631SKirk McKusick 	irelse(&ip);
5937578c6abSKirk McKusick 	if (cursnapshot != 0) {
5947578c6abSKirk McKusick 		pfatal("FILE LINKUP IN SNAPSHOT");
5957578c6abSKirk McKusick 		return (0);
5967578c6abSKirk McKusick 	}
5978fae3551SRodney W. Grimes 	if (preen)
5988fae3551SRodney W. Grimes 		printf(" (RECONNECTED)\n");
5995cc52631SKirk McKusick 	else if (reply("RECONNECT") == 0)
6008fae3551SRodney W. Grimes 		return (0);
6018fae3551SRodney W. Grimes 	if (lfdir == 0) {
6025cc52631SKirk McKusick 		ginode(UFS_ROOTINO, &ip);
603599304a4SPoul-Henning Kamp 		idesc.id_name = strdup(lfname);
6048fae3551SRodney W. Grimes 		idesc.id_type = DATA;
6058fae3551SRodney W. Grimes 		idesc.id_func = findino;
6061dc349abSEd Maste 		idesc.id_number = UFS_ROOTINO;
6075cc52631SKirk McKusick 		if ((ckinode(ip.i_dp, &idesc) & FOUND) != 0) {
6088fae3551SRodney W. Grimes 			lfdir = idesc.id_parent;
6098fae3551SRodney W. Grimes 		} else {
6108fae3551SRodney W. Grimes 			pwarn("NO lost+found DIRECTORY");
6118fae3551SRodney W. Grimes 			if (preen || reply("CREATE")) {
6121dc349abSEd Maste 				lfdir = allocdir(UFS_ROOTINO, (ino_t)0, lfmode);
6138fae3551SRodney W. Grimes 				if (lfdir != 0) {
6141dc349abSEd Maste 					if (makeentry(UFS_ROOTINO, lfdir,
6151dc349abSEd Maste 					    lfname) != 0) {
616d33e92f9SJulian Elischer 						numdirs++;
6178fae3551SRodney W. Grimes 						if (preen)
6188fae3551SRodney W. Grimes 							printf(" (CREATED)\n");
6198fae3551SRodney W. Grimes 					} else {
62052f97104SKirk McKusick 						freedirino(lfdir, UFS_ROOTINO);
6218fae3551SRodney W. Grimes 						lfdir = 0;
6228fae3551SRodney W. Grimes 						if (preen)
6238fae3551SRodney W. Grimes 							printf("\n");
6248fae3551SRodney W. Grimes 					}
6258fae3551SRodney W. Grimes 				}
6268fae3551SRodney W. Grimes 			}
6278fae3551SRodney W. Grimes 		}
6285cc52631SKirk McKusick 		irelse(&ip);
629e5d0d1c5SKirk McKusick 		free(idesc.id_name);
6308fae3551SRodney W. Grimes 		if (lfdir == 0) {
6318fae3551SRodney W. Grimes 			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
6328fae3551SRodney W. Grimes 			printf("\n\n");
6338fae3551SRodney W. Grimes 			return (0);
6348fae3551SRodney W. Grimes 		}
6358fae3551SRodney W. Grimes 	}
6365cc52631SKirk McKusick 	ginode(lfdir, &ip);
6375cc52631SKirk McKusick 	dp = ip.i_dp;
638d8ba45e2SEd Maste 	if ((DIP(dp, di_mode) & IFMT) != IFDIR) {
6398fae3551SRodney W. Grimes 		pfatal("lost+found IS NOT A DIRECTORY");
6405cc52631SKirk McKusick 		if (reply("REALLOCATE") == 0) {
6415cc52631SKirk McKusick 			irelse(&ip);
6428fae3551SRodney W. Grimes 			return (0);
6435cc52631SKirk McKusick 		}
6448fae3551SRodney W. Grimes 		oldlfdir = lfdir;
6451dc349abSEd Maste 		if ((lfdir = allocdir(UFS_ROOTINO, (ino_t)0, lfmode)) == 0) {
6468fae3551SRodney W. Grimes 			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
6475cc52631SKirk McKusick 			irelse(&ip);
6488fae3551SRodney W. Grimes 			return (0);
6498fae3551SRodney W. Grimes 		}
650fe5e6e2cSKirk McKusick 		if ((changeino(UFS_ROOTINO, lfname, lfdir, 1) & ALTERED) == 0) {
6518fae3551SRodney W. Grimes 			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
6525cc52631SKirk McKusick 			irelse(&ip);
6538fae3551SRodney W. Grimes 			return (0);
6548fae3551SRodney W. Grimes 		}
6555cc52631SKirk McKusick 		idesc.id_type = inoinfo(oldlfdir)->ino_idtype;
6567180f1abSKirk McKusick 		idesc.id_func = freeblock;
6578fae3551SRodney W. Grimes 		idesc.id_number = oldlfdir;
658d33e92f9SJulian Elischer 		adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1);
659d33e92f9SJulian Elischer 		inoinfo(oldlfdir)->ino_linkcnt = 0;
6605cc52631SKirk McKusick 		inodirty(&ip);
6615cc52631SKirk McKusick 		irelse(&ip);
6625cc52631SKirk McKusick 		ginode(lfdir, &ip);
6635cc52631SKirk McKusick 		dp = ip.i_dp;
6648fae3551SRodney W. Grimes 	}
665d33e92f9SJulian Elischer 	if (inoinfo(lfdir)->ino_state != DFOUND) {
6668fae3551SRodney W. Grimes 		pfatal("SORRY. NO lost+found DIRECTORY\n\n");
6675cc52631SKirk McKusick 		irelse(&ip);
6688fae3551SRodney W. Grimes 		return (0);
6698fae3551SRodney W. Grimes 	}
6708fae3551SRodney W. Grimes 	(void)lftempname(tempname, orphan);
671d33e92f9SJulian Elischer 	if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) {
6728fae3551SRodney W. Grimes 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
6738fae3551SRodney W. Grimes 		printf("\n\n");
6745cc52631SKirk McKusick 		irelse(&ip);
6758fae3551SRodney W. Grimes 		return (0);
6768fae3551SRodney W. Grimes 	}
677d33e92f9SJulian Elischer 	inoinfo(orphan)->ino_linkcnt--;
6788fae3551SRodney W. Grimes 	if (lostdir) {
679fe5e6e2cSKirk McKusick 		depth = DIP(dp, di_dirdepth) + 1;
680fe5e6e2cSKirk McKusick 		if ((changeino(orphan, "..", lfdir, depth) & ALTERED) == 0 &&
6818fae3551SRodney W. Grimes 		    parentdir != (ino_t)-1)
6828fae3551SRodney W. Grimes 			(void)makeentry(orphan, lfdir, "..");
683c3b2344bSScott Long 		DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
6845cc52631SKirk McKusick 		inodirty(&ip);
685d33e92f9SJulian Elischer 		inoinfo(lfdir)->ino_linkcnt++;
686bf58d635SIan Dowse 		pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan);
687f4fc3895SKirk McKusick 		inp = getinoinfo(parentdir);
68852f97104SKirk McKusick 		if (parentdir != (ino_t)-1 && inp != NULL) {
689b1046626SBruce Evans 			printf("PARENT WAS I=%lu\n", (u_long)parentdir);
6906b100474SJulian Elischer 			/*
691f4fc3895SKirk McKusick 			 * If the parent directory did not have to
692f4fc3895SKirk McKusick 			 * be replaced then because of the ordering
6936b100474SJulian Elischer 			 * guarantees, has had the link count incremented
6946b100474SJulian Elischer 			 * for the child, but no entry was made.  This
6956b100474SJulian Elischer 			 * fixes the parent link count so that fsck does
6966b100474SJulian Elischer 			 * not need to be rerun.
6976b100474SJulian Elischer 			 */
69852f97104SKirk McKusick 			if ((inp->i_flags & INFO_NEW) != 0)
699d33e92f9SJulian Elischer 				inoinfo(parentdir)->ino_linkcnt++;
700119e9fc2SNate Williams 		}
7018fae3551SRodney W. Grimes 		if (preen == 0)
7028fae3551SRodney W. Grimes 			printf("\n");
7038fae3551SRodney W. Grimes 	}
7045cc52631SKirk McKusick 	irelse(&ip);
7058fae3551SRodney W. Grimes 	return (1);
7068fae3551SRodney W. Grimes }
7078fae3551SRodney W. Grimes 
7088fae3551SRodney W. Grimes /*
7098fae3551SRodney W. Grimes  * fix an entry in a directory.
7108fae3551SRodney W. Grimes  */
71131f4ab50SBruce Evans int
712fe5e6e2cSKirk McKusick changeino(ino_t dir, const char *name, ino_t newnum, int depth)
7138fae3551SRodney W. Grimes {
7148fae3551SRodney W. Grimes 	struct inodesc idesc;
7155cc52631SKirk McKusick 	struct inode ip;
7165cc52631SKirk McKusick 	int error;
7178fae3551SRodney W. Grimes 
718780a5c1eSPeter Wemm 	memset(&idesc, 0, sizeof(struct inodesc));
7198fae3551SRodney W. Grimes 	idesc.id_type = DATA;
7208fae3551SRodney W. Grimes 	idesc.id_func = chgino;
7218fae3551SRodney W. Grimes 	idesc.id_number = dir;
7228fae3551SRodney W. Grimes 	idesc.id_fix = DONTKNOW;
723599304a4SPoul-Henning Kamp 	idesc.id_name = strdup(name);
7248fae3551SRodney W. Grimes 	idesc.id_parent = newnum;	/* new value for name */
7255cc52631SKirk McKusick 	ginode(dir, &ip);
726fe5e6e2cSKirk McKusick 	if (((error = ckinode(ip.i_dp, &idesc)) & ALTERED) && newnum != 0) {
727fe5e6e2cSKirk McKusick 		DIP_SET(ip.i_dp, di_dirdepth, depth);
728fe5e6e2cSKirk McKusick 		getinoinfo(dir)->i_depth = depth;
729fe5e6e2cSKirk McKusick 	}
730e5d0d1c5SKirk McKusick 	free(idesc.id_name);
7315cc52631SKirk McKusick 	irelse(&ip);
7325cc52631SKirk McKusick 	return (error);
7338fae3551SRodney W. Grimes }
7348fae3551SRodney W. Grimes 
7358fae3551SRodney W. Grimes /*
7368fae3551SRodney W. Grimes  * make an entry in a directory
7378fae3551SRodney W. Grimes  */
73831f4ab50SBruce Evans int
739599304a4SPoul-Henning Kamp makeentry(ino_t parent, ino_t ino, const char *name)
7408fae3551SRodney W. Grimes {
7415cc52631SKirk McKusick 	struct inode ip;
7421c85e6a3SKirk McKusick 	union dinode *dp;
7438fae3551SRodney W. Grimes 	struct inodesc idesc;
7445cc52631SKirk McKusick 	int retval;
7458fae3551SRodney W. Grimes 	char pathbuf[MAXPATHLEN + 1];
7468fae3551SRodney W. Grimes 
7471dc349abSEd Maste 	if (parent < UFS_ROOTINO || parent >= maxino ||
7481dc349abSEd Maste 	    ino < UFS_ROOTINO || ino >= maxino)
7498fae3551SRodney W. Grimes 		return (0);
750780a5c1eSPeter Wemm 	memset(&idesc, 0, sizeof(struct inodesc));
7518fae3551SRodney W. Grimes 	idesc.id_type = DATA;
7528fae3551SRodney W. Grimes 	idesc.id_func = mkentry;
7538fae3551SRodney W. Grimes 	idesc.id_number = parent;
7548fae3551SRodney W. Grimes 	idesc.id_parent = ino;	/* this is the inode to enter */
7558fae3551SRodney W. Grimes 	idesc.id_fix = DONTKNOW;
756599304a4SPoul-Henning Kamp 	idesc.id_name = strdup(name);
7575cc52631SKirk McKusick 	ginode(parent, &ip);
7585cc52631SKirk McKusick 	dp = ip.i_dp;
7591c85e6a3SKirk McKusick 	if (DIP(dp, di_size) % DIRBLKSIZ) {
760c3b2344bSScott Long 		DIP_SET(dp, di_size, roundup(DIP(dp, di_size), DIRBLKSIZ));
7615cc52631SKirk McKusick 		inodirty(&ip);
7628fae3551SRodney W. Grimes 	}
7635cc52631SKirk McKusick 	if ((ckinode(dp, &idesc) & ALTERED) != 0) {
7645cc52631SKirk McKusick 		irelse(&ip);
765e5d0d1c5SKirk McKusick 		free(idesc.id_name);
7668fae3551SRodney W. Grimes 		return (1);
7675cc52631SKirk McKusick 	}
7688fae3551SRodney W. Grimes 	getpathname(pathbuf, parent, parent);
7695cc52631SKirk McKusick 	if (expanddir(&ip, pathbuf) == 0) {
7705cc52631SKirk McKusick 		irelse(&ip);
771e5d0d1c5SKirk McKusick 		free(idesc.id_name);
7728fae3551SRodney W. Grimes 		return (0);
7735cc52631SKirk McKusick 	}
7745cc52631SKirk McKusick 	retval = ckinode(dp, &idesc) & ALTERED;
7755cc52631SKirk McKusick 	irelse(&ip);
776e5d0d1c5SKirk McKusick 	free(idesc.id_name);
7775cc52631SKirk McKusick 	return (retval);
7788fae3551SRodney W. Grimes }
7798fae3551SRodney W. Grimes 
7808fae3551SRodney W. Grimes /*
7818fae3551SRodney W. Grimes  * Attempt to expand the size of a directory
7828fae3551SRodney W. Grimes  */
783780a5c1eSPeter Wemm static int
7845cc52631SKirk McKusick expanddir(struct inode *ip, char *name)
7858fae3551SRodney W. Grimes {
786997f81afSKirk McKusick 	ufs2_daddr_t lastlbn, oldblk, newblk, indirblk;
787997f81afSKirk McKusick 	size_t filesize, lastlbnsize;
788997f81afSKirk McKusick 	struct bufarea *bp, *nbp;
7897180f1abSKirk McKusick 	struct inodesc idesc;
7905cc52631SKirk McKusick 	union dinode *dp;
791460ed610SKirk McKusick 	long cg, indiralloced;
792997f81afSKirk McKusick 	char *cp;
7938fae3551SRodney W. Grimes 
794997f81afSKirk McKusick 	nbp = NULL;
795997f81afSKirk McKusick 	indiralloced = newblk = indirblk = 0;
796460ed610SKirk McKusick 	memset(&idesc, 0, sizeof(struct inodesc));
797460ed610SKirk McKusick 	idesc.id_type = ADDR;
798997f81afSKirk McKusick 	pwarn("NO SPACE LEFT IN %s", name);
799997f81afSKirk McKusick 	if (!preen && reply("EXPAND") == 0)
8008fae3551SRodney W. Grimes 		return (0);
801460ed610SKirk McKusick 	cg = ino_to_cg(&sblock, ip->i_number);
8025cc52631SKirk McKusick 	dp = ip->i_dp;
803997f81afSKirk McKusick 	filesize = DIP(dp, di_size);
804997f81afSKirk McKusick 	lastlbn = lblkno(&sblock, filesize);
805997f81afSKirk McKusick 	/*
806997f81afSKirk McKusick 	 * We only expand lost+found to a single indirect block.
807997f81afSKirk McKusick 	 */
808997f81afSKirk McKusick 	if ((DIP(dp, di_mode) & IFMT) != IFDIR || filesize == 0 ||
809997f81afSKirk McKusick 	    lastlbn >= UFS_NDADDR + NINDIR(&sblock))
810997f81afSKirk McKusick 		goto bad;
811997f81afSKirk McKusick 	/*
812997f81afSKirk McKusick 	 * If last block is a fragment, expand it to a full size block.
813997f81afSKirk McKusick 	 */
814997f81afSKirk McKusick 	lastlbnsize = sblksize(&sblock, filesize, lastlbn);
815c8a7a3ffSKirk McKusick 	if (lastlbnsize > 0 && lastlbnsize < sblock.fs_bsize) {
816997f81afSKirk McKusick 		oldblk = DIP(dp, di_db[lastlbn]);
817997f81afSKirk McKusick 		bp = getdirblk(oldblk, lastlbnsize);
8188fae3551SRodney W. Grimes 		if (bp->b_errs)
8198fae3551SRodney W. Grimes 			goto bad;
820460ed610SKirk McKusick 		newblk = allocblk(cg, sblock.fs_frag, std_checkblkavail);
821460ed610SKirk McKusick 		if (newblk == 0)
822997f81afSKirk McKusick 			goto bad;
823997f81afSKirk McKusick 		nbp = getdatablk(newblk, sblock.fs_bsize, BT_DIRDATA);
824997f81afSKirk McKusick 		if (nbp->b_errs)
825997f81afSKirk McKusick 			goto bad;
826997f81afSKirk McKusick 		DIP_SET(dp, di_db[lastlbn], newblk);
827997f81afSKirk McKusick 		DIP_SET(dp, di_size, filesize + sblock.fs_bsize - lastlbnsize);
828997f81afSKirk McKusick 		DIP_SET(dp, di_blocks, DIP(dp, di_blocks) +
829997f81afSKirk McKusick 		    btodb(sblock.fs_bsize - lastlbnsize));
8305cc52631SKirk McKusick 		inodirty(ip);
831997f81afSKirk McKusick 		memmove(nbp->b_un.b_buf, bp->b_un.b_buf, lastlbnsize);
832997f81afSKirk McKusick 		memset(&nbp->b_un.b_buf[lastlbnsize], 0,
833997f81afSKirk McKusick 		    sblock.fs_bsize - lastlbnsize);
834997f81afSKirk McKusick 		for (cp = &nbp->b_un.b_buf[lastlbnsize];
835997f81afSKirk McKusick 		     cp < &nbp->b_un.b_buf[sblock.fs_bsize];
836997f81afSKirk McKusick 		     cp += DIRBLKSIZ)
837997f81afSKirk McKusick 			memmove(cp, &emptydir, sizeof emptydir);
838997f81afSKirk McKusick 		dirty(nbp);
8395cc52631SKirk McKusick 		brelse(nbp);
840460ed610SKirk McKusick 		binval(bp);
841997f81afSKirk McKusick 		idesc.id_blkno = oldblk;
842997f81afSKirk McKusick 		idesc.id_numfrags = numfrags(&sblock, lastlbnsize);
843997f81afSKirk McKusick 		(void)freeblock(&idesc);
8445cc52631SKirk McKusick 		if (preen)
8455cc52631SKirk McKusick 			printf(" (EXPANDED)\n");
846997f81afSKirk McKusick 		return (1);
847997f81afSKirk McKusick 	}
848460ed610SKirk McKusick 	if ((newblk = allocblk(cg, sblock.fs_frag, std_checkblkavail)) == 0)
849997f81afSKirk McKusick 		goto bad;
8508fae3551SRodney W. Grimes 	bp = getdirblk(newblk, sblock.fs_bsize);
8518fae3551SRodney W. Grimes 	if (bp->b_errs)
8528fae3551SRodney W. Grimes 		goto bad;
853997f81afSKirk McKusick 	memset(bp->b_un.b_buf, 0, sblock.fs_bsize);
854997f81afSKirk McKusick 	for (cp = bp->b_un.b_buf;
8558fae3551SRodney W. Grimes 	     cp < &bp->b_un.b_buf[sblock.fs_bsize];
8568fae3551SRodney W. Grimes 	     cp += DIRBLKSIZ)
857780a5c1eSPeter Wemm 		memmove(cp, &emptydir, sizeof emptydir);
8588fae3551SRodney W. Grimes 	dirty(bp);
859997f81afSKirk McKusick 	if (lastlbn < UFS_NDADDR) {
860997f81afSKirk McKusick 		DIP_SET(dp, di_db[lastlbn], newblk);
861997f81afSKirk McKusick 	} else {
862997f81afSKirk McKusick 		/*
863997f81afSKirk McKusick 		 * Allocate indirect block if needed.
864997f81afSKirk McKusick 		 */
865997f81afSKirk McKusick 		if ((indirblk = DIP(dp, di_ib[0])) == 0) {
866460ed610SKirk McKusick 			indirblk = allocblk(cg, sblock.fs_frag,
867460ed610SKirk McKusick 			    std_checkblkavail);
868460ed610SKirk McKusick 			if (indirblk == 0) {
869460ed610SKirk McKusick 				binval(bp);
8708fae3551SRodney W. Grimes 				goto bad;
871460ed610SKirk McKusick 			}
872997f81afSKirk McKusick 			indiralloced = 1;
873997f81afSKirk McKusick 		}
874997f81afSKirk McKusick 		nbp = getdatablk(indirblk, sblock.fs_bsize, BT_LEVEL1);
875997f81afSKirk McKusick 		if (nbp->b_errs)
876997f81afSKirk McKusick 			goto bad;
877997f81afSKirk McKusick 		if (indiralloced) {
878997f81afSKirk McKusick 			memset(nbp->b_un.b_buf, 0, sblock.fs_bsize);
879997f81afSKirk McKusick 			DIP_SET(dp, di_ib[0], indirblk);
880997f81afSKirk McKusick 			DIP_SET(dp, di_blocks,
881997f81afSKirk McKusick 			    DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
882997f81afSKirk McKusick 		}
883997f81afSKirk McKusick 		IBLK_SET(nbp, lastlbn - UFS_NDADDR, newblk);
884997f81afSKirk McKusick 		dirty(nbp);
8855cc52631SKirk McKusick 		brelse(nbp);
886997f81afSKirk McKusick 	}
887997f81afSKirk McKusick 	DIP_SET(dp, di_size, filesize + sblock.fs_bsize);
888997f81afSKirk McKusick 	DIP_SET(dp, di_blocks, DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
8895cc52631SKirk McKusick 	inodirty(ip);
8908fae3551SRodney W. Grimes 	if (preen)
8918fae3551SRodney W. Grimes 		printf(" (EXPANDED)\n");
8928fae3551SRodney W. Grimes 	return (1);
8938fae3551SRodney W. Grimes bad:
894997f81afSKirk McKusick 	pfatal(" (EXPANSION FAILED)\n");
895460ed610SKirk McKusick 	if (nbp != NULL) {
896460ed610SKirk McKusick 		binval(bp);
8975cc52631SKirk McKusick 		brelse(nbp);
898460ed610SKirk McKusick 	}
899997f81afSKirk McKusick 	if (newblk != 0) {
9007180f1abSKirk McKusick 		idesc.id_blkno = newblk;
9017180f1abSKirk McKusick 		idesc.id_numfrags = sblock.fs_frag;
9027180f1abSKirk McKusick 		(void)freeblock(&idesc);
903997f81afSKirk McKusick 	}
904997f81afSKirk McKusick 	if (indiralloced) {
905997f81afSKirk McKusick 		idesc.id_blkno = indirblk;
906997f81afSKirk McKusick 		idesc.id_numfrags = sblock.fs_frag;
907997f81afSKirk McKusick 		(void)freeblock(&idesc);
908997f81afSKirk McKusick 	}
9098fae3551SRodney W. Grimes 	return (0);
9108fae3551SRodney W. Grimes }
9118fae3551SRodney W. Grimes 
9128fae3551SRodney W. Grimes /*
9138fae3551SRodney W. Grimes  * allocate a new directory
9148fae3551SRodney W. Grimes  */
9153eeb5bdcSBruce Evans ino_t
916b70cd7eeSWarner Losh allocdir(ino_t parent, ino_t request, int mode)
9178fae3551SRodney W. Grimes {
9188fae3551SRodney W. Grimes 	ino_t ino;
9198fae3551SRodney W. Grimes 	char *cp;
9205cc52631SKirk McKusick 	struct inode ip;
9211c85e6a3SKirk McKusick 	union dinode *dp;
92291ea1615SKirk McKusick 	struct bufarea *bp;
9238fae3551SRodney W. Grimes 	struct dirtemplate *dirp;
924fe5e6e2cSKirk McKusick 	struct inoinfo *inp, *parentinp;
9258fae3551SRodney W. Grimes 
926d8ba45e2SEd Maste 	ino = allocino(request, IFDIR|mode);
92784a0e3f9SKirk McKusick 	if (ino == 0)
92884a0e3f9SKirk McKusick 		return (0);
9298fae3551SRodney W. Grimes 	dirp = &dirhead;
9308fae3551SRodney W. Grimes 	dirp->dot_ino = ino;
9318fae3551SRodney W. Grimes 	dirp->dotdot_ino = parent;
9325cc52631SKirk McKusick 	ginode(ino, &ip);
9335cc52631SKirk McKusick 	dp = ip.i_dp;
9341c85e6a3SKirk McKusick 	bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize);
9358fae3551SRodney W. Grimes 	if (bp->b_errs) {
9368fae3551SRodney W. Grimes 		freeino(ino);
9375cc52631SKirk McKusick 		irelse(&ip);
9388fae3551SRodney W. Grimes 		return (0);
9398fae3551SRodney W. Grimes 	}
940780a5c1eSPeter Wemm 	memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
9418fae3551SRodney W. Grimes 	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
9428fae3551SRodney W. Grimes 	     cp < &bp->b_un.b_buf[sblock.fs_fsize];
9438fae3551SRodney W. Grimes 	     cp += DIRBLKSIZ)
944780a5c1eSPeter Wemm 		memmove(cp, &emptydir, sizeof emptydir);
9458fae3551SRodney W. Grimes 	dirty(bp);
946c3b2344bSScott Long 	DIP_SET(dp, di_nlink, 2);
9475cc52631SKirk McKusick 	inodirty(&ip);
9481dc349abSEd Maste 	if (ino == UFS_ROOTINO) {
949f4fc3895SKirk McKusick 		inp = cacheino(dp, ino);
950f4fc3895SKirk McKusick 		inp->i_parent = parent;
951f4fc3895SKirk McKusick 		inp->i_dotdot = parent;
95252f97104SKirk McKusick 		inp->i_flags |= INFO_NEW;
95352f97104SKirk McKusick 		inoinfo(ino)->ino_type = DT_DIR;
95452f97104SKirk McKusick 		inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink);
9555cc52631SKirk McKusick 		irelse(&ip);
9568fae3551SRodney W. Grimes 		return(ino);
9578fae3551SRodney W. Grimes 	}
958af6726e6SDon Lewis 	if (!INO_IS_DVALID(parent)) {
9598fae3551SRodney W. Grimes 		freeino(ino);
9605cc52631SKirk McKusick 		irelse(&ip);
9618fae3551SRodney W. Grimes 		return (0);
9628fae3551SRodney W. Grimes 	}
963f4fc3895SKirk McKusick 	inp = cacheino(dp, ino);
96491ea1615SKirk McKusick 	inp->i_parent = parent;
96591ea1615SKirk McKusick 	inp->i_dotdot = parent;
96652f97104SKirk McKusick 	inp->i_flags |= INFO_NEW;
967fe5e6e2cSKirk McKusick 	if ((parentinp = getinoinfo(inp->i_parent)) == NULL) {
968fe5e6e2cSKirk McKusick 		pfatal("allocdir: UNKNOWN PARENT DIR");
969fe5e6e2cSKirk McKusick 	} else {
970fe5e6e2cSKirk McKusick 		inp->i_depth = parentinp->i_depth + 1;
971fe5e6e2cSKirk McKusick 		DIP_SET(dp, di_dirdepth, inp->i_depth);
972fe5e6e2cSKirk McKusick 	}
97352f97104SKirk McKusick 	inoinfo(ino)->ino_type = DT_DIR;
974d33e92f9SJulian Elischer 	inoinfo(ino)->ino_state = inoinfo(parent)->ino_state;
975d33e92f9SJulian Elischer 	if (inoinfo(ino)->ino_state == DSTATE) {
9761c85e6a3SKirk McKusick 		inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink);
977d33e92f9SJulian Elischer 		inoinfo(parent)->ino_linkcnt++;
9788fae3551SRodney W. Grimes 	}
9795cc52631SKirk McKusick 	irelse(&ip);
9805cc52631SKirk McKusick 	ginode(parent, &ip);
9815cc52631SKirk McKusick 	dp = ip.i_dp;
982c3b2344bSScott Long 	DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
9835cc52631SKirk McKusick 	inodirty(&ip);
9845cc52631SKirk McKusick 	irelse(&ip);
9858fae3551SRodney W. Grimes 	return (ino);
9868fae3551SRodney W. Grimes }
9878fae3551SRodney W. Grimes 
9888fae3551SRodney W. Grimes /*
9898fae3551SRodney W. Grimes  * free a directory inode
9908fae3551SRodney W. Grimes  */
99152f97104SKirk McKusick void
99252f97104SKirk McKusick freedirino(ino_t ino, ino_t parent)
9938fae3551SRodney W. Grimes {
9945cc52631SKirk McKusick 	struct inode ip;
9951c85e6a3SKirk McKusick 	union dinode *dp;
9968fae3551SRodney W. Grimes 
9978fae3551SRodney W. Grimes 	if (ino != parent) {
9985cc52631SKirk McKusick 		ginode(parent, &ip);
9995cc52631SKirk McKusick 		dp = ip.i_dp;
1000c3b2344bSScott Long 		DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - 1);
10015cc52631SKirk McKusick 		inodirty(&ip);
10025cc52631SKirk McKusick 		irelse(&ip);
10038fae3551SRodney W. Grimes 	}
100452f97104SKirk McKusick 	removecachedino(ino);
10058fae3551SRodney W. Grimes 	freeino(ino);
10068fae3551SRodney W. Grimes }
10078fae3551SRodney W. Grimes 
10088fae3551SRodney W. Grimes /*
10098fae3551SRodney W. Grimes  * generate a temporary name for the lost+found directory.
10108fae3551SRodney W. Grimes  */
1011780a5c1eSPeter Wemm static int
1012b70cd7eeSWarner Losh lftempname(char *bufp, ino_t ino)
10138fae3551SRodney W. Grimes {
10143d438ad6SDavid E. O'Brien 	ino_t in;
10153d438ad6SDavid E. O'Brien 	char *cp;
10168fae3551SRodney W. Grimes 	int namlen;
10178fae3551SRodney W. Grimes 
10188fae3551SRodney W. Grimes 	cp = bufp + 2;
10198fae3551SRodney W. Grimes 	for (in = maxino; in > 0; in /= 10)
10208fae3551SRodney W. Grimes 		cp++;
10218fae3551SRodney W. Grimes 	*--cp = 0;
10228fae3551SRodney W. Grimes 	namlen = cp - bufp;
10238fae3551SRodney W. Grimes 	in = ino;
10248fae3551SRodney W. Grimes 	while (cp > bufp) {
10258fae3551SRodney W. Grimes 		*--cp = (in % 10) + '0';
10268fae3551SRodney W. Grimes 		in /= 10;
10278fae3551SRodney W. Grimes 	}
10288fae3551SRodney W. Grimes 	*cp = '#';
10298fae3551SRodney W. Grimes 	return (namlen);
10308fae3551SRodney W. Grimes }
10318fae3551SRodney W. Grimes 
10328fae3551SRodney W. Grimes /*
10338fae3551SRodney W. Grimes  * Get a directory block.
10348fae3551SRodney W. Grimes  * Insure that it is held until another is requested.
10358fae3551SRodney W. Grimes  */
1036780a5c1eSPeter Wemm static struct bufarea *
10371c85e6a3SKirk McKusick getdirblk(ufs2_daddr_t blkno, long size)
10388fae3551SRodney W. Grimes {
10398fae3551SRodney W. Grimes 
10405cc52631SKirk McKusick 	if (pdirbp != NULL && pdirbp->b_errs == 0)
10415cc52631SKirk McKusick 		brelse(pdirbp);
1042ed75b5a1SKirk McKusick 	pdirbp = getdatablk(blkno, size, BT_DIRDATA);
10438fae3551SRodney W. Grimes 	return (pdirbp);
10448fae3551SRodney W. Grimes }
1045