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