xref: /freebsd/sbin/fsck_ffs/dir.c (revision f7cee4fa57a2b52a6e43a1f820ce7ba891b8e7d9)
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 
328fae3551SRodney W. Grimes #include <sys/param.h>
33d33e92f9SJulian Elischer #include <sys/time.h>
3413eb765fSBaptiste Daroussin #include <sys/types.h>
357578c6abSKirk McKusick #include <sys/sysctl.h>
36780a5c1eSPeter Wemm 
378fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
388fae3551SRodney W. Grimes #include <ufs/ufs/dir.h>
398fae3551SRodney W. Grimes #include <ufs/ffs/fs.h>
4004aba254SBruce Evans 
41780a5c1eSPeter Wemm #include <err.h>
428fae3551SRodney W. Grimes #include <string.h>
43780a5c1eSPeter Wemm 
448fae3551SRodney W. Grimes #include "fsck.h"
458fae3551SRodney W. Grimes 
467703a6ffSScott Long static struct	dirtemplate emptydir = {
477578c6abSKirk McKusick 	0, DIRBLKSIZ, DT_UNKNOWN, 0, "",
487578c6abSKirk McKusick 	0, 0, DT_UNKNOWN, 0, ""
497578c6abSKirk McKusick };
507703a6ffSScott Long static struct	dirtemplate dirhead = {
518fae3551SRodney W. Grimes 	0, 12, DT_DIR, 1, ".",
528fae3551SRodney W. Grimes 	0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
538fae3551SRodney W. Grimes };
548fae3551SRodney W. Grimes 
55b70cd7eeSWarner Losh static int chgino(struct inodesc *);
56bfc5d3f9SKirk McKusick static int dircheck(struct inodesc *, struct bufarea *, struct direct *);
575cc52631SKirk McKusick static int expanddir(struct inode *ip, char *name);
58b70cd7eeSWarner Losh static struct direct *fsck_readdir(struct inodesc *);
591c85e6a3SKirk McKusick static struct bufarea *getdirblk(ufs2_daddr_t blkno, long size);
60b70cd7eeSWarner Losh static int lftempname(char *bufp, ino_t ino);
61b70cd7eeSWarner Losh static int mkentry(struct inodesc *);
628fae3551SRodney W. Grimes 
638fae3551SRodney W. Grimes /*
648fae3551SRodney W. Grimes  * Propagate connected state through the tree.
658fae3551SRodney W. Grimes  */
6631f4ab50SBruce Evans void
67b70cd7eeSWarner Losh propagate(void)
688fae3551SRodney W. Grimes {
693d438ad6SDavid E. O'Brien 	struct inoinfo **inpp, *inp;
708fae3551SRodney W. Grimes 	struct inoinfo **inpend;
718fae3551SRodney W. Grimes 	long change;
728fae3551SRodney W. Grimes 
738fae3551SRodney W. Grimes 	inpend = &inpsort[inplast];
748fae3551SRodney W. Grimes 	do {
758fae3551SRodney W. Grimes 		change = 0;
768fae3551SRodney W. Grimes 		for (inpp = inpsort; inpp < inpend; inpp++) {
778fae3551SRodney W. Grimes 			inp = *inpp;
788fae3551SRodney W. Grimes 			if (inp->i_parent == 0)
798fae3551SRodney W. Grimes 				continue;
80d33e92f9SJulian Elischer 			if (inoinfo(inp->i_parent)->ino_state == DFOUND &&
81af6726e6SDon Lewis 			    INO_IS_DUNFOUND(inp->i_number)) {
82d33e92f9SJulian Elischer 				inoinfo(inp->i_number)->ino_state = DFOUND;
83fe5e6e2cSKirk McKusick 				check_dirdepth(inp);
848fae3551SRodney W. Grimes 				change++;
858fae3551SRodney W. Grimes 			}
868fae3551SRodney W. Grimes 		}
878fae3551SRodney W. Grimes 	} while (change > 0);
888fae3551SRodney W. Grimes }
898fae3551SRodney W. Grimes 
908fae3551SRodney W. Grimes /*
91fe5e6e2cSKirk McKusick  * Check that the recorded depth of the directory is correct.
92fe5e6e2cSKirk McKusick  */
93fe5e6e2cSKirk McKusick void
94fe5e6e2cSKirk McKusick check_dirdepth(struct inoinfo *inp)
95fe5e6e2cSKirk McKusick {
96fe5e6e2cSKirk McKusick 	struct inoinfo *parentinp;
97fe5e6e2cSKirk McKusick 	struct inode ip;
98fe5e6e2cSKirk McKusick 	union dinode *dp;
99fe5e6e2cSKirk McKusick 	int saveresolved;
100e4a905d1SKirk McKusick 	size_t size;
101fe5e6e2cSKirk McKusick 	static int updateasked, dirdepthupdate;
102fe5e6e2cSKirk McKusick 
103fe5e6e2cSKirk McKusick 	if ((parentinp = getinoinfo(inp->i_parent)) == NULL) {
104fe5e6e2cSKirk McKusick 		pfatal("check_dirdepth: UNKNOWN PARENT DIR");
105fe5e6e2cSKirk McKusick 		return;
106fe5e6e2cSKirk McKusick 	}
107fe5e6e2cSKirk McKusick 	/*
108fe5e6e2cSKirk McKusick 	 * If depth is correct, nothing to do.
109fe5e6e2cSKirk McKusick 	 */
110fe5e6e2cSKirk McKusick 	if (parentinp->i_depth + 1 == inp->i_depth)
111fe5e6e2cSKirk McKusick 		return;
112fe5e6e2cSKirk McKusick 	/*
113fe5e6e2cSKirk McKusick 	 * Only the root inode should have depth of 0, so if any other
114fe5e6e2cSKirk McKusick 	 * directory has a depth of 0 then this is an old filesystem
115fe5e6e2cSKirk McKusick 	 * that has not been tracking directory depth. Ask just once
116fe5e6e2cSKirk McKusick 	 * whether it should start tracking directory depth.
117fe5e6e2cSKirk McKusick 	 */
118fe5e6e2cSKirk McKusick 	if (inp->i_depth == 0 && updateasked == 0) {
119fe5e6e2cSKirk McKusick 		updateasked = 1;
120fe5e6e2cSKirk McKusick 		if (preen) {
12111ce203eSKirk McKusick 			pwarn("UPDATING FILESYSTEM TO TRACK DIRECTORY DEPTH\n");
122fe5e6e2cSKirk McKusick 			dirdepthupdate = 1;
123fe5e6e2cSKirk McKusick 		} else {
124fe5e6e2cSKirk McKusick 			/*
125fe5e6e2cSKirk McKusick 			 * The file system can be marked clean even if
126fe5e6e2cSKirk McKusick 			 * a directory does not have the right depth.
127fe5e6e2cSKirk McKusick 			 * Hence, resolved should not be cleared when
128fe5e6e2cSKirk McKusick 			 * the filesystem does not update directory depths.
129fe5e6e2cSKirk McKusick 			 */
130fe5e6e2cSKirk McKusick 			saveresolved = resolved;
131fe5e6e2cSKirk McKusick 			dirdepthupdate =
132fe5e6e2cSKirk McKusick 			    reply("UPDATE FILESYSTEM TO TRACK DIRECTORY DEPTH");
133fe5e6e2cSKirk McKusick 			resolved = saveresolved;
134fe5e6e2cSKirk McKusick 		}
135fe5e6e2cSKirk McKusick 	}
136fe5e6e2cSKirk McKusick 	/*
137e4a905d1SKirk McKusick 	 * If we are not converting or we are running in no-write mode
138e4a905d1SKirk McKusick 	 * there is nothing more to do.
139fe5e6e2cSKirk McKusick 	 */
140e4a905d1SKirk McKusick 	if ((inp->i_depth == 0 && dirdepthupdate == 0) ||
141e4a905d1SKirk McKusick 	    (fswritefd < 0 && bkgrdflag == 0))
142fe5e6e2cSKirk McKusick 		return;
143fe5e6e2cSKirk McKusick 	/*
144fe5e6e2cSKirk McKusick 	 * Individual directory at wrong depth. Report it and correct if
145fe5e6e2cSKirk McKusick 	 * in preen mode or ask if in interactive mode. Note that if a
146fe5e6e2cSKirk McKusick 	 * directory is renamed to a new location that is at a different
147fe5e6e2cSKirk McKusick 	 * level in the tree, its depth will be recalculated, but none of
148fe5e6e2cSKirk McKusick 	 * the directories that it contains will be updated. Thus it is
149fe5e6e2cSKirk McKusick 	 * not unexpected to find directories with incorrect depths. No
150fe5e6e2cSKirk McKusick 	 * operational harm will come from this though new directory
151fe5e6e2cSKirk McKusick 	 * placement in the subtree may not be as optimal until the depths
152fe5e6e2cSKirk McKusick 	 * of the affected directories are corrected.
153fe5e6e2cSKirk McKusick 	 *
154fe5e6e2cSKirk McKusick 	 * To avoid much spurious output on otherwise clean filesystems
155fe5e6e2cSKirk McKusick 	 * we only generate detailed output when the debug flag is given.
156fe5e6e2cSKirk McKusick 	 */
157fe5e6e2cSKirk McKusick 	ginode(inp->i_number, &ip);
158fe5e6e2cSKirk McKusick 	dp = ip.i_dp;
159fe5e6e2cSKirk McKusick 	if (inp->i_depth != 0 && debug) {
160fe5e6e2cSKirk McKusick 		pwarn("DIRECTORY");
161fe5e6e2cSKirk McKusick 		prtinode(&ip);
162fe5e6e2cSKirk McKusick 		printf(" DEPTH %d SHOULD BE %d", inp->i_depth,
163fe5e6e2cSKirk McKusick 		    parentinp->i_depth + 1);
164fe5e6e2cSKirk McKusick 		if (preen == 0 && reply("ADJUST") == 0) {
165fe5e6e2cSKirk McKusick 			irelse(&ip);
166fe5e6e2cSKirk McKusick 			return;
167fe5e6e2cSKirk McKusick 		}
168fe5e6e2cSKirk McKusick 		if (preen)
169fe5e6e2cSKirk McKusick 			printf(" (ADJUSTED)\n");
170fe5e6e2cSKirk McKusick 	}
171fe5e6e2cSKirk McKusick 	inp->i_depth = parentinp->i_depth + 1;
172e4a905d1SKirk McKusick 	if (bkgrdflag == 0) {
173fe5e6e2cSKirk McKusick 		DIP_SET(dp, di_dirdepth, inp->i_depth);
174fe5e6e2cSKirk McKusick 		inodirty(&ip);
175e4a905d1SKirk McKusick 	} else {
176e4a905d1SKirk McKusick 		cmd.value = inp->i_number;
177e4a905d1SKirk McKusick 		cmd.size = (int64_t)inp->i_depth - DIP(dp, di_dirdepth);
178e4a905d1SKirk McKusick 		if (debug)
179e4a905d1SKirk McKusick 			printf("adjdepth ino %ld amt %jd\n", (long)cmd.value,
180e4a905d1SKirk McKusick 			    (intmax_t)cmd.size);
181e4a905d1SKirk McKusick 		size = MIBSIZE;
182e4a905d1SKirk McKusick 		if (sysctlnametomib("vfs.ffs.adjdepth", adjdepth, &size) < 0 ||
183e4a905d1SKirk McKusick 		    sysctl(adjdepth, MIBSIZE, 0, 0, &cmd, sizeof cmd) == -1)
184e4a905d1SKirk McKusick 			rwerror("ADJUST INODE DEPTH", cmd.value);
185e4a905d1SKirk McKusick 	}
186fe5e6e2cSKirk McKusick 	irelse(&ip);
187fe5e6e2cSKirk McKusick }
188fe5e6e2cSKirk McKusick 
189fe5e6e2cSKirk McKusick /*
1908fae3551SRodney W. Grimes  * Scan each entry in a directory block.
1918fae3551SRodney W. Grimes  */
19231f4ab50SBruce Evans int
193b70cd7eeSWarner Losh dirscan(struct inodesc *idesc)
1948fae3551SRodney W. Grimes {
1953d438ad6SDavid E. O'Brien 	struct direct *dp;
1963d438ad6SDavid E. O'Brien 	struct bufarea *bp;
1977578c6abSKirk McKusick 	u_int dsize, n;
1988fae3551SRodney W. Grimes 	long blksiz;
1998fae3551SRodney W. Grimes 	char dbuf[DIRBLKSIZ];
2008fae3551SRodney W. Grimes 
2018fae3551SRodney W. Grimes 	if (idesc->id_type != DATA)
202780a5c1eSPeter Wemm 		errx(EEXIT, "wrong type to dirscan %d", idesc->id_type);
2038fae3551SRodney W. Grimes 	if (idesc->id_entryno == 0 &&
2048fae3551SRodney W. Grimes 	    (idesc->id_filesize & (DIRBLKSIZ - 1)) != 0)
2058fae3551SRodney W. Grimes 		idesc->id_filesize = roundup(idesc->id_filesize, DIRBLKSIZ);
2068fae3551SRodney W. Grimes 	blksiz = idesc->id_numfrags * sblock.fs_fsize;
2078fae3551SRodney W. Grimes 	if (chkrange(idesc->id_blkno, idesc->id_numfrags)) {
2088fae3551SRodney W. Grimes 		idesc->id_filesize -= blksiz;
2098fae3551SRodney W. Grimes 		return (SKIP);
2108fae3551SRodney W. Grimes 	}
2118fae3551SRodney W. Grimes 	idesc->id_loc = 0;
2128fae3551SRodney W. Grimes 	for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
2138fae3551SRodney W. Grimes 		dsize = dp->d_reclen;
214d33e92f9SJulian Elischer 		if (dsize > sizeof(dbuf))
215d33e92f9SJulian Elischer 			dsize = sizeof(dbuf);
216780a5c1eSPeter Wemm 		memmove(dbuf, dp, (size_t)dsize);
2178fae3551SRodney W. Grimes 		idesc->id_dirp = (struct direct *)dbuf;
2188fae3551SRodney W. Grimes 		if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
2198fae3551SRodney W. Grimes 			bp = getdirblk(idesc->id_blkno, blksiz);
2205cc52631SKirk McKusick 			if (bp->b_errs != 0)
2215cc52631SKirk McKusick 				return (STOP);
222780a5c1eSPeter Wemm 			memmove(bp->b_un.b_buf + idesc->id_loc - dsize, dbuf,
2238fae3551SRodney W. Grimes 			    (size_t)dsize);
2248fae3551SRodney W. Grimes 			dirty(bp);
2258fae3551SRodney W. Grimes 			sbdirty();
2268fae3551SRodney W. Grimes 		}
2278fae3551SRodney W. Grimes 		if (n & STOP)
2288fae3551SRodney W. Grimes 			return (n);
2298fae3551SRodney W. Grimes 	}
2308fae3551SRodney W. Grimes 	return (idesc->id_filesize > 0 ? KEEPON : STOP);
2318fae3551SRodney W. Grimes }
2328fae3551SRodney W. Grimes 
2338fae3551SRodney W. Grimes /*
234bfc5d3f9SKirk McKusick  * Get and verify the next entry in a directory.
235bfc5d3f9SKirk McKusick  * We also verify that if there is another entry in the block that it is
236bfc5d3f9SKirk McKusick  * valid, so if it is not valid it can be subsumed into the current entry.
2378fae3551SRodney W. Grimes  */
238780a5c1eSPeter Wemm static struct direct *
239b70cd7eeSWarner Losh fsck_readdir(struct inodesc *idesc)
2408fae3551SRodney W. Grimes {
2413d438ad6SDavid E. O'Brien 	struct direct *dp, *ndp;
2423d438ad6SDavid E. O'Brien 	struct bufarea *bp;
243bfc5d3f9SKirk McKusick 	long size, blksiz, subsume_ndp;
2448fae3551SRodney W. Grimes 
245bfc5d3f9SKirk McKusick 	subsume_ndp = 0;
2468fae3551SRodney W. Grimes 	blksiz = idesc->id_numfrags * sblock.fs_fsize;
2478fae3551SRodney W. Grimes 	if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
248bfc5d3f9SKirk McKusick 		return (NULL);
249bfc5d3f9SKirk McKusick 	bp = getdirblk(idesc->id_blkno, blksiz);
2505cc52631SKirk McKusick 	if (bp->b_errs != 0)
2515cc52631SKirk McKusick 		return (NULL);
252bfc5d3f9SKirk McKusick 	dp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
253bfc5d3f9SKirk McKusick 	/*
254bfc5d3f9SKirk McKusick 	 * Only need to check current entry if it is the first in the
255*f7cee4faSElyes Haouas 	 * block, as later entries will have been checked in the
256bfc5d3f9SKirk McKusick 	 * previous call to this function.
257bfc5d3f9SKirk McKusick 	 */
258bfc5d3f9SKirk McKusick 	if (idesc->id_loc % DIRBLKSIZ != 0 || dircheck(idesc, bp, dp) != 0) {
259bfc5d3f9SKirk McKusick 		/*
260bfc5d3f9SKirk McKusick 		 * Current entry is good, update to point at next.
261bfc5d3f9SKirk McKusick 		 */
2628fae3551SRodney W. Grimes 		idesc->id_loc += dp->d_reclen;
2638fae3551SRodney W. Grimes 		idesc->id_filesize -= dp->d_reclen;
264bfc5d3f9SKirk McKusick 		/*
265bfc5d3f9SKirk McKusick 		 * If at end of directory block, just return this entry.
266bfc5d3f9SKirk McKusick 		 */
267bfc5d3f9SKirk McKusick 		if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz ||
268bfc5d3f9SKirk McKusick 		    idesc->id_loc % DIRBLKSIZ == 0)
2698fae3551SRodney W. Grimes 			return (dp);
270bfc5d3f9SKirk McKusick 		/*
271bfc5d3f9SKirk McKusick 		 * If the next entry good, return this entry.
272bfc5d3f9SKirk McKusick 		 */
2738fae3551SRodney W. Grimes 		ndp = (struct direct *)(bp->b_un.b_buf + idesc->id_loc);
274bfc5d3f9SKirk McKusick 		if (dircheck(idesc, bp, ndp) != 0)
275bfc5d3f9SKirk McKusick 			return (dp);
276bfc5d3f9SKirk McKusick 		/*
277bfc5d3f9SKirk McKusick 		 * The next entry is bad, so subsume it and the remainder
278bfc5d3f9SKirk McKusick 		 * of this directory block into this entry.
279bfc5d3f9SKirk McKusick 		 */
280bfc5d3f9SKirk McKusick 		subsume_ndp = 1;
281bfc5d3f9SKirk McKusick 	}
282bfc5d3f9SKirk McKusick 	/*
283bfc5d3f9SKirk McKusick 	 * Current or next entry is bad. Zap current entry or
284bfc5d3f9SKirk McKusick 	 * subsume next entry into current entry as appropriate.
285bfc5d3f9SKirk McKusick 	 */
2868fae3551SRodney W. Grimes 	size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
2878fae3551SRodney W. Grimes 	idesc->id_loc += size;
2888fae3551SRodney W. Grimes 	idesc->id_filesize -= size;
289780a5c1eSPeter Wemm 	if (idesc->id_fix == IGNORE)
290bfc5d3f9SKirk McKusick 		return (NULL);
291bfc5d3f9SKirk McKusick 	if (subsume_ndp) {
292bfc5d3f9SKirk McKusick 		memset(ndp, 0, size);
2938fae3551SRodney W. Grimes 		dp->d_reclen += size;
294bfc5d3f9SKirk McKusick 	} else {
295bfc5d3f9SKirk McKusick 		memset(dp, 0, size);
296bfc5d3f9SKirk McKusick 		dp->d_reclen = size;
2970061238fSKirk McKusick 	}
298bfc5d3f9SKirk McKusick 	if (dofix(idesc, "DIRECTORY CORRUPTED"))
299bfc5d3f9SKirk McKusick 		dirty(bp);
3008fae3551SRodney W. Grimes 	return (dp);
3018fae3551SRodney W. Grimes }
3028fae3551SRodney W. Grimes 
3038fae3551SRodney W. Grimes /*
3048fae3551SRodney W. Grimes  * Verify that a directory entry is valid.
3058fae3551SRodney W. Grimes  * This is a superset of the checks made in the kernel.
3060061238fSKirk McKusick  * Also optionally clears padding and unused directory space.
3070061238fSKirk McKusick  *
308bfc5d3f9SKirk McKusick  * Returns 0 if the entry is bad, 1 if the entry is good.
3098fae3551SRodney W. Grimes  */
310780a5c1eSPeter Wemm static int
311bfc5d3f9SKirk McKusick dircheck(struct inodesc *idesc, struct bufarea *bp, struct direct *dp)
3128fae3551SRodney W. Grimes {
313c69284caSDavid E. O'Brien 	size_t size;
3143d438ad6SDavid E. O'Brien 	char *cp;
315fdc61a88SXin LI 	u_int8_t namlen;
3160061238fSKirk McKusick 	int spaceleft, modified, unused;
3178fae3551SRodney W. Grimes 
3188fae3551SRodney W. Grimes 	spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
319bfc5d3f9SKirk McKusick 	size = DIRSIZ(0, dp);
320d33e92f9SJulian Elischer 	if (dp->d_reclen == 0 ||
321780a5c1eSPeter Wemm 	    dp->d_reclen > spaceleft ||
322bfc5d3f9SKirk McKusick 	    dp->d_reclen < size ||
323bfc5d3f9SKirk McKusick 	    idesc->id_filesize < size ||
3240061238fSKirk McKusick 	    (dp->d_reclen & (DIR_ROUNDUP - 1)) != 0)
325142d8d2fSKirk McKusick 		goto bad;
326bfc5d3f9SKirk McKusick 	modified = 0;
3270061238fSKirk McKusick 	if (dp->d_ino == 0) {
328bfc5d3f9SKirk McKusick 		if (!zflag || fswritefd < 0)
329bfc5d3f9SKirk McKusick 			return (1);
3300061238fSKirk McKusick 		/*
331bfc5d3f9SKirk McKusick 		 * Special case of an unused directory entry. Normally only
332bfc5d3f9SKirk McKusick 		 * occurs at the beginning of a directory block when the block
333bfc5d3f9SKirk McKusick 		 * contains no entries. Other than the first entry in a
334bfc5d3f9SKirk McKusick 		 * directory block, the kernel coalesces unused space with
335bfc5d3f9SKirk McKusick 		 * the previous entry by extending its d_reclen. However,
336bfc5d3f9SKirk McKusick 		 * when cleaning up a directory, fsck may set d_ino to zero
337bfc5d3f9SKirk McKusick 		 * in the middle of a directory block. If we're clearing out
338bfc5d3f9SKirk McKusick 		 * directory cruft (-z flag), then make sure that all directory
339bfc5d3f9SKirk McKusick 		 * space in entries with d_ino == 0 gets fully cleared.
3400061238fSKirk McKusick 		 */
3410061238fSKirk McKusick 		if (dp->d_type != 0) {
3420061238fSKirk McKusick 			dp->d_type = 0;
3430061238fSKirk McKusick 			modified = 1;
3440061238fSKirk McKusick 		}
3450061238fSKirk McKusick 		if (dp->d_namlen != 0) {
3460061238fSKirk McKusick 			dp->d_namlen = 0;
3470061238fSKirk McKusick 			modified = 1;
3480061238fSKirk McKusick 		}
349bfc5d3f9SKirk McKusick 		unused = dp->d_reclen - __offsetof(struct direct, d_name);
350bfc5d3f9SKirk McKusick 		for (cp = dp->d_name; unused > 0; unused--, cp++) {
351bfc5d3f9SKirk McKusick 			if (*cp != '\0') {
352bfc5d3f9SKirk McKusick 				*cp = '\0';
3530061238fSKirk McKusick 				modified = 1;
3540061238fSKirk McKusick 			}
3550061238fSKirk McKusick 		}
356bfc5d3f9SKirk McKusick 		if (modified)
357bfc5d3f9SKirk McKusick 			dirty(bp);
358bfc5d3f9SKirk McKusick 		return (1);
3590061238fSKirk McKusick 	}
360bfc5d3f9SKirk McKusick 	/*
361bfc5d3f9SKirk McKusick 	 * The d_type field should not be tested here. A bad type is an error
362bfc5d3f9SKirk McKusick 	 * in the entry itself but is not a corruption of the directory
363bfc5d3f9SKirk McKusick 	 * structure itself. So blowing away all the remaining entries in the
364bfc5d3f9SKirk McKusick 	 * directory block is inappropriate. Rather the type error should be
365bfc5d3f9SKirk McKusick 	 * checked in pass1 and fixed there.
366bfc5d3f9SKirk McKusick 	 *
367bfc5d3f9SKirk McKusick 	 * The name validation should also be done in pass1 although the
368bfc5d3f9SKirk McKusick 	 * check to see if the name is longer than fits in the space
369bfc5d3f9SKirk McKusick 	 * allocated for it (i.e., the *cp != '\0' fails after exiting the
370bfc5d3f9SKirk McKusick 	 * loop below) then it really is a structural error that requires
371bfc5d3f9SKirk McKusick 	 * the stronger action taken here.
372bfc5d3f9SKirk McKusick 	 */
3738fae3551SRodney W. Grimes 	namlen = dp->d_namlen;
374bfc5d3f9SKirk McKusick 	if (namlen == 0 || dp->d_type > 15)
375142d8d2fSKirk McKusick 		goto bad;
376bfc5d3f9SKirk McKusick 	for (cp = dp->d_name, size = 0; size < namlen; size++) {
377bfc5d3f9SKirk McKusick 		if (*cp == '\0' || *cp++ == '/')
378142d8d2fSKirk McKusick 			goto bad;
379bfc5d3f9SKirk McKusick 	}
380780a5c1eSPeter Wemm 	if (*cp != '\0')
381142d8d2fSKirk McKusick 		goto bad;
3820061238fSKirk McKusick 	if (zflag && fswritefd >= 0) {
3830061238fSKirk McKusick 		/*
3840061238fSKirk McKusick 		 * Clear unused directory entry space, including the d_name
3850061238fSKirk McKusick 		 * padding.
3860061238fSKirk McKusick 		 */
3870061238fSKirk McKusick 		/* First figure the number of pad bytes. */
3880061238fSKirk McKusick 		unused = roundup2(namlen + 1, DIR_ROUNDUP) - (namlen + 1);
3890061238fSKirk McKusick 
3900061238fSKirk McKusick 		/* Add in the free space to the end of the record. */
3910061238fSKirk McKusick 		unused += dp->d_reclen - DIRSIZ(0, dp);
3920061238fSKirk McKusick 
3930061238fSKirk McKusick 		/*
3940061238fSKirk McKusick 		 * Now clear out the unused space, keeping track if we actually
3950061238fSKirk McKusick 		 * changed anything.
3960061238fSKirk McKusick 		 */
3970061238fSKirk McKusick 		for (cp = &dp->d_name[namlen + 1]; unused > 0; unused--, cp++) {
3980061238fSKirk McKusick 			if (*cp != '\0') {
3990061238fSKirk McKusick 				*cp = '\0';
4000061238fSKirk McKusick 				modified = 1;
4010061238fSKirk McKusick 			}
4020061238fSKirk McKusick 		}
4030061238fSKirk McKusick 
404bfc5d3f9SKirk McKusick 		if (modified)
405bfc5d3f9SKirk McKusick 			dirty(bp);
4060061238fSKirk McKusick 	}
4078fae3551SRodney W. Grimes 	return (1);
4080061238fSKirk McKusick 
409142d8d2fSKirk McKusick bad:
410142d8d2fSKirk McKusick 	if (debug)
411142d8d2fSKirk McKusick 		printf("Bad dir: ino %d reclen %d namlen %d type %d name %s\n",
412142d8d2fSKirk McKusick 		    dp->d_ino, dp->d_reclen, dp->d_namlen, dp->d_type,
413142d8d2fSKirk McKusick 		    dp->d_name);
414142d8d2fSKirk McKusick 	return (0);
4158fae3551SRodney W. Grimes }
4168fae3551SRodney W. Grimes 
41731f4ab50SBruce Evans void
418599304a4SPoul-Henning Kamp direrror(ino_t ino, const char *errmesg)
4198fae3551SRodney W. Grimes {
4208fae3551SRodney W. Grimes 
4218fae3551SRodney W. Grimes 	fileerror(ino, ino, errmesg);
4228fae3551SRodney W. Grimes }
4238fae3551SRodney W. Grimes 
42431f4ab50SBruce Evans void
425599304a4SPoul-Henning Kamp fileerror(ino_t cwd, ino_t ino, const char *errmesg)
4268fae3551SRodney W. Grimes {
4275cc52631SKirk McKusick 	struct inode ip;
4281c85e6a3SKirk McKusick 	union dinode *dp;
4298fae3551SRodney W. Grimes 	char pathbuf[MAXPATHLEN + 1];
4308fae3551SRodney W. Grimes 
4318fae3551SRodney W. Grimes 	pwarn("%s ", errmesg);
43211ce203eSKirk McKusick 	if (ino < UFS_ROOTINO || ino >= maxino) {
4339fc5d538SKirk McKusick 		pfatal("out-of-range inode number %ju", (uintmax_t)ino);
4348fae3551SRodney W. Grimes 		return;
4358fae3551SRodney W. Grimes 	}
4365cc52631SKirk McKusick 	ginode(ino, &ip);
4375cc52631SKirk McKusick 	dp = ip.i_dp;
4385cc52631SKirk McKusick 	prtinode(&ip);
4399fc5d538SKirk McKusick 	printf("\n");
4409fc5d538SKirk McKusick 	getpathname(pathbuf, cwd, ino);
4418fae3551SRodney W. Grimes 	if (ftypeok(dp))
4428fae3551SRodney W. Grimes 		pfatal("%s=%s\n",
443d8ba45e2SEd Maste 		    (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE",
4441c85e6a3SKirk McKusick 		    pathbuf);
4458fae3551SRodney W. Grimes 	else
4468fae3551SRodney W. Grimes 		pfatal("NAME=%s\n", pathbuf);
4475cc52631SKirk McKusick 	irelse(&ip);
4488fae3551SRodney W. Grimes }
4498fae3551SRodney W. Grimes 
45031f4ab50SBruce Evans void
451b70cd7eeSWarner Losh adjust(struct inodesc *idesc, int lcnt)
4528fae3551SRodney W. Grimes {
4535cc52631SKirk McKusick 	struct inode ip;
4541c85e6a3SKirk McKusick 	union dinode *dp;
455d33e92f9SJulian Elischer 	int saveresolved;
4568fae3551SRodney W. Grimes 
4575cc52631SKirk McKusick 	ginode(idesc->id_number, &ip);
4585cc52631SKirk McKusick 	dp = ip.i_dp;
4591c85e6a3SKirk McKusick 	if (DIP(dp, di_nlink) == lcnt) {
460d33e92f9SJulian Elischer 		/*
461d33e92f9SJulian Elischer 		 * If we have not hit any unresolved problems, are running
462d33e92f9SJulian Elischer 		 * in preen mode, and are on a file system using soft updates,
463d33e92f9SJulian Elischer 		 * then just toss any partially allocated files.
464d33e92f9SJulian Elischer 		 */
4657578c6abSKirk McKusick 		if (resolved && (preen || bkgrdflag) && usedsoftdep) {
466d33e92f9SJulian Elischer 			clri(idesc, "UNREF", 1);
4675cc52631SKirk McKusick 			irelse(&ip);
468d33e92f9SJulian Elischer 			return;
4698fae3551SRodney W. Grimes 		} else {
470d33e92f9SJulian Elischer 			/*
471d33e92f9SJulian Elischer 			 * The file system can be marked clean even if
472d33e92f9SJulian Elischer 			 * a file is not linked up, but is cleared.
473d33e92f9SJulian Elischer 			 * Hence, resolved should not be cleared when
474d33e92f9SJulian Elischer 			 * linkup is answered no, but clri is answered yes.
475d33e92f9SJulian Elischer 			 */
476d33e92f9SJulian Elischer 			saveresolved = resolved;
477d33e92f9SJulian Elischer 			if (linkup(idesc->id_number, (ino_t)0, NULL) == 0) {
478d33e92f9SJulian Elischer 				resolved = saveresolved;
479d33e92f9SJulian Elischer 				clri(idesc, "UNREF", 0);
4805cc52631SKirk McKusick 				irelse(&ip);
481d33e92f9SJulian Elischer 				return;
482d33e92f9SJulian Elischer 			}
483d33e92f9SJulian Elischer 			/*
484d33e92f9SJulian Elischer 			 * Account for the new reference created by linkup().
485d33e92f9SJulian Elischer 			 */
486d33e92f9SJulian Elischer 			lcnt--;
487d33e92f9SJulian Elischer 		}
488d33e92f9SJulian Elischer 	}
489d33e92f9SJulian Elischer 	if (lcnt != 0) {
4908fae3551SRodney W. Grimes 		pwarn("LINK COUNT %s", (lfdir == idesc->id_number) ? lfname :
491d8ba45e2SEd Maste 			((DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"));
4925cc52631SKirk McKusick 		prtinode(&ip);
4938fae3551SRodney W. Grimes 		printf(" COUNT %d SHOULD BE %d",
4941c85e6a3SKirk McKusick 			DIP(dp, di_nlink), DIP(dp, di_nlink) - lcnt);
495b1897c19SJulian Elischer 		if (preen || usedsoftdep) {
4968fae3551SRodney W. Grimes 			if (lcnt < 0) {
4978fae3551SRodney W. Grimes 				printf("\n");
4988fae3551SRodney W. Grimes 				pfatal("LINK COUNT INCREASING");
4998fae3551SRodney W. Grimes 			}
500b1897c19SJulian Elischer 			if (preen)
5018fae3551SRodney W. Grimes 				printf(" (ADJUSTED)\n");
5028fae3551SRodney W. Grimes 		}
5038fae3551SRodney W. Grimes 		if (preen || reply("ADJUST") == 1) {
5047578c6abSKirk McKusick 			if (bkgrdflag == 0) {
505c3b2344bSScott Long 				DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - lcnt);
5065cc52631SKirk McKusick 				inodirty(&ip);
5077578c6abSKirk McKusick 			} else {
5087578c6abSKirk McKusick 				cmd.value = idesc->id_number;
5097578c6abSKirk McKusick 				cmd.size = -lcnt;
5107578c6abSKirk McKusick 				if (debug)
511599304a4SPoul-Henning Kamp 					printf("adjrefcnt ino %ld amt %lld\n",
512599304a4SPoul-Henning Kamp 					    (long)cmd.value,
513599304a4SPoul-Henning Kamp 					    (long long)cmd.size);
5147578c6abSKirk McKusick 				if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
5157578c6abSKirk McKusick 				    &cmd, sizeof cmd) == -1)
516e4a905d1SKirk McKusick 					rwerror("ADJUST INODE LINK COUNT",
517e4a905d1SKirk McKusick 					    cmd.value);
5187578c6abSKirk McKusick 			}
5198fae3551SRodney W. Grimes 		}
5208fae3551SRodney W. Grimes 	}
5215cc52631SKirk McKusick 	irelse(&ip);
5228fae3551SRodney W. Grimes }
5238fae3551SRodney W. Grimes 
524780a5c1eSPeter Wemm static int
525b70cd7eeSWarner Losh mkentry(struct inodesc *idesc)
5268fae3551SRodney W. Grimes {
5273d438ad6SDavid E. O'Brien 	struct direct *dirp = idesc->id_dirp;
5288fae3551SRodney W. Grimes 	struct direct newent;
5298fae3551SRodney W. Grimes 	int newlen, oldlen;
5308fae3551SRodney W. Grimes 
5318fae3551SRodney W. Grimes 	newent.d_namlen = strlen(idesc->id_name);
5328fae3551SRodney W. Grimes 	newlen = DIRSIZ(0, &newent);
5338fae3551SRodney W. Grimes 	if (dirp->d_ino != 0)
5348fae3551SRodney W. Grimes 		oldlen = DIRSIZ(0, dirp);
5358fae3551SRodney W. Grimes 	else
5368fae3551SRodney W. Grimes 		oldlen = 0;
5378fae3551SRodney W. Grimes 	if (dirp->d_reclen - oldlen < newlen)
5388fae3551SRodney W. Grimes 		return (KEEPON);
5398fae3551SRodney W. Grimes 	newent.d_reclen = dirp->d_reclen - oldlen;
5408fae3551SRodney W. Grimes 	dirp->d_reclen = oldlen;
5418fae3551SRodney W. Grimes 	dirp = (struct direct *)(((char *)dirp) + oldlen);
5428fae3551SRodney W. Grimes 	dirp->d_ino = idesc->id_parent;	/* ino to be entered is in id_parent */
543780a5c1eSPeter Wemm 	dirp->d_reclen = newent.d_reclen;
544d33e92f9SJulian Elischer 	dirp->d_type = inoinfo(idesc->id_parent)->ino_type;
5459fef3122SDavid Greenman 	dirp->d_namlen = newent.d_namlen;
546780a5c1eSPeter Wemm 	memmove(dirp->d_name, idesc->id_name, (size_t)newent.d_namlen + 1);
5478fae3551SRodney W. Grimes 	return (ALTERED|STOP);
5488fae3551SRodney W. Grimes }
5498fae3551SRodney W. Grimes 
550780a5c1eSPeter Wemm static int
551b70cd7eeSWarner Losh chgino(struct inodesc *idesc)
5528fae3551SRodney W. Grimes {
5533d438ad6SDavid E. O'Brien 	struct direct *dirp = idesc->id_dirp;
5548fae3551SRodney W. Grimes 
555780a5c1eSPeter Wemm 	if (memcmp(dirp->d_name, idesc->id_name, (int)dirp->d_namlen + 1))
5568fae3551SRodney W. Grimes 		return (KEEPON);
5578fae3551SRodney W. Grimes 	dirp->d_ino = idesc->id_parent;
558d33e92f9SJulian Elischer 	dirp->d_type = inoinfo(idesc->id_parent)->ino_type;
5598fae3551SRodney W. Grimes 	return (ALTERED|STOP);
5608fae3551SRodney W. Grimes }
5618fae3551SRodney W. Grimes 
56231f4ab50SBruce Evans int
563b70cd7eeSWarner Losh linkup(ino_t orphan, ino_t parentdir, char *name)
5648fae3551SRodney W. Grimes {
5655cc52631SKirk McKusick 	struct inode ip;
5661c85e6a3SKirk McKusick 	union dinode *dp;
567fe5e6e2cSKirk McKusick 	int lostdir, depth;
5688fae3551SRodney W. Grimes 	ino_t oldlfdir;
569f4fc3895SKirk McKusick 	struct inoinfo *inp;
5708fae3551SRodney W. Grimes 	struct inodesc idesc;
5718fae3551SRodney W. Grimes 	char tempname[BUFSIZ];
5728fae3551SRodney W. Grimes 
573780a5c1eSPeter Wemm 	memset(&idesc, 0, sizeof(struct inodesc));
5745cc52631SKirk McKusick 	ginode(orphan, &ip);
5755cc52631SKirk McKusick 	dp = ip.i_dp;
576d8ba45e2SEd Maste 	lostdir = (DIP(dp, di_mode) & IFMT) == IFDIR;
5778fae3551SRodney W. Grimes 	pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
5785cc52631SKirk McKusick 	prtinode(&ip);
5799fc5d538SKirk McKusick 	printf("\n");
5805cc52631SKirk McKusick 	if (preen && DIP(dp, di_size) == 0) {
5815cc52631SKirk McKusick 		irelse(&ip);
5828fae3551SRodney W. Grimes 		return (0);
5835cc52631SKirk McKusick 	}
5845cc52631SKirk McKusick 	irelse(&ip);
5857578c6abSKirk McKusick 	if (cursnapshot != 0) {
5867578c6abSKirk McKusick 		pfatal("FILE LINKUP IN SNAPSHOT");
5877578c6abSKirk McKusick 		return (0);
5887578c6abSKirk McKusick 	}
5898fae3551SRodney W. Grimes 	if (preen)
5908fae3551SRodney W. Grimes 		printf(" (RECONNECTED)\n");
5915cc52631SKirk McKusick 	else if (reply("RECONNECT") == 0)
5928fae3551SRodney W. Grimes 		return (0);
5938fae3551SRodney W. Grimes 	if (lfdir == 0) {
5945cc52631SKirk McKusick 		ginode(UFS_ROOTINO, &ip);
595599304a4SPoul-Henning Kamp 		idesc.id_name = strdup(lfname);
5968fae3551SRodney W. Grimes 		idesc.id_type = DATA;
5978fae3551SRodney W. Grimes 		idesc.id_func = findino;
5981dc349abSEd Maste 		idesc.id_number = UFS_ROOTINO;
5995cc52631SKirk McKusick 		if ((ckinode(ip.i_dp, &idesc) & FOUND) != 0) {
6008fae3551SRodney W. Grimes 			lfdir = idesc.id_parent;
6018fae3551SRodney W. Grimes 		} else {
6028fae3551SRodney W. Grimes 			pwarn("NO lost+found DIRECTORY");
6038fae3551SRodney W. Grimes 			if (preen || reply("CREATE")) {
6041dc349abSEd Maste 				lfdir = allocdir(UFS_ROOTINO, (ino_t)0, lfmode);
6058fae3551SRodney W. Grimes 				if (lfdir != 0) {
6061dc349abSEd Maste 					if (makeentry(UFS_ROOTINO, lfdir,
6071dc349abSEd Maste 					    lfname) != 0) {
608d33e92f9SJulian Elischer 						numdirs++;
6098fae3551SRodney W. Grimes 						if (preen)
6108fae3551SRodney W. Grimes 							printf(" (CREATED)\n");
6118fae3551SRodney W. Grimes 					} else {
61252f97104SKirk McKusick 						freedirino(lfdir, UFS_ROOTINO);
6138fae3551SRodney W. Grimes 						lfdir = 0;
6148fae3551SRodney W. Grimes 						if (preen)
6158fae3551SRodney W. Grimes 							printf("\n");
6168fae3551SRodney W. Grimes 					}
6178fae3551SRodney W. Grimes 				}
6188fae3551SRodney W. Grimes 			}
6198fae3551SRodney W. Grimes 		}
6205cc52631SKirk McKusick 		irelse(&ip);
621e5d0d1c5SKirk McKusick 		free(idesc.id_name);
6228fae3551SRodney W. Grimes 		if (lfdir == 0) {
6238fae3551SRodney W. Grimes 			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY");
6248fae3551SRodney W. Grimes 			printf("\n\n");
6258fae3551SRodney W. Grimes 			return (0);
6268fae3551SRodney W. Grimes 		}
6278fae3551SRodney W. Grimes 	}
6285cc52631SKirk McKusick 	ginode(lfdir, &ip);
6295cc52631SKirk McKusick 	dp = ip.i_dp;
630d8ba45e2SEd Maste 	if ((DIP(dp, di_mode) & IFMT) != IFDIR) {
6318fae3551SRodney W. Grimes 		pfatal("lost+found IS NOT A DIRECTORY");
6325cc52631SKirk McKusick 		if (reply("REALLOCATE") == 0) {
6335cc52631SKirk McKusick 			irelse(&ip);
6348fae3551SRodney W. Grimes 			return (0);
6355cc52631SKirk McKusick 		}
6368fae3551SRodney W. Grimes 		oldlfdir = lfdir;
6371dc349abSEd Maste 		if ((lfdir = allocdir(UFS_ROOTINO, (ino_t)0, lfmode)) == 0) {
6388fae3551SRodney W. Grimes 			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
6395cc52631SKirk McKusick 			irelse(&ip);
6408fae3551SRodney W. Grimes 			return (0);
6418fae3551SRodney W. Grimes 		}
642fe5e6e2cSKirk McKusick 		if ((changeino(UFS_ROOTINO, lfname, lfdir, 1) & ALTERED) == 0) {
6438fae3551SRodney W. Grimes 			pfatal("SORRY. CANNOT CREATE lost+found DIRECTORY\n\n");
6445cc52631SKirk McKusick 			irelse(&ip);
6458fae3551SRodney W. Grimes 			return (0);
6468fae3551SRodney W. Grimes 		}
6475cc52631SKirk McKusick 		idesc.id_type = inoinfo(oldlfdir)->ino_idtype;
6487180f1abSKirk McKusick 		idesc.id_func = freeblock;
6498fae3551SRodney W. Grimes 		idesc.id_number = oldlfdir;
650d33e92f9SJulian Elischer 		adjust(&idesc, inoinfo(oldlfdir)->ino_linkcnt + 1);
651d33e92f9SJulian Elischer 		inoinfo(oldlfdir)->ino_linkcnt = 0;
6525cc52631SKirk McKusick 		inodirty(&ip);
6535cc52631SKirk McKusick 		irelse(&ip);
6545cc52631SKirk McKusick 		ginode(lfdir, &ip);
6555cc52631SKirk McKusick 		dp = ip.i_dp;
6568fae3551SRodney W. Grimes 	}
657d33e92f9SJulian Elischer 	if (inoinfo(lfdir)->ino_state != DFOUND) {
6588fae3551SRodney W. Grimes 		pfatal("SORRY. NO lost+found DIRECTORY\n\n");
6595cc52631SKirk McKusick 		irelse(&ip);
6608fae3551SRodney W. Grimes 		return (0);
6618fae3551SRodney W. Grimes 	}
6628fae3551SRodney W. Grimes 	(void)lftempname(tempname, orphan);
663d33e92f9SJulian Elischer 	if (makeentry(lfdir, orphan, (name ? name : tempname)) == 0) {
6648fae3551SRodney W. Grimes 		pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
6658fae3551SRodney W. Grimes 		printf("\n\n");
6665cc52631SKirk McKusick 		irelse(&ip);
6678fae3551SRodney W. Grimes 		return (0);
6688fae3551SRodney W. Grimes 	}
669d33e92f9SJulian Elischer 	inoinfo(orphan)->ino_linkcnt--;
6708fae3551SRodney W. Grimes 	if (lostdir) {
671fe5e6e2cSKirk McKusick 		depth = DIP(dp, di_dirdepth) + 1;
672fe5e6e2cSKirk McKusick 		if ((changeino(orphan, "..", lfdir, depth) & ALTERED) == 0 &&
6738fae3551SRodney W. Grimes 		    parentdir != (ino_t)-1)
6748fae3551SRodney W. Grimes 			(void)makeentry(orphan, lfdir, "..");
675c3b2344bSScott Long 		DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
6765cc52631SKirk McKusick 		inodirty(&ip);
677d33e92f9SJulian Elischer 		inoinfo(lfdir)->ino_linkcnt++;
678bf58d635SIan Dowse 		pwarn("DIR I=%lu CONNECTED. ", (u_long)orphan);
679f4fc3895SKirk McKusick 		inp = getinoinfo(parentdir);
68052f97104SKirk McKusick 		if (parentdir != (ino_t)-1 && inp != NULL) {
681b1046626SBruce Evans 			printf("PARENT WAS I=%lu\n", (u_long)parentdir);
6826b100474SJulian Elischer 			/*
683f4fc3895SKirk McKusick 			 * If the parent directory did not have to
684f4fc3895SKirk McKusick 			 * be replaced then because of the ordering
6856b100474SJulian Elischer 			 * guarantees, has had the link count incremented
6866b100474SJulian Elischer 			 * for the child, but no entry was made.  This
6876b100474SJulian Elischer 			 * fixes the parent link count so that fsck does
6886b100474SJulian Elischer 			 * not need to be rerun.
6896b100474SJulian Elischer 			 */
69052f97104SKirk McKusick 			if ((inp->i_flags & INFO_NEW) != 0)
691d33e92f9SJulian Elischer 				inoinfo(parentdir)->ino_linkcnt++;
692119e9fc2SNate Williams 		}
6938fae3551SRodney W. Grimes 		if (preen == 0)
6948fae3551SRodney W. Grimes 			printf("\n");
6958fae3551SRodney W. Grimes 	}
6965cc52631SKirk McKusick 	irelse(&ip);
6978fae3551SRodney W. Grimes 	return (1);
6988fae3551SRodney W. Grimes }
6998fae3551SRodney W. Grimes 
7008fae3551SRodney W. Grimes /*
7018fae3551SRodney W. Grimes  * fix an entry in a directory.
7028fae3551SRodney W. Grimes  */
70331f4ab50SBruce Evans int
704fe5e6e2cSKirk McKusick changeino(ino_t dir, const char *name, ino_t newnum, int depth)
7058fae3551SRodney W. Grimes {
7068fae3551SRodney W. Grimes 	struct inodesc idesc;
7075cc52631SKirk McKusick 	struct inode ip;
7085cc52631SKirk McKusick 	int error;
7098fae3551SRodney W. Grimes 
710780a5c1eSPeter Wemm 	memset(&idesc, 0, sizeof(struct inodesc));
7118fae3551SRodney W. Grimes 	idesc.id_type = DATA;
7128fae3551SRodney W. Grimes 	idesc.id_func = chgino;
7138fae3551SRodney W. Grimes 	idesc.id_number = dir;
7148fae3551SRodney W. Grimes 	idesc.id_fix = DONTKNOW;
715599304a4SPoul-Henning Kamp 	idesc.id_name = strdup(name);
7168fae3551SRodney W. Grimes 	idesc.id_parent = newnum;	/* new value for name */
7175cc52631SKirk McKusick 	ginode(dir, &ip);
718fe5e6e2cSKirk McKusick 	if (((error = ckinode(ip.i_dp, &idesc)) & ALTERED) && newnum != 0) {
719fe5e6e2cSKirk McKusick 		DIP_SET(ip.i_dp, di_dirdepth, depth);
72052671206SKirk McKusick 		inodirty(&ip);
721fe5e6e2cSKirk McKusick 		getinoinfo(dir)->i_depth = depth;
722fe5e6e2cSKirk McKusick 	}
723e5d0d1c5SKirk McKusick 	free(idesc.id_name);
7245cc52631SKirk McKusick 	irelse(&ip);
7255cc52631SKirk McKusick 	return (error);
7268fae3551SRodney W. Grimes }
7278fae3551SRodney W. Grimes 
7288fae3551SRodney W. Grimes /*
7298fae3551SRodney W. Grimes  * make an entry in a directory
7308fae3551SRodney W. Grimes  */
73131f4ab50SBruce Evans int
732599304a4SPoul-Henning Kamp makeentry(ino_t parent, ino_t ino, const char *name)
7338fae3551SRodney W. Grimes {
7345cc52631SKirk McKusick 	struct inode ip;
7351c85e6a3SKirk McKusick 	union dinode *dp;
7368fae3551SRodney W. Grimes 	struct inodesc idesc;
7375cc52631SKirk McKusick 	int retval;
7388fae3551SRodney W. Grimes 	char pathbuf[MAXPATHLEN + 1];
7398fae3551SRodney W. Grimes 
7401dc349abSEd Maste 	if (parent < UFS_ROOTINO || parent >= maxino ||
7411dc349abSEd Maste 	    ino < UFS_ROOTINO || ino >= maxino)
7428fae3551SRodney W. Grimes 		return (0);
743780a5c1eSPeter Wemm 	memset(&idesc, 0, sizeof(struct inodesc));
7448fae3551SRodney W. Grimes 	idesc.id_type = DATA;
7458fae3551SRodney W. Grimes 	idesc.id_func = mkentry;
7468fae3551SRodney W. Grimes 	idesc.id_number = parent;
7478fae3551SRodney W. Grimes 	idesc.id_parent = ino;	/* this is the inode to enter */
7488fae3551SRodney W. Grimes 	idesc.id_fix = DONTKNOW;
749599304a4SPoul-Henning Kamp 	idesc.id_name = strdup(name);
7505cc52631SKirk McKusick 	ginode(parent, &ip);
7515cc52631SKirk McKusick 	dp = ip.i_dp;
7521c85e6a3SKirk McKusick 	if (DIP(dp, di_size) % DIRBLKSIZ) {
753c3b2344bSScott Long 		DIP_SET(dp, di_size, roundup(DIP(dp, di_size), DIRBLKSIZ));
7545cc52631SKirk McKusick 		inodirty(&ip);
7558fae3551SRodney W. Grimes 	}
7565cc52631SKirk McKusick 	if ((ckinode(dp, &idesc) & ALTERED) != 0) {
7575cc52631SKirk McKusick 		irelse(&ip);
758e5d0d1c5SKirk McKusick 		free(idesc.id_name);
7598fae3551SRodney W. Grimes 		return (1);
7605cc52631SKirk McKusick 	}
7618fae3551SRodney W. Grimes 	getpathname(pathbuf, parent, parent);
7625cc52631SKirk McKusick 	if (expanddir(&ip, pathbuf) == 0) {
7635cc52631SKirk McKusick 		irelse(&ip);
764e5d0d1c5SKirk McKusick 		free(idesc.id_name);
7658fae3551SRodney W. Grimes 		return (0);
7665cc52631SKirk McKusick 	}
7675cc52631SKirk McKusick 	retval = ckinode(dp, &idesc) & ALTERED;
7685cc52631SKirk McKusick 	irelse(&ip);
769e5d0d1c5SKirk McKusick 	free(idesc.id_name);
7705cc52631SKirk McKusick 	return (retval);
7718fae3551SRodney W. Grimes }
7728fae3551SRodney W. Grimes 
7738fae3551SRodney W. Grimes /*
7748fae3551SRodney W. Grimes  * Attempt to expand the size of a directory
7758fae3551SRodney W. Grimes  */
776780a5c1eSPeter Wemm static int
7775cc52631SKirk McKusick expanddir(struct inode *ip, char *name)
7788fae3551SRodney W. Grimes {
779997f81afSKirk McKusick 	ufs2_daddr_t lastlbn, oldblk, newblk, indirblk;
780997f81afSKirk McKusick 	size_t filesize, lastlbnsize;
781997f81afSKirk McKusick 	struct bufarea *bp, *nbp;
7827180f1abSKirk McKusick 	struct inodesc idesc;
7835cc52631SKirk McKusick 	union dinode *dp;
784460ed610SKirk McKusick 	long cg, indiralloced;
785997f81afSKirk McKusick 	char *cp;
7868fae3551SRodney W. Grimes 
787997f81afSKirk McKusick 	nbp = NULL;
788997f81afSKirk McKusick 	indiralloced = newblk = indirblk = 0;
789460ed610SKirk McKusick 	memset(&idesc, 0, sizeof(struct inodesc));
790460ed610SKirk McKusick 	idesc.id_type = ADDR;
791997f81afSKirk McKusick 	pwarn("NO SPACE LEFT IN %s", name);
792997f81afSKirk McKusick 	if (!preen && reply("EXPAND") == 0)
7938fae3551SRodney W. Grimes 		return (0);
794460ed610SKirk McKusick 	cg = ino_to_cg(&sblock, ip->i_number);
7955cc52631SKirk McKusick 	dp = ip->i_dp;
796997f81afSKirk McKusick 	filesize = DIP(dp, di_size);
797997f81afSKirk McKusick 	lastlbn = lblkno(&sblock, filesize);
798997f81afSKirk McKusick 	/*
799997f81afSKirk McKusick 	 * We only expand lost+found to a single indirect block.
800997f81afSKirk McKusick 	 */
801997f81afSKirk McKusick 	if ((DIP(dp, di_mode) & IFMT) != IFDIR || filesize == 0 ||
802997f81afSKirk McKusick 	    lastlbn >= UFS_NDADDR + NINDIR(&sblock))
803997f81afSKirk McKusick 		goto bad;
804997f81afSKirk McKusick 	/*
805997f81afSKirk McKusick 	 * If last block is a fragment, expand it to a full size block.
806997f81afSKirk McKusick 	 */
807997f81afSKirk McKusick 	lastlbnsize = sblksize(&sblock, filesize, lastlbn);
808c8a7a3ffSKirk McKusick 	if (lastlbnsize > 0 && lastlbnsize < sblock.fs_bsize) {
809997f81afSKirk McKusick 		oldblk = DIP(dp, di_db[lastlbn]);
810997f81afSKirk McKusick 		bp = getdirblk(oldblk, lastlbnsize);
8118fae3551SRodney W. Grimes 		if (bp->b_errs)
8128fae3551SRodney W. Grimes 			goto bad;
813460ed610SKirk McKusick 		newblk = allocblk(cg, sblock.fs_frag, std_checkblkavail);
814460ed610SKirk McKusick 		if (newblk == 0)
815997f81afSKirk McKusick 			goto bad;
816997f81afSKirk McKusick 		nbp = getdatablk(newblk, sblock.fs_bsize, BT_DIRDATA);
817997f81afSKirk McKusick 		if (nbp->b_errs)
818997f81afSKirk McKusick 			goto bad;
819997f81afSKirk McKusick 		DIP_SET(dp, di_db[lastlbn], newblk);
820997f81afSKirk McKusick 		DIP_SET(dp, di_size, filesize + sblock.fs_bsize - lastlbnsize);
821997f81afSKirk McKusick 		DIP_SET(dp, di_blocks, DIP(dp, di_blocks) +
822997f81afSKirk McKusick 		    btodb(sblock.fs_bsize - lastlbnsize));
8235cc52631SKirk McKusick 		inodirty(ip);
824997f81afSKirk McKusick 		memmove(nbp->b_un.b_buf, bp->b_un.b_buf, lastlbnsize);
825997f81afSKirk McKusick 		memset(&nbp->b_un.b_buf[lastlbnsize], 0,
826997f81afSKirk McKusick 		    sblock.fs_bsize - lastlbnsize);
827997f81afSKirk McKusick 		for (cp = &nbp->b_un.b_buf[lastlbnsize];
828997f81afSKirk McKusick 		     cp < &nbp->b_un.b_buf[sblock.fs_bsize];
829997f81afSKirk McKusick 		     cp += DIRBLKSIZ)
830997f81afSKirk McKusick 			memmove(cp, &emptydir, sizeof emptydir);
831997f81afSKirk McKusick 		dirty(nbp);
8325cc52631SKirk McKusick 		brelse(nbp);
833460ed610SKirk McKusick 		binval(bp);
834997f81afSKirk McKusick 		idesc.id_blkno = oldblk;
835997f81afSKirk McKusick 		idesc.id_numfrags = numfrags(&sblock, lastlbnsize);
836997f81afSKirk McKusick 		(void)freeblock(&idesc);
8375cc52631SKirk McKusick 		if (preen)
8385cc52631SKirk McKusick 			printf(" (EXPANDED)\n");
839997f81afSKirk McKusick 		return (1);
840997f81afSKirk McKusick 	}
841460ed610SKirk McKusick 	if ((newblk = allocblk(cg, sblock.fs_frag, std_checkblkavail)) == 0)
842997f81afSKirk McKusick 		goto bad;
8438fae3551SRodney W. Grimes 	bp = getdirblk(newblk, sblock.fs_bsize);
8448fae3551SRodney W. Grimes 	if (bp->b_errs)
8458fae3551SRodney W. Grimes 		goto bad;
846997f81afSKirk McKusick 	memset(bp->b_un.b_buf, 0, sblock.fs_bsize);
847997f81afSKirk McKusick 	for (cp = bp->b_un.b_buf;
8488fae3551SRodney W. Grimes 	     cp < &bp->b_un.b_buf[sblock.fs_bsize];
8498fae3551SRodney W. Grimes 	     cp += DIRBLKSIZ)
850780a5c1eSPeter Wemm 		memmove(cp, &emptydir, sizeof emptydir);
8518fae3551SRodney W. Grimes 	dirty(bp);
852997f81afSKirk McKusick 	if (lastlbn < UFS_NDADDR) {
853997f81afSKirk McKusick 		DIP_SET(dp, di_db[lastlbn], newblk);
854997f81afSKirk McKusick 	} else {
855997f81afSKirk McKusick 		/*
856997f81afSKirk McKusick 		 * Allocate indirect block if needed.
857997f81afSKirk McKusick 		 */
858997f81afSKirk McKusick 		if ((indirblk = DIP(dp, di_ib[0])) == 0) {
859460ed610SKirk McKusick 			indirblk = allocblk(cg, sblock.fs_frag,
860460ed610SKirk McKusick 			    std_checkblkavail);
861460ed610SKirk McKusick 			if (indirblk == 0) {
862460ed610SKirk McKusick 				binval(bp);
8638fae3551SRodney W. Grimes 				goto bad;
864460ed610SKirk McKusick 			}
865997f81afSKirk McKusick 			indiralloced = 1;
866997f81afSKirk McKusick 		}
867997f81afSKirk McKusick 		nbp = getdatablk(indirblk, sblock.fs_bsize, BT_LEVEL1);
868997f81afSKirk McKusick 		if (nbp->b_errs)
869997f81afSKirk McKusick 			goto bad;
870997f81afSKirk McKusick 		if (indiralloced) {
871997f81afSKirk McKusick 			memset(nbp->b_un.b_buf, 0, sblock.fs_bsize);
872997f81afSKirk McKusick 			DIP_SET(dp, di_ib[0], indirblk);
873997f81afSKirk McKusick 			DIP_SET(dp, di_blocks,
874997f81afSKirk McKusick 			    DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
87552671206SKirk McKusick 			inodirty(ip);
876997f81afSKirk McKusick 		}
877997f81afSKirk McKusick 		IBLK_SET(nbp, lastlbn - UFS_NDADDR, newblk);
878997f81afSKirk McKusick 		dirty(nbp);
8795cc52631SKirk McKusick 		brelse(nbp);
880997f81afSKirk McKusick 	}
881997f81afSKirk McKusick 	DIP_SET(dp, di_size, filesize + sblock.fs_bsize);
882997f81afSKirk McKusick 	DIP_SET(dp, di_blocks, DIP(dp, di_blocks) + btodb(sblock.fs_bsize));
8835cc52631SKirk McKusick 	inodirty(ip);
8848fae3551SRodney W. Grimes 	if (preen)
8858fae3551SRodney W. Grimes 		printf(" (EXPANDED)\n");
8868fae3551SRodney W. Grimes 	return (1);
8878fae3551SRodney W. Grimes bad:
888997f81afSKirk McKusick 	pfatal(" (EXPANSION FAILED)\n");
889460ed610SKirk McKusick 	if (nbp != NULL) {
890460ed610SKirk McKusick 		binval(bp);
8915cc52631SKirk McKusick 		brelse(nbp);
892460ed610SKirk McKusick 	}
893997f81afSKirk McKusick 	if (newblk != 0) {
8947180f1abSKirk McKusick 		idesc.id_blkno = newblk;
8957180f1abSKirk McKusick 		idesc.id_numfrags = sblock.fs_frag;
8967180f1abSKirk McKusick 		(void)freeblock(&idesc);
897997f81afSKirk McKusick 	}
898997f81afSKirk McKusick 	if (indiralloced) {
899997f81afSKirk McKusick 		idesc.id_blkno = indirblk;
900997f81afSKirk McKusick 		idesc.id_numfrags = sblock.fs_frag;
901997f81afSKirk McKusick 		(void)freeblock(&idesc);
902997f81afSKirk McKusick 	}
9038fae3551SRodney W. Grimes 	return (0);
9048fae3551SRodney W. Grimes }
9058fae3551SRodney W. Grimes 
9068fae3551SRodney W. Grimes /*
9078fae3551SRodney W. Grimes  * allocate a new directory
9088fae3551SRodney W. Grimes  */
9093eeb5bdcSBruce Evans ino_t
910b70cd7eeSWarner Losh allocdir(ino_t parent, ino_t request, int mode)
9118fae3551SRodney W. Grimes {
9128fae3551SRodney W. Grimes 	ino_t ino;
9138fae3551SRodney W. Grimes 	char *cp;
9145cc52631SKirk McKusick 	struct inode ip;
9151c85e6a3SKirk McKusick 	union dinode *dp;
91691ea1615SKirk McKusick 	struct bufarea *bp;
9178fae3551SRodney W. Grimes 	struct dirtemplate *dirp;
918fe5e6e2cSKirk McKusick 	struct inoinfo *inp, *parentinp;
9198fae3551SRodney W. Grimes 
920d8ba45e2SEd Maste 	ino = allocino(request, IFDIR|mode);
92184a0e3f9SKirk McKusick 	if (ino == 0)
92284a0e3f9SKirk McKusick 		return (0);
9238fae3551SRodney W. Grimes 	dirp = &dirhead;
9248fae3551SRodney W. Grimes 	dirp->dot_ino = ino;
9258fae3551SRodney W. Grimes 	dirp->dotdot_ino = parent;
9265cc52631SKirk McKusick 	ginode(ino, &ip);
9275cc52631SKirk McKusick 	dp = ip.i_dp;
9281c85e6a3SKirk McKusick 	bp = getdirblk(DIP(dp, di_db[0]), sblock.fs_fsize);
9298fae3551SRodney W. Grimes 	if (bp->b_errs) {
9308fae3551SRodney W. Grimes 		freeino(ino);
9315cc52631SKirk McKusick 		irelse(&ip);
9328fae3551SRodney W. Grimes 		return (0);
9338fae3551SRodney W. Grimes 	}
934780a5c1eSPeter Wemm 	memmove(bp->b_un.b_buf, dirp, sizeof(struct dirtemplate));
9358fae3551SRodney W. Grimes 	for (cp = &bp->b_un.b_buf[DIRBLKSIZ];
9368fae3551SRodney W. Grimes 	     cp < &bp->b_un.b_buf[sblock.fs_fsize];
9378fae3551SRodney W. Grimes 	     cp += DIRBLKSIZ)
938780a5c1eSPeter Wemm 		memmove(cp, &emptydir, sizeof emptydir);
9398fae3551SRodney W. Grimes 	dirty(bp);
940c3b2344bSScott Long 	DIP_SET(dp, di_nlink, 2);
9415cc52631SKirk McKusick 	inodirty(&ip);
9421dc349abSEd Maste 	if (ino == UFS_ROOTINO) {
943f4fc3895SKirk McKusick 		inp = cacheino(dp, ino);
944f4fc3895SKirk McKusick 		inp->i_parent = parent;
945f4fc3895SKirk McKusick 		inp->i_dotdot = parent;
94652f97104SKirk McKusick 		inp->i_flags |= INFO_NEW;
94752f97104SKirk McKusick 		inoinfo(ino)->ino_type = DT_DIR;
94852f97104SKirk McKusick 		inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink);
9495cc52631SKirk McKusick 		irelse(&ip);
9508fae3551SRodney W. Grimes 		return(ino);
9518fae3551SRodney W. Grimes 	}
952af6726e6SDon Lewis 	if (!INO_IS_DVALID(parent)) {
9538fae3551SRodney W. Grimes 		freeino(ino);
9545cc52631SKirk McKusick 		irelse(&ip);
9558fae3551SRodney W. Grimes 		return (0);
9568fae3551SRodney W. Grimes 	}
957f4fc3895SKirk McKusick 	inp = cacheino(dp, ino);
95891ea1615SKirk McKusick 	inp->i_parent = parent;
95991ea1615SKirk McKusick 	inp->i_dotdot = parent;
96052f97104SKirk McKusick 	inp->i_flags |= INFO_NEW;
961fe5e6e2cSKirk McKusick 	if ((parentinp = getinoinfo(inp->i_parent)) == NULL) {
962fe5e6e2cSKirk McKusick 		pfatal("allocdir: UNKNOWN PARENT DIR");
963fe5e6e2cSKirk McKusick 	} else {
964fe5e6e2cSKirk McKusick 		inp->i_depth = parentinp->i_depth + 1;
965fe5e6e2cSKirk McKusick 		DIP_SET(dp, di_dirdepth, inp->i_depth);
96652671206SKirk McKusick 		inodirty(&ip);
967fe5e6e2cSKirk McKusick 	}
96852f97104SKirk McKusick 	inoinfo(ino)->ino_type = DT_DIR;
969d33e92f9SJulian Elischer 	inoinfo(ino)->ino_state = inoinfo(parent)->ino_state;
970d33e92f9SJulian Elischer 	if (inoinfo(ino)->ino_state == DSTATE) {
9711c85e6a3SKirk McKusick 		inoinfo(ino)->ino_linkcnt = DIP(dp, di_nlink);
972d33e92f9SJulian Elischer 		inoinfo(parent)->ino_linkcnt++;
9738fae3551SRodney W. Grimes 	}
9745cc52631SKirk McKusick 	irelse(&ip);
9755cc52631SKirk McKusick 	ginode(parent, &ip);
9765cc52631SKirk McKusick 	dp = ip.i_dp;
977c3b2344bSScott Long 	DIP_SET(dp, di_nlink, DIP(dp, di_nlink) + 1);
9785cc52631SKirk McKusick 	inodirty(&ip);
9795cc52631SKirk McKusick 	irelse(&ip);
9808fae3551SRodney W. Grimes 	return (ino);
9818fae3551SRodney W. Grimes }
9828fae3551SRodney W. Grimes 
9838fae3551SRodney W. Grimes /*
9848fae3551SRodney W. Grimes  * free a directory inode
9858fae3551SRodney W. Grimes  */
98652f97104SKirk McKusick void
98752f97104SKirk McKusick freedirino(ino_t ino, ino_t parent)
9888fae3551SRodney W. Grimes {
9895cc52631SKirk McKusick 	struct inode ip;
9901c85e6a3SKirk McKusick 	union dinode *dp;
9918fae3551SRodney W. Grimes 
9928fae3551SRodney W. Grimes 	if (ino != parent) {
9935cc52631SKirk McKusick 		ginode(parent, &ip);
9945cc52631SKirk McKusick 		dp = ip.i_dp;
995c3b2344bSScott Long 		DIP_SET(dp, di_nlink, DIP(dp, di_nlink) - 1);
9965cc52631SKirk McKusick 		inodirty(&ip);
9975cc52631SKirk McKusick 		irelse(&ip);
9988fae3551SRodney W. Grimes 	}
99952f97104SKirk McKusick 	removecachedino(ino);
10008fae3551SRodney W. Grimes 	freeino(ino);
10018fae3551SRodney W. Grimes }
10028fae3551SRodney W. Grimes 
10038fae3551SRodney W. Grimes /*
10048fae3551SRodney W. Grimes  * generate a temporary name for the lost+found directory.
10058fae3551SRodney W. Grimes  */
1006780a5c1eSPeter Wemm static int
1007b70cd7eeSWarner Losh lftempname(char *bufp, ino_t ino)
10088fae3551SRodney W. Grimes {
10093d438ad6SDavid E. O'Brien 	ino_t in;
10103d438ad6SDavid E. O'Brien 	char *cp;
10118fae3551SRodney W. Grimes 	int namlen;
10128fae3551SRodney W. Grimes 
10138fae3551SRodney W. Grimes 	cp = bufp + 2;
10148fae3551SRodney W. Grimes 	for (in = maxino; in > 0; in /= 10)
10158fae3551SRodney W. Grimes 		cp++;
10168fae3551SRodney W. Grimes 	*--cp = 0;
10178fae3551SRodney W. Grimes 	namlen = cp - bufp;
10188fae3551SRodney W. Grimes 	in = ino;
10198fae3551SRodney W. Grimes 	while (cp > bufp) {
10208fae3551SRodney W. Grimes 		*--cp = (in % 10) + '0';
10218fae3551SRodney W. Grimes 		in /= 10;
10228fae3551SRodney W. Grimes 	}
10238fae3551SRodney W. Grimes 	*cp = '#';
10248fae3551SRodney W. Grimes 	return (namlen);
10258fae3551SRodney W. Grimes }
10268fae3551SRodney W. Grimes 
10278fae3551SRodney W. Grimes /*
10288fae3551SRodney W. Grimes  * Get a directory block.
10298fae3551SRodney W. Grimes  * Insure that it is held until another is requested.
10308fae3551SRodney W. Grimes  */
1031780a5c1eSPeter Wemm static struct bufarea *
10321c85e6a3SKirk McKusick getdirblk(ufs2_daddr_t blkno, long size)
10338fae3551SRodney W. Grimes {
10348fae3551SRodney W. Grimes 
10355cc52631SKirk McKusick 	if (pdirbp != NULL && pdirbp->b_errs == 0)
10365cc52631SKirk McKusick 		brelse(pdirbp);
1037ed75b5a1SKirk McKusick 	pdirbp = getdatablk(blkno, size, BT_DIRDATA);
10388fae3551SRodney W. Grimes 	return (pdirbp);
10398fae3551SRodney W. Grimes }
1040