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