inode.c revision 57573
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 57573 2000-02-28 20:02:41Z 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;
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++) {
831558Srgrimes		if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
841558Srgrimes			idesc->id_numfrags =
851558Srgrimes				numfrags(&sblock, fragroundup(&sblock, offset));
861558Srgrimes		else
871558Srgrimes			idesc->id_numfrags = sblock.fs_frag;
8818808Sguido		if (*ap == 0) {
8918808Sguido			if (idesc->id_type == DATA && ndb >= 0) {
9018808Sguido				/* An empty block in a directory XXX */
9118808Sguido				getpathname(pathbuf, idesc->id_number,
9218808Sguido						idesc->id_number);
9318808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
9418808Sguido					pathbuf);
9518808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
9618808Sguido					dp = ginode(idesc->id_number);
9718808Sguido                                	dp->di_size = (ap - &dino.di_db[0]) *
9818808Sguido					    sblock.fs_bsize;
9918808Sguido					printf(
10018808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
10118808Sguido					rerun = 1;
10218808Sguido                                	inodirty();
10318808Sguido
10418808Sguido                        	}
10518808Sguido			}
1061558Srgrimes			continue;
10718808Sguido		}
1081558Srgrimes		idesc->id_blkno = *ap;
1091558Srgrimes		if (idesc->id_type == ADDR)
1101558Srgrimes			ret = (*idesc->id_func)(idesc);
1111558Srgrimes		else
1121558Srgrimes			ret = dirscan(idesc);
1131558Srgrimes		if (ret & STOP)
1141558Srgrimes			return (ret);
1151558Srgrimes	}
1161558Srgrimes	idesc->id_numfrags = sblock.fs_frag;
1171558Srgrimes	remsize = dino.di_size - sblock.fs_bsize * NDADDR;
1181558Srgrimes	sizepb = sblock.fs_bsize;
1191558Srgrimes	for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) {
1201558Srgrimes		if (*ap) {
1211558Srgrimes			idesc->id_blkno = *ap;
1221558Srgrimes			ret = iblock(idesc, n, remsize);
1231558Srgrimes			if (ret & STOP)
1241558Srgrimes				return (ret);
12518808Sguido		} else {
12618808Sguido			if (idesc->id_type == DATA && remsize > 0) {
12718808Sguido				/* An empty block in a directory XXX */
12818808Sguido				getpathname(pathbuf, idesc->id_number,
12918808Sguido						idesc->id_number);
13018808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
13118808Sguido					pathbuf);
13218808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
13318808Sguido					dp = ginode(idesc->id_number);
13418808Sguido                                	dp->di_size -= remsize;
13518808Sguido					remsize = 0;
13618808Sguido					printf(
13718808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
13818808Sguido					rerun = 1;
13918808Sguido                                	inodirty();
14018808Sguido					break;
14118808Sguido                        	}
14218808Sguido			}
1431558Srgrimes		}
1441558Srgrimes		sizepb *= NINDIR(&sblock);
1451558Srgrimes		remsize -= sizepb;
1461558Srgrimes	}
1471558Srgrimes	return (KEEPON);
1481558Srgrimes}
1491558Srgrimes
1507585Sbdestatic int
1511558Srgrimesiblock(idesc, ilevel, isize)
1521558Srgrimes	struct inodesc *idesc;
1531558Srgrimes	long ilevel;
1541558Srgrimes	quad_t isize;
1551558Srgrimes{
15623675Speter	ufs_daddr_t *ap;
15723675Speter	ufs_daddr_t *aplim;
15823675Speter	struct bufarea *bp;
1591558Srgrimes	int i, n, (*func)(), nif;
1601558Srgrimes	quad_t sizepb;
1611558Srgrimes	char buf[BUFSIZ];
16218808Sguido	char pathbuf[MAXPATHLEN + 1];
16318808Sguido	struct dinode *dp;
1641558Srgrimes
1651558Srgrimes	if (idesc->id_type == ADDR) {
1661558Srgrimes		func = idesc->id_func;
1671558Srgrimes		if (((n = (*func)(idesc)) & KEEPON) == 0)
1681558Srgrimes			return (n);
1691558Srgrimes	} else
1701558Srgrimes		func = dirscan;
1711558Srgrimes	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
1721558Srgrimes		return (SKIP);
1731558Srgrimes	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
1741558Srgrimes	ilevel--;
1751558Srgrimes	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
1761558Srgrimes		sizepb *= NINDIR(&sblock);
1771558Srgrimes	nif = howmany(isize , sizepb);
1781558Srgrimes	if (nif > NINDIR(&sblock))
1791558Srgrimes		nif = NINDIR(&sblock);
1801558Srgrimes	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
1811558Srgrimes		aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
1821558Srgrimes		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
1831558Srgrimes			if (*ap == 0)
1841558Srgrimes				continue;
1851558Srgrimes			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
18637236Sbde			    (u_long)idesc->id_number);
1871558Srgrimes			if (dofix(idesc, buf)) {
1881558Srgrimes				*ap = 0;
1891558Srgrimes				dirty(bp);
1901558Srgrimes			}
1911558Srgrimes		}
1921558Srgrimes		flush(fswritefd, bp);
1931558Srgrimes	}
1941558Srgrimes	aplim = &bp->b_un.b_indir[nif];
1951558Srgrimes	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
1961558Srgrimes		if (*ap) {
1971558Srgrimes			idesc->id_blkno = *ap;
1981558Srgrimes			if (ilevel == 0)
1991558Srgrimes				n = (*func)(idesc);
2001558Srgrimes			else
2011558Srgrimes				n = iblock(idesc, ilevel, isize);
2021558Srgrimes			if (n & STOP) {
2031558Srgrimes				bp->b_flags &= ~B_INUSE;
2041558Srgrimes				return (n);
2051558Srgrimes			}
20618808Sguido		} else {
20718808Sguido			if (idesc->id_type == DATA && isize > 0) {
20818808Sguido				/* An empty block in a directory XXX */
20918808Sguido				getpathname(pathbuf, idesc->id_number,
21018808Sguido						idesc->id_number);
21118808Sguido                        	pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
21218808Sguido					pathbuf);
21318808Sguido                        	if (reply("ADJUST LENGTH") == 1) {
21418808Sguido					dp = ginode(idesc->id_number);
21518808Sguido                                	dp->di_size -= isize;
21618808Sguido					isize = 0;
21718808Sguido					printf(
21818808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
21918808Sguido					rerun = 1;
22018808Sguido                                	inodirty();
22118808Sguido					bp->b_flags &= ~B_INUSE;
22218808Sguido					return(STOP);
22318808Sguido                        	}
22418808Sguido			}
2251558Srgrimes		}
2261558Srgrimes		isize -= sizepb;
2271558Srgrimes	}
2281558Srgrimes	bp->b_flags &= ~B_INUSE;
2291558Srgrimes	return (KEEPON);
2301558Srgrimes}
2311558Srgrimes
2321558Srgrimes/*
2331558Srgrimes * Check that a block in a legal block number.
2341558Srgrimes * Return 0 if in range, 1 if out of range.
2351558Srgrimes */
2367585Sbdeint
2371558Srgrimeschkrange(blk, cnt)
23823675Speter	ufs_daddr_t blk;
2391558Srgrimes	int cnt;
2401558Srgrimes{
2411558Srgrimes	register int c;
2421558Srgrimes
24341474Sjulian	if (cnt <= 0 || blk <= 0 || blk > maxfsblock ||
24441474Sjulian	    cnt - 1 > maxfsblock - blk)
2451558Srgrimes		return (1);
24641474Sjulian	if (cnt > sblock.fs_frag ||
24741474Sjulian	    fragnum(&sblock, blk) + cnt > sblock.fs_frag) {
24841474Sjulian		if (debug)
24941474Sjulian			printf("bad size: blk %ld, offset %ld, size %ld\n",
25041474Sjulian				blk, fragnum(&sblock, blk), cnt);
25141474Sjulian		return (1);
25241474Sjulian	}
2531558Srgrimes	c = dtog(&sblock, blk);
2541558Srgrimes	if (blk < cgdmin(&sblock, c)) {
2551558Srgrimes		if ((blk + cnt) > cgsblock(&sblock, c)) {
2561558Srgrimes			if (debug) {
2571558Srgrimes				printf("blk %ld < cgdmin %ld;",
25837236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2591558Srgrimes				printf(" blk + cnt %ld > cgsbase %ld\n",
26037236Sbde				    (long)(blk + cnt),
26137236Sbde				    (long)cgsblock(&sblock, c));
2621558Srgrimes			}
2631558Srgrimes			return (1);
2641558Srgrimes		}
2651558Srgrimes	} else {
2661558Srgrimes		if ((blk + cnt) > cgbase(&sblock, c+1)) {
2671558Srgrimes			if (debug)  {
2681558Srgrimes				printf("blk %ld >= cgdmin %ld;",
26937236Sbde				    (long)blk, (long)cgdmin(&sblock, c));
2701558Srgrimes				printf(" blk + cnt %ld > sblock.fs_fpg %ld\n",
27137236Sbde				    (long)(blk + cnt), (long)sblock.fs_fpg);
2721558Srgrimes			}
2731558Srgrimes			return (1);
2741558Srgrimes		}
2751558Srgrimes	}
2761558Srgrimes	return (0);
2771558Srgrimes}
2781558Srgrimes
2791558Srgrimes/*
2801558Srgrimes * General purpose interface for reading inodes.
2811558Srgrimes */
2821558Srgrimesstruct dinode *
2831558Srgrimesginode(inumber)
2841558Srgrimes	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 */
3051558Srgrimesino_t nextino, lastinum;
3061558Srgrimeslong readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
3071558Srgrimesstruct dinode *inodebuf;
3081558Srgrimes
3091558Srgrimesstruct dinode *
3101558Srgrimesgetnextinode(inumber)
3111558Srgrimes	ino_t inumber;
3121558Srgrimes{
3131558Srgrimes	long size;
31423675Speter	ufs_daddr_t dblk;
3151558Srgrimes	static struct dinode *dp;
3161558Srgrimes
3171558Srgrimes	if (inumber != nextino++ || inumber > maxino)
31823675Speter		errx(EEXIT, "bad inode number %d to nextinode", inumber);
3191558Srgrimes	if (inumber >= lastinum) {
3201558Srgrimes		readcnt++;
3211558Srgrimes		dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
3221558Srgrimes		if (readcnt % readpercg == 0) {
3231558Srgrimes			size = partialsize;
3241558Srgrimes			lastinum += partialcnt;
3251558Srgrimes		} else {
3261558Srgrimes			size = inobufsize;
3271558Srgrimes			lastinum += fullcnt;
3281558Srgrimes		}
32941474Sjulian		/*
33041474Sjulian		 * If bread returns an error, it will already have zeroed
33141474Sjulian		 * out the buffer, so we do not need to do so here.
33241474Sjulian		 */
33341474Sjulian		(void)bread(fsreadfd, (char *)inodebuf, dblk, size);
3341558Srgrimes		dp = inodebuf;
3351558Srgrimes	}
3361558Srgrimes	return (dp++);
3371558Srgrimes}
3381558Srgrimes
3397585Sbdevoid
34041474Sjuliansetinodebuf(inum)
34141474Sjulian	ino_t inum;
3421558Srgrimes{
3431558Srgrimes
34441474Sjulian	if (inum % sblock.fs_ipg != 0)
34541474Sjulian		errx(EEXIT, "bad inode number %d to setinodebuf", inum);
3461558Srgrimes	startinum = 0;
34741474Sjulian	nextino = inum;
34841474Sjulian	lastinum = inum;
3491558Srgrimes	readcnt = 0;
35041474Sjulian	if (inodebuf != NULL)
35141474Sjulian		return;
3521558Srgrimes	inobufsize = blkroundup(&sblock, INOBUFSIZE);
3531558Srgrimes	fullcnt = inobufsize / sizeof(struct dinode);
3541558Srgrimes	readpercg = sblock.fs_ipg / fullcnt;
3551558Srgrimes	partialcnt = sblock.fs_ipg % fullcnt;
3561558Srgrimes	partialsize = partialcnt * sizeof(struct dinode);
3571558Srgrimes	if (partialcnt != 0) {
3581558Srgrimes		readpercg++;
3591558Srgrimes	} else {
3601558Srgrimes		partialcnt = fullcnt;
3611558Srgrimes		partialsize = inobufsize;
3621558Srgrimes	}
36341474Sjulian	if ((inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL)
36437000Scharnier		errx(EEXIT, "cannot allocate space for inode buffer");
3651558Srgrimes}
3661558Srgrimes
3677585Sbdevoid
3681558Srgrimesfreeinodebuf()
3691558Srgrimes{
3701558Srgrimes
3711558Srgrimes	if (inodebuf != NULL)
3721558Srgrimes		free((char *)inodebuf);
3731558Srgrimes	inodebuf = NULL;
3741558Srgrimes}
3751558Srgrimes
3761558Srgrimes/*
3771558Srgrimes * Routines to maintain information about directory inodes.
3781558Srgrimes * This is built during the first pass and used during the
3791558Srgrimes * second and third passes.
3801558Srgrimes *
3811558Srgrimes * Enter inodes into the cache.
3821558Srgrimes */
3837585Sbdevoid
3841558Srgrimescacheino(dp, inumber)
3851558Srgrimes	register struct dinode *dp;
3861558Srgrimes	ino_t inumber;
3871558Srgrimes{
3881558Srgrimes	register struct inoinfo *inp;
3891558Srgrimes	struct inoinfo **inpp;
39038002Sdfr	int blks;
3911558Srgrimes
3921558Srgrimes	blks = howmany(dp->di_size, sblock.fs_bsize);
3931558Srgrimes	if (blks > NDADDR)
3941558Srgrimes		blks = NDADDR + NIADDR;
3951558Srgrimes	inp = (struct inoinfo *)
39623675Speter		malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t));
3971558Srgrimes	if (inp == NULL)
39841474Sjulian		errx(EEXIT, "cannot increase directory list");
39957573Smckusick	inpp = &inphead[inumber % dirhash];
4001558Srgrimes	inp->i_nexthash = *inpp;
4011558Srgrimes	*inpp = inp;
40241474Sjulian	inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0;
4031558Srgrimes	inp->i_dotdot = (ino_t)0;
4041558Srgrimes	inp->i_number = inumber;
4051558Srgrimes	inp->i_isize = dp->di_size;
40623675Speter	inp->i_numblks = blks * sizeof(ufs_daddr_t);
40723675Speter	memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks);
4081558Srgrimes	if (inplast == listmax) {
4091558Srgrimes		listmax += 100;
4101558Srgrimes		inpsort = (struct inoinfo **)realloc((char *)inpsort,
4111558Srgrimes		    (unsigned)listmax * sizeof(struct inoinfo *));
4121558Srgrimes		if (inpsort == NULL)
41323675Speter			errx(EEXIT, "cannot increase directory list");
4141558Srgrimes	}
4151558Srgrimes	inpsort[inplast++] = inp;
4161558Srgrimes}
4171558Srgrimes
4181558Srgrimes/*
4191558Srgrimes * Look up an inode cache structure.
4201558Srgrimes */
4211558Srgrimesstruct inoinfo *
4221558Srgrimesgetinoinfo(inumber)
4231558Srgrimes	ino_t inumber;
4241558Srgrimes{
4251558Srgrimes	register struct inoinfo *inp;
4261558Srgrimes
42757573Smckusick	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
4281558Srgrimes		if (inp->i_number != inumber)
4291558Srgrimes			continue;
4301558Srgrimes		return (inp);
4311558Srgrimes	}
43223675Speter	errx(EEXIT, "cannot find inode %d", inumber);
4331558Srgrimes	return ((struct inoinfo *)0);
4341558Srgrimes}
4351558Srgrimes
4361558Srgrimes/*
4371558Srgrimes * Clean up all the inode cache structure.
4381558Srgrimes */
4397585Sbdevoid
4401558Srgrimesinocleanup()
4411558Srgrimes{
4421558Srgrimes	register struct inoinfo **inpp;
4431558Srgrimes
4441558Srgrimes	if (inphead == NULL)
4451558Srgrimes		return;
4461558Srgrimes	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
4471558Srgrimes		free((char *)(*inpp));
4481558Srgrimes	free((char *)inphead);
4491558Srgrimes	free((char *)inpsort);
4501558Srgrimes	inphead = inpsort = NULL;
4511558Srgrimes}
4528871Srgrimes
4537585Sbdevoid
4541558Srgrimesinodirty()
4551558Srgrimes{
45623797Sbde
4571558Srgrimes	dirty(pbp);
4581558Srgrimes}
4591558Srgrimes
4607585Sbdevoid
4611558Srgrimesclri(idesc, type, flag)
4621558Srgrimes	register struct inodesc *idesc;
4631558Srgrimes	char *type;
4641558Srgrimes	int flag;
4651558Srgrimes{
4661558Srgrimes	register struct dinode *dp;
4671558Srgrimes
4681558Srgrimes	dp = ginode(idesc->id_number);
4691558Srgrimes	if (flag == 1) {
4701558Srgrimes		pwarn("%s %s", type,
4711558Srgrimes		    (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
4721558Srgrimes		pinode(idesc->id_number);
4731558Srgrimes	}
4741558Srgrimes	if (preen || reply("CLEAR") == 1) {
4751558Srgrimes		if (preen)
4761558Srgrimes			printf(" (CLEARED)\n");
4771558Srgrimes		n_files--;
4781558Srgrimes		(void)ckinode(dp, idesc);
4791558Srgrimes		clearinode(dp);
48041474Sjulian		inoinfo(idesc->id_number)->ino_state = USTATE;
4811558Srgrimes		inodirty();
4821558Srgrimes	}
4831558Srgrimes}
4841558Srgrimes
4857585Sbdeint
4861558Srgrimesfindname(idesc)
4871558Srgrimes	struct inodesc *idesc;
4881558Srgrimes{
4891558Srgrimes	register struct direct *dirp = idesc->id_dirp;
4901558Srgrimes
49141474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
49241474Sjulian		idesc->id_entryno++;
4931558Srgrimes		return (KEEPON);
49441474Sjulian	}
49523675Speter	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
4961558Srgrimes	return (STOP|FOUND);
4971558Srgrimes}
4981558Srgrimes
4997585Sbdeint
5001558Srgrimesfindino(idesc)
5011558Srgrimes	struct inodesc *idesc;
5021558Srgrimes{
5031558Srgrimes	register struct direct *dirp = idesc->id_dirp;
5041558Srgrimes
5051558Srgrimes	if (dirp->d_ino == 0)
5061558Srgrimes		return (KEEPON);
5071558Srgrimes	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
5081558Srgrimes	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
5091558Srgrimes		idesc->id_parent = dirp->d_ino;
5101558Srgrimes		return (STOP|FOUND);
5111558Srgrimes	}
5121558Srgrimes	return (KEEPON);
5131558Srgrimes}
5141558Srgrimes
51541474Sjulianint
51641474Sjulianclearentry(idesc)
51741474Sjulian	struct inodesc *idesc;
51841474Sjulian{
51941474Sjulian	register struct direct *dirp = idesc->id_dirp;
52041474Sjulian
52141474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
52241474Sjulian		idesc->id_entryno++;
52341474Sjulian		return (KEEPON);
52441474Sjulian	}
52541474Sjulian	dirp->d_ino = 0;
52641474Sjulian	return (STOP|FOUND|ALTERED);
52741474Sjulian}
52841474Sjulian
5297585Sbdevoid
5301558Srgrimespinode(ino)
5311558Srgrimes	ino_t ino;
5321558Srgrimes{
5331558Srgrimes	register struct dinode *dp;
5341558Srgrimes	register 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
5571558Srgrimesblkerror(ino, type, blk)
5581558Srgrimes	ino_t ino;
5591558Srgrimes	char *type;
56023675Speter	ufs_daddr_t blk;
5611558Srgrimes{
5621558Srgrimes
5631558Srgrimes	pfatal("%ld %s I=%lu", blk, type, ino);
5641558Srgrimes	printf("\n");
56541474Sjulian	switch (inoinfo(ino)->ino_state) {
5661558Srgrimes
5671558Srgrimes	case FSTATE:
56841474Sjulian		inoinfo(ino)->ino_state = FCLEAR;
5691558Srgrimes		return;
5701558Srgrimes
5711558Srgrimes	case DSTATE:
57241474Sjulian		inoinfo(ino)->ino_state = DCLEAR;
5731558Srgrimes		return;
5741558Srgrimes
5751558Srgrimes	case FCLEAR:
5761558Srgrimes	case DCLEAR:
5771558Srgrimes		return;
5781558Srgrimes
5791558Srgrimes	default:
58041474Sjulian		errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
5811558Srgrimes		/* NOTREACHED */
5821558Srgrimes	}
5831558Srgrimes}
5841558Srgrimes
5851558Srgrimes/*
5861558Srgrimes * allocate an unused inode
5871558Srgrimes */
5881558Srgrimesino_t
5891558Srgrimesallocino(request, type)
5901558Srgrimes	ino_t request;
5911558Srgrimes	int type;
5921558Srgrimes{
5931558Srgrimes	register ino_t ino;
5941558Srgrimes	register struct dinode *dp;
59534266Sjulian	struct cg *cgp = &cgrp;
59634266Sjulian	int cg;
5971558Srgrimes
5981558Srgrimes	if (request == 0)
5991558Srgrimes		request = ROOTINO;
60041474Sjulian	else if (inoinfo(request)->ino_state != USTATE)
6011558Srgrimes		return (0);
6021558Srgrimes	for (ino = request; ino < maxino; ino++)
60341474Sjulian		if (inoinfo(ino)->ino_state == USTATE)
6041558Srgrimes			break;
6051558Srgrimes	if (ino == maxino)
6061558Srgrimes		return (0);
60734266Sjulian	cg = ino_to_cg(&sblock, ino);
60834266Sjulian	getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
60934266Sjulian	if (!cg_chkmagic(cgp))
61034266Sjulian		pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
61134266Sjulian	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
61234266Sjulian	cgp->cg_cs.cs_nifree--;
6131558Srgrimes	switch (type & IFMT) {
6141558Srgrimes	case IFDIR:
61541474Sjulian		inoinfo(ino)->ino_state = DSTATE;
61634266Sjulian		cgp->cg_cs.cs_ndir++;
6171558Srgrimes		break;
6181558Srgrimes	case IFREG:
6191558Srgrimes	case IFLNK:
62041474Sjulian		inoinfo(ino)->ino_state = FSTATE;
6211558Srgrimes		break;
6221558Srgrimes	default:
6231558Srgrimes		return (0);
6241558Srgrimes	}
62534266Sjulian	cgdirty();
6261558Srgrimes	dp = ginode(ino);
6271558Srgrimes	dp->di_db[0] = allocblk((long)1);
6281558Srgrimes	if (dp->di_db[0] == 0) {
62941474Sjulian		inoinfo(ino)->ino_state = USTATE;
6301558Srgrimes		return (0);
6311558Srgrimes	}
63241474Sjulian	dp->di_mode = type;
63334266Sjulian	dp->di_flags = 0;
63424002Speter	dp->di_atime = time(NULL);
6351558Srgrimes	dp->di_mtime = dp->di_ctime = dp->di_atime;
63641477Sjulian	dp->di_mtimensec = dp->di_ctimensec = dp->di_atimensec = 0;
6371558Srgrimes	dp->di_size = sblock.fs_fsize;
6381558Srgrimes	dp->di_blocks = btodb(sblock.fs_fsize);
6391558Srgrimes	n_files++;
6401558Srgrimes	inodirty();
6411558Srgrimes	if (newinofmt)
64241474Sjulian		inoinfo(ino)->ino_type = IFTODT(type);
6431558Srgrimes	return (ino);
6441558Srgrimes}
6451558Srgrimes
6461558Srgrimes/*
6471558Srgrimes * deallocate an inode
6481558Srgrimes */
6497585Sbdevoid
6501558Srgrimesfreeino(ino)
6511558Srgrimes	ino_t ino;
6521558Srgrimes{
6531558Srgrimes	struct inodesc idesc;
6541558Srgrimes	struct dinode *dp;
6551558Srgrimes
65623675Speter	memset(&idesc, 0, sizeof(struct inodesc));
6571558Srgrimes	idesc.id_type = ADDR;
6581558Srgrimes	idesc.id_func = pass4check;
6591558Srgrimes	idesc.id_number = ino;
6601558Srgrimes	dp = ginode(ino);
6611558Srgrimes	(void)ckinode(dp, &idesc);
6621558Srgrimes	clearinode(dp);
6631558Srgrimes	inodirty();
66441474Sjulian	inoinfo(ino)->ino_state = USTATE;
6651558Srgrimes	n_files--;
6661558Srgrimes}
667