1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 1996, 1998, 2001-2003 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
7*0Sstevel@tonic-gate /*	  All Rights Reserved	*/
8*0Sstevel@tonic-gate 
9*0Sstevel@tonic-gate /*
10*0Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
11*0Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
12*0Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
13*0Sstevel@tonic-gate  */
14*0Sstevel@tonic-gate 
15*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*0Sstevel@tonic-gate 
17*0Sstevel@tonic-gate #include "dump.h"
18*0Sstevel@tonic-gate #include <sys/file.h>
19*0Sstevel@tonic-gate #include <sys/mman.h>
20*0Sstevel@tonic-gate 
21*0Sstevel@tonic-gate #ifdef __STDC__
22*0Sstevel@tonic-gate static void lf_dmpindir(daddr32_t, int, u_offset_t *);
23*0Sstevel@tonic-gate static void indir(daddr32_t, int, u_offset_t *);
24*0Sstevel@tonic-gate static void lf_blksout(daddr32_t *, u_offset_t);
25*0Sstevel@tonic-gate static void lf_dumpinode(struct dinode *);
26*0Sstevel@tonic-gate static void dsrch(daddr32_t, ulong_t, u_offset_t);
27*0Sstevel@tonic-gate void lf_dump(struct dinode *);
28*0Sstevel@tonic-gate #else
29*0Sstevel@tonic-gate static void lf_dmpindir();
30*0Sstevel@tonic-gate static void indir();
31*0Sstevel@tonic-gate static void lf_blksout();
32*0Sstevel@tonic-gate static void dsrch();
33*0Sstevel@tonic-gate void lf_dump();
34*0Sstevel@tonic-gate #endif
35*0Sstevel@tonic-gate 
36*0Sstevel@tonic-gate static	char msgbuf[256];
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate void
39*0Sstevel@tonic-gate pass(fn, map)
40*0Sstevel@tonic-gate 	void (*fn)(struct dinode *);
41*0Sstevel@tonic-gate 	uchar_t *map;
42*0Sstevel@tonic-gate {
43*0Sstevel@tonic-gate 	int bits;
44*0Sstevel@tonic-gate 	ino_t maxino;
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate 	maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg - 1);
47*0Sstevel@tonic-gate 	/*
48*0Sstevel@tonic-gate 	 * Handle pass restarts.  We don't check for UFSROOTINO just in
49*0Sstevel@tonic-gate 	 * case we need to restart on the root inode.
50*0Sstevel@tonic-gate 	 */
51*0Sstevel@tonic-gate 	if (ino != 0) {
52*0Sstevel@tonic-gate 		bits = ~0;
53*0Sstevel@tonic-gate 		if (map != NULL) {
54*0Sstevel@tonic-gate 			/* LINTED: lint seems to think map is signed */
55*0Sstevel@tonic-gate 			map += (ino / NBBY);
56*0Sstevel@tonic-gate 			bits = *map++;
57*0Sstevel@tonic-gate 		}
58*0Sstevel@tonic-gate 		bits >>= (ino % NBBY);
59*0Sstevel@tonic-gate 		resetino(ino);
60*0Sstevel@tonic-gate 		goto restart;
61*0Sstevel@tonic-gate 	}
62*0Sstevel@tonic-gate 	while (ino < maxino) {
63*0Sstevel@tonic-gate 		if ((ino % NBBY) == 0) {
64*0Sstevel@tonic-gate 			bits = ~0;
65*0Sstevel@tonic-gate 			if (map != NULL)
66*0Sstevel@tonic-gate 				bits = *map++;
67*0Sstevel@tonic-gate 		}
68*0Sstevel@tonic-gate restart:
69*0Sstevel@tonic-gate 		ino++;
70*0Sstevel@tonic-gate 		/*
71*0Sstevel@tonic-gate 		 * Ignore any inode less than UFSROOTINO and inodes that
72*0Sstevel@tonic-gate 		 * we have already done on a previous pass.
73*0Sstevel@tonic-gate 		 */
74*0Sstevel@tonic-gate 		if ((ino >= UFSROOTINO) && (bits & 1)) {
75*0Sstevel@tonic-gate 			/*
76*0Sstevel@tonic-gate 			 * The following test is merely an optimization
77*0Sstevel@tonic-gate 			 * for common case where "add" will just return.
78*0Sstevel@tonic-gate 			 */
79*0Sstevel@tonic-gate 			if (!(fn == add && BIT(ino, nodmap)))
80*0Sstevel@tonic-gate 				(*fn)(getino(ino));
81*0Sstevel@tonic-gate 		}
82*0Sstevel@tonic-gate 		bits >>= 1;
83*0Sstevel@tonic-gate 	}
84*0Sstevel@tonic-gate }
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate void
87*0Sstevel@tonic-gate mark(ip)
88*0Sstevel@tonic-gate 	struct dinode *ip;
89*0Sstevel@tonic-gate {
90*0Sstevel@tonic-gate 	int f;
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	f = ip->di_mode & IFMT;
93*0Sstevel@tonic-gate 	if (f == 0 || ip->di_nlink <= 0) {
94*0Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
95*0Sstevel@tonic-gate 		BIC(ino, clrmap);
96*0Sstevel@tonic-gate 		return;
97*0Sstevel@tonic-gate 	}
98*0Sstevel@tonic-gate 	/* LINTED: 32-bit to 8-bit assignment ok */
99*0Sstevel@tonic-gate 	BIS(ino, clrmap);
100*0Sstevel@tonic-gate 	if (f == IFDIR || f == IFATTRDIR) {
101*0Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
102*0Sstevel@tonic-gate 		BIS(ino, dirmap);
103*0Sstevel@tonic-gate 	}
104*0Sstevel@tonic-gate 	if (ip->di_ctime >= spcl.c_ddate) {
105*0Sstevel@tonic-gate 		if (f == IFSHAD)
106*0Sstevel@tonic-gate 			return;
107*0Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
108*0Sstevel@tonic-gate 		BIS(ino, nodmap);
109*0Sstevel@tonic-gate 		/* attribute changes impact the root */
110*0Sstevel@tonic-gate 		if (f == IFATTRDIR)
111*0Sstevel@tonic-gate 			BIS(UFSROOTINO, nodmap);
112*0Sstevel@tonic-gate 		if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) {
113*0Sstevel@tonic-gate 			o_esize += 1;
114*0Sstevel@tonic-gate 			return;
115*0Sstevel@tonic-gate 		}
116*0Sstevel@tonic-gate 		est(ip);
117*0Sstevel@tonic-gate 	}
118*0Sstevel@tonic-gate }
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate void
121*0Sstevel@tonic-gate active_mark(ip)
122*0Sstevel@tonic-gate 	struct dinode *ip;
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate 	int f;
125*0Sstevel@tonic-gate 
126*0Sstevel@tonic-gate 	f = ip->di_mode & IFMT;
127*0Sstevel@tonic-gate 	if (f == 0 || ip->di_nlink <= 0) {
128*0Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
129*0Sstevel@tonic-gate 		BIC(ino, clrmap);
130*0Sstevel@tonic-gate 		return;
131*0Sstevel@tonic-gate 	}
132*0Sstevel@tonic-gate 	/* LINTED: 32-bit to 8-bit assignment ok */
133*0Sstevel@tonic-gate 	BIS(ino, clrmap);
134*0Sstevel@tonic-gate 	if (f == IFDIR || f == IFATTRDIR) {
135*0Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
136*0Sstevel@tonic-gate 		BIS(ino, dirmap);
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate 	if (BIT(ino, activemap)) {
139*0Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
140*0Sstevel@tonic-gate 		BIS(ino, nodmap);
141*0Sstevel@tonic-gate 		/* attribute changes impact the root */
142*0Sstevel@tonic-gate 		if (f == IFATTRDIR)
143*0Sstevel@tonic-gate 			BIS(UFSROOTINO, nodmap);
144*0Sstevel@tonic-gate 		if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) {
145*0Sstevel@tonic-gate 			o_esize += 1;
146*0Sstevel@tonic-gate 			return;
147*0Sstevel@tonic-gate 		}
148*0Sstevel@tonic-gate 		est(ip);
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate }
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate static struct shcount {
153*0Sstevel@tonic-gate 	struct shcount *higher, *lower;
154*0Sstevel@tonic-gate 	ino_t ino;
155*0Sstevel@tonic-gate 	unsigned long count;
156*0Sstevel@tonic-gate } shcounts = {
157*0Sstevel@tonic-gate 	NULL, NULL,
158*0Sstevel@tonic-gate 	0,
159*0Sstevel@tonic-gate 	0
160*0Sstevel@tonic-gate };
161*0Sstevel@tonic-gate static struct shcount *shc = NULL;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate void
164*0Sstevel@tonic-gate markshad(ip)
165*0Sstevel@tonic-gate 	struct dinode *ip;
166*0Sstevel@tonic-gate {
167*0Sstevel@tonic-gate 	ino_t shadow;
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	if (ip->di_shadow == 0)
170*0Sstevel@tonic-gate 		return;
171*0Sstevel@tonic-gate 	if (shc == NULL)
172*0Sstevel@tonic-gate 		shc = &shcounts;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	shadow = (ino_t)(unsigned)(ip->di_shadow);
175*0Sstevel@tonic-gate 	while ((shadow > shc->ino) && (shc->higher))
176*0Sstevel@tonic-gate 		shc = shc->higher;
177*0Sstevel@tonic-gate 	while ((shadow < shc->ino) && (shc->lower))
178*0Sstevel@tonic-gate 		shc = shc->lower;
179*0Sstevel@tonic-gate 	if (shadow != shc->ino) {
180*0Sstevel@tonic-gate 		struct shcount *new;
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 		new = (struct shcount *)xcalloc(1, sizeof (*new));
183*0Sstevel@tonic-gate 		new->higher = shc->higher;
184*0Sstevel@tonic-gate 		if (shc->higher != NULL)
185*0Sstevel@tonic-gate 			shc->higher->lower = new;
186*0Sstevel@tonic-gate 		shc->higher = new;
187*0Sstevel@tonic-gate 		new->lower = shc;
188*0Sstevel@tonic-gate 		shc = new;
189*0Sstevel@tonic-gate 		shc->ino = shadow;
190*0Sstevel@tonic-gate 	}
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	/* LINTED: 32-bit to 8-bit assignment ok */
193*0Sstevel@tonic-gate 	BIS(shadow, shamap);
194*0Sstevel@tonic-gate 	shc->count++;
195*0Sstevel@tonic-gate }
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate void
198*0Sstevel@tonic-gate estshad(ip)
199*0Sstevel@tonic-gate 	struct dinode *ip;
200*0Sstevel@tonic-gate {
201*0Sstevel@tonic-gate 	u_offset_t esizeprime;
202*0Sstevel@tonic-gate 	u_offset_t tmpesize;
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 	if (ip->di_size <= sizeof (union u_shadow))
205*0Sstevel@tonic-gate 		return;
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 	while ((ino > shc->ino) && (shc->higher))
208*0Sstevel@tonic-gate 		shc = shc->higher;
209*0Sstevel@tonic-gate 	while ((ino < shc->ino) && (shc->lower))
210*0Sstevel@tonic-gate 		shc = shc->lower;
211*0Sstevel@tonic-gate 	if (ino != shc->ino)
212*0Sstevel@tonic-gate 		return; /* xxx panic? complain? */
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	tmpesize = (o_esize + f_esize);
215*0Sstevel@tonic-gate 	esizeprime = tmpesize;
216*0Sstevel@tonic-gate 	est(ip);
217*0Sstevel@tonic-gate 	esizeprime = tmpesize - esizeprime;
218*0Sstevel@tonic-gate 	esizeprime *= shc->count - 1;
219*0Sstevel@tonic-gate 	f_esize += esizeprime;
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate void
223*0Sstevel@tonic-gate freeshad()
224*0Sstevel@tonic-gate {
225*0Sstevel@tonic-gate 	if (shc == NULL)
226*0Sstevel@tonic-gate 		return;
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	while (shc->higher)
229*0Sstevel@tonic-gate 		shc = shc->higher;
230*0Sstevel@tonic-gate 	while (shc->lower) {
231*0Sstevel@tonic-gate 		shc = shc->lower;
232*0Sstevel@tonic-gate 		if (shc->higher) /* else panic? */
233*0Sstevel@tonic-gate 			(void) free(shc->higher);
234*0Sstevel@tonic-gate 	}
235*0Sstevel@tonic-gate 	/*
236*0Sstevel@tonic-gate 	 * This should be unnecessary, but do it just to be safe.
237*0Sstevel@tonic-gate 	 * Note that shc might be malloc'd or static, so can't free().
238*0Sstevel@tonic-gate 	 */
239*0Sstevel@tonic-gate 	bzero(shc, sizeof (*shc));
240*0Sstevel@tonic-gate }
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate void
243*0Sstevel@tonic-gate add(ip)
244*0Sstevel@tonic-gate 	struct	dinode	*ip;
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate 	int i;
247*0Sstevel@tonic-gate 	u_offset_t filesize;
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate 	if (BIT(ino, nodmap))
250*0Sstevel@tonic-gate 		return;
251*0Sstevel@tonic-gate 	if ((ip->di_mode & IFMT) != IFDIR &&
252*0Sstevel@tonic-gate 	    (ip->di_mode & IFMT) != IFATTRDIR) {
253*0Sstevel@tonic-gate 		(void) snprintf(msgbuf, sizeof (msgbuf), gettext(
254*0Sstevel@tonic-gate 		    "Warning - directory at inode `%lu' vanished!\n"), ino);
255*0Sstevel@tonic-gate 		msg(msgbuf);
256*0Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
257*0Sstevel@tonic-gate 		BIC(ino, dirmap);
258*0Sstevel@tonic-gate 		return;
259*0Sstevel@tonic-gate 	}
260*0Sstevel@tonic-gate 	nsubdir = 0;
261*0Sstevel@tonic-gate 	dadded = 0;
262*0Sstevel@tonic-gate 	filesize = ip->di_size;
263*0Sstevel@tonic-gate 	for (i = 0; i < NDADDR; i++) {
264*0Sstevel@tonic-gate 		if (ip->di_db[i] != 0)
265*0Sstevel@tonic-gate 			/* LINTED dblksize/blkoff does a safe cast here */
266*0Sstevel@tonic-gate 			dsrch(ip->di_db[i], (ulong_t)dblksize(sblock, ip, i),
267*0Sstevel@tonic-gate 			    filesize);
268*0Sstevel@tonic-gate 		filesize -= (unsigned)(sblock->fs_bsize);
269*0Sstevel@tonic-gate 	}
270*0Sstevel@tonic-gate 	for (i = 0; i < NIADDR; i++) {
271*0Sstevel@tonic-gate 		if (ip->di_ib[i] != 0)
272*0Sstevel@tonic-gate 			indir(ip->di_ib[i], i, &filesize);
273*0Sstevel@tonic-gate 	}
274*0Sstevel@tonic-gate 	if (dadded) {
275*0Sstevel@tonic-gate 		nadded++;
276*0Sstevel@tonic-gate 		if (!BIT(ino, nodmap)) {
277*0Sstevel@tonic-gate 			/* LINTED: 32-bit to 8-bit assignment ok */
278*0Sstevel@tonic-gate 			BIS(ino, nodmap);
279*0Sstevel@tonic-gate 			if ((ip->di_mode & IFMT) == IFATTRDIR) {
280*0Sstevel@tonic-gate 				/* attribute changes "auto-percolate" to root */
281*0Sstevel@tonic-gate 				BIS(UFSROOTINO, nodmap);
282*0Sstevel@tonic-gate 			}
283*0Sstevel@tonic-gate 			est(ip);
284*0Sstevel@tonic-gate 		}
285*0Sstevel@tonic-gate 	}
286*0Sstevel@tonic-gate 	if (nsubdir == 0) {
287*0Sstevel@tonic-gate 		if (!BIT(ino, nodmap)) {
288*0Sstevel@tonic-gate 			/* LINTED: 32-bit to 8-bit assignment ok */
289*0Sstevel@tonic-gate 			BIC(ino, dirmap);
290*0Sstevel@tonic-gate 		}
291*0Sstevel@tonic-gate 	}
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate static void
295*0Sstevel@tonic-gate indir(d, n, filesize)
296*0Sstevel@tonic-gate 	daddr32_t d;
297*0Sstevel@tonic-gate 	int n;
298*0Sstevel@tonic-gate 	u_offset_t *filesize;
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate 	int i;
301*0Sstevel@tonic-gate 	daddr32_t idblk[MAXNINDIR];
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) {
304*0Sstevel@tonic-gate 		msg(gettext(
305*0Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
306*0Sstevel@tonic-gate 		dumpabort();
307*0Sstevel@tonic-gate 		/*NOTREACHED*/
308*0Sstevel@tonic-gate 	}
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 	if ((unsigned)NINDIR(sblock) > MAXNINDIR) {
311*0Sstevel@tonic-gate 		/*CSTYLED*/
312*0Sstevel@tonic-gate 		msg(gettext(
313*0Sstevel@tonic-gate "Inconsistency detected: inode has more indirect \
314*0Sstevel@tonic-gate blocks than valid maximum.\n"));
315*0Sstevel@tonic-gate 		dumpabort();
316*0Sstevel@tonic-gate 		/*NOTREACHED*/
317*0Sstevel@tonic-gate 	}
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	if (dadded || *filesize == 0)
320*0Sstevel@tonic-gate 		return;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate #ifdef	lint
323*0Sstevel@tonic-gate 	idblk[0] = '\0';
324*0Sstevel@tonic-gate #endif	/* lint */
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	/* xxx sanity check sblock contents before trusting them */
327*0Sstevel@tonic-gate 	bread(fsbtodb(sblock, d), (uchar_t *)idblk, (size_t)sblock->fs_bsize);
328*0Sstevel@tonic-gate 	if (n <= 0) {
329*0Sstevel@tonic-gate 		for (i = 0; i < NINDIR(sblock); i++) {
330*0Sstevel@tonic-gate 			d = idblk[i];
331*0Sstevel@tonic-gate 			if (d != 0)
332*0Sstevel@tonic-gate 				dsrch(d, (ulong_t)(uint32_t)sblock->fs_bsize,
333*0Sstevel@tonic-gate 				    *filesize);
334*0Sstevel@tonic-gate 			*filesize -= (unsigned)(sblock->fs_bsize);
335*0Sstevel@tonic-gate 		}
336*0Sstevel@tonic-gate 	} else {
337*0Sstevel@tonic-gate 		n--;
338*0Sstevel@tonic-gate 		for (i = 0; i < NINDIR(sblock); i++) {
339*0Sstevel@tonic-gate 			d = idblk[i];
340*0Sstevel@tonic-gate 			if (d != 0)
341*0Sstevel@tonic-gate 				indir(d, n, filesize);
342*0Sstevel@tonic-gate 		}
343*0Sstevel@tonic-gate 	}
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate void
347*0Sstevel@tonic-gate dirdump(ip)
348*0Sstevel@tonic-gate 	struct dinode *ip;
349*0Sstevel@tonic-gate {
350*0Sstevel@tonic-gate 	/* watchout for dir inodes deleted and maybe reallocated */
351*0Sstevel@tonic-gate 	if (((ip->di_mode & IFMT) != IFDIR &&
352*0Sstevel@tonic-gate 	    (ip->di_mode & IFMT) != IFATTRDIR) || ip->di_nlink < 2) {
353*0Sstevel@tonic-gate 		(void) snprintf(msgbuf, sizeof (msgbuf), gettext(
354*0Sstevel@tonic-gate 		    "Warning - directory at inode `%lu' vanished!\n"),
355*0Sstevel@tonic-gate 			ino);
356*0Sstevel@tonic-gate 		msg(msgbuf);
357*0Sstevel@tonic-gate 		return;
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate 	lf_dump(ip);
360*0Sstevel@tonic-gate }
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate static u_offset_t loffset; /* current offset in file (ufsdump) */
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate static void
365*0Sstevel@tonic-gate lf_dumpmeta(ip)
366*0Sstevel@tonic-gate 	struct dinode *ip;
367*0Sstevel@tonic-gate {
368*0Sstevel@tonic-gate 	if ((ip->di_shadow == 0) || shortmeta)
369*0Sstevel@tonic-gate 	    return;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 	lf_dumpinode(getino((ino_t)(unsigned)(ip->di_shadow)));
372*0Sstevel@tonic-gate }
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate int
375*0Sstevel@tonic-gate hasshortmeta(ip)
376*0Sstevel@tonic-gate 	struct dinode **ip;
377*0Sstevel@tonic-gate {
378*0Sstevel@tonic-gate 	ino_t savino;
379*0Sstevel@tonic-gate 	int rc;
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate 	if ((*ip)->di_shadow == 0)
382*0Sstevel@tonic-gate 		return (0);
383*0Sstevel@tonic-gate 	savino = ino;
384*0Sstevel@tonic-gate 	*ip = getino((ino_t)(unsigned)((*ip)->di_shadow));
385*0Sstevel@tonic-gate 	rc = ((*ip)->di_size <= sizeof (union u_shadow));
386*0Sstevel@tonic-gate 	*ip = getino(ino = savino);
387*0Sstevel@tonic-gate 	return (rc);
388*0Sstevel@tonic-gate }
389*0Sstevel@tonic-gate 
390*0Sstevel@tonic-gate void
391*0Sstevel@tonic-gate lf_dumpinode(ip)
392*0Sstevel@tonic-gate     struct dinode *ip;
393*0Sstevel@tonic-gate {
394*0Sstevel@tonic-gate 	int i;
395*0Sstevel@tonic-gate 	u_offset_t size;
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate 	i = ip->di_mode & IFMT;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	if (i == 0 || ip->di_nlink <= 0)
400*0Sstevel@tonic-gate 		return;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	spcl.c_dinode = *ip;
403*0Sstevel@tonic-gate 	spcl.c_count = 0;
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	if ((i != IFDIR && i != IFATTRDIR && i != IFREG && i != IFLNK &&
406*0Sstevel@tonic-gate 	    i != IFSHAD) || ip->di_size == 0) {
407*0Sstevel@tonic-gate 		toslave(dospcl, ino);
408*0Sstevel@tonic-gate 		return;
409*0Sstevel@tonic-gate 	}
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	size = NDADDR * (unsigned)(sblock->fs_bsize);
412*0Sstevel@tonic-gate 	if (size > ip->di_size)
413*0Sstevel@tonic-gate 		size = ip->di_size;
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	lf_blksout(&ip->di_db[0], size);
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 	size = ip->di_size - size;
418*0Sstevel@tonic-gate 	if (size > 0) {
419*0Sstevel@tonic-gate 		for (i = 0; i < NIADDR; i++) {
420*0Sstevel@tonic-gate 			lf_dmpindir(ip->di_ib[i], i, &size);
421*0Sstevel@tonic-gate 			if (size == 0)
422*0Sstevel@tonic-gate 				break;
423*0Sstevel@tonic-gate 		}
424*0Sstevel@tonic-gate 	}
425*0Sstevel@tonic-gate }
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate void
428*0Sstevel@tonic-gate lf_dump(ip)
429*0Sstevel@tonic-gate 	struct dinode *ip;
430*0Sstevel@tonic-gate {
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 	if ((!BIT(ino, nodmap)) && (!BIT(ino, shamap)))
433*0Sstevel@tonic-gate 		return;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	shortmeta = hasshortmeta(&ip);
436*0Sstevel@tonic-gate 	if (shortmeta) {
437*0Sstevel@tonic-gate 		ip = getino((ino_t)(unsigned)(ip->di_shadow));
438*0Sstevel@tonic-gate 		/* assume spcl.c_shadow is smaller than 1 block */
439*0Sstevel@tonic-gate 		bread(fsbtodb(sblock, ip->di_db[0]),
440*0Sstevel@tonic-gate 		    (uchar_t *)spcl.c_shadow.c_shadow, sizeof (spcl.c_shadow));
441*0Sstevel@tonic-gate 		spcl.c_flags |= DR_HASMETA;
442*0Sstevel@tonic-gate 	} else {
443*0Sstevel@tonic-gate 		spcl.c_flags &= ~DR_HASMETA;
444*0Sstevel@tonic-gate 	}
445*0Sstevel@tonic-gate 	ip = getino(ino);
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	loffset = 0;
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	if (newtape) {
450*0Sstevel@tonic-gate 		spcl.c_type = TS_TAPE;
451*0Sstevel@tonic-gate 	} else if (pos)
452*0Sstevel@tonic-gate 		spcl.c_type = TS_ADDR;
453*0Sstevel@tonic-gate 	else
454*0Sstevel@tonic-gate 		spcl.c_type = TS_INODE;
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate 	newtape = 0;
457*0Sstevel@tonic-gate 	lf_dumpinode(ip);
458*0Sstevel@tonic-gate 	lf_dumpmeta(ip);
459*0Sstevel@tonic-gate 	pos = 0;
460*0Sstevel@tonic-gate }
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate static void
463*0Sstevel@tonic-gate lf_dmpindir(blk, lvl, size)
464*0Sstevel@tonic-gate 	daddr32_t blk;
465*0Sstevel@tonic-gate 	int lvl;
466*0Sstevel@tonic-gate 	u_offset_t *size;
467*0Sstevel@tonic-gate {
468*0Sstevel@tonic-gate 	int i;
469*0Sstevel@tonic-gate 	u_offset_t cnt;
470*0Sstevel@tonic-gate 	daddr32_t idblk[MAXNINDIR];
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 	if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) {
473*0Sstevel@tonic-gate 		msg(gettext(
474*0Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
475*0Sstevel@tonic-gate 		dumpabort();
476*0Sstevel@tonic-gate 		/*NOTREACHED*/
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 	if ((unsigned)NINDIR(sblock) > MAXNINDIR) {
480*0Sstevel@tonic-gate 		msg(gettext(
481*0Sstevel@tonic-gate "Inconsistency detected: inode has more indirect \
482*0Sstevel@tonic-gate blocks than valid maximum.\n"));
483*0Sstevel@tonic-gate 		dumpabort();
484*0Sstevel@tonic-gate 		/*NOTREACHED*/
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	if (blk != 0)
488*0Sstevel@tonic-gate 		bread(fsbtodb(sblock, blk), (uchar_t *)idblk,
489*0Sstevel@tonic-gate 		    (size_t)sblock->fs_bsize);
490*0Sstevel@tonic-gate 	else
491*0Sstevel@tonic-gate 		bzero((char *)idblk, (size_t)sblock->fs_bsize);
492*0Sstevel@tonic-gate 	if (lvl <= 0) {
493*0Sstevel@tonic-gate 		cnt = (u_offset_t)(unsigned)NINDIR(sblock) *
494*0Sstevel@tonic-gate 		    (u_offset_t)(unsigned)(sblock->fs_bsize);
495*0Sstevel@tonic-gate 		if (cnt > *size)
496*0Sstevel@tonic-gate 			cnt = *size;
497*0Sstevel@tonic-gate 		*size -= cnt;
498*0Sstevel@tonic-gate 		lf_blksout(&idblk[0], cnt);
499*0Sstevel@tonic-gate 		return;
500*0Sstevel@tonic-gate 	}
501*0Sstevel@tonic-gate 	lvl--;
502*0Sstevel@tonic-gate 	for (i = 0; i < NINDIR(sblock); i++) {
503*0Sstevel@tonic-gate 		lf_dmpindir(idblk[i], lvl, size);
504*0Sstevel@tonic-gate 		if (*size == 0)
505*0Sstevel@tonic-gate 			return;
506*0Sstevel@tonic-gate 	}
507*0Sstevel@tonic-gate }
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate static void
510*0Sstevel@tonic-gate lf_blksout(blkp, bytes)
511*0Sstevel@tonic-gate 	daddr32_t *blkp;
512*0Sstevel@tonic-gate 	u_offset_t bytes;
513*0Sstevel@tonic-gate {
514*0Sstevel@tonic-gate 	u_offset_t i;
515*0Sstevel@tonic-gate 	u_offset_t tbperfsb = (unsigned)(sblock->fs_bsize / tp_bsize);
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	u_offset_t j, k, count;
518*0Sstevel@tonic-gate 
519*0Sstevel@tonic-gate 	u_offset_t bytepos, diff;
520*0Sstevel@tonic-gate 	u_offset_t bytecnt = 0;
521*0Sstevel@tonic-gate 	off_t byteoff = 0;	/* bytes to skip within first f/s block */
522*0Sstevel@tonic-gate 	off_t fragoff = 0;	/* frags to skip within first f/s block */
523*0Sstevel@tonic-gate 
524*0Sstevel@tonic-gate 	u_offset_t tpblkoff = 0; /* tape blocks to skip in first f/s block */
525*0Sstevel@tonic-gate 	u_offset_t tpblkskip = 0;	/* total tape blocks to skip  */
526*0Sstevel@tonic-gate 	u_offset_t skip;		/* tape blocks to skip this pass */
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	if (pos) {
529*0Sstevel@tonic-gate 		/*
530*0Sstevel@tonic-gate 		 * We get here if a slave throws a signal to the
531*0Sstevel@tonic-gate 		 * master indicating a partially dumped file.
532*0Sstevel@tonic-gate 		 * Begin by figuring out what was undone.
533*0Sstevel@tonic-gate 		 */
534*0Sstevel@tonic-gate 		bytepos = (offset_t)pos * tp_bsize;
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 		if ((loffset + bytes) <= bytepos) {
537*0Sstevel@tonic-gate 			/* This stuff was dumped already, forget it. */
538*0Sstevel@tonic-gate 			loffset += (u_offset_t)tp_bsize *
539*0Sstevel@tonic-gate 			    /* LINTED: spurious complaint on sign-extending */
540*0Sstevel@tonic-gate 			    d_howmany(bytes, (u_offset_t)tp_bsize);
541*0Sstevel@tonic-gate 			return;
542*0Sstevel@tonic-gate 		}
543*0Sstevel@tonic-gate 
544*0Sstevel@tonic-gate 		if (loffset < bytepos) {
545*0Sstevel@tonic-gate 			/*
546*0Sstevel@tonic-gate 			 * Some of this was dumped, some wasn't.
547*0Sstevel@tonic-gate 			 * Figure out what was done and skip it.
548*0Sstevel@tonic-gate 			 */
549*0Sstevel@tonic-gate 			diff = bytepos - loffset;
550*0Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
551*0Sstevel@tonic-gate 			tpblkskip = d_howmany(diff, (u_offset_t)tp_bsize);
552*0Sstevel@tonic-gate 			/* LINTED room after EOT is only a few MB */
553*0Sstevel@tonic-gate 			blkp += (int)(diff / sblock->fs_bsize);
554*0Sstevel@tonic-gate 
555*0Sstevel@tonic-gate 			bytecnt = diff % (unsigned)(sblock->fs_bsize);
556*0Sstevel@tonic-gate 			/* LINTED: result fits, due to modulus */
557*0Sstevel@tonic-gate 			byteoff = bytecnt % (off_t)(sblock->fs_fsize);
558*0Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
559*0Sstevel@tonic-gate 			tpblkoff = d_howmany(bytecnt,
560*0Sstevel@tonic-gate 			    (u_offset_t)(unsigned)tp_bsize);
561*0Sstevel@tonic-gate 			/* LINTED: result fits, due to modulus */
562*0Sstevel@tonic-gate 			fragoff = bytecnt / (off_t)(sblock->fs_fsize);
563*0Sstevel@tonic-gate 			bytecnt = (unsigned)(sblock->fs_bsize) - bytecnt;
564*0Sstevel@tonic-gate 		}
565*0Sstevel@tonic-gate 	}
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 	loffset += bytes;
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 	while (bytes > 0) {
570*0Sstevel@tonic-gate 		if (bytes < TP_NINDIR*tp_bsize)
571*0Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
572*0Sstevel@tonic-gate 			count = d_howmany(bytes, (u_offset_t)tp_bsize);
573*0Sstevel@tonic-gate 		else
574*0Sstevel@tonic-gate 			count = TP_NINDIR;
575*0Sstevel@tonic-gate 		if (tpblkskip) {
576*0Sstevel@tonic-gate 			if (tpblkskip < TP_NINDIR) {
577*0Sstevel@tonic-gate 				bytes -= (tpblkskip * (u_offset_t)tp_bsize);
578*0Sstevel@tonic-gate 				skip = tpblkskip;
579*0Sstevel@tonic-gate 				tpblkskip = 0;
580*0Sstevel@tonic-gate 			} else {
581*0Sstevel@tonic-gate 				bytes -= (offset_t)TP_NINDIR*tp_bsize;
582*0Sstevel@tonic-gate 				tpblkskip -= TP_NINDIR;
583*0Sstevel@tonic-gate 				continue;
584*0Sstevel@tonic-gate 			}
585*0Sstevel@tonic-gate 		} else
586*0Sstevel@tonic-gate 			skip = 0;
587*0Sstevel@tonic-gate 		assert(tbperfsb >= tpblkoff);
588*0Sstevel@tonic-gate 		assert((count - skip) <= TP_NINDIR);
589*0Sstevel@tonic-gate 		for (j = 0, k = 0; j < count - skip; j++, k++) {
590*0Sstevel@tonic-gate 			spcl.c_addr[j] = (blkp[k] != 0);
591*0Sstevel@tonic-gate 			for (i = tbperfsb - tpblkoff; --i > 0; j++)
592*0Sstevel@tonic-gate 				spcl.c_addr[j+1] = spcl.c_addr[j];
593*0Sstevel@tonic-gate 			tpblkoff = 0;
594*0Sstevel@tonic-gate 		}
595*0Sstevel@tonic-gate 		/* LINTED (count - skip) will always fit into an int32_t */
596*0Sstevel@tonic-gate 		spcl.c_count = count - skip;
597*0Sstevel@tonic-gate 		toslave(dospcl, ino);
598*0Sstevel@tonic-gate 		bytecnt = MIN(bytes, bytecnt ?
599*0Sstevel@tonic-gate 		    bytecnt : (unsigned)(sblock->fs_bsize));
600*0Sstevel@tonic-gate 		j = 0;
601*0Sstevel@tonic-gate 		while (j < count - skip) {
602*0Sstevel@tonic-gate 			if (*blkp != 0) {
603*0Sstevel@tonic-gate 				/* LINTED: fragoff fits into 32 bits */
604*0Sstevel@tonic-gate 				dmpblk(*blkp+(int32_t)fragoff,
605*0Sstevel@tonic-gate 				    /* LINTED: bytecnt fits into 32 bits */
606*0Sstevel@tonic-gate 				    (size_t)bytecnt, byteoff);
607*0Sstevel@tonic-gate 			}
608*0Sstevel@tonic-gate 			blkp++;
609*0Sstevel@tonic-gate 			bytes -= bytecnt;
610*0Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
611*0Sstevel@tonic-gate 			j += d_howmany(bytecnt, (u_offset_t)tp_bsize);
612*0Sstevel@tonic-gate 			bytecnt = MIN(bytes, (unsigned)(sblock->fs_bsize));
613*0Sstevel@tonic-gate 			byteoff = 0;
614*0Sstevel@tonic-gate 			fragoff = 0;
615*0Sstevel@tonic-gate 		}
616*0Sstevel@tonic-gate 		spcl.c_type = TS_ADDR;
617*0Sstevel@tonic-gate 		bytecnt = 0;
618*0Sstevel@tonic-gate 	}
619*0Sstevel@tonic-gate 	pos = 0;
620*0Sstevel@tonic-gate }
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate void
623*0Sstevel@tonic-gate bitmap(map, typ)
624*0Sstevel@tonic-gate 	uchar_t *map;
625*0Sstevel@tonic-gate 	int typ;
626*0Sstevel@tonic-gate {
627*0Sstevel@tonic-gate 	int i;
628*0Sstevel@tonic-gate 	u_offset_t count;
629*0Sstevel@tonic-gate 	uchar_t *cp;
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	if (!newtape)
632*0Sstevel@tonic-gate 		spcl.c_type = typ;
633*0Sstevel@tonic-gate 	else
634*0Sstevel@tonic-gate 		newtape = 0;
635*0Sstevel@tonic-gate 	for (i = 0; i < TP_NINDIR; i++)
636*0Sstevel@tonic-gate 		spcl.c_addr[i] = 1;
637*0Sstevel@tonic-gate 	/* LINTED: spurious complaint on sign-extending */
638*0Sstevel@tonic-gate 	count = d_howmany(msiz * sizeof (map[0]), tp_bsize) - pos;
639*0Sstevel@tonic-gate 	for (cp = &map[pos * tp_bsize]; count > 0;
640*0Sstevel@tonic-gate 	    count -= (u_offset_t)(unsigned)spcl.c_count) {
641*0Sstevel@tonic-gate 		if (leftover) {
642*0Sstevel@tonic-gate 			spcl.c_count = leftover;
643*0Sstevel@tonic-gate 			leftover = 0;
644*0Sstevel@tonic-gate 		} else {
645*0Sstevel@tonic-gate 			/* LINTED value always less than INT32_MAX */
646*0Sstevel@tonic-gate 			spcl.c_count = count > TP_NINDIR ? TP_NINDIR : count;
647*0Sstevel@tonic-gate 		}
648*0Sstevel@tonic-gate 		spclrec();
649*0Sstevel@tonic-gate 		for (i = 0; i < spcl.c_count; i++, cp += tp_bsize)
650*0Sstevel@tonic-gate 			taprec(cp, 0, tp_bsize);
651*0Sstevel@tonic-gate 		spcl.c_type = TS_ADDR;
652*0Sstevel@tonic-gate 	}
653*0Sstevel@tonic-gate }
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate static void
656*0Sstevel@tonic-gate dsrch(d, size, filesize)
657*0Sstevel@tonic-gate 	daddr32_t d;
658*0Sstevel@tonic-gate 	ulong_t size; 	/* block size */
659*0Sstevel@tonic-gate 	u_offset_t filesize;
660*0Sstevel@tonic-gate {
661*0Sstevel@tonic-gate 	struct direct *dp;
662*0Sstevel@tonic-gate 	struct dinode *ip;
663*0Sstevel@tonic-gate 	ulong_t loc;
664*0Sstevel@tonic-gate 	char dblk[MAXBSIZE];
665*0Sstevel@tonic-gate 
666*0Sstevel@tonic-gate 	if (dadded || filesize == 0)
667*0Sstevel@tonic-gate 		return;
668*0Sstevel@tonic-gate 	if (filesize > (u_offset_t)size)
669*0Sstevel@tonic-gate 		filesize = (u_offset_t)size;
670*0Sstevel@tonic-gate 	if (sizeof (dblk) < roundup(filesize, DEV_BSIZE)) {
671*0Sstevel@tonic-gate 		msg(gettext(
672*0Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
673*0Sstevel@tonic-gate 		dumpabort();
674*0Sstevel@tonic-gate 		/*NOTREACHED*/
675*0Sstevel@tonic-gate 	}
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate #ifdef	lint
678*0Sstevel@tonic-gate 	dblk[0] = '\0';
679*0Sstevel@tonic-gate #endif	/* lint */
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	/* LINTED ufs disk addresses always fit into 32 bits */
682*0Sstevel@tonic-gate 	bread(fsbtodb(sblock, d), (uchar_t *)dblk,
683*0Sstevel@tonic-gate 	    /* LINTED from sizeof check above, roundup() <= max(size_t) */
684*0Sstevel@tonic-gate 	    (size_t)(roundup(filesize, DEV_BSIZE)));
685*0Sstevel@tonic-gate 	loc = 0;
686*0Sstevel@tonic-gate 	while ((u_offset_t)loc < filesize) {
687*0Sstevel@tonic-gate 		/*LINTED [dblk is char[], loc (dp->d_reclen) % 4 == 0]*/
688*0Sstevel@tonic-gate 		dp = (struct direct *)(dblk + loc);
689*0Sstevel@tonic-gate 		if (dp->d_reclen == 0) {
690*0Sstevel@tonic-gate 			(void) snprintf(msgbuf, sizeof (msgbuf), gettext(
691*0Sstevel@tonic-gate 		    "Warning - directory at inode `%lu' is corrupted\n"),
692*0Sstevel@tonic-gate 				ino);
693*0Sstevel@tonic-gate 			msg(msgbuf);
694*0Sstevel@tonic-gate 			break;
695*0Sstevel@tonic-gate 		}
696*0Sstevel@tonic-gate 		loc += dp->d_reclen;
697*0Sstevel@tonic-gate 		if (dp->d_ino == 0)
698*0Sstevel@tonic-gate 			continue;
699*0Sstevel@tonic-gate 		if (dp->d_name[0] == '.') {
700*0Sstevel@tonic-gate 			if (dp->d_name[1] == '\0') {
701*0Sstevel@tonic-gate 				if ((ino_t)(dp->d_ino) != ino) {
702*0Sstevel@tonic-gate 					(void) snprintf(msgbuf, sizeof (msgbuf),
703*0Sstevel@tonic-gate 					    gettext(
704*0Sstevel@tonic-gate 			"Warning - directory at inode `%lu' is corrupted:\n\
705*0Sstevel@tonic-gate \t\".\" points to inode `%lu' - run fsck\n"),
706*0Sstevel@tonic-gate 					    ino, dp->d_ino);
707*0Sstevel@tonic-gate 					msg(msgbuf);
708*0Sstevel@tonic-gate 				}
709*0Sstevel@tonic-gate 				continue;
710*0Sstevel@tonic-gate 			}
711*0Sstevel@tonic-gate 			if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') {
712*0Sstevel@tonic-gate 				if (!BIT(dp->d_ino, dirmap) &&
713*0Sstevel@tonic-gate 				    ((ip = getino(ino)) == NULL ||
714*0Sstevel@tonic-gate 				    (ip->di_mode & IFMT) != IFATTRDIR)) {
715*0Sstevel@tonic-gate 					(void) snprintf(msgbuf, sizeof (msgbuf),
716*0Sstevel@tonic-gate 					    gettext(
717*0Sstevel@tonic-gate 			"Warning - directory at inode `%lu' is corrupted:\n\
718*0Sstevel@tonic-gate \t\"..\" points to non-directory inode `%lu' - run fsck\n"),
719*0Sstevel@tonic-gate 					    ino, dp->d_ino);
720*0Sstevel@tonic-gate 					msg(msgbuf);
721*0Sstevel@tonic-gate 				}
722*0Sstevel@tonic-gate 				continue;
723*0Sstevel@tonic-gate 			}
724*0Sstevel@tonic-gate 		}
725*0Sstevel@tonic-gate 		if (BIT(dp->d_ino, nodmap)) {
726*0Sstevel@tonic-gate 			dadded++;
727*0Sstevel@tonic-gate 			return;
728*0Sstevel@tonic-gate 		}
729*0Sstevel@tonic-gate 		if (BIT(dp->d_ino, dirmap))
730*0Sstevel@tonic-gate 			nsubdir++;
731*0Sstevel@tonic-gate 	}
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate #define	CACHESIZE 32
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate struct dinode *
737*0Sstevel@tonic-gate getino(ino)
738*0Sstevel@tonic-gate 	ino_t ino;
739*0Sstevel@tonic-gate {
740*0Sstevel@tonic-gate 	static ino_t minino, maxino;
741*0Sstevel@tonic-gate 	static struct dinode itab[MAXINOPB];
742*0Sstevel@tonic-gate 	static struct dinode icache[CACHESIZE];
743*0Sstevel@tonic-gate 	static ino_t icacheval[CACHESIZE], lasti = 0;
744*0Sstevel@tonic-gate 	static int cacheoff = 0;
745*0Sstevel@tonic-gate 	int i;
746*0Sstevel@tonic-gate 
747*0Sstevel@tonic-gate 	if (ino >= minino && ino < maxino) {
748*0Sstevel@tonic-gate 		lasti = ino;
749*0Sstevel@tonic-gate 		return (&itab[ino - minino]);
750*0Sstevel@tonic-gate 	}
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 	/* before we do major i/o, check for a secondary cache hit */
753*0Sstevel@tonic-gate 	for (i = 0; i < CACHESIZE; i++)
754*0Sstevel@tonic-gate 		if (icacheval[i] == ino)
755*0Sstevel@tonic-gate 			return (icache + i);
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 	/* we need to do major i/o.  throw the last inode retrieved into */
758*0Sstevel@tonic-gate 	/* the cache.  note: this copies garbage the first time it is    */
759*0Sstevel@tonic-gate 	/* used, but no harm done.					 */
760*0Sstevel@tonic-gate 	icacheval[cacheoff] = lasti;
761*0Sstevel@tonic-gate 	bcopy(itab + (lasti - minino), icache + cacheoff, sizeof (itab[0]));
762*0Sstevel@tonic-gate 	lasti = ino;
763*0Sstevel@tonic-gate 	if (++cacheoff >= CACHESIZE)
764*0Sstevel@tonic-gate 		cacheoff = 0;
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate #define	INOPERDB (DEV_BSIZE / sizeof (struct dinode))
767*0Sstevel@tonic-gate 	minino = ino &~ (INOPERDB - 1);
768*0Sstevel@tonic-gate 	maxino = ((itog(sblock, ino) + 1) * (unsigned)(sblock->fs_ipg));
769*0Sstevel@tonic-gate 	if (maxino > minino + MAXINOPB)
770*0Sstevel@tonic-gate 		maxino = minino + MAXINOPB;
771*0Sstevel@tonic-gate 	bread(
772*0Sstevel@tonic-gate 	    /* LINTED: can't make up for broken system macros here */
773*0Sstevel@tonic-gate 	    (fsbtodb(sblock, itod(sblock, ino)) + itoo(sblock, ino) / INOPERDB),
774*0Sstevel@tonic-gate 	    /* LINTED: (max - min) * size fits into a size_t */
775*0Sstevel@tonic-gate 	    (uchar_t *)itab, (size_t)((maxino - minino) * sizeof (*itab)));
776*0Sstevel@tonic-gate 	return (&itab[ino - minino]);
777*0Sstevel@tonic-gate }
778*0Sstevel@tonic-gate 
779*0Sstevel@tonic-gate #define	BREADEMAX 32
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate #ifdef NO__LONGLONG__
782*0Sstevel@tonic-gate #define	DEV_LSEEK(fd, offset, whence) \
783*0Sstevel@tonic-gate 	lseek((fd), (((off_t)(offset))*DEV_BSIZE), (whence))
784*0Sstevel@tonic-gate #else
785*0Sstevel@tonic-gate #define	DEV_LSEEK(fd, offset, whence) \
786*0Sstevel@tonic-gate 	llseek((fd), (((offset_t)(((unsigned)offset)))*DEV_BSIZE), (whence))
787*0Sstevel@tonic-gate #endif
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate #define	BREAD_FAIL(buf, size)	{ \
790*0Sstevel@tonic-gate 		breaderrors += 1; \
791*0Sstevel@tonic-gate 		bzero(buf, (size_t)size); \
792*0Sstevel@tonic-gate 	}
793*0Sstevel@tonic-gate 
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate void
797*0Sstevel@tonic-gate bread(da, ba, cnt)
798*0Sstevel@tonic-gate diskaddr_t da;
799*0Sstevel@tonic-gate uchar_t	*ba;
800*0Sstevel@tonic-gate size_t	cnt;
801*0Sstevel@tonic-gate {
802*0Sstevel@tonic-gate 	caddr_t maddr;
803*0Sstevel@tonic-gate 	uchar_t *dest;
804*0Sstevel@tonic-gate 	int saverr;
805*0Sstevel@tonic-gate 	int n;
806*0Sstevel@tonic-gate 	size_t len;
807*0Sstevel@tonic-gate 	off64_t filoff;
808*0Sstevel@tonic-gate 	off64_t mapoff;
809*0Sstevel@tonic-gate 	off64_t displacement;
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	static size_t pagesize = 0;
812*0Sstevel@tonic-gate 	static int breaderrors = 0;
813*0Sstevel@tonic-gate 
814*0Sstevel@tonic-gate 	/* mechanics for caching small bread requests.  these are */
815*0Sstevel@tonic-gate 	/* often small ACLs that are used over and over.	  */
816*0Sstevel@tonic-gate 	static uchar_t bcache[DEV_BSIZE * CACHESIZE];
817*0Sstevel@tonic-gate 	static diskaddr_t bcacheval[CACHESIZE];
818*0Sstevel@tonic-gate 	static int cacheoff = 0;
819*0Sstevel@tonic-gate 	int i;
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 	if ((cnt >= DEV_BSIZE) && (mapfd != -1)) {
822*0Sstevel@tonic-gate 		if (pagesize == 0)
823*0Sstevel@tonic-gate 			pagesize = getpagesize();
824*0Sstevel@tonic-gate 		/*
825*0Sstevel@tonic-gate 		 * We depend on mmap(2)'s guarantee that mapping a
826*0Sstevel@tonic-gate 		 * partial page will cause the remainder of the page
827*0Sstevel@tonic-gate 		 * to be zero-filled.
828*0Sstevel@tonic-gate 		 */
829*0Sstevel@tonic-gate 		filoff = ((off64_t)da) * DEV_BSIZE;
830*0Sstevel@tonic-gate 		displacement = filoff & (pagesize - 1);
831*0Sstevel@tonic-gate 		mapoff = filoff - displacement;
832*0Sstevel@tonic-gate 		/* LINTED offset will fit into 32 bits */
833*0Sstevel@tonic-gate 		len = (size_t)roundup(cnt + (filoff - mapoff), pagesize);
834*0Sstevel@tonic-gate 		maddr = mmap64(NULL, len, PROT_READ, MAP_SHARED, mapfd, mapoff);
835*0Sstevel@tonic-gate 		if (maddr != MAP_FAILED) {
836*0Sstevel@tonic-gate 			(void) memcpy(ba, maddr + displacement, cnt);
837*0Sstevel@tonic-gate 			(void) munmap(maddr, len);
838*0Sstevel@tonic-gate 			return;
839*0Sstevel@tonic-gate 		}
840*0Sstevel@tonic-gate 	}
841*0Sstevel@tonic-gate 
842*0Sstevel@tonic-gate 	if (DEV_LSEEK(fi, da, L_SET) < 0) {
843*0Sstevel@tonic-gate 		saverr = errno;
844*0Sstevel@tonic-gate 		msg(gettext("bread: dev_seek error: %s\n"), strerror(saverr));
845*0Sstevel@tonic-gate 		/* Don't know where we are, return the least-harmful data */
846*0Sstevel@tonic-gate 		BREAD_FAIL(ba, cnt);
847*0Sstevel@tonic-gate 		return;
848*0Sstevel@tonic-gate 	}
849*0Sstevel@tonic-gate 
850*0Sstevel@tonic-gate 	if (read(fi, ba, (size_t)cnt) == (size_t)cnt)
851*0Sstevel@tonic-gate 	    return;
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate 	while (cnt != 0) {
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 		if (da >= fsbtodb(sblock, sblock->fs_size)) {
856*0Sstevel@tonic-gate 			msg(gettext(
857*0Sstevel@tonic-gate 			    "Warning - block %llu is beyond the end of `%s'\n"),
858*0Sstevel@tonic-gate 			    da, disk);
859*0Sstevel@tonic-gate 			BREAD_FAIL(ba, cnt);
860*0Sstevel@tonic-gate 			break;
861*0Sstevel@tonic-gate 		}
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 		if (DEV_LSEEK(fi, da, L_SET) < 0) {
864*0Sstevel@tonic-gate 			msg(gettext("%s: %s error\n"), "bread", "DEV_LSEEK2");
865*0Sstevel@tonic-gate 			BREAD_FAIL(ba, cnt);
866*0Sstevel@tonic-gate 			break;
867*0Sstevel@tonic-gate 		}
868*0Sstevel@tonic-gate 
869*0Sstevel@tonic-gate 		if (cnt < DEV_BSIZE) {
870*0Sstevel@tonic-gate 			/* small read.  check for cache hit. */
871*0Sstevel@tonic-gate 			for (i = 0; i < CACHESIZE; i++)
872*0Sstevel@tonic-gate 				if (bcacheval[i] == da) {
873*0Sstevel@tonic-gate 					bcopy(bcache + (i * DEV_BSIZE),
874*0Sstevel@tonic-gate 					    ba, cnt);
875*0Sstevel@tonic-gate 					return;
876*0Sstevel@tonic-gate 				}
877*0Sstevel@tonic-gate 
878*0Sstevel@tonic-gate 			/* no cache hit; throw this one into the cache... */
879*0Sstevel@tonic-gate 			len = cnt;
880*0Sstevel@tonic-gate 			dest = bcache + (cacheoff * DEV_BSIZE);
881*0Sstevel@tonic-gate 			bcacheval[cacheoff] = da;
882*0Sstevel@tonic-gate 			if (++cacheoff >= CACHESIZE)
883*0Sstevel@tonic-gate 				cacheoff = 0;
884*0Sstevel@tonic-gate 		} else {
885*0Sstevel@tonic-gate 			len = DEV_BSIZE;
886*0Sstevel@tonic-gate 			dest = ba;
887*0Sstevel@tonic-gate 		}
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate 		n = read(fi, dest, DEV_BSIZE);
890*0Sstevel@tonic-gate 		if (n != DEV_BSIZE) {
891*0Sstevel@tonic-gate 			n = MAX(n, 0);
892*0Sstevel@tonic-gate 			bzero(dest+n, DEV_BSIZE-n);
893*0Sstevel@tonic-gate 			breaderrors += 1;
894*0Sstevel@tonic-gate 			msg(gettext(
895*0Sstevel@tonic-gate 			    "Warning - cannot read sector %llu of `%s'\n"),
896*0Sstevel@tonic-gate 			    da, disk);
897*0Sstevel@tonic-gate 		}
898*0Sstevel@tonic-gate 		if (dest != ba)
899*0Sstevel@tonic-gate 			bcopy(dest, ba, len);
900*0Sstevel@tonic-gate 
901*0Sstevel@tonic-gate 		da++;
902*0Sstevel@tonic-gate 		/* LINTED character pointers aren't signed */
903*0Sstevel@tonic-gate 		ba += len;
904*0Sstevel@tonic-gate 		cnt -= len;
905*0Sstevel@tonic-gate 	}
906*0Sstevel@tonic-gate 
907*0Sstevel@tonic-gate 	if (breaderrors > BREADEMAX) {
908*0Sstevel@tonic-gate 		msg(gettext(
909*0Sstevel@tonic-gate 		    "More than %d block read errors from dump device `%s'\n"),
910*0Sstevel@tonic-gate 		    BREADEMAX, disk);
911*0Sstevel@tonic-gate 		dumpailing();
912*0Sstevel@tonic-gate 		breaderrors = 0;
913*0Sstevel@tonic-gate 	}
914*0Sstevel@tonic-gate }
915