xref: /freebsd/sbin/fsck_ffs/inode.c (revision df7f5d4de4592a8948a25ce01e5bddfbb7ce39dc)
1 /*
2  * Copyright (c) 1980, 1986, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static const char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
36 #endif /* not lint */
37 
38 #include <sys/param.h>
39 #include <sys/time.h>
40 
41 #include <ufs/ufs/dinode.h>
42 #include <ufs/ufs/dir.h>
43 #include <ufs/ffs/fs.h>
44 
45 #include <err.h>
46 #include <pwd.h>
47 #include <string.h>
48 
49 #include "fsck.h"
50 
51 static ino_t startinum;
52 
53 static int iblock __P((struct inodesc *, long ilevel, quad_t isize));
54 
55 int
56 ckinode(dp, idesc)
57 	struct dinode *dp;
58 	register struct inodesc *idesc;
59 {
60 	ufs_daddr_t *ap;
61 	long ret, n, ndb, offset;
62 	struct dinode dino;
63 	quad_t remsize, sizepb;
64 	mode_t mode;
65 	char pathbuf[MAXPATHLEN + 1];
66 
67 	if (idesc->id_fix != IGNORE)
68 		idesc->id_fix = DONTKNOW;
69 	idesc->id_entryno = 0;
70 	idesc->id_filesize = dp->di_size;
71 	mode = dp->di_mode & IFMT;
72 	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
73 	    (dp->di_size < sblock.fs_maxsymlinklen || dp->di_blocks == 0)))
74 		return (KEEPON);
75 	dino = *dp;
76 	ndb = howmany(dino.di_size, sblock.fs_bsize);
77 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
78 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
79 			idesc->id_numfrags =
80 				numfrags(&sblock, fragroundup(&sblock, offset));
81 		else
82 			idesc->id_numfrags = sblock.fs_frag;
83 		if (*ap == 0) {
84 			if (idesc->id_type == DATA && ndb >= 0) {
85 				/* An empty block in a directory XXX */
86 				getpathname(pathbuf, idesc->id_number,
87 						idesc->id_number);
88                         	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
89 					pathbuf);
90                         	if (reply("ADJUST LENGTH") == 1) {
91 					dp = ginode(idesc->id_number);
92                                 	dp->di_size = (ap - &dino.di_db[0]) *
93 					    sblock.fs_bsize;
94 					printf(
95 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
96 					rerun = 1;
97                                 	inodirty();
98 
99                         	}
100 			}
101 			continue;
102 		}
103 		idesc->id_blkno = *ap;
104 		if (idesc->id_type == ADDR)
105 			ret = (*idesc->id_func)(idesc);
106 		else
107 			ret = dirscan(idesc);
108 		if (ret & STOP)
109 			return (ret);
110 	}
111 	idesc->id_numfrags = sblock.fs_frag;
112 	remsize = dino.di_size - sblock.fs_bsize * NDADDR;
113 	sizepb = sblock.fs_bsize;
114 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
115 		if (*ap) {
116 			idesc->id_blkno = *ap;
117 			ret = iblock(idesc, n, remsize);
118 			if (ret & STOP)
119 				return (ret);
120 		} else {
121 			if (idesc->id_type == DATA && remsize > 0) {
122 				/* An empty block in a directory XXX */
123 				getpathname(pathbuf, idesc->id_number,
124 						idesc->id_number);
125                         	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
126 					pathbuf);
127                         	if (reply("ADJUST LENGTH") == 1) {
128 					dp = ginode(idesc->id_number);
129                                 	dp->di_size -= remsize;
130 					remsize = 0;
131 					printf(
132 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
133 					rerun = 1;
134                                 	inodirty();
135 					break;
136                         	}
137 			}
138 		}
139 		sizepb *= NINDIR(&sblock);
140 		remsize -= sizepb;
141 	}
142 	return (KEEPON);
143 }
144 
145 static int
146 iblock(idesc, ilevel, isize)
147 	struct inodesc *idesc;
148 	long ilevel;
149 	quad_t isize;
150 {
151 	ufs_daddr_t *ap;
152 	ufs_daddr_t *aplim;
153 	struct bufarea *bp;
154 	int i, n, (*func)(), nif;
155 	quad_t sizepb;
156 	char buf[BUFSIZ];
157 	char pathbuf[MAXPATHLEN + 1];
158 	struct dinode *dp;
159 
160 	if (idesc->id_type == ADDR) {
161 		func = idesc->id_func;
162 		if (((n = (*func)(idesc)) & KEEPON) == 0)
163 			return (n);
164 	} else
165 		func = dirscan;
166 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
167 		return (SKIP);
168 	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
169 	ilevel--;
170 	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
171 		sizepb *= NINDIR(&sblock);
172 	nif = howmany(isize , sizepb);
173 	if (nif > NINDIR(&sblock))
174 		nif = NINDIR(&sblock);
175 	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
176 		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
177 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
178 			if (*ap == 0)
179 				continue;
180 			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
181 				idesc->id_number);
182 			if (dofix(idesc, buf)) {
183 				*ap = 0;
184 				dirty(bp);
185 			}
186 		}
187 		flush(fswritefd, bp);
188 	}
189 	aplim = &bp->b_un.b_indir[nif];
190 	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
191 		if (*ap) {
192 			idesc->id_blkno = *ap;
193 			if (ilevel == 0)
194 				n = (*func)(idesc);
195 			else
196 				n = iblock(idesc, ilevel, isize);
197 			if (n & STOP) {
198 				bp->b_flags &= ~B_INUSE;
199 				return (n);
200 			}
201 		} else {
202 			if (idesc->id_type == DATA && isize > 0) {
203 				/* An empty block in a directory XXX */
204 				getpathname(pathbuf, idesc->id_number,
205 						idesc->id_number);
206                         	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
207 					pathbuf);
208                         	if (reply("ADJUST LENGTH") == 1) {
209 					dp = ginode(idesc->id_number);
210                                 	dp->di_size -= isize;
211 					isize = 0;
212 					printf(
213 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
214 					rerun = 1;
215                                 	inodirty();
216 					bp->b_flags &= ~B_INUSE;
217 					return(STOP);
218                         	}
219 			}
220 		}
221 		isize -= sizepb;
222 	}
223 	bp->b_flags &= ~B_INUSE;
224 	return (KEEPON);
225 }
226 
227 /*
228  * Check that a block in a legal block number.
229  * Return 0 if in range, 1 if out of range.
230  */
231 int
232 chkrange(blk, cnt)
233 	ufs_daddr_t blk;
234 	int cnt;
235 {
236 	register int c;
237 
238 	if ((unsigned)(blk + cnt) > maxfsblock)
239 		return (1);
240 	c = dtog(&sblock, blk);
241 	if (blk < cgdmin(&sblock, c)) {
242 		if ((blk + cnt) > cgsblock(&sblock, c)) {
243 			if (debug) {
244 				printf("blk %ld < cgdmin %ld;",
245 				    blk, cgdmin(&sblock, c));
246 				printf(" blk + cnt %ld > cgsbase %ld\n",
247 				    blk + cnt, cgsblock(&sblock, c));
248 			}
249 			return (1);
250 		}
251 	} else {
252 		if ((blk + cnt) > cgbase(&sblock, c+1)) {
253 			if (debug)  {
254 				printf("blk %ld >= cgdmin %ld;",
255 				    blk, cgdmin(&sblock, c));
256 				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
257 				    blk+cnt, sblock.fs_fpg);
258 			}
259 			return (1);
260 		}
261 	}
262 	return (0);
263 }
264 
265 /*
266  * General purpose interface for reading inodes.
267  */
268 struct dinode *
269 ginode(inumber)
270 	ino_t inumber;
271 {
272 	ufs_daddr_t iblk;
273 
274 	if (inumber < ROOTINO || inumber > maxino)
275 		errx(EEXIT, "bad inode number %d to ginode", inumber);
276 	if (startinum == 0 ||
277 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
278 		iblk = ino_to_fsba(&sblock, inumber);
279 		if (pbp != 0)
280 			pbp->b_flags &= ~B_INUSE;
281 		pbp = getdatablk(iblk, sblock.fs_bsize);
282 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
283 	}
284 	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
285 }
286 
287 /*
288  * Special purpose version of ginode used to optimize first pass
289  * over all the inodes in numerical order.
290  */
291 ino_t nextino, lastinum;
292 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
293 struct dinode *inodebuf;
294 
295 struct dinode *
296 getnextinode(inumber)
297 	ino_t inumber;
298 {
299 	long size;
300 	ufs_daddr_t dblk;
301 	static struct dinode *dp;
302 
303 	if (inumber != nextino++ || inumber > maxino)
304 		errx(EEXIT, "bad inode number %d to nextinode", inumber);
305 	if (inumber >= lastinum) {
306 		readcnt++;
307 		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
308 		if (readcnt % readpercg == 0) {
309 			size = partialsize;
310 			lastinum += partialcnt;
311 		} else {
312 			size = inobufsize;
313 			lastinum += fullcnt;
314 		}
315 		(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
316 		dp = inodebuf;
317 	}
318 	return (dp++);
319 }
320 
321 void
322 resetinodebuf()
323 {
324 
325 	startinum = 0;
326 	nextino = 0;
327 	lastinum = 0;
328 	readcnt = 0;
329 	inobufsize = blkroundup(&sblock, INOBUFSIZE);
330 	fullcnt = inobufsize / sizeof(struct dinode);
331 	readpercg = sblock.fs_ipg / fullcnt;
332 	partialcnt = sblock.fs_ipg % fullcnt;
333 	partialsize = partialcnt * sizeof(struct dinode);
334 	if (partialcnt != 0) {
335 		readpercg++;
336 	} else {
337 		partialcnt = fullcnt;
338 		partialsize = inobufsize;
339 	}
340 	if (inodebuf == NULL &&
341 	    (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
342 		errx(EEXIT, "Cannot allocate space for inode buffer");
343 	while (nextino < ROOTINO)
344 		(void)getnextinode(nextino);
345 }
346 
347 void
348 freeinodebuf()
349 {
350 
351 	if (inodebuf != NULL)
352 		free((char *)inodebuf);
353 	inodebuf = NULL;
354 }
355 
356 /*
357  * Routines to maintain information about directory inodes.
358  * This is built during the first pass and used during the
359  * second and third passes.
360  *
361  * Enter inodes into the cache.
362  */
363 void
364 cacheino(dp, inumber)
365 	register struct dinode *dp;
366 	ino_t inumber;
367 {
368 	register struct inoinfo *inp;
369 	struct inoinfo **inpp;
370 	unsigned int blks;
371 
372 	blks = howmany(dp->di_size, sblock.fs_bsize);
373 	if (blks > NDADDR)
374 		blks = NDADDR + NIADDR;
375 	inp = (struct inoinfo *)
376 		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
377 	if (inp == NULL)
378 		return;
379 	inpp = &inphead[inumber % numdirs];
380 	inp->i_nexthash = *inpp;
381 	*inpp = inp;
382 	if (inumber == ROOTINO)
383 		inp->i_parent = ROOTINO;
384 	else
385 		inp->i_parent = (ino_t)0;
386 	inp->i_dotdot = (ino_t)0;
387 	inp->i_number = inumber;
388 	inp->i_isize = dp->di_size;
389 	inp->i_numblks = blks * sizeof(ufs_daddr_t);
390 	memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
391 	if (inplast == listmax) {
392 		listmax += 100;
393 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
394 		    (unsigned)listmax * sizeof(struct inoinfo *));
395 		if (inpsort == NULL)
396 			errx(EEXIT, "cannot increase directory list");
397 	}
398 	inpsort[inplast++] = inp;
399 }
400 
401 /*
402  * Look up an inode cache structure.
403  */
404 struct inoinfo *
405 getinoinfo(inumber)
406 	ino_t inumber;
407 {
408 	register struct inoinfo *inp;
409 
410 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
411 		if (inp->i_number != inumber)
412 			continue;
413 		return (inp);
414 	}
415 	errx(EEXIT, "cannot find inode %d", inumber);
416 	return ((struct inoinfo *)0);
417 }
418 
419 /*
420  * Clean up all the inode cache structure.
421  */
422 void
423 inocleanup()
424 {
425 	register struct inoinfo **inpp;
426 
427 	if (inphead == NULL)
428 		return;
429 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
430 		free((char *)(*inpp));
431 	free((char *)inphead);
432 	free((char *)inpsort);
433 	inphead = inpsort = NULL;
434 }
435 
436 void
437 inodirty()
438 {
439 
440 	dirty(pbp);
441 }
442 
443 void
444 clri(idesc, type, flag)
445 	register struct inodesc *idesc;
446 	char *type;
447 	int flag;
448 {
449 	register struct dinode *dp;
450 
451 	dp = ginode(idesc->id_number);
452 	if (flag == 1) {
453 		pwarn("%s %s", type,
454 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
455 		pinode(idesc->id_number);
456 	}
457 	if (preen || reply("CLEAR") == 1) {
458 		if (preen)
459 			printf(" (CLEARED)\n");
460 		n_files--;
461 		(void)ckinode(dp, idesc);
462 		clearinode(dp);
463 		statemap[idesc->id_number] = USTATE;
464 		inodirty();
465 	}
466 }
467 
468 int
469 findname(idesc)
470 	struct inodesc *idesc;
471 {
472 	register struct direct *dirp = idesc->id_dirp;
473 
474 	if (dirp->d_ino != idesc->id_parent)
475 		return (KEEPON);
476 	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
477 	return (STOP|FOUND);
478 }
479 
480 int
481 findino(idesc)
482 	struct inodesc *idesc;
483 {
484 	register struct direct *dirp = idesc->id_dirp;
485 
486 	if (dirp->d_ino == 0)
487 		return (KEEPON);
488 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
489 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
490 		idesc->id_parent = dirp->d_ino;
491 		return (STOP|FOUND);
492 	}
493 	return (KEEPON);
494 }
495 
496 void
497 pinode(ino)
498 	ino_t ino;
499 {
500 	register struct dinode *dp;
501 	register char *p;
502 	struct passwd *pw;
503 	time_t t;
504 
505 	printf(" I=%lu ", ino);
506 	if (ino < ROOTINO || ino > maxino)
507 		return;
508 	dp = ginode(ino);
509 	printf(" OWNER=");
510 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
511 		printf("%s ", pw->pw_name);
512 	else
513 		printf("%u ", (unsigned)dp->di_uid);
514 	printf("MODE=%o\n", dp->di_mode);
515 	if (preen)
516 		printf("%s: ", cdevname);
517 	printf("SIZE=%qu ", dp->di_size);
518 	t = dp->di_mtime;
519 	p = ctime(&t);
520 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
521 }
522 
523 void
524 blkerror(ino, type, blk)
525 	ino_t ino;
526 	char *type;
527 	ufs_daddr_t blk;
528 {
529 
530 	pfatal("%ld %s I=%lu", blk, type, ino);
531 	printf("\n");
532 	switch (statemap[ino]) {
533 
534 	case FSTATE:
535 		statemap[ino] = FCLEAR;
536 		return;
537 
538 	case DSTATE:
539 		statemap[ino] = DCLEAR;
540 		return;
541 
542 	case FCLEAR:
543 	case DCLEAR:
544 		return;
545 
546 	default:
547 		errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
548 		/* NOTREACHED */
549 	}
550 }
551 
552 /*
553  * allocate an unused inode
554  */
555 ino_t
556 allocino(request, type)
557 	ino_t request;
558 	int type;
559 {
560 	register ino_t ino;
561 	register struct dinode *dp;
562 
563 	if (request == 0)
564 		request = ROOTINO;
565 	else if (statemap[request] != USTATE)
566 		return (0);
567 	for (ino = request; ino < maxino; ino++)
568 		if (statemap[ino] == USTATE)
569 			break;
570 	if (ino == maxino)
571 		return (0);
572 	switch (type & IFMT) {
573 	case IFDIR:
574 		statemap[ino] = DSTATE;
575 		break;
576 	case IFREG:
577 	case IFLNK:
578 		statemap[ino] = FSTATE;
579 		break;
580 	default:
581 		return (0);
582 	}
583 	dp = ginode(ino);
584 	dp->di_db[0] = allocblk((long)1);
585 	if (dp->di_db[0] == 0) {
586 		statemap[ino] = USTATE;
587 		return (0);
588 	}
589 	dp->di_mode = type;
590 	dp->di_atime = time(NULL);
591 	dp->di_mtime = dp->di_ctime = dp->di_atime;
592 	dp->di_size = sblock.fs_fsize;
593 	dp->di_blocks = btodb(sblock.fs_fsize);
594 	n_files++;
595 	inodirty();
596 	if (newinofmt)
597 		typemap[ino] = IFTODT(type);
598 	return (ino);
599 }
600 
601 /*
602  * deallocate an inode
603  */
604 void
605 freeino(ino)
606 	ino_t ino;
607 {
608 	struct inodesc idesc;
609 	struct dinode *dp;
610 
611 	memset(&idesc, 0, sizeof(struct inodesc));
612 	idesc.id_type = ADDR;
613 	idesc.id_func = pass4check;
614 	idesc.id_number = ino;
615 	dp = ginode(ino);
616 	(void)ckinode(dp, &idesc);
617 	clearinode(dp);
618 	inodirty();
619 	statemap[ino] = USTATE;
620 	n_files--;
621 }
622