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