Home | History | Annotate | Line # | Download | only in fsck_ffs
inode.c revision 1.6
      1 /*
      2  * Copyright (c) 1980, 1986 The Regents of the University of California.
      3  * 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 char sccsid[] = "from: @(#)inode.c	5.18 (Berkeley) 3/19/91";*/
     36 static char rcsid[] = "$Id: inode.c,v 1.6 1994/04/18 06:08:27 cgd Exp $";
     37 #endif /* not lint */
     38 
     39 #include <sys/param.h>
     40 #include <ufs/dinode.h>
     41 #include <ufs/fs.h>
     42 #include <ufs/dir.h>
     43 #ifndef SMALL
     44 #include <pwd.h>
     45 #endif
     46 #include <stdlib.h>
     47 #include <string.h>
     48 #include "fsck.h"
     49 
     50 static ino_t startinum;
     51 
     52 ckinode(dp, idesc)
     53 	struct dinode *dp;
     54 	register struct inodesc *idesc;
     55 {
     56 	register daddr_t *ap;
     57 	long ret, n, ndb, offset;
     58 	struct dinode dino;
     59 
     60 	if (idesc->id_fix != IGNORE)
     61 		idesc->id_fix = DONTKNOW;
     62 	idesc->id_entryno = 0;
     63 	idesc->id_filesize = dp->di_size;
     64 	if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR ||
     65 		DFASTLINK(*dp))
     66 		return (KEEPON);
     67 	dino = *dp;
     68 	ndb = howmany(dino.di_size, sblock.fs_bsize);
     69 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
     70 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
     71 			idesc->id_numfrags =
     72 				numfrags(&sblock, fragroundup(&sblock, offset));
     73 		else
     74 			idesc->id_numfrags = sblock.fs_frag;
     75 		if (*ap == 0)
     76 			continue;
     77 		idesc->id_blkno = *ap;
     78 		if (idesc->id_type == ADDR)
     79 			ret = (*idesc->id_func)(idesc);
     80 		else
     81 			ret = dirscan(idesc);
     82 		if (ret & STOP)
     83 			return (ret);
     84 	}
     85 	idesc->id_numfrags = sblock.fs_frag;
     86 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
     87 		if (*ap) {
     88 			idesc->id_blkno = *ap;
     89 			ret = iblock(idesc, n,
     90 				dino.di_size - sblock.fs_bsize * NDADDR);
     91 			if (ret & STOP)
     92 				return (ret);
     93 		}
     94 	}
     95 	return (KEEPON);
     96 }
     97 
     98 iblock(idesc, ilevel, isize)
     99 	struct inodesc *idesc;
    100 	register long ilevel;
    101 	u_long isize;
    102 {
    103 	register daddr_t *ap;
    104 	register daddr_t *aplim;
    105 	int i, n, (*func)(), nif, sizepb;
    106 	register struct bufarea *bp;
    107 	char buf[BUFSIZ];
    108 	extern int dirscan(), pass1check();
    109 
    110 	if (idesc->id_type == ADDR) {
    111 		func = idesc->id_func;
    112 		if (((n = (*func)(idesc)) & KEEPON) == 0)
    113 			return (n);
    114 	} else
    115 		func = dirscan;
    116 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
    117 		return (SKIP);
    118 	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
    119 	ilevel--;
    120 	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
    121 		sizepb *= NINDIR(&sblock);
    122 	nif = isize / sizepb + 1;
    123 	if (nif > NINDIR(&sblock))
    124 		nif = NINDIR(&sblock);
    125 	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
    126 		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
    127 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
    128 			if (*ap == 0)
    129 				continue;
    130 			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
    131 				idesc->id_number);
    132 			if (dofix(idesc, buf)) {
    133 				*ap = 0;
    134 				dirty(bp);
    135 			}
    136 		}
    137 		flush(fswritefd, bp);
    138 	}
    139 	aplim = &bp->b_un.b_indir[nif];
    140 	for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) {
    141 		if (*ap) {
    142 			idesc->id_blkno = *ap;
    143 			if (ilevel > 0)
    144 				n = iblock(idesc, ilevel, isize - i * sizepb);
    145 			else
    146 				n = (*func)(idesc);
    147 			if (n & STOP) {
    148 				bp->b_flags &= ~B_INUSE;
    149 				return (n);
    150 			}
    151 		}
    152 	}
    153 	bp->b_flags &= ~B_INUSE;
    154 	return (KEEPON);
    155 }
    156 
    157 /*
    158  * Check that a block in a legal block number.
    159  * Return 0 if in range, 1 if out of range.
    160  */
    161 chkrange(blk, cnt)
    162 	daddr_t blk;
    163 	int cnt;
    164 {
    165 	register int c;
    166 
    167 	if ((unsigned)(blk + cnt) > maxfsblock)
    168 		return (1);
    169 	c = dtog(&sblock, blk);
    170 	if (blk < cgdmin(&sblock, c)) {
    171 		if ((blk + cnt) > cgsblock(&sblock, c)) {
    172 			if (debug) {
    173 				printf("blk %ld < cgdmin %ld;",
    174 				    blk, cgdmin(&sblock, c));
    175 				printf(" blk + cnt %ld > cgsbase %ld\n",
    176 				    blk + cnt, cgsblock(&sblock, c));
    177 			}
    178 			return (1);
    179 		}
    180 	} else {
    181 		if ((blk + cnt) > cgbase(&sblock, c+1)) {
    182 			if (debug)  {
    183 				printf("blk %ld >= cgdmin %ld;",
    184 				    blk, cgdmin(&sblock, c));
    185 				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
    186 				    blk+cnt, sblock.fs_fpg);
    187 			}
    188 			return (1);
    189 		}
    190 	}
    191 	return (0);
    192 }
    193 
    194 /*
    195  * General purpose interface for reading inodes.
    196  */
    197 struct dinode *
    198 ginode(inumber)
    199 	ino_t inumber;
    200 {
    201 	daddr_t iblk;
    202 
    203 	if (inumber < ROOTINO || inumber > maxino)
    204 		errexit("bad inode number %d to ginode\n", inumber);
    205 	if (startinum == 0 ||
    206 	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
    207 		iblk = itod(&sblock, inumber);
    208 		if (pbp != 0)
    209 			pbp->b_flags &= ~B_INUSE;
    210 		pbp = getdatablk(iblk, sblock.fs_bsize);
    211 		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
    212 	}
    213 	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
    214 }
    215 
    216 /*
    217  * Special purpose version of ginode used to optimize first pass
    218  * over all the inodes in numerical order.
    219  */
    220 ino_t nextino, lastinum;
    221 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
    222 struct dinode *inodebuf;
    223 
    224 struct dinode *
    225 getnextinode(inumber)
    226 	ino_t inumber;
    227 {
    228 	long size;
    229 	daddr_t dblk;
    230 	static struct dinode *dp;
    231 
    232 	if (inumber != nextino++ || inumber > maxino)
    233 		errexit("bad inode number %d to nextinode\n", inumber);
    234 	if (inumber >= lastinum) {
    235 		readcnt++;
    236 		dblk = fsbtodb(&sblock, itod(&sblock, lastinum));
    237 		if (readcnt % readpercg == 0) {
    238 			size = partialsize;
    239 			lastinum += partialcnt;
    240 		} else {
    241 			size = inobufsize;
    242 			lastinum += fullcnt;
    243 		}
    244 		(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
    245 		dp = inodebuf;
    246 	}
    247 	return (dp++);
    248 }
    249 
    250 resetinodebuf()
    251 {
    252 
    253 	startinum = 0;
    254 	nextino = 0;
    255 	lastinum = 0;
    256 	readcnt = 0;
    257 	inobufsize = blkroundup(&sblock, INOBUFSIZE);
    258 	fullcnt = inobufsize / sizeof(struct dinode);
    259 	readpercg = sblock.fs_ipg / fullcnt;
    260 	partialcnt = sblock.fs_ipg % fullcnt;
    261 	partialsize = partialcnt * sizeof(struct dinode);
    262 	if (partialcnt != 0) {
    263 		readpercg++;
    264 	} else {
    265 		partialcnt = fullcnt;
    266 		partialsize = inobufsize;
    267 	}
    268 	if (inodebuf == NULL &&
    269 	    (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
    270 		errexit("Cannot allocate space for inode buffer\n");
    271 	while (nextino < ROOTINO)
    272 		(void)getnextinode(nextino);
    273 }
    274 
    275 freeinodebuf()
    276 {
    277 
    278 	if (inodebuf != NULL)
    279 		free((char *)inodebuf);
    280 	inodebuf = NULL;
    281 }
    282 
    283 /*
    284  * Routines to maintain information about directory inodes.
    285  * This is built during the first pass and used during the
    286  * second and third passes.
    287  *
    288  * Enter inodes into the cache.
    289  */
    290 cacheino(dp, inumber)
    291 	register struct dinode *dp;
    292 	ino_t inumber;
    293 {
    294 	register struct inoinfo *inp;
    295 	struct inoinfo **inpp;
    296 	unsigned int blks;
    297 
    298 	blks = howmany(dp->di_size, sblock.fs_bsize);
    299 	if (blks > NDADDR)
    300 		blks = NDADDR + NIADDR;
    301 	inp = (struct inoinfo *)
    302 		malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t));
    303 	if (inp == NULL)
    304 		return;
    305 	inpp = &inphead[inumber % numdirs];
    306 	inp->i_nexthash = *inpp;
    307 	*inpp = inp;
    308 	inp->i_parent = (ino_t)0;
    309 	inp->i_dotdot = (ino_t)0;
    310 	inp->i_number = inumber;
    311 	inp->i_isize = dp->di_size;
    312 	inp->i_numblks = blks * sizeof(daddr_t);
    313 	bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0],
    314 	    (size_t)inp->i_numblks);
    315 	if (inplast == listmax) {
    316 		listmax += 100;
    317 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
    318 		    (unsigned)listmax * sizeof(struct inoinfo *));
    319 		if (inpsort == NULL)
    320 			errexit("cannot increase directory list");
    321 	}
    322 	inpsort[inplast++] = inp;
    323 }
    324 
    325 /*
    326  * Look up an inode cache structure.
    327  */
    328 struct inoinfo *
    329 getinoinfo(inumber)
    330 	ino_t inumber;
    331 {
    332 	register struct inoinfo *inp;
    333 
    334 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
    335 		if (inp->i_number != inumber)
    336 			continue;
    337 		return (inp);
    338 	}
    339 	errexit("cannot find inode %d\n", inumber);
    340 	return ((struct inoinfo *)0);
    341 }
    342 
    343 /*
    344  * Clean up all the inode cache structure.
    345  */
    346 inocleanup()
    347 {
    348 	register struct inoinfo **inpp;
    349 
    350 	if (inphead == NULL)
    351 		return;
    352 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
    353 		free((char *)(*inpp));
    354 	free((char *)inphead);
    355 	free((char *)inpsort);
    356 	inphead = inpsort = NULL;
    357 }
    358 
    359 inodirty()
    360 {
    361 
    362 	dirty(pbp);
    363 }
    364 
    365 clri(idesc, type, flag)
    366 	register struct inodesc *idesc;
    367 	char *type;
    368 	int flag;
    369 {
    370 	register struct dinode *dp;
    371 
    372 	dp = ginode(idesc->id_number);
    373 	if (flag == 1) {
    374 		pwarn("%s %s", type,
    375 		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
    376 		pinode(idesc->id_number);
    377 	}
    378 	if (preen || reply("CLEAR") == 1) {
    379 		if (preen)
    380 			printf(" (CLEARED)\n");
    381 		n_files--;
    382 		(void)ckinode(dp, idesc);
    383 		clearinode(dp);
    384 		statemap[idesc->id_number] = USTATE;
    385 		inodirty();
    386 	}
    387 }
    388 
    389 findname(idesc)
    390 	struct inodesc *idesc;
    391 {
    392 	register struct direct *dirp = idesc->id_dirp;
    393 
    394 	if (dirp->d_ino != idesc->id_parent)
    395 		return (KEEPON);
    396 	bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1);
    397 	return (STOP|FOUND);
    398 }
    399 
    400 findino(idesc)
    401 	struct inodesc *idesc;
    402 {
    403 	register struct direct *dirp = idesc->id_dirp;
    404 
    405 	if (dirp->d_ino == 0)
    406 		return (KEEPON);
    407 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
    408 	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
    409 		idesc->id_parent = dirp->d_ino;
    410 		return (STOP|FOUND);
    411 	}
    412 	return (KEEPON);
    413 }
    414 
    415 pinode(ino)
    416 	ino_t ino;
    417 {
    418 	register struct dinode *dp;
    419 	register char *p;
    420 	struct passwd *pw;
    421 	char *ctime();
    422 
    423 	printf(" I=%lu ", ino);
    424 	if (ino < ROOTINO || ino > maxino)
    425 		return;
    426 	dp = ginode(ino);
    427 	printf(" OWNER=");
    428 #ifndef SMALL
    429 	if ((pw = getpwuid((int)dp->di_uid)) != 0)
    430 		printf("%s ", pw->pw_name);
    431 	else
    432 #endif
    433 		printf("%u ", (unsigned)dp->di_uid);
    434 	printf("MODE=%o\n", dp->di_mode);
    435 	if (preen)
    436 		printf("%s: ", devname);
    437 	printf("SIZE=%lu ", dp->di_size);
    438 	p = ctime(&dp->di_mtime);
    439 	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
    440 }
    441 
    442 blkerror(ino, type, blk)
    443 	ino_t ino;
    444 	char *type;
    445 	daddr_t blk;
    446 {
    447 
    448 	pfatal("%ld %s I=%lu", blk, type, ino);
    449 	printf("\n");
    450 	switch (statemap[ino]) {
    451 
    452 	case FSTATE:
    453 		statemap[ino] = FCLEAR;
    454 		return;
    455 
    456 	case DSTATE:
    457 		statemap[ino] = DCLEAR;
    458 		return;
    459 
    460 	case FCLEAR:
    461 	case DCLEAR:
    462 		return;
    463 
    464 	default:
    465 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
    466 		/* NOTREACHED */
    467 	}
    468 }
    469 
    470 /*
    471  * allocate an unused inode
    472  */
    473 ino_t
    474 allocino(request, type)
    475 	ino_t request;
    476 	int type;
    477 {
    478 	register ino_t ino;
    479 	register struct dinode *dp;
    480 
    481 	if (request == 0)
    482 		request = ROOTINO;
    483 	else if (statemap[request] != USTATE)
    484 		return (0);
    485 	for (ino = request; ino < maxino; ino++)
    486 		if (statemap[ino] == USTATE)
    487 			break;
    488 	if (ino == maxino)
    489 		return (0);
    490 	switch (type & IFMT) {
    491 	case IFDIR:
    492 		statemap[ino] = DSTATE;
    493 		break;
    494 	case IFREG:
    495 	case IFLNK:
    496 		statemap[ino] = FSTATE;
    497 		break;
    498 	default:
    499 		return (0);
    500 	}
    501 	dp = ginode(ino);
    502 	dp->di_db[0] = allocblk((long)1);
    503 	if (dp->di_db[0] == 0) {
    504 		statemap[ino] = USTATE;
    505 		return (0);
    506 	}
    507 	dp->di_mode = type;
    508 	(void)time(&dp->di_atime);
    509 	dp->di_mtime = dp->di_ctime = dp->di_atime;
    510 	dp->di_size = sblock.fs_fsize;
    511 	dp->di_blocks = btodb(sblock.fs_fsize);
    512 	n_files++;
    513 	inodirty();
    514 	return (ino);
    515 }
    516 
    517 /*
    518  * deallocate an inode
    519  */
    520 freeino(ino)
    521 	ino_t ino;
    522 {
    523 	struct inodesc idesc;
    524 	extern int pass4check();
    525 	struct dinode *dp;
    526 
    527 	bzero((char *)&idesc, sizeof(struct inodesc));
    528 	idesc.id_type = ADDR;
    529 	idesc.id_func = pass4check;
    530 	idesc.id_number = ino;
    531 	dp = ginode(ino);
    532 	(void)ckinode(dp, &idesc);
    533 	clearinode(dp);
    534 	inodirty();
    535 	statemap[ino] = USTATE;
    536 	n_files--;
    537 }
    538