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