inode.c revision 37236
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
3537000Scharnier#if 0
3623675Speterstatic const char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
3737000Scharnier#endif
3837000Scharnierstatic const char rcsid[] =
3937236Sbde	"$Id: inode.c,v 1.14 1998/06/15 07:07:12 charnier Exp $";
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;
6523675Speter	long ret, n, ndb, offset;
661558Srgrimes	struct dinode dino;
671558Srgrimes	quad_t remsize, sizepb;
681558Srgrimes	mode_t mode;
6918808Sguido	char pathbuf[MAXPATHLEN + 1];
701558Srgrimes
711558Srgrimes	if (idesc->id_fix != IGNORE)
721558Srgrimes		idesc->id_fix = DONTKNOW;
731558Srgrimes	idesc->id_entryno = 0;
741558Srgrimes	idesc->id_filesize = dp->di_size;
751558Srgrimes	mode = dp->di_mode & IFMT;
761558Srgrimes	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
771820Sdg	    (dp->di_size < sblock.fs_maxsymlinklen || dp->di_blocks == 0)))
781558Srgrimes		return (KEEPON);
791558Srgrimes	dino = *dp;
801558Srgrimes	ndb = howmany(dino.di_size, sblock.fs_bsize);
811558Srgrimes	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
821558Srgrimes		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
831558Srgrimes			idesc->id_numfrags =
841558Srgrimes				numfrags(&sblock, fragroundup(&sblock, offset));
851558Srgrimes		else
861558Srgrimes			idesc->id_numfrags = sblock.fs_frag;
8718808Sguido		if (*ap == 0) {
8818808Sguido			if (idesc->id_type == DATA && ndb >= 0) {
8918808Sguido				/* An empty block in a directory XXX */
9018808Sguido				getpathname(pathbuf, idesc->id_number,
9118808Sguido						idesc->id_number);
9218808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
9318808Sguido					pathbuf);
9418808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
9518808Sguido					dp = ginode(idesc->id_number);
9618808Sguido                                	dp->di_size = (ap - &dino.di_db[0]) *
9718808Sguido					    sblock.fs_bsize;
9818808Sguido					printf(
9918808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
10018808Sguido					rerun = 1;
10118808Sguido                                	inodirty();
10218808Sguido
10318808Sguido                        	}
10418808Sguido			}
1051558Srgrimes			continue;
10618808Sguido		}
1071558Srgrimes		idesc->id_blkno = *ap;
1081558Srgrimes		if (idesc->id_type == ADDR)
1091558Srgrimes			ret = (*idesc->id_func)(idesc);
1101558Srgrimes		else
1111558Srgrimes			ret = dirscan(idesc);
1121558Srgrimes		if (ret & STOP)
1131558Srgrimes			return (ret);
1141558Srgrimes	}
1151558Srgrimes	idesc->id_numfrags = sblock.fs_frag;
1161558Srgrimes	remsize = dino.di_size - sblock.fs_bsize * NDADDR;
1171558Srgrimes	sizepb = sblock.fs_bsize;
1181558Srgrimes	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
1191558Srgrimes		if (*ap) {
1201558Srgrimes			idesc->id_blkno = *ap;
1211558Srgrimes			ret = iblock(idesc, n, remsize);
1221558Srgrimes			if (ret & STOP)
1231558Srgrimes				return (ret);
12418808Sguido		} else {
12518808Sguido			if (idesc->id_type == DATA && remsize > 0) {
12618808Sguido				/* An empty block in a directory XXX */
12718808Sguido				getpathname(pathbuf, idesc->id_number,
12818808Sguido						idesc->id_number);
12918808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
13018808Sguido					pathbuf);
13118808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
13218808Sguido					dp = ginode(idesc->id_number);
13318808Sguido                                	dp->di_size -= remsize;
13418808Sguido					remsize = 0;
13518808Sguido					printf(
13618808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
13718808Sguido					rerun = 1;
13818808Sguido                                	inodirty();
13918808Sguido					break;
14018808Sguido                        	}
14118808Sguido			}
1421558Srgrimes		}
1431558Srgrimes		sizepb *= NINDIR(&sblock);
1441558Srgrimes		remsize -= sizepb;
1451558Srgrimes	}
1461558Srgrimes	return (KEEPON);
1471558Srgrimes}
1481558Srgrimes
1497585Sbdestatic int
1501558Srgrimesiblock(idesc, ilevel, isize)
1511558Srgrimes	struct inodesc *idesc;
1521558Srgrimes	long ilevel;
1531558Srgrimes	quad_t isize;
1541558Srgrimes{
15523675Speter	ufs_daddr_t *ap;
15623675Speter	ufs_daddr_t *aplim;
15723675Speter	struct bufarea *bp;
1581558Srgrimes	int i, n, (*func)(), nif;
1591558Srgrimes	quad_t sizepb;
1601558Srgrimes	char buf[BUFSIZ];
16118808Sguido	char pathbuf[MAXPATHLEN + 1];
16218808Sguido	struct dinode *dp;
1631558Srgrimes
1641558Srgrimes	if (idesc->id_type == ADDR) {
1651558Srgrimes		func = idesc->id_func;
1661558Srgrimes		if (((n = (*func)(idesc)) & KEEPON) == 0)
1671558Srgrimes			return (n);
1681558Srgrimes	} else
1691558Srgrimes		func = dirscan;
1701558Srgrimes	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
1711558Srgrimes		return (SKIP);
1721558Srgrimes	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
1731558Srgrimes	ilevel--;
1741558Srgrimes	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
1751558Srgrimes		sizepb *= NINDIR(&sblock);
1761558Srgrimes	nif = howmany(isize , sizepb);
1771558Srgrimes	if (nif > NINDIR(&sblock))
1781558Srgrimes		nif = NINDIR(&sblock);
1791558Srgrimes	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
1801558Srgrimes		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
1811558Srgrimes		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
1821558Srgrimes			if (*ap == 0)
1831558Srgrimes				continue;
1841558Srgrimes			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
18537236Sbde			    (u_long)idesc->id_number);
1861558Srgrimes			if (dofix(idesc, buf)) {
1871558Srgrimes				*ap = 0;
1881558Srgrimes				dirty(bp);
1891558Srgrimes			}
1901558Srgrimes		}
1911558Srgrimes		flush(fswritefd, bp);
1921558Srgrimes	}
1931558Srgrimes	aplim = &bp->b_un.b_indir[nif];
1941558Srgrimes	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
1951558Srgrimes		if (*ap) {
1961558Srgrimes			idesc->id_blkno = *ap;
1971558Srgrimes			if (ilevel == 0)
1981558Srgrimes				n = (*func)(idesc);
1991558Srgrimes			else
2001558Srgrimes				n = iblock(idesc, ilevel, isize);
2011558Srgrimes			if (n & STOP) {
2021558Srgrimes				bp->b_flags &= ~B_INUSE;
2031558Srgrimes				return (n);
2041558Srgrimes			}
20518808Sguido		} else {
20618808Sguido			if (idesc->id_type == DATA && isize > 0) {
20718808Sguido				/* An empty block in a directory XXX */
20818808Sguido				getpathname(pathbuf, idesc->id_number,
20918808Sguido						idesc->id_number);
21018808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
21118808Sguido					pathbuf);
21218808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
21318808Sguido					dp = ginode(idesc->id_number);
21418808Sguido                                	dp->di_size -= isize;
21518808Sguido					isize = 0;
21618808Sguido					printf(
21718808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
21818808Sguido					rerun = 1;
21918808Sguido                                	inodirty();
22018808Sguido					bp->b_flags &= ~B_INUSE;
22118808Sguido					return(STOP);
22218808Sguido                        	}
22318808Sguido			}
2241558Srgrimes		}
2251558Srgrimes		isize -= sizepb;
2261558Srgrimes	}
2271558Srgrimes	bp->b_flags &= ~B_INUSE;
2281558Srgrimes	return (KEEPON);
2291558Srgrimes}
2301558Srgrimes
2311558Srgrimes/*
2321558Srgrimes * Check that a block in a legal block number.
2331558Srgrimes * Return 0 if in range, 1 if out of range.
2341558Srgrimes */
2357585Sbdeint
2361558Srgrimeschkrange(blk, cnt)
23723675Speter	ufs_daddr_t blk;
2381558Srgrimes	int cnt;
2391558Srgrimes{
2401558Srgrimes	register int c;
2411558Srgrimes
24231910Sbde	if (blk < 0 || blk >= maxfsblock || cnt < 0 || cnt > maxfsblock - blk)
2431558Srgrimes		return (1);
2441558Srgrimes	c = dtog(&sblock, blk);
2451558Srgrimes	if (blk < cgdmin(&sblock, c)) {
2461558Srgrimes		if ((blk + cnt) > cgsblock(&sblock, c)) {
2471558Srgrimes			if (debug) {
2481558Srgrimes				printf("blk %ld < cgdmin %ld;",
24937236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2501558Srgrimes				printf(" blk + cnt %ld > cgsbase %ld\n",
25137236Sbde				    (long)(blk + cnt),
25237236Sbde				    (long)cgsblock(&sblock, c));
2531558Srgrimes			}
2541558Srgrimes			return (1);
2551558Srgrimes		}
2561558Srgrimes	} else {
2571558Srgrimes		if ((blk + cnt) > cgbase(&sblock, c+1)) {
2581558Srgrimes			if (debug)  {
2591558Srgrimes				printf("blk %ld >= cgdmin %ld;",
26037236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2611558Srgrimes				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
26237236Sbde				    (long)(blk + cnt), (long)sblock.fs_fpg);
2631558Srgrimes			}
2641558Srgrimes			return (1);
2651558Srgrimes		}
2661558Srgrimes	}
2671558Srgrimes	return (0);
2681558Srgrimes}
2691558Srgrimes
2701558Srgrimes/*
2711558Srgrimes * General purpose interface for reading inodes.
2721558Srgrimes */
2731558Srgrimesstruct dinode *
2741558Srgrimesginode(inumber)
2751558Srgrimes	ino_t inumber;
2761558Srgrimes{
27723675Speter	ufs_daddr_t iblk;
2781558Srgrimes
2791558Srgrimes	if (inumber < ROOTINO || inumber > maxino)
28023675Speter		errx(EEXIT, "bad inode number %d to ginode", inumber);
2811558Srgrimes	if (startinum == 0 ||
2821558Srgrimes	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
2831558Srgrimes		iblk = ino_to_fsba(&sblock, inumber);
2841558Srgrimes		if (pbp != 0)
2851558Srgrimes			pbp->b_flags &= ~B_INUSE;
2861558Srgrimes		pbp = getdatablk(iblk, sblock.fs_bsize);
2871558Srgrimes		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
2881558Srgrimes	}
2891558Srgrimes	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
2901558Srgrimes}
2911558Srgrimes
2921558Srgrimes/*
2931558Srgrimes * Special purpose version of ginode used to optimize first pass
2941558Srgrimes * over all the inodes in numerical order.
2951558Srgrimes */
2961558Srgrimesino_t nextino, lastinum;
2971558Srgrimeslong readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
2981558Srgrimesstruct dinode *inodebuf;
2991558Srgrimes
3001558Srgrimesstruct dinode *
3011558Srgrimesgetnextinode(inumber)
3021558Srgrimes	ino_t inumber;
3031558Srgrimes{
3041558Srgrimes	long size;
30523675Speter	ufs_daddr_t dblk;
3061558Srgrimes	static struct dinode *dp;
3071558Srgrimes
3081558Srgrimes	if (inumber != nextino++ || inumber > maxino)
30923675Speter		errx(EEXIT, "bad inode number %d to nextinode", inumber);
3101558Srgrimes	if (inumber >= lastinum) {
3111558Srgrimes		readcnt++;
3121558Srgrimes		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
3131558Srgrimes		if (readcnt % readpercg == 0) {
3141558Srgrimes			size = partialsize;
3151558Srgrimes			lastinum += partialcnt;
3161558Srgrimes		} else {
3171558Srgrimes			size = inobufsize;
3181558Srgrimes			lastinum += fullcnt;
3191558Srgrimes		}
3201558Srgrimes		(void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */
3211558Srgrimes		dp = inodebuf;
3221558Srgrimes	}
3231558Srgrimes	return (dp++);
3241558Srgrimes}
3251558Srgrimes
3267585Sbdevoid
3271558Srgrimesresetinodebuf()
3281558Srgrimes{
3291558Srgrimes
3301558Srgrimes	startinum = 0;
3311558Srgrimes	nextino = 0;
3321558Srgrimes	lastinum = 0;
3331558Srgrimes	readcnt = 0;
3341558Srgrimes	inobufsize = blkroundup(&sblock, INOBUFSIZE);
3351558Srgrimes	fullcnt = inobufsize / sizeof(struct dinode);
3361558Srgrimes	readpercg = sblock.fs_ipg / fullcnt;
3371558Srgrimes	partialcnt = sblock.fs_ipg % fullcnt;
3381558Srgrimes	partialsize = partialcnt * sizeof(struct dinode);
3391558Srgrimes	if (partialcnt != 0) {
3401558Srgrimes		readpercg++;
3411558Srgrimes	} else {
3421558Srgrimes		partialcnt = fullcnt;
3431558Srgrimes		partialsize = inobufsize;
3441558Srgrimes	}
3451558Srgrimes	if (inodebuf == NULL &&
3461558Srgrimes	    (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
34737000Scharnier		errx(EEXIT, "cannot allocate space for inode buffer");
3481558Srgrimes	while (nextino < ROOTINO)
3491558Srgrimes		(void)getnextinode(nextino);
3501558Srgrimes}
3511558Srgrimes
3527585Sbdevoid
3531558Srgrimesfreeinodebuf()
3541558Srgrimes{
3551558Srgrimes
3561558Srgrimes	if (inodebuf != NULL)
3571558Srgrimes		free((char *)inodebuf);
3581558Srgrimes	inodebuf = NULL;
3591558Srgrimes}
3601558Srgrimes
3611558Srgrimes/*
3621558Srgrimes * Routines to maintain information about directory inodes.
3631558Srgrimes * This is built during the first pass and used during the
3641558Srgrimes * second and third passes.
3651558Srgrimes *
3661558Srgrimes * Enter inodes into the cache.
3671558Srgrimes */
3687585Sbdevoid
3691558Srgrimescacheino(dp, inumber)
3701558Srgrimes	register struct dinode *dp;
3711558Srgrimes	ino_t inumber;
3721558Srgrimes{
3731558Srgrimes	register struct inoinfo *inp;
3741558Srgrimes	struct inoinfo **inpp;
3751558Srgrimes	unsigned int blks;
3761558Srgrimes
3771558Srgrimes	blks = howmany(dp->di_size, sblock.fs_bsize);
3781558Srgrimes	if (blks > NDADDR)
3791558Srgrimes		blks = NDADDR + NIADDR;
3801558Srgrimes	inp = (struct inoinfo *)
38123675Speter		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
3821558Srgrimes	if (inp == NULL)
3831558Srgrimes		return;
3841558Srgrimes	inpp = &inphead[inumber % numdirs];
3851558Srgrimes	inp->i_nexthash = *inpp;
3861558Srgrimes	*inpp = inp;
3876404Sdg	if (inumber == ROOTINO)
3886404Sdg		inp->i_parent = ROOTINO;
3896404Sdg	else
3906404Sdg		inp->i_parent = (ino_t)0;
3911558Srgrimes	inp->i_dotdot = (ino_t)0;
3921558Srgrimes	inp->i_number = inumber;
3931558Srgrimes	inp->i_isize = dp->di_size;
39423675Speter	inp->i_numblks = blks * sizeof(ufs_daddr_t);
39523675Speter	memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
3961558Srgrimes	if (inplast == listmax) {
3971558Srgrimes		listmax += 100;
3981558Srgrimes		inpsort = (struct inoinfo **)realloc((char *)inpsort,
3991558Srgrimes		    (unsigned)listmax * sizeof(struct inoinfo *));
4001558Srgrimes		if (inpsort == NULL)
40123675Speter			errx(EEXIT, "cannot increase directory list");
4021558Srgrimes	}
4031558Srgrimes	inpsort[inplast++] = inp;
4041558Srgrimes}
4051558Srgrimes
4061558Srgrimes/*
4071558Srgrimes * Look up an inode cache structure.
4081558Srgrimes */
4091558Srgrimesstruct inoinfo *
4101558Srgrimesgetinoinfo(inumber)
4111558Srgrimes	ino_t inumber;
4121558Srgrimes{
4131558Srgrimes	register struct inoinfo *inp;
4141558Srgrimes
4151558Srgrimes	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
4161558Srgrimes		if (inp->i_number != inumber)
4171558Srgrimes			continue;
4181558Srgrimes		return (inp);
4191558Srgrimes	}
42023675Speter	errx(EEXIT, "cannot find inode %d", inumber);
4211558Srgrimes	return ((struct inoinfo *)0);
4221558Srgrimes}
4231558Srgrimes
4241558Srgrimes/*
4251558Srgrimes * Clean up all the inode cache structure.
4261558Srgrimes */
4277585Sbdevoid
4281558Srgrimesinocleanup()
4291558Srgrimes{
4301558Srgrimes	register struct inoinfo **inpp;
4311558Srgrimes
4321558Srgrimes	if (inphead == NULL)
4331558Srgrimes		return;
4341558Srgrimes	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
4351558Srgrimes		free((char *)(*inpp));
4361558Srgrimes	free((char *)inphead);
4371558Srgrimes	free((char *)inpsort);
4381558Srgrimes	inphead = inpsort = NULL;
4391558Srgrimes}
4408871Srgrimes
4417585Sbdevoid
4421558Srgrimesinodirty()
4431558Srgrimes{
44423797Sbde
4451558Srgrimes	dirty(pbp);
4461558Srgrimes}
4471558Srgrimes
4487585Sbdevoid
4491558Srgrimesclri(idesc, type, flag)
4501558Srgrimes	register struct inodesc *idesc;
4511558Srgrimes	char *type;
4521558Srgrimes	int flag;
4531558Srgrimes{
4541558Srgrimes	register struct dinode *dp;
4551558Srgrimes
4561558Srgrimes	dp = ginode(idesc->id_number);
4571558Srgrimes	if (flag == 1) {
4581558Srgrimes		pwarn("%s %s", type,
4591558Srgrimes		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
4601558Srgrimes		pinode(idesc->id_number);
4611558Srgrimes	}
4621558Srgrimes	if (preen || reply("CLEAR") == 1) {
4631558Srgrimes		if (preen)
4641558Srgrimes			printf(" (CLEARED)\n");
4651558Srgrimes		n_files--;
4661558Srgrimes		(void)ckinode(dp, idesc);
4671558Srgrimes		clearinode(dp);
4681558Srgrimes		statemap[idesc->id_number] = USTATE;
4691558Srgrimes		inodirty();
4701558Srgrimes	}
4711558Srgrimes}
4721558Srgrimes
4737585Sbdeint
4741558Srgrimesfindname(idesc)
4751558Srgrimes	struct inodesc *idesc;
4761558Srgrimes{
4771558Srgrimes	register struct direct *dirp = idesc->id_dirp;
4781558Srgrimes
4791558Srgrimes	if (dirp->d_ino != idesc->id_parent)
4801558Srgrimes		return (KEEPON);
48123675Speter	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
4821558Srgrimes	return (STOP|FOUND);
4831558Srgrimes}
4841558Srgrimes
4857585Sbdeint
4861558Srgrimesfindino(idesc)
4871558Srgrimes	struct inodesc *idesc;
4881558Srgrimes{
4891558Srgrimes	register struct direct *dirp = idesc->id_dirp;
4901558Srgrimes
4911558Srgrimes	if (dirp->d_ino == 0)
4921558Srgrimes		return (KEEPON);
4931558Srgrimes	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
4941558Srgrimes	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
4951558Srgrimes		idesc->id_parent = dirp->d_ino;
4961558Srgrimes		return (STOP|FOUND);
4971558Srgrimes	}
4981558Srgrimes	return (KEEPON);
4991558Srgrimes}
5001558Srgrimes
5017585Sbdevoid
5021558Srgrimespinode(ino)
5031558Srgrimes	ino_t ino;
5041558Srgrimes{
5051558Srgrimes	register struct dinode *dp;
5061558Srgrimes	register char *p;
5071558Srgrimes	struct passwd *pw;
50824002Speter	time_t t;
5091558Srgrimes
51037236Sbde	printf(" I=%lu ", (u_long)ino);
5111558Srgrimes	if (ino < ROOTINO || ino > maxino)
5121558Srgrimes		return;
5131558Srgrimes	dp = ginode(ino);
5141558Srgrimes	printf(" OWNER=");
5151558Srgrimes	if ((pw = getpwuid((int)dp->di_uid)) != 0)
5161558Srgrimes		printf("%s ", pw->pw_name);
5171558Srgrimes	else
5181558Srgrimes		printf("%u ", (unsigned)dp->di_uid);
5191558Srgrimes	printf("MODE=%o\n", dp->di_mode);
5201558Srgrimes	if (preen)
5211558Srgrimes		printf("%s: ", cdevname);
5221558Srgrimes	printf("SIZE=%qu ", dp->di_size);
52324002Speter	t = dp->di_mtime;
52424002Speter	p = ctime(&t);
5251558Srgrimes	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
5261558Srgrimes}
5271558Srgrimes
5287585Sbdevoid
5291558Srgrimesblkerror(ino, type, blk)
5301558Srgrimes	ino_t ino;
5311558Srgrimes	char *type;
53223675Speter	ufs_daddr_t blk;
5331558Srgrimes{
5341558Srgrimes
5351558Srgrimes	pfatal("%ld %s I=%lu", blk, type, ino);
5361558Srgrimes	printf("\n");
5371558Srgrimes	switch (statemap[ino]) {
5381558Srgrimes
5391558Srgrimes	case FSTATE:
5401558Srgrimes		statemap[ino] = FCLEAR;
5411558Srgrimes		return;
5421558Srgrimes
5431558Srgrimes	case DSTATE:
5441558Srgrimes		statemap[ino] = DCLEAR;
5451558Srgrimes		return;
5461558Srgrimes
5471558Srgrimes	case FCLEAR:
5481558Srgrimes	case DCLEAR:
5491558Srgrimes		return;
5501558Srgrimes
5511558Srgrimes	default:
55223675Speter		errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
5531558Srgrimes		/* NOTREACHED */
5541558Srgrimes	}
5551558Srgrimes}
5561558Srgrimes
5571558Srgrimes/*
5581558Srgrimes * allocate an unused inode
5591558Srgrimes */
5601558Srgrimesino_t
5611558Srgrimesallocino(request, type)
5621558Srgrimes	ino_t request;
5631558Srgrimes	int type;
5641558Srgrimes{
5651558Srgrimes	register ino_t ino;
5661558Srgrimes	register struct dinode *dp;
56734266Sjulian	struct cg *cgp = &cgrp;
56834266Sjulian	int cg;
5691558Srgrimes
5701558Srgrimes	if (request == 0)
5711558Srgrimes		request = ROOTINO;
5721558Srgrimes	else if (statemap[request] != USTATE)
5731558Srgrimes		return (0);
5741558Srgrimes	for (ino = request; ino < maxino; ino++)
5751558Srgrimes		if (statemap[ino] == USTATE)
5761558Srgrimes			break;
5771558Srgrimes	if (ino == maxino)
5781558Srgrimes		return (0);
57934266Sjulian	cg = ino_to_cg(&sblock, ino);
58034266Sjulian	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
58134266Sjulian	if (!cg_chkmagic(cgp))
58234266Sjulian		pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
58334266Sjulian	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
58434266Sjulian	cgp->cg_cs.cs_nifree--;
5851558Srgrimes	switch (type & IFMT) {
5861558Srgrimes	case IFDIR:
5871558Srgrimes		statemap[ino] = DSTATE;
58834266Sjulian		cgp->cg_cs.cs_ndir++;
5891558Srgrimes		break;
5901558Srgrimes	case IFREG:
5911558Srgrimes	case IFLNK:
5921558Srgrimes		statemap[ino] = FSTATE;
5931558Srgrimes		break;
5941558Srgrimes	default:
5951558Srgrimes		return (0);
5961558Srgrimes	}
59734266Sjulian	cgdirty();
5981558Srgrimes	dp = ginode(ino);
5991558Srgrimes	dp->di_db[0] = allocblk((long)1);
6001558Srgrimes	if (dp->di_db[0] == 0) {
6011558Srgrimes		statemap[ino] = USTATE;
6021558Srgrimes		return (0);
6031558Srgrimes	}
60434266Sjulian	dp->di_flags = 0;
6051558Srgrimes	dp->di_mode = type;
60624002Speter	dp->di_atime = time(NULL);
6071558Srgrimes	dp->di_mtime = dp->di_ctime = dp->di_atime;
6081558Srgrimes	dp->di_size = sblock.fs_fsize;
6091558Srgrimes	dp->di_blocks = btodb(sblock.fs_fsize);
6101558Srgrimes	n_files++;
6111558Srgrimes	inodirty();
6121558Srgrimes	if (newinofmt)
6131558Srgrimes		typemap[ino] = IFTODT(type);
6141558Srgrimes	return (ino);
6151558Srgrimes}
6161558Srgrimes
6171558Srgrimes/*
6181558Srgrimes * deallocate an inode
6191558Srgrimes */
6207585Sbdevoid
6211558Srgrimesfreeino(ino)
6221558Srgrimes	ino_t ino;
6231558Srgrimes{
6241558Srgrimes	struct inodesc idesc;
6251558Srgrimes	struct dinode *dp;
6261558Srgrimes
62723675Speter	memset(&idesc, 0, sizeof(struct inodesc));
6281558Srgrimes	idesc.id_type = ADDR;
6291558Srgrimes	idesc.id_func = pass4check;
6301558Srgrimes	idesc.id_number = ino;
6311558Srgrimes	dp = ginode(ino);
6321558Srgrimes	(void)ckinode(dp, &idesc);
6331558Srgrimes	clearinode(dp);
6341558Srgrimes	inodirty();
6351558Srgrimes	statemap[ino] = USTATE;
6361558Srgrimes	n_files--;
6371558Srgrimes}
638