Home | History | Annotate | Line # | Download | only in fsck_lfs
inode.c revision 1.15
      1 /* $NetBSD: inode.c,v 1.15 2003/02/17 23:48:09 perseant Exp $	 */
      2 
      3 /*
      4  * Copyright (c) 1997, 1998
      5  *      Konrad Schroder.  All rights reserved.
      6  * Copyright (c) 1980, 1986, 1993
      7  *	The Regents of the University of California.  All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *	This product includes software developed by the University of
     20  *	California, Berkeley and its contributors.
     21  * 4. Neither the name of the University nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  */
     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 <sys/mount.h>		/* XXX */
     43 #include <ufs/lfs/lfs.h>
     44 #include <ufs/lfs/lfs_extern.h>
     45 #ifndef SMALL
     46 #include <pwd.h>
     47 #endif
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 
     52 #include "fsck.h"
     53 #include "fsutil.h"
     54 #include "extern.h"
     55 
     56 extern SEGUSE  *seg_table;
     57 extern daddr_t *din_table;
     58 
     59 static int      iblock(struct inodesc *, long, u_int64_t);
     60 int             blksreqd(struct lfs *, int);
     61 int             lfs_maxino(void);
     62 /* static void dump_inoblk (struct lfs *, struct dinode *); */
     63 
     64 /* stolen from lfs_inode.c */
     65 /* Search a block for a specific dinode. */
     66 struct dinode  *
     67 lfs_difind(struct lfs * fs, ino_t ino, struct dinode * dip)
     68 {
     69 	struct dinode *ldip, *fin;
     70 
     71 #ifdef LFS_IFILE_FRAG_ADDRESSING
     72 	if (fs->lfs_version == 1)
     73 		fin = dip + INOPB(fs);
     74 	else
     75 		fin = dip + INOPF(fs);
     76 #else
     77 	fin = dip + INOPB(fs);
     78 #endif
     79 
     80 	for (ldip = dip; ldip < fin; ++ldip) {
     81 		if (ldip->di_inumber == ino)
     82 			return ldip;
     83 	}
     84 	/* printf("lfs_difind: dinode %u not found\n", ino); */
     85 	return NULL;
     86 }
     87 
     88 /*
     89  * Calculate the number of blocks required to be able to address data block
     90  * blkno (counting, of course, indirect blocks).  blkno must >=0.
     91  */
     92 int
     93 blksreqd(struct lfs * fs, int blkno)
     94 {
     95 	long            n = blkno;
     96 
     97 	if (blkno < NDADDR)
     98 		return blkno;
     99 	n -= NDADDR;
    100 	if (n < NINDIR(fs))
    101 		return blkno + 1;
    102 	n -= NINDIR(fs);
    103 	if (n < NINDIR(fs) * NINDIR(fs))
    104 		return blkno + 2 + n / NINDIR(fs) + 1;
    105 	n -= NINDIR(fs) * NINDIR(fs);
    106 	return blkno + 2 + NINDIR(fs) + n / (NINDIR(fs) * NINDIR(fs)) + 1;
    107 }
    108 
    109 #define BASE_SINDIR (NDADDR)
    110 #define BASE_DINDIR (NDADDR+NINDIR(fs))
    111 #define BASE_TINDIR (NDADDR+NINDIR(fs)+NINDIR(fs)*NINDIR(fs))
    112 
    113 #define D_UNITS (NINDIR(fs))
    114 #define T_UNITS (NINDIR(fs)*NINDIR(fs))
    115 
    116 daddr_t     lfs_bmap(struct lfs *, struct dinode *, daddr_t);
    117 
    118 daddr_t
    119 lfs_bmap(struct lfs * fs, struct dinode * idinode, daddr_t lbn)
    120 {
    121 	daddr_t     residue, up, off = 0;
    122 	struct bufarea *bp;
    123 
    124 	if (lbn > 0 && lbn > (idinode->di_size - 1) / dev_bsize) {
    125 		return UNASSIGNED;
    126 	}
    127 	/*
    128 	 * Indirect blocks: if it is a first-level indirect, pull its
    129 	 * address from the inode; otherwise, call ourselves to find the
    130 	 * address of the parent indirect block, and load that to find
    131 	 * the desired address.
    132 	 */
    133 	if (lbn < 0) {
    134 		lbn *= -1;
    135 		if (lbn == NDADDR) {
    136 			/* printf("lbn %d: single indir base\n", -lbn); */
    137 			return idinode->di_ib[0];	/* single indirect */
    138 		} else if (lbn == BASE_DINDIR + 1) {
    139 			/* printf("lbn %d: double indir base\n", -lbn); */
    140 			return idinode->di_ib[1];	/* double indirect */
    141 		} else if (lbn == BASE_TINDIR + 2) {
    142 			/* printf("lbn %d: triple indir base\n", -lbn); */
    143 			return idinode->di_ib[2];	/* triple indirect */
    144 		}
    145 		/*
    146 		 * Find the immediate parent. This is essentially finding the
    147 		 * residue of modulus, and then rounding accordingly.
    148 		 */
    149 		residue = (lbn - NDADDR) % NINDIR(fs);
    150 		if (residue == 1) {
    151 			/* Double indirect.  Parent is the triple. */
    152 			up = idinode->di_ib[2];
    153 			off = (lbn - 2 - BASE_TINDIR) / (NINDIR(fs) * NINDIR(fs));
    154 			if (up == UNASSIGNED || up == LFS_UNUSED_DADDR)
    155 				return UNASSIGNED;
    156 			/* printf("lbn %d: parent is the triple\n", -lbn); */
    157 			bp = getddblk(up, sblock.lfs_bsize);
    158 			bp->b_flags &= ~B_INUSE;
    159 			return (daddr_t)(((int32_t *)(bp->b_un.b_buf))[off]);
    160 		} else {	/* residue == 0 */
    161 			/* Single indirect.  Two cases. */
    162 			if (lbn < BASE_TINDIR) {
    163 				/* Parent is the double, simple */
    164 				up = -(BASE_DINDIR) - 1;
    165 				off = (lbn - BASE_DINDIR) / D_UNITS;
    166 				/*
    167 				 * printf("lbn %d: parent is %d/%d\n", -lbn,
    168 				 * up,off);
    169 				 */
    170 			} else {
    171 				/* Ancestor is the triple, more complex */
    172 				up = ((lbn - BASE_TINDIR) / T_UNITS)
    173 					* T_UNITS + BASE_TINDIR + 1;
    174 				off = (lbn / D_UNITS) - (up / D_UNITS);
    175 				up = -up;
    176 				/*
    177 				 * printf("lbn %d: parent is %d/%d\n", -lbn,
    178 				 * up,off);
    179 				 */
    180 			}
    181 		}
    182 	} else {
    183 		/* Direct block.  Its parent must be a single indirect. */
    184 		if (lbn < NDADDR)
    185 			return idinode->di_db[lbn];
    186 		else {
    187 			/* Parent is an indirect block. */
    188 			up = -(((lbn - NDADDR) / D_UNITS) * D_UNITS + NDADDR);
    189 			off = (lbn - NDADDR) % D_UNITS;
    190 			/* printf("lbn %d: parent is %d/%d\n", lbn,up,off); */
    191 		}
    192 	}
    193 	up = lfs_bmap(fs, idinode, up);
    194 	if (up == UNASSIGNED || up == LFS_UNUSED_DADDR)
    195 		return UNASSIGNED;
    196 	bp = getddblk(up, sblock.lfs_bsize);
    197 	bp->b_flags &= ~B_INUSE;
    198 	/* XXX ondisk32 */
    199 	return (daddr_t)(((int32_t *)(bp->b_un.b_buf))[off]);
    200 }
    201 
    202 /*
    203  * This is kind of gross.  We use this to find the nth block
    204  * from a file whose inode has disk address idaddr.  In practice
    205  * we will only use this to find blocks of the ifile.
    206  */
    207 static struct bufarea empty;
    208 
    209 struct bufarea *
    210 getfileblk(struct lfs * fs, struct dinode * idinode, ino_t lbn)
    211 {
    212 	struct bufarea *bp;
    213 	daddr_t     blkno;
    214 	static char     empty_buf[65536];
    215 
    216 	empty.b_un.b_buf = &(empty_buf[0]);
    217 
    218 	blkno = lfs_bmap(fs, idinode, lbn);
    219 	if (blkno == UNASSIGNED || blkno == LFS_UNUSED_DADDR) {
    220 		printf("Warning: ifile lbn %d unassigned!\n", lbn);
    221 		return &empty;
    222 	}
    223 	bp = getddblk(blkno, sblock.lfs_bsize);
    224 	return bp;
    225 }
    226 
    227 #if 0
    228 static struct dinode *
    229 gidinode(void)
    230 {
    231 	static struct dinode *idinode;
    232 
    233 	if (!idinode) {		/* only need to do this once */
    234 		idinode = lfs_difind(&sblock, sblock.lfs_ifile, &ifblock);
    235 	}
    236 	return idinode;
    237 }
    238 #endif
    239 
    240 struct ifile   *
    241 lfs_ientry(ino_t ino, struct bufarea ** bpp)
    242 {
    243 	IFILE *ifp;
    244 
    245 	*bpp = getfileblk(&sblock, lfs_ginode(LFS_IFILE_INUM),
    246 			  ino / sblock.lfs_ifpb + sblock.lfs_cleansz +
    247 			  sblock.lfs_segtabsz);
    248 	if (*bpp == &empty) {
    249 		printf("Warning: ino %d ientry in unassigned block\n", ino);
    250 	}
    251 	if (*bpp) {
    252 		if (sblock.lfs_version > 1) {
    253 			ifp = (((IFILE *)((*bpp)->b_un.b_buf)) +
    254 			       (ino % sblock.lfs_ifpb));
    255 		} else {
    256 			ifp = (IFILE *)(((IFILE_V1 *)
    257 					 ((*bpp)->b_un.b_buf)) +
    258 					(ino % sblock.lfs_ifpb));
    259 		}
    260 		return ifp;
    261 	} else
    262 		return NULL;
    263 }
    264 
    265 SEGUSE         *
    266 lfs_gseguse(int segnum, struct bufarea ** bpp)
    267 {
    268 	int             blkno;
    269 	struct bufarea *bp;
    270 
    271 	blkno = segnum / sblock.lfs_sepb + sblock.lfs_cleansz;
    272 	(*bpp) = bp = getfileblk(&sblock, lfs_ginode(LFS_IFILE_INUM), blkno);
    273 	if (sblock.lfs_version == 1)
    274 		return (SEGUSE *)((SEGUSE_V1 *)(bp->b_un.b_buf) +
    275 				  segnum % sblock.lfs_sepb);
    276 	else
    277 		return (SEGUSE *)(bp->b_un.b_buf) + segnum % sblock.lfs_sepb;
    278 }
    279 
    280 daddr_t
    281 lfs_ino_daddr(ino_t inumber)
    282 {
    283 	daddr_t         daddr;
    284 	IFILE          *ifp;
    285 	struct bufarea *bp;
    286 
    287 	if (din_table[inumber]) {
    288 		daddr = din_table[inumber];
    289 	} else {
    290 		if (inumber == LFS_IFILE_INUM)
    291 			daddr = idaddr;
    292 		else {
    293 			ifp = lfs_ientry(inumber, &bp);
    294 			if (ifp == NULL) {
    295 				return NULL;
    296 			}
    297 			if (ifp->if_daddr == LFS_UNUSED_DADDR) {
    298 				bp->b_flags &= ~B_INUSE;
    299 				return NULL;
    300 			}
    301 			bp->b_flags &= ~B_INUSE;
    302 			daddr = ifp->if_daddr;
    303 		}
    304 
    305 		din_table[inumber] = daddr;
    306 		seg_table[dtosn(&sblock, daddr)].su_nbytes += DINODE_SIZE;
    307 	}
    308 	return daddr;
    309 }
    310 
    311 struct dinode  *
    312 lfs_ginode(ino_t inumber)
    313 {
    314 	struct ifile   *ifp;
    315 	struct dinode  *din;
    316 	struct bufarea *bp;
    317 	daddr_t         daddr;
    318 
    319 	if (inumber >= maxino)
    320 		errexit("bad inode number %d to lfs_ginode\n", inumber);
    321 
    322 #if 0
    323 	if (inumber == LFS_IFILE_INUM) {
    324 		daddr = idaddr;
    325 		if (din_table[LFS_IFILE_INUM] == 0) {
    326 			din_table[LFS_IFILE_INUM] = daddr;
    327 			seg_table[dtosn(&sblock, daddr)].su_nbytes += DINODE_SIZE;
    328 		}
    329 		return gidinode();
    330 	}
    331 #endif
    332 
    333 	daddr = lfs_ino_daddr(inumber);
    334 	if (daddr == 0)
    335 		return NULL;
    336 
    337 	if (pbp)
    338 		pbp->b_flags &= ~B_INUSE;
    339 
    340 	if (sblock.lfs_version == 1)
    341 		pbp = getddblk(daddr, sblock.lfs_bsize);
    342 	else
    343 		pbp = getddblk(daddr, sblock.lfs_fsize);
    344 	din = lfs_difind(&sblock, inumber, pbp->b_un.b_dinode);
    345 
    346 	if (din == NULL) {
    347 		pfatal("INODE %d NOT FOUND\n", inumber);
    348 		if (reply("free")) {
    349 			ifp = lfs_ientry(inumber, &bp);
    350 			ifp->if_daddr = LFS_UNUSED_DADDR;
    351 			ifp->if_nextfree = sblock.lfs_freehd;
    352 			sblock.lfs_freehd = inumber;
    353 			sbdirty();
    354 			dirty(bp);
    355 			bp->b_flags &= ~B_INUSE;
    356 		}
    357 	}
    358 	return din;
    359 }
    360 
    361 /* imported from lfs_vfsops.c */
    362 int
    363 ino_to_fsba(struct lfs * fs, ino_t ino)
    364 {
    365 	daddr_t         daddr = LFS_UNUSED_DADDR;
    366 	struct ifile   *ifp;
    367 	struct bufarea *bp;
    368 
    369 	/* Translate the inode number to a disk address. */
    370 	if (ino == LFS_IFILE_INUM)
    371 		daddr = fs->lfs_idaddr;
    372 	else {
    373 		ifp = lfs_ientry(ino, &bp);
    374 		if (ifp) {
    375 			daddr = ifp->if_daddr;
    376 		} else {
    377 			pwarn("Can't locate inode #%ud\n", ino);
    378 		}
    379 		bp->b_flags &= ~B_INUSE;
    380 	}
    381 	return daddr;
    382 }
    383 
    384 /*
    385  * Check validity of held (direct) blocks in an inode.
    386  */
    387 int
    388 ckinode(struct dinode *dp, struct inodesc *idesc)
    389 {
    390 	/* XXX ondisk32 */
    391 	register int32_t *ap;
    392 	long            ret, n, ndb, offset;
    393 	struct dinode   dino;
    394 	u_int64_t       remsize, sizepb;
    395 	mode_t          mode;
    396 	char            pathbuf[MAXPATHLEN + 1];
    397 
    398 	if (idesc->id_fix != IGNORE)
    399 		idesc->id_fix = DONTKNOW;
    400 	idesc->id_entryno = 0;
    401 	idesc->id_filesize = dp->di_size;
    402 	mode = dp->di_mode & IFMT;
    403 	if (mode == IFBLK || mode == IFCHR ||
    404 	    (mode == IFLNK && (dp->di_size < sblock.lfs_maxsymlinklen ||
    405 	                       (sblock.lfs_maxsymlinklen == 0 &&
    406 				dp->di_blocks == 0))))
    407 		return (KEEPON);
    408 	dino = *dp;
    409 	ndb = howmany(dino.di_size, sblock.lfs_bsize);
    410 
    411 	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
    412 		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) {
    413 			idesc->id_numfrags =
    414 				numfrags(&sblock, fragroundup(&sblock, offset));
    415 		} else
    416 			idesc->id_numfrags = sblock.lfs_frag;
    417 		if (*ap == 0) {
    418 			if (idesc->id_type == DATA && ndb >= 0) {
    419 				/* An empty block in a directory XXX */
    420 				getpathname(pathbuf, idesc->id_number,
    421 					    idesc->id_number);
    422 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
    423 				       pathbuf);
    424 				if (reply("ADJUST LENGTH") == 1) {
    425 					dp = ginode(idesc->id_number);
    426 					dp->di_size = (ap - &dino.di_db[0]) *
    427 						sblock.lfs_bsize;
    428 					printf(
    429 					"YOU MUST RERUN FSCK AFTERWARDS\n");
    430 					rerun = 1;
    431 					inodirty();
    432 				}
    433 			}
    434 			continue;
    435 		}
    436 		idesc->id_blkno = *ap;
    437 		idesc->id_lblkno = ap - &dino.di_db[0];
    438 		if (idesc->id_type == ADDR) {
    439 			ret = (*idesc->id_func)(idesc);
    440 		} else
    441 			ret = dirscan(idesc);
    442 		idesc->id_lblkno = 0;
    443 		if (ret & STOP)
    444 			return (ret);
    445 	}
    446 	idesc->id_numfrags = sblock.lfs_frag;
    447 	remsize = dino.di_size - sblock.lfs_bsize * NDADDR;
    448 	sizepb = sblock.lfs_bsize;
    449 	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
    450 		if (*ap) {
    451 			idesc->id_blkno = *ap;
    452 			ret = iblock(idesc, n, remsize);
    453 			if (ret & STOP)
    454 				return (ret);
    455 		} else {
    456 			if (idesc->id_type == DATA && remsize > 0) {
    457 				/* An empty block in a directory XXX */
    458 				getpathname(pathbuf, idesc->id_number,
    459 					    idesc->id_number);
    460 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
    461 				       pathbuf);
    462 				if (reply("ADJUST LENGTH") == 1) {
    463 					dp = ginode(idesc->id_number);
    464 					dp->di_size -= remsize;
    465 					remsize = 0;
    466 					printf(
    467 					"YOU MUST RERUN FSCK AFTERWARDS\n");
    468 					rerun = 1;
    469 					inodirty();
    470 					break;
    471 				}
    472 			}
    473 		}
    474 		sizepb *= NINDIR(&sblock);
    475 		remsize -= sizepb;
    476 	}
    477 	return (KEEPON);
    478 }
    479 
    480 static int
    481 iblock(struct inodesc * idesc, long ilevel, u_int64_t isize)
    482 {
    483 	/* XXX ondisk32 */
    484 	int32_t	       *ap, *aplim;
    485 	struct bufarea *bp;
    486 	int             i, n, (*func)(struct inodesc *), nif;
    487 	u_int64_t       sizepb;
    488 	char            pathbuf[MAXPATHLEN + 1], buf[BUFSIZ];
    489 	struct dinode  *dp;
    490 
    491 	if (idesc->id_type == ADDR) {
    492 		func = idesc->id_func;
    493 		n = (*func)(idesc);
    494 		if ((n & KEEPON) == 0)
    495 			return (n);
    496 	} else
    497 		func = dirscan;
    498 	if (chkrange(idesc->id_blkno, fragstofsb(&sblock, idesc->id_numfrags)))
    499 		return (SKIP);
    500 	bp = getddblk(idesc->id_blkno, sblock.lfs_bsize);
    501 	ilevel--;
    502 	for (sizepb = sblock.lfs_bsize, i = 0; i < ilevel; i++)
    503 		sizepb *= NINDIR(&sblock);
    504 	if (isize > sizepb * NINDIR(&sblock))
    505 		nif = NINDIR(&sblock);
    506 	else
    507 		nif = howmany(isize, sizepb);
    508 	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
    509 		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
    510 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
    511 			if (*ap == 0)
    512 				continue;
    513 			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%u",
    514 					      idesc->id_number);
    515 			if (dofix(idesc, buf)) {
    516 				*ap = 0;
    517 				dirty(bp);
    518 			}
    519 		}
    520 		flush(fswritefd, bp);
    521 	}
    522 	aplim = &bp->b_un.b_indir[nif];
    523 	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
    524 		if (*ap) {
    525 			idesc->id_blkno = *ap;
    526 			if (ilevel == 0)
    527 				n = (*func)(idesc);
    528 			else
    529 				n = iblock(idesc, ilevel, isize);
    530 			if (n & STOP) {
    531 				bp->b_flags &= ~B_INUSE;
    532 				return (n);
    533 			}
    534 		} else {
    535 			if (idesc->id_type == DATA && isize > 0) {
    536 				/* An empty block in a directory XXX */
    537 				getpathname(pathbuf, idesc->id_number,
    538 					    idesc->id_number);
    539 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
    540 				       pathbuf);
    541 				if (reply("ADJUST LENGTH") == 1) {
    542 					dp = ginode(idesc->id_number);
    543 					dp->di_size -= isize;
    544 					isize = 0;
    545 					printf(
    546 					"YOU MUST RERUN FSCK AFTERWARDS\n");
    547 					rerun = 1;
    548 					inodirty();
    549 					bp->b_flags &= ~B_INUSE;
    550 					return (STOP);
    551 				}
    552 			}
    553 		}
    554 		isize -= sizepb;
    555 	}
    556 	bp->b_flags &= ~B_INUSE;
    557 	return (KEEPON);
    558 }
    559 
    560 /*
    561  * Check that a block in a legal block number.
    562  * Return 0 if in range, 1 if out of range.
    563  */
    564 int
    565 chkrange(daddr_t blk, int cnt)
    566 {
    567 	if (blk < sntod(&sblock, 0)) {
    568 		return (1);
    569 	}
    570 	if (blk > maxfsblock) {
    571 		return (1);
    572 	}
    573 	if (blk + cnt < sntod(&sblock, 0)) {
    574 		return (1);
    575 	}
    576 	if (blk + cnt > maxfsblock) {
    577 		return (1);
    578 	}
    579 	return (0);
    580 }
    581 
    582 /*
    583  * General purpose interface for reading inodes.
    584  */
    585 struct dinode  *
    586 ginode(ino_t inumber)
    587 {
    588 	return lfs_ginode(inumber);
    589 }
    590 
    591 /*
    592  * Routines to maintain information about directory inodes.
    593  * This is built during the first pass and used during the
    594  * second and third passes.
    595  *
    596  * Enter inodes into the cache.
    597  */
    598 void
    599 cacheino(struct dinode *dp, ino_t inumber)
    600 {
    601 	register struct inoinfo *inp;
    602 	struct inoinfo **inpp;
    603 	unsigned int    blks;
    604 
    605 	blks = howmany(dp->di_size, sblock.lfs_bsize);
    606 	if (blks > NDADDR)
    607 		blks = NDADDR + NIADDR;
    608 	/* XXX ondisk32 */
    609 	inp = (struct inoinfo *)
    610 		malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t));
    611 	if (inp == NULL)
    612 		return;
    613 	inpp = &inphead[inumber % numdirs];
    614 	inp->i_nexthash = *inpp;
    615 	*inpp = inp;
    616 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
    617 	if (inumber == ROOTINO)
    618 		inp->i_parent = ROOTINO;
    619 	else
    620 		inp->i_parent = (ino_t)0;
    621 	inp->i_dotdot = (ino_t)0;
    622 	inp->i_number = inumber;
    623 	inp->i_isize = dp->di_size;
    624 	/* XXX ondisk32 */
    625 	inp->i_numblks = blks * sizeof(int32_t);
    626 	memcpy(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
    627 	if (inplast == listmax) {
    628 		listmax += 100;
    629 		inpsort = (struct inoinfo **)realloc((char *) inpsort,
    630 			     (unsigned)listmax * sizeof(struct inoinfo *));
    631 		if (inpsort == NULL)
    632 			errexit("cannot increase directory list\n");
    633 	}
    634 	inpsort[inplast++] = inp;
    635 }
    636 
    637 /*
    638  * Look up an inode cache structure.
    639  */
    640 struct inoinfo *
    641 getinoinfo(ino_t inumber)
    642 {
    643 	register struct inoinfo *inp;
    644 
    645 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
    646 		if (inp->i_number != inumber)
    647 			continue;
    648 		return (inp);
    649 	}
    650 	errexit("cannot find inode %d\n", inumber);
    651 	return ((struct inoinfo *)0);
    652 }
    653 
    654 /*
    655  * Clean up all the inode cache structure.
    656  */
    657 void
    658 inocleanup()
    659 {
    660 	register struct inoinfo **inpp;
    661 
    662 	if (inphead == NULL)
    663 		return;
    664 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
    665 		free((char *)(*inpp));
    666 	free((char *)inphead);
    667 	free((char *)inpsort);
    668 	inphead = inpsort = NULL;
    669 }
    670 
    671 void
    672 inodirty()
    673 {
    674 	dirty(pbp);
    675 }
    676 
    677 void
    678 clri(struct inodesc *idesc, char *type, int flag)
    679 {
    680 	register struct dinode *dp;
    681 	struct bufarea *bp;
    682 	IFILE          *ifp;
    683 
    684 	dp = ginode(idesc->id_number);
    685 	if (flag == 1) {
    686 		pwarn("%s %s", type,
    687 		      (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
    688 		pinode(idesc->id_number);
    689 	}
    690 	if (preen || reply("CLEAR") == 1) {
    691 		if (preen)
    692 			printf(" (CLEARED)\n");
    693 		n_files--;
    694 		(void)ckinode(dp, idesc);
    695 		clearinode(dp);
    696 		statemap[idesc->id_number] = USTATE;
    697 		inodirty();
    698 
    699 		/* Send cleared inode to the free list */
    700 
    701 		ifp = lfs_ientry(idesc->id_number, &bp);
    702 		ifp->if_daddr = LFS_UNUSED_DADDR;
    703 		ifp->if_nextfree = sblock.lfs_freehd;
    704 		sblock.lfs_freehd = idesc->id_number;
    705 		sbdirty();
    706 		dirty(bp);
    707 		bp->b_flags &= ~B_INUSE;
    708 	}
    709 }
    710 
    711 int
    712 findname(struct inodesc *idesc)
    713 {
    714 	register struct direct *dirp = idesc->id_dirp;
    715 
    716 	if (dirp->d_ino != idesc->id_parent)
    717 		return (KEEPON);
    718 	memcpy(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
    719 	return (STOP | FOUND);
    720 }
    721 
    722 int
    723 findino(struct inodesc *idesc)
    724 {
    725 	register struct direct *dirp = idesc->id_dirp;
    726 
    727 	if (dirp->d_ino == 0)
    728 		return (KEEPON);
    729 	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
    730 	    dirp->d_ino >= ROOTINO && dirp->d_ino < maxino) {
    731 		idesc->id_parent = dirp->d_ino;
    732 		return (STOP | FOUND);
    733 	}
    734 	return (KEEPON);
    735 }
    736 
    737 void
    738 pinode(ino_t ino)
    739 {
    740 	register struct dinode *dp;
    741 	register char  *p;
    742 	struct passwd  *pw;
    743 	time_t          t;
    744 
    745 	printf(" I=%u ", ino);
    746 	if (ino < ROOTINO || ino >= maxino)
    747 		return;
    748 	dp = ginode(ino);
    749 	if (dp) {
    750 		printf(" OWNER=");
    751 #ifndef SMALL
    752 		if ((pw = getpwuid((int)dp->di_uid)) != 0)
    753 			printf("%s ", pw->pw_name);
    754 		else
    755 #endif
    756 			printf("%u ", (unsigned)dp->di_uid);
    757 		printf("MODE=%o\n", dp->di_mode);
    758 		if (preen)
    759 			printf("%s: ", cdevname());
    760 		printf("SIZE=%llu ", (unsigned long long)dp->di_size);
    761 		t = dp->di_mtime;
    762 		p = ctime(&t);
    763 		printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
    764 	}
    765 }
    766 
    767 void
    768 blkerror(ino_t ino, char *type, daddr_t blk)
    769 {
    770 
    771 	pfatal("%lld %s I=%u", (long long)blk, type, ino);
    772 	printf("\n");
    773 	if (exitonfail)
    774 		exit(1);
    775 	switch (statemap[ino]) {
    776 
    777 	case FSTATE:
    778 		statemap[ino] = FCLEAR;
    779 		return;
    780 
    781 	case DSTATE:
    782 		statemap[ino] = DCLEAR;
    783 		return;
    784 
    785 	case FCLEAR:
    786 	case DCLEAR:
    787 		return;
    788 
    789 	default:
    790 		errexit("BAD STATE %d TO BLKERR\n", statemap[ino]);
    791 		/* NOTREACHED */
    792 	}
    793 }
    794 
    795 /*
    796  * allocate an unused inode
    797  */
    798 ino_t
    799 allocino(ino_t request, int type)
    800 {
    801 	register ino_t  ino;
    802 	register struct dinode *dp;
    803 	time_t          t;
    804 
    805 	if (request == 0)
    806 		request = ROOTINO;
    807 	else if (statemap[request] != USTATE)
    808 		return (0);
    809 	for (ino = request; ino < maxino; ino++)
    810 		if (statemap[ino] == USTATE)
    811 			break;
    812 	if (ino == maxino)
    813 		return (0);
    814 	switch (type & IFMT) {
    815 	case IFDIR:
    816 		statemap[ino] = DSTATE;
    817 		break;
    818 	case IFREG:
    819 	case IFLNK:
    820 		statemap[ino] = FSTATE;
    821 		break;
    822 	default:
    823 		return (0);
    824 	}
    825 	dp = ginode(ino);
    826 	dp->di_db[0] = allocblk((long)1);
    827 	if (dp->di_db[0] == 0) {
    828 		statemap[ino] = USTATE;
    829 		return (0);
    830 	}
    831 	dp->di_mode = type;
    832 	(void)time(&t);
    833 	dp->di_atime = t;
    834 	dp->di_mtime = dp->di_ctime = dp->di_atime;
    835 	dp->di_size = sblock.lfs_fsize;
    836 	dp->di_blocks = btofsb(&sblock, sblock.lfs_fsize);
    837 	n_files++;
    838 	inodirty();
    839 	if (newinofmt)
    840 		typemap[ino] = IFTODT(type);
    841 	return (ino);
    842 }
    843 
    844 /*
    845  * deallocate an inode
    846  */
    847 void
    848 freeino(ino_t ino)
    849 {
    850 	struct inodesc  idesc;
    851 	struct dinode  *dp;
    852 
    853 	memset(&idesc, 0, sizeof(struct inodesc));
    854 	idesc.id_type = ADDR;
    855 	idesc.id_func = pass4check;
    856 	idesc.id_number = ino;
    857 	dp = ginode(ino);
    858 	(void)ckinode(dp, &idesc);
    859 	clearinode(dp);
    860 	inodirty();
    861 	statemap[ino] = USTATE;
    862 
    863 	n_files--;
    864 }
    865