xref: /netbsd-src/sbin/fsck_ffs/inode.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: inode.c,v 1.70 2013/12/02 18:46:52 bouyer Exp $	*/
2 
3 /*
4  * Copyright (c) 1980, 1986, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
36 #else
37 __RCSID("$NetBSD: inode.c,v 1.70 2013/12/02 18:46:52 bouyer Exp $");
38 #endif
39 #endif /* not lint */
40 
41 #include <sys/param.h>
42 #include <sys/time.h>
43 #include <sys/stat.h>
44 
45 #include <ufs/ufs/dinode.h>
46 #include <ufs/ufs/dir.h>
47 #include <ufs/ffs/fs.h>
48 #include <ufs/ffs/ffs_extern.h>
49 #include <ufs/ufs/ufs_bswap.h>
50 
51 #ifndef SMALL
52 #include <err.h>
53 #include <pwd.h>
54 #endif
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <time.h>
59 
60 #include "fsck.h"
61 #include "fsutil.h"
62 #include "extern.h"
63 
64 static ino_t startinum;
65 
66 static int iblock(struct inodesc *, long, u_int64_t);
67 static void swap_dinode1(union dinode *, int);
68 static void swap_dinode2(union dinode *, int);
69 
70 int
71 ckinode(union dinode *dp, struct inodesc *idesc)
72 {
73 	int ret, offset, i;
74 	union dinode dino;
75 	u_int64_t sizepb;
76 	int64_t remsize;
77 	daddr_t ndb;
78 	mode_t mode;
79 	char pathbuf[MAXPATHLEN + 1];
80 
81 	if (idesc->id_fix != IGNORE)
82 		idesc->id_fix = DONTKNOW;
83 	idesc->id_entryno = 0;
84 	idesc->id_filesize = iswap64(DIP(dp, size));
85 	mode = iswap16(DIP(dp, mode)) & IFMT;
86 	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
87 	    (idesc->id_filesize < sblock->fs_maxsymlinklen ||
88 	    (isappleufs && (idesc->id_filesize < APPLEUFS_MAXSYMLINKLEN)) ||
89 	     (sblock->fs_maxsymlinklen == 0 && DIP(dp, blocks) == 0))))
90 		return (KEEPON);
91 	if (is_ufs2)
92 		dino.dp2 = dp->dp2;
93 	else
94 		dino.dp1 = dp->dp1;
95 	ndb = howmany(iswap64(DIP(&dino, size)), sblock->fs_bsize);
96 	for (i = 0; i < UFS_NDADDR; i++) {
97 		if (--ndb == 0 &&
98 		    (offset = ffs_blkoff(sblock, iswap64(DIP(&dino, size)))) != 0)
99 			idesc->id_numfrags =
100 				ffs_numfrags(sblock, ffs_fragroundup(sblock, offset));
101 		else
102 			idesc->id_numfrags = sblock->fs_frag;
103 		if (DIP(&dino, db[i]) == 0) {
104 			if (idesc->id_type == DATA && ndb >= 0) {
105 				/* An empty block in a directory XXX */
106 				markclean = 0;
107 				getpathname(pathbuf, sizeof(pathbuf),
108 				    idesc->id_number, idesc->id_number);
109 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
110 				    pathbuf);
111 				if (reply("ADJUST LENGTH") == 1) {
112 					dp = ginode(idesc->id_number);
113 					DIP_SET(dp, size, iswap64(i *
114 					    sblock->fs_bsize));
115 					printf(
116 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
117 					rerun = 1;
118 					inodirty();
119 				}
120 			}
121 			continue;
122 		}
123 		if (is_ufs2)
124 			idesc->id_blkno = iswap64(dino.dp2.di_db[i]);
125 		else
126 			idesc->id_blkno = iswap32(dino.dp1.di_db[i]);
127 		if (idesc->id_type != DATA)
128 			ret = (*idesc->id_func)(idesc);
129 		else
130 			ret = dirscan(idesc);
131 		if (ret & STOP)
132 			return (ret);
133 	}
134 	idesc->id_numfrags = sblock->fs_frag;
135 	remsize = iswap64(DIP(&dino, size)) - sblock->fs_bsize * UFS_NDADDR;
136 	sizepb = sblock->fs_bsize;
137 	for (i = 0; i < UFS_NIADDR; i++) {
138 		if (DIP(&dino, ib[i])) {
139 			if (is_ufs2)
140 				idesc->id_blkno = iswap64(dino.dp2.di_ib[i]);
141 			else
142 				idesc->id_blkno = iswap32(dino.dp1.di_ib[i]);
143 			ret = iblock(idesc, i + 1, remsize);
144 			if (ret & STOP)
145 				return (ret);
146 		} else {
147 			if (idesc->id_type == DATA && remsize > 0) {
148 				/* An empty block in a directory XXX */
149 				markclean = 0;
150 				getpathname(pathbuf, sizeof(pathbuf),
151 				    idesc->id_number, idesc->id_number);
152 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
153 				    pathbuf);
154 				if (reply("ADJUST LENGTH") == 1) {
155 					dp = ginode(idesc->id_number);
156 					DIP_SET(dp, size,
157 					    iswap64(iswap64(DIP(dp, size))
158 						- remsize));
159 					remsize = 0;
160 					printf(
161 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
162 					rerun = 1;
163 					inodirty();
164 					break;
165 				}
166 			}
167 		}
168 		sizepb *= FFS_NINDIR(sblock);
169 		remsize -= sizepb;
170 	}
171 	return (KEEPON);
172 }
173 
174 static int
175 iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
176 {
177 	struct bufarea *bp;
178 	int i, n, (*func) (struct inodesc *), nif;
179 	u_int64_t sizepb;
180 	char buf[BUFSIZ];
181 	char pathbuf[MAXPATHLEN + 1];
182 	union dinode *dp;
183 
184 	if (idesc->id_type != DATA) {
185 		func = idesc->id_func;
186 		if (((n = (*func)(idesc)) & KEEPON) == 0)
187 			return (n);
188 	} else
189 		func = dirscan;
190 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
191 		return (SKIP);
192 	bp = getdatablk(idesc->id_blkno, sblock->fs_bsize);
193 	ilevel--;
194 	for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++)
195 		sizepb *= FFS_NINDIR(sblock);
196 	if (howmany(isize, sizepb) > (size_t)FFS_NINDIR(sblock))
197 		nif = FFS_NINDIR(sblock);
198 	else
199 		nif = howmany(isize, sizepb);
200 	if (do_blkswap) { /* swap byte order of the whole blk */
201 		if (is_ufs2) {
202 			for (i = 0; i < nif; i++)
203 				bp->b_un.b_indir2[i] =
204 				    bswap64(bp->b_un.b_indir2[i]);
205 		} else {
206 			for (i = 0; i < nif; i++)
207 				bp->b_un.b_indir1[i] =
208 				    bswap32(bp->b_un.b_indir1[i]);
209 		}
210 		dirty(bp);
211 		flush(fswritefd, bp);
212 	}
213 	if (idesc->id_func == pass1check && nif < FFS_NINDIR(sblock)) {
214 		for (i = nif; i < FFS_NINDIR(sblock); i++) {
215 			if (IBLK(bp, i) == 0)
216 				continue;
217 			(void)snprintf(buf, sizeof(buf),
218 			    "PARTIALLY TRUNCATED INODE I=%llu",
219 			    (unsigned long long)idesc->id_number);
220 			if (dofix(idesc, buf)) {
221 				IBLK_SET(bp, i, 0);
222 				dirty(bp);
223 			} else
224 				markclean = 0;
225 		}
226 		flush(fswritefd, bp);
227 	}
228 	for (i = 0; i < nif; i++) {
229 		if (IBLK(bp, i)) {
230 			if (is_ufs2)
231 				idesc->id_blkno = iswap64(bp->b_un.b_indir2[i]);
232 			else
233 				idesc->id_blkno = iswap32(bp->b_un.b_indir1[i]);
234 			if (ilevel == 0)
235 				n = (*func)(idesc);
236 			else
237 				n = iblock(idesc, ilevel, isize);
238 			if (n & STOP) {
239 				bp->b_flags &= ~B_INUSE;
240 				return (n);
241 			}
242 		} else {
243 			if (idesc->id_type == DATA && isize > 0) {
244 				/* An empty block in a directory XXX */
245 				markclean = 0;
246 				getpathname(pathbuf, sizeof(pathbuf),
247 				    idesc->id_number, idesc->id_number);
248 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
249 				    pathbuf);
250 				if (reply("ADJUST LENGTH") == 1) {
251 					dp = ginode(idesc->id_number);
252 					DIP_SET(dp, size,
253 					    iswap64(iswap64(DIP(dp, size))
254 						- isize));
255 					isize = 0;
256 					printf(
257 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
258 					rerun = 1;
259 					inodirty();
260 					bp->b_flags &= ~B_INUSE;
261 					return(STOP);
262 				}
263 			}
264 		}
265 		isize -= sizepb;
266 	}
267 	bp->b_flags &= ~B_INUSE;
268 	return (KEEPON);
269 }
270 
271 /*
272  * Check that a block in a legal block number.
273  * Return 0 if in range, 1 if out of range.
274  */
275 int
276 chkrange(daddr_t blk, int cnt)
277 {
278 	int c;
279 
280 	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
281 	    cnt - 1 > maxfsblock - blk)
282 		return (1);
283 	if (cnt > sblock->fs_frag ||
284 	    ffs_fragnum(sblock, blk) + cnt > sblock->fs_frag) {
285 		if (debug)
286 			printf("bad size: blk %lld, offset %d, size %d\n",
287 			    (long long)blk, (int)ffs_fragnum(sblock, blk), cnt);
288 	}
289 	c = dtog(sblock, blk);
290 	if (blk < cgdmin(sblock, c)) {
291 		if ((blk + cnt) > cgsblock(sblock, c)) {
292 			if (debug) {
293 				printf("blk %lld < cgdmin %lld;",
294 				    (long long)blk,
295 				    (long long)cgdmin(sblock, c));
296 				printf(" blk + cnt %lld > cgsbase %lld\n",
297 				    (long long)(blk + cnt),
298 				    (long long)cgsblock(sblock, c));
299 			}
300 			return (1);
301 		}
302 	} else {
303 		if ((blk + cnt) > cgbase(sblock, c+1)) {
304 			if (debug)  {
305 				printf("blk %lld >= cgdmin %lld;",
306 				    (long long)blk,
307 				    (long long)cgdmin(sblock, c));
308 				printf(" blk + cnt %lld > sblock->fs_fpg %d\n",
309 				    (long long)(blk+cnt), sblock->fs_fpg);
310 			}
311 			return (1);
312 		}
313 	}
314 	return (0);
315 }
316 
317 /*
318  * General purpose interface for reading inodes.
319  */
320 union dinode *
321 ginode(ino_t inumber)
322 {
323 	daddr_t iblk;
324 	int blkoff;
325 
326 	if (inumber < UFS_ROOTINO || inumber > maxino)
327 		errexit("bad inode number %llu to ginode",
328 		    (unsigned long long)inumber);
329 	if (startinum == 0 ||
330 	    inumber < startinum || inumber >= startinum + FFS_INOPB(sblock)) {
331 		iblk = ino_to_fsba(sblock, inumber);
332 		if (pbp != 0)
333 			pbp->b_flags &= ~B_INUSE;
334 		pbp = getdatablk(iblk, sblock->fs_bsize);
335 		startinum = (inumber / FFS_INOPB(sblock)) * FFS_INOPB(sblock);
336 	}
337 	if (is_ufs2) {
338 		blkoff = (inumber % FFS_INOPB(sblock)) * DINODE2_SIZE;
339 		return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff));
340 	}
341 	blkoff = (inumber % FFS_INOPB(sblock)) * DINODE1_SIZE;
342 	return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff));
343 }
344 
345 static void
346 swap_dinode1(union dinode *dp, int n)
347 {
348 	int i, j;
349 	struct ufs1_dinode *dp1;
350 	int32_t maxsymlinklen = sblock->fs_maxsymlinklen;
351 	if (isappleufs)
352 		maxsymlinklen = APPLEUFS_MAXSYMLINKLEN;
353 
354 	dp1 = (struct ufs1_dinode *)&dp->dp1;
355 	for (i = 0; i < n; i++, dp1++) {
356 		ffs_dinode1_swap(dp1, dp1);
357 		if (((iswap16(dp1->di_mode) & IFMT) != IFLNK) ||
358 		    doinglevel2 ||
359 		    (maxsymlinklen < 0) ||
360 		    (iswap64(dp1->di_size) > (uint64_t)maxsymlinklen)) {
361 			for (j = 0; j < (UFS_NDADDR + UFS_NIADDR); j++)
362 			    dp1->di_db[j] = bswap32(dp1->di_db[j]);
363 		}
364 	}
365 }
366 
367 static void
368 swap_dinode2(union dinode *dp, int n)
369 {
370 	int i, j;
371 	struct ufs2_dinode *dp2;
372 
373 	dp2 = (struct ufs2_dinode *)&dp->dp2;
374 	for (i = 0; i < n; i++, dp2++) {
375 		ffs_dinode2_swap(dp2, dp2);
376 		if ((iswap16(dp2->di_mode) & IFMT) != IFLNK) {
377 			for (j = 0; j < (UFS_NDADDR + UFS_NIADDR + UFS_NXADDR); j++)
378 				dp2->di_extb[j] = bswap64(dp2->di_extb[j]);
379 		}
380 	}
381 }
382 
383 /*
384  * Special purpose version of ginode used to optimize first pass
385  * over all the inodes in numerical order.
386  */
387 ino_t nextino, lastinum, lastvalidinum;
388 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
389 union dinode *inodebuf;
390 
391 union dinode *
392 getnextinode(ino_t inumber)
393 {
394 	long size;
395 	daddr_t dblk;
396 	static union dinode *dp;
397 	union dinode *ret;
398 
399 	if (inumber != nextino++ || inumber > lastvalidinum)
400 		errexit("bad inode number %llu to nextinode",
401 		    (unsigned long long)inumber);
402 
403 	if (inumber >= lastinum) {
404 		readcnt++;
405 		dblk = FFS_FSBTODB(sblock, ino_to_fsba(sblock, lastinum));
406 		if (readcnt % readpercg == 0) {
407 			size = partialsize;
408 			lastinum += partialcnt;
409 		} else {
410 			size = inobufsize;
411 			lastinum += fullcnt;
412 		}
413 		(void)bread(fsreadfd, (caddr_t)inodebuf, dblk, size);
414 		if (doswap) {
415 			if (is_ufs2)
416 				swap_dinode2(inodebuf, lastinum - inumber);
417 			else
418 				swap_dinode1(inodebuf, lastinum - inumber);
419 			bwrite(fswritefd, (char *)inodebuf, dblk, size);
420 		}
421 		dp = (union dinode *)inodebuf;
422 	}
423 	ret = dp;
424 	dp = (union dinode *)
425 	    ((char *)dp + (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE));
426 	return ret;
427 }
428 
429 void
430 setinodebuf(ino_t inum)
431 {
432 
433 	if (inum % sblock->fs_ipg != 0)
434 		errexit("bad inode number %llu to setinodebuf",
435 		    (unsigned long long)inum);
436 
437 	lastvalidinum = inum + sblock->fs_ipg - 1;
438 	startinum = 0;
439 	nextino = inum;
440 	lastinum = inum;
441 	readcnt = 0;
442 	if (inodebuf != NULL)
443 		return;
444 	inobufsize = ffs_blkroundup(sblock, INOBUFSIZE);
445 	fullcnt = inobufsize / (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE);
446 	readpercg = sblock->fs_ipg / fullcnt;
447 	partialcnt = sblock->fs_ipg % fullcnt;
448 	partialsize = partialcnt * (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE);
449 	if (partialcnt != 0) {
450 		readpercg++;
451 	} else {
452 		partialcnt = fullcnt;
453 		partialsize = inobufsize;
454 	}
455 	if (inodebuf == NULL &&
456 	    (inodebuf = malloc((unsigned)inobufsize)) == NULL)
457 		errexit("Cannot allocate space for inode buffer");
458 }
459 
460 void
461 freeinodebuf(void)
462 {
463 
464 	if (inodebuf != NULL)
465 		free((char *)inodebuf);
466 	inodebuf = NULL;
467 }
468 
469 /*
470  * Routines to maintain information about directory inodes.
471  * This is built during the first pass and used during the
472  * second and third passes.
473  *
474  * Enter inodes into the cache.
475  */
476 void
477 cacheino(union dinode *dp, ino_t inumber)
478 {
479 	struct inoinfo *inp;
480 	struct inoinfo **inpp, **ninpsort;
481 	unsigned int i, blks, extra;
482 	int64_t size;
483 
484 	size = iswap64(DIP(dp, size));
485 	blks = howmany(size, sblock->fs_bsize);
486 	if (blks > UFS_NDADDR)
487 		blks = UFS_NDADDR + UFS_NIADDR;
488 	if (blks > 0)
489 		extra = (blks - 1) * sizeof (int64_t);
490 	else
491 		extra = 0;
492 	inp = malloc(sizeof(*inp) + extra);
493 	if (inp == NULL)
494 		return;
495 	inpp = &inphead[inumber % dirhash];
496 	inp->i_nexthash = *inpp;
497 	*inpp = inp;
498 	inp->i_child = inp->i_sibling = 0;
499 	if (inumber == UFS_ROOTINO)
500 		inp->i_parent = UFS_ROOTINO;
501 	else
502 		inp->i_parent = (ino_t)0;
503 	inp->i_dotdot = (ino_t)0;
504 	inp->i_number = inumber;
505 	inp->i_isize = size;
506 	inp->i_numblks = blks;
507 	for (i = 0; i < (blks < UFS_NDADDR ? blks : UFS_NDADDR); i++)
508 		inp->i_blks[i] = DIP(dp, db[i]);
509 	if (blks > UFS_NDADDR)
510 		for (i = 0; i < UFS_NIADDR; i++)
511 			inp->i_blks[UFS_NDADDR + i] = DIP(dp, ib[i]);
512 	if (inplast == listmax) {
513 		ninpsort = (struct inoinfo **)realloc((char *)inpsort,
514 		    (unsigned)(listmax + 100) * sizeof(struct inoinfo *));
515 		if (inpsort == NULL)
516 			errexit("cannot increase directory list");
517 		inpsort = ninpsort;
518 		listmax += 100;
519 	}
520 	inpsort[inplast++] = inp;
521 }
522 
523 /*
524  * Look up an inode cache structure.
525  */
526 struct inoinfo *
527 getinoinfo(ino_t inumber)
528 {
529 	struct inoinfo *inp;
530 
531 	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
532 		if (inp->i_number != inumber)
533 			continue;
534 		return (inp);
535 	}
536 	errexit("cannot find inode %llu", (unsigned long long)inumber);
537 	return ((struct inoinfo *)0);
538 }
539 
540 /*
541  * Clean up all the inode cache structure.
542  */
543 void
544 inocleanup(void)
545 {
546 	struct inoinfo **inpp;
547 
548 	if (inphead == NULL)
549 		return;
550 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
551 		free((char *)(*inpp));
552 	free((char *)inphead);
553 	free((char *)inpsort);
554 	inphead = inpsort = NULL;
555 }
556 
557 void
558 inodirty(void)
559 {
560 
561 	dirty(pbp);
562 }
563 
564 void
565 clri(struct inodesc *idesc, const char *type, int flag)
566 {
567 	union dinode *dp;
568 
569 	dp = ginode(idesc->id_number);
570 	if (flag == 1) {
571 		pwarn("%s %s", type,
572 		    (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? "DIR" : "FILE");
573 		pinode(idesc->id_number);
574 	}
575 	if (preen || reply("CLEAR") == 1) {
576 		if (preen)
577 			printf(" (CLEARED)\n");
578 		n_files--;
579 		/*
580 		 * ckinode will call id_func (actually always pass4check)
581 		 * which will update the block count
582 		 */
583 		if (idesc->id_type != SNAP)
584 			update_uquot(idesc->id_number,
585 			    idesc->id_uid, idesc->id_gid, 0, -1);
586 		(void)ckinode(dp, idesc);
587 		clearinode(dp);
588 		inoinfo(idesc->id_number)->ino_state = USTATE;
589 		inodirty();
590 	} else
591 		markclean = 0;
592 }
593 
594 int
595 findname(struct inodesc *idesc)
596 {
597 	struct direct *dirp = idesc->id_dirp;
598 	size_t len;
599 	char *buf;
600 
601 	if (iswap32(dirp->d_ino) != idesc->id_parent || idesc->id_entryno < 2) {
602 		idesc->id_entryno++;
603 		return (KEEPON);
604 	}
605 	if ((len = dirp->d_namlen + 1) > MAXPATHLEN) {
606 		/* XXX: We don't fix but we ignore */
607 		len = MAXPATHLEN;
608 	}
609 	/* this is namebuf from utilities.c */
610 	buf = __UNCONST(idesc->id_name);
611 	(void)memcpy(buf, dirp->d_name, (size_t)dirp->d_namlen + 1);
612 	return (STOP|FOUND);
613 }
614 
615 int
616 findino(struct inodesc *idesc)
617 {
618 	struct direct *dirp = idesc->id_dirp;
619 
620 	if (dirp->d_ino == 0)
621 		return (KEEPON);
622 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
623 	    iswap32(dirp->d_ino) >= UFS_ROOTINO && iswap32(dirp->d_ino) <= maxino) {
624 		idesc->id_parent = iswap32(dirp->d_ino);
625 		return (STOP|FOUND);
626 	}
627 	return (KEEPON);
628 }
629 
630 int
631 clearentry(struct inodesc *idesc)
632 {
633 	struct direct *dirp = idesc->id_dirp;
634 
635 	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
636 		idesc->id_entryno++;
637 		return (KEEPON);
638 	}
639 	dirp->d_ino = 0;
640 	return (STOP|FOUND|ALTERED);
641 }
642 
643 void
644 pinode(ino_t ino)
645 {
646 	union dinode *dp;
647 	struct passwd *pw;
648 
649 	printf(" I=%llu ", (unsigned long long)ino);
650 	if (ino < UFS_ROOTINO || ino > maxino)
651 		return;
652 	dp = ginode(ino);
653 	printf(" OWNER=");
654 #ifndef SMALL
655 	if (Uflag && (pw = getpwuid((int)iswap32(DIP(dp, uid)))) != 0)
656 		printf("%s ", pw->pw_name);
657 	else
658 #endif
659 		printf("%u ", (unsigned)iswap32(DIP(dp, uid)));
660 	printf("MODE=%o\n", iswap16(DIP(dp, mode)));
661 	if (preen)
662 		printf("%s: ", cdevname());
663 	printf("SIZE=%llu ", (unsigned long long)iswap64(DIP(dp, size)));
664 	printf("MTIME=%s ", print_mtime(iswap32(DIP(dp, mtime))));
665 }
666 
667 void
668 blkerror(ino_t ino, const char *type, daddr_t blk)
669 {
670 	struct inostat *info;
671 
672 	pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino);
673 	printf("\n");
674 	info = inoinfo(ino);
675 	switch (info->ino_state) {
676 
677 	case FSTATE:
678 		info->ino_state = FCLEAR;
679 		return;
680 
681 	case DSTATE:
682 		info->ino_state = DCLEAR;
683 		return;
684 
685 	case FCLEAR:
686 	case DCLEAR:
687 		return;
688 
689 	default:
690 		errexit("BAD STATE %d TO BLKERR", info->ino_state);
691 		/* NOTREACHED */
692 	}
693 }
694 
695 /*
696  * allocate an unused inode
697  */
698 ino_t
699 allocino(ino_t request, int type)
700 {
701 	ino_t ino;
702 	union dinode *dp;
703 	struct ufs1_dinode *dp1;
704 	struct ufs2_dinode *dp2;
705 	time_t t;
706 	struct cg *cgp = cgrp;
707 	int cg;
708 	struct inostat *info = NULL;
709 	int nfrags;
710 
711 	if (request == 0)
712 		request = UFS_ROOTINO;
713 	else if (inoinfo(request)->ino_state != USTATE)
714 		return (0);
715 	for (ino = request; ino < maxino; ino++) {
716 		info = inoinfo(ino);
717 		if (info->ino_state == USTATE)
718 			break;
719 	}
720 	if (ino == maxino)
721 		return (0);
722 	cg = ino_to_cg(sblock, ino);
723 	/* If necessary, extend the inoinfo array. grow exponentially */
724 	if ((ino % sblock->fs_ipg) >= (uint64_t)inostathead[cg].il_numalloced) {
725 		unsigned long newalloced, i;
726 		newalloced = MIN(sblock->fs_ipg,
727 			MAX(2 * inostathead[cg].il_numalloced, 10));
728 		info = calloc(newalloced, sizeof(struct inostat));
729 		if (info == NULL) {
730 			pwarn("cannot alloc %lu bytes to extend inoinfo\n",
731 				sizeof(struct inostat) * newalloced);
732 			return 0;
733 		}
734 		memmove(info, inostathead[cg].il_stat,
735 			inostathead[cg].il_numalloced * sizeof(*info));
736 		for (i = inostathead[cg].il_numalloced; i < newalloced; i++) {
737 			info[i].ino_state = USTATE;
738 		}
739 		if (inostathead[cg].il_numalloced)
740 			free(inostathead[cg].il_stat);
741 		inostathead[cg].il_stat = info;
742 		inostathead[cg].il_numalloced = newalloced;
743 		info = inoinfo(ino);
744 	}
745 	getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize);
746 	memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize);
747 	if ((doswap && !needswap) || (!doswap && needswap))
748 		ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock);
749 	if (!cg_chkmagic(cgp, 0))
750 		pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg);
751 	if (doswap)
752 		cgdirty();
753 	setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg);
754 	cgp->cg_cs.cs_nifree--;
755 	sblock->fs_cstotal.cs_nifree--;
756 	sblock->fs_cs(fs, cg).cs_nifree--;
757 	sbdirty();
758 	switch (type & IFMT) {
759 	case IFDIR:
760 		info->ino_state = DSTATE;
761 		cgp->cg_cs.cs_ndir++;
762 		nfrags = 1;
763 		break;
764 	case IFREG:
765 		info->ino_state = FSTATE;
766 		nfrags = sblock->fs_frag;
767 		break;
768 	case IFLNK:
769 		info->ino_state = FSTATE;
770 		nfrags = 1;
771 		break;
772 	default:
773 		return (0);
774 	}
775 	cgdirty();
776 	dp = ginode(ino);
777 	if (is_ufs2) {
778 		dp2 = &dp->dp2;
779 		dp2->di_db[0] = iswap64(allocblk(nfrags));
780 		if (dp2->di_db[0] == 0) {
781 			info->ino_state = USTATE;
782 			return (0);
783 		}
784 		dp2->di_mode = iswap16(type);
785 		dp2->di_flags = 0;
786 		(void)time(&t);
787 		dp2->di_atime = iswap64(t);
788 		dp2->di_mtime = dp2->di_ctime = dp2->di_atime;
789 		dp2->di_size = iswap64(ffs_lfragtosize(sblock, nfrags));
790 		dp2->di_blocks = iswap64(btodb(ffs_lfragtosize(sblock, nfrags)));
791 	} else {
792 		dp1 = &dp->dp1;
793 		dp1->di_db[0] = iswap32(allocblk(nfrags));
794 		if (dp1->di_db[0] == 0) {
795 			info->ino_state = USTATE;
796 			return (0);
797 		}
798 		dp1->di_mode = iswap16(type);
799 		dp1->di_flags = 0;
800 		(void)time(&t);
801 		dp1->di_atime = iswap32(t);
802 		dp1->di_mtime = dp1->di_ctime = dp1->di_atime;
803 		dp1->di_size = iswap64(ffs_lfragtosize(sblock, nfrags));
804 		dp1->di_blocks = iswap32(btodb(ffs_lfragtosize(sblock, nfrags)));
805 	}
806 	n_files++;
807 	inodirty();
808 	if (newinofmt)
809 		info->ino_type = IFTODT(type);
810 	return (ino);
811 }
812 
813 /*
814  * deallocate an inode
815  */
816 void
817 freeino(ino_t ino)
818 {
819 	struct inodesc idesc;
820 	union dinode *dp;
821 	struct cg *cgp = cgrp;
822 	int cg;
823 
824 	cg = ino_to_cg(sblock, ino);
825 	getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize);
826 	memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize);
827 	if ((doswap && !needswap) || (!doswap && needswap))
828 		ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock);
829 	if (!cg_chkmagic(cgp, 0)) {
830 		pwarn("CG %d: FREEINO: BAD MAGIC NUMBER\n", cg);
831 		cgp = NULL;
832 	}
833 
834 	memset(&idesc, 0, sizeof(struct inodesc));
835 	idesc.id_func = pass4check;
836 	idesc.id_number = ino;
837 	dp = ginode(ino);
838 	idesc.id_uid = iswap32(DIP(dp, uid));
839 	idesc.id_gid = iswap32(DIP(dp, gid));
840 	if (iswap32(DIP(dp, flags)) & SF_SNAPSHOT)
841 		idesc.id_type = SNAP;
842 	else
843 		idesc.id_type = ADDR;
844 	(void)ckinode(dp, &idesc);
845 	clearinode(dp);
846 	inodirty();
847 	inoinfo(ino)->ino_state = USTATE;
848 	if (idesc.id_type != SNAP)
849 		update_uquot(idesc.id_number,
850 		    idesc.id_uid, idesc.id_gid, 0, -1);
851 	n_files--;
852 	if (cgp) {
853 		clrbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg);
854 		cgp->cg_cs.cs_nifree++;
855 		sblock->fs_cstotal.cs_nifree++;
856 		sblock->fs_cs(fs, cg).cs_nifree++;
857 		sbdirty();
858 		cgdirty();
859 	}
860 }
861 
862 /* read a data block from inode */
863 ssize_t
864 readblk(union dinode *dp, off_t offset, struct bufarea **bp)
865 {
866 	daddr_t blkno = ffs_lblkno(sblock, offset);
867 	daddr_t iblkno;
868 	int type = IFMT & iswap16(DIP(dp, mode));
869 	ssize_t filesize = iswap64(DIP(dp, size));
870 	int ilevel;
871 	daddr_t nblks;
872 	const daddr_t naddrperblk = sblock->fs_bsize /
873 	    (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t));
874 	struct bufarea *ibp;
875 
876 	*bp = NULL;
877 	offset &= ~(sblock->fs_bsize - 1);
878 
879 	if (type != IFREG)
880 		return 0;
881 	if (offset >= filesize)
882 		return 0; /* short read */
883 	if (blkno < UFS_NDADDR) {
884 		blkno = is_ufs2 ? iswap64(dp->dp2.di_db[blkno]) :
885 		    iswap32(dp->dp1.di_db[blkno]);
886 		if (blkno == 0)
887 			return 0;
888 		*bp = getdatablk(blkno, sblock->fs_bsize);
889 		return (bp != NULL) ? sblock->fs_bsize : 0;
890 	}
891 	blkno -= UFS_NDADDR;
892 	/* find indir level */
893 	for (ilevel = 1, nblks = naddrperblk;
894 	     ilevel <= UFS_NIADDR;
895 	     ilevel++, nblks *= naddrperblk) {
896 		if (blkno < nblks)
897 			break;
898 		else
899 			blkno -= nblks;
900 	}
901 	if (ilevel > UFS_NIADDR)
902 		errexit("bad ofsset %" PRIu64 " to readblk", offset);
903 
904 	/* get the first indirect block */
905 	iblkno = is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) :
906 		    iswap32(dp->dp1.di_ib[ilevel - 1]);
907 	if (iblkno == 0)
908 		return 0;
909 	ibp = getdatablk(iblkno, sblock->fs_bsize);
910 	/* walk indirect blocks up to the data block */
911 	for (; ilevel >0 ; ilevel--) {
912 		nblks = nblks / naddrperblk;
913 		if (is_ufs2)
914 			iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]);
915 		else
916 			iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]);
917 		if (iblkno == 0)
918 			return 0;
919 		blkno = blkno % nblks;
920 		ibp->b_flags &= ~B_INUSE;
921 		ibp = getdatablk(iblkno, sblock->fs_bsize);
922 	}
923 	*bp = ibp;
924 	return sblock->fs_bsize;
925 }
926 
927 static struct bufarea * getnewblk(daddr_t *);
928 static struct bufarea *
929 getnewblk(daddr_t *blkno)
930 {
931 	struct bufarea *bp;
932 	*blkno = allocblk(sblock->fs_frag);
933 	if (*blkno == 0)
934 		return NULL;
935 	bp = getdatablk(*blkno, sblock->fs_bsize);
936 	memset(bp->b_un.b_buf, 0, sblock->fs_bsize);
937 	return bp;
938 }
939 
940 /* expand given inode by one full fs block */
941 struct bufarea *
942 expandfile(union dinode *dp)
943 {
944 	uint64_t filesize = iswap64(DIP(dp, size));
945 	daddr_t newblk, blkno, iblkno, nblks;
946 	daddr_t di_blocks;
947 	int ilevel;
948 	const daddr_t naddrperblk = sblock->fs_bsize /
949 	    (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t));
950 	struct bufarea *ibp, *bp = NULL;
951 
952 	di_blocks = is_ufs2 ? iswap64(dp->dp2.di_blocks) :
953 	    iswap32(dp->dp1.di_blocks);
954 	/* compute location of new block */
955 	blkno = ffs_lblkno(sblock, filesize);
956 
957 	if (blkno < UFS_NDADDR) {
958 		/* easy way: allocate a direct block */
959 		if ((bp = getnewblk(&newblk)) == NULL) {
960 			return NULL;
961 		}
962 		di_blocks += btodb(sblock->fs_bsize);
963 
964 		if (is_ufs2) {
965 			dp->dp2.di_db[blkno] = iswap64(newblk);
966 		} else {
967 			dp->dp1.di_db[blkno] = iswap32(newblk);
968 		}
969 		goto out;
970 	}
971 	blkno -= UFS_NDADDR;
972 	/* find indir level */
973 	for (ilevel = 1, nblks = naddrperblk;
974 	     ilevel <= UFS_NIADDR;
975 	     ilevel++, nblks *= naddrperblk) {
976 		if (blkno < nblks)
977 			break;
978 		else
979 			blkno -= nblks;
980 	}
981 	if (ilevel > UFS_NIADDR)
982 		errexit("bad filesize %" PRIu64 " to expandfile", filesize);
983 
984 	/* get the first indirect block, allocating if needed */
985 	if ((is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) :
986 		iswap32(dp->dp1.di_ib[ilevel - 1])) == 0) {
987 		if ((ibp = getnewblk(&newblk)) == NULL)
988 			return 0;
989 		di_blocks += btodb(sblock->fs_bsize);
990 		if (is_ufs2)
991 			dp->dp2.di_ib[ilevel - 1] = iswap64(newblk);
992 		else
993 			dp->dp1.di_ib[ilevel - 1] = iswap32(newblk);
994 	} else {
995 		ibp = getdatablk(is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) :
996 		    iswap32(dp->dp1.di_ib[ilevel - 1]), sblock->fs_bsize);
997 	}
998 	/* walk indirect blocks up to the data block */
999 	for (; ilevel >0 ; ilevel--) {
1000 		nblks = nblks / naddrperblk;
1001 		if (is_ufs2)
1002 			iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]);
1003 		else
1004 			iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]);
1005 		if (iblkno == 0) {
1006 			if ((bp = getnewblk(&newblk)) == NULL)
1007 				return NULL;
1008 			di_blocks += btodb(sblock->fs_bsize);
1009 			if (is_ufs2)
1010 				ibp->b_un.b_indir2[blkno / nblks] =
1011 				    iswap64(newblk);
1012 			else
1013 				ibp->b_un.b_indir1[blkno / nblks] =
1014 				    iswap32(newblk);
1015 			dirty(ibp);
1016 			ibp->b_flags &= ~B_INUSE;
1017 			ibp = bp;
1018 		} else {
1019 			ibp->b_flags &= ~B_INUSE;
1020 			ibp = getdatablk(iblkno, sblock->fs_bsize);
1021 			bp = NULL;
1022 		}
1023 		blkno = blkno % nblks;
1024 	}
1025 	if (bp == NULL) {
1026 		errexit("INTERNAL ERROR: "
1027 		    "expandfile() failed to allocate a new block\n");
1028 	}
1029 
1030 out:
1031 	filesize += sblock->fs_bsize;
1032 	if (is_ufs2) {
1033 		dp->dp2.di_size = iswap64(filesize);
1034 		dp->dp2.di_blocks = iswap64(di_blocks);
1035 	} else {
1036 		dp->dp1.di_size = iswap64(filesize);
1037 		dp->dp1.di_blocks = iswap32(di_blocks);
1038 	}
1039 	inodirty();
1040 	return bp;
1041 }
1042