xref: /netbsd/sbin/fsck_lfs/inode.c (revision 913768d6)
1*913768d6Sjoerg /* $NetBSD: inode.c,v 1.70 2020/04/03 19:36:33 joerg Exp $	 */
25aaab72dSperseant 
35aaab72dSperseant /*-
45aaab72dSperseant  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
55aaab72dSperseant  * All rights reserved.
65aaab72dSperseant  *
75aaab72dSperseant  * This code is derived from software contributed to The NetBSD Foundation
85aaab72dSperseant  * by Konrad E. Schroder <perseant@hhhh.org>.
95aaab72dSperseant  *
105aaab72dSperseant  * Redistribution and use in source and binary forms, with or without
115aaab72dSperseant  * modification, are permitted provided that the following conditions
125aaab72dSperseant  * are met:
135aaab72dSperseant  * 1. Redistributions of source code must retain the above copyright
145aaab72dSperseant  *    notice, this list of conditions and the following disclaimer.
155aaab72dSperseant  * 2. Redistributions in binary form must reproduce the above copyright
165aaab72dSperseant  *    notice, this list of conditions and the following disclaimer in the
175aaab72dSperseant  *    documentation and/or other materials provided with the distribution.
185aaab72dSperseant  *
195aaab72dSperseant  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
205aaab72dSperseant  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
215aaab72dSperseant  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
225aaab72dSperseant  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
235aaab72dSperseant  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
245aaab72dSperseant  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
255aaab72dSperseant  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
265aaab72dSperseant  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
275aaab72dSperseant  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
285aaab72dSperseant  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
295aaab72dSperseant  * POSSIBILITY OF SUCH DAMAGE.
305aaab72dSperseant  */
31276d62f6Sagc 
32276d62f6Sagc /*
33276d62f6Sagc  * Copyright (c) 1980, 1986, 1993
34276d62f6Sagc  *	The Regents of the University of California.  All rights reserved.
35276d62f6Sagc  *
36276d62f6Sagc  * Redistribution and use in source and binary forms, with or without
37276d62f6Sagc  * modification, are permitted provided that the following conditions
38276d62f6Sagc  * are met:
39276d62f6Sagc  * 1. Redistributions of source code must retain the above copyright
40276d62f6Sagc  *    notice, this list of conditions and the following disclaimer.
41276d62f6Sagc  * 2. Redistributions in binary form must reproduce the above copyright
42276d62f6Sagc  *    notice, this list of conditions and the following disclaimer in the
43276d62f6Sagc  *    documentation and/or other materials provided with the distribution.
44276d62f6Sagc  * 3. Neither the name of the University nor the names of its contributors
45276d62f6Sagc  *    may be used to endorse or promote products derived from this software
46276d62f6Sagc  *    without specific prior written permission.
47276d62f6Sagc  *
48276d62f6Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49276d62f6Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50276d62f6Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51276d62f6Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52276d62f6Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53276d62f6Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54276d62f6Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55276d62f6Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56276d62f6Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57276d62f6Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58276d62f6Sagc  * SUCH DAMAGE.
59276d62f6Sagc  */
60369e9cadSperseant 
61ba10361aSperseant #include <sys/types.h>
62369e9cadSperseant #include <sys/param.h>
63369e9cadSperseant #include <sys/time.h>
64ba10361aSperseant #include <sys/buf.h>
65ba10361aSperseant #include <sys/mount.h>
66ba10361aSperseant 
67f5ac0b5fSdholland #define vnode uvnode
68369e9cadSperseant #include <ufs/lfs/lfs.h>
69835d1242Sdholland #include <ufs/lfs/lfs_accessors.h>
7079e35bebSdholland #include <ufs/lfs/lfs_inode.h>
71ba10361aSperseant #undef vnode
72ba10361aSperseant 
73ba10361aSperseant #include <err.h>
74369e9cadSperseant #ifndef SMALL
75369e9cadSperseant #include <pwd.h>
76369e9cadSperseant #endif
77369e9cadSperseant #include <stdio.h>
78369e9cadSperseant #include <stdlib.h>
79369e9cadSperseant #include <string.h>
80b6479e9fSchristos #include <util.h>
81369e9cadSperseant 
82ba10361aSperseant #include "bufcache.h"
83100801edSchristos #include "lfs_user.h"
84ba10361aSperseant 
85369e9cadSperseant #include "fsck.h"
86369e9cadSperseant #include "fsutil.h"
87369e9cadSperseant #include "extern.h"
88369e9cadSperseant 
891d259671Sperseant static int iblock(struct inodesc *, long, u_int64_t);
90369e9cadSperseant int blksreqd(struct lfs *, int);
91369e9cadSperseant int lfs_maxino(void);
92369e9cadSperseant 
93ba10361aSperseant /*
94ba10361aSperseant  * Get a dinode of a given inum.
95ba10361aSperseant  * XXX combine this function with vget.
96ba10361aSperseant  */
9708d0c37fSdholland union lfs_dinode *
ginode(ino_t ino)98ba10361aSperseant ginode(ino_t ino)
99369e9cadSperseant {
100ba10361aSperseant 	struct uvnode *vp;
101ba10361aSperseant 	struct ubuf *bp;
1024e3fced9Sperseant 	IFILE *ifp;
103daf91f9bSdholland 	daddr_t daddr;
104daf91f9bSdholland 	unsigned segno;
105369e9cadSperseant 
106ba10361aSperseant 	vp = vget(fs, ino);
107ba10361aSperseant 	if (vp == NULL)
108e6c70652Sperseant 		return NULL;
109e6c70652Sperseant 
110ba10361aSperseant 	if (din_table[ino] == 0x0) {
111ba10361aSperseant 		LFS_IENTRY(ifp, fs, ino, bp);
112daf91f9bSdholland 		daddr = lfs_if_getdaddr(fs, ifp);
113daf91f9bSdholland 		segno = lfs_dtosn(fs, daddr);
114daf91f9bSdholland 		din_table[ino] = daddr;
11508d0c37fSdholland 		seg_table[segno].su_nbytes += DINOSIZE(fs);
116fe44973fSad 		brelse(bp, 0);
117e6c70652Sperseant 	}
11840401aa6Sdholland 	return VTOI(vp)->i_din;
119369e9cadSperseant }
120369e9cadSperseant 
121369e9cadSperseant /*
122ba10361aSperseant  * Check validity of held blocks in an inode, recursing through all blocks.
123369e9cadSperseant  */
124369e9cadSperseant int
ckinode(union lfs_dinode * dp,struct inodesc * idesc)12508d0c37fSdholland ckinode(union lfs_dinode *dp, struct inodesc *idesc)
126369e9cadSperseant {
127639239a1Sdholland 	daddr_t lbn, pbn;
128369e9cadSperseant 	long ret, n, ndb, offset;
12908d0c37fSdholland 	union lfs_dinode dino;
130369e9cadSperseant 	u_int64_t remsize, sizepb;
131369e9cadSperseant 	mode_t mode;
132369e9cadSperseant 	char pathbuf[MAXPATHLEN + 1];
133ba10361aSperseant 	struct uvnode *vp, *thisvp;
134369e9cadSperseant 
135369e9cadSperseant 	if (idesc->id_fix != IGNORE)
136369e9cadSperseant 		idesc->id_fix = DONTKNOW;
137369e9cadSperseant 	idesc->id_entryno = 0;
13808d0c37fSdholland 	idesc->id_filesize = lfs_dino_getsize(fs, dp);
13908d0c37fSdholland 	mode = lfs_dino_getmode(fs, dp) & LFS_IFMT;
14055fd1169Sdholland 	if (mode == LFS_IFBLK || mode == LFS_IFCHR ||
14108d0c37fSdholland 	    (mode == LFS_IFLNK && (lfs_dino_getsize(fs, dp) < lfs_sb_getmaxsymlinklen(fs) ||
142958ff91fSdholland 		    (lfs_sb_getmaxsymlinklen(fs) == 0 &&
14308d0c37fSdholland 			lfs_dino_getblocks(fs, dp) == 0))))
144369e9cadSperseant 		return (KEEPON);
14508d0c37fSdholland 	/* XXX is this safe if we're 32-bit? */
146369e9cadSperseant 	dino = *dp;
14708d0c37fSdholland 	ndb = howmany(lfs_dino_getsize(fs, &dino), lfs_sb_getbsize(fs));
148369e9cadSperseant 
149884f970fSyamt 	thisvp = vget(fs, idesc->id_number);
1504f8bc7f7Sdholland 	for (lbn = 0; lbn < ULFS_NDADDR; lbn++) {
15108d0c37fSdholland 		pbn = lfs_dino_getdb(fs, &dino, lbn);
152ba10361aSperseant 		if (thisvp)
153369e9cadSperseant 			idesc->id_numfrags =
1549ae6af71Schristos 				lfs_numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]);
155ba10361aSperseant 		else {
15608d0c37fSdholland 			if (--ndb == 0 && (offset = lfs_blkoff(fs, lfs_dino_getsize(fs, &dino))) != 0) {
157ba10361aSperseant 				idesc->id_numfrags =
1589ae6af71Schristos 			    	lfs_numfrags(fs, lfs_fragroundup(fs, offset));
159369e9cadSperseant 			} else
160576195d5Sdholland 				idesc->id_numfrags = lfs_sb_getfrag(fs);
161ba10361aSperseant 		}
16208d0c37fSdholland 		if (pbn == 0) {
163369e9cadSperseant 			if (idesc->id_type == DATA && ndb >= 0) {
164369e9cadSperseant 				/* An empty block in a directory XXX */
1658883e1fbSitojun 				getpathname(pathbuf, sizeof(pathbuf),
1668883e1fbSitojun 				    idesc->id_number, idesc->id_number);
16729f1062bSperseant 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [1]",
16829f1062bSperseant 				    pathbuf, (long long)idesc->id_number);
169369e9cadSperseant 				if (reply("ADJUST LENGTH") == 1) {
170ba10361aSperseant 					vp = vget(fs, idesc->id_number);
171ba10361aSperseant 					dp = VTOD(vp);
17208d0c37fSdholland 					lfs_dino_setsize(fs, dp,
17308d0c37fSdholland 					    lbn * lfs_sb_getbsize(fs));
174369e9cadSperseant 					printf(
175369e9cadSperseant 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
176369e9cadSperseant 					rerun = 1;
177ba10361aSperseant 					inodirty(VTOI(vp));
17829f1062bSperseant 				} else
17929f1062bSperseant 					break;
180369e9cadSperseant 			}
181369e9cadSperseant 			continue;
182369e9cadSperseant 		}
18308d0c37fSdholland 		idesc->id_blkno = pbn;
18408d0c37fSdholland 		idesc->id_lblkno = lbn;
185369e9cadSperseant 		if (idesc->id_type == ADDR) {
186369e9cadSperseant 			ret = (*idesc->id_func) (idesc);
1871d259671Sperseant 		} else
188369e9cadSperseant 			ret = dirscan(idesc);
189369e9cadSperseant 		if (ret & STOP)
190369e9cadSperseant 			return (ret);
191369e9cadSperseant 	}
192576195d5Sdholland 	idesc->id_numfrags = lfs_sb_getfrag(fs);
19308d0c37fSdholland 	remsize = lfs_dino_getsize(fs, &dino) - lfs_sb_getbsize(fs) * ULFS_NDADDR;
194576195d5Sdholland 	sizepb = lfs_sb_getbsize(fs);
19508d0c37fSdholland 	for (n = 1; n <= ULFS_NIADDR; n++) {
19608d0c37fSdholland 		pbn = lfs_dino_getib(fs, &dino, n-1);
19708d0c37fSdholland 		if (pbn) {
19808d0c37fSdholland 			idesc->id_blkno = pbn;
199369e9cadSperseant 			ret = iblock(idesc, n, remsize);
200369e9cadSperseant 			if (ret & STOP)
201369e9cadSperseant 				return (ret);
202369e9cadSperseant 		} else {
203369e9cadSperseant 			if (idesc->id_type == DATA && remsize > 0) {
204369e9cadSperseant 				/* An empty block in a directory XXX */
2058883e1fbSitojun 				getpathname(pathbuf, sizeof(pathbuf),
2068883e1fbSitojun 				    idesc->id_number, idesc->id_number);
20729f1062bSperseant 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [2]",
20829f1062bSperseant 				    pathbuf, (long long)idesc->id_number);
209369e9cadSperseant 				if (reply("ADJUST LENGTH") == 1) {
210ba10361aSperseant 					vp = vget(fs, idesc->id_number);
211ba10361aSperseant 					dp = VTOD(vp);
21208d0c37fSdholland 					lfs_dino_setsize(fs, dp,
21308d0c37fSdholland 					    lfs_dino_getsize(fs, dp) - remsize);
214369e9cadSperseant 					remsize = 0;
215369e9cadSperseant 					printf(
216369e9cadSperseant 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
217369e9cadSperseant 					rerun = 1;
218ba10361aSperseant 					inodirty(VTOI(vp));
219369e9cadSperseant 					break;
22029f1062bSperseant 				} else
22129f1062bSperseant 					break;
222369e9cadSperseant 			}
223369e9cadSperseant 		}
2249ae6af71Schristos 		sizepb *= LFS_NINDIR(fs);
225369e9cadSperseant 		remsize -= sizepb;
226369e9cadSperseant 	}
227369e9cadSperseant 	return (KEEPON);
228369e9cadSperseant }
229369e9cadSperseant 
230369e9cadSperseant static int
iblock(struct inodesc * idesc,long ilevel,u_int64_t isize)2311d259671Sperseant iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
232369e9cadSperseant {
233639239a1Sdholland 	unsigned j, maxindir;
234639239a1Sdholland 	daddr_t found;
235ba10361aSperseant 	struct ubuf *bp;
2361d259671Sperseant 	int i, n, (*func) (struct inodesc *), nif;
237369e9cadSperseant 	u_int64_t sizepb;
238369e9cadSperseant 	char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ];
239ba10361aSperseant 	struct uvnode *devvp, *vp;
240ba10361aSperseant 	int diddirty = 0;
241369e9cadSperseant 
242369e9cadSperseant 	if (idesc->id_type == ADDR) {
243369e9cadSperseant 		func = idesc->id_func;
244369e9cadSperseant 		n = (*func) (idesc);
245369e9cadSperseant 		if ((n & KEEPON) == 0)
246369e9cadSperseant 			return (n);
247369e9cadSperseant 	} else
248369e9cadSperseant 		func = dirscan;
24979748725Smlelstv 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
250369e9cadSperseant 		return (SKIP);
251ba10361aSperseant 
252dcba0206Sperseant 	devvp = fs->lfs_devvp;
253576195d5Sdholland 	bread(devvp, LFS_FSBTODB(fs, idesc->id_blkno), lfs_sb_getbsize(fs),
2544ec44e9dSchopps 	    0, &bp);
255369e9cadSperseant 	ilevel--;
256576195d5Sdholland 	for (sizepb = lfs_sb_getbsize(fs), i = 0; i < ilevel; i++)
2579ae6af71Schristos 		sizepb *= LFS_NINDIR(fs);
2589ae6af71Schristos 	if (isize > sizepb * LFS_NINDIR(fs))
2599ae6af71Schristos 		nif = LFS_NINDIR(fs);
260369e9cadSperseant 	else
261369e9cadSperseant 		nif = howmany(isize, sizepb);
2629ae6af71Schristos 	if (idesc->id_func == pass1check && nif < LFS_NINDIR(fs)) {
263639239a1Sdholland 		maxindir = LFS_NINDIR(fs);
264639239a1Sdholland 		for (j = nif; j < maxindir; j++) {
265639239a1Sdholland 			found = lfs_iblock_get(fs, bp->b_data, j);
266639239a1Sdholland 			if (found == 0)
267369e9cadSperseant 				continue;
26877c21aedSdholland 			(void)snprintf(buf, sizeof(buf),
26977c21aedSdholland 			    "PARTIALLY TRUNCATED INODE I=%llu",
270c4ee9f6dSchristos 			    (unsigned long long)idesc->id_number);
271369e9cadSperseant 			if (dofix(idesc, buf)) {
272639239a1Sdholland 				lfs_iblock_set(fs, bp->b_data, j, 0);
273ba10361aSperseant 				++diddirty;
274369e9cadSperseant 			}
275369e9cadSperseant 		}
276369e9cadSperseant 	}
277639239a1Sdholland 	maxindir = nif;
278639239a1Sdholland 	for (j = 0; j < maxindir; j++) {
279639239a1Sdholland 		found = lfs_iblock_get(fs, bp->b_data, j);
280639239a1Sdholland 		if (found) {
281639239a1Sdholland 			idesc->id_blkno = found;
2826e547a61Syamt 			if (ilevel == 0) {
2836e547a61Syamt 				/*
2849ae6af71Schristos 				 * dirscan needs lfs_lblkno.
2856e547a61Syamt 				 */
2866e547a61Syamt 				idesc->id_lblkno++;
287369e9cadSperseant 				n = (*func) (idesc);
2886e547a61Syamt 			} else {
289369e9cadSperseant 				n = iblock(idesc, ilevel, isize);
2906e547a61Syamt 			}
291369e9cadSperseant 			if (n & STOP) {
292ba10361aSperseant 				if (diddirty)
293ba10361aSperseant 					VOP_BWRITE(bp);
294ba10361aSperseant 				else
295fe44973fSad 					brelse(bp, 0);
296369e9cadSperseant 				return (n);
297369e9cadSperseant 			}
298369e9cadSperseant 		} else {
299369e9cadSperseant 			if (idesc->id_type == DATA && isize > 0) {
300369e9cadSperseant 				/* An empty block in a directory XXX */
3018883e1fbSitojun 				getpathname(pathbuf, sizeof(pathbuf),
3028883e1fbSitojun 				    idesc->id_number, idesc->id_number);
30329f1062bSperseant 				pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [3]",
30429f1062bSperseant 				    pathbuf, (long long)idesc->id_number);
305369e9cadSperseant 				if (reply("ADJUST LENGTH") == 1) {
306ba10361aSperseant 					vp = vget(fs, idesc->id_number);
307f4c19b7cSdholland 					lfs_dino_setsize(fs, VTOI(vp)->i_din,
308f4c19b7cSdholland 					    lfs_dino_getsize(fs,
309f4c19b7cSdholland 							     VTOI(vp)->i_din)
310f4c19b7cSdholland 					    - isize);
311369e9cadSperseant 					isize = 0;
312369e9cadSperseant 					printf(
313369e9cadSperseant 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
314369e9cadSperseant 					rerun = 1;
315ba10361aSperseant 					inodirty(VTOI(vp));
316ba10361aSperseant 					if (diddirty)
317ba10361aSperseant 						VOP_BWRITE(bp);
318ba10361aSperseant 					else
319fe44973fSad 						brelse(bp, 0);
320369e9cadSperseant 					return (STOP);
321369e9cadSperseant 				}
322369e9cadSperseant 			}
323369e9cadSperseant 		}
324369e9cadSperseant 		isize -= sizepb;
325369e9cadSperseant 	}
326ba10361aSperseant 	if (diddirty)
327ba10361aSperseant 		VOP_BWRITE(bp);
328ba10361aSperseant 	else
329fe44973fSad 		brelse(bp, 0);
330369e9cadSperseant 	return (KEEPON);
331369e9cadSperseant }
3324b8db838Sperseant 
333369e9cadSperseant /*
334369e9cadSperseant  * Check that a block in a legal block number.
335369e9cadSperseant  * Return 0 if in range, 1 if out of range.
336369e9cadSperseant  */
337369e9cadSperseant int
chkrange(daddr_t blk,int cnt)3381d259671Sperseant chkrange(daddr_t blk, int cnt)
339369e9cadSperseant {
3409ae6af71Schristos 	if (blk < lfs_sntod(fs, 0)) {
34175453f28Sperseant 		return (1);
34275453f28Sperseant 	}
3434e3fced9Sperseant 	if (blk > maxfsblock) {
3444e3fced9Sperseant 		return (1);
3454e3fced9Sperseant 	}
3469ae6af71Schristos 	if (blk + cnt < lfs_sntod(fs, 0)) {
3474e3fced9Sperseant 		return (1);
3484e3fced9Sperseant 	}
3494e3fced9Sperseant 	if (blk + cnt > maxfsblock) {
350369e9cadSperseant 		return (1);
351369e9cadSperseant 	}
352369e9cadSperseant 	return (0);
353369e9cadSperseant }
3544b8db838Sperseant 
355369e9cadSperseant /*
356369e9cadSperseant  * Routines to maintain information about directory inodes.
357369e9cadSperseant  * This is built during the first pass and used during the
358369e9cadSperseant  * second and third passes.
359369e9cadSperseant  *
360369e9cadSperseant  * Enter inodes into the cache.
361369e9cadSperseant  */
362369e9cadSperseant void
cacheino(union lfs_dinode * dp,ino_t inumber)36308d0c37fSdholland cacheino(union lfs_dinode *dp, ino_t inumber)
364369e9cadSperseant {
365ba10361aSperseant 	struct inoinfo *inp;
3666379e111Sitojun 	struct inoinfo **inpp, **ninpsort;
36708d0c37fSdholland 	unsigned int blks, i;
368369e9cadSperseant 
36908d0c37fSdholland 	blks = howmany(lfs_dino_getsize(fs, dp), lfs_sb_getbsize(fs));
3704f8bc7f7Sdholland 	if (blks > ULFS_NDADDR)
3714f8bc7f7Sdholland 		blks = ULFS_NDADDR + ULFS_NIADDR;
372639239a1Sdholland 	inp = emalloc(sizeof(*inp) + (blks - 1) * sizeof(inp->i_blks[0]));
373369e9cadSperseant 	inpp = &inphead[inumber % numdirs];
374369e9cadSperseant 	inp->i_nexthash = *inpp;
375369e9cadSperseant 	*inpp = inp;
376369e9cadSperseant 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
3774f8bc7f7Sdholland 	if (inumber == ULFS_ROOTINO)
3784f8bc7f7Sdholland 		inp->i_parent = ULFS_ROOTINO;
379369e9cadSperseant 	else
380369e9cadSperseant 		inp->i_parent = (ino_t) 0;
381369e9cadSperseant 	inp->i_dotdot = (ino_t) 0;
382369e9cadSperseant 	inp->i_number = inumber;
38308d0c37fSdholland 	inp->i_isize = lfs_dino_getsize(fs, dp);
384ba10361aSperseant 
385639239a1Sdholland 	inp->i_numblks = blks * sizeof(inp->i_blks[0]);
38608d0c37fSdholland 	for (i=0; i<blks && i<ULFS_NDADDR; i++) {
38708d0c37fSdholland 		inp->i_blks[i] = lfs_dino_getdb(fs, dp, i);
38808d0c37fSdholland 	}
38908d0c37fSdholland 	for (; i<blks; i++) {
39008d0c37fSdholland 		inp->i_blks[i] = lfs_dino_getib(fs, dp, i - ULFS_NDADDR);
39108d0c37fSdholland 	}
392369e9cadSperseant 	if (inplast == listmax) {
393b6479e9fSchristos 		ninpsort = erealloc(inpsort,
394b6479e9fSchristos 		    (listmax + 100) * sizeof(struct inoinfo *));
3956379e111Sitojun 		inpsort = ninpsort;
3966379e111Sitojun 		listmax += 100;
397369e9cadSperseant 	}
398369e9cadSperseant 	inpsort[inplast++] = inp;
399369e9cadSperseant }
400369e9cadSperseant 
401369e9cadSperseant /*
402369e9cadSperseant  * Look up an inode cache structure.
403369e9cadSperseant  */
404369e9cadSperseant struct inoinfo *
getinoinfo(ino_t inumber)4051d259671Sperseant getinoinfo(ino_t inumber)
406369e9cadSperseant {
407251f7f59Sperry 	struct inoinfo *inp;
408369e9cadSperseant 
409369e9cadSperseant 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
410369e9cadSperseant 		if (inp->i_number != inumber)
411369e9cadSperseant 			continue;
412369e9cadSperseant 		return (inp);
413369e9cadSperseant 	}
4144ff9f6f7Schristos 	err(EEXIT, "cannot find inode %llu", (unsigned long long)inumber);
415369e9cadSperseant 	return ((struct inoinfo *) 0);
416369e9cadSperseant }
417369e9cadSperseant 
418369e9cadSperseant /*
419369e9cadSperseant  * Clean up all the inode cache structure.
420369e9cadSperseant  */
421369e9cadSperseant void
inocleanup(void)422251f7f59Sperry inocleanup(void)
423369e9cadSperseant {
424251f7f59Sperry 	struct inoinfo **inpp;
425369e9cadSperseant 
426369e9cadSperseant 	if (inphead == NULL)
427369e9cadSperseant 		return;
428369e9cadSperseant 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
429369e9cadSperseant 		free((char *) (*inpp));
430369e9cadSperseant 	free((char *) inphead);
431369e9cadSperseant 	free((char *) inpsort);
432369e9cadSperseant 	inphead = inpsort = NULL;
433369e9cadSperseant }
434369e9cadSperseant 
435369e9cadSperseant void
inodirty(struct inode * ip)436ba10361aSperseant inodirty(struct inode *ip)
437369e9cadSperseant {
438f2b481f7Spgoyette 	ip->i_state |= IN_MODIFIED;
439369e9cadSperseant }
440369e9cadSperseant 
441369e9cadSperseant void
clri(struct inodesc * idesc,const char * type,int flag)442e0dd0ca2Schristos clri(struct inodesc * idesc, const char *type, int flag)
443369e9cadSperseant {
444ba10361aSperseant 	struct uvnode *vp;
445369e9cadSperseant 
446ba10361aSperseant 	vp = vget(fs, idesc->id_number);
447cb2499acSperseant 	if (flag & 0x1) {
448369e9cadSperseant 		pwarn("%s %s", type,
449f4c19b7cSdholland 		      (lfs_dino_getmode(fs, VTOI(vp)->i_din) & LFS_IFMT) == LFS_IFDIR ? "DIR" : "FILE");
450369e9cadSperseant 		pinode(idesc->id_number);
451369e9cadSperseant 	}
452cb2499acSperseant 	if ((flag & 0x2) || preen || reply("CLEAR") == 1) {
453ba10361aSperseant 		if (preen && flag != 2)
454369e9cadSperseant 			printf(" (CLEARED)\n");
455369e9cadSperseant 		n_files--;
456ba10361aSperseant 		(void) ckinode(VTOD(vp), idesc);
45717d264b6Syamt 		clearinode(idesc->id_number);
458369e9cadSperseant 		statemap[idesc->id_number] = USTATE;
45917d264b6Syamt 		vnode_destroy(vp);
460cb2499acSperseant 		return;
46117d264b6Syamt 	}
462cb2499acSperseant 	return;
46317d264b6Syamt }
46417d264b6Syamt 
46517d264b6Syamt void
clearinode(ino_t inumber)46617d264b6Syamt clearinode(ino_t inumber)
46717d264b6Syamt {
46817d264b6Syamt 	struct ubuf *bp;
46917d264b6Syamt 	IFILE *ifp;
47017d264b6Syamt 	daddr_t daddr;
471e6c70652Sperseant 
472e6c70652Sperseant 	/* Send cleared inode to the free list */
473e6c70652Sperseant 
47417d264b6Syamt 	LFS_IENTRY(ifp, fs, inumber, bp);
475daf91f9bSdholland 	daddr = lfs_if_getdaddr(fs, ifp);
476a37f15f0Sperseant 	if (daddr == LFS_UNUSED_DADDR) {
477fe44973fSad 		brelse(bp, 0);
478a37f15f0Sperseant 		return;
479a37f15f0Sperseant 	}
480daf91f9bSdholland 	lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
481daf91f9bSdholland 	lfs_if_setnextfree(fs, ifp, lfs_sb_getfreehd(fs));
482576195d5Sdholland 	lfs_sb_setfreehd(fs, inumber);
483e6c70652Sperseant 	sbdirty();
484ba10361aSperseant 	VOP_BWRITE(bp);
48517d264b6Syamt 
48617d264b6Syamt 	/*
48717d264b6Syamt 	 * update segment usage.
48817d264b6Syamt 	 */
48917d264b6Syamt 	if (daddr != LFS_UNUSED_DADDR) {
49017d264b6Syamt 		SEGUSE *sup;
4919ae6af71Schristos 		u_int32_t oldsn = lfs_dtosn(fs, daddr);
49217d264b6Syamt 
49308d0c37fSdholland 		seg_table[oldsn].su_nbytes -= DINOSIZE(fs);
49417d264b6Syamt 		LFS_SEGENTRY(sup, fs, oldsn, bp);
49508d0c37fSdholland 		sup->su_nbytes -= DINOSIZE(fs);
49617d264b6Syamt 		LFS_WRITESEGENTRY(sup, fs, oldsn, bp);	/* Ifile */
497369e9cadSperseant 	}
498369e9cadSperseant }
499369e9cadSperseant 
500369e9cadSperseant int
findname(struct inodesc * idesc)5011d259671Sperseant findname(struct inodesc * idesc)
502369e9cadSperseant {
503d01ce2a2Sdholland 	LFS_DIRHEADER *dirp = idesc->id_dirp;
504e0dd0ca2Schristos 	size_t len;
505e0dd0ca2Schristos 	char *buf;
506369e9cadSperseant 
507e9e7bd33Sdholland 	if (lfs_dir_getino(fs, dirp) != idesc->id_parent)
508369e9cadSperseant 		return (KEEPON);
5093da39f1cSdholland 	len = lfs_dir_getnamlen(fs, dirp) + 1;
5103da39f1cSdholland 	if (len > MAXPATHLEN) {
511e0dd0ca2Schristos 		/* Truncate it but don't overflow the buffer */
5123da39f1cSdholland 		/* XXX: this case doesn't null-terminate the result */
513e0dd0ca2Schristos 		len = MAXPATHLEN;
514e0dd0ca2Schristos 	}
515e0dd0ca2Schristos 	/* this is namebuf with utils.h */
516e0dd0ca2Schristos 	buf = __UNCONST(idesc->id_name);
517d033ca8cSdholland 	(void)memcpy(buf, lfs_dir_nameptr(fs, dirp), len);
518369e9cadSperseant 	return (STOP | FOUND);
519369e9cadSperseant }
520369e9cadSperseant 
521369e9cadSperseant int
findino(struct inodesc * idesc)5221d259671Sperseant findino(struct inodesc * idesc)
523369e9cadSperseant {
524d01ce2a2Sdholland 	LFS_DIRHEADER *dirp = idesc->id_dirp;
525e9e7bd33Sdholland 	ino_t ino;
526369e9cadSperseant 
527e9e7bd33Sdholland 	ino = lfs_dir_getino(fs, dirp);
528e9e7bd33Sdholland 	if (ino == 0)
529369e9cadSperseant 		return (KEEPON);
530d033ca8cSdholland 	if (strcmp(lfs_dir_nameptr(fs, dirp), idesc->id_name) == 0 &&
531e9e7bd33Sdholland 	    ino >= ULFS_ROOTINO && ino < maxino) {
532e9e7bd33Sdholland 		idesc->id_parent = ino;
533369e9cadSperseant 		return (STOP | FOUND);
534369e9cadSperseant 	}
535369e9cadSperseant 	return (KEEPON);
536369e9cadSperseant }
537369e9cadSperseant 
538369e9cadSperseant void
pinode(ino_t ino)5391d259671Sperseant pinode(ino_t ino)
540369e9cadSperseant {
54108d0c37fSdholland 	union lfs_dinode *dp;
542369e9cadSperseant 	struct passwd *pw;
543369e9cadSperseant 
544c4ee9f6dSchristos 	printf(" I=%llu ", (unsigned long long)ino);
5454f8bc7f7Sdholland 	if (ino < ULFS_ROOTINO || ino >= maxino)
546369e9cadSperseant 		return;
547369e9cadSperseant 	dp = ginode(ino);
548369e9cadSperseant 	if (dp) {
549369e9cadSperseant 		printf(" OWNER=");
550369e9cadSperseant #ifndef SMALL
55108d0c37fSdholland 		if (Uflag && (pw = getpwuid(lfs_dino_getuid(fs, dp))) != 0)
552369e9cadSperseant 			printf("%s ", pw->pw_name);
553369e9cadSperseant 		else
554369e9cadSperseant #endif
55508d0c37fSdholland 			printf("%u ", (unsigned)lfs_dino_getuid(fs, dp));
55608d0c37fSdholland 		printf("MODE=%o\n", lfs_dino_getmode(fs, dp));
557369e9cadSperseant 		if (preen)
558369e9cadSperseant 			printf("%s: ", cdevname());
55908d0c37fSdholland 		printf("SIZE=%ju ", (uintmax_t) lfs_dino_getsize(fs, dp));
56008d0c37fSdholland 		printf("MTIME=%s ", print_mtime(lfs_dino_getmtime(fs, dp)));
561369e9cadSperseant 	}
562369e9cadSperseant }
563369e9cadSperseant 
564369e9cadSperseant void
blkerror(ino_t ino,const char * type,daddr_t blk)5659be35a63Schristos blkerror(ino_t ino, const char *type, daddr_t blk)
566369e9cadSperseant {
567369e9cadSperseant 
568c4ee9f6dSchristos 	pfatal("%lld %s I=%llu", (long long) blk, type,
569c4ee9f6dSchristos 	    (unsigned long long)ino);
570369e9cadSperseant 	printf("\n");
571369e9cadSperseant 	if (exitonfail)
572369e9cadSperseant 		exit(1);
573369e9cadSperseant 	switch (statemap[ino]) {
574369e9cadSperseant 
575369e9cadSperseant 	case FSTATE:
576369e9cadSperseant 		statemap[ino] = FCLEAR;
577369e9cadSperseant 		return;
578369e9cadSperseant 
579369e9cadSperseant 	case DSTATE:
580369e9cadSperseant 		statemap[ino] = DCLEAR;
581369e9cadSperseant 		return;
582369e9cadSperseant 
583369e9cadSperseant 	case FCLEAR:
584369e9cadSperseant 	case DCLEAR:
585369e9cadSperseant 		return;
586369e9cadSperseant 
587369e9cadSperseant 	default:
5884ff9f6f7Schristos 		err(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
589369e9cadSperseant 		/* NOTREACHED */
590369e9cadSperseant 	}
591369e9cadSperseant }
5924b8db838Sperseant 
593369e9cadSperseant /*
594369e9cadSperseant  * allocate an unused inode
595369e9cadSperseant  */
596369e9cadSperseant ino_t
allocino(ino_t request,int type)5971d259671Sperseant allocino(ino_t request, int type)
598369e9cadSperseant {
599ba10361aSperseant 	ino_t ino;
60008d0c37fSdholland 	union lfs_dinode *dp;
601369e9cadSperseant 	time_t t;
602ba10361aSperseant 	struct uvnode *vp;
603ba10361aSperseant 	struct ubuf *bp;
604369e9cadSperseant 
605369e9cadSperseant 	if (request == 0)
6064f8bc7f7Sdholland 		request = ULFS_ROOTINO;
607369e9cadSperseant 	else if (statemap[request] != USTATE)
608369e9cadSperseant 		return (0);
609369e9cadSperseant 	for (ino = request; ino < maxino; ino++)
610369e9cadSperseant 		if (statemap[ino] == USTATE)
611369e9cadSperseant 			break;
612369e9cadSperseant 	if (ino == maxino)
61329f1062bSperseant 		extend_ifile(fs);
61429f1062bSperseant 
61555fd1169Sdholland 	switch (type & LFS_IFMT) {
61655fd1169Sdholland 	case LFS_IFDIR:
617369e9cadSperseant 		statemap[ino] = DSTATE;
618369e9cadSperseant 		break;
61955fd1169Sdholland 	case LFS_IFREG:
62055fd1169Sdholland 	case LFS_IFLNK:
621369e9cadSperseant 		statemap[ino] = FSTATE;
622369e9cadSperseant 		break;
623369e9cadSperseant 	default:
624369e9cadSperseant 		return (0);
625369e9cadSperseant 	}
6264b8db838Sperseant         vp = lfs_valloc(fs, ino);
6274b8db838Sperseant 	if (vp == NULL)
6284b8db838Sperseant 		return (0);
62940401aa6Sdholland 	dp = VTOI(vp)->i_din;
630576195d5Sdholland 	bp = getblk(vp, 0, lfs_sb_getfsize(fs));
631ba10361aSperseant 	VOP_BWRITE(bp);
63208d0c37fSdholland 	lfs_dino_setmode(fs, dp, type);
633369e9cadSperseant 	(void) time(&t);
63408d0c37fSdholland 	lfs_dino_setatime(fs, dp, t);
63508d0c37fSdholland 	lfs_dino_setctime(fs, dp, t);
63608d0c37fSdholland 	lfs_dino_setmtime(fs, dp, t);
63708d0c37fSdholland 	lfs_dino_setsize(fs, dp, lfs_sb_getfsize(fs));
63808d0c37fSdholland 	lfs_dino_setblocks(fs, dp, lfs_btofsb(fs, lfs_sb_getfsize(fs)));
639369e9cadSperseant 	n_files++;
640ba10361aSperseant 	inodirty(VTOI(vp));
641caf768dcSdholland 	typemap[ino] = LFS_IFTODT(type);
642369e9cadSperseant 	return (ino);
643369e9cadSperseant }
6444b8db838Sperseant 
645369e9cadSperseant /*
646369e9cadSperseant  * deallocate an inode
647369e9cadSperseant  */
648369e9cadSperseant void
freeino(ino_t ino)6491d259671Sperseant freeino(ino_t ino)
650369e9cadSperseant {
651369e9cadSperseant 	struct inodesc idesc;
652ba10361aSperseant 	struct uvnode *vp;
653369e9cadSperseant 
654369e9cadSperseant 	memset(&idesc, 0, sizeof(struct inodesc));
655369e9cadSperseant 	idesc.id_type = ADDR;
656369e9cadSperseant 	idesc.id_func = pass4check;
657369e9cadSperseant 	idesc.id_number = ino;
658ba10361aSperseant 	vp = vget(fs, ino);
659ba10361aSperseant 	(void) ckinode(VTOD(vp), &idesc);
66017d264b6Syamt 	clearinode(ino);
661369e9cadSperseant 	statemap[ino] = USTATE;
66217d264b6Syamt 	vnode_destroy(vp);
663e6c70652Sperseant 
664369e9cadSperseant 	n_files--;
665369e9cadSperseant }
666