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 * 4. Neither the name of the University nor the names of its contributors
141558Srgrimes *    may be used to endorse or promote products derived from this software
151558Srgrimes *    without specific prior written permission.
161558Srgrimes *
171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271558Srgrimes * SUCH DAMAGE.
281558Srgrimes */
291558Srgrimes
30114589Sobrien#if 0
311558Srgrimes#ifndef lint
3223675Speterstatic const char sccsid[] = "@(#)inode.c	8.8 (Berkeley) 4/28/95";
33114589Sobrien#endif /* not lint */
3441477Sjulian#endif
35114589Sobrien#include <sys/cdefs.h>
36114589Sobrien__FBSDID("$FreeBSD$");
371558Srgrimes
381558Srgrimes#include <sys/param.h>
3998542Smckusick#include <sys/stdint.h>
4074556Smckusick#include <sys/sysctl.h>
4123675Speter
421558Srgrimes#include <ufs/ufs/dinode.h>
431558Srgrimes#include <ufs/ufs/dir.h>
441558Srgrimes#include <ufs/ffs/fs.h>
4523675Speter
4623675Speter#include <err.h>
471558Srgrimes#include <pwd.h>
481558Srgrimes#include <string.h>
49217769Smckusick#include <time.h>
5023675Speter
511558Srgrimes#include "fsck.h"
521558Srgrimes
531558Srgrimesstatic ino_t startinum;
541558Srgrimes
55249788Smckusickstatic int iblock(struct inodesc *, long ilevel, off_t isize, int type);
567585Sbde
577585Sbdeint
5898542Smckusickckinode(union dinode *dp, struct inodesc *idesc)
591558Srgrimes{
6098542Smckusick	off_t remsize, sizepb;
6198542Smckusick	int i, offset, ret;
6298542Smckusick	union dinode dino;
6398542Smckusick	ufs2_daddr_t ndb;
641558Srgrimes	mode_t mode;
6518808Sguido	char pathbuf[MAXPATHLEN + 1];
661558Srgrimes
671558Srgrimes	if (idesc->id_fix != IGNORE)
681558Srgrimes		idesc->id_fix = DONTKNOW;
6962668Smckusick	idesc->id_lbn = -1;
701558Srgrimes	idesc->id_entryno = 0;
7198542Smckusick	idesc->id_filesize = DIP(dp, di_size);
7298542Smckusick	mode = DIP(dp, di_mode) & IFMT;
731558Srgrimes	if (mode == IFBLK || mode == IFCHR || (mode == IFLNK &&
7498542Smckusick	    DIP(dp, di_size) < (unsigned)sblock.fs_maxsymlinklen))
751558Srgrimes		return (KEEPON);
7698542Smckusick	if (sblock.fs_magic == FS_UFS1_MAGIC)
7798542Smckusick		dino.dp1 = dp->dp1;
7898542Smckusick	else
7998542Smckusick		dino.dp2 = dp->dp2;
8098542Smckusick	ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize);
8198542Smckusick	for (i = 0; i < NDADDR; i++) {
8262668Smckusick		idesc->id_lbn++;
8398542Smckusick		if (--ndb == 0 &&
8498542Smckusick		    (offset = blkoff(&sblock, DIP(&dino, di_size))) != 0)
851558Srgrimes			idesc->id_numfrags =
861558Srgrimes				numfrags(&sblock, fragroundup(&sblock, offset));
871558Srgrimes		else
881558Srgrimes			idesc->id_numfrags = sblock.fs_frag;
8998542Smckusick		if (DIP(&dino, di_db[i]) == 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);
94221110Sdes				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
9518808Sguido					pathbuf);
96221110Sdes				if (reply("ADJUST LENGTH") == 1) {
9718808Sguido					dp = ginode(idesc->id_number);
98221110Sdes					DIP_SET(dp, di_size,
99134589Sscottl					    i * sblock.fs_bsize);
10018808Sguido					printf(
10118808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
10218808Sguido					rerun = 1;
103221110Sdes					inodirty();
104221110Sdes
105221110Sdes				}
10618808Sguido			}
1071558Srgrimes			continue;
10818808Sguido		}
10998542Smckusick		idesc->id_blkno = DIP(&dino, di_db[i]);
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;
11898542Smckusick	remsize = DIP(&dino, di_size) - sblock.fs_bsize * NDADDR;
1191558Srgrimes	sizepb = sblock.fs_bsize;
12098542Smckusick	for (i = 0; i < NIADDR; i++) {
12162668Smckusick		sizepb *= NINDIR(&sblock);
12298542Smckusick		if (DIP(&dino, di_ib[i])) {
12398542Smckusick			idesc->id_blkno = DIP(&dino, di_ib[i]);
124249788Smckusick			ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i);
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);
133221110Sdes				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
13418808Sguido					pathbuf);
135221110Sdes				if (reply("ADJUST LENGTH") == 1) {
13618808Sguido					dp = ginode(idesc->id_number);
137221110Sdes					DIP_SET(dp, di_size,
138134589Sscottl					    DIP(dp, di_size) - remsize);
13918808Sguido					remsize = 0;
14018808Sguido					printf(
14118808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
14218808Sguido					rerun = 1;
143221110Sdes					inodirty();
14418808Sguido					break;
145221110Sdes				}
14618808Sguido			}
1471558Srgrimes		}
1481558Srgrimes		remsize -= sizepb;
1491558Srgrimes	}
1501558Srgrimes	return (KEEPON);
1511558Srgrimes}
1521558Srgrimes
1537585Sbdestatic int
154249788Smckusickiblock(struct inodesc *idesc, long ilevel, off_t isize, int type)
1551558Srgrimes{
15623675Speter	struct bufarea *bp;
157100935Sphk	int i, n, (*func)(struct inodesc *), nif;
15898542Smckusick	off_t sizepb;
1591558Srgrimes	char buf[BUFSIZ];
16018808Sguido	char pathbuf[MAXPATHLEN + 1];
16198542Smckusick	union dinode *dp;
1621558Srgrimes
16362668Smckusick	if (idesc->id_type != DATA) {
1641558Srgrimes		func = idesc->id_func;
1651558Srgrimes		if (((n = (*func)(idesc)) & KEEPON) == 0)
1661558Srgrimes			return (n);
1671558Srgrimes	} else
1681558Srgrimes		func = dirscan;
1691558Srgrimes	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
1701558Srgrimes		return (SKIP);
171249788Smckusick	bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type);
1721558Srgrimes	ilevel--;
1731558Srgrimes	for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
1741558Srgrimes		sizepb *= NINDIR(&sblock);
17598542Smckusick	if (howmany(isize, sizepb) > NINDIR(&sblock))
1761558Srgrimes		nif = NINDIR(&sblock);
17798542Smckusick	else
17898542Smckusick		nif = howmany(isize, sizepb);
1791558Srgrimes	if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) {
18098542Smckusick		for (i = nif; i < NINDIR(&sblock); i++) {
18198542Smckusick			if (IBLK(bp, i) == 0)
1821558Srgrimes				continue;
1831558Srgrimes			(void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu",
18437236Sbde			    (u_long)idesc->id_number);
18576352Smckusick			if (preen) {
18681911Skris				pfatal("%s", buf);
18774556Smckusick			} else if (dofix(idesc, buf)) {
188134589Sscottl				IBLK_SET(bp, i, 0);
1891558Srgrimes				dirty(bp);
1901558Srgrimes			}
1911558Srgrimes		}
1921558Srgrimes		flush(fswritefd, bp);
1931558Srgrimes	}
19498542Smckusick	for (i = 0; i < nif; i++) {
19562668Smckusick		if (ilevel == 0)
19662668Smckusick			idesc->id_lbn++;
19798542Smckusick		if (IBLK(bp, i)) {
19898542Smckusick			idesc->id_blkno = IBLK(bp, i);
1991558Srgrimes			if (ilevel == 0)
2001558Srgrimes				n = (*func)(idesc);
2011558Srgrimes			else
202249788Smckusick				n = iblock(idesc, ilevel, isize, type);
2031558Srgrimes			if (n & STOP) {
2041558Srgrimes				bp->b_flags &= ~B_INUSE;
2051558Srgrimes				return (n);
2061558Srgrimes			}
20718808Sguido		} else {
20818808Sguido			if (idesc->id_type == DATA && isize > 0) {
20918808Sguido				/* An empty block in a directory XXX */
21018808Sguido				getpathname(pathbuf, idesc->id_number,
21118808Sguido						idesc->id_number);
212221110Sdes				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
21318808Sguido					pathbuf);
214221110Sdes				if (reply("ADJUST LENGTH") == 1) {
21518808Sguido					dp = ginode(idesc->id_number);
216221110Sdes					DIP_SET(dp, di_size,
217134589Sscottl					    DIP(dp, di_size) - isize);
21818808Sguido					isize = 0;
21918808Sguido					printf(
22018808Sguido					    "YOU MUST RERUN FSCK AFTERWARDS\n");
22118808Sguido					rerun = 1;
222221110Sdes					inodirty();
22318808Sguido					bp->b_flags &= ~B_INUSE;
22418808Sguido					return(STOP);
225221110Sdes				}
22618808Sguido			}
2271558Srgrimes		}
2281558Srgrimes		isize -= sizepb;
2291558Srgrimes	}
2301558Srgrimes	bp->b_flags &= ~B_INUSE;
2311558Srgrimes	return (KEEPON);
2321558Srgrimes}
2331558Srgrimes
2341558Srgrimes/*
2351558Srgrimes * Check that a block in a legal block number.
2361558Srgrimes * Return 0 if in range, 1 if out of range.
2371558Srgrimes */
2387585Sbdeint
23998542Smckusickchkrange(ufs2_daddr_t blk, int cnt)
2401558Srgrimes{
24192806Sobrien	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)
24986514Siedowse			printf("bad size: blk %ld, offset %i, size %d\n",
25086514Siedowse			    (long)blk, (int)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 */
28298542Smckusickunion dinode *
28392839Simpginode(ino_t inumber)
2841558Srgrimes{
28598542Smckusick	ufs2_daddr_t iblk;
2861558Srgrimes
2871558Srgrimes	if (inumber < ROOTINO || inumber > maxino)
28823675Speter		errx(EEXIT, "bad inode number %d to ginode", inumber);
2891558Srgrimes	if (startinum == 0 ||
2901558Srgrimes	    inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
2911558Srgrimes		iblk = ino_to_fsba(&sblock, inumber);
2921558Srgrimes		if (pbp != 0)
2931558Srgrimes			pbp->b_flags &= ~B_INUSE;
294249788Smckusick		pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES);
2951558Srgrimes		startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
2961558Srgrimes	}
29798542Smckusick	if (sblock.fs_magic == FS_UFS1_MAGIC)
29898542Smckusick		return ((union dinode *)
29998542Smckusick		    &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]);
30098542Smckusick	return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]);
3011558Srgrimes}
3021558Srgrimes
3031558Srgrimes/*
3041558Srgrimes * Special purpose version of ginode used to optimize first pass
3051558Srgrimes * over all the inodes in numerical order.
3061558Srgrimes */
30788413Salfredstatic ino_t nextino, lastinum, lastvalidinum;
308249788Smckusickstatic long readcount, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
309249788Smckusickstatic struct bufarea inobuf;
3101558Srgrimes
31198542Smckusickunion dinode *
312188110Smckusickgetnextinode(ino_t inumber, int rebuildcg)
3131558Srgrimes{
314188110Smckusick	int j;
3151558Srgrimes	long size;
316188110Smckusick	mode_t mode;
317249788Smckusick	ufs2_daddr_t ndb, blk;
31898542Smckusick	union dinode *dp;
31998542Smckusick	static caddr_t nextinop;
3201558Srgrimes
32163231Smckusick	if (inumber != nextino++ || inumber > lastvalidinum)
32223675Speter		errx(EEXIT, "bad inode number %d to nextinode", inumber);
3231558Srgrimes	if (inumber >= lastinum) {
324249788Smckusick		readcount++;
325249788Smckusick		blk = ino_to_fsba(&sblock, lastinum);
326249788Smckusick		if (readcount % readpercg == 0) {
3271558Srgrimes			size = partialsize;
3281558Srgrimes			lastinum += partialcnt;
3291558Srgrimes		} else {
3301558Srgrimes			size = inobufsize;
3311558Srgrimes			lastinum += fullcnt;
3321558Srgrimes		}
33341474Sjulian		/*
334249788Smckusick		 * If getblk encounters an error, it will already have zeroed
33541474Sjulian		 * out the buffer, so we do not need to do so here.
33641474Sjulian		 */
337249788Smckusick		getblk(&inobuf, blk, size);
338249788Smckusick		nextinop = inobuf.b_un.b_buf;
3391558Srgrimes	}
34098542Smckusick	dp = (union dinode *)nextinop;
341249788Smckusick	if (rebuildcg && nextinop == inobuf.b_un.b_buf) {
342188110Smckusick		/*
343188110Smckusick		 * Try to determine if we have reached the end of the
344188110Smckusick		 * allocated inodes.
345188110Smckusick		 */
346188110Smckusick		mode = DIP(dp, di_mode) & IFMT;
347188110Smckusick		if (mode == 0) {
348188110Smckusick			if (memcmp(dp->dp2.di_db, ufs2_zino.di_db,
349188110Smckusick				NDADDR * sizeof(ufs2_daddr_t)) ||
350188110Smckusick			      memcmp(dp->dp2.di_ib, ufs2_zino.di_ib,
351188110Smckusick				NIADDR * sizeof(ufs2_daddr_t)) ||
352188110Smckusick			      dp->dp2.di_mode || dp->dp2.di_size)
353188110Smckusick				return (NULL);
354188110Smckusick			goto inodegood;
355188110Smckusick		}
356188110Smckusick		if (!ftypeok(dp))
357188110Smckusick			return (NULL);
358188110Smckusick		ndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
359188110Smckusick		if (ndb < 0)
360188110Smckusick			return (NULL);
361188110Smckusick		if (mode == IFBLK || mode == IFCHR)
362188110Smckusick			ndb++;
363188110Smckusick		if (mode == IFLNK) {
364188110Smckusick			/*
365188110Smckusick			 * Fake ndb value so direct/indirect block checks below
366188110Smckusick			 * will detect any garbage after symlink string.
367188110Smckusick			 */
368188110Smckusick			if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) {
369188110Smckusick				ndb = howmany(DIP(dp, di_size),
370188110Smckusick				    sizeof(ufs2_daddr_t));
371188110Smckusick				if (ndb > NDADDR) {
372188110Smckusick					j = ndb - NDADDR;
373188110Smckusick					for (ndb = 1; j > 1; j--)
374188110Smckusick						ndb *= NINDIR(&sblock);
375188110Smckusick					ndb += NDADDR;
376188110Smckusick				}
377188110Smckusick			}
378188110Smckusick		}
379188110Smckusick		for (j = ndb; ndb < NDADDR && j < NDADDR; j++)
380188110Smckusick			if (DIP(dp, di_db[j]) != 0)
381188110Smckusick				return (NULL);
382188110Smckusick		for (j = 0, ndb -= NDADDR; ndb > 0; j++)
383188110Smckusick			ndb /= NINDIR(&sblock);
384188110Smckusick		for (; j < NIADDR; j++)
385188110Smckusick			if (DIP(dp, di_ib[j]) != 0)
386188110Smckusick				return (NULL);
387188110Smckusick	}
388188110Smckusickinodegood:
38998542Smckusick	if (sblock.fs_magic == FS_UFS1_MAGIC)
39098542Smckusick		nextinop += sizeof(struct ufs1_dinode);
39198542Smckusick	else
39298542Smckusick		nextinop += sizeof(struct ufs2_dinode);
39398542Smckusick	return (dp);
3941558Srgrimes}
3951558Srgrimes
3967585Sbdevoid
39792839Simpsetinodebuf(ino_t inum)
3981558Srgrimes{
3991558Srgrimes
40041474Sjulian	if (inum % sblock.fs_ipg != 0)
40141474Sjulian		errx(EEXIT, "bad inode number %d to setinodebuf", inum);
40263231Smckusick	lastvalidinum = inum + sblock.fs_ipg - 1;
4031558Srgrimes	startinum = 0;
40441474Sjulian	nextino = inum;
40541474Sjulian	lastinum = inum;
406249788Smckusick	readcount = 0;
407249788Smckusick	if (inobuf.b_un.b_buf != NULL)
40841474Sjulian		return;
4091558Srgrimes	inobufsize = blkroundup(&sblock, INOBUFSIZE);
41098542Smckusick	fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
41198542Smckusick	    sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
4121558Srgrimes	readpercg = sblock.fs_ipg / fullcnt;
4131558Srgrimes	partialcnt = sblock.fs_ipg % fullcnt;
41498542Smckusick	partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ?
41598542Smckusick	    sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode));
4161558Srgrimes	if (partialcnt != 0) {
4171558Srgrimes		readpercg++;
4181558Srgrimes	} else {
4191558Srgrimes		partialcnt = fullcnt;
4201558Srgrimes		partialsize = inobufsize;
4211558Srgrimes	}
422249788Smckusick	initbarea(&inobuf, BT_INODES);
423249788Smckusick	if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL)
42437000Scharnier		errx(EEXIT, "cannot allocate space for inode buffer");
4251558Srgrimes}
4261558Srgrimes
4277585Sbdevoid
42892839Simpfreeinodebuf(void)
4291558Srgrimes{
4301558Srgrimes
431249788Smckusick	if (inobuf.b_un.b_buf != NULL)
432249788Smckusick		free((char *)inobuf.b_un.b_buf);
433249788Smckusick	inobuf.b_un.b_buf = NULL;
4341558Srgrimes}
4351558Srgrimes
4361558Srgrimes/*
4371558Srgrimes * Routines to maintain information about directory inodes.
4381558Srgrimes * This is built during the first pass and used during the
4391558Srgrimes * second and third passes.
4401558Srgrimes *
4411558Srgrimes * Enter inodes into the cache.
4421558Srgrimes */
4437585Sbdevoid
44498542Smckusickcacheino(union dinode *dp, ino_t inumber)
4451558Srgrimes{
44698542Smckusick	struct inoinfo *inp, **inpp;
44798542Smckusick	int i, blks;
4481558Srgrimes
44998542Smckusick	if (howmany(DIP(dp, di_size), sblock.fs_bsize) > NDADDR)
4501558Srgrimes		blks = NDADDR + NIADDR;
45198542Smckusick	else
45298542Smckusick		blks = howmany(DIP(dp, di_size), sblock.fs_bsize);
4531558Srgrimes	inp = (struct inoinfo *)
454249788Smckusick		Malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
4551558Srgrimes	if (inp == NULL)
45641474Sjulian		errx(EEXIT, "cannot increase directory list");
45757573Smckusick	inpp = &inphead[inumber % dirhash];
4581558Srgrimes	inp->i_nexthash = *inpp;
4591558Srgrimes	*inpp = inp;
46041474Sjulian	inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0;
4611558Srgrimes	inp->i_dotdot = (ino_t)0;
4621558Srgrimes	inp->i_number = inumber;
46398542Smckusick	inp->i_isize = DIP(dp, di_size);
46498542Smckusick	inp->i_numblks = blks;
46598542Smckusick	for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++)
46698542Smckusick		inp->i_blks[i] = DIP(dp, di_db[i]);
46798542Smckusick	if (blks > NDADDR)
46898542Smckusick		for (i = 0; i < NIADDR; i++)
46998542Smckusick			inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]);
4701558Srgrimes	if (inplast == listmax) {
4711558Srgrimes		listmax += 100;
4721558Srgrimes		inpsort = (struct inoinfo **)realloc((char *)inpsort,
4731558Srgrimes		    (unsigned)listmax * sizeof(struct inoinfo *));
4741558Srgrimes		if (inpsort == NULL)
47523675Speter			errx(EEXIT, "cannot increase directory list");
4761558Srgrimes	}
4771558Srgrimes	inpsort[inplast++] = inp;
4781558Srgrimes}
4791558Srgrimes
4801558Srgrimes/*
4811558Srgrimes * Look up an inode cache structure.
4821558Srgrimes */
4831558Srgrimesstruct inoinfo *
48492839Simpgetinoinfo(ino_t inumber)
4851558Srgrimes{
48692806Sobrien	struct inoinfo *inp;
4871558Srgrimes
48857573Smckusick	for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) {
4891558Srgrimes		if (inp->i_number != inumber)
4901558Srgrimes			continue;
4911558Srgrimes		return (inp);
4921558Srgrimes	}
49323675Speter	errx(EEXIT, "cannot find inode %d", inumber);
4941558Srgrimes	return ((struct inoinfo *)0);
4951558Srgrimes}
4961558Srgrimes
4971558Srgrimes/*
4981558Srgrimes * Clean up all the inode cache structure.
4991558Srgrimes */
5007585Sbdevoid
50192839Simpinocleanup(void)
5021558Srgrimes{
50392806Sobrien	struct inoinfo **inpp;
5041558Srgrimes
5051558Srgrimes	if (inphead == NULL)
5061558Srgrimes		return;
5071558Srgrimes	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
5081558Srgrimes		free((char *)(*inpp));
5091558Srgrimes	free((char *)inphead);
5101558Srgrimes	free((char *)inpsort);
5111558Srgrimes	inphead = inpsort = NULL;
5121558Srgrimes}
5138871Srgrimes
5147585Sbdevoid
51592839Simpinodirty(void)
5161558Srgrimes{
51723797Sbde
5181558Srgrimes	dirty(pbp);
5191558Srgrimes}
5201558Srgrimes
5217585Sbdevoid
522100935Sphkclri(struct inodesc *idesc, const char *type, int flag)
5231558Srgrimes{
52498542Smckusick	union dinode *dp;
5251558Srgrimes
5261558Srgrimes	dp = ginode(idesc->id_number);
5271558Srgrimes	if (flag == 1) {
5281558Srgrimes		pwarn("%s %s", type,
52998542Smckusick		    (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
5301558Srgrimes		pinode(idesc->id_number);
5311558Srgrimes	}
5321558Srgrimes	if (preen || reply("CLEAR") == 1) {
5331558Srgrimes		if (preen)
5341558Srgrimes			printf(" (CLEARED)\n");
5351558Srgrimes		n_files--;
53674556Smckusick		if (bkgrdflag == 0) {
53774556Smckusick			(void)ckinode(dp, idesc);
53874556Smckusick			inoinfo(idesc->id_number)->ino_state = USTATE;
53974556Smckusick			clearinode(dp);
54074556Smckusick			inodirty();
54174556Smckusick		} else {
54274556Smckusick			cmd.value = idesc->id_number;
54398542Smckusick			cmd.size = -DIP(dp, di_nlink);
54474556Smckusick			if (debug)
545100935Sphk				printf("adjrefcnt ino %ld amt %lld\n",
546100935Sphk				    (long)cmd.value, (long long)cmd.size);
54774556Smckusick			if (sysctl(adjrefcnt, MIBSIZE, 0, 0,
54874556Smckusick			    &cmd, sizeof cmd) == -1)
54974556Smckusick				rwerror("ADJUST INODE", cmd.value);
55074556Smckusick		}
5511558Srgrimes	}
5521558Srgrimes}
5531558Srgrimes
5547585Sbdeint
55592839Simpfindname(struct inodesc *idesc)
5561558Srgrimes{
55792806Sobrien	struct direct *dirp = idesc->id_dirp;
5581558Srgrimes
55941474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
56041474Sjulian		idesc->id_entryno++;
5611558Srgrimes		return (KEEPON);
56241474Sjulian	}
56323675Speter	memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1);
5641558Srgrimes	return (STOP|FOUND);
5651558Srgrimes}
5661558Srgrimes
5677585Sbdeint
56892839Simpfindino(struct inodesc *idesc)
5691558Srgrimes{
57092806Sobrien	struct direct *dirp = idesc->id_dirp;
5711558Srgrimes
5721558Srgrimes	if (dirp->d_ino == 0)
5731558Srgrimes		return (KEEPON);
5741558Srgrimes	if (strcmp(dirp->d_name, idesc->id_name) == 0 &&
5751558Srgrimes	    dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) {
5761558Srgrimes		idesc->id_parent = dirp->d_ino;
5771558Srgrimes		return (STOP|FOUND);
5781558Srgrimes	}
5791558Srgrimes	return (KEEPON);
5801558Srgrimes}
5811558Srgrimes
58241474Sjulianint
58392839Simpclearentry(struct inodesc *idesc)
58441474Sjulian{
58592806Sobrien	struct direct *dirp = idesc->id_dirp;
58641474Sjulian
58741474Sjulian	if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) {
58841474Sjulian		idesc->id_entryno++;
58941474Sjulian		return (KEEPON);
59041474Sjulian	}
59141474Sjulian	dirp->d_ino = 0;
59241474Sjulian	return (STOP|FOUND|ALTERED);
59341474Sjulian}
59441474Sjulian
5957585Sbdevoid
59692839Simppinode(ino_t ino)
5971558Srgrimes{
59898542Smckusick	union dinode *dp;
59992806Sobrien	char *p;
6001558Srgrimes	struct passwd *pw;
60124002Speter	time_t t;
6021558Srgrimes
60337236Sbde	printf(" I=%lu ", (u_long)ino);
6041558Srgrimes	if (ino < ROOTINO || ino > maxino)
6051558Srgrimes		return;
6061558Srgrimes	dp = ginode(ino);
6071558Srgrimes	printf(" OWNER=");
60898542Smckusick	if ((pw = getpwuid((int)DIP(dp, di_uid))) != 0)
6091558Srgrimes		printf("%s ", pw->pw_name);
6101558Srgrimes	else
61198542Smckusick		printf("%u ", (unsigned)DIP(dp, di_uid));
61298542Smckusick	printf("MODE=%o\n", DIP(dp, di_mode));
6131558Srgrimes	if (preen)
6141558Srgrimes		printf("%s: ", cdevname);
615101037Smux	printf("SIZE=%ju ", (uintmax_t)DIP(dp, di_size));
61698542Smckusick	t = DIP(dp, di_mtime);
61724002Speter	p = ctime(&t);
6181558Srgrimes	printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
6191558Srgrimes}
6201558Srgrimes
6217585Sbdevoid
622100935Sphkblkerror(ino_t ino, const char *type, ufs2_daddr_t blk)
6231558Srgrimes{
6241558Srgrimes
625101037Smux	pfatal("%jd %s I=%ju", (intmax_t)blk, type, (uintmax_t)ino);
6261558Srgrimes	printf("\n");
62741474Sjulian	switch (inoinfo(ino)->ino_state) {
6281558Srgrimes
6291558Srgrimes	case FSTATE:
630136281Struckman	case FZLINK:
63141474Sjulian		inoinfo(ino)->ino_state = FCLEAR;
6321558Srgrimes		return;
6331558Srgrimes
6341558Srgrimes	case DSTATE:
635136281Struckman	case DZLINK:
63641474Sjulian		inoinfo(ino)->ino_state = DCLEAR;
6371558Srgrimes		return;
6381558Srgrimes
6391558Srgrimes	case FCLEAR:
6401558Srgrimes	case DCLEAR:
6411558Srgrimes		return;
6421558Srgrimes
6431558Srgrimes	default:
64441474Sjulian		errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state);
6451558Srgrimes		/* NOTREACHED */
6461558Srgrimes	}
6471558Srgrimes}
6481558Srgrimes
6491558Srgrimes/*
6501558Srgrimes * allocate an unused inode
6511558Srgrimes */
6521558Srgrimesino_t
65392839Simpallocino(ino_t request, int type)
6541558Srgrimes{
65592806Sobrien	ino_t ino;
65698542Smckusick	union dinode *dp;
657249788Smckusick	struct bufarea *cgbp;
658249788Smckusick	struct cg *cgp;
65934266Sjulian	int cg;
6601558Srgrimes
6611558Srgrimes	if (request == 0)
6621558Srgrimes		request = ROOTINO;
66341474Sjulian	else if (inoinfo(request)->ino_state != USTATE)
6641558Srgrimes		return (0);
6651558Srgrimes	for (ino = request; ino < maxino; ino++)
66641474Sjulian		if (inoinfo(ino)->ino_state == USTATE)
6671558Srgrimes			break;
6681558Srgrimes	if (ino == maxino)
6691558Srgrimes		return (0);
67034266Sjulian	cg = ino_to_cg(&sblock, ino);
671249788Smckusick	cgbp = cgget(cg);
672249788Smckusick	cgp = cgbp->b_un.b_cg;
673249788Smckusick	if (!check_cgmagic(cg, cgbp))
674188110Smckusick		return (0);
67534266Sjulian	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
67634266Sjulian	cgp->cg_cs.cs_nifree--;
6771558Srgrimes	switch (type & IFMT) {
6781558Srgrimes	case IFDIR:
67941474Sjulian		inoinfo(ino)->ino_state = DSTATE;
68034266Sjulian		cgp->cg_cs.cs_ndir++;
6811558Srgrimes		break;
6821558Srgrimes	case IFREG:
6831558Srgrimes	case IFLNK:
68441474Sjulian		inoinfo(ino)->ino_state = FSTATE;
6851558Srgrimes		break;
6861558Srgrimes	default:
6871558Srgrimes		return (0);
6881558Srgrimes	}
689249788Smckusick	dirty(cgbp);
6901558Srgrimes	dp = ginode(ino);
691134589Sscottl	DIP_SET(dp, di_db[0], allocblk((long)1));
69298542Smckusick	if (DIP(dp, di_db[0]) == 0) {
69341474Sjulian		inoinfo(ino)->ino_state = USTATE;
6941558Srgrimes		return (0);
6951558Srgrimes	}
696134589Sscottl	DIP_SET(dp, di_mode, type);
697134589Sscottl	DIP_SET(dp, di_flags, 0);
698134589Sscottl	DIP_SET(dp, di_atime, time(NULL));
699134589Sscottl	DIP_SET(dp, di_ctime, DIP(dp, di_atime));
700134589Sscottl	DIP_SET(dp, di_mtime, DIP(dp, di_ctime));
701134589Sscottl	DIP_SET(dp, di_mtimensec, 0);
702134589Sscottl	DIP_SET(dp, di_ctimensec, 0);
703134589Sscottl	DIP_SET(dp, di_atimensec, 0);
704134589Sscottl	DIP_SET(dp, di_size, sblock.fs_fsize);
705134589Sscottl	DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize));
7061558Srgrimes	n_files++;
7071558Srgrimes	inodirty();
70896483Sphk	inoinfo(ino)->ino_type = IFTODT(type);
7091558Srgrimes	return (ino);
7101558Srgrimes}
7111558Srgrimes
7121558Srgrimes/*
7131558Srgrimes * deallocate an inode
7141558Srgrimes */
7157585Sbdevoid
71692839Simpfreeino(ino_t ino)
7171558Srgrimes{
7181558Srgrimes	struct inodesc idesc;
71998542Smckusick	union dinode *dp;
7201558Srgrimes
72123675Speter	memset(&idesc, 0, sizeof(struct inodesc));
7221558Srgrimes	idesc.id_type = ADDR;
7231558Srgrimes	idesc.id_func = pass4check;
7241558Srgrimes	idesc.id_number = ino;
7251558Srgrimes	dp = ginode(ino);
7261558Srgrimes	(void)ckinode(dp, &idesc);
7271558Srgrimes	clearinode(dp);
7281558Srgrimes	inodirty();
72941474Sjulian	inoinfo(ino)->ino_state = USTATE;
7301558Srgrimes	n_files--;
7311558Srgrimes}
732