inode.c revision 92839
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 92839 2002-03-20 22:57:10Z imp $";
401558Srgrimes#endif /* not lint */
411558Srgrimes
421558Srgrimes#include <sys/param.h>
431558Srgrimes#include <sys/time.h>
4474556Smckusick#include <sys/sysctl.h>
4523675Speter
461558Srgrimes#include <ufs/ufs/dinode.h>
471558Srgrimes#include <ufs/ufs/dir.h>
481558Srgrimes#include <ufs/ffs/fs.h>
4923675Speter
5023675Speter#include <err.h>
511558Srgrimes#include <pwd.h>
521558Srgrimes#include <string.h>
5323675Speter
541558Srgrimes#include "fsck.h"
551558Srgrimes
561558Srgrimesstatic ino_t startinum;
571558Srgrimes
5892839Simpstatic int iblock(struct inodesc *, long ilevel, quad_t isize);
597585Sbde
607585Sbdeint
6192839Simpckinode(struct dinode *dp, struct inodesc *idesc)
621558Srgrimes{
6323675Speter	ufs_daddr_t *ap;
6441474Sjulian	int ret;
6541474Sjulian	long 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;
7362668Smckusick	idesc->id_lbn = -1;
741558Srgrimes	idesc->id_entryno = 0;
751558Srgrimes	idesc->id_filesize = dp->di_size;
761558Srgrimes	mode = dp->di_mode & IFMT;
771558Srgrimes	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
7841474Sjulian	    dp->di_size < (unsigned)sblock.fs_maxsymlinklen))
791558Srgrimes		return (KEEPON);
801558Srgrimes	dino = *dp;
811558Srgrimes	ndb = howmany(dino.di_size, sblock.fs_bsize);
821558Srgrimes	for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
8362668Smckusick		idesc->id_lbn++;
841558Srgrimes		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
851558Srgrimes			idesc->id_numfrags =
861558Srgrimes				numfrags(&sblock, fragroundup(&sblock, offset));
871558Srgrimes		else
881558Srgrimes			idesc->id_numfrags = sblock.fs_frag;
8918808Sguido		if (*ap == 0) {
9018808Sguido			if (idesc->id_type == DATA && ndb >= 0) {
9118808Sguido				/* An empty block in a directory XXX */
9218808Sguido				getpathname(pathbuf, idesc->id_number,
9318808Sguido						idesc->id_number);
9418808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
9518808Sguido					pathbuf);
9618808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
9718808Sguido					dp = ginode(idesc->id_number);
9818808Sguido                                	dp->di_size = (ap - &dino.di_db[0]) *
9918808Sguido					    sblock.fs_bsize;
10018808Sguido					printf(
10118808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
10218808Sguido					rerun = 1;
10318808Sguido                                	inodirty();
10418808Sguido
10518808Sguido                        	}
10618808Sguido			}
1071558Srgrimes			continue;
10818808Sguido		}
1091558Srgrimes		idesc->id_blkno = *ap;
11062668Smckusick		if (idesc->id_type != DATA)
1111558Srgrimes			ret = (*idesc->id_func)(idesc);
1121558Srgrimes		else
1131558Srgrimes			ret = dirscan(idesc);
1141558Srgrimes		if (ret & STOP)
1151558Srgrimes			return (ret);
1161558Srgrimes	}
1171558Srgrimes	idesc->id_numfrags = sblock.fs_frag;
1181558Srgrimes	remsize = dino.di_size - sblock.fs_bsize * NDADDR;
1191558Srgrimes	sizepb = sblock.fs_bsize;
1201558Srgrimes	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
12162668Smckusick		sizepb *= NINDIR(&sblock);
1221558Srgrimes		if (*ap) {
1231558Srgrimes			idesc->id_blkno = *ap;
1241558Srgrimes			ret = iblock(idesc, n, remsize);
1251558Srgrimes			if (ret & STOP)
1261558Srgrimes				return (ret);
12718808Sguido		} else {
12862668Smckusick			idesc->id_lbn += sizepb / sblock.fs_bsize;
12918808Sguido			if (idesc->id_type == DATA && remsize > 0) {
13018808Sguido				/* An empty block in a directory XXX */
13118808Sguido				getpathname(pathbuf, idesc->id_number,
13218808Sguido						idesc->id_number);
13318808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
13418808Sguido					pathbuf);
13518808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
13618808Sguido					dp = ginode(idesc->id_number);
13718808Sguido                                	dp->di_size -= remsize;
13818808Sguido					remsize = 0;
13918808Sguido					printf(
14018808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
14118808Sguido					rerun = 1;
14218808Sguido                                	inodirty();
14318808Sguido					break;
14418808Sguido                        	}
14518808Sguido			}
1461558Srgrimes		}
1471558Srgrimes		remsize -= sizepb;
1481558Srgrimes	}
1491558Srgrimes	return (KEEPON);
1501558Srgrimes}
1511558Srgrimes
1527585Sbdestatic int
15392839Simpiblock(struct inodesc *idesc, long ilevel, 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
16462668Smckusick	if (idesc->id_type != DATA) {
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);
18676352Smckusick			if (preen) {
18781911Skris				pfatal("%s", buf);
18874556Smckusick			} else if (dofix(idesc, buf)) {
1891558Srgrimes				*ap = 0;
1901558Srgrimes				dirty(bp);
1911558Srgrimes			}
1921558Srgrimes		}
1931558Srgrimes		flush(fswritefd, bp);
1941558Srgrimes	}
1951558Srgrimes	aplim = &bp->b_un.b_indir[nif];
1961558Srgrimes	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
19762668Smckusick		if (ilevel == 0)
19862668Smckusick			idesc->id_lbn++;
1991558Srgrimes		if (*ap) {
2001558Srgrimes			idesc->id_blkno = *ap;
2011558Srgrimes			if (ilevel == 0)
2021558Srgrimes				n = (*func)(idesc);
2031558Srgrimes			else
2041558Srgrimes				n = iblock(idesc, ilevel, isize);
2051558Srgrimes			if (n & STOP) {
2061558Srgrimes				bp->b_flags &= ~B_INUSE;
2071558Srgrimes				return (n);
2081558Srgrimes			}
20918808Sguido		} else {
21018808Sguido			if (idesc->id_type == DATA && isize > 0) {
21118808Sguido				/* An empty block in a directory XXX */
21218808Sguido				getpathname(pathbuf, idesc->id_number,
21318808Sguido						idesc->id_number);
21418808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
21518808Sguido					pathbuf);
21618808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
21718808Sguido					dp = ginode(idesc->id_number);
21818808Sguido                                	dp->di_size -= isize;
21918808Sguido					isize = 0;
22018808Sguido					printf(
22118808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
22218808Sguido					rerun = 1;
22318808Sguido                                	inodirty();
22418808Sguido					bp->b_flags &= ~B_INUSE;
22518808Sguido					return(STOP);
22618808Sguido                        	}
22718808Sguido			}
2281558Srgrimes		}
2291558Srgrimes		isize -= sizepb;
2301558Srgrimes	}
2311558Srgrimes	bp->b_flags &= ~B_INUSE;
2321558Srgrimes	return (KEEPON);
2331558Srgrimes}
2341558Srgrimes
2351558Srgrimes/*
2361558Srgrimes * Check that a block in a legal block number.
2371558Srgrimes * Return 0 if in range, 1 if out of range.
2381558Srgrimes */
2397585Sbdeint
24092839Simpchkrange(ufs_daddr_t blk, int cnt)
2411558Srgrimes{
24292806Sobrien	int c;
2431558Srgrimes
24441474Sjulian	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
24541474Sjulian	    cnt - 1 > maxfsblock - blk)
2461558Srgrimes		return (1);
24741474Sjulian	if (cnt > sblock.fs_frag ||
24841474Sjulian	    fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
24941474Sjulian		if (debug)
25086514Siedowse			printf("bad size: blk %ld, offset %i, size %d\n",
25186514Siedowse			    (long)blk, (int)fragnum(&sblock, blk), cnt);
25241474Sjulian		return (1);
25341474Sjulian	}
2541558Srgrimes	c = dtog(&sblock, blk);
2551558Srgrimes	if (blk < cgdmin(&sblock, c)) {
2561558Srgrimes		if ((blk + cnt) > cgsblock(&sblock, c)) {
2571558Srgrimes			if (debug) {
2581558Srgrimes				printf("blk %ld < cgdmin %ld;",
25937236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2601558Srgrimes				printf(" blk + cnt %ld > cgsbase %ld\n",
26137236Sbde				    (long)(blk + cnt),
26237236Sbde				    (long)cgsblock(&sblock, c));
2631558Srgrimes			}
2641558Srgrimes			return (1);
2651558Srgrimes		}
2661558Srgrimes	} else {
2671558Srgrimes		if ((blk + cnt) > cgbase(&sblock, c+1)) {
2681558Srgrimes			if (debug)  {
2691558Srgrimes				printf("blk %ld >= cgdmin %ld;",
27037236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2711558Srgrimes				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
27237236Sbde				    (long)(blk + cnt), (long)sblock.fs_fpg);
2731558Srgrimes			}
2741558Srgrimes			return (1);
2751558Srgrimes		}
2761558Srgrimes	}
2771558Srgrimes	return (0);
2781558Srgrimes}
2791558Srgrimes
2801558Srgrimes/*
2811558Srgrimes * General purpose interface for reading inodes.
2821558Srgrimes */
2831558Srgrimesstruct dinode *
28492839Simpginode(ino_t inumber)
2851558Srgrimes{
28623675Speter	ufs_daddr_t iblk;
2871558Srgrimes
2881558Srgrimes	if (inumber < ROOTINO || inumber > maxino)
28923675Speter		errx(EEXIT, "bad inode number %d to ginode", inumber);
2901558Srgrimes	if (startinum == 0 ||
2911558Srgrimes	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
2921558Srgrimes		iblk = ino_to_fsba(&sblock, inumber);
2931558Srgrimes		if (pbp != 0)
2941558Srgrimes			pbp->b_flags &= ~B_INUSE;
2951558Srgrimes		pbp = getdatablk(iblk, sblock.fs_bsize);
2961558Srgrimes		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
2971558Srgrimes	}
2981558Srgrimes	return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]);
2991558Srgrimes}
3001558Srgrimes
3011558Srgrimes/*
3021558Srgrimes * Special purpose version of ginode used to optimize first pass
3031558Srgrimes * over all the inodes in numerical order.
3041558Srgrimes */
30588413Salfredstatic ino_t nextino, lastinum, lastvalidinum;
30688413Salfredstatic long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
30788413Salfredstatic struct dinode *inodebuf;
3081558Srgrimes
3091558Srgrimesstruct dinode *
31092839Simpgetnextinode(ino_t inumber)
3111558Srgrimes{
3121558Srgrimes	long size;
31323675Speter	ufs_daddr_t dblk;
3141558Srgrimes	static struct dinode *dp;
3151558Srgrimes
31663231Smckusick	if (inumber != nextino++ || inumber > lastvalidinum)
31723675Speter		errx(EEXIT, "bad inode number %d to nextinode", inumber);
3181558Srgrimes	if (inumber >= lastinum) {
3191558Srgrimes		readcnt++;
3201558Srgrimes		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
3211558Srgrimes		if (readcnt % readpercg == 0) {
3221558Srgrimes			size = partialsize;
3231558Srgrimes			lastinum += partialcnt;
3241558Srgrimes		} else {
3251558Srgrimes			size = inobufsize;
3261558Srgrimes			lastinum += fullcnt;
3271558Srgrimes		}
32841474Sjulian		/*
32941474Sjulian		 * If bread returns an error, it will already have zeroed
33041474Sjulian		 * out the buffer, so we do not need to do so here.
33141474Sjulian		 */
33241474Sjulian		(void)bread(fsreadfd, (char *)inodebuf, dblk, size);
3331558Srgrimes		dp = inodebuf;
3341558Srgrimes	}
3351558Srgrimes	return (dp++);
3361558Srgrimes}
3371558Srgrimes
3387585Sbdevoid
33992839Simpsetinodebuf(ino_t inum)
3401558Srgrimes{
3411558Srgrimes
34241474Sjulian	if (inum % sblock.fs_ipg != 0)
34341474Sjulian		errx(EEXIT, "bad inode number %d to setinodebuf", inum);
34463231Smckusick	lastvalidinum = inum + sblock.fs_ipg - 1;
3451558Srgrimes	startinum = 0;
34641474Sjulian	nextino = inum;
34741474Sjulian	lastinum = inum;
3481558Srgrimes	readcnt = 0;
34941474Sjulian	if (inodebuf != NULL)
35041474Sjulian		return;
3511558Srgrimes	inobufsize = blkroundup(&sblock, INOBUFSIZE);
3521558Srgrimes	fullcnt = inobufsize / sizeof(struct dinode);
3531558Srgrimes	readpercg = sblock.fs_ipg / fullcnt;
3541558Srgrimes	partialcnt = sblock.fs_ipg % fullcnt;
3551558Srgrimes	partialsize = partialcnt * sizeof(struct dinode);
3561558Srgrimes	if (partialcnt != 0) {
3571558Srgrimes		readpercg++;
3581558Srgrimes	} else {
3591558Srgrimes		partialcnt = fullcnt;
3601558Srgrimes		partialsize = inobufsize;
3611558Srgrimes	}
36241474Sjulian	if ((inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
36337000Scharnier		errx(EEXIT, "cannot allocate space for inode buffer");
3641558Srgrimes}
3651558Srgrimes
3667585Sbdevoid
36792839Simpfreeinodebuf(void)
3681558Srgrimes{
3691558Srgrimes
3701558Srgrimes	if (inodebuf != NULL)
3711558Srgrimes		free((char *)inodebuf);
3721558Srgrimes	inodebuf = NULL;
3731558Srgrimes}
3741558Srgrimes
3751558Srgrimes/*
3761558Srgrimes * Routines to maintain information about directory inodes.
3771558Srgrimes * This is built during the first pass and used during the
3781558Srgrimes * second and third passes.
3791558Srgrimes *
3801558Srgrimes * Enter inodes into the cache.
3811558Srgrimes */
3827585Sbdevoid
38392839Simpcacheino(struct dinode *dp, ino_t inumber)
3841558Srgrimes{
38592806Sobrien	struct inoinfo *inp;
3861558Srgrimes	struct inoinfo **inpp;
38738002Sdfr	int blks;
3881558Srgrimes
3891558Srgrimes	blks = howmany(dp->di_size, sblock.fs_bsize);
3901558Srgrimes	if (blks > NDADDR)
3911558Srgrimes		blks = NDADDR + NIADDR;
3921558Srgrimes	inp = (struct inoinfo *)
39323675Speter		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
3941558Srgrimes	if (inp == NULL)
39541474Sjulian		errx(EEXIT, "cannot increase directory list");
39657573Smckusick	inpp = &inphead[inumber % dirhash];
3971558Srgrimes	inp->i_nexthash = *inpp;
3981558Srgrimes	*inpp = inp;
39941474Sjulian	inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0;
4001558Srgrimes	inp->i_dotdot = (ino_t)0;
4011558Srgrimes	inp->i_number = inumber;
4021558Srgrimes	inp->i_isize = dp->di_size;
40323675Speter	inp->i_numblks = blks * sizeof(ufs_daddr_t);
40423675Speter	memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
4051558Srgrimes	if (inplast == listmax) {
4061558Srgrimes		listmax += 100;
4071558Srgrimes		inpsort = (struct inoinfo **)realloc((char *)inpsort,
4081558Srgrimes		    (unsigned)listmax * sizeof(struct inoinfo *));
4091558Srgrimes		if (inpsort == NULL)
41023675Speter			errx(EEXIT, "cannot increase directory list");
4111558Srgrimes	}
4121558Srgrimes	inpsort[inplast++] = inp;
4131558Srgrimes}
4141558Srgrimes
4151558Srgrimes/*
4161558Srgrimes * Look up an inode cache structure.
4171558Srgrimes */
4181558Srgrimesstruct inoinfo *
41992839Simpgetinoinfo(ino_t inumber)
4201558Srgrimes{
42192806Sobrien	struct inoinfo *inp;
4221558Srgrimes
42357573Smckusick	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
4241558Srgrimes		if (inp->i_number != inumber)
4251558Srgrimes			continue;
4261558Srgrimes		return (inp);
4271558Srgrimes	}
42823675Speter	errx(EEXIT, "cannot find inode %d", inumber);
4291558Srgrimes	return ((struct inoinfo *)0);
4301558Srgrimes}
4311558Srgrimes
4321558Srgrimes/*
4331558Srgrimes * Clean up all the inode cache structure.
4341558Srgrimes */
4357585Sbdevoid
43692839Simpinocleanup(void)
4371558Srgrimes{
43892806Sobrien	struct inoinfo **inpp;
4391558Srgrimes
4401558Srgrimes	if (inphead == NULL)
4411558Srgrimes		return;
4421558Srgrimes	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
4431558Srgrimes		free((char *)(*inpp));
4441558Srgrimes	free((char *)inphead);
4451558Srgrimes	free((char *)inpsort);
4461558Srgrimes	inphead = inpsort = NULL;
4471558Srgrimes}
4488871Srgrimes
4497585Sbdevoid
45092839Simpinodirty(void)
4511558Srgrimes{
45223797Sbde
4531558Srgrimes	dirty(pbp);
4541558Srgrimes}
4551558Srgrimes
4567585Sbdevoid
45792839Simpclri(struct inodesc *idesc, char *type, int flag)
4581558Srgrimes{
45992806Sobrien	struct dinode *dp;
4601558Srgrimes
4611558Srgrimes	dp = ginode(idesc->id_number);
4621558Srgrimes	if (flag == 1) {
4631558Srgrimes		pwarn("%s %s", type,
4641558Srgrimes		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
4651558Srgrimes		pinode(idesc->id_number);
4661558Srgrimes	}
4671558Srgrimes	if (preen || reply("CLEAR") == 1) {
4681558Srgrimes		if (preen)
4691558Srgrimes			printf(" (CLEARED)\n");
4701558Srgrimes		n_files--;
47174556Smckusick		if (bkgrdflag == 0) {
47274556Smckusick			(void)ckinode(dp, idesc);
47374556Smckusick			inoinfo(idesc->id_number)->ino_state = USTATE;
47474556Smckusick			clearinode(dp);
47574556Smckusick			inodirty();
47674556Smckusick		} else {
47774556Smckusick			cmd.value = idesc->id_number;
47874556Smckusick			cmd.size = -dp->di_nlink;
47974556Smckusick			if (debug)
48086514Siedowse				printf("adjrefcnt ino %ld amt %ld\n",
48174556Smckusick				    (long)cmd.value, cmd.size);
48274556Smckusick			if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
48374556Smckusick			    &cmd, sizeof cmd) == -1)
48474556Smckusick				rwerror("ADJUST INODE", cmd.value);
48574556Smckusick		}
4861558Srgrimes	}
4871558Srgrimes}
4881558Srgrimes
4897585Sbdeint
49092839Simpfindname(struct inodesc *idesc)
4911558Srgrimes{
49292806Sobrien	struct direct *dirp = idesc->id_dirp;
4931558Srgrimes
49441474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
49541474Sjulian		idesc->id_entryno++;
4961558Srgrimes		return (KEEPON);
49741474Sjulian	}
49823675Speter	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
4991558Srgrimes	return (STOP|FOUND);
5001558Srgrimes}
5011558Srgrimes
5027585Sbdeint
50392839Simpfindino(struct inodesc *idesc)
5041558Srgrimes{
50592806Sobrien	struct direct *dirp = idesc->id_dirp;
5061558Srgrimes
5071558Srgrimes	if (dirp->d_ino == 0)
5081558Srgrimes		return (KEEPON);
5091558Srgrimes	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
5101558Srgrimes	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
5111558Srgrimes		idesc->id_parent = dirp->d_ino;
5121558Srgrimes		return (STOP|FOUND);
5131558Srgrimes	}
5141558Srgrimes	return (KEEPON);
5151558Srgrimes}
5161558Srgrimes
51741474Sjulianint
51892839Simpclearentry(struct inodesc *idesc)
51941474Sjulian{
52092806Sobrien	struct direct *dirp = idesc->id_dirp;
52141474Sjulian
52241474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
52341474Sjulian		idesc->id_entryno++;
52441474Sjulian		return (KEEPON);
52541474Sjulian	}
52641474Sjulian	dirp->d_ino = 0;
52741474Sjulian	return (STOP|FOUND|ALTERED);
52841474Sjulian}
52941474Sjulian
5307585Sbdevoid
53192839Simppinode(ino_t ino)
5321558Srgrimes{
53392806Sobrien	struct dinode *dp;
53492806Sobrien	char *p;
5351558Srgrimes	struct passwd *pw;
53624002Speter	time_t t;
5371558Srgrimes
53837236Sbde	printf(" I=%lu ", (u_long)ino);
5391558Srgrimes	if (ino < ROOTINO || ino > maxino)
5401558Srgrimes		return;
5411558Srgrimes	dp = ginode(ino);
5421558Srgrimes	printf(" OWNER=");
5431558Srgrimes	if ((pw = getpwuid((int)dp->di_uid)) != 0)
5441558Srgrimes		printf("%s ", pw->pw_name);
5451558Srgrimes	else
5461558Srgrimes		printf("%u ", (unsigned)dp->di_uid);
5471558Srgrimes	printf("MODE=%o\n", dp->di_mode);
5481558Srgrimes	if (preen)
5491558Srgrimes		printf("%s: ", cdevname);
5501558Srgrimes	printf("SIZE=%qu ", dp->di_size);
55124002Speter	t = dp->di_mtime;
55224002Speter	p = ctime(&t);
5531558Srgrimes	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
5541558Srgrimes}
5551558Srgrimes
5567585Sbdevoid
55792839Simpblkerror(ino_t ino, char *type, ufs_daddr_t blk)
5581558Srgrimes{
5591558Srgrimes
56086514Siedowse	pfatal("%ld %s I=%lu", (long)blk, type, (u_long)ino);
5611558Srgrimes	printf("\n");
56241474Sjulian	switch (inoinfo(ino)->ino_state) {
5631558Srgrimes
5641558Srgrimes	case FSTATE:
56541474Sjulian		inoinfo(ino)->ino_state = FCLEAR;
5661558Srgrimes		return;
5671558Srgrimes
5681558Srgrimes	case DSTATE:
56941474Sjulian		inoinfo(ino)->ino_state = DCLEAR;
5701558Srgrimes		return;
5711558Srgrimes
5721558Srgrimes	case FCLEAR:
5731558Srgrimes	case DCLEAR:
5741558Srgrimes		return;
5751558Srgrimes
5761558Srgrimes	default:
57741474Sjulian		errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
5781558Srgrimes		/* NOTREACHED */
5791558Srgrimes	}
5801558Srgrimes}
5811558Srgrimes
5821558Srgrimes/*
5831558Srgrimes * allocate an unused inode
5841558Srgrimes */
5851558Srgrimesino_t
58692839Simpallocino(ino_t request, int type)
5871558Srgrimes{
58892806Sobrien	ino_t ino;
58992806Sobrien	struct dinode *dp;
59034266Sjulian	struct cg *cgp = &cgrp;
59134266Sjulian	int cg;
5921558Srgrimes
5931558Srgrimes	if (request == 0)
5941558Srgrimes		request = ROOTINO;
59541474Sjulian	else if (inoinfo(request)->ino_state != USTATE)
5961558Srgrimes		return (0);
5971558Srgrimes	for (ino = request; ino < maxino; ino++)
59841474Sjulian		if (inoinfo(ino)->ino_state == USTATE)
5991558Srgrimes			break;
6001558Srgrimes	if (ino == maxino)
6011558Srgrimes		return (0);
60234266Sjulian	cg = ino_to_cg(&sblock, ino);
60334266Sjulian	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
60434266Sjulian	if (!cg_chkmagic(cgp))
60534266Sjulian		pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
60634266Sjulian	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
60734266Sjulian	cgp->cg_cs.cs_nifree--;
6081558Srgrimes	switch (type & IFMT) {
6091558Srgrimes	case IFDIR:
61041474Sjulian		inoinfo(ino)->ino_state = DSTATE;
61134266Sjulian		cgp->cg_cs.cs_ndir++;
6121558Srgrimes		break;
6131558Srgrimes	case IFREG:
6141558Srgrimes	case IFLNK:
61541474Sjulian		inoinfo(ino)->ino_state = FSTATE;
6161558Srgrimes		break;
6171558Srgrimes	default:
6181558Srgrimes		return (0);
6191558Srgrimes	}
62034266Sjulian	cgdirty();
6211558Srgrimes	dp = ginode(ino);
6221558Srgrimes	dp->di_db[0] = allocblk((long)1);
6231558Srgrimes	if (dp->di_db[0] == 0) {
62441474Sjulian		inoinfo(ino)->ino_state = USTATE;
6251558Srgrimes		return (0);
6261558Srgrimes	}
62741474Sjulian	dp->di_mode = type;
62834266Sjulian	dp->di_flags = 0;
62924002Speter	dp->di_atime = time(NULL);
6301558Srgrimes	dp->di_mtime = dp->di_ctime = dp->di_atime;
63141477Sjulian	dp->di_mtimensec = dp->di_ctimensec = dp->di_atimensec = 0;
6321558Srgrimes	dp->di_size = sblock.fs_fsize;
6331558Srgrimes	dp->di_blocks = btodb(sblock.fs_fsize);
6341558Srgrimes	n_files++;
6351558Srgrimes	inodirty();
6361558Srgrimes	if (newinofmt)
63741474Sjulian		inoinfo(ino)->ino_type = IFTODT(type);
6381558Srgrimes	return (ino);
6391558Srgrimes}
6401558Srgrimes
6411558Srgrimes/*
6421558Srgrimes * deallocate an inode
6431558Srgrimes */
6447585Sbdevoid
64592839Simpfreeino(ino_t ino)
6461558Srgrimes{
6471558Srgrimes	struct inodesc idesc;
6481558Srgrimes	struct dinode *dp;
6491558Srgrimes
65023675Speter	memset(&idesc, 0, sizeof(struct inodesc));
6511558Srgrimes	idesc.id_type = ADDR;
6521558Srgrimes	idesc.id_func = pass4check;
6531558Srgrimes	idesc.id_number = ino;
6541558Srgrimes	dp = ginode(ino);
6551558Srgrimes	(void)ckinode(dp, &idesc);
6561558Srgrimes	clearinode(dp);
6571558Srgrimes	inodirty();
65841474Sjulian	inoinfo(ino)->ino_state = USTATE;
6591558Srgrimes	n_files--;
6601558Srgrimes}
661