1 /*
2 * Copyright (c) 1980 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[] = "@(#)dumptraverse.c 1.2 (UKC) 08/08/87 5.3 (Berkeley) 1/9/86";
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
add(ip)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
indir(d,n,filesize)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
dmpindir(blk,lvl,size)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
blksout(blkp,frags)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
bitmap(map,typ)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
spclrec()234 spclrec()
235 {
236 register int s, i, *ip;
237
238 spcl.c_inumber = ino;
239 spcl.c_magic = NFS_MAGIC;
240 if(newtape) /* add label */
241 strcpy(spcl.c_label, createlabel(tapeno));
242 spcl.c_checksum = 0;
243 ip = (int *)&spcl;
244 s = 0;
245 i = sizeof(union u_spcl) / (4*sizeof(int));
246 while (--i >= 0) {
247 s += *ip++; s += *ip++;
248 s += *ip++; s += *ip++;
249 }
250 spcl.c_checksum = CHECKSUM - s;
251 taprec((char *)&spcl);
252 }
253
dsrch(d,size,filesize)254 dsrch(d, size, filesize)
255 daddr_t d;
256 int size, filesize;
257 {
258 register struct direct *dp;
259 long loc;
260 char dblk[MAXBSIZE];
261
262 if(dadded)
263 return;
264 if (filesize > size)
265 filesize = size;
266 bread(fsbtodb(sblock, d), dblk, filesize);
267 for (loc = 0; loc < filesize; ) {
268 dp = (struct direct *)(dblk + loc);
269 if (dp->d_reclen == 0) {
270 msg("corrupted directory, inumber %d\n", ino);
271 break;
272 }
273 loc += dp->d_reclen;
274 if(dp->d_ino == 0)
275 continue;
276 if(dp->d_name[0] == '.') {
277 if(dp->d_name[1] == '\0')
278 continue;
279 if(dp->d_name[1] == '.' && dp->d_name[2] == '\0')
280 continue;
281 }
282 if(BIT(dp->d_ino, nodmap)) {
283 dadded++;
284 return;
285 }
286 if(BIT(dp->d_ino, dirmap))
287 nsubdir++;
288 }
289 }
290
291 struct dinode *
getino(ino)292 getino(ino)
293 daddr_t ino;
294 {
295 static daddr_t minino, maxino;
296 static struct dinode itab[MAXINOPB];
297
298 if (ino >= minino && ino < maxino) {
299 return (&itab[ino - minino]);
300 }
301 bread(fsbtodb(sblock, itod(sblock, ino)), itab, sblock->fs_bsize);
302 minino = ino - (ino % INOPB(sblock));
303 maxino = minino + INOPB(sblock);
304 return (&itab[ino - minino]);
305 }
306
307 int breaderrors = 0;
308 #define BREADEMAX 32
309
bread(da,ba,cnt)310 bread(da, ba, cnt)
311 daddr_t da;
312 char *ba;
313 int cnt;
314 {
315 int n;
316
317 loop:
318 if (lseek(fi, (long)(da * DEV_BSIZE), 0) < 0){
319 msg("bread: lseek fails\n");
320 }
321 n = read(fi, ba, cnt);
322 if (n == cnt)
323 return;
324 if (da + (cnt / DEV_BSIZE) > fsbtodb(sblock, sblock->fs_size)) {
325 /*
326 * Trying to read the final fragment.
327 *
328 * NB - dump only works in TP_BSIZE blocks, hence
329 * rounds DEV_BSIZE fragments up to TP_BSIZE pieces.
330 * It should be smarter about not actually trying to
331 * read more than it can get, but for the time being
332 * we punt and scale back the read only when it gets
333 * us into trouble. (mkm 9/25/83)
334 */
335 cnt -= DEV_BSIZE;
336 goto loop;
337 }
338 msg("(This should not happen)bread from %s [block %d]: count=%d, got=%d\n",
339 disk, da, cnt, n);
340 if (++breaderrors > BREADEMAX){
341 msg("More than %d block read errors from %d\n",
342 BREADEMAX, disk);
343 broadcast("DUMP IS AILING!\n");
344 msg("This is an unrecoverable error.\n");
345 if (!query("Do you want to attempt to continue?")){
346 dumpabort();
347 /*NOTREACHED*/
348 } else
349 breaderrors = 0;
350 }
351 }
352