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 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 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 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 * 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 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