xref: /freebsd/sbin/fsck_ffs/inode.c (revision bcd92649c9952c9c9e8845dbd34276a60dd16664)
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.5 (Berkeley) 2/8/95";
36 #endif /* not lint */
37 
38 #include <sys/param.h>
39 #include <sys/time.h>
40 #include <ufs/ufs/dinode.h>
41 #include <ufs/ufs/dir.h>
42 #include <ufs/ffs/fs.h>
43 #include <pwd.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include "fsck.h"
48 
49 static ino_t startinum;
50 
51 static int	iblock __P((struct inodesc *idesc, long ilevel, quad_t isize));
52 
53 int
54 ckinode(dp, idesc)
55 	struct dinode *dp;
56 	register struct inodesc *idesc;
57 {
58 	register daddr_t *ap;
59 	int ret;
60 	long n, ndb, offset;
61 	struct dinode dino;
62 	quad_t remsize, sizepb;
63 	mode_t mode;
64 	char pathbuf[MAXPATHLEN + 1];
65 
66 	if (idesc->id_fix != IGNORE)
67 		idesc->id_fix = DONTKNOW;
68 	idesc->id_entryno = 0;
69 	idesc->id_filesize = dp->di_size;
70 	mode = dp->di_mode & IFMT;
71 	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
72 	    (dp->di_size < sblock.fs_maxsymlinklen || dp->di_blocks == 0)))
73 		return (KEEPON);
74 	dino = *dp;
75 	ndb = howmany(dino.di_size, sblock.fs_bsize);
76 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
77 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
78 			idesc->id_numfrags =
79 				numfrags(&sblock, fragroundup(&sblock, offset));
80 		else
81 			idesc->id_numfrags = sblock.fs_frag;
82 		if (*ap == 0) {
83 			if (idesc->id_type == DATA && ndb >= 0) {
84 				/* An empty block in a directory XXX */
85 				getpathname(pathbuf, idesc->id_number,
86 						idesc->id_number);
87                         	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
88 					pathbuf);
89                         	if (reply("ADJUST LENGTH") == 1) {
90 					dp = ginode(idesc->id_number);
91                                 	dp->di_size = (ap - &dino.di_db[0]) *
92 					    sblock.fs_bsize;
93 					printf(
94 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
95 					rerun = 1;
96                                 	inodirty();
97 
98                         	}
99 			}
100 			continue;
101 		}
102 		idesc->id_blkno = *ap;
103 		if (idesc->id_type == ADDR)
104 			ret = (*idesc->id_func)(idesc);
105 		else
106 			ret = dirscan(idesc);
107 		if (ret & STOP)
108 			return (ret);
109 	}
110 	idesc->id_numfrags = sblock.fs_frag;
111 	remsize = dino.di_size - sblock.fs_bsize * NDADDR;
112 	sizepb = sblock.fs_bsize;
113 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
114 		if (*ap) {
115 			idesc->id_blkno = *ap;
116 			ret = iblock(idesc, n, remsize);
117 			if (ret & STOP)
118 				return (ret);
119 		} else {
120 			if (idesc->id_type == DATA && remsize > 0) {
121 				/* An empty block in a directory XXX */
122 				getpathname(pathbuf, idesc->id_number,
123 						idesc->id_number);
124                         	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
125 					pathbuf);
126                         	if (reply("ADJUST LENGTH") == 1) {
127 					dp = ginode(idesc->id_number);
128                                 	dp->di_size -= remsize;
129 					remsize = 0;
130 					printf(
131 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
132 					rerun = 1;
133                                 	inodirty();
134 					break;
135                         	}
136 			}
137 		}
138 		sizepb *= NINDIR(&sblock);
139 		remsize -= sizepb;
140 	}
141 	return (KEEPON);
142 }
143 
144 static int
145 iblock(idesc, ilevel, isize)
146 	struct inodesc *idesc;
147 	long ilevel;
148 	quad_t isize;
149 {
150 	register daddr_t *ap;
151 	register daddr_t *aplim;
152 	register struct bufarea *bp;
153 	int i, n, (*func)(), nif;
154 	quad_t sizepb;
155 	char buf[BUFSIZ];
156 	char pathbuf[MAXPATHLEN + 1];
157 	struct dinode *dp;
158 
159 	if (idesc->id_type == ADDR) {
160 		func = idesc->id_func;
161 		if (((n = (*func)(idesc)) & KEEPON) == 0)
162 			return (n);
163 	} else
164 		func = dirscan;
165 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
166 		return (SKIP);
167 	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
168 	ilevel--;
169 	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
170 		sizepb *= NINDIR(&sblock);
171 	nif = howmany(isize , sizepb);
172 	if (nif > NINDIR(&sblock))
173 		nif = NINDIR(&sblock);
174 	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
175 		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
176 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
177 			if (*ap == 0)
178 				continue;
179 			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
180 				idesc->id_number);
181 			if (dofix(idesc, buf)) {
182 				*ap = 0;
183 				dirty(bp);
184 			}
185 		}
186 		flush(fswritefd, bp);
187 	}
188 	aplim = &bp->b_un.b_indir[nif];
189 	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
190 		if (*ap) {
191 			idesc->id_blkno = *ap;
192 			if (ilevel == 0)
193 				n = (*func)(idesc);
194 			else
195 				n = iblock(idesc, ilevel, isize);
196 			if (n & STOP) {
197 				bp->b_flags &= ~B_INUSE;
198 				return (n);
199 			}
200 		} else {
201 			if (idesc->id_type == DATA && isize > 0) {
202 				/* An empty block in a directory XXX */
203 				getpathname(pathbuf, idesc->id_number,
204 						idesc->id_number);
205                         	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
206 					pathbuf);
207                         	if (reply("ADJUST LENGTH") == 1) {
208 					dp = ginode(idesc->id_number);
209                                 	dp->di_size -= isize;
210 					isize = 0;
211 					printf(
212 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
213 					rerun = 1;
214                                 	inodirty();
215 					bp->b_flags &= ~B_INUSE;
216 					return(STOP);
217                         	}
218 			}
219 		}
220 		isize -= sizepb;
221 	}
222 	bp->b_flags &= ~B_INUSE;
223 	return (KEEPON);
224 }
225 
226 /*
227  * Check that a block in a legal block number.
228  * Return 0 if in range, 1 if out of range.
229  */
230 int
231 chkrange(blk, cnt)
232 	daddr_t blk;
233 	int cnt;
234 {
235 	register int c;
236 
237 	if ((unsigned)(blk + cnt) > maxfsblock)
238 		return (1);
239 	c = dtog(&sblock, blk);
240 	if (blk < cgdmin(&sblock, c)) {
241 		if ((blk + cnt) > cgsblock(&sblock, c)) {
242 			if (debug) {
243 				printf("blk %ld < cgdmin %ld;",
244 				    blk, cgdmin(&sblock, c));
245 				printf(" blk + cnt %ld > cgsbase %ld\n",
246 				    blk + cnt, cgsblock(&sblock, c));
247 			}
248 			return (1);
249 		}
250 	} else {
251 		if ((blk + cnt) > cgbase(&sblock, c+1)) {
252 			if (debug)  {
253 				printf("blk %ld >= cgdmin %ld;",
254 				    blk, cgdmin(&sblock, c));
255 				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
256 				    blk+cnt, sblock.fs_fpg);
257 			}
258 			return (1);
259 		}
260 	}
261 	return (0);
262 }
263 
264 /*
265  * General purpose interface for reading inodes.
266  */
267 struct dinode *
268 ginode(inumber)
269 	ino_t inumber;
270 {
271 	daddr_t iblk;
272 
273 	if (inumber < ROOTINO || inumber > maxino)
274 		errexit("bad inode number %d to ginode\n", inumber);
275 	if (startinum == 0 ||
276 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
277 		iblk = ino_to_fsba(&sblock, inumber);
278 		if (pbp != 0)
279 			pbp->b_flags &= ~B_INUSE;
280 		pbp = getdatablk(iblk, sblock.fs_bsize);
281 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
282 	}
283 	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
284 }
285 
286 /*
287  * Special purpose version of ginode used to optimize first pass
288  * over all the inodes in numerical order.
289  */
290 ino_t nextino, lastinum;
291 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
292 struct dinode *inodebuf;
293 
294 struct dinode *
295 getnextinode(inumber)
296 	ino_t inumber;
297 {
298 	long size;
299 	daddr_t dblk;
300 	static struct dinode *dp;
301 
302 	if (inumber != nextino++ || inumber > maxino)
303 		errexit("bad inode number %d to nextinode\n", inumber);
304 	if (inumber >= lastinum) {
305 		readcnt++;
306 		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
307 		if (readcnt % readpercg == 0) {
308 			size = partialsize;
309 			lastinum += partialcnt;
310 		} else {
311 			size = inobufsize;
312 			lastinum += fullcnt;
313 		}
314 		(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
315 		dp = inodebuf;
316 	}
317 	return (dp++);
318 }
319 
320 void
321 resetinodebuf()
322 {
323 
324 	startinum = 0;
325 	nextino = 0;
326 	lastinum = 0;
327 	readcnt = 0;
328 	inobufsize = blkroundup(&sblock, INOBUFSIZE);
329 	fullcnt = inobufsize / sizeof(struct dinode);
330 	readpercg = sblock.fs_ipg / fullcnt;
331 	partialcnt = sblock.fs_ipg % fullcnt;
332 	partialsize = partialcnt * sizeof(struct dinode);
333 	if (partialcnt != 0) {
334 		readpercg++;
335 	} else {
336 		partialcnt = fullcnt;
337 		partialsize = inobufsize;
338 	}
339 	if (inodebuf == NULL &&
340 	    (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
341 		errexit("Cannot allocate space for inode buffer\n");
342 	while (nextino < ROOTINO)
343 		(void)getnextinode(nextino);
344 }
345 
346 void
347 freeinodebuf()
348 {
349 
350 	if (inodebuf != NULL)
351 		free((char *)inodebuf);
352 	inodebuf = NULL;
353 }
354 
355 /*
356  * Routines to maintain information about directory inodes.
357  * This is built during the first pass and used during the
358  * second and third passes.
359  *
360  * Enter inodes into the cache.
361  */
362 void
363 cacheino(dp, inumber)
364 	register struct dinode *dp;
365 	ino_t inumber;
366 {
367 	register struct inoinfo *inp;
368 	struct inoinfo **inpp;
369 	unsigned int blks;
370 
371 	blks = howmany(dp->di_size, sblock.fs_bsize);
372 	if (blks > NDADDR)
373 		blks = NDADDR + NIADDR;
374 	inp = (struct inoinfo *)
375 		malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
376 	if (inp == NULL)
377 		return;
378 	inpp = &inphead[inumber % numdirs];
379 	inp->i_nexthash = *inpp;
380 	*inpp = inp;
381 	if (inumber == ROOTINO)
382 		inp->i_parent = ROOTINO;
383 	else
384 		inp->i_parent = (ino_t)0;
385 	inp->i_dotdot = (ino_t)0;
386 	inp->i_number = inumber;
387 	inp->i_isize = dp->di_size;
388 	inp->i_numblks = blks * sizeof(daddr_t);
389 	bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
390 	    (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 			errexit("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 	errexit("cannot find inode %d\n", 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 	dirty(pbp);
440 }
441 
442 void
443 clri(idesc, type, flag)
444 	register struct inodesc *idesc;
445 	char *type;
446 	int flag;
447 {
448 	register struct dinode *dp;
449 
450 	dp = ginode(idesc->id_number);
451 	if (flag == 1) {
452 		pwarn("%s %s", type,
453 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
454 		pinode(idesc->id_number);
455 	}
456 	if (preen || reply("CLEAR") == 1) {
457 		if (preen)
458 			printf(" (CLEARED)\n");
459 		n_files--;
460 		(void)ckinode(dp, idesc);
461 		clearinode(dp);
462 		statemap[idesc->id_number] = USTATE;
463 		inodirty();
464 	}
465 }
466 
467 int
468 findname(idesc)
469 	struct inodesc *idesc;
470 {
471 	register struct direct *dirp = idesc->id_dirp;
472 
473 	if (dirp->d_ino != idesc->id_parent)
474 		return (KEEPON);
475 	bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
476 	return (STOP|FOUND);
477 }
478 
479 int
480 findino(idesc)
481 	struct inodesc *idesc;
482 {
483 	register struct direct *dirp = idesc->id_dirp;
484 
485 	if (dirp->d_ino == 0)
486 		return (KEEPON);
487 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
488 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
489 		idesc->id_parent = dirp->d_ino;
490 		return (STOP|FOUND);
491 	}
492 	return (KEEPON);
493 }
494 
495 void
496 pinode(ino)
497 	ino_t ino;
498 {
499 	register struct dinode *dp;
500 	register char *p;
501 	struct passwd *pw;
502 	char *ctime();
503 
504 	printf(" I=%lu ", ino);
505 	if (ino < ROOTINO || ino > maxino)
506 		return;
507 	dp = ginode(ino);
508 	printf(" OWNER=");
509 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
510 		printf("%s ", pw->pw_name);
511 	else
512 		printf("%u ", (unsigned)dp->di_uid);
513 	printf("MODE=%o\n", dp->di_mode);
514 	if (preen)
515 		printf("%s: ", cdevname);
516 	printf("SIZE=%qu ", dp->di_size);
517 	p = ctime(&dp->di_mtime.tv_sec);
518 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
519 }
520 
521 void
522 blkerror(ino, type, blk)
523 	ino_t ino;
524 	char *type;
525 	daddr_t blk;
526 {
527 
528 	pfatal("%ld %s I=%lu", blk, type, ino);
529 	printf("\n");
530 	switch (statemap[ino]) {
531 
532 	case FSTATE:
533 		statemap[ino] = FCLEAR;
534 		return;
535 
536 	case DSTATE:
537 		statemap[ino] = DCLEAR;
538 		return;
539 
540 	case FCLEAR:
541 	case DCLEAR:
542 		return;
543 
544 	default:
545 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
546 		/* NOTREACHED */
547 	}
548 }
549 
550 /*
551  * allocate an unused inode
552  */
553 ino_t
554 allocino(request, type)
555 	ino_t request;
556 	int type;
557 {
558 	register ino_t ino;
559 	register struct dinode *dp;
560 
561 	if (request == 0)
562 		request = ROOTINO;
563 	else if (statemap[request] != USTATE)
564 		return (0);
565 	for (ino = request; ino < maxino; ino++)
566 		if (statemap[ino] == USTATE)
567 			break;
568 	if (ino == maxino)
569 		return (0);
570 	switch (type & IFMT) {
571 	case IFDIR:
572 		statemap[ino] = DSTATE;
573 		break;
574 	case IFREG:
575 	case IFLNK:
576 		statemap[ino] = FSTATE;
577 		break;
578 	default:
579 		return (0);
580 	}
581 	dp = ginode(ino);
582 	dp->di_db[0] = allocblk((long)1);
583 	if (dp->di_db[0] == 0) {
584 		statemap[ino] = USTATE;
585 		return (0);
586 	}
587 	dp->di_mode = type;
588 	(void)time(&dp->di_atime.tv_sec);
589 	dp->di_mtime = dp->di_ctime = dp->di_atime;
590 	dp->di_size = sblock.fs_fsize;
591 	dp->di_blocks = btodb(sblock.fs_fsize);
592 	n_files++;
593 	inodirty();
594 	if (newinofmt)
595 		typemap[ino] = IFTODT(type);
596 	return (ino);
597 }
598 
599 /*
600  * deallocate an inode
601  */
602 void
603 freeino(ino)
604 	ino_t ino;
605 {
606 	struct inodesc idesc;
607 	struct dinode *dp;
608 
609 	bzero((char *)&idesc, sizeof(struct inodesc));
610 	idesc.id_type = ADDR;
611 	idesc.id_func = pass4check;
612 	idesc.id_number = ino;
613 	dp = ginode(ino);
614 	(void)ckinode(dp, &idesc);
615 	clearinode(dp);
616 	inodirty();
617 	statemap[ino] = USTATE;
618 	n_files--;
619 }
620