xref: /original-bsd/sbin/dump/traverse.c (revision 5d3a6356)
1 /*
2  * Copyright (c) 1980, 1988 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)traverse.c	5.5 (Berkeley) 05/20/88";
9 #endif not lint
10 
11 #include "dump.h"
12 
13 pass(fn, map)
14 	register int (*fn)();
15 	register char *map;
16 {
17 	register int bits;
18 	ino_t maxino;
19 
20 	maxino = sblock->fs_ipg * sblock->fs_ncg - 1;
21 	for (ino = 0; ino < maxino; ) {
22 		if ((ino % NBBY) == 0) {
23 			bits = ~0;
24 			if (map != NULL)
25 				bits = *map++;
26 		}
27 		ino++;
28 		if (bits & 1)
29 			(*fn)(getino(ino));
30 		bits >>= 1;
31 	}
32 }
33 
34 mark(ip)
35 	struct dinode *ip;
36 {
37 	register int f;
38 	extern int anydskipped;
39 
40 	f = ip->di_mode & IFMT;
41 	if (f == 0)
42 		return;
43 	BIS(ino, clrmap);
44 	if (f == IFDIR)
45 		BIS(ino, dirmap);
46 	if ((ip->di_mtime >= spcl.c_ddate || ip->di_ctime >= spcl.c_ddate) &&
47 	    !BIT(ino, nodmap)) {
48 		BIS(ino, nodmap);
49 		if (f != IFREG && f != IFDIR && f != IFLNK) {
50 			esize += 1;
51 			return;
52 		}
53 		est(ip);
54 	} else if (f == IFDIR)
55 		anydskipped = 1;
56 }
57 
58 add(ip)
59 	register struct	dinode	*ip;
60 {
61 	register int i;
62 	long filesize;
63 
64 	if(BIT(ino, nodmap))
65 		return;
66 	nsubdir = 0;
67 	dadded = 0;
68 	filesize = ip->di_size;
69 	for (i = 0; i < NDADDR; i++) {
70 		if (ip->di_db[i] != 0)
71 			dsrch(ip->di_db[i], dblksize(sblock, ip, i), filesize);
72 		filesize -= sblock->fs_bsize;
73 	}
74 	for (i = 0; i < NIADDR; i++) {
75 		if (ip->di_ib[i] != 0)
76 			indir(ip->di_ib[i], i, &filesize);
77 	}
78 	if(dadded) {
79 		nadded++;
80 		if (!BIT(ino, nodmap)) {
81 			BIS(ino, nodmap);
82 			est(ip);
83 		}
84 	}
85 	if(nsubdir == 0)
86 		if(!BIT(ino, nodmap))
87 			BIC(ino, dirmap);
88 }
89 
90 indir(d, n, filesize)
91 	daddr_t d;
92 	int n, *filesize;
93 {
94 	register i;
95 	daddr_t	idblk[MAXNINDIR];
96 
97 	bread(fsbtodb(sblock, d), (char *)idblk, sblock->fs_bsize);
98 	if(n <= 0) {
99 		for(i=0; i < NINDIR(sblock); i++) {
100 			d = idblk[i];
101 			if(d != 0)
102 				dsrch(d, sblock->fs_bsize, *filesize);
103 			*filesize -= sblock->fs_bsize;
104 		}
105 	} else {
106 		n--;
107 		for(i=0; i < NINDIR(sblock); i++) {
108 			d = idblk[i];
109 			if(d != 0)
110 				indir(d, n, filesize);
111 		}
112 	}
113 }
114 
115 dirdump(ip)
116 	struct dinode *ip;
117 {
118 	/* watchout for dir inodes deleted and maybe reallocated */
119 	if ((ip->di_mode & IFMT) != IFDIR)
120 		return;
121 	dump(ip);
122 }
123 
124 dump(ip)
125 	struct dinode *ip;
126 {
127 	register int i;
128 	long size;
129 
130 	if(newtape) {
131 		newtape = 0;
132 		bitmap(nodmap, TS_BITS);
133 	}
134 	BIC(ino, nodmap);
135 	spcl.c_dinode = *ip;
136 	spcl.c_type = TS_INODE;
137 	spcl.c_count = 0;
138 	i = ip->di_mode & IFMT;
139 	if (i == 0) /* free inode */
140 		return;
141 	if ((i != IFDIR && i != IFREG && i != IFLNK) || ip->di_size == 0) {
142 		spclrec();
143 		return;
144 	}
145 	if (ip->di_size > NDADDR * sblock->fs_bsize)
146 		i = NDADDR * sblock->fs_frag;
147 	else
148 		i = howmany(ip->di_size, sblock->fs_fsize);
149 	blksout(&ip->di_db[0], i);
150 	size = ip->di_size - NDADDR * sblock->fs_bsize;
151 	if (size <= 0)
152 		return;
153 	for (i = 0; i < NIADDR; i++) {
154 		dmpindir(ip->di_ib[i], i, &size);
155 		if (size <= 0)
156 			return;
157 	}
158 }
159 
160 dmpindir(blk, lvl, size)
161 	daddr_t blk;
162 	int lvl;
163 	long *size;
164 {
165 	int i, cnt;
166 	daddr_t idblk[MAXNINDIR];
167 
168 	if (blk != 0)
169 		bread(fsbtodb(sblock, blk), (char *)idblk, sblock->fs_bsize);
170 	else
171 		bzero(idblk, sblock->fs_bsize);
172 	if (lvl <= 0) {
173 		if (*size < NINDIR(sblock) * sblock->fs_bsize)
174 			cnt = howmany(*size, sblock->fs_fsize);
175 		else
176 			cnt = NINDIR(sblock) * sblock->fs_frag;
177 		*size -= NINDIR(sblock) * sblock->fs_bsize;
178 		blksout(&idblk[0], cnt);
179 		return;
180 	}
181 	lvl--;
182 	for (i = 0; i < NINDIR(sblock); i++) {
183 		dmpindir(idblk[i], lvl, size);
184 		if (*size <= 0)
185 			return;
186 	}
187 }
188 
189 blksout(blkp, frags)
190 	daddr_t *blkp;
191 	int frags;
192 {
193 	int i, j, count, blks, tbperdb;
194 
195 	blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
196 	tbperdb = sblock->fs_bsize / TP_BSIZE;
197 	for (i = 0; i < blks; i += TP_NINDIR) {
198 		if (i + TP_NINDIR > blks)
199 			count = blks;
200 		else
201 			count = i + TP_NINDIR;
202 		for (j = i; j < count; j++)
203 			if (blkp[j / tbperdb] != 0)
204 				spcl.c_addr[j - i] = 1;
205 			else
206 				spcl.c_addr[j - i] = 0;
207 		spcl.c_count = count - i;
208 		spclrec();
209 		for (j = i; j < count; j += tbperdb)
210 			if (blkp[j / tbperdb] != 0)
211 				if (j + tbperdb <= count)
212 					dmpblk(blkp[j / tbperdb],
213 					    sblock->fs_bsize);
214 				else
215 					dmpblk(blkp[j / tbperdb],
216 					    (count - j) * TP_BSIZE);
217 		spcl.c_type = TS_ADDR;
218 	}
219 }
220 
221 bitmap(map, typ)
222 	char *map;
223 {
224 	register i;
225 	char *cp;
226 
227 	spcl.c_type = typ;
228 	spcl.c_count = howmany(msiz * sizeof(map[0]), TP_BSIZE);
229 	spclrec();
230 	for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
231 		taprec(cp);
232 }
233 
234 spclrec()
235 {
236 	register int s, i, *ip;
237 
238 	spcl.c_inumber = ino;
239 	spcl.c_magic = NFS_MAGIC;
240 	spcl.c_checksum = 0;
241 	ip = (int *)&spcl;
242 	s = 0;
243 	i = sizeof(union u_spcl) / (4*sizeof(int));
244 	while (--i >= 0) {
245 		s += *ip++; s += *ip++;
246 		s += *ip++; s += *ip++;
247 	}
248 	spcl.c_checksum = CHECKSUM - s;
249 	taprec((char *)&spcl);
250 }
251 
252 dsrch(d, size, filesize)
253 	daddr_t d;
254 	int size, filesize;
255 {
256 	register struct direct *dp;
257 	long loc;
258 	char dblk[MAXBSIZE];
259 
260 	if(dadded)
261 		return;
262 	if (filesize > size)
263 		filesize = size;
264 	bread(fsbtodb(sblock, d), dblk, filesize);
265 	for (loc = 0; loc < filesize; ) {
266 		dp = (struct direct *)(dblk + loc);
267 		if (dp->d_reclen == 0) {
268 			msg("corrupted directory, inumber %d\n", ino);
269 			break;
270 		}
271 		loc += dp->d_reclen;
272 		if(dp->d_ino == 0)
273 			continue;
274 		if(dp->d_name[0] == '.') {
275 			if(dp->d_name[1] == '\0')
276 				continue;
277 			if(dp->d_name[1] == '.' && dp->d_name[2] == '\0')
278 				continue;
279 		}
280 		if(BIT(dp->d_ino, nodmap)) {
281 			dadded++;
282 			return;
283 		}
284 		if(BIT(dp->d_ino, dirmap))
285 			nsubdir++;
286 	}
287 }
288 
289 struct dinode *
290 getino(ino)
291 	daddr_t ino;
292 {
293 	static daddr_t minino, maxino;
294 	static struct dinode itab[MAXINOPB];
295 
296 	if (ino >= minino && ino < maxino) {
297 		return (&itab[ino - minino]);
298 	}
299 	bread(fsbtodb(sblock, itod(sblock, ino)), itab, sblock->fs_bsize);
300 	minino = ino - (ino % INOPB(sblock));
301 	maxino = minino + INOPB(sblock);
302 	return (&itab[ino - minino]);
303 }
304 
305 int	breaderrors = 0;
306 #define	BREADEMAX 32
307 
308 bread(da, ba, cnt)
309 	daddr_t da;
310 	char *ba;
311 	int	cnt;
312 {
313 	int n, i;
314 	extern int errno;
315 
316 loop:
317 	if (lseek(fi, (long)(da * dev_bsize), 0) < 0){
318 		msg("bread: lseek fails\n");
319 	}
320 	n = read(fi, ba, cnt);
321 	if (n == cnt)
322 		return;
323 	if (da + (cnt / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
324 		/*
325 		 * Trying to read the final fragment.
326 		 *
327 		 * NB - dump only works in TP_BSIZE blocks, hence
328 		 * rounds `dev_bsize' fragments up to TP_BSIZE pieces.
329 		 * It should be smarter about not actually trying to
330 		 * read more than it can get, but for the time being
331 		 * we punt and scale back the read only when it gets
332 		 * us into trouble. (mkm 9/25/83)
333 		 */
334 		cnt -= dev_bsize;
335 		goto loop;
336 	}
337 	msg("read error from %s [block %d]: count=%d, got=%d, errno=%d\n",
338 		disk, da, cnt, n, errno);
339 	if (++breaderrors > BREADEMAX){
340 		msg("More than %d block read errors from %d\n",
341 			BREADEMAX, disk);
342 		broadcast("DUMP IS AILING!\n");
343 		msg("This is an unrecoverable error.\n");
344 		if (!query("Do you want to attempt to continue?")){
345 			dumpabort();
346 			/*NOTREACHED*/
347 		} else
348 			breaderrors = 0;
349 	}
350 	/*
351 	 * Zero buffer, then try to read each sector of buffer separately.
352 	 */
353 	bzero(ba, cnt);
354 	for (i = 0; i < cnt; i += dev_bsize, ba += dev_bsize, da++) {
355 		if (lseek(fi, (long)(da * dev_bsize), 0) < 0)
356 			msg("bread: lseek2 fails!\n");
357 		n = read(fi, ba, dev_bsize);
358 		if (n != dev_bsize)
359 			msg("    read error from %s [sector %d, errno %d]\n",
360 			    disk, da, errno);
361 	}
362 }
363