xref: /csrg-svn/sbin/dump/traverse.c (revision 46584)
122041Sdist /*
234359Skarels  * Copyright (c) 1980, 1988 Regents of the University of California.
322041Sdist  * All rights reserved.  The Berkeley software License Agreement
422041Sdist  * specifies the terms and conditions for redistribution.
522041Sdist  */
65329Smckusic 
722041Sdist #ifndef lint
8*46584Storek static char sccsid[] = "@(#)traverse.c	5.6 (Berkeley) 02/23/91";
9*46584Storek #endif /* not lint */
1022041Sdist 
111426Sroot #include "dump.h"
121426Sroot 
13*46584Storek void	indir(), dmpindir(), dsrch();
14*46584Storek 
15*46584Storek /*
16*46584Storek  * This is an estimation of the number of TP_BSIZE blocks in the file.
17*46584Storek  * It estimates the number of blocks in files with holes by assuming
18*46584Storek  * that all of the blocks accounted for by di_blocks are data blocks
19*46584Storek  * (when some of the blocks are usually used for indirect pointers);
20*46584Storek  * hence the estimate may be high.
21*46584Storek  */
22*46584Storek void
23*46584Storek est(ip)
24*46584Storek 	struct dinode *ip;
25*46584Storek {
26*46584Storek 	long s, t;
27*46584Storek 
28*46584Storek 	/*
29*46584Storek 	 * ip->di_size is the size of the file in bytes.
30*46584Storek 	 * ip->di_blocks stores the number of sectors actually in the file.
31*46584Storek 	 * If there are more sectors than the size would indicate, this just
32*46584Storek 	 *	means that there are indirect blocks in the file or unused
33*46584Storek 	 *	sectors in the last file block; we can safely ignore these
34*46584Storek 	 *	(s = t below).
35*46584Storek 	 * If the file is bigger than the number of sectors would indicate,
36*46584Storek 	 *	then the file has holes in it.	In this case we must use the
37*46584Storek 	 *	block count to estimate the number of data blocks used, but
38*46584Storek 	 *	we use the actual size for estimating the number of indirect
39*46584Storek 	 *	dump blocks (t vs. s in the indirect block calculation).
40*46584Storek 	 */
41*46584Storek 	esize++;
42*46584Storek 	s = howmany(dbtob(ip->di_blocks), TP_BSIZE);
43*46584Storek 	t = howmany(ip->di_size, TP_BSIZE);
44*46584Storek 	if (s > t)
45*46584Storek 		s = t;
46*46584Storek 	if (ip->di_size > sblock->fs_bsize * NDADDR) {
47*46584Storek 		/* calculate the number of indirect blocks on the dump tape */
48*46584Storek 		s += howmany(t - NDADDR * sblock->fs_bsize / TP_BSIZE,
49*46584Storek 			TP_NINDIR);
50*46584Storek 	}
51*46584Storek 	esize += s;
52*46584Storek }
53*46584Storek 
54*46584Storek void
55*46584Storek bmapest(map)
56*46584Storek 	char *map;
57*46584Storek {
58*46584Storek 
59*46584Storek 	esize += howmany(msiz * sizeof map[0], TP_BSIZE) + 1;
60*46584Storek }
61*46584Storek 
62*46584Storek void
631426Sroot pass(fn, map)
6425797Smckusick 	register int (*fn)();
6525797Smckusick 	register char *map;
661426Sroot {
67*46584Storek 	register int bits = 0;	/* this value not used, but keeps gcc happy */
684702Smckusic 	ino_t maxino;
691426Sroot 
705329Smckusic 	maxino = sblock->fs_ipg * sblock->fs_ncg - 1;
714702Smckusic 	for (ino = 0; ino < maxino; ) {
72*46584Storek 		if ((ino % NBBY) == 0)
73*46584Storek 			bits = map ? *map++ : ~0;
744702Smckusic 		ino++;
7525797Smckusick 		if (bits & 1)
7625797Smckusick 			(*fn)(getino(ino));
774702Smckusic 		bits >>= 1;
781426Sroot 	}
791426Sroot }
801426Sroot 
81*46584Storek void
821426Sroot mark(ip)
834777Smckusic 	struct dinode *ip;
841426Sroot {
8525797Smckusick 	register int f;
8625797Smckusick 	extern int anydskipped;
871426Sroot 
881426Sroot 	f = ip->di_mode & IFMT;
8925797Smckusick 	if (f == 0)
901426Sroot 		return;
911426Sroot 	BIS(ino, clrmap);
9225797Smckusick 	if (f == IFDIR)
931426Sroot 		BIS(ino, dirmap);
945329Smckusic 	if ((ip->di_mtime >= spcl.c_ddate || ip->di_ctime >= spcl.c_ddate) &&
955329Smckusic 	    !BIT(ino, nodmap)) {
961426Sroot 		BIS(ino, nodmap);
976288Smckusick 		if (f != IFREG && f != IFDIR && f != IFLNK) {
981426Sroot 			esize += 1;
991426Sroot 			return;
1001426Sroot 		}
1011426Sroot 		est(ip);
10225797Smckusick 	} else if (f == IFDIR)
10325797Smckusick 		anydskipped = 1;
1041426Sroot }
1051426Sroot 
106*46584Storek void
1071426Sroot add(ip)
1085329Smckusic 	register struct	dinode	*ip;
1091426Sroot {
1105329Smckusic 	register int i;
11114928Smckusick 	long filesize;
1121426Sroot 
1131426Sroot 	if(BIT(ino, nodmap))
1141426Sroot 		return;
1151426Sroot 	nsubdir = 0;
1161426Sroot 	dadded = 0;
11714928Smckusick 	filesize = ip->di_size;
1185329Smckusic 	for (i = 0; i < NDADDR; i++) {
1195329Smckusic 		if (ip->di_db[i] != 0)
12014928Smckusick 			dsrch(ip->di_db[i], dblksize(sblock, ip, i), filesize);
12114928Smckusick 		filesize -= sblock->fs_bsize;
1225329Smckusic 	}
1235329Smckusic 	for (i = 0; i < NIADDR; i++) {
1245329Smckusic 		if (ip->di_ib[i] != 0)
12514928Smckusick 			indir(ip->di_ib[i], i, &filesize);
1265329Smckusic 	}
1271426Sroot 	if(dadded) {
1281426Sroot 		nadded++;
1295329Smckusic 		if (!BIT(ino, nodmap)) {
1305329Smckusic 			BIS(ino, nodmap);
1315329Smckusic 			est(ip);
1325329Smckusic 		}
1331426Sroot 	}
1341426Sroot 	if(nsubdir == 0)
1351426Sroot 		if(!BIT(ino, nodmap))
1361426Sroot 			BIC(ino, dirmap);
1371426Sroot }
1381426Sroot 
139*46584Storek void
14014928Smckusick indir(d, n, filesize)
1415329Smckusic 	daddr_t d;
14214928Smckusick 	int n, *filesize;
1435329Smckusic {
1445329Smckusic 	register i;
1455329Smckusic 	daddr_t	idblk[MAXNINDIR];
1465329Smckusic 
1475329Smckusic 	bread(fsbtodb(sblock, d), (char *)idblk, sblock->fs_bsize);
1485329Smckusic 	if(n <= 0) {
1495329Smckusic 		for(i=0; i < NINDIR(sblock); i++) {
1505329Smckusic 			d = idblk[i];
1515329Smckusic 			if(d != 0)
15214928Smckusick 				dsrch(d, sblock->fs_bsize, *filesize);
15314928Smckusick 			*filesize -= sblock->fs_bsize;
1545329Smckusic 		}
1555329Smckusic 	} else {
1565329Smckusic 		n--;
1575329Smckusic 		for(i=0; i < NINDIR(sblock); i++) {
1585329Smckusic 			d = idblk[i];
1595329Smckusic 			if(d != 0)
16014928Smckusick 				indir(d, n, filesize);
1615329Smckusic 		}
1625329Smckusic 	}
1635329Smckusic }
1645329Smckusic 
165*46584Storek void
16617234Smckusick dirdump(ip)
16717234Smckusick 	struct dinode *ip;
16817234Smckusick {
16917234Smckusick 	/* watchout for dir inodes deleted and maybe reallocated */
17017234Smckusick 	if ((ip->di_mode & IFMT) != IFDIR)
17117234Smckusick 		return;
17217234Smckusick 	dump(ip);
17317234Smckusick }
17417234Smckusick 
175*46584Storek void
1761426Sroot dump(ip)
1774777Smckusic 	struct dinode *ip;
1781426Sroot {
1794777Smckusic 	register int i;
1804777Smckusic 	long size;
1811426Sroot 
1821426Sroot 	if(newtape) {
1831426Sroot 		newtape = 0;
1841426Sroot 		bitmap(nodmap, TS_BITS);
1851426Sroot 	}
1861426Sroot 	BIC(ino, nodmap);
1871426Sroot 	spcl.c_dinode = *ip;
1881426Sroot 	spcl.c_type = TS_INODE;
1891426Sroot 	spcl.c_count = 0;
1901426Sroot 	i = ip->di_mode & IFMT;
19117234Smckusick 	if (i == 0) /* free inode */
19217234Smckusick 		return;
1936288Smckusick 	if ((i != IFDIR && i != IFREG && i != IFLNK) || ip->di_size == 0) {
1941426Sroot 		spclrec();
1951426Sroot 		return;
1961426Sroot 	}
1975329Smckusic 	if (ip->di_size > NDADDR * sblock->fs_bsize)
1985329Smckusic 		i = NDADDR * sblock->fs_frag;
1994777Smckusic 	else
2005329Smckusic 		i = howmany(ip->di_size, sblock->fs_fsize);
2014777Smckusic 	blksout(&ip->di_db[0], i);
2025329Smckusic 	size = ip->di_size - NDADDR * sblock->fs_bsize;
2034777Smckusic 	if (size <= 0)
2044777Smckusic 		return;
2054777Smckusic 	for (i = 0; i < NIADDR; i++) {
2064777Smckusic 		dmpindir(ip->di_ib[i], i, &size);
2074777Smckusic 		if (size <= 0)
2084777Smckusic 			return;
2094777Smckusic 	}
2101426Sroot }
2111426Sroot 
212*46584Storek void
2134777Smckusic dmpindir(blk, lvl, size)
2144777Smckusic 	daddr_t blk;
2154777Smckusic 	int lvl;
2164777Smckusic 	long *size;
2171426Sroot {
2184777Smckusic 	int i, cnt;
2195329Smckusic 	daddr_t idblk[MAXNINDIR];
2201426Sroot 
2214777Smckusic 	if (blk != 0)
2225329Smckusic 		bread(fsbtodb(sblock, blk), (char *)idblk, sblock->fs_bsize);
2234777Smckusic 	else
224*46584Storek 		bzero((char *)idblk, sblock->fs_bsize);
2254777Smckusic 	if (lvl <= 0) {
2265329Smckusic 		if (*size < NINDIR(sblock) * sblock->fs_bsize)
2275329Smckusic 			cnt = howmany(*size, sblock->fs_fsize);
2284777Smckusic 		else
2295329Smckusic 			cnt = NINDIR(sblock) * sblock->fs_frag;
2305329Smckusic 		*size -= NINDIR(sblock) * sblock->fs_bsize;
2314777Smckusic 		blksout(&idblk[0], cnt);
2324777Smckusic 		return;
2331426Sroot 	}
2344777Smckusic 	lvl--;
2355329Smckusic 	for (i = 0; i < NINDIR(sblock); i++) {
2364777Smckusic 		dmpindir(idblk[i], lvl, size);
2374777Smckusic 		if (*size <= 0)
2384777Smckusic 			return;
2394777Smckusic 	}
2401426Sroot }
2411426Sroot 
242*46584Storek void
2434777Smckusic blksout(blkp, frags)
2444777Smckusic 	daddr_t *blkp;
2454777Smckusic 	int frags;
2464777Smckusic {
247*46584Storek 	register daddr_t *bp;
2485329Smckusic 	int i, j, count, blks, tbperdb;
2494777Smckusic 
2509403Smckusick 	blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
251*46584Storek 	tbperdb = sblock->fs_bsize >> tp_bshift;
2524777Smckusic 	for (i = 0; i < blks; i += TP_NINDIR) {
2534777Smckusic 		if (i + TP_NINDIR > blks)
2544777Smckusic 			count = blks;
2554777Smckusic 		else
2564777Smckusic 			count = i + TP_NINDIR;
2574777Smckusic 		for (j = i; j < count; j++)
2585329Smckusic 			if (blkp[j / tbperdb] != 0)
2594777Smckusic 				spcl.c_addr[j - i] = 1;
2604777Smckusic 			else
2614777Smckusic 				spcl.c_addr[j - i] = 0;
2624777Smckusic 		spcl.c_count = count - i;
2634777Smckusic 		spclrec();
264*46584Storek 		bp = &blkp[i / tbperdb];
265*46584Storek 		for (j = i; j < count; j += tbperdb, bp++)
266*46584Storek 			if (*bp != 0)
2675329Smckusic 				if (j + tbperdb <= count)
268*46584Storek 					dmpblk(*bp, sblock->fs_bsize);
2694777Smckusic 				else
270*46584Storek 					dmpblk(*bp, (count - j) * TP_BSIZE);
2714777Smckusic 		spcl.c_type = TS_ADDR;
2724777Smckusic 	}
2734777Smckusic }
2744777Smckusic 
275*46584Storek void
2761426Sroot bitmap(map, typ)
2775329Smckusic 	char *map;
278*46584Storek 	int typ;
2791426Sroot {
28016134Smckusick 	register i;
2811426Sroot 	char *cp;
2821426Sroot 
2831426Sroot 	spcl.c_type = typ;
28416134Smckusick 	spcl.c_count = howmany(msiz * sizeof(map[0]), TP_BSIZE);
2851426Sroot 	spclrec();
2865329Smckusic 	for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
2871426Sroot 		taprec(cp);
2881426Sroot }
2891426Sroot 
290*46584Storek void
2911426Sroot spclrec()
2921426Sroot {
2934777Smckusic 	register int s, i, *ip;
2941426Sroot 
2951426Sroot 	spcl.c_inumber = ino;
2968368Smckusick 	spcl.c_magic = NFS_MAGIC;
2971426Sroot 	spcl.c_checksum = 0;
2981426Sroot 	ip = (int *)&spcl;
2991426Sroot 	s = 0;
30024168Smckusick 	i = sizeof(union u_spcl) / (4*sizeof(int));
30124168Smckusick 	while (--i >= 0) {
30224168Smckusick 		s += *ip++; s += *ip++;
30324168Smckusick 		s += *ip++; s += *ip++;
30424168Smckusick 	}
3051426Sroot 	spcl.c_checksum = CHECKSUM - s;
3061426Sroot 	taprec((char *)&spcl);
3071426Sroot }
3081426Sroot 
309*46584Storek void
31014928Smckusick dsrch(d, size, filesize)
3114777Smckusic 	daddr_t d;
31214928Smckusick 	int size, filesize;
3131426Sroot {
3145942Smckusic 	register struct direct *dp;
3155942Smckusic 	long loc;
3165942Smckusic 	char dblk[MAXBSIZE];
3171426Sroot 
3181426Sroot 	if(dadded)
3191426Sroot 		return;
32014928Smckusick 	if (filesize > size)
32114928Smckusick 		filesize = size;
32215095Smckusick 	bread(fsbtodb(sblock, d), dblk, filesize);
32314928Smckusick 	for (loc = 0; loc < filesize; ) {
3245942Smckusic 		dp = (struct direct *)(dblk + loc);
32514928Smckusick 		if (dp->d_reclen == 0) {
32614928Smckusick 			msg("corrupted directory, inumber %d\n", ino);
3275942Smckusic 			break;
32814928Smckusick 		}
3295942Smckusic 		loc += dp->d_reclen;
3305942Smckusic 		if(dp->d_ino == 0)
3311426Sroot 			continue;
3325942Smckusic 		if(dp->d_name[0] == '.') {
3335942Smckusic 			if(dp->d_name[1] == '\0')
3341426Sroot 				continue;
3355942Smckusic 			if(dp->d_name[1] == '.' && dp->d_name[2] == '\0')
3361426Sroot 				continue;
3371426Sroot 		}
3385942Smckusic 		if(BIT(dp->d_ino, nodmap)) {
3391426Sroot 			dadded++;
3401426Sroot 			return;
3411426Sroot 		}
3425942Smckusic 		if(BIT(dp->d_ino, dirmap))
3431426Sroot 			nsubdir++;
3441426Sroot 	}
3451426Sroot }
3461426Sroot 
3474702Smckusic struct dinode *
3484702Smckusic getino(ino)
3494702Smckusic 	daddr_t ino;
3504702Smckusic {
3514702Smckusic 	static daddr_t minino, maxino;
3525329Smckusic 	static struct dinode itab[MAXINOPB];
3534702Smckusic 
354*46584Storek 	if (ino >= minino && ino < maxino)
3554702Smckusic 		return (&itab[ino - minino]);
3565386Smckusic 	bread(fsbtodb(sblock, itod(sblock, ino)), itab, sblock->fs_bsize);
3575329Smckusic 	minino = ino - (ino % INOPB(sblock));
3585329Smckusic 	maxino = minino + INOPB(sblock);
3594702Smckusic 	return (&itab[ino - minino]);
3604702Smckusic }
3614702Smckusic 
3621426Sroot int	breaderrors = 0;
3631426Sroot #define	BREADEMAX 32
3641426Sroot 
365*46584Storek void
36615095Smckusick bread(da, ba, cnt)
3671426Sroot 	daddr_t da;
3681426Sroot 	char *ba;
36915095Smckusick 	int	cnt;
3701426Sroot {
37134359Skarels 	int n, i;
37234359Skarels 	extern int errno;
3731426Sroot 
37415095Smckusick loop:
375*46584Storek 	if (lseek(fi, (long)(da << dev_bshift), 0) < 0)
3761426Sroot 		msg("bread: lseek fails\n");
37715095Smckusick 	n = read(fi, ba, cnt);
37815095Smckusick 	if (n == cnt)
37915095Smckusick 		return;
38030560Smckusick 	if (da + (cnt / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
38115095Smckusick 		/*
38215095Smckusick 		 * Trying to read the final fragment.
38315095Smckusick 		 *
38415095Smckusick 		 * NB - dump only works in TP_BSIZE blocks, hence
38530560Smckusick 		 * rounds `dev_bsize' fragments up to TP_BSIZE pieces.
38615095Smckusick 		 * It should be smarter about not actually trying to
38715095Smckusick 		 * read more than it can get, but for the time being
38815095Smckusick 		 * we punt and scale back the read only when it gets
38915095Smckusick 		 * us into trouble. (mkm 9/25/83)
39015095Smckusick 		 */
39130560Smckusick 		cnt -= dev_bsize;
39215095Smckusick 		goto loop;
3931426Sroot 	}
394*46584Storek 	msg("read error from %s [block %d]: count=%d, got=%d, errno=%d (%s)\n",
395*46584Storek 		disk, da, cnt, n, errno, strerror(errno));
396*46584Storek 	if (++breaderrors > BREADEMAX) {
39715095Smckusick 		msg("More than %d block read errors from %d\n",
39815095Smckusick 			BREADEMAX, disk);
39915095Smckusick 		broadcast("DUMP IS AILING!\n");
40015095Smckusick 		msg("This is an unrecoverable error.\n");
40115095Smckusick 		if (!query("Do you want to attempt to continue?")){
40215095Smckusick 			dumpabort();
40315095Smckusick 			/*NOTREACHED*/
40415095Smckusick 		} else
40515095Smckusick 			breaderrors = 0;
40615095Smckusick 	}
40734359Skarels 	/*
40834359Skarels 	 * Zero buffer, then try to read each sector of buffer separately.
40934359Skarels 	 */
41034359Skarels 	bzero(ba, cnt);
41134359Skarels 	for (i = 0; i < cnt; i += dev_bsize, ba += dev_bsize, da++) {
412*46584Storek 		if (lseek(fi, (long)(da << dev_bshift), 0) < 0)
41334359Skarels 			msg("bread: lseek2 fails!\n");
41434359Skarels 		n = read(fi, ba, dev_bsize);
41534359Skarels 		if (n != dev_bsize)
41634359Skarels 			msg("    read error from %s [sector %d, errno %d]\n",
41734359Skarels 			    disk, da, errno);
41834359Skarels 	}
4191426Sroot }
420