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