xref: /freebsd/sbin/fsck_ffs/inode.c (revision 74ca7bf1d4c7173d5575ba168bc4b5f6d181ff5a)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
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 #if 0
33 #ifndef lint
34 static const char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
35 #endif /* not lint */
36 #endif
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 #include <sys/param.h>
41 #include <sys/stdint.h>
42 #include <sys/sysctl.h>
43 
44 #include <ufs/ufs/dinode.h>
45 #include <ufs/ufs/dir.h>
46 #include <ufs/ffs/fs.h>
47 
48 #include <err.h>
49 #include <pwd.h>
50 #include <string.h>
51 #include <time.h>
52 
53 #include "fsck.h"
54 
55 static ino_t startinum;
56 
57 static int iblock(struct inodesc *, long ilevel, off_t isize, int type);
58 
59 int
60 ckinode(union dinode *dp, struct inodesc *idesc)
61 {
62 	off_t remsize, sizepb;
63 	int i, offset, ret;
64 	union dinode dino;
65 	ufs2_daddr_t ndb;
66 	mode_t mode;
67 	char pathbuf[MAXPATHLEN + 1];
68 
69 	if (idesc->id_fix != IGNORE)
70 		idesc->id_fix = DONTKNOW;
71 	idesc->id_lbn = -1;
72 	idesc->id_entryno = 0;
73 	idesc->id_filesize = DIP(dp, di_size);
74 	mode = DIP(dp, di_mode) & IFMT;
75 	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
76 	    DIP(dp, di_size) < (unsigned)sblock.fs_maxsymlinklen))
77 		return (KEEPON);
78 	if (sblock.fs_magic == FS_UFS1_MAGIC)
79 		dino.dp1 = dp->dp1;
80 	else
81 		dino.dp2 = dp->dp2;
82 	ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize);
83 	for (i = 0; i < UFS_NDADDR; i++) {
84 		idesc->id_lbn++;
85 		if (--ndb == 0 &&
86 		    (offset = blkoff(&sblock, DIP(&dino, di_size))) != 0)
87 			idesc->id_numfrags =
88 				numfrags(&sblock, fragroundup(&sblock, offset));
89 		else
90 			idesc->id_numfrags = sblock.fs_frag;
91 		if (DIP(&dino, di_db[i]) == 0) {
92 			if (idesc->id_type == DATA && ndb >= 0) {
93 				/* An empty block in a directory XXX */
94 				getpathname(pathbuf, idesc->id_number,
95 						idesc->id_number);
96 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
97 					pathbuf);
98 				if (reply("ADJUST LENGTH") == 1) {
99 					dp = ginode(idesc->id_number);
100 					DIP_SET(dp, di_size,
101 					    i * sblock.fs_bsize);
102 					printf(
103 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
104 					rerun = 1;
105 					inodirty();
106 
107 				}
108 			}
109 			continue;
110 		}
111 		idesc->id_blkno = DIP(&dino, di_db[i]);
112 		if (idesc->id_type != DATA)
113 			ret = (*idesc->id_func)(idesc);
114 		else
115 			ret = dirscan(idesc);
116 		if (ret & STOP)
117 			return (ret);
118 	}
119 	idesc->id_numfrags = sblock.fs_frag;
120 	remsize = DIP(&dino, di_size) - sblock.fs_bsize * UFS_NDADDR;
121 	sizepb = sblock.fs_bsize;
122 	for (i = 0; i < UFS_NIADDR; i++) {
123 		sizepb *= NINDIR(&sblock);
124 		if (DIP(&dino, di_ib[i])) {
125 			idesc->id_blkno = DIP(&dino, di_ib[i]);
126 			ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i);
127 			if (ret & STOP)
128 				return (ret);
129 		} else {
130 			idesc->id_lbn += sizepb / sblock.fs_bsize;
131 			if (idesc->id_type == DATA && remsize > 0) {
132 				/* An empty block in a directory XXX */
133 				getpathname(pathbuf, idesc->id_number,
134 						idesc->id_number);
135 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
136 					pathbuf);
137 				if (reply("ADJUST LENGTH") == 1) {
138 					dp = ginode(idesc->id_number);
139 					DIP_SET(dp, di_size,
140 					    DIP(dp, di_size) - remsize);
141 					remsize = 0;
142 					printf(
143 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
144 					rerun = 1;
145 					inodirty();
146 					break;
147 				}
148 			}
149 		}
150 		remsize -= sizepb;
151 	}
152 	return (KEEPON);
153 }
154 
155 static int
156 iblock(struct inodesc *idesc, long ilevel, off_t isize, int type)
157 {
158 	struct bufarea *bp;
159 	int i, n, (*func)(struct inodesc *), nif;
160 	off_t sizepb;
161 	char buf[BUFSIZ];
162 	char pathbuf[MAXPATHLEN + 1];
163 	union dinode *dp;
164 
165 	if (idesc->id_type != DATA) {
166 		func = idesc->id_func;
167 		if (((n = (*func)(idesc)) & KEEPON) == 0)
168 			return (n);
169 	} else
170 		func = dirscan;
171 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
172 		return (SKIP);
173 	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type);
174 	ilevel--;
175 	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
176 		sizepb *= NINDIR(&sblock);
177 	if (howmany(isize, sizepb) > NINDIR(&sblock))
178 		nif = NINDIR(&sblock);
179 	else
180 		nif = howmany(isize, sizepb);
181 	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
182 		for (i = nif; i < NINDIR(&sblock); i++) {
183 			if (IBLK(bp, i) == 0)
184 				continue;
185 			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
186 			    (u_long)idesc->id_number);
187 			if (preen) {
188 				pfatal("%s", buf);
189 			} else if (dofix(idesc, buf)) {
190 				IBLK_SET(bp, i, 0);
191 				dirty(bp);
192 			}
193 		}
194 		flush(fswritefd, bp);
195 	}
196 	for (i = 0; i < nif; i++) {
197 		if (ilevel == 0)
198 			idesc->id_lbn++;
199 		if (IBLK(bp, i)) {
200 			idesc->id_blkno = IBLK(bp, i);
201 			if (ilevel == 0)
202 				n = (*func)(idesc);
203 			else
204 				n = iblock(idesc, ilevel, isize, type);
205 			if (n & STOP) {
206 				bp->b_flags &= ~B_INUSE;
207 				return (n);
208 			}
209 		} else {
210 			if (idesc->id_type == DATA && isize > 0) {
211 				/* An empty block in a directory XXX */
212 				getpathname(pathbuf, idesc->id_number,
213 						idesc->id_number);
214 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
215 					pathbuf);
216 				if (reply("ADJUST LENGTH") == 1) {
217 					dp = ginode(idesc->id_number);
218 					DIP_SET(dp, di_size,
219 					    DIP(dp, di_size) - isize);
220 					isize = 0;
221 					printf(
222 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
223 					rerun = 1;
224 					inodirty();
225 					bp->b_flags &= ~B_INUSE;
226 					return(STOP);
227 				}
228 			}
229 		}
230 		isize -= sizepb;
231 	}
232 	bp->b_flags &= ~B_INUSE;
233 	return (KEEPON);
234 }
235 
236 /*
237  * Check that a block in a legal block number.
238  * Return 0 if in range, 1 if out of range.
239  */
240 int
241 chkrange(ufs2_daddr_t blk, int cnt)
242 {
243 	int c;
244 
245 	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
246 	    cnt - 1 > maxfsblock - blk)
247 		return (1);
248 	if (cnt > sblock.fs_frag ||
249 	    fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
250 		if (debug)
251 			printf("bad size: blk %ld, offset %i, size %d\n",
252 			    (long)blk, (int)fragnum(&sblock, blk), cnt);
253 		return (1);
254 	}
255 	c = dtog(&sblock, blk);
256 	if (blk < cgdmin(&sblock, c)) {
257 		if ((blk + cnt) > cgsblock(&sblock, c)) {
258 			if (debug) {
259 				printf("blk %ld < cgdmin %ld;",
260 				    (long)blk, (long)cgdmin(&sblock, c));
261 				printf(" blk + cnt %ld > cgsbase %ld\n",
262 				    (long)(blk + cnt),
263 				    (long)cgsblock(&sblock, c));
264 			}
265 			return (1);
266 		}
267 	} else {
268 		if ((blk + cnt) > cgbase(&sblock, c+1)) {
269 			if (debug)  {
270 				printf("blk %ld >= cgdmin %ld;",
271 				    (long)blk, (long)cgdmin(&sblock, c));
272 				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
273 				    (long)(blk + cnt), (long)sblock.fs_fpg);
274 			}
275 			return (1);
276 		}
277 	}
278 	return (0);
279 }
280 
281 /*
282  * General purpose interface for reading inodes.
283  */
284 union dinode *
285 ginode(ino_t inumber)
286 {
287 	ufs2_daddr_t iblk;
288 
289 	if (inumber < UFS_ROOTINO || inumber > maxino)
290 		errx(EEXIT, "bad inode number %ju to ginode",
291 		    (uintmax_t)inumber);
292 	if (startinum == 0 ||
293 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
294 		iblk = ino_to_fsba(&sblock, inumber);
295 		if (pbp != NULL)
296 			pbp->b_flags &= ~B_INUSE;
297 		pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES);
298 		startinum = rounddown(inumber, INOPB(&sblock));
299 	}
300 	if (sblock.fs_magic == FS_UFS1_MAGIC)
301 		return ((union dinode *)
302 		    &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]);
303 	return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]);
304 }
305 
306 /*
307  * Special purpose version of ginode used to optimize first pass
308  * over all the inodes in numerical order.
309  */
310 static ino_t nextino, lastinum, lastvalidinum;
311 static long readcount, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
312 static struct bufarea inobuf;
313 
314 union dinode *
315 getnextinode(ino_t inumber, int rebuildcg)
316 {
317 	int j;
318 	long size;
319 	mode_t mode;
320 	ufs2_daddr_t ndb, blk;
321 	union dinode *dp;
322 	static caddr_t nextinop;
323 
324 	if (inumber != nextino++ || inumber > lastvalidinum)
325 		errx(EEXIT, "bad inode number %ju to nextinode",
326 		    (uintmax_t)inumber);
327 	if (inumber >= lastinum) {
328 		readcount++;
329 		blk = ino_to_fsba(&sblock, lastinum);
330 		if (readcount % readpercg == 0) {
331 			size = partialsize;
332 			lastinum += partialcnt;
333 		} else {
334 			size = inobufsize;
335 			lastinum += fullcnt;
336 		}
337 		/*
338 		 * If getblk encounters an error, it will already have zeroed
339 		 * out the buffer, so we do not need to do so here.
340 		 */
341 		getblk(&inobuf, blk, size);
342 		nextinop = inobuf.b_un.b_buf;
343 	}
344 	dp = (union dinode *)nextinop;
345 	if (rebuildcg && nextinop == inobuf.b_un.b_buf) {
346 		/*
347 		 * Try to determine if we have reached the end of the
348 		 * allocated inodes.
349 		 */
350 		mode = DIP(dp, di_mode) & IFMT;
351 		if (mode == 0) {
352 			if (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
353 				UFS_NDADDR * sizeof(ufs2_daddr_t)) ||
354 			      memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
355 				UFS_NIADDR * sizeof(ufs2_daddr_t)) ||
356 			      dp->dp2.di_mode || dp->dp2.di_size)
357 				return (NULL);
358 			goto inodegood;
359 		}
360 		if (!ftypeok(dp))
361 			return (NULL);
362 		ndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
363 		if (ndb < 0)
364 			return (NULL);
365 		if (mode == IFBLK || mode == IFCHR)
366 			ndb++;
367 		if (mode == IFLNK) {
368 			/*
369 			 * Fake ndb value so direct/indirect block checks below
370 			 * will detect any garbage after symlink string.
371 			 */
372 			if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) {
373 				ndb = howmany(DIP(dp, di_size),
374 				    sizeof(ufs2_daddr_t));
375 				if (ndb > UFS_NDADDR) {
376 					j = ndb - UFS_NDADDR;
377 					for (ndb = 1; j > 1; j--)
378 						ndb *= NINDIR(&sblock);
379 					ndb += UFS_NDADDR;
380 				}
381 			}
382 		}
383 		for (j = ndb; ndb < UFS_NDADDR && j < UFS_NDADDR; j++)
384 			if (DIP(dp, di_db[j]) != 0)
385 				return (NULL);
386 		for (j = 0, ndb -= UFS_NDADDR; ndb > 0; j++)
387 			ndb /= NINDIR(&sblock);
388 		for (; j < UFS_NIADDR; j++)
389 			if (DIP(dp, di_ib[j]) != 0)
390 				return (NULL);
391 	}
392 inodegood:
393 	if (sblock.fs_magic == FS_UFS1_MAGIC)
394 		nextinop += sizeof(struct ufs1_dinode);
395 	else
396 		nextinop += sizeof(struct ufs2_dinode);
397 	return (dp);
398 }
399 
400 void
401 setinodebuf(ino_t inum)
402 {
403 
404 	if (inum % sblock.fs_ipg != 0)
405 		errx(EEXIT, "bad inode number %ju to setinodebuf",
406 		    (uintmax_t)inum);
407 	lastvalidinum = inum + sblock.fs_ipg - 1;
408 	startinum = 0;
409 	nextino = inum;
410 	lastinum = inum;
411 	readcount = 0;
412 	if (inobuf.b_un.b_buf != NULL)
413 		return;
414 	inobufsize = blkroundup(&sblock, INOBUFSIZE);
415 	fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
416 	    sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
417 	readpercg = sblock.fs_ipg / fullcnt;
418 	partialcnt = sblock.fs_ipg % fullcnt;
419 	partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ?
420 	    sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
421 	if (partialcnt != 0) {
422 		readpercg++;
423 	} else {
424 		partialcnt = fullcnt;
425 		partialsize = inobufsize;
426 	}
427 	initbarea(&inobuf, BT_INODES);
428 	if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL)
429 		errx(EEXIT, "cannot allocate space for inode buffer");
430 }
431 
432 void
433 freeinodebuf(void)
434 {
435 
436 	if (inobuf.b_un.b_buf != NULL)
437 		free((char *)inobuf.b_un.b_buf);
438 	inobuf.b_un.b_buf = NULL;
439 }
440 
441 /*
442  * Routines to maintain information about directory inodes.
443  * This is built during the first pass and used during the
444  * second and third passes.
445  *
446  * Enter inodes into the cache.
447  */
448 void
449 cacheino(union dinode *dp, ino_t inumber)
450 {
451 	struct inoinfo *inp, **inpp;
452 	int i, blks;
453 
454 	if (howmany(DIP(dp, di_size), sblock.fs_bsize) > UFS_NDADDR)
455 		blks = UFS_NDADDR + UFS_NIADDR;
456 	else if (DIP(dp, di_size) > 0)
457 		blks = howmany(DIP(dp, di_size), sblock.fs_bsize);
458 	else
459 		blks = 1;
460 	inp = (struct inoinfo *)
461 		Malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
462 	if (inp == NULL)
463 		errx(EEXIT, "cannot increase directory list");
464 	inpp = &inphead[inumber % dirhash];
465 	inp->i_nexthash = *inpp;
466 	*inpp = inp;
467 	inp->i_parent = inumber == UFS_ROOTINO ? UFS_ROOTINO : (ino_t)0;
468 	inp->i_dotdot = (ino_t)0;
469 	inp->i_number = inumber;
470 	inp->i_isize = DIP(dp, di_size);
471 	inp->i_numblks = blks;
472 	for (i = 0; i < MIN(blks, UFS_NDADDR); i++)
473 		inp->i_blks[i] = DIP(dp, di_db[i]);
474 	if (blks > UFS_NDADDR)
475 		for (i = 0; i < UFS_NIADDR; i++)
476 			inp->i_blks[UFS_NDADDR + i] = DIP(dp, di_ib[i]);
477 	if (inplast == listmax) {
478 		listmax += 100;
479 		inpsort = (struct inoinfo **)reallocarray((char *)inpsort,
480 		    listmax, sizeof(struct inoinfo *));
481 		if (inpsort == NULL)
482 			errx(EEXIT, "cannot increase directory list");
483 	}
484 	inpsort[inplast++] = inp;
485 }
486 
487 /*
488  * Look up an inode cache structure.
489  */
490 struct inoinfo *
491 getinoinfo(ino_t inumber)
492 {
493 	struct inoinfo *inp;
494 
495 	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
496 		if (inp->i_number != inumber)
497 			continue;
498 		return (inp);
499 	}
500 	errx(EEXIT, "cannot find inode %ju", (uintmax_t)inumber);
501 	return ((struct inoinfo *)0);
502 }
503 
504 /*
505  * Clean up all the inode cache structure.
506  */
507 void
508 inocleanup(void)
509 {
510 	struct inoinfo **inpp;
511 
512 	if (inphead == NULL)
513 		return;
514 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
515 		free((char *)(*inpp));
516 	free((char *)inphead);
517 	free((char *)inpsort);
518 	inphead = inpsort = NULL;
519 }
520 
521 void
522 inodirty(void)
523 {
524 
525 	dirty(pbp);
526 }
527 
528 void
529 clri(struct inodesc *idesc, const char *type, int flag)
530 {
531 	union dinode *dp;
532 
533 	dp = ginode(idesc->id_number);
534 	if (flag == 1) {
535 		pwarn("%s %s", type,
536 		    (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
537 		pinode(idesc->id_number);
538 	}
539 	if (preen || reply("CLEAR") == 1) {
540 		if (preen)
541 			printf(" (CLEARED)\n");
542 		n_files--;
543 		if (bkgrdflag == 0) {
544 			(void)ckinode(dp, idesc);
545 			inoinfo(idesc->id_number)->ino_state = USTATE;
546 			clearinode(dp);
547 			inodirty();
548 		} else {
549 			cmd.value = idesc->id_number;
550 			cmd.size = -DIP(dp, di_nlink);
551 			if (debug)
552 				printf("adjrefcnt ino %ld amt %lld\n",
553 				    (long)cmd.value, (long long)cmd.size);
554 			if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
555 			    &cmd, sizeof cmd) == -1)
556 				rwerror("ADJUST INODE", cmd.value);
557 		}
558 	}
559 }
560 
561 int
562 findname(struct inodesc *idesc)
563 {
564 	struct direct *dirp = idesc->id_dirp;
565 
566 	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
567 		idesc->id_entryno++;
568 		return (KEEPON);
569 	}
570 	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
571 	return (STOP|FOUND);
572 }
573 
574 int
575 findino(struct inodesc *idesc)
576 {
577 	struct direct *dirp = idesc->id_dirp;
578 
579 	if (dirp->d_ino == 0)
580 		return (KEEPON);
581 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
582 	    dirp->d_ino >= UFS_ROOTINO && dirp->d_ino <= maxino) {
583 		idesc->id_parent = dirp->d_ino;
584 		return (STOP|FOUND);
585 	}
586 	return (KEEPON);
587 }
588 
589 int
590 clearentry(struct inodesc *idesc)
591 {
592 	struct direct *dirp = idesc->id_dirp;
593 
594 	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
595 		idesc->id_entryno++;
596 		return (KEEPON);
597 	}
598 	dirp->d_ino = 0;
599 	return (STOP|FOUND|ALTERED);
600 }
601 
602 void
603 pinode(ino_t ino)
604 {
605 	union dinode *dp;
606 	char *p;
607 	struct passwd *pw;
608 	time_t t;
609 
610 	printf(" I=%lu ", (u_long)ino);
611 	if (ino < UFS_ROOTINO || ino > maxino)
612 		return;
613 	dp = ginode(ino);
614 	printf(" OWNER=");
615 	if ((pw = getpwuid((int)DIP(dp, di_uid))) != NULL)
616 		printf("%s ", pw->pw_name);
617 	else
618 		printf("%u ", (unsigned)DIP(dp, di_uid));
619 	printf("MODE=%o\n", DIP(dp, di_mode));
620 	if (preen)
621 		printf("%s: ", cdevname);
622 	printf("SIZE=%ju ", (uintmax_t)DIP(dp, di_size));
623 	t = DIP(dp, di_mtime);
624 	p = ctime(&t);
625 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
626 }
627 
628 void
629 blkerror(ino_t ino, const char *type, ufs2_daddr_t blk)
630 {
631 
632 	pfatal("%jd %s I=%ju", (intmax_t)blk, type, (uintmax_t)ino);
633 	printf("\n");
634 	switch (inoinfo(ino)->ino_state) {
635 
636 	case FSTATE:
637 	case FZLINK:
638 		inoinfo(ino)->ino_state = FCLEAR;
639 		return;
640 
641 	case DSTATE:
642 	case DZLINK:
643 		inoinfo(ino)->ino_state = DCLEAR;
644 		return;
645 
646 	case FCLEAR:
647 	case DCLEAR:
648 		return;
649 
650 	default:
651 		errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
652 		/* NOTREACHED */
653 	}
654 }
655 
656 /*
657  * allocate an unused inode
658  */
659 ino_t
660 allocino(ino_t request, int type)
661 {
662 	ino_t ino;
663 	union dinode *dp;
664 	struct bufarea *cgbp;
665 	struct cg *cgp;
666 	int cg;
667 
668 	if (request == 0)
669 		request = UFS_ROOTINO;
670 	else if (inoinfo(request)->ino_state != USTATE)
671 		return (0);
672 	for (ino = request; ino < maxino; ino++)
673 		if (inoinfo(ino)->ino_state == USTATE)
674 			break;
675 	if (ino == maxino)
676 		return (0);
677 	cg = ino_to_cg(&sblock, ino);
678 	cgbp = cglookup(cg);
679 	cgp = cgbp->b_un.b_cg;
680 	if (!check_cgmagic(cg, cgbp))
681 		return (0);
682 	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
683 	cgp->cg_cs.cs_nifree--;
684 	switch (type & IFMT) {
685 	case IFDIR:
686 		inoinfo(ino)->ino_state = DSTATE;
687 		cgp->cg_cs.cs_ndir++;
688 		break;
689 	case IFREG:
690 	case IFLNK:
691 		inoinfo(ino)->ino_state = FSTATE;
692 		break;
693 	default:
694 		return (0);
695 	}
696 	dirty(cgbp);
697 	dp = ginode(ino);
698 	DIP_SET(dp, di_db[0], allocblk((long)1));
699 	if (DIP(dp, di_db[0]) == 0) {
700 		inoinfo(ino)->ino_state = USTATE;
701 		return (0);
702 	}
703 	DIP_SET(dp, di_mode, type);
704 	DIP_SET(dp, di_flags, 0);
705 	DIP_SET(dp, di_atime, time(NULL));
706 	DIP_SET(dp, di_ctime, DIP(dp, di_atime));
707 	DIP_SET(dp, di_mtime, DIP(dp, di_ctime));
708 	DIP_SET(dp, di_mtimensec, 0);
709 	DIP_SET(dp, di_ctimensec, 0);
710 	DIP_SET(dp, di_atimensec, 0);
711 	DIP_SET(dp, di_size, sblock.fs_fsize);
712 	DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize));
713 	n_files++;
714 	inodirty();
715 	inoinfo(ino)->ino_type = IFTODT(type);
716 	return (ino);
717 }
718 
719 /*
720  * deallocate an inode
721  */
722 void
723 freeino(ino_t ino)
724 {
725 	struct inodesc idesc;
726 	union dinode *dp;
727 
728 	memset(&idesc, 0, sizeof(struct inodesc));
729 	idesc.id_type = ADDR;
730 	idesc.id_func = pass4check;
731 	idesc.id_number = ino;
732 	dp = ginode(ino);
733 	(void)ckinode(dp, &idesc);
734 	clearinode(dp);
735 	inodirty();
736 	inoinfo(ino)->ino_state = USTATE;
737 	n_files--;
738 }
739