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