xref: /titanic_44/usr/src/cmd/backup/dump/dumptraverse.c (revision 90eb94cfb94cf76036f814623665c51517beebfb)
17c478bd9Sstevel@tonic-gate /*
2*90eb94cfSns158690  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include "dump.h"
187c478bd9Sstevel@tonic-gate #include <sys/file.h>
197c478bd9Sstevel@tonic-gate #include <sys/mman.h>
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate #ifdef __STDC__
227c478bd9Sstevel@tonic-gate static void lf_dmpindir(daddr32_t, int, u_offset_t *);
237c478bd9Sstevel@tonic-gate static void indir(daddr32_t, int, u_offset_t *);
247c478bd9Sstevel@tonic-gate static void lf_blksout(daddr32_t *, u_offset_t);
257c478bd9Sstevel@tonic-gate static void lf_dumpinode(struct dinode *);
267c478bd9Sstevel@tonic-gate static void dsrch(daddr32_t, ulong_t, u_offset_t);
277c478bd9Sstevel@tonic-gate void lf_dump(struct dinode *);
287c478bd9Sstevel@tonic-gate #else
297c478bd9Sstevel@tonic-gate static void lf_dmpindir();
307c478bd9Sstevel@tonic-gate static void indir();
317c478bd9Sstevel@tonic-gate static void lf_blksout();
327c478bd9Sstevel@tonic-gate static void dsrch();
337c478bd9Sstevel@tonic-gate void lf_dump();
347c478bd9Sstevel@tonic-gate #endif
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate static	char msgbuf[256];
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate void
397c478bd9Sstevel@tonic-gate pass(fn, map)
407c478bd9Sstevel@tonic-gate 	void (*fn)(struct dinode *);
417c478bd9Sstevel@tonic-gate 	uchar_t *map;
427c478bd9Sstevel@tonic-gate {
437c478bd9Sstevel@tonic-gate 	int bits;
447c478bd9Sstevel@tonic-gate 	ino_t maxino;
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate 	maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg - 1);
477c478bd9Sstevel@tonic-gate 	/*
487c478bd9Sstevel@tonic-gate 	 * Handle pass restarts.  We don't check for UFSROOTINO just in
497c478bd9Sstevel@tonic-gate 	 * case we need to restart on the root inode.
507c478bd9Sstevel@tonic-gate 	 */
517c478bd9Sstevel@tonic-gate 	if (ino != 0) {
527c478bd9Sstevel@tonic-gate 		bits = ~0;
537c478bd9Sstevel@tonic-gate 		if (map != NULL) {
547c478bd9Sstevel@tonic-gate 			/* LINTED: lint seems to think map is signed */
557c478bd9Sstevel@tonic-gate 			map += (ino / NBBY);
567c478bd9Sstevel@tonic-gate 			bits = *map++;
577c478bd9Sstevel@tonic-gate 		}
587c478bd9Sstevel@tonic-gate 		bits >>= (ino % NBBY);
597c478bd9Sstevel@tonic-gate 		resetino(ino);
607c478bd9Sstevel@tonic-gate 		goto restart;
617c478bd9Sstevel@tonic-gate 	}
627c478bd9Sstevel@tonic-gate 	while (ino < maxino) {
637c478bd9Sstevel@tonic-gate 		if ((ino % NBBY) == 0) {
647c478bd9Sstevel@tonic-gate 			bits = ~0;
657c478bd9Sstevel@tonic-gate 			if (map != NULL)
667c478bd9Sstevel@tonic-gate 				bits = *map++;
677c478bd9Sstevel@tonic-gate 		}
687c478bd9Sstevel@tonic-gate restart:
697c478bd9Sstevel@tonic-gate 		ino++;
707c478bd9Sstevel@tonic-gate 		/*
717c478bd9Sstevel@tonic-gate 		 * Ignore any inode less than UFSROOTINO and inodes that
727c478bd9Sstevel@tonic-gate 		 * we have already done on a previous pass.
737c478bd9Sstevel@tonic-gate 		 */
747c478bd9Sstevel@tonic-gate 		if ((ino >= UFSROOTINO) && (bits & 1)) {
757c478bd9Sstevel@tonic-gate 			/*
767c478bd9Sstevel@tonic-gate 			 * The following test is merely an optimization
777c478bd9Sstevel@tonic-gate 			 * for common case where "add" will just return.
787c478bd9Sstevel@tonic-gate 			 */
797c478bd9Sstevel@tonic-gate 			if (!(fn == add && BIT(ino, nodmap)))
807c478bd9Sstevel@tonic-gate 				(*fn)(getino(ino));
817c478bd9Sstevel@tonic-gate 		}
827c478bd9Sstevel@tonic-gate 		bits >>= 1;
837c478bd9Sstevel@tonic-gate 	}
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate void
mark(ip)877c478bd9Sstevel@tonic-gate mark(ip)
887c478bd9Sstevel@tonic-gate 	struct dinode *ip;
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	int f;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	f = ip->di_mode & IFMT;
937c478bd9Sstevel@tonic-gate 	if (f == 0 || ip->di_nlink <= 0) {
947c478bd9Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
957c478bd9Sstevel@tonic-gate 		BIC(ino, clrmap);
967c478bd9Sstevel@tonic-gate 		return;
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 	/* LINTED: 32-bit to 8-bit assignment ok */
997c478bd9Sstevel@tonic-gate 	BIS(ino, clrmap);
1007c478bd9Sstevel@tonic-gate 	if (f == IFDIR || f == IFATTRDIR) {
1017c478bd9Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
1027c478bd9Sstevel@tonic-gate 		BIS(ino, dirmap);
1037c478bd9Sstevel@tonic-gate 	}
1047c478bd9Sstevel@tonic-gate 	if (ip->di_ctime >= spcl.c_ddate) {
1057c478bd9Sstevel@tonic-gate 		if (f == IFSHAD)
1067c478bd9Sstevel@tonic-gate 			return;
1077c478bd9Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
1087c478bd9Sstevel@tonic-gate 		BIS(ino, nodmap);
1097c478bd9Sstevel@tonic-gate 		/* attribute changes impact the root */
1107c478bd9Sstevel@tonic-gate 		if (f == IFATTRDIR)
1117c478bd9Sstevel@tonic-gate 			BIS(UFSROOTINO, nodmap);
1127c478bd9Sstevel@tonic-gate 		if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) {
1137c478bd9Sstevel@tonic-gate 			o_esize += 1;
1147c478bd9Sstevel@tonic-gate 			return;
1157c478bd9Sstevel@tonic-gate 		}
1167c478bd9Sstevel@tonic-gate 		est(ip);
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate void
active_mark(ip)1217c478bd9Sstevel@tonic-gate active_mark(ip)
1227c478bd9Sstevel@tonic-gate 	struct dinode *ip;
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	int f;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	f = ip->di_mode & IFMT;
1277c478bd9Sstevel@tonic-gate 	if (f == 0 || ip->di_nlink <= 0) {
1287c478bd9Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
1297c478bd9Sstevel@tonic-gate 		BIC(ino, clrmap);
1307c478bd9Sstevel@tonic-gate 		return;
1317c478bd9Sstevel@tonic-gate 	}
1327c478bd9Sstevel@tonic-gate 	/* LINTED: 32-bit to 8-bit assignment ok */
1337c478bd9Sstevel@tonic-gate 	BIS(ino, clrmap);
1347c478bd9Sstevel@tonic-gate 	if (f == IFDIR || f == IFATTRDIR) {
1357c478bd9Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
1367c478bd9Sstevel@tonic-gate 		BIS(ino, dirmap);
1377c478bd9Sstevel@tonic-gate 	}
1387c478bd9Sstevel@tonic-gate 	if (BIT(ino, activemap)) {
1397c478bd9Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
1407c478bd9Sstevel@tonic-gate 		BIS(ino, nodmap);
1417c478bd9Sstevel@tonic-gate 		/* attribute changes impact the root */
1427c478bd9Sstevel@tonic-gate 		if (f == IFATTRDIR)
1437c478bd9Sstevel@tonic-gate 			BIS(UFSROOTINO, nodmap);
1447c478bd9Sstevel@tonic-gate 		if (f != IFREG && f != IFDIR && f != IFATTRDIR && f != IFLNK) {
1457c478bd9Sstevel@tonic-gate 			o_esize += 1;
1467c478bd9Sstevel@tonic-gate 			return;
1477c478bd9Sstevel@tonic-gate 		}
1487c478bd9Sstevel@tonic-gate 		est(ip);
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static struct shcount {
1537c478bd9Sstevel@tonic-gate 	struct shcount *higher, *lower;
1547c478bd9Sstevel@tonic-gate 	ino_t ino;
1557c478bd9Sstevel@tonic-gate 	unsigned long count;
1567c478bd9Sstevel@tonic-gate } shcounts = {
1577c478bd9Sstevel@tonic-gate 	NULL, NULL,
1587c478bd9Sstevel@tonic-gate 	0,
1597c478bd9Sstevel@tonic-gate 	0
1607c478bd9Sstevel@tonic-gate };
1617c478bd9Sstevel@tonic-gate static struct shcount *shc = NULL;
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate void
markshad(ip)1647c478bd9Sstevel@tonic-gate markshad(ip)
1657c478bd9Sstevel@tonic-gate 	struct dinode *ip;
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	ino_t shadow;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	if (ip->di_shadow == 0)
1707c478bd9Sstevel@tonic-gate 		return;
1717c478bd9Sstevel@tonic-gate 	if (shc == NULL)
1727c478bd9Sstevel@tonic-gate 		shc = &shcounts;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	shadow = (ino_t)(unsigned)(ip->di_shadow);
1757c478bd9Sstevel@tonic-gate 	while ((shadow > shc->ino) && (shc->higher))
1767c478bd9Sstevel@tonic-gate 		shc = shc->higher;
1777c478bd9Sstevel@tonic-gate 	while ((shadow < shc->ino) && (shc->lower))
1787c478bd9Sstevel@tonic-gate 		shc = shc->lower;
1797c478bd9Sstevel@tonic-gate 	if (shadow != shc->ino) {
1807c478bd9Sstevel@tonic-gate 		struct shcount *new;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 		new = (struct shcount *)xcalloc(1, sizeof (*new));
1837c478bd9Sstevel@tonic-gate 		new->higher = shc->higher;
1847c478bd9Sstevel@tonic-gate 		if (shc->higher != NULL)
1857c478bd9Sstevel@tonic-gate 			shc->higher->lower = new;
1867c478bd9Sstevel@tonic-gate 		shc->higher = new;
1877c478bd9Sstevel@tonic-gate 		new->lower = shc;
1887c478bd9Sstevel@tonic-gate 		shc = new;
1897c478bd9Sstevel@tonic-gate 		shc->ino = shadow;
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	/* LINTED: 32-bit to 8-bit assignment ok */
1937c478bd9Sstevel@tonic-gate 	BIS(shadow, shamap);
1947c478bd9Sstevel@tonic-gate 	shc->count++;
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate void
estshad(ip)1987c478bd9Sstevel@tonic-gate estshad(ip)
1997c478bd9Sstevel@tonic-gate 	struct dinode *ip;
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate 	u_offset_t esizeprime;
2027c478bd9Sstevel@tonic-gate 	u_offset_t tmpesize;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if (ip->di_size <= sizeof (union u_shadow))
2057c478bd9Sstevel@tonic-gate 		return;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	while ((ino > shc->ino) && (shc->higher))
2087c478bd9Sstevel@tonic-gate 		shc = shc->higher;
2097c478bd9Sstevel@tonic-gate 	while ((ino < shc->ino) && (shc->lower))
2107c478bd9Sstevel@tonic-gate 		shc = shc->lower;
2117c478bd9Sstevel@tonic-gate 	if (ino != shc->ino)
2127c478bd9Sstevel@tonic-gate 		return; /* xxx panic? complain? */
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	tmpesize = (o_esize + f_esize);
2157c478bd9Sstevel@tonic-gate 	esizeprime = tmpesize;
2167c478bd9Sstevel@tonic-gate 	est(ip);
2177c478bd9Sstevel@tonic-gate 	esizeprime = tmpesize - esizeprime;
2187c478bd9Sstevel@tonic-gate 	esizeprime *= shc->count - 1;
2197c478bd9Sstevel@tonic-gate 	f_esize += esizeprime;
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate void
freeshad()2237c478bd9Sstevel@tonic-gate freeshad()
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	if (shc == NULL)
2267c478bd9Sstevel@tonic-gate 		return;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	while (shc->higher)
2297c478bd9Sstevel@tonic-gate 		shc = shc->higher;
2307c478bd9Sstevel@tonic-gate 	while (shc->lower) {
2317c478bd9Sstevel@tonic-gate 		shc = shc->lower;
2327c478bd9Sstevel@tonic-gate 		if (shc->higher) /* else panic? */
2337c478bd9Sstevel@tonic-gate 			(void) free(shc->higher);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 	/*
2367c478bd9Sstevel@tonic-gate 	 * This should be unnecessary, but do it just to be safe.
2377c478bd9Sstevel@tonic-gate 	 * Note that shc might be malloc'd or static, so can't free().
2387c478bd9Sstevel@tonic-gate 	 */
2397c478bd9Sstevel@tonic-gate 	bzero(shc, sizeof (*shc));
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate void
add(ip)2437c478bd9Sstevel@tonic-gate add(ip)
2447c478bd9Sstevel@tonic-gate 	struct	dinode	*ip;
2457c478bd9Sstevel@tonic-gate {
2467c478bd9Sstevel@tonic-gate 	int i;
2477c478bd9Sstevel@tonic-gate 	u_offset_t filesize;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if (BIT(ino, nodmap))
2507c478bd9Sstevel@tonic-gate 		return;
2517c478bd9Sstevel@tonic-gate 	if ((ip->di_mode & IFMT) != IFDIR &&
2527c478bd9Sstevel@tonic-gate 	    (ip->di_mode & IFMT) != IFATTRDIR) {
2537c478bd9Sstevel@tonic-gate 		(void) snprintf(msgbuf, sizeof (msgbuf), gettext(
2547c478bd9Sstevel@tonic-gate 		    "Warning - directory at inode `%lu' vanished!\n"), ino);
2557c478bd9Sstevel@tonic-gate 		msg(msgbuf);
2567c478bd9Sstevel@tonic-gate 		/* LINTED: 32-bit to 8-bit assignment ok */
2577c478bd9Sstevel@tonic-gate 		BIC(ino, dirmap);
2587c478bd9Sstevel@tonic-gate 		return;
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 	nsubdir = 0;
2617c478bd9Sstevel@tonic-gate 	dadded = 0;
2627c478bd9Sstevel@tonic-gate 	filesize = ip->di_size;
2637c478bd9Sstevel@tonic-gate 	for (i = 0; i < NDADDR; i++) {
2647c478bd9Sstevel@tonic-gate 		if (ip->di_db[i] != 0)
2657c478bd9Sstevel@tonic-gate 			/* LINTED dblksize/blkoff does a safe cast here */
2667c478bd9Sstevel@tonic-gate 			dsrch(ip->di_db[i], (ulong_t)dblksize(sblock, ip, i),
2677c478bd9Sstevel@tonic-gate 			    filesize);
2687c478bd9Sstevel@tonic-gate 		filesize -= (unsigned)(sblock->fs_bsize);
2697c478bd9Sstevel@tonic-gate 	}
2707c478bd9Sstevel@tonic-gate 	for (i = 0; i < NIADDR; i++) {
2717c478bd9Sstevel@tonic-gate 		if (ip->di_ib[i] != 0)
2727c478bd9Sstevel@tonic-gate 			indir(ip->di_ib[i], i, &filesize);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	if (dadded) {
2757c478bd9Sstevel@tonic-gate 		nadded++;
2767c478bd9Sstevel@tonic-gate 		if (!BIT(ino, nodmap)) {
2777c478bd9Sstevel@tonic-gate 			/* LINTED: 32-bit to 8-bit assignment ok */
2787c478bd9Sstevel@tonic-gate 			BIS(ino, nodmap);
2797c478bd9Sstevel@tonic-gate 			if ((ip->di_mode & IFMT) == IFATTRDIR) {
2807c478bd9Sstevel@tonic-gate 				/* attribute changes "auto-percolate" to root */
2817c478bd9Sstevel@tonic-gate 				BIS(UFSROOTINO, nodmap);
2827c478bd9Sstevel@tonic-gate 			}
2837c478bd9Sstevel@tonic-gate 			est(ip);
2847c478bd9Sstevel@tonic-gate 		}
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	if (nsubdir == 0) {
2877c478bd9Sstevel@tonic-gate 		if (!BIT(ino, nodmap)) {
2887c478bd9Sstevel@tonic-gate 			/* LINTED: 32-bit to 8-bit assignment ok */
2897c478bd9Sstevel@tonic-gate 			BIC(ino, dirmap);
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate static void
indir(d,n,filesize)2957c478bd9Sstevel@tonic-gate indir(d, n, filesize)
2967c478bd9Sstevel@tonic-gate 	daddr32_t d;
2977c478bd9Sstevel@tonic-gate 	int n;
2987c478bd9Sstevel@tonic-gate 	u_offset_t *filesize;
2997c478bd9Sstevel@tonic-gate {
3007c478bd9Sstevel@tonic-gate 	int i;
3017c478bd9Sstevel@tonic-gate 	daddr32_t idblk[MAXNINDIR];
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) {
3047c478bd9Sstevel@tonic-gate 		msg(gettext(
3057c478bd9Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
3067c478bd9Sstevel@tonic-gate 		dumpabort();
3077c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3087c478bd9Sstevel@tonic-gate 	}
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	if ((unsigned)NINDIR(sblock) > MAXNINDIR) {
3117c478bd9Sstevel@tonic-gate 		/*CSTYLED*/
3127c478bd9Sstevel@tonic-gate 		msg(gettext(
3137c478bd9Sstevel@tonic-gate "Inconsistency detected: inode has more indirect \
3147c478bd9Sstevel@tonic-gate blocks than valid maximum.\n"));
3157c478bd9Sstevel@tonic-gate 		dumpabort();
3167c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	if (dadded || *filesize == 0)
3207c478bd9Sstevel@tonic-gate 		return;
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate #ifdef	lint
3237c478bd9Sstevel@tonic-gate 	idblk[0] = '\0';
3247c478bd9Sstevel@tonic-gate #endif	/* lint */
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/* xxx sanity check sblock contents before trusting them */
3277c478bd9Sstevel@tonic-gate 	bread(fsbtodb(sblock, d), (uchar_t *)idblk, (size_t)sblock->fs_bsize);
3287c478bd9Sstevel@tonic-gate 	if (n <= 0) {
3297c478bd9Sstevel@tonic-gate 		for (i = 0; i < NINDIR(sblock); i++) {
3307c478bd9Sstevel@tonic-gate 			d = idblk[i];
3317c478bd9Sstevel@tonic-gate 			if (d != 0)
3327c478bd9Sstevel@tonic-gate 				dsrch(d, (ulong_t)(uint32_t)sblock->fs_bsize,
3337c478bd9Sstevel@tonic-gate 				    *filesize);
3347c478bd9Sstevel@tonic-gate 			*filesize -= (unsigned)(sblock->fs_bsize);
3357c478bd9Sstevel@tonic-gate 		}
3367c478bd9Sstevel@tonic-gate 	} else {
3377c478bd9Sstevel@tonic-gate 		n--;
3387c478bd9Sstevel@tonic-gate 		for (i = 0; i < NINDIR(sblock); i++) {
3397c478bd9Sstevel@tonic-gate 			d = idblk[i];
3407c478bd9Sstevel@tonic-gate 			if (d != 0)
3417c478bd9Sstevel@tonic-gate 				indir(d, n, filesize);
3427c478bd9Sstevel@tonic-gate 		}
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate void
dirdump(ip)3477c478bd9Sstevel@tonic-gate dirdump(ip)
3487c478bd9Sstevel@tonic-gate 	struct dinode *ip;
3497c478bd9Sstevel@tonic-gate {
3507c478bd9Sstevel@tonic-gate 	/* watchout for dir inodes deleted and maybe reallocated */
3517c478bd9Sstevel@tonic-gate 	if (((ip->di_mode & IFMT) != IFDIR &&
3527c478bd9Sstevel@tonic-gate 	    (ip->di_mode & IFMT) != IFATTRDIR) || ip->di_nlink < 2) {
3537c478bd9Sstevel@tonic-gate 		(void) snprintf(msgbuf, sizeof (msgbuf), gettext(
3547c478bd9Sstevel@tonic-gate 		    "Warning - directory at inode `%lu' vanished!\n"),
3557c478bd9Sstevel@tonic-gate 			ino);
3567c478bd9Sstevel@tonic-gate 		msg(msgbuf);
3577c478bd9Sstevel@tonic-gate 		return;
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	lf_dump(ip);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate static u_offset_t loffset; /* current offset in file (ufsdump) */
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate static void
lf_dumpmeta(ip)3657c478bd9Sstevel@tonic-gate lf_dumpmeta(ip)
3667c478bd9Sstevel@tonic-gate 	struct dinode *ip;
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	if ((ip->di_shadow == 0) || shortmeta)
3697c478bd9Sstevel@tonic-gate 	    return;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	lf_dumpinode(getino((ino_t)(unsigned)(ip->di_shadow)));
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate int
hasshortmeta(ip)3757c478bd9Sstevel@tonic-gate hasshortmeta(ip)
3767c478bd9Sstevel@tonic-gate 	struct dinode **ip;
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	ino_t savino;
3797c478bd9Sstevel@tonic-gate 	int rc;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if ((*ip)->di_shadow == 0)
3827c478bd9Sstevel@tonic-gate 		return (0);
3837c478bd9Sstevel@tonic-gate 	savino = ino;
3847c478bd9Sstevel@tonic-gate 	*ip = getino((ino_t)(unsigned)((*ip)->di_shadow));
3857c478bd9Sstevel@tonic-gate 	rc = ((*ip)->di_size <= sizeof (union u_shadow));
3867c478bd9Sstevel@tonic-gate 	*ip = getino(ino = savino);
3877c478bd9Sstevel@tonic-gate 	return (rc);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate void
lf_dumpinode(ip)3917c478bd9Sstevel@tonic-gate lf_dumpinode(ip)
3927c478bd9Sstevel@tonic-gate     struct dinode *ip;
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	int i;
3957c478bd9Sstevel@tonic-gate 	u_offset_t size;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	i = ip->di_mode & IFMT;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (i == 0 || ip->di_nlink <= 0)
4007c478bd9Sstevel@tonic-gate 		return;
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	spcl.c_dinode = *ip;
4037c478bd9Sstevel@tonic-gate 	spcl.c_count = 0;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if ((i != IFDIR && i != IFATTRDIR && i != IFREG && i != IFLNK &&
4067c478bd9Sstevel@tonic-gate 	    i != IFSHAD) || ip->di_size == 0) {
4077c478bd9Sstevel@tonic-gate 		toslave(dospcl, ino);
4087c478bd9Sstevel@tonic-gate 		return;
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	size = NDADDR * (unsigned)(sblock->fs_bsize);
4127c478bd9Sstevel@tonic-gate 	if (size > ip->di_size)
4137c478bd9Sstevel@tonic-gate 		size = ip->di_size;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	lf_blksout(&ip->di_db[0], size);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	size = ip->di_size - size;
4187c478bd9Sstevel@tonic-gate 	if (size > 0) {
4197c478bd9Sstevel@tonic-gate 		for (i = 0; i < NIADDR; i++) {
4207c478bd9Sstevel@tonic-gate 			lf_dmpindir(ip->di_ib[i], i, &size);
4217c478bd9Sstevel@tonic-gate 			if (size == 0)
4227c478bd9Sstevel@tonic-gate 				break;
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate void
lf_dump(ip)4287c478bd9Sstevel@tonic-gate lf_dump(ip)
4297c478bd9Sstevel@tonic-gate 	struct dinode *ip;
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if ((!BIT(ino, nodmap)) && (!BIT(ino, shamap)))
4337c478bd9Sstevel@tonic-gate 		return;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	shortmeta = hasshortmeta(&ip);
4367c478bd9Sstevel@tonic-gate 	if (shortmeta) {
4377c478bd9Sstevel@tonic-gate 		ip = getino((ino_t)(unsigned)(ip->di_shadow));
4387c478bd9Sstevel@tonic-gate 		/* assume spcl.c_shadow is smaller than 1 block */
4397c478bd9Sstevel@tonic-gate 		bread(fsbtodb(sblock, ip->di_db[0]),
4407c478bd9Sstevel@tonic-gate 		    (uchar_t *)spcl.c_shadow.c_shadow, sizeof (spcl.c_shadow));
4417c478bd9Sstevel@tonic-gate 		spcl.c_flags |= DR_HASMETA;
4427c478bd9Sstevel@tonic-gate 	} else {
4437c478bd9Sstevel@tonic-gate 		spcl.c_flags &= ~DR_HASMETA;
4447c478bd9Sstevel@tonic-gate 	}
4457c478bd9Sstevel@tonic-gate 	ip = getino(ino);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	loffset = 0;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	if (newtape) {
4507c478bd9Sstevel@tonic-gate 		spcl.c_type = TS_TAPE;
4517c478bd9Sstevel@tonic-gate 	} else if (pos)
4527c478bd9Sstevel@tonic-gate 		spcl.c_type = TS_ADDR;
4537c478bd9Sstevel@tonic-gate 	else
4547c478bd9Sstevel@tonic-gate 		spcl.c_type = TS_INODE;
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	newtape = 0;
4577c478bd9Sstevel@tonic-gate 	lf_dumpinode(ip);
4587c478bd9Sstevel@tonic-gate 	lf_dumpmeta(ip);
4597c478bd9Sstevel@tonic-gate 	pos = 0;
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate static void
lf_dmpindir(blk,lvl,size)4637c478bd9Sstevel@tonic-gate lf_dmpindir(blk, lvl, size)
4647c478bd9Sstevel@tonic-gate 	daddr32_t blk;
4657c478bd9Sstevel@tonic-gate 	int lvl;
4667c478bd9Sstevel@tonic-gate 	u_offset_t *size;
4677c478bd9Sstevel@tonic-gate {
4687c478bd9Sstevel@tonic-gate 	int i;
4697c478bd9Sstevel@tonic-gate 	u_offset_t cnt;
4707c478bd9Sstevel@tonic-gate 	daddr32_t idblk[MAXNINDIR];
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if ((unsigned)(sblock->fs_bsize) > sizeof (idblk)) {
4737c478bd9Sstevel@tonic-gate 		msg(gettext(
4747c478bd9Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
4757c478bd9Sstevel@tonic-gate 		dumpabort();
4767c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if ((unsigned)NINDIR(sblock) > MAXNINDIR) {
4807c478bd9Sstevel@tonic-gate 		msg(gettext(
4817c478bd9Sstevel@tonic-gate "Inconsistency detected: inode has more indirect \
4827c478bd9Sstevel@tonic-gate blocks than valid maximum.\n"));
4837c478bd9Sstevel@tonic-gate 		dumpabort();
4847c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	if (blk != 0)
4887c478bd9Sstevel@tonic-gate 		bread(fsbtodb(sblock, blk), (uchar_t *)idblk,
4897c478bd9Sstevel@tonic-gate 		    (size_t)sblock->fs_bsize);
4907c478bd9Sstevel@tonic-gate 	else
4917c478bd9Sstevel@tonic-gate 		bzero((char *)idblk, (size_t)sblock->fs_bsize);
4927c478bd9Sstevel@tonic-gate 	if (lvl <= 0) {
4937c478bd9Sstevel@tonic-gate 		cnt = (u_offset_t)(unsigned)NINDIR(sblock) *
4947c478bd9Sstevel@tonic-gate 		    (u_offset_t)(unsigned)(sblock->fs_bsize);
4957c478bd9Sstevel@tonic-gate 		if (cnt > *size)
4967c478bd9Sstevel@tonic-gate 			cnt = *size;
4977c478bd9Sstevel@tonic-gate 		*size -= cnt;
4987c478bd9Sstevel@tonic-gate 		lf_blksout(&idblk[0], cnt);
4997c478bd9Sstevel@tonic-gate 		return;
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	lvl--;
5027c478bd9Sstevel@tonic-gate 	for (i = 0; i < NINDIR(sblock); i++) {
5037c478bd9Sstevel@tonic-gate 		lf_dmpindir(idblk[i], lvl, size);
5047c478bd9Sstevel@tonic-gate 		if (*size == 0)
5057c478bd9Sstevel@tonic-gate 			return;
5067c478bd9Sstevel@tonic-gate 	}
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate static void
lf_blksout(blkp,bytes)5107c478bd9Sstevel@tonic-gate lf_blksout(blkp, bytes)
5117c478bd9Sstevel@tonic-gate 	daddr32_t *blkp;
5127c478bd9Sstevel@tonic-gate 	u_offset_t bytes;
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	u_offset_t i;
5157c478bd9Sstevel@tonic-gate 	u_offset_t tbperfsb = (unsigned)(sblock->fs_bsize / tp_bsize);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	u_offset_t j, k, count;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	u_offset_t bytepos, diff;
5207c478bd9Sstevel@tonic-gate 	u_offset_t bytecnt = 0;
5217c478bd9Sstevel@tonic-gate 	off_t byteoff = 0;	/* bytes to skip within first f/s block */
5227c478bd9Sstevel@tonic-gate 	off_t fragoff = 0;	/* frags to skip within first f/s block */
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	u_offset_t tpblkoff = 0; /* tape blocks to skip in first f/s block */
5257c478bd9Sstevel@tonic-gate 	u_offset_t tpblkskip = 0;	/* total tape blocks to skip  */
5267c478bd9Sstevel@tonic-gate 	u_offset_t skip;		/* tape blocks to skip this pass */
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	if (pos) {
5297c478bd9Sstevel@tonic-gate 		/*
5307c478bd9Sstevel@tonic-gate 		 * We get here if a slave throws a signal to the
5317c478bd9Sstevel@tonic-gate 		 * master indicating a partially dumped file.
5327c478bd9Sstevel@tonic-gate 		 * Begin by figuring out what was undone.
5337c478bd9Sstevel@tonic-gate 		 */
5347c478bd9Sstevel@tonic-gate 		bytepos = (offset_t)pos * tp_bsize;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 		if ((loffset + bytes) <= bytepos) {
5377c478bd9Sstevel@tonic-gate 			/* This stuff was dumped already, forget it. */
5387c478bd9Sstevel@tonic-gate 			loffset += (u_offset_t)tp_bsize *
5397c478bd9Sstevel@tonic-gate 			    /* LINTED: spurious complaint on sign-extending */
5407c478bd9Sstevel@tonic-gate 			    d_howmany(bytes, (u_offset_t)tp_bsize);
5417c478bd9Sstevel@tonic-gate 			return;
5427c478bd9Sstevel@tonic-gate 		}
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 		if (loffset < bytepos) {
5457c478bd9Sstevel@tonic-gate 			/*
5467c478bd9Sstevel@tonic-gate 			 * Some of this was dumped, some wasn't.
5477c478bd9Sstevel@tonic-gate 			 * Figure out what was done and skip it.
5487c478bd9Sstevel@tonic-gate 			 */
5497c478bd9Sstevel@tonic-gate 			diff = bytepos - loffset;
5507c478bd9Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
5517c478bd9Sstevel@tonic-gate 			tpblkskip = d_howmany(diff, (u_offset_t)tp_bsize);
5527c478bd9Sstevel@tonic-gate 			/* LINTED room after EOT is only a few MB */
5537c478bd9Sstevel@tonic-gate 			blkp += (int)(diff / sblock->fs_bsize);
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 			bytecnt = diff % (unsigned)(sblock->fs_bsize);
5567c478bd9Sstevel@tonic-gate 			/* LINTED: result fits, due to modulus */
5577c478bd9Sstevel@tonic-gate 			byteoff = bytecnt % (off_t)(sblock->fs_fsize);
5587c478bd9Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
5597c478bd9Sstevel@tonic-gate 			tpblkoff = d_howmany(bytecnt,
5607c478bd9Sstevel@tonic-gate 			    (u_offset_t)(unsigned)tp_bsize);
5617c478bd9Sstevel@tonic-gate 			/* LINTED: result fits, due to modulus */
5627c478bd9Sstevel@tonic-gate 			fragoff = bytecnt / (off_t)(sblock->fs_fsize);
5637c478bd9Sstevel@tonic-gate 			bytecnt = (unsigned)(sblock->fs_bsize) - bytecnt;
5647c478bd9Sstevel@tonic-gate 		}
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	loffset += bytes;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	while (bytes > 0) {
5707c478bd9Sstevel@tonic-gate 		if (bytes < TP_NINDIR*tp_bsize)
5717c478bd9Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
5727c478bd9Sstevel@tonic-gate 			count = d_howmany(bytes, (u_offset_t)tp_bsize);
5737c478bd9Sstevel@tonic-gate 		else
5747c478bd9Sstevel@tonic-gate 			count = TP_NINDIR;
5757c478bd9Sstevel@tonic-gate 		if (tpblkskip) {
5767c478bd9Sstevel@tonic-gate 			if (tpblkskip < TP_NINDIR) {
5777c478bd9Sstevel@tonic-gate 				bytes -= (tpblkskip * (u_offset_t)tp_bsize);
5787c478bd9Sstevel@tonic-gate 				skip = tpblkskip;
5797c478bd9Sstevel@tonic-gate 				tpblkskip = 0;
5807c478bd9Sstevel@tonic-gate 			} else {
5817c478bd9Sstevel@tonic-gate 				bytes -= (offset_t)TP_NINDIR*tp_bsize;
5827c478bd9Sstevel@tonic-gate 				tpblkskip -= TP_NINDIR;
5837c478bd9Sstevel@tonic-gate 				continue;
5847c478bd9Sstevel@tonic-gate 			}
5857c478bd9Sstevel@tonic-gate 		} else
5867c478bd9Sstevel@tonic-gate 			skip = 0;
5877c478bd9Sstevel@tonic-gate 		assert(tbperfsb >= tpblkoff);
5887c478bd9Sstevel@tonic-gate 		assert((count - skip) <= TP_NINDIR);
5897c478bd9Sstevel@tonic-gate 		for (j = 0, k = 0; j < count - skip; j++, k++) {
5907c478bd9Sstevel@tonic-gate 			spcl.c_addr[j] = (blkp[k] != 0);
5917c478bd9Sstevel@tonic-gate 			for (i = tbperfsb - tpblkoff; --i > 0; j++)
5927c478bd9Sstevel@tonic-gate 				spcl.c_addr[j+1] = spcl.c_addr[j];
5937c478bd9Sstevel@tonic-gate 			tpblkoff = 0;
5947c478bd9Sstevel@tonic-gate 		}
5957c478bd9Sstevel@tonic-gate 		/* LINTED (count - skip) will always fit into an int32_t */
5967c478bd9Sstevel@tonic-gate 		spcl.c_count = count - skip;
5977c478bd9Sstevel@tonic-gate 		toslave(dospcl, ino);
5987c478bd9Sstevel@tonic-gate 		bytecnt = MIN(bytes, bytecnt ?
5997c478bd9Sstevel@tonic-gate 		    bytecnt : (unsigned)(sblock->fs_bsize));
6007c478bd9Sstevel@tonic-gate 		j = 0;
6017c478bd9Sstevel@tonic-gate 		while (j < count - skip) {
6027c478bd9Sstevel@tonic-gate 			if (*blkp != 0) {
6037c478bd9Sstevel@tonic-gate 				/* LINTED: fragoff fits into 32 bits */
6047c478bd9Sstevel@tonic-gate 				dmpblk(*blkp+(int32_t)fragoff,
6057c478bd9Sstevel@tonic-gate 				    /* LINTED: bytecnt fits into 32 bits */
6067c478bd9Sstevel@tonic-gate 				    (size_t)bytecnt, byteoff);
6077c478bd9Sstevel@tonic-gate 			}
6087c478bd9Sstevel@tonic-gate 			blkp++;
6097c478bd9Sstevel@tonic-gate 			bytes -= bytecnt;
6107c478bd9Sstevel@tonic-gate 			/* LINTED: spurious complaint on sign-extending */
6117c478bd9Sstevel@tonic-gate 			j += d_howmany(bytecnt, (u_offset_t)tp_bsize);
6127c478bd9Sstevel@tonic-gate 			bytecnt = MIN(bytes, (unsigned)(sblock->fs_bsize));
6137c478bd9Sstevel@tonic-gate 			byteoff = 0;
6147c478bd9Sstevel@tonic-gate 			fragoff = 0;
6157c478bd9Sstevel@tonic-gate 		}
6167c478bd9Sstevel@tonic-gate 		spcl.c_type = TS_ADDR;
6177c478bd9Sstevel@tonic-gate 		bytecnt = 0;
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 	pos = 0;
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate void
bitmap(map,typ)6237c478bd9Sstevel@tonic-gate bitmap(map, typ)
6247c478bd9Sstevel@tonic-gate 	uchar_t *map;
6257c478bd9Sstevel@tonic-gate 	int typ;
6267c478bd9Sstevel@tonic-gate {
6277c478bd9Sstevel@tonic-gate 	int i;
6287c478bd9Sstevel@tonic-gate 	u_offset_t count;
6297c478bd9Sstevel@tonic-gate 	uchar_t *cp;
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (!newtape)
6327c478bd9Sstevel@tonic-gate 		spcl.c_type = typ;
6337c478bd9Sstevel@tonic-gate 	else
6347c478bd9Sstevel@tonic-gate 		newtape = 0;
6357c478bd9Sstevel@tonic-gate 	for (i = 0; i < TP_NINDIR; i++)
6367c478bd9Sstevel@tonic-gate 		spcl.c_addr[i] = 1;
6377c478bd9Sstevel@tonic-gate 	/* LINTED: spurious complaint on sign-extending */
6387c478bd9Sstevel@tonic-gate 	count = d_howmany(msiz * sizeof (map[0]), tp_bsize) - pos;
6397c478bd9Sstevel@tonic-gate 	for (cp = &map[pos * tp_bsize]; count > 0;
6407c478bd9Sstevel@tonic-gate 	    count -= (u_offset_t)(unsigned)spcl.c_count) {
6417c478bd9Sstevel@tonic-gate 		if (leftover) {
6427c478bd9Sstevel@tonic-gate 			spcl.c_count = leftover;
6437c478bd9Sstevel@tonic-gate 			leftover = 0;
6447c478bd9Sstevel@tonic-gate 		} else {
6457c478bd9Sstevel@tonic-gate 			/* LINTED value always less than INT32_MAX */
6467c478bd9Sstevel@tonic-gate 			spcl.c_count = count > TP_NINDIR ? TP_NINDIR : count;
6477c478bd9Sstevel@tonic-gate 		}
6487c478bd9Sstevel@tonic-gate 		spclrec();
6497c478bd9Sstevel@tonic-gate 		for (i = 0; i < spcl.c_count; i++, cp += tp_bsize)
6507c478bd9Sstevel@tonic-gate 			taprec(cp, 0, tp_bsize);
6517c478bd9Sstevel@tonic-gate 		spcl.c_type = TS_ADDR;
6527c478bd9Sstevel@tonic-gate 	}
6537c478bd9Sstevel@tonic-gate }
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate static void
dsrch(d,size,filesize)6567c478bd9Sstevel@tonic-gate dsrch(d, size, filesize)
6577c478bd9Sstevel@tonic-gate 	daddr32_t d;
6587c478bd9Sstevel@tonic-gate 	ulong_t size; 	/* block size */
6597c478bd9Sstevel@tonic-gate 	u_offset_t filesize;
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	struct direct *dp;
6627c478bd9Sstevel@tonic-gate 	struct dinode *ip;
6637c478bd9Sstevel@tonic-gate 	ulong_t loc;
6647c478bd9Sstevel@tonic-gate 	char dblk[MAXBSIZE];
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (dadded || filesize == 0)
6677c478bd9Sstevel@tonic-gate 		return;
6687c478bd9Sstevel@tonic-gate 	if (filesize > (u_offset_t)size)
6697c478bd9Sstevel@tonic-gate 		filesize = (u_offset_t)size;
6707c478bd9Sstevel@tonic-gate 	if (sizeof (dblk) < roundup(filesize, DEV_BSIZE)) {
6717c478bd9Sstevel@tonic-gate 		msg(gettext(
6727c478bd9Sstevel@tonic-gate "Inconsistency detected: filesystem block size larger than valid maximum.\n"));
6737c478bd9Sstevel@tonic-gate 		dumpabort();
6747c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate #ifdef	lint
6787c478bd9Sstevel@tonic-gate 	dblk[0] = '\0';
6797c478bd9Sstevel@tonic-gate #endif	/* lint */
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	/* LINTED ufs disk addresses always fit into 32 bits */
6827c478bd9Sstevel@tonic-gate 	bread(fsbtodb(sblock, d), (uchar_t *)dblk,
6837c478bd9Sstevel@tonic-gate 	    /* LINTED from sizeof check above, roundup() <= max(size_t) */
6847c478bd9Sstevel@tonic-gate 	    (size_t)(roundup(filesize, DEV_BSIZE)));
6857c478bd9Sstevel@tonic-gate 	loc = 0;
6867c478bd9Sstevel@tonic-gate 	while ((u_offset_t)loc < filesize) {
6877c478bd9Sstevel@tonic-gate 		/*LINTED [dblk is char[], loc (dp->d_reclen) % 4 == 0]*/
6887c478bd9Sstevel@tonic-gate 		dp = (struct direct *)(dblk + loc);
6897c478bd9Sstevel@tonic-gate 		if (dp->d_reclen == 0) {
6907c478bd9Sstevel@tonic-gate 			(void) snprintf(msgbuf, sizeof (msgbuf), gettext(
6917c478bd9Sstevel@tonic-gate 		    "Warning - directory at inode `%lu' is corrupted\n"),
6927c478bd9Sstevel@tonic-gate 				ino);
6937c478bd9Sstevel@tonic-gate 			msg(msgbuf);
6947c478bd9Sstevel@tonic-gate 			break;
6957c478bd9Sstevel@tonic-gate 		}
6967c478bd9Sstevel@tonic-gate 		loc += dp->d_reclen;
6977c478bd9Sstevel@tonic-gate 		if (dp->d_ino == 0)
6987c478bd9Sstevel@tonic-gate 			continue;
6997c478bd9Sstevel@tonic-gate 		if (dp->d_name[0] == '.') {
7007c478bd9Sstevel@tonic-gate 			if (dp->d_name[1] == '\0') {
7017c478bd9Sstevel@tonic-gate 				if ((ino_t)(dp->d_ino) != ino) {
7027c478bd9Sstevel@tonic-gate 					(void) snprintf(msgbuf, sizeof (msgbuf),
7037c478bd9Sstevel@tonic-gate 					    gettext(
7047c478bd9Sstevel@tonic-gate 			"Warning - directory at inode `%lu' is corrupted:\n\
7057c478bd9Sstevel@tonic-gate \t\".\" points to inode `%lu' - run fsck\n"),
7067c478bd9Sstevel@tonic-gate 					    ino, dp->d_ino);
7077c478bd9Sstevel@tonic-gate 					msg(msgbuf);
7087c478bd9Sstevel@tonic-gate 				}
7097c478bd9Sstevel@tonic-gate 				continue;
7107c478bd9Sstevel@tonic-gate 			}
7117c478bd9Sstevel@tonic-gate 			if (dp->d_name[1] == '.' && dp->d_name[2] == '\0') {
7127c478bd9Sstevel@tonic-gate 				if (!BIT(dp->d_ino, dirmap) &&
7137c478bd9Sstevel@tonic-gate 				    ((ip = getino(ino)) == NULL ||
7147c478bd9Sstevel@tonic-gate 				    (ip->di_mode & IFMT) != IFATTRDIR)) {
7157c478bd9Sstevel@tonic-gate 					(void) snprintf(msgbuf, sizeof (msgbuf),
7167c478bd9Sstevel@tonic-gate 					    gettext(
7177c478bd9Sstevel@tonic-gate 			"Warning - directory at inode `%lu' is corrupted:\n\
7187c478bd9Sstevel@tonic-gate \t\"..\" points to non-directory inode `%lu' - run fsck\n"),
7197c478bd9Sstevel@tonic-gate 					    ino, dp->d_ino);
7207c478bd9Sstevel@tonic-gate 					msg(msgbuf);
7217c478bd9Sstevel@tonic-gate 				}
7227c478bd9Sstevel@tonic-gate 				continue;
7237c478bd9Sstevel@tonic-gate 			}
7247c478bd9Sstevel@tonic-gate 		}
7257c478bd9Sstevel@tonic-gate 		if (BIT(dp->d_ino, nodmap)) {
7267c478bd9Sstevel@tonic-gate 			dadded++;
7277c478bd9Sstevel@tonic-gate 			return;
7287c478bd9Sstevel@tonic-gate 		}
7297c478bd9Sstevel@tonic-gate 		if (BIT(dp->d_ino, dirmap))
7307c478bd9Sstevel@tonic-gate 			nsubdir++;
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate #define	CACHESIZE 32
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate struct dinode *
getino(ino)7377c478bd9Sstevel@tonic-gate getino(ino)
7387c478bd9Sstevel@tonic-gate 	ino_t ino;
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate 	static ino_t minino, maxino;
7417c478bd9Sstevel@tonic-gate 	static struct dinode itab[MAXINOPB];
7427c478bd9Sstevel@tonic-gate 	static struct dinode icache[CACHESIZE];
7437c478bd9Sstevel@tonic-gate 	static ino_t icacheval[CACHESIZE], lasti = 0;
7447c478bd9Sstevel@tonic-gate 	static int cacheoff = 0;
7457c478bd9Sstevel@tonic-gate 	int i;
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	if (ino >= minino && ino < maxino) {
7487c478bd9Sstevel@tonic-gate 		lasti = ino;
7497c478bd9Sstevel@tonic-gate 		return (&itab[ino - minino]);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/* before we do major i/o, check for a secondary cache hit */
7537c478bd9Sstevel@tonic-gate 	for (i = 0; i < CACHESIZE; i++)
7547c478bd9Sstevel@tonic-gate 		if (icacheval[i] == ino)
7557c478bd9Sstevel@tonic-gate 			return (icache + i);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	/* we need to do major i/o.  throw the last inode retrieved into */
7587c478bd9Sstevel@tonic-gate 	/* the cache.  note: this copies garbage the first time it is    */
7597c478bd9Sstevel@tonic-gate 	/* used, but no harm done.					 */
7607c478bd9Sstevel@tonic-gate 	icacheval[cacheoff] = lasti;
7617c478bd9Sstevel@tonic-gate 	bcopy(itab + (lasti - minino), icache + cacheoff, sizeof (itab[0]));
7627c478bd9Sstevel@tonic-gate 	lasti = ino;
7637c478bd9Sstevel@tonic-gate 	if (++cacheoff >= CACHESIZE)
7647c478bd9Sstevel@tonic-gate 		cacheoff = 0;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate #define	INOPERDB (DEV_BSIZE / sizeof (struct dinode))
7677c478bd9Sstevel@tonic-gate 	minino = ino &~ (INOPERDB - 1);
7687c478bd9Sstevel@tonic-gate 	maxino = ((itog(sblock, ino) + 1) * (unsigned)(sblock->fs_ipg));
7697c478bd9Sstevel@tonic-gate 	if (maxino > minino + MAXINOPB)
7707c478bd9Sstevel@tonic-gate 		maxino = minino + MAXINOPB;
7717c478bd9Sstevel@tonic-gate 	bread(
7727c478bd9Sstevel@tonic-gate 	    /* LINTED: can't make up for broken system macros here */
7737c478bd9Sstevel@tonic-gate 	    (fsbtodb(sblock, itod(sblock, ino)) + itoo(sblock, ino) / INOPERDB),
7747c478bd9Sstevel@tonic-gate 	    /* LINTED: (max - min) * size fits into a size_t */
7757c478bd9Sstevel@tonic-gate 	    (uchar_t *)itab, (size_t)((maxino - minino) * sizeof (*itab)));
7767c478bd9Sstevel@tonic-gate 	return (&itab[ino - minino]);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate #define	BREADEMAX 32
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate #ifdef NO__LONGLONG__
7827c478bd9Sstevel@tonic-gate #define	DEV_LSEEK(fd, offset, whence) \
7837c478bd9Sstevel@tonic-gate 	lseek((fd), (((off_t)(offset))*DEV_BSIZE), (whence))
7847c478bd9Sstevel@tonic-gate #else
7857c478bd9Sstevel@tonic-gate #define	DEV_LSEEK(fd, offset, whence) \
786*90eb94cfSns158690 	llseek((fd), (((offset_t)((offset)))*DEV_BSIZE), (whence))
7877c478bd9Sstevel@tonic-gate #endif
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate #define	BREAD_FAIL(buf, size)	{ \
7907c478bd9Sstevel@tonic-gate 		breaderrors += 1; \
7917c478bd9Sstevel@tonic-gate 		bzero(buf, (size_t)size); \
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate void
bread(da,ba,cnt)7977c478bd9Sstevel@tonic-gate bread(da, ba, cnt)
7987c478bd9Sstevel@tonic-gate diskaddr_t da;
7997c478bd9Sstevel@tonic-gate uchar_t	*ba;
8007c478bd9Sstevel@tonic-gate size_t	cnt;
8017c478bd9Sstevel@tonic-gate {
8027c478bd9Sstevel@tonic-gate 	caddr_t maddr;
8037c478bd9Sstevel@tonic-gate 	uchar_t *dest;
8047c478bd9Sstevel@tonic-gate 	int saverr;
8057c478bd9Sstevel@tonic-gate 	int n;
8067c478bd9Sstevel@tonic-gate 	size_t len;
8077c478bd9Sstevel@tonic-gate 	off64_t filoff;
8087c478bd9Sstevel@tonic-gate 	off64_t mapoff;
8097c478bd9Sstevel@tonic-gate 	off64_t displacement;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	static size_t pagesize = 0;
8127c478bd9Sstevel@tonic-gate 	static int breaderrors = 0;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	/* mechanics for caching small bread requests.  these are */
8157c478bd9Sstevel@tonic-gate 	/* often small ACLs that are used over and over.	  */
8167c478bd9Sstevel@tonic-gate 	static uchar_t bcache[DEV_BSIZE * CACHESIZE];
8177c478bd9Sstevel@tonic-gate 	static diskaddr_t bcacheval[CACHESIZE];
8187c478bd9Sstevel@tonic-gate 	static int cacheoff = 0;
8197c478bd9Sstevel@tonic-gate 	int i;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	if ((cnt >= DEV_BSIZE) && (mapfd != -1)) {
8227c478bd9Sstevel@tonic-gate 		if (pagesize == 0)
8237c478bd9Sstevel@tonic-gate 			pagesize = getpagesize();
8247c478bd9Sstevel@tonic-gate 		/*
8257c478bd9Sstevel@tonic-gate 		 * We depend on mmap(2)'s guarantee that mapping a
8267c478bd9Sstevel@tonic-gate 		 * partial page will cause the remainder of the page
8277c478bd9Sstevel@tonic-gate 		 * to be zero-filled.
8287c478bd9Sstevel@tonic-gate 		 */
8297c478bd9Sstevel@tonic-gate 		filoff = ((off64_t)da) * DEV_BSIZE;
8307c478bd9Sstevel@tonic-gate 		displacement = filoff & (pagesize - 1);
8317c478bd9Sstevel@tonic-gate 		mapoff = filoff - displacement;
8327c478bd9Sstevel@tonic-gate 		/* LINTED offset will fit into 32 bits */
8337c478bd9Sstevel@tonic-gate 		len = (size_t)roundup(cnt + (filoff - mapoff), pagesize);
8347c478bd9Sstevel@tonic-gate 		maddr = mmap64(NULL, len, PROT_READ, MAP_SHARED, mapfd, mapoff);
8357c478bd9Sstevel@tonic-gate 		if (maddr != MAP_FAILED) {
8367c478bd9Sstevel@tonic-gate 			(void) memcpy(ba, maddr + displacement, cnt);
8377c478bd9Sstevel@tonic-gate 			(void) munmap(maddr, len);
8387c478bd9Sstevel@tonic-gate 			return;
8397c478bd9Sstevel@tonic-gate 		}
8407c478bd9Sstevel@tonic-gate 	}
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	if (DEV_LSEEK(fi, da, L_SET) < 0) {
8437c478bd9Sstevel@tonic-gate 		saverr = errno;
8447c478bd9Sstevel@tonic-gate 		msg(gettext("bread: dev_seek error: %s\n"), strerror(saverr));
8457c478bd9Sstevel@tonic-gate 		/* Don't know where we are, return the least-harmful data */
8467c478bd9Sstevel@tonic-gate 		BREAD_FAIL(ba, cnt);
8477c478bd9Sstevel@tonic-gate 		return;
8487c478bd9Sstevel@tonic-gate 	}
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate 	if (read(fi, ba, (size_t)cnt) == (size_t)cnt)
8517c478bd9Sstevel@tonic-gate 	    return;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	while (cnt != 0) {
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 		if (da >= fsbtodb(sblock, sblock->fs_size)) {
8567c478bd9Sstevel@tonic-gate 			msg(gettext(
8577c478bd9Sstevel@tonic-gate 			    "Warning - block %llu is beyond the end of `%s'\n"),
8587c478bd9Sstevel@tonic-gate 			    da, disk);
8597c478bd9Sstevel@tonic-gate 			BREAD_FAIL(ba, cnt);
8607c478bd9Sstevel@tonic-gate 			break;
8617c478bd9Sstevel@tonic-gate 		}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 		if (DEV_LSEEK(fi, da, L_SET) < 0) {
8647c478bd9Sstevel@tonic-gate 			msg(gettext("%s: %s error\n"), "bread", "DEV_LSEEK2");
8657c478bd9Sstevel@tonic-gate 			BREAD_FAIL(ba, cnt);
8667c478bd9Sstevel@tonic-gate 			break;
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 		if (cnt < DEV_BSIZE) {
8707c478bd9Sstevel@tonic-gate 			/* small read.  check for cache hit. */
8717c478bd9Sstevel@tonic-gate 			for (i = 0; i < CACHESIZE; i++)
8727c478bd9Sstevel@tonic-gate 				if (bcacheval[i] == da) {
8737c478bd9Sstevel@tonic-gate 					bcopy(bcache + (i * DEV_BSIZE),
8747c478bd9Sstevel@tonic-gate 					    ba, cnt);
8757c478bd9Sstevel@tonic-gate 					return;
8767c478bd9Sstevel@tonic-gate 				}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 			/* no cache hit; throw this one into the cache... */
8797c478bd9Sstevel@tonic-gate 			len = cnt;
8807c478bd9Sstevel@tonic-gate 			dest = bcache + (cacheoff * DEV_BSIZE);
8817c478bd9Sstevel@tonic-gate 			bcacheval[cacheoff] = da;
8827c478bd9Sstevel@tonic-gate 			if (++cacheoff >= CACHESIZE)
8837c478bd9Sstevel@tonic-gate 				cacheoff = 0;
8847c478bd9Sstevel@tonic-gate 		} else {
8857c478bd9Sstevel@tonic-gate 			len = DEV_BSIZE;
8867c478bd9Sstevel@tonic-gate 			dest = ba;
8877c478bd9Sstevel@tonic-gate 		}
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 		n = read(fi, dest, DEV_BSIZE);
8907c478bd9Sstevel@tonic-gate 		if (n != DEV_BSIZE) {
8917c478bd9Sstevel@tonic-gate 			n = MAX(n, 0);
8927c478bd9Sstevel@tonic-gate 			bzero(dest+n, DEV_BSIZE-n);
8937c478bd9Sstevel@tonic-gate 			breaderrors += 1;
8947c478bd9Sstevel@tonic-gate 			msg(gettext(
8957c478bd9Sstevel@tonic-gate 			    "Warning - cannot read sector %llu of `%s'\n"),
8967c478bd9Sstevel@tonic-gate 			    da, disk);
8977c478bd9Sstevel@tonic-gate 		}
8987c478bd9Sstevel@tonic-gate 		if (dest != ba)
8997c478bd9Sstevel@tonic-gate 			bcopy(dest, ba, len);
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 		da++;
9027c478bd9Sstevel@tonic-gate 		/* LINTED character pointers aren't signed */
9037c478bd9Sstevel@tonic-gate 		ba += len;
9047c478bd9Sstevel@tonic-gate 		cnt -= len;
9057c478bd9Sstevel@tonic-gate 	}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	if (breaderrors > BREADEMAX) {
9087c478bd9Sstevel@tonic-gate 		msg(gettext(
9097c478bd9Sstevel@tonic-gate 		    "More than %d block read errors from dump device `%s'\n"),
9107c478bd9Sstevel@tonic-gate 		    BREADEMAX, disk);
9117c478bd9Sstevel@tonic-gate 		dumpailing();
9127c478bd9Sstevel@tonic-gate 		breaderrors = 0;
9137c478bd9Sstevel@tonic-gate 	}
9147c478bd9Sstevel@tonic-gate }
915