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