xref: /netbsd/sbin/fsck_lfs/inode.c (revision 251f7f59)
1*251f7f59Sperry /* $NetBSD: inode.c,v 1.25 2005/02/06 06:13:12 perry 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  * 3. All advertising materials mentioning features or use of this software
195aaab72dSperseant  *    must display the following acknowledgement:
205aaab72dSperseant  *      This product includes software developed by the NetBSD
215aaab72dSperseant  *      Foundation, Inc. and its contributors.
225aaab72dSperseant  * 4. Neither the name of The NetBSD Foundation nor the names of its
235aaab72dSperseant  *    contributors may be used to endorse or promote products derived
245aaab72dSperseant  *    from this software without specific prior written permission.
255aaab72dSperseant  *
265aaab72dSperseant  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
275aaab72dSperseant  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
285aaab72dSperseant  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
295aaab72dSperseant  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
305aaab72dSperseant  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
315aaab72dSperseant  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
325aaab72dSperseant  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
335aaab72dSperseant  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
345aaab72dSperseant  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
355aaab72dSperseant  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
365aaab72dSperseant  * POSSIBILITY OF SUCH DAMAGE.
375aaab72dSperseant  */
38276d62f6Sagc 
39276d62f6Sagc /*
40276d62f6Sagc  * Copyright (c) 1980, 1986, 1993
41276d62f6Sagc  *	The Regents of the University of California.  All rights reserved.
42276d62f6Sagc  *
43276d62f6Sagc  * Redistribution and use in source and binary forms, with or without
44276d62f6Sagc  * modification, are permitted provided that the following conditions
45276d62f6Sagc  * are met:
46276d62f6Sagc  * 1. Redistributions of source code must retain the above copyright
47276d62f6Sagc  *    notice, this list of conditions and the following disclaimer.
48276d62f6Sagc  * 2. Redistributions in binary form must reproduce the above copyright
49276d62f6Sagc  *    notice, this list of conditions and the following disclaimer in the
50276d62f6Sagc  *    documentation and/or other materials provided with the distribution.
51276d62f6Sagc  * 3. Neither the name of the University nor the names of its contributors
52276d62f6Sagc  *    may be used to endorse or promote products derived from this software
53276d62f6Sagc  *    without specific prior written permission.
54276d62f6Sagc  *
55276d62f6Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56276d62f6Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57276d62f6Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58276d62f6Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59276d62f6Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60276d62f6Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61276d62f6Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62276d62f6Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63276d62f6Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64276d62f6Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65276d62f6Sagc  * SUCH DAMAGE.
66276d62f6Sagc  */
67369e9cadSperseant 
68ba10361aSperseant #include <sys/types.h>
69369e9cadSperseant #include <sys/param.h>
70369e9cadSperseant #include <sys/time.h>
71ba10361aSperseant #include <sys/buf.h>
72ba10361aSperseant #include <sys/mount.h>
73ba10361aSperseant 
74ba10361aSperseant #include <ufs/ufs/inode.h>
75369e9cadSperseant #include <ufs/ufs/dir.h>
76ba10361aSperseant #define vnode uvnode
77369e9cadSperseant #include <ufs/lfs/lfs.h>
78ba10361aSperseant #undef vnode
79ba10361aSperseant 
80ba10361aSperseant #include <err.h>
81369e9cadSperseant #ifndef SMALL
82369e9cadSperseant #include <pwd.h>
83369e9cadSperseant #endif
84369e9cadSperseant #include <stdio.h>
85369e9cadSperseant #include <stdlib.h>
86369e9cadSperseant #include <string.h>
87369e9cadSperseant 
88ba10361aSperseant #include "bufcache.h"
89ba10361aSperseant #include "vnode.h"
90ba10361aSperseant #include "lfs.h"
91ba10361aSperseant 
92369e9cadSperseant #include "fsck.h"
93369e9cadSperseant #include "fsutil.h"
94369e9cadSperseant #include "extern.h"
95369e9cadSperseant 
96369e9cadSperseant extern SEGUSE *seg_table;
97ba10361aSperseant extern ufs_daddr_t *din_table;
98369e9cadSperseant 
991d259671Sperseant static int iblock(struct inodesc *, long, u_int64_t);
100369e9cadSperseant int blksreqd(struct lfs *, int);
101369e9cadSperseant int lfs_maxino(void);
102369e9cadSperseant 
103ba10361aSperseant /*
104ba10361aSperseant  * Get a dinode of a given inum.
105ba10361aSperseant  * XXX combine this function with vget.
106ba10361aSperseant  */
10742614ed3Sfvdl struct ufs1_dinode *
108ba10361aSperseant ginode(ino_t ino)
109369e9cadSperseant {
110ba10361aSperseant 	struct uvnode *vp;
111ba10361aSperseant 	struct ubuf *bp;
1124e3fced9Sperseant 	IFILE *ifp;
113369e9cadSperseant 
114ba10361aSperseant 	vp = vget(fs, ino);
115ba10361aSperseant 	if (vp == NULL)
116e6c70652Sperseant 		return NULL;
117e6c70652Sperseant 
118ba10361aSperseant 	if (din_table[ino] == 0x0) {
119ba10361aSperseant 		LFS_IENTRY(ifp, fs, ino, bp);
120ba10361aSperseant 		din_table[ino] = ifp->if_daddr;
12142614ed3Sfvdl 		seg_table[dtosn(fs, ifp->if_daddr)].su_nbytes += DINODE1_SIZE;
122ba10361aSperseant 		brelse(bp);
123e6c70652Sperseant 	}
12442614ed3Sfvdl 	return (VTOI(vp)->i_din.ffs1_din);
125369e9cadSperseant }
126369e9cadSperseant 
127369e9cadSperseant /*
128ba10361aSperseant  * Check validity of held blocks in an inode, recursing through all blocks.
129369e9cadSperseant  */
130369e9cadSperseant int
13142614ed3Sfvdl ckinode(struct ufs1_dinode *dp, struct inodesc *idesc)
132369e9cadSperseant {
133ba10361aSperseant 	ufs_daddr_t *ap, lbn;
134369e9cadSperseant 	long ret, n, ndb, offset;
13542614ed3Sfvdl 	struct ufs1_dinode dino;
136369e9cadSperseant 	u_int64_t remsize, sizepb;
137369e9cadSperseant 	mode_t mode;
138369e9cadSperseant 	char pathbuf[MAXPATHLEN + 1];
139ba10361aSperseant 	struct uvnode *vp, *thisvp;
140369e9cadSperseant 
141369e9cadSperseant 	if (idesc->id_fix != IGNORE)
142369e9cadSperseant 		idesc->id_fix = DONTKNOW;
143369e9cadSperseant 	idesc->id_entryno = 0;
144369e9cadSperseant 	idesc->id_filesize = dp->di_size;
145369e9cadSperseant 	mode = dp->di_mode & IFMT;
1461d259671Sperseant 	if (mode == IFBLK || mode == IFCHR ||
147ba10361aSperseant 	    (mode == IFLNK && (dp->di_size < fs->lfs_maxsymlinklen ||
148ba10361aSperseant 		    (fs->lfs_maxsymlinklen == 0 &&
1491d259671Sperseant 			dp->di_blocks == 0))))
150369e9cadSperseant 		return (KEEPON);
151369e9cadSperseant 	dino = *dp;
152ba10361aSperseant 	ndb = howmany(dino.di_size, fs->lfs_bsize);
153369e9cadSperseant 
154884f970fSyamt 	thisvp = vget(fs, idesc->id_number);
155ba10361aSperseant 	for (lbn = 0; lbn < NDADDR; lbn++) {
156ba10361aSperseant 		ap = dino.di_db + lbn;
157ba10361aSperseant 		if (thisvp)
158369e9cadSperseant 			idesc->id_numfrags =
159ba10361aSperseant 				numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]);
160ba10361aSperseant 		else {
161ba10361aSperseant 			if (--ndb == 0 && (offset = blkoff(fs, dino.di_size)) != 0) {
162ba10361aSperseant 				idesc->id_numfrags =
163ba10361aSperseant 			    	numfrags(fs, fragroundup(fs, offset));
164369e9cadSperseant 			} else
165ba10361aSperseant 				idesc->id_numfrags = fs->lfs_frag;
166ba10361aSperseant 		}
167369e9cadSperseant 		if (*ap == 0) {
168369e9cadSperseant 			if (idesc->id_type == DATA && ndb >= 0) {
169369e9cadSperseant 				/* An empty block in a directory XXX */
1708883e1fbSitojun 				getpathname(pathbuf, sizeof(pathbuf),
1718883e1fbSitojun 				    idesc->id_number, idesc->id_number);
172369e9cadSperseant 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
173369e9cadSperseant 				    pathbuf);
174369e9cadSperseant 				if (reply("ADJUST LENGTH") == 1) {
175ba10361aSperseant 					vp = vget(fs, idesc->id_number);
176ba10361aSperseant 					dp = VTOD(vp);
177369e9cadSperseant 					dp->di_size = (ap - &dino.di_db[0]) *
178ba10361aSperseant 					    fs->lfs_bsize;
179369e9cadSperseant 					printf(
180369e9cadSperseant 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
181369e9cadSperseant 					rerun = 1;
182ba10361aSperseant 					inodirty(VTOI(vp));
183369e9cadSperseant 				}
184369e9cadSperseant 			}
185369e9cadSperseant 			continue;
186369e9cadSperseant 		}
187369e9cadSperseant 		idesc->id_blkno = *ap;
188369e9cadSperseant 		idesc->id_lblkno = ap - &dino.di_db[0];
189369e9cadSperseant 		if (idesc->id_type == ADDR) {
190369e9cadSperseant 			ret = (*idesc->id_func) (idesc);
1911d259671Sperseant 		} else
192369e9cadSperseant 			ret = dirscan(idesc);
193369e9cadSperseant 		if (ret & STOP)
194369e9cadSperseant 			return (ret);
195369e9cadSperseant 	}
196ba10361aSperseant 	idesc->id_numfrags = fs->lfs_frag;
197ba10361aSperseant 	remsize = dino.di_size - fs->lfs_bsize * NDADDR;
198ba10361aSperseant 	sizepb = fs->lfs_bsize;
199369e9cadSperseant 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
200369e9cadSperseant 		if (*ap) {
201369e9cadSperseant 			idesc->id_blkno = *ap;
202369e9cadSperseant 			ret = iblock(idesc, n, remsize);
203369e9cadSperseant 			if (ret & STOP)
204369e9cadSperseant 				return (ret);
205369e9cadSperseant 		} else {
206369e9cadSperseant 			if (idesc->id_type == DATA && remsize > 0) {
207369e9cadSperseant 				/* An empty block in a directory XXX */
2088883e1fbSitojun 				getpathname(pathbuf, sizeof(pathbuf),
2098883e1fbSitojun 				    idesc->id_number, idesc->id_number);
210369e9cadSperseant 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
211369e9cadSperseant 				    pathbuf);
212369e9cadSperseant 				if (reply("ADJUST LENGTH") == 1) {
213ba10361aSperseant 					vp = vget(fs, idesc->id_number);
214ba10361aSperseant 					dp = VTOD(vp);
215369e9cadSperseant 					dp->di_size -= remsize;
216369e9cadSperseant 					remsize = 0;
217369e9cadSperseant 					printf(
218369e9cadSperseant 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
219369e9cadSperseant 					rerun = 1;
220ba10361aSperseant 					inodirty(VTOI(vp));
221369e9cadSperseant 					break;
222369e9cadSperseant 				}
223369e9cadSperseant 			}
224369e9cadSperseant 		}
225ba10361aSperseant 		sizepb *= NINDIR(fs);
226369e9cadSperseant 		remsize -= sizepb;
227369e9cadSperseant 	}
228369e9cadSperseant 	return (KEEPON);
229369e9cadSperseant }
230369e9cadSperseant 
231369e9cadSperseant static int
2321d259671Sperseant iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
233369e9cadSperseant {
234ba10361aSperseant 	ufs_daddr_t *ap, *aplim;
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;
249ba10361aSperseant 	if (chkrange(idesc->id_blkno, fragstofsb(fs, idesc->id_numfrags)))
250369e9cadSperseant 		return (SKIP);
251ba10361aSperseant 
252ba10361aSperseant 	devvp = fs->lfs_unlockvp;
253ba10361aSperseant 	bread(devvp, fsbtodb(fs, idesc->id_blkno), fs->lfs_bsize, NOCRED, &bp);
254369e9cadSperseant 	ilevel--;
255ba10361aSperseant 	for (sizepb = fs->lfs_bsize, i = 0; i < ilevel; i++)
256ba10361aSperseant 		sizepb *= NINDIR(fs);
257ba10361aSperseant 	if (isize > sizepb * NINDIR(fs))
258ba10361aSperseant 		nif = NINDIR(fs);
259369e9cadSperseant 	else
260369e9cadSperseant 		nif = howmany(isize, sizepb);
261ba10361aSperseant 	if (idesc->id_func == pass1check && nif < NINDIR(fs)) {
262ba10361aSperseant 		aplim = ((ufs_daddr_t *) bp->b_data) + NINDIR(fs);
263ba10361aSperseant 		for (ap = ((ufs_daddr_t *) bp->b_data) + nif; ap < aplim; ap++) {
264369e9cadSperseant 			if (*ap == 0)
265369e9cadSperseant 				continue;
266369e9cadSperseant 			(void) sprintf(buf, "PARTIALLY TRUNCATED INODE I=%u",
267369e9cadSperseant 			    idesc->id_number);
268369e9cadSperseant 			if (dofix(idesc, buf)) {
269369e9cadSperseant 				*ap = 0;
270ba10361aSperseant 				++diddirty;
271369e9cadSperseant 			}
272369e9cadSperseant 		}
273369e9cadSperseant 	}
274ba10361aSperseant 	aplim = ((ufs_daddr_t *) bp->b_data) + nif;
275ba10361aSperseant 	for (ap = ((ufs_daddr_t *) bp->b_data); ap < aplim; ap++) {
276369e9cadSperseant 		if (*ap) {
277369e9cadSperseant 			idesc->id_blkno = *ap;
2786e547a61Syamt 			if (ilevel == 0) {
2796e547a61Syamt 				/*
2806e547a61Syamt 				 * dirscan needs lblkno.
2816e547a61Syamt 				 */
2826e547a61Syamt 				idesc->id_lblkno++;
283369e9cadSperseant 				n = (*func) (idesc);
2846e547a61Syamt 			} else {
285369e9cadSperseant 				n = iblock(idesc, ilevel, isize);
2866e547a61Syamt 			}
287369e9cadSperseant 			if (n & STOP) {
288ba10361aSperseant 				if (diddirty)
289ba10361aSperseant 					VOP_BWRITE(bp);
290ba10361aSperseant 				else
291ba10361aSperseant 					brelse(bp);
292369e9cadSperseant 				return (n);
293369e9cadSperseant 			}
294369e9cadSperseant 		} else {
295369e9cadSperseant 			if (idesc->id_type == DATA && isize > 0) {
296369e9cadSperseant 				/* An empty block in a directory XXX */
2978883e1fbSitojun 				getpathname(pathbuf, sizeof(pathbuf),
2988883e1fbSitojun 				    idesc->id_number, idesc->id_number);
299369e9cadSperseant 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
300369e9cadSperseant 				    pathbuf);
301369e9cadSperseant 				if (reply("ADJUST LENGTH") == 1) {
302ba10361aSperseant 					vp = vget(fs, idesc->id_number);
30342614ed3Sfvdl 					VTOI(vp)->i_ffs1_size -= isize;
304369e9cadSperseant 					isize = 0;
305369e9cadSperseant 					printf(
306369e9cadSperseant 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
307369e9cadSperseant 					rerun = 1;
308ba10361aSperseant 					inodirty(VTOI(vp));
309ba10361aSperseant 					if (diddirty)
310ba10361aSperseant 						VOP_BWRITE(bp);
311ba10361aSperseant 					else
312ba10361aSperseant 						brelse(bp);
313369e9cadSperseant 					return (STOP);
314369e9cadSperseant 				}
315369e9cadSperseant 			}
316369e9cadSperseant 		}
317369e9cadSperseant 		isize -= sizepb;
318369e9cadSperseant 	}
319ba10361aSperseant 	if (diddirty)
320ba10361aSperseant 		VOP_BWRITE(bp);
321ba10361aSperseant 	else
322ba10361aSperseant 		brelse(bp);
323369e9cadSperseant 	return (KEEPON);
324369e9cadSperseant }
325369e9cadSperseant /*
326369e9cadSperseant  * Check that a block in a legal block number.
327369e9cadSperseant  * Return 0 if in range, 1 if out of range.
328369e9cadSperseant  */
329369e9cadSperseant int
3301d259671Sperseant chkrange(daddr_t blk, int cnt)
331369e9cadSperseant {
332ba10361aSperseant 	if (blk < sntod(fs, 0)) {
33375453f28Sperseant 		return (1);
33475453f28Sperseant 	}
3354e3fced9Sperseant 	if (blk > maxfsblock) {
3364e3fced9Sperseant 		return (1);
3374e3fced9Sperseant 	}
338ba10361aSperseant 	if (blk + cnt < sntod(fs, 0)) {
3394e3fced9Sperseant 		return (1);
3404e3fced9Sperseant 	}
3414e3fced9Sperseant 	if (blk + cnt > maxfsblock) {
342369e9cadSperseant 		return (1);
343369e9cadSperseant 	}
344369e9cadSperseant 	return (0);
345369e9cadSperseant }
346369e9cadSperseant /*
347369e9cadSperseant  * Routines to maintain information about directory inodes.
348369e9cadSperseant  * This is built during the first pass and used during the
349369e9cadSperseant  * second and third passes.
350369e9cadSperseant  *
351369e9cadSperseant  * Enter inodes into the cache.
352369e9cadSperseant  */
353369e9cadSperseant void
35442614ed3Sfvdl cacheino(struct ufs1_dinode * dp, ino_t inumber)
355369e9cadSperseant {
356ba10361aSperseant 	struct inoinfo *inp;
3576379e111Sitojun 	struct inoinfo **inpp, **ninpsort;
358369e9cadSperseant 	unsigned int blks;
359369e9cadSperseant 
360ba10361aSperseant 	blks = howmany(dp->di_size, fs->lfs_bsize);
361369e9cadSperseant 	if (blks > NDADDR)
362369e9cadSperseant 		blks = NDADDR + NIADDR;
363369e9cadSperseant 	inp = (struct inoinfo *)
364ba10361aSperseant 	    malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
365369e9cadSperseant 	if (inp == NULL)
366369e9cadSperseant 		return;
367369e9cadSperseant 	inpp = &inphead[inumber % numdirs];
368369e9cadSperseant 	inp->i_nexthash = *inpp;
369369e9cadSperseant 	*inpp = inp;
370369e9cadSperseant 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
371369e9cadSperseant 	if (inumber == ROOTINO)
372369e9cadSperseant 		inp->i_parent = ROOTINO;
373369e9cadSperseant 	else
374369e9cadSperseant 		inp->i_parent = (ino_t) 0;
375369e9cadSperseant 	inp->i_dotdot = (ino_t) 0;
376369e9cadSperseant 	inp->i_number = inumber;
377369e9cadSperseant 	inp->i_isize = dp->di_size;
378ba10361aSperseant 
379ba10361aSperseant 	inp->i_numblks = blks * sizeof(ufs_daddr_t);
380369e9cadSperseant 	memcpy(&inp->i_blks[0], &dp->di_db[0], (size_t) inp->i_numblks);
381369e9cadSperseant 	if (inplast == listmax) {
3826379e111Sitojun 		ninpsort = (struct inoinfo **) realloc((char *) inpsort,
3836379e111Sitojun 		    (unsigned) (listmax + 100) * sizeof(struct inoinfo *));
3846379e111Sitojun 		if (ninpsort == NULL)
385ba10361aSperseant 			err(8, "cannot increase directory list\n");
3866379e111Sitojun 		inpsort = ninpsort;
3876379e111Sitojun 		listmax += 100;
388369e9cadSperseant 	}
389369e9cadSperseant 	inpsort[inplast++] = inp;
390369e9cadSperseant }
391369e9cadSperseant 
392369e9cadSperseant /*
393369e9cadSperseant  * Look up an inode cache structure.
394369e9cadSperseant  */
395369e9cadSperseant struct inoinfo *
3961d259671Sperseant getinoinfo(ino_t inumber)
397369e9cadSperseant {
398*251f7f59Sperry 	struct inoinfo *inp;
399369e9cadSperseant 
400369e9cadSperseant 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
401369e9cadSperseant 		if (inp->i_number != inumber)
402369e9cadSperseant 			continue;
403369e9cadSperseant 		return (inp);
404369e9cadSperseant 	}
405ba10361aSperseant 	err(8, "cannot find inode %d\n", inumber);
406369e9cadSperseant 	return ((struct inoinfo *) 0);
407369e9cadSperseant }
408369e9cadSperseant 
409369e9cadSperseant /*
410369e9cadSperseant  * Clean up all the inode cache structure.
411369e9cadSperseant  */
412369e9cadSperseant void
413*251f7f59Sperry inocleanup(void)
414369e9cadSperseant {
415*251f7f59Sperry 	struct inoinfo **inpp;
416369e9cadSperseant 
417369e9cadSperseant 	if (inphead == NULL)
418369e9cadSperseant 		return;
419369e9cadSperseant 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
420369e9cadSperseant 		free((char *) (*inpp));
421369e9cadSperseant 	free((char *) inphead);
422369e9cadSperseant 	free((char *) inpsort);
423369e9cadSperseant 	inphead = inpsort = NULL;
424369e9cadSperseant }
425369e9cadSperseant 
426369e9cadSperseant void
427ba10361aSperseant inodirty(struct inode *ip)
428369e9cadSperseant {
429ba10361aSperseant 	ip->i_flag |= IN_MODIFIED;
430369e9cadSperseant }
431369e9cadSperseant 
432369e9cadSperseant void
4331d259671Sperseant clri(struct inodesc * idesc, char *type, int flag)
434369e9cadSperseant {
435ba10361aSperseant 	struct uvnode *vp;
436369e9cadSperseant 
437ba10361aSperseant 	vp = vget(fs, idesc->id_number);
438369e9cadSperseant 	if (flag == 1) {
439369e9cadSperseant 		pwarn("%s %s", type,
44042614ed3Sfvdl 		      (VTOI(vp)->i_ffs1_mode & IFMT) == IFDIR ? "DIR" : "FILE");
441369e9cadSperseant 		pinode(idesc->id_number);
442369e9cadSperseant 	}
443ba10361aSperseant 	if (flag == 2 || preen || reply("CLEAR") == 1) {
444ba10361aSperseant 		if (preen && flag != 2)
445369e9cadSperseant 			printf(" (CLEARED)\n");
446369e9cadSperseant 		n_files--;
447ba10361aSperseant 		(void) ckinode(VTOD(vp), idesc);
44817d264b6Syamt 		clearinode(idesc->id_number);
449369e9cadSperseant 		statemap[idesc->id_number] = USTATE;
45017d264b6Syamt 		vnode_destroy(vp);
45117d264b6Syamt 	}
45217d264b6Syamt }
45317d264b6Syamt 
45417d264b6Syamt void
45517d264b6Syamt clearinode(ino_t inumber)
45617d264b6Syamt {
45717d264b6Syamt 	struct ubuf *bp;
45817d264b6Syamt 	IFILE *ifp;
45917d264b6Syamt 	daddr_t daddr;
460e6c70652Sperseant 
461e6c70652Sperseant 	/* Send cleared inode to the free list */
462e6c70652Sperseant 
46317d264b6Syamt 	LFS_IENTRY(ifp, fs, inumber, bp);
46417d264b6Syamt 	daddr = ifp->if_daddr;
465e6c70652Sperseant 	ifp->if_daddr = LFS_UNUSED_DADDR;
466ba10361aSperseant 	ifp->if_nextfree = fs->lfs_freehd;
46717d264b6Syamt 	fs->lfs_freehd = inumber;
468e6c70652Sperseant 	sbdirty();
469ba10361aSperseant 	VOP_BWRITE(bp);
47017d264b6Syamt 
47117d264b6Syamt 	/*
47217d264b6Syamt 	 * update segment usage.
47317d264b6Syamt 	 */
47417d264b6Syamt 	if (daddr != LFS_UNUSED_DADDR) {
47517d264b6Syamt 		SEGUSE *sup;
47617d264b6Syamt 		u_int32_t oldsn = dtosn(fs, daddr);
47717d264b6Syamt 
47817d264b6Syamt 		LFS_SEGENTRY(sup, fs, oldsn, bp);
47917d264b6Syamt 		sup->su_nbytes -= DINODE1_SIZE;
48017d264b6Syamt 		LFS_WRITESEGENTRY(sup, fs, oldsn, bp);	/* Ifile */
481369e9cadSperseant 	}
482369e9cadSperseant }
483369e9cadSperseant 
484369e9cadSperseant int
4851d259671Sperseant findname(struct inodesc * idesc)
486369e9cadSperseant {
487*251f7f59Sperry 	struct direct *dirp = idesc->id_dirp;
488369e9cadSperseant 
489369e9cadSperseant 	if (dirp->d_ino != idesc->id_parent)
490369e9cadSperseant 		return (KEEPON);
491369e9cadSperseant 	memcpy(idesc->id_name, dirp->d_name, (size_t) dirp->d_namlen + 1);
492369e9cadSperseant 	return (STOP | FOUND);
493369e9cadSperseant }
494369e9cadSperseant 
495369e9cadSperseant int
4961d259671Sperseant findino(struct inodesc * idesc)
497369e9cadSperseant {
498*251f7f59Sperry 	struct direct *dirp = idesc->id_dirp;
499369e9cadSperseant 
500369e9cadSperseant 	if (dirp->d_ino == 0)
501369e9cadSperseant 		return (KEEPON);
502369e9cadSperseant 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
50375453f28Sperseant 	    dirp->d_ino >= ROOTINO && dirp->d_ino < maxino) {
504369e9cadSperseant 		idesc->id_parent = dirp->d_ino;
505369e9cadSperseant 		return (STOP | FOUND);
506369e9cadSperseant 	}
507369e9cadSperseant 	return (KEEPON);
508369e9cadSperseant }
509369e9cadSperseant 
510369e9cadSperseant void
5111d259671Sperseant pinode(ino_t ino)
512369e9cadSperseant {
513*251f7f59Sperry 	struct ufs1_dinode *dp;
514*251f7f59Sperry 	char *p;
515369e9cadSperseant 	struct passwd *pw;
516369e9cadSperseant 	time_t t;
517369e9cadSperseant 
518369e9cadSperseant 	printf(" I=%u ", ino);
51975453f28Sperseant 	if (ino < ROOTINO || ino >= maxino)
520369e9cadSperseant 		return;
521369e9cadSperseant 	dp = ginode(ino);
522369e9cadSperseant 	if (dp) {
523369e9cadSperseant 		printf(" OWNER=");
524369e9cadSperseant #ifndef SMALL
525369e9cadSperseant 		if ((pw = getpwuid((int) dp->di_uid)) != 0)
526369e9cadSperseant 			printf("%s ", pw->pw_name);
527369e9cadSperseant 		else
528369e9cadSperseant #endif
529369e9cadSperseant 			printf("%u ", (unsigned) dp->di_uid);
530369e9cadSperseant 		printf("MODE=%o\n", dp->di_mode);
531369e9cadSperseant 		if (preen)
532369e9cadSperseant 			printf("%s: ", cdevname());
533f7650338Slukem 		printf("SIZE=%llu ", (unsigned long long) dp->di_size);
534369e9cadSperseant 		t = dp->di_mtime;
535369e9cadSperseant 		p = ctime(&t);
536369e9cadSperseant 		printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
537369e9cadSperseant 	}
538369e9cadSperseant }
539369e9cadSperseant 
540369e9cadSperseant void
5411d259671Sperseant blkerror(ino_t ino, char *type, daddr_t blk)
542369e9cadSperseant {
543369e9cadSperseant 
544a3ff3a30Sfvdl 	pfatal("%lld %s I=%u", (long long) blk, type, ino);
545369e9cadSperseant 	printf("\n");
546369e9cadSperseant 	if (exitonfail)
547369e9cadSperseant 		exit(1);
548369e9cadSperseant 	switch (statemap[ino]) {
549369e9cadSperseant 
550369e9cadSperseant 	case FSTATE:
551369e9cadSperseant 		statemap[ino] = FCLEAR;
552369e9cadSperseant 		return;
553369e9cadSperseant 
554369e9cadSperseant 	case DSTATE:
555369e9cadSperseant 		statemap[ino] = DCLEAR;
556369e9cadSperseant 		return;
557369e9cadSperseant 
558369e9cadSperseant 	case FCLEAR:
559369e9cadSperseant 	case DCLEAR:
560369e9cadSperseant 		return;
561369e9cadSperseant 
562369e9cadSperseant 	default:
563ba10361aSperseant 		err(8, "BAD STATE %d TO BLKERR\n", statemap[ino]);
564369e9cadSperseant 		/* NOTREACHED */
565369e9cadSperseant 	}
566369e9cadSperseant }
567369e9cadSperseant /*
568369e9cadSperseant  * allocate an unused inode
569369e9cadSperseant  */
570369e9cadSperseant ino_t
5711d259671Sperseant allocino(ino_t request, int type)
572369e9cadSperseant {
573ba10361aSperseant 	ino_t ino;
57442614ed3Sfvdl 	struct ufs1_dinode *dp;
575369e9cadSperseant 	time_t t;
576ba10361aSperseant 	struct uvnode *vp;
577ba10361aSperseant 	struct ubuf *bp;
578369e9cadSperseant 
579369e9cadSperseant 	if (request == 0)
580369e9cadSperseant 		request = ROOTINO;
581369e9cadSperseant 	else if (statemap[request] != USTATE)
582369e9cadSperseant 		return (0);
583369e9cadSperseant 	for (ino = request; ino < maxino; ino++)
584369e9cadSperseant 		if (statemap[ino] == USTATE)
585369e9cadSperseant 			break;
586369e9cadSperseant 	if (ino == maxino)
587369e9cadSperseant 		return (0);
588369e9cadSperseant 	switch (type & IFMT) {
589369e9cadSperseant 	case IFDIR:
590369e9cadSperseant 		statemap[ino] = DSTATE;
591369e9cadSperseant 		break;
592369e9cadSperseant 	case IFREG:
593369e9cadSperseant 	case IFLNK:
594369e9cadSperseant 		statemap[ino] = FSTATE;
595369e9cadSperseant 		break;
596369e9cadSperseant 	default:
597369e9cadSperseant 		return (0);
598369e9cadSperseant 	}
599ba10361aSperseant 	vp = vget(fs, ino);
60042614ed3Sfvdl 	dp = (VTOI(vp)->i_din.ffs1_din);
601ba10361aSperseant 	bp = getblk(vp, 0, fs->lfs_fsize);
602ba10361aSperseant 	VOP_BWRITE(bp);
603369e9cadSperseant 	dp->di_mode = type;
604369e9cadSperseant 	(void) time(&t);
605369e9cadSperseant 	dp->di_atime = t;
606369e9cadSperseant 	dp->di_mtime = dp->di_ctime = dp->di_atime;
607ba10361aSperseant 	dp->di_size = fs->lfs_fsize;
608ba10361aSperseant 	dp->di_blocks = btofsb(fs, fs->lfs_fsize);
609369e9cadSperseant 	n_files++;
610ba10361aSperseant 	inodirty(VTOI(vp));
611369e9cadSperseant 	typemap[ino] = IFTODT(type);
612369e9cadSperseant 	return (ino);
613369e9cadSperseant }
614369e9cadSperseant /*
615369e9cadSperseant  * deallocate an inode
616369e9cadSperseant  */
617369e9cadSperseant void
6181d259671Sperseant freeino(ino_t ino)
619369e9cadSperseant {
620369e9cadSperseant 	struct inodesc idesc;
621ba10361aSperseant 	struct uvnode *vp;
622369e9cadSperseant 
623369e9cadSperseant 	memset(&idesc, 0, sizeof(struct inodesc));
624369e9cadSperseant 	idesc.id_type = ADDR;
625369e9cadSperseant 	idesc.id_func = pass4check;
626369e9cadSperseant 	idesc.id_number = ino;
627ba10361aSperseant 	vp = vget(fs, ino);
628ba10361aSperseant 	(void) ckinode(VTOD(vp), &idesc);
62917d264b6Syamt 	clearinode(ino);
630369e9cadSperseant 	statemap[ino] = USTATE;
63117d264b6Syamt 	vnode_destroy(vp);
632e6c70652Sperseant 
633369e9cadSperseant 	n_files--;
634369e9cadSperseant }
635