inode.c revision 50476
160812Sps/*
260786Sps * Copyright (c) 1980, 1986, 1993
360786Sps *	The Regents of the University of California.  All rights reserved.
460786Sps *
560786Sps * Redistribution and use in source and binary forms, with or without
660786Sps * modification, are permitted provided that the following conditions
760786Sps * are met:
860786Sps * 1. Redistributions of source code must retain the above copyright
960786Sps *    notice, this list of conditions and the following disclaimer.
1060786Sps * 2. Redistributions in binary form must reproduce the above copyright
1160786Sps *    notice, this list of conditions and the following disclaimer in the
1260786Sps *    documentation and/or other materials provided with the distribution.
1360786Sps * 3. All advertising materials mentioning features or use of this software
1460786Sps *    must display the following acknowledgement:
1560786Sps *	This product includes software developed by the University of
1660786Sps *	California, Berkeley and its contributors.
1760786Sps * 4. Neither the name of the University nor the names of its contributors
1860786Sps *    may be used to endorse or promote products derived from this software
1960786Sps *    without specific prior written permission.
2060786Sps *
2160786Sps * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2260786Sps * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2360786Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2460786Sps * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2560786Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2660812Sps * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2760786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2860786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2960786Sps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3060786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3160786Sps * SUCH DAMAGE.
3260786Sps */
3360786Sps
3460786Sps#ifndef lint
3560786Sps#if 0
3660786Spsstatic const char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
3760786Sps#endif
3860786Spsstatic const char rcsid[] =
3960786Sps  "$FreeBSD: head/sbin/fsck_ffs/inode.c 50476 1999-08-28 00:22:10Z peter $";
4060786Sps#endif /* not lint */
4160786Sps
4260786Sps#include <sys/param.h>
4360786Sps#include <sys/time.h>
4460786Sps
4560786Sps#include <ufs/ufs/dinode.h>
4660786Sps#include <ufs/ufs/dir.h>
4760786Sps#include <ufs/ffs/fs.h>
4860786Sps
4960786Sps#include <err.h>
5060786Sps#include <pwd.h>
5160786Sps#include <string.h>
5260786Sps
5360786Sps#include "fsck.h"
5460786Sps
5560786Spsstatic ino_t startinum;
5660812Sps
5763131Spsstatic int iblock __P((struct inodesc *, long ilevel, quad_t isize));
5860786Sps
5960786Spsint
6060786Spsckinode(dp, idesc)
6160786Sps	struct dinode *dp;
6260786Sps	register struct inodesc *idesc;
6360786Sps{
6460786Sps	ufs_daddr_t *ap;
6560786Sps	int ret;
6660786Sps	long n, ndb, offset;
6760786Sps	struct dinode dino;
6860786Sps	quad_t remsize, sizepb;
6960786Sps	mode_t mode;
7060786Sps	char pathbuf[MAXPATHLEN + 1];
7160786Sps
7260786Sps	if (idesc->id_fix != IGNORE)
7360786Sps		idesc->id_fix = DONTKNOW;
7460786Sps	idesc->id_entryno = 0;
7560786Sps	idesc->id_filesize = dp->di_size;
7660786Sps	mode = dp->di_mode & IFMT;
7760786Sps	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
7860786Sps	    dp->di_size < (unsigned)sblock.fs_maxsymlinklen))
7960786Sps		return (KEEPON);
8060786Sps	dino = *dp;
8160786Sps	ndb = howmany(dino.di_size, sblock.fs_bsize);
8260786Sps	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
8360786Sps		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
8460786Sps			idesc->id_numfrags =
8560786Sps				numfrags(&sblock, fragroundup(&sblock, offset));
8660786Sps		else
8760786Sps			idesc->id_numfrags = sblock.fs_frag;
8860786Sps		if (*ap == 0) {
8960786Sps			if (idesc->id_type == DATA && ndb >= 0) {
9060786Sps				/* An empty block in a directory XXX */
9160786Sps				getpathname(pathbuf, idesc->id_number,
9260786Sps						idesc->id_number);
9360786Sps                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
9460786Sps					pathbuf);
9560786Sps                        	if (reply("ADJUST LENGTH") == 1) {
9660786Sps					dp = ginode(idesc->id_number);
9760786Sps                                	dp->di_size = (ap - &dino.di_db[0]) *
9860786Sps					    sblock.fs_bsize;
9960786Sps					printf(
10060786Sps					    "YOU MUST RERUN FSCK AFTERWARDS\n");
10160786Sps					rerun = 1;
10260786Sps                                	inodirty();
10360786Sps
10460786Sps                        	}
10560786Sps			}
10660786Sps			continue;
10760786Sps		}
10860786Sps		idesc->id_blkno = *ap;
10960786Sps		if (idesc->id_type == ADDR)
11060786Sps			ret = (*idesc->id_func)(idesc);
11160786Sps		else
11260786Sps			ret = dirscan(idesc);
11360786Sps		if (ret & STOP)
11460786Sps			return (ret);
11560786Sps	}
11660786Sps	idesc->id_numfrags = sblock.fs_frag;
11760786Sps	remsize = dino.di_size - sblock.fs_bsize * NDADDR;
11860786Sps	sizepb = sblock.fs_bsize;
11960786Sps	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
12060786Sps		if (*ap) {
12160786Sps			idesc->id_blkno = *ap;
12260786Sps			ret = iblock(idesc, n, remsize);
12360786Sps			if (ret & STOP)
12460786Sps				return (ret);
12560786Sps		} else {
12660786Sps			if (idesc->id_type == DATA && remsize > 0) {
12760786Sps				/* An empty block in a directory XXX */
12860786Sps				getpathname(pathbuf, idesc->id_number,
12960786Sps						idesc->id_number);
13060786Sps                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
13160786Sps					pathbuf);
13260786Sps                        	if (reply("ADJUST LENGTH") == 1) {
13360786Sps					dp = ginode(idesc->id_number);
13460786Sps                                	dp->di_size -= remsize;
13560786Sps					remsize = 0;
13660786Sps					printf(
13760786Sps					    "YOU MUST RERUN FSCK AFTERWARDS\n");
13860786Sps					rerun = 1;
13960786Sps                                	inodirty();
14060786Sps					break;
14160786Sps                        	}
14260786Sps			}
14360786Sps		}
14460786Sps		sizepb *= NINDIR(&sblock);
14560786Sps		remsize -= sizepb;
14660786Sps	}
14760786Sps	return (KEEPON);
14860786Sps}
14960786Sps
15060786Spsstatic int
15160786Spsiblock(idesc, ilevel, isize)
15260786Sps	struct inodesc *idesc;
15360786Sps	long ilevel;
15460786Sps	quad_t isize;
15560786Sps{
15660786Sps	ufs_daddr_t *ap;
15760786Sps	ufs_daddr_t *aplim;
15860786Sps	struct bufarea *bp;
15960786Sps	int i, n, (*func)(), nif;
16060786Sps	quad_t sizepb;
16160786Sps	char buf[BUFSIZ];
16260786Sps	char pathbuf[MAXPATHLEN + 1];
16360786Sps	struct dinode *dp;
16460786Sps
16560786Sps	if (idesc->id_type == ADDR) {
16660786Sps		func = idesc->id_func;
16760786Sps		if (((n = (*func)(idesc)) & KEEPON) == 0)
16860786Sps			return (n);
16960786Sps	} else
17060786Sps		func = dirscan;
17160786Sps	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
17260786Sps		return (SKIP);
17360786Sps	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
17460786Sps	ilevel--;
17560786Sps	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
17660786Sps		sizepb *= NINDIR(&sblock);
17760786Sps	nif = howmany(isize , sizepb);
17860786Sps	if (nif > NINDIR(&sblock))
17960786Sps		nif = NINDIR(&sblock);
18060786Sps	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
18160786Sps		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
18260786Sps		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
18360786Sps			if (*ap == 0)
18460786Sps				continue;
18560786Sps			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
18660786Sps			    (u_long)idesc->id_number);
18760786Sps			if (dofix(idesc, buf)) {
18860786Sps				*ap = 0;
18960786Sps				dirty(bp);
19060786Sps			}
19160786Sps		}
19260786Sps		flush(fswritefd, bp);
19360786Sps	}
19460786Sps	aplim = &bp->b_un.b_indir[nif];
19560786Sps	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
19660786Sps		if (*ap) {
19760786Sps			idesc->id_blkno = *ap;
19860786Sps			if (ilevel == 0)
19960786Sps				n = (*func)(idesc);
20060786Sps			else
20160786Sps				n = iblock(idesc, ilevel, isize);
20260786Sps			if (n & STOP) {
20360786Sps				bp->b_flags &= ~B_INUSE;
20460786Sps				return (n);
20560786Sps			}
20660786Sps		} else {
20760786Sps			if (idesc->id_type == DATA && isize > 0) {
20860786Sps				/* An empty block in a directory XXX */
20960786Sps				getpathname(pathbuf, idesc->id_number,
21060786Sps						idesc->id_number);
21160786Sps                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
21260786Sps					pathbuf);
21360786Sps                        	if (reply("ADJUST LENGTH") == 1) {
21460786Sps					dp = ginode(idesc->id_number);
21560786Sps                                	dp->di_size -= isize;
21660786Sps					isize = 0;
21760786Sps					printf(
21860786Sps					    "YOU MUST RERUN FSCK AFTERWARDS\n");
21960786Sps					rerun = 1;
22060786Sps                                	inodirty();
22160786Sps					bp->b_flags &= ~B_INUSE;
22260786Sps					return(STOP);
22360786Sps                        	}
22460786Sps			}
22560786Sps		}
22660786Sps		isize -= sizepb;
22760786Sps	}
22860786Sps	bp->b_flags &= ~B_INUSE;
22960786Sps	return (KEEPON);
23060786Sps}
23160786Sps
23260786Sps/*
23360786Sps * Check that a block in a legal block number.
23460786Sps * Return 0 if in range, 1 if out of range.
23560786Sps */
23660786Spsint
23760786Spschkrange(blk, cnt)
23860786Sps	ufs_daddr_t blk;
23960786Sps	int cnt;
24060786Sps{
24160786Sps	register int c;
24260786Sps
24360786Sps	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
24460786Sps	    cnt - 1 > maxfsblock - blk)
24560786Sps		return (1);
24660786Sps	if (cnt > sblock.fs_frag ||
24760786Sps	    fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
24860786Sps		if (debug)
24960786Sps			printf("bad size: blk %ld, offset %ld, size %ld\n",
25060786Sps				blk, fragnum(&sblock, blk), cnt);
25160786Sps		return (1);
25260786Sps	}
25360786Sps	c = dtog(&sblock, blk);
25460786Sps	if (blk < cgdmin(&sblock, c)) {
25560786Sps		if ((blk + cnt) > cgsblock(&sblock, c)) {
25660786Sps			if (debug) {
25760786Sps				printf("blk %ld < cgdmin %ld;",
25860786Sps				    (long)blk, (long)cgdmin(&sblock, c));
25960786Sps				printf(" blk + cnt %ld > cgsbase %ld\n",
26060786Sps				    (long)(blk + cnt),
26160786Sps				    (long)cgsblock(&sblock, c));
26260786Sps			}
26360786Sps			return (1);
26460786Sps		}
26560786Sps	} else {
26660786Sps		if ((blk + cnt) > cgbase(&sblock, c+1)) {
26760786Sps			if (debug)  {
26860786Sps				printf("blk %ld >= cgdmin %ld;",
26960786Sps				    (long)blk, (long)cgdmin(&sblock, c));
27060786Sps				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
27160786Sps				    (long)(blk + cnt), (long)sblock.fs_fpg);
27260786Sps			}
27360786Sps			return (1);
27460786Sps		}
27560786Sps	}
27660786Sps	return (0);
27760786Sps}
27860786Sps
27960786Sps/*
28060786Sps * General purpose interface for reading inodes.
28160786Sps */
28260786Spsstruct dinode *
28360786Spsginode(inumber)
28460786Sps	ino_t inumber;
28560786Sps{
28660786Sps	ufs_daddr_t iblk;
28760786Sps
28860786Sps	if (inumber < ROOTINO || inumber > maxino)
28960786Sps		errx(EEXIT, "bad inode number %d to ginode", inumber);
29060786Sps	if (startinum == 0 ||
29160786Sps	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
29260786Sps		iblk = ino_to_fsba(&sblock, inumber);
29360786Sps		if (pbp != 0)
29460786Sps			pbp->b_flags &= ~B_INUSE;
29560786Sps		pbp = getdatablk(iblk, sblock.fs_bsize);
29660786Sps		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
29760786Sps	}
29860786Sps	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
29960786Sps}
30060786Sps
30160786Sps/*
30260786Sps * Special purpose version of ginode used to optimize first pass
30360786Sps * over all the inodes in numerical order.
30460786Sps */
30560786Spsino_t nextino, lastinum;
30660786Spslong readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
30760786Spsstruct dinode *inodebuf;
30860786Sps
30960786Spsstruct dinode *
31060786Spsgetnextinode(inumber)
31160786Sps	ino_t inumber;
31260786Sps{
31360786Sps	long size;
31460786Sps	ufs_daddr_t dblk;
31560786Sps	static struct dinode *dp;
31660786Sps
31760786Sps	if (inumber != nextino++ || inumber > maxino)
31860786Sps		errx(EEXIT, "bad inode number %d to nextinode", inumber);
31960786Sps	if (inumber >= lastinum) {
32060786Sps		readcnt++;
32160786Sps		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
32260786Sps		if (readcnt % readpercg == 0) {
32360786Sps			size = partialsize;
32460786Sps			lastinum += partialcnt;
32560786Sps		} else {
32660786Sps			size = inobufsize;
32760786Sps			lastinum += fullcnt;
32860786Sps		}
32960786Sps		/*
33060786Sps		 * If bread returns an error, it will already have zeroed
33160786Sps		 * out the buffer, so we do not need to do so here.
33260786Sps		 */
33360786Sps		(void)bread(fsreadfd, (char *)inodebuf, dblk, size);
33460786Sps		dp = inodebuf;
33560786Sps	}
33660786Sps	return (dp++);
33760786Sps}
33860786Sps
33960786Spsvoid
34060786Spssetinodebuf(inum)
34160786Sps	ino_t inum;
34260786Sps{
34360786Sps
34460786Sps	if (inum % sblock.fs_ipg != 0)
34560786Sps		errx(EEXIT, "bad inode number %d to setinodebuf", inum);
34660786Sps	startinum = 0;
34760786Sps	nextino = inum;
34860786Sps	lastinum = inum;
34960786Sps	readcnt = 0;
35060786Sps	if (inodebuf != NULL)
35160786Sps		return;
35260786Sps	inobufsize = blkroundup(&sblock, INOBUFSIZE);
35360786Sps	fullcnt = inobufsize / sizeof(struct dinode);
35460786Sps	readpercg = sblock.fs_ipg / fullcnt;
35560786Sps	partialcnt = sblock.fs_ipg % fullcnt;
35660786Sps	partialsize = partialcnt * sizeof(struct dinode);
35760786Sps	if (partialcnt != 0) {
35860786Sps		readpercg++;
35960786Sps	} else {
36060786Sps		partialcnt = fullcnt;
36160786Sps		partialsize = inobufsize;
36260786Sps	}
36360786Sps	if ((inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
36460786Sps		errx(EEXIT, "cannot allocate space for inode buffer");
36560786Sps}
36660786Sps
36760786Spsvoid
36860786Spsfreeinodebuf()
36960786Sps{
37060786Sps
37160786Sps	if (inodebuf != NULL)
37260786Sps		free((char *)inodebuf);
37360786Sps	inodebuf = NULL;
37460786Sps}
37560786Sps
37660786Sps/*
37760786Sps * Routines to maintain information about directory inodes.
37860786Sps * This is built during the first pass and used during the
37960786Sps * second and third passes.
38060786Sps *
38160786Sps * Enter inodes into the cache.
38260786Sps */
38360786Spsvoid
38460786Spscacheino(dp, inumber)
38560786Sps	register struct dinode *dp;
38660786Sps	ino_t inumber;
38760786Sps{
38860786Sps	register struct inoinfo *inp;
38960786Sps	struct inoinfo **inpp;
39060786Sps	int blks;
39160786Sps
39260786Sps	blks = howmany(dp->di_size, sblock.fs_bsize);
39360786Sps	if (blks > NDADDR)
39460786Sps		blks = NDADDR + NIADDR;
39560786Sps	inp = (struct inoinfo *)
39660786Sps		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
39760786Sps	if (inp == NULL)
39860786Sps		errx(EEXIT, "cannot increase directory list");
39960786Sps	inpp = &inphead[inumber % numdirs];
40060786Sps	inp->i_nexthash = *inpp;
40160786Sps	*inpp = inp;
40260786Sps	inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0;
40360786Sps	inp->i_dotdot = (ino_t)0;
40460786Sps	inp->i_number = inumber;
40560786Sps	inp->i_isize = dp->di_size;
40660786Sps	inp->i_numblks = blks * sizeof(ufs_daddr_t);
40760786Sps	memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
40860786Sps	if (inplast == listmax) {
40960786Sps		listmax += 100;
41060786Sps		inpsort = (struct inoinfo **)realloc((char *)inpsort,
41160786Sps		    (unsigned)listmax * sizeof(struct inoinfo *));
41260786Sps		if (inpsort == NULL)
41360786Sps			errx(EEXIT, "cannot increase directory list");
41460786Sps	}
41560786Sps	inpsort[inplast++] = inp;
41660786Sps}
41760786Sps
41860786Sps/*
41960786Sps * Look up an inode cache structure.
42060786Sps */
42160786Spsstruct inoinfo *
42260786Spsgetinoinfo(inumber)
42360786Sps	ino_t inumber;
42460786Sps{
42560786Sps	register struct inoinfo *inp;
42660786Sps
42760786Sps	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
42860786Sps		if (inp->i_number != inumber)
42960786Sps			continue;
43060786Sps		return (inp);
43160786Sps	}
43260786Sps	errx(EEXIT, "cannot find inode %d", inumber);
43360786Sps	return ((struct inoinfo *)0);
43460786Sps}
43560786Sps
43660786Sps/*
43760786Sps * Clean up all the inode cache structure.
43860786Sps */
43960786Spsvoid
44060786Spsinocleanup()
44160786Sps{
44260786Sps	register struct inoinfo **inpp;
44360786Sps
44460786Sps	if (inphead == NULL)
44560786Sps		return;
44660786Sps	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
44760786Sps		free((char *)(*inpp));
44860786Sps	free((char *)inphead);
44960786Sps	free((char *)inpsort);
45060786Sps	inphead = inpsort = NULL;
45160786Sps}
45260786Sps
45360786Spsvoid
45460786Spsinodirty()
45560786Sps{
45660786Sps
45760786Sps	dirty(pbp);
45860786Sps}
45960786Sps
46060786Spsvoid
46160786Spsclri(idesc, type, flag)
46260786Sps	register struct inodesc *idesc;
46360786Sps	char *type;
46460786Sps	int flag;
46560786Sps{
46660786Sps	register struct dinode *dp;
46760786Sps
46860786Sps	dp = ginode(idesc->id_number);
46960786Sps	if (flag == 1) {
47060786Sps		pwarn("%s %s", type,
47160786Sps		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
47260786Sps		pinode(idesc->id_number);
47360786Sps	}
47460786Sps	if (preen || reply("CLEAR") == 1) {
47560786Sps		if (preen)
47660786Sps			printf(" (CLEARED)\n");
47760786Sps		n_files--;
47860786Sps		(void)ckinode(dp, idesc);
47960786Sps		clearinode(dp);
48060786Sps		inoinfo(idesc->id_number)->ino_state = USTATE;
48160786Sps		inodirty();
48260786Sps	}
48360786Sps}
48460786Sps
48560786Spsint
48660786Spsfindname(idesc)
48760786Sps	struct inodesc *idesc;
48860786Sps{
48960786Sps	register struct direct *dirp = idesc->id_dirp;
49060786Sps
49160786Sps	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
49260786Sps		idesc->id_entryno++;
49360786Sps		return (KEEPON);
49460786Sps	}
49560786Sps	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
49660786Sps	return (STOP|FOUND);
49760786Sps}
49860786Sps
49960786Spsint
50060786Spsfindino(idesc)
50160786Sps	struct inodesc *idesc;
50260786Sps{
50360786Sps	register struct direct *dirp = idesc->id_dirp;
50460786Sps
50560786Sps	if (dirp->d_ino == 0)
50660786Sps		return (KEEPON);
50760786Sps	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
50860786Sps	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
50960786Sps		idesc->id_parent = dirp->d_ino;
51060786Sps		return (STOP|FOUND);
51160786Sps	}
51260786Sps	return (KEEPON);
51360786Sps}
51460786Sps
51563131Spsint
51663131Spsclearentry(idesc)
51760786Sps	struct inodesc *idesc;
51860786Sps{
51960786Sps	register struct direct *dirp = idesc->id_dirp;
52060786Sps
52160786Sps	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
52260786Sps		idesc->id_entryno++;
52360786Sps		return (KEEPON);
52460786Sps	}
52560786Sps	dirp->d_ino = 0;
52660786Sps	return (STOP|FOUND|ALTERED);
52760786Sps}
52860786Sps
52960786Spsvoid
53060786Spspinode(ino)
53160786Sps	ino_t ino;
53260786Sps{
53360786Sps	register struct dinode *dp;
53460786Sps	register char *p;
53560786Sps	struct passwd *pw;
53660786Sps	time_t t;
53760786Sps
53860786Sps	printf(" I=%lu ", (u_long)ino);
53960786Sps	if (ino < ROOTINO || ino > maxino)
54060786Sps		return;
54160786Sps	dp = ginode(ino);
54260786Sps	printf(" OWNER=");
54360786Sps	if ((pw = getpwuid((int)dp->di_uid)) != 0)
54460786Sps		printf("%s ", pw->pw_name);
54560786Sps	else
54660786Sps		printf("%u ", (unsigned)dp->di_uid);
54760786Sps	printf("MODE=%o\n", dp->di_mode);
54860786Sps	if (preen)
54960786Sps		printf("%s: ", cdevname);
55060786Sps	printf("SIZE=%qu ", dp->di_size);
55160786Sps	t = dp->di_mtime;
55260786Sps	p = ctime(&t);
55360786Sps	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
55460786Sps}
55560786Sps
55660786Spsvoid
55760786Spsblkerror(ino, type, blk)
55860786Sps	ino_t ino;
55960786Sps	char *type;
56060786Sps	ufs_daddr_t blk;
56160786Sps{
56260786Sps
56360786Sps	pfatal("%ld %s I=%lu", blk, type, ino);
56460786Sps	printf("\n");
56560786Sps	switch (inoinfo(ino)->ino_state) {
56660786Sps
56760786Sps	case FSTATE:
56860786Sps		inoinfo(ino)->ino_state = FCLEAR;
56960786Sps		return;
57060786Sps
57160786Sps	case DSTATE:
57260786Sps		inoinfo(ino)->ino_state = DCLEAR;
57360786Sps		return;
57460786Sps
57560786Sps	case FCLEAR:
57660786Sps	case DCLEAR:
57760786Sps		return;
57860786Sps
57960786Sps	default:
58060786Sps		errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
58160786Sps		/* NOTREACHED */
58260786Sps	}
58360786Sps}
58460786Sps
58560786Sps/*
58660786Sps * allocate an unused inode
58760786Sps */
58860786Spsino_t
58960786Spsallocino(request, type)
59060786Sps	ino_t request;
59160786Sps	int type;
59260786Sps{
59360786Sps	register ino_t ino;
59460786Sps	register struct dinode *dp;
59560786Sps	struct cg *cgp = &cgrp;
59660786Sps	int cg;
59760786Sps
59860786Sps	if (request == 0)
59960786Sps		request = ROOTINO;
60060786Sps	else if (inoinfo(request)->ino_state != USTATE)
60160786Sps		return (0);
60260786Sps	for (ino = request; ino < maxino; ino++)
60360786Sps		if (inoinfo(ino)->ino_state == USTATE)
60460786Sps			break;
60560786Sps	if (ino == maxino)
60660786Sps		return (0);
60760786Sps	cg = ino_to_cg(&sblock, ino);
60860786Sps	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
60960786Sps	if (!cg_chkmagic(cgp))
61060786Sps		pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
61160786Sps	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
61260786Sps	cgp->cg_cs.cs_nifree--;
61360786Sps	switch (type & IFMT) {
61460786Sps	case IFDIR:
61560786Sps		inoinfo(ino)->ino_state = DSTATE;
61660786Sps		cgp->cg_cs.cs_ndir++;
61760786Sps		break;
61860786Sps	case IFREG:
61960786Sps	case IFLNK:
62060786Sps		inoinfo(ino)->ino_state = FSTATE;
62160786Sps		break;
62260786Sps	default:
62360786Sps		return (0);
62460786Sps	}
62560786Sps	cgdirty();
62660786Sps	dp = ginode(ino);
62760786Sps	dp->di_db[0] = allocblk((long)1);
62860786Sps	if (dp->di_db[0] == 0) {
62960786Sps		inoinfo(ino)->ino_state = USTATE;
63060786Sps		return (0);
63160786Sps	}
63260786Sps	dp->di_mode = type;
63360786Sps	dp->di_flags = 0;
63460786Sps	dp->di_atime = time(NULL);
63560786Sps	dp->di_mtime = dp->di_ctime = dp->di_atime;
63660786Sps	dp->di_mtimensec = dp->di_ctimensec = dp->di_atimensec = 0;
63760786Sps	dp->di_size = sblock.fs_fsize;
63860786Sps	dp->di_blocks = btodb(sblock.fs_fsize);
63960786Sps	n_files++;
64060786Sps	inodirty();
64160786Sps	if (newinofmt)
64260786Sps		inoinfo(ino)->ino_type = IFTODT(type);
64360786Sps	return (ino);
64460786Sps}
64560786Sps
64660786Sps/*
64760786Sps * deallocate an inode
64860786Sps */
64960786Spsvoid
65060786Spsfreeino(ino)
65160786Sps	ino_t ino;
65260786Sps{
65360786Sps	struct inodesc idesc;
65460786Sps	struct dinode *dp;
65560786Sps
65660786Sps	memset(&idesc, 0, sizeof(struct inodesc));
65760786Sps	idesc.id_type = ADDR;
65860786Sps	idesc.id_func = pass4check;
65960786Sps	idesc.id_number = ino;
66060786Sps	dp = ginode(ino);
66160786Sps	(void)ckinode(dp, &idesc);
66260786Sps	clearinode(dp);
66360786Sps	inodirty();
66460786Sps	inoinfo(ino)->ino_state = USTATE;
66560786Sps	n_files--;
66660786Sps}
66760786Sps