inode.c revision 63231
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1980, 1986, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 3. All advertising materials mentioning features or use of this software
141558Srgrimes *    must display the following acknowledgement:
151558Srgrimes *	This product includes software developed by the University of
161558Srgrimes *	California, Berkeley and its contributors.
171558Srgrimes * 4. Neither the name of the University nor the names of its contributors
181558Srgrimes *    may be used to endorse or promote products derived from this software
191558Srgrimes *    without specific prior written permission.
201558Srgrimes *
211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311558Srgrimes * SUCH DAMAGE.
321558Srgrimes */
331558Srgrimes
341558Srgrimes#ifndef lint
3541477Sjulian#if 0
3623675Speterstatic const char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
3741477Sjulian#endif
3841477Sjulianstatic const char rcsid[] =
3950476Speter  "$FreeBSD: head/sbin/fsck_ffs/inode.c 63231 2000-07-15 18:28:36Z mckusick $";
401558Srgrimes#endif /* not lint */
411558Srgrimes
421558Srgrimes#include <sys/param.h>
431558Srgrimes#include <sys/time.h>
4423675Speter
451558Srgrimes#include <ufs/ufs/dinode.h>
461558Srgrimes#include <ufs/ufs/dir.h>
471558Srgrimes#include <ufs/ffs/fs.h>
4823675Speter
4923675Speter#include <err.h>
501558Srgrimes#include <pwd.h>
511558Srgrimes#include <string.h>
5223675Speter
531558Srgrimes#include "fsck.h"
541558Srgrimes
551558Srgrimesstatic ino_t startinum;
561558Srgrimes
5723675Speterstatic int iblock __P((struct inodesc *, long ilevel, quad_t isize));
587585Sbde
597585Sbdeint
601558Srgrimesckinode(dp, idesc)
611558Srgrimes	struct dinode *dp;
621558Srgrimes	register struct inodesc *idesc;
631558Srgrimes{
6423675Speter	ufs_daddr_t *ap;
6541474Sjulian	int ret;
6641474Sjulian	long n, ndb, offset;
671558Srgrimes	struct dinode dino;
681558Srgrimes	quad_t remsize, sizepb;
691558Srgrimes	mode_t mode;
7018808Sguido	char pathbuf[MAXPATHLEN + 1];
711558Srgrimes
721558Srgrimes	if (idesc->id_fix != IGNORE)
731558Srgrimes		idesc->id_fix = DONTKNOW;
7462668Smckusick	idesc->id_lbn = -1;
751558Srgrimes	idesc->id_entryno = 0;
761558Srgrimes	idesc->id_filesize = dp->di_size;
771558Srgrimes	mode = dp->di_mode & IFMT;
781558Srgrimes	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
7941474Sjulian	    dp->di_size < (unsigned)sblock.fs_maxsymlinklen))
801558Srgrimes		return (KEEPON);
811558Srgrimes	dino = *dp;
821558Srgrimes	ndb = howmany(dino.di_size, sblock.fs_bsize);
831558Srgrimes	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
8462668Smckusick		idesc->id_lbn++;
851558Srgrimes		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
861558Srgrimes			idesc->id_numfrags =
871558Srgrimes				numfrags(&sblock, fragroundup(&sblock, offset));
881558Srgrimes		else
891558Srgrimes			idesc->id_numfrags = sblock.fs_frag;
9018808Sguido		if (*ap == 0) {
9118808Sguido			if (idesc->id_type == DATA && ndb >= 0) {
9218808Sguido				/* An empty block in a directory XXX */
9318808Sguido				getpathname(pathbuf, idesc->id_number,
9418808Sguido						idesc->id_number);
9518808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
9618808Sguido					pathbuf);
9718808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
9818808Sguido					dp = ginode(idesc->id_number);
9918808Sguido                                	dp->di_size = (ap - &dino.di_db[0]) *
10018808Sguido					    sblock.fs_bsize;
10118808Sguido					printf(
10218808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
10318808Sguido					rerun = 1;
10418808Sguido                                	inodirty();
10518808Sguido
10618808Sguido                        	}
10718808Sguido			}
1081558Srgrimes			continue;
10918808Sguido		}
1101558Srgrimes		idesc->id_blkno = *ap;
11162668Smckusick		if (idesc->id_type != DATA)
1121558Srgrimes			ret = (*idesc->id_func)(idesc);
1131558Srgrimes		else
1141558Srgrimes			ret = dirscan(idesc);
1151558Srgrimes		if (ret & STOP)
1161558Srgrimes			return (ret);
1171558Srgrimes	}
1181558Srgrimes	idesc->id_numfrags = sblock.fs_frag;
1191558Srgrimes	remsize = dino.di_size - sblock.fs_bsize * NDADDR;
1201558Srgrimes	sizepb = sblock.fs_bsize;
1211558Srgrimes	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
12262668Smckusick		sizepb *= NINDIR(&sblock);
1231558Srgrimes		if (*ap) {
1241558Srgrimes			idesc->id_blkno = *ap;
1251558Srgrimes			ret = iblock(idesc, n, remsize);
1261558Srgrimes			if (ret & STOP)
1271558Srgrimes				return (ret);
12818808Sguido		} else {
12962668Smckusick			idesc->id_lbn += sizepb / sblock.fs_bsize;
13018808Sguido			if (idesc->id_type == DATA && remsize > 0) {
13118808Sguido				/* An empty block in a directory XXX */
13218808Sguido				getpathname(pathbuf, idesc->id_number,
13318808Sguido						idesc->id_number);
13418808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
13518808Sguido					pathbuf);
13618808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
13718808Sguido					dp = ginode(idesc->id_number);
13818808Sguido                                	dp->di_size -= remsize;
13918808Sguido					remsize = 0;
14018808Sguido					printf(
14118808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
14218808Sguido					rerun = 1;
14318808Sguido                                	inodirty();
14418808Sguido					break;
14518808Sguido                        	}
14618808Sguido			}
1471558Srgrimes		}
1481558Srgrimes		remsize -= sizepb;
1491558Srgrimes	}
1501558Srgrimes	return (KEEPON);
1511558Srgrimes}
1521558Srgrimes
1537585Sbdestatic int
1541558Srgrimesiblock(idesc, ilevel, isize)
1551558Srgrimes	struct inodesc *idesc;
1561558Srgrimes	long ilevel;
1571558Srgrimes	quad_t isize;
1581558Srgrimes{
15923675Speter	ufs_daddr_t *ap;
16023675Speter	ufs_daddr_t *aplim;
16123675Speter	struct bufarea *bp;
1621558Srgrimes	int i, n, (*func)(), nif;
1631558Srgrimes	quad_t sizepb;
1641558Srgrimes	char buf[BUFSIZ];
16518808Sguido	char pathbuf[MAXPATHLEN + 1];
16618808Sguido	struct dinode *dp;
1671558Srgrimes
16862668Smckusick	if (idesc->id_type != DATA) {
1691558Srgrimes		func = idesc->id_func;
1701558Srgrimes		if (((n = (*func)(idesc)) & KEEPON) == 0)
1711558Srgrimes			return (n);
1721558Srgrimes	} else
1731558Srgrimes		func = dirscan;
1741558Srgrimes	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
1751558Srgrimes		return (SKIP);
1761558Srgrimes	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
1771558Srgrimes	ilevel--;
1781558Srgrimes	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
1791558Srgrimes		sizepb *= NINDIR(&sblock);
1801558Srgrimes	nif = howmany(isize , sizepb);
1811558Srgrimes	if (nif > NINDIR(&sblock))
1821558Srgrimes		nif = NINDIR(&sblock);
1831558Srgrimes	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
1841558Srgrimes		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
1851558Srgrimes		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
1861558Srgrimes			if (*ap == 0)
1871558Srgrimes				continue;
1881558Srgrimes			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
18937236Sbde			    (u_long)idesc->id_number);
1901558Srgrimes			if (dofix(idesc, buf)) {
1911558Srgrimes				*ap = 0;
1921558Srgrimes				dirty(bp);
1931558Srgrimes			}
1941558Srgrimes		}
1951558Srgrimes		flush(fswritefd, bp);
1961558Srgrimes	}
1971558Srgrimes	aplim = &bp->b_un.b_indir[nif];
1981558Srgrimes	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
19962668Smckusick		if (ilevel == 0)
20062668Smckusick			idesc->id_lbn++;
2011558Srgrimes		if (*ap) {
2021558Srgrimes			idesc->id_blkno = *ap;
2031558Srgrimes			if (ilevel == 0)
2041558Srgrimes				n = (*func)(idesc);
2051558Srgrimes			else
2061558Srgrimes				n = iblock(idesc, ilevel, isize);
2071558Srgrimes			if (n & STOP) {
2081558Srgrimes				bp->b_flags &= ~B_INUSE;
2091558Srgrimes				return (n);
2101558Srgrimes			}
21118808Sguido		} else {
21218808Sguido			if (idesc->id_type == DATA && isize > 0) {
21318808Sguido				/* An empty block in a directory XXX */
21418808Sguido				getpathname(pathbuf, idesc->id_number,
21518808Sguido						idesc->id_number);
21618808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
21718808Sguido					pathbuf);
21818808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
21918808Sguido					dp = ginode(idesc->id_number);
22018808Sguido                                	dp->di_size -= isize;
22118808Sguido					isize = 0;
22218808Sguido					printf(
22318808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
22418808Sguido					rerun = 1;
22518808Sguido                                	inodirty();
22618808Sguido					bp->b_flags &= ~B_INUSE;
22718808Sguido					return(STOP);
22818808Sguido                        	}
22918808Sguido			}
2301558Srgrimes		}
2311558Srgrimes		isize -= sizepb;
2321558Srgrimes	}
2331558Srgrimes	bp->b_flags &= ~B_INUSE;
2341558Srgrimes	return (KEEPON);
2351558Srgrimes}
2361558Srgrimes
2371558Srgrimes/*
2381558Srgrimes * Check that a block in a legal block number.
2391558Srgrimes * Return 0 if in range, 1 if out of range.
2401558Srgrimes */
2417585Sbdeint
2421558Srgrimeschkrange(blk, cnt)
24323675Speter	ufs_daddr_t blk;
2441558Srgrimes	int cnt;
2451558Srgrimes{
2461558Srgrimes	register int c;
2471558Srgrimes
24841474Sjulian	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
24941474Sjulian	    cnt - 1 > maxfsblock - blk)
2501558Srgrimes		return (1);
25141474Sjulian	if (cnt > sblock.fs_frag ||
25241474Sjulian	    fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
25341474Sjulian		if (debug)
25441474Sjulian			printf("bad size: blk %ld, offset %ld, size %ld\n",
25541474Sjulian				blk, fragnum(&sblock, blk), cnt);
25641474Sjulian		return (1);
25741474Sjulian	}
2581558Srgrimes	c = dtog(&sblock, blk);
2591558Srgrimes	if (blk < cgdmin(&sblock, c)) {
2601558Srgrimes		if ((blk + cnt) > cgsblock(&sblock, c)) {
2611558Srgrimes			if (debug) {
2621558Srgrimes				printf("blk %ld < cgdmin %ld;",
26337236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2641558Srgrimes				printf(" blk + cnt %ld > cgsbase %ld\n",
26537236Sbde				    (long)(blk + cnt),
26637236Sbde				    (long)cgsblock(&sblock, c));
2671558Srgrimes			}
2681558Srgrimes			return (1);
2691558Srgrimes		}
2701558Srgrimes	} else {
2711558Srgrimes		if ((blk + cnt) > cgbase(&sblock, c+1)) {
2721558Srgrimes			if (debug)  {
2731558Srgrimes				printf("blk %ld >= cgdmin %ld;",
27437236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2751558Srgrimes				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
27637236Sbde				    (long)(blk + cnt), (long)sblock.fs_fpg);
2771558Srgrimes			}
2781558Srgrimes			return (1);
2791558Srgrimes		}
2801558Srgrimes	}
2811558Srgrimes	return (0);
2821558Srgrimes}
2831558Srgrimes
2841558Srgrimes/*
2851558Srgrimes * General purpose interface for reading inodes.
2861558Srgrimes */
2871558Srgrimesstruct dinode *
2881558Srgrimesginode(inumber)
2891558Srgrimes	ino_t inumber;
2901558Srgrimes{
29123675Speter	ufs_daddr_t iblk;
2921558Srgrimes
2931558Srgrimes	if (inumber < ROOTINO || inumber > maxino)
29423675Speter		errx(EEXIT, "bad inode number %d to ginode", inumber);
2951558Srgrimes	if (startinum == 0 ||
2961558Srgrimes	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
2971558Srgrimes		iblk = ino_to_fsba(&sblock, inumber);
2981558Srgrimes		if (pbp != 0)
2991558Srgrimes			pbp->b_flags &= ~B_INUSE;
3001558Srgrimes		pbp = getdatablk(iblk, sblock.fs_bsize);
3011558Srgrimes		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
3021558Srgrimes	}
3031558Srgrimes	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
3041558Srgrimes}
3051558Srgrimes
3061558Srgrimes/*
3071558Srgrimes * Special purpose version of ginode used to optimize first pass
3081558Srgrimes * over all the inodes in numerical order.
3091558Srgrimes */
31063231Smckusickino_t nextino, lastinum, lastvalidinum;
3111558Srgrimeslong readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
3121558Srgrimesstruct dinode *inodebuf;
3131558Srgrimes
3141558Srgrimesstruct dinode *
3151558Srgrimesgetnextinode(inumber)
3161558Srgrimes	ino_t inumber;
3171558Srgrimes{
3181558Srgrimes	long size;
31923675Speter	ufs_daddr_t dblk;
3201558Srgrimes	static struct dinode *dp;
3211558Srgrimes
32263231Smckusick	if (inumber != nextino++ || inumber > lastvalidinum)
32323675Speter		errx(EEXIT, "bad inode number %d to nextinode", inumber);
3241558Srgrimes	if (inumber >= lastinum) {
3251558Srgrimes		readcnt++;
3261558Srgrimes		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
3271558Srgrimes		if (readcnt % readpercg == 0) {
3281558Srgrimes			size = partialsize;
3291558Srgrimes			lastinum += partialcnt;
3301558Srgrimes		} else {
3311558Srgrimes			size = inobufsize;
3321558Srgrimes			lastinum += fullcnt;
3331558Srgrimes		}
33441474Sjulian		/*
33541474Sjulian		 * If bread returns an error, it will already have zeroed
33641474Sjulian		 * out the buffer, so we do not need to do so here.
33741474Sjulian		 */
33841474Sjulian		(void)bread(fsreadfd, (char *)inodebuf, dblk, size);
3391558Srgrimes		dp = inodebuf;
3401558Srgrimes	}
3411558Srgrimes	return (dp++);
3421558Srgrimes}
3431558Srgrimes
3447585Sbdevoid
34541474Sjuliansetinodebuf(inum)
34641474Sjulian	ino_t inum;
3471558Srgrimes{
3481558Srgrimes
34941474Sjulian	if (inum % sblock.fs_ipg != 0)
35041474Sjulian		errx(EEXIT, "bad inode number %d to setinodebuf", inum);
35163231Smckusick	lastvalidinum = inum + sblock.fs_ipg - 1;
3521558Srgrimes	startinum = 0;
35341474Sjulian	nextino = inum;
35441474Sjulian	lastinum = inum;
3551558Srgrimes	readcnt = 0;
35641474Sjulian	if (inodebuf != NULL)
35741474Sjulian		return;
3581558Srgrimes	inobufsize = blkroundup(&sblock, INOBUFSIZE);
3591558Srgrimes	fullcnt = inobufsize / sizeof(struct dinode);
3601558Srgrimes	readpercg = sblock.fs_ipg / fullcnt;
3611558Srgrimes	partialcnt = sblock.fs_ipg % fullcnt;
3621558Srgrimes	partialsize = partialcnt * sizeof(struct dinode);
3631558Srgrimes	if (partialcnt != 0) {
3641558Srgrimes		readpercg++;
3651558Srgrimes	} else {
3661558Srgrimes		partialcnt = fullcnt;
3671558Srgrimes		partialsize = inobufsize;
3681558Srgrimes	}
36941474Sjulian	if ((inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
37037000Scharnier		errx(EEXIT, "cannot allocate space for inode buffer");
3711558Srgrimes}
3721558Srgrimes
3737585Sbdevoid
3741558Srgrimesfreeinodebuf()
3751558Srgrimes{
3761558Srgrimes
3771558Srgrimes	if (inodebuf != NULL)
3781558Srgrimes		free((char *)inodebuf);
3791558Srgrimes	inodebuf = NULL;
3801558Srgrimes}
3811558Srgrimes
3821558Srgrimes/*
3831558Srgrimes * Routines to maintain information about directory inodes.
3841558Srgrimes * This is built during the first pass and used during the
3851558Srgrimes * second and third passes.
3861558Srgrimes *
3871558Srgrimes * Enter inodes into the cache.
3881558Srgrimes */
3897585Sbdevoid
3901558Srgrimescacheino(dp, inumber)
3911558Srgrimes	register struct dinode *dp;
3921558Srgrimes	ino_t inumber;
3931558Srgrimes{
3941558Srgrimes	register struct inoinfo *inp;
3951558Srgrimes	struct inoinfo **inpp;
39638002Sdfr	int blks;
3971558Srgrimes
3981558Srgrimes	blks = howmany(dp->di_size, sblock.fs_bsize);
3991558Srgrimes	if (blks > NDADDR)
4001558Srgrimes		blks = NDADDR + NIADDR;
4011558Srgrimes	inp = (struct inoinfo *)
40223675Speter		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
4031558Srgrimes	if (inp == NULL)
40441474Sjulian		errx(EEXIT, "cannot increase directory list");
40557573Smckusick	inpp = &inphead[inumber % dirhash];
4061558Srgrimes	inp->i_nexthash = *inpp;
4071558Srgrimes	*inpp = inp;
40841474Sjulian	inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0;
4091558Srgrimes	inp->i_dotdot = (ino_t)0;
4101558Srgrimes	inp->i_number = inumber;
4111558Srgrimes	inp->i_isize = dp->di_size;
41223675Speter	inp->i_numblks = blks * sizeof(ufs_daddr_t);
41323675Speter	memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
4141558Srgrimes	if (inplast == listmax) {
4151558Srgrimes		listmax += 100;
4161558Srgrimes		inpsort = (struct inoinfo **)realloc((char *)inpsort,
4171558Srgrimes		    (unsigned)listmax * sizeof(struct inoinfo *));
4181558Srgrimes		if (inpsort == NULL)
41923675Speter			errx(EEXIT, "cannot increase directory list");
4201558Srgrimes	}
4211558Srgrimes	inpsort[inplast++] = inp;
4221558Srgrimes}
4231558Srgrimes
4241558Srgrimes/*
4251558Srgrimes * Look up an inode cache structure.
4261558Srgrimes */
4271558Srgrimesstruct inoinfo *
4281558Srgrimesgetinoinfo(inumber)
4291558Srgrimes	ino_t inumber;
4301558Srgrimes{
4311558Srgrimes	register struct inoinfo *inp;
4321558Srgrimes
43357573Smckusick	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
4341558Srgrimes		if (inp->i_number != inumber)
4351558Srgrimes			continue;
4361558Srgrimes		return (inp);
4371558Srgrimes	}
43823675Speter	errx(EEXIT, "cannot find inode %d", inumber);
4391558Srgrimes	return ((struct inoinfo *)0);
4401558Srgrimes}
4411558Srgrimes
4421558Srgrimes/*
4431558Srgrimes * Clean up all the inode cache structure.
4441558Srgrimes */
4457585Sbdevoid
4461558Srgrimesinocleanup()
4471558Srgrimes{
4481558Srgrimes	register struct inoinfo **inpp;
4491558Srgrimes
4501558Srgrimes	if (inphead == NULL)
4511558Srgrimes		return;
4521558Srgrimes	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
4531558Srgrimes		free((char *)(*inpp));
4541558Srgrimes	free((char *)inphead);
4551558Srgrimes	free((char *)inpsort);
4561558Srgrimes	inphead = inpsort = NULL;
4571558Srgrimes}
4588871Srgrimes
4597585Sbdevoid
4601558Srgrimesinodirty()
4611558Srgrimes{
46223797Sbde
4631558Srgrimes	dirty(pbp);
4641558Srgrimes}
4651558Srgrimes
4667585Sbdevoid
4671558Srgrimesclri(idesc, type, flag)
4681558Srgrimes	register struct inodesc *idesc;
4691558Srgrimes	char *type;
4701558Srgrimes	int flag;
4711558Srgrimes{
4721558Srgrimes	register struct dinode *dp;
4731558Srgrimes
4741558Srgrimes	dp = ginode(idesc->id_number);
4751558Srgrimes	if (flag == 1) {
4761558Srgrimes		pwarn("%s %s", type,
4771558Srgrimes		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
4781558Srgrimes		pinode(idesc->id_number);
4791558Srgrimes	}
4801558Srgrimes	if (preen || reply("CLEAR") == 1) {
4811558Srgrimes		if (preen)
4821558Srgrimes			printf(" (CLEARED)\n");
4831558Srgrimes		n_files--;
4841558Srgrimes		(void)ckinode(dp, idesc);
4851558Srgrimes		clearinode(dp);
48641474Sjulian		inoinfo(idesc->id_number)->ino_state = USTATE;
4871558Srgrimes		inodirty();
4881558Srgrimes	}
4891558Srgrimes}
4901558Srgrimes
4917585Sbdeint
4921558Srgrimesfindname(idesc)
4931558Srgrimes	struct inodesc *idesc;
4941558Srgrimes{
4951558Srgrimes	register struct direct *dirp = idesc->id_dirp;
4961558Srgrimes
49741474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
49841474Sjulian		idesc->id_entryno++;
4991558Srgrimes		return (KEEPON);
50041474Sjulian	}
50123675Speter	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
5021558Srgrimes	return (STOP|FOUND);
5031558Srgrimes}
5041558Srgrimes
5057585Sbdeint
5061558Srgrimesfindino(idesc)
5071558Srgrimes	struct inodesc *idesc;
5081558Srgrimes{
5091558Srgrimes	register struct direct *dirp = idesc->id_dirp;
5101558Srgrimes
5111558Srgrimes	if (dirp->d_ino == 0)
5121558Srgrimes		return (KEEPON);
5131558Srgrimes	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
5141558Srgrimes	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
5151558Srgrimes		idesc->id_parent = dirp->d_ino;
5161558Srgrimes		return (STOP|FOUND);
5171558Srgrimes	}
5181558Srgrimes	return (KEEPON);
5191558Srgrimes}
5201558Srgrimes
52141474Sjulianint
52241474Sjulianclearentry(idesc)
52341474Sjulian	struct inodesc *idesc;
52441474Sjulian{
52541474Sjulian	register struct direct *dirp = idesc->id_dirp;
52641474Sjulian
52741474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
52841474Sjulian		idesc->id_entryno++;
52941474Sjulian		return (KEEPON);
53041474Sjulian	}
53141474Sjulian	dirp->d_ino = 0;
53241474Sjulian	return (STOP|FOUND|ALTERED);
53341474Sjulian}
53441474Sjulian
5357585Sbdevoid
5361558Srgrimespinode(ino)
5371558Srgrimes	ino_t ino;
5381558Srgrimes{
5391558Srgrimes	register struct dinode *dp;
5401558Srgrimes	register char *p;
5411558Srgrimes	struct passwd *pw;
54224002Speter	time_t t;
5431558Srgrimes
54437236Sbde	printf(" I=%lu ", (u_long)ino);
5451558Srgrimes	if (ino < ROOTINO || ino > maxino)
5461558Srgrimes		return;
5471558Srgrimes	dp = ginode(ino);
5481558Srgrimes	printf(" OWNER=");
5491558Srgrimes	if ((pw = getpwuid((int)dp->di_uid)) != 0)
5501558Srgrimes		printf("%s ", pw->pw_name);
5511558Srgrimes	else
5521558Srgrimes		printf("%u ", (unsigned)dp->di_uid);
5531558Srgrimes	printf("MODE=%o\n", dp->di_mode);
5541558Srgrimes	if (preen)
5551558Srgrimes		printf("%s: ", cdevname);
5561558Srgrimes	printf("SIZE=%qu ", dp->di_size);
55724002Speter	t = dp->di_mtime;
55824002Speter	p = ctime(&t);
5591558Srgrimes	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
5601558Srgrimes}
5611558Srgrimes
5627585Sbdevoid
5631558Srgrimesblkerror(ino, type, blk)
5641558Srgrimes	ino_t ino;
5651558Srgrimes	char *type;
56623675Speter	ufs_daddr_t blk;
5671558Srgrimes{
5681558Srgrimes
5691558Srgrimes	pfatal("%ld %s I=%lu", blk, type, ino);
5701558Srgrimes	printf("\n");
57141474Sjulian	switch (inoinfo(ino)->ino_state) {
5721558Srgrimes
5731558Srgrimes	case FSTATE:
57441474Sjulian		inoinfo(ino)->ino_state = FCLEAR;
5751558Srgrimes		return;
5761558Srgrimes
5771558Srgrimes	case DSTATE:
57841474Sjulian		inoinfo(ino)->ino_state = DCLEAR;
5791558Srgrimes		return;
5801558Srgrimes
5811558Srgrimes	case FCLEAR:
5821558Srgrimes	case DCLEAR:
5831558Srgrimes		return;
5841558Srgrimes
5851558Srgrimes	default:
58641474Sjulian		errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
5871558Srgrimes		/* NOTREACHED */
5881558Srgrimes	}
5891558Srgrimes}
5901558Srgrimes
5911558Srgrimes/*
5921558Srgrimes * allocate an unused inode
5931558Srgrimes */
5941558Srgrimesino_t
5951558Srgrimesallocino(request, type)
5961558Srgrimes	ino_t request;
5971558Srgrimes	int type;
5981558Srgrimes{
5991558Srgrimes	register ino_t ino;
6001558Srgrimes	register struct dinode *dp;
60134266Sjulian	struct cg *cgp = &cgrp;
60234266Sjulian	int cg;
6031558Srgrimes
6041558Srgrimes	if (request == 0)
6051558Srgrimes		request = ROOTINO;
60641474Sjulian	else if (inoinfo(request)->ino_state != USTATE)
6071558Srgrimes		return (0);
6081558Srgrimes	for (ino = request; ino < maxino; ino++)
60941474Sjulian		if (inoinfo(ino)->ino_state == USTATE)
6101558Srgrimes			break;
6111558Srgrimes	if (ino == maxino)
6121558Srgrimes		return (0);
61334266Sjulian	cg = ino_to_cg(&sblock, ino);
61434266Sjulian	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
61534266Sjulian	if (!cg_chkmagic(cgp))
61634266Sjulian		pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
61734266Sjulian	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
61834266Sjulian	cgp->cg_cs.cs_nifree--;
6191558Srgrimes	switch (type & IFMT) {
6201558Srgrimes	case IFDIR:
62141474Sjulian		inoinfo(ino)->ino_state = DSTATE;
62234266Sjulian		cgp->cg_cs.cs_ndir++;
6231558Srgrimes		break;
6241558Srgrimes	case IFREG:
6251558Srgrimes	case IFLNK:
62641474Sjulian		inoinfo(ino)->ino_state = FSTATE;
6271558Srgrimes		break;
6281558Srgrimes	default:
6291558Srgrimes		return (0);
6301558Srgrimes	}
63134266Sjulian	cgdirty();
6321558Srgrimes	dp = ginode(ino);
6331558Srgrimes	dp->di_db[0] = allocblk((long)1);
6341558Srgrimes	if (dp->di_db[0] == 0) {
63541474Sjulian		inoinfo(ino)->ino_state = USTATE;
6361558Srgrimes		return (0);
6371558Srgrimes	}
63841474Sjulian	dp->di_mode = type;
63934266Sjulian	dp->di_flags = 0;
64024002Speter	dp->di_atime = time(NULL);
6411558Srgrimes	dp->di_mtime = dp->di_ctime = dp->di_atime;
64241477Sjulian	dp->di_mtimensec = dp->di_ctimensec = dp->di_atimensec = 0;
6431558Srgrimes	dp->di_size = sblock.fs_fsize;
6441558Srgrimes	dp->di_blocks = btodb(sblock.fs_fsize);
6451558Srgrimes	n_files++;
6461558Srgrimes	inodirty();
6471558Srgrimes	if (newinofmt)
64841474Sjulian		inoinfo(ino)->ino_type = IFTODT(type);
6491558Srgrimes	return (ino);
6501558Srgrimes}
6511558Srgrimes
6521558Srgrimes/*
6531558Srgrimes * deallocate an inode
6541558Srgrimes */
6557585Sbdevoid
6561558Srgrimesfreeino(ino)
6571558Srgrimes	ino_t ino;
6581558Srgrimes{
6591558Srgrimes	struct inodesc idesc;
6601558Srgrimes	struct dinode *dp;
6611558Srgrimes
66223675Speter	memset(&idesc, 0, sizeof(struct inodesc));
6631558Srgrimes	idesc.id_type = ADDR;
6641558Srgrimes	idesc.id_func = pass4check;
6651558Srgrimes	idesc.id_number = ino;
6661558Srgrimes	dp = ginode(ino);
6671558Srgrimes	(void)ckinode(dp, &idesc);
6681558Srgrimes	clearinode(dp);
6691558Srgrimes	inodirty();
67041474Sjulian	inoinfo(ino)->ino_state = USTATE;
6711558Srgrimes	n_files--;
6721558Srgrimes}
673