+#define NI 16
+#define DIRPB (BSIZE/sizeof(struct direct))
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/inode.h>
+#include <sys/ino.h>
+#include <sys/fblk.h>
+#include <sys/filsys.h>
+#include <sys/dir.h>
+#include <dumprestor.h>
+
+#define MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
+#define MBIT(i) (1<<((unsigned)(i-1)%MLEN))
+#define BIS(i,w) (MWORD(w,i) |= MBIT(i))
+#define BIC(i,w) (MWORD(w,i) &= ~MBIT(i))
+#define BIT(i,w) (MWORD(w,i) & MBIT(i))
+
+struct filsys sblock;
+struct dinode itab[INOPB*NI];
+short clrmap[MSIZ];
+short dirmap[MSIZ];
+short nodmap[MSIZ];
+
+char *disk;
+char *tape;
+char *increm;
+char incno;
+int uflag;
+int fi;
+int to;
+ino_t ino;
+int nsubdir;
+int ntape;
+int nadded;
+int dadded;
+int density = 160;
+
+char *ctime();
+char *prdate();
+long atol();
+int fi;
+long tsize;
+long esize;
+long asize;
+int mark();
+int add();
+int dump();
+int tapsrec();
+int dmpspc();
+int dsrch();
+int nullf();
+
+#define HOUR (60L*60L)
+#define DAY (24L*HOUR)
+#define YEAR (365L*DAY)
+
+main(argc, argv)
+char *argv[];
+{
+ char *arg;
+ register i;
+
+ time(&spcl.c_date);
+
+ tsize = 2300L*12L*10L;
+ tape = "/dev/rmt1";
+ disk = "/dev/rrp1g";
+ increm = "/etc/ddate";
+ incno = '9';
+ uflag = 0;
+ arg = "u";
+ if(argc > 1) {
+ argv++;
+ argc--;
+ arg = *argv;
+ }
+ while(*arg)
+ switch (*arg++) {
+
+ case 'f':
+ if(argc > 1) {
+ argv++;
+ argc--;
+ tape = *argv;
+ }
+ break;
+
+ case 'd':
+ if (argc > 1) {
+ argv++;
+ argc--;
+ density = atoi(*argv);
+ }
+ break;
+
+ case 's':
+ if(argc > 1) {
+ argv++;
+ argc--;
+ tsize = atol(*argv);
+ tsize *= 12L*10L;
+ }
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ incno = arg[-1];
+ break;
+
+ case 'u':
+ uflag++;
+ break;
+
+ default:
+ printf("bad key '%c%'\n", arg[-1]);
+ exit(1);
+ }
+ if(argc > 1) {
+ argv++;
+ argc--;
+ disk = *argv;
+ }
+
+ getitime();
+ printf(" date = %s\n", prdate(spcl.c_date));
+ printf("dump date = %s\n", prdate(spcl.c_ddate));
+ printf("dumping %s to %s\n", disk, tape);
+ fi = open(disk, 0);
+ if(fi < 0) {
+ printf("dump: cannot open %s\n", disk);
+ exit(1);
+ }
+ otape();
+ printf("I\n");
+ esize = 0;
+ CLR(clrmap);
+ CLR(dirmap);
+ CLR(nodmap);
+
+ pass(mark, (short *)NULL);
+ do {
+ printf("II\n");
+ nadded = 0;
+ pass(add, dirmap);
+ } while(nadded);
+
+ bmapest(clrmap);
+ bmapest(nodmap);
+ printf("estimated %ld tape blocks on %d tape(s)\n",
+ esize, 0);
+
+ printf("III\n");
+ bitmap(clrmap, TS_CLRI);
+ pass(dump, dirmap);
+ printf("IV\n");
+ pass(dump, nodmap);
+ putitime();
+ printf("DONE\n");
+ spcl.c_type = TS_END;
+ for(i=0; i<NTREC; i++)
+ spclrec();
+ printf("%ld tape blocks on %d tape(s)\n",
+ spcl.c_tapea, spcl.c_volume);
+}
+
+pass(fn, map)
+int (*fn)();
+short *map;
+{
+ register i, j;
+ int bits;
+ ino_t mino;
+ daddr_t d;
+
+ sync();
+ bread((daddr_t)1, (char *)&sblock, sizeof(sblock));
+ mino = (sblock.s_isize-2) * INOPB;
+ ino = 0;
+ for(i=2;; i+=NI) {
+ if(ino >= mino)
+ break;
+ d = (unsigned)i;
+ for(j=0; j<INOPB*NI; j++) {
+ if(ino >= mino)
+ break;
+ if((ino % MLEN) == 0) {
+ bits = ~0;
+ if(map != NULL)
+ bits = *map++;
+ }
+ ino++;
+ if(bits & 1) {
+ if(d != 0) {
+ bread(d, (char *)itab, sizeof(itab));
+ d = 0;
+ }
+ (*fn)(&itab[j]);
+ }
+ bits >>= 1;
+ }
+ }
+}
+
+icat(ip, fn1, fn2)
+struct dinode *ip;
+int (*fn1)(), (*fn2)();
+{
+ register i;
+ daddr_t d[NADDR];
+
+ l3tol(&d[0], &ip->di_addr[0], NADDR);
+ (*fn2)(d, NADDR-3);
+ for(i=0; i<NADDR; i++) {
+ if(d[i] != 0) {
+ if(i < NADDR-3)
+ (*fn1)(d[i]); else
+ indir(d[i], fn1, fn2, i-(NADDR-3));
+ }
+ }
+}
+
+indir(d, fn1, fn2, n)
+daddr_t d;
+int (*fn1)(), (*fn2)();
+{
+ register i;
+ daddr_t idblk[NINDIR];
+
+ bread(d, (char *)idblk, sizeof(idblk));
+ if(n <= 0) {
+ spcl.c_type = TS_ADDR;
+ (*fn2)(idblk, NINDIR);
+ for(i=0; i<NINDIR; i++) {
+ d = idblk[i];
+ if(d != 0)
+ (*fn1)(d);
+ }
+ } else {
+ n--;
+ for(i=0; i<NINDIR; i++) {
+ d = idblk[i];
+ if(d != 0)
+ indir(d, fn1, fn2, n);
+ }
+ }
+}
+
+mark(ip)
+struct dinode *ip;
+{
+ register f;
+
+ f = ip->di_mode & IFMT;
+ if(f == 0)
+ return;
+ BIS(ino, clrmap);
+ if(f == IFDIR)
+ BIS(ino, dirmap);
+ if(ip->di_mtime >= spcl.c_ddate ||
+ ip->di_ctime >= spcl.c_ddate) {
+ BIS(ino, nodmap);
+ if (f != IFREG)
+ return;
+ est(ip);
+ }
+}
+
+add(ip)
+struct dinode *ip;
+{
+
+ if(BIT(ino, nodmap))
+ return;
+ nsubdir = 0;
+ dadded = 0;
+ icat(ip, dsrch, nullf);
+ if(dadded) {
+ BIS(ino, nodmap);
+ est(ip);
+ nadded++;
+ }
+ if(nsubdir == 0)
+ if(!BIT(ino, nodmap))
+ BIC(ino, dirmap);
+}
+
+dump(ip)
+struct dinode *ip;
+{
+ register i;
+
+ if(ntape) {
+ ntape = 0;
+ bitmap(nodmap, TS_BITS);
+ }
+ BIC(ino, nodmap);
+ spcl.c_dinode = *ip;
+ spcl.c_type = TS_INODE;
+ spcl.c_count = 0;
+ i = ip->di_mode & IFMT;
+ if(i != IFDIR && i != IFREG) {
+ spclrec();
+ return;
+ }
+ icat(ip, tapsrec, dmpspc);
+}
+
+dmpspc(dp, n)
+daddr_t *dp;
+{
+ register i, t;
+
+ spcl.c_count = n;
+ for(i=0; i<n; i++) {
+ t = 0;
+ if(dp[i] != 0)
+ t++;
+ spcl.c_addr[i] = t;
+ }
+ spclrec();
+}
+
+bitmap(map, typ)
+short *map;
+{
+ register i, n;
+ char *cp;
+
+ n = -1;
+ for(i=0; i<MSIZ; i++)
+ if(map[i])
+ n = i;
+ if(n < 0)
+ return;
+ spcl.c_type = typ;
+ spcl.c_count = (n*sizeof(map[0]) + BSIZE)/BSIZE;
+ spclrec();
+ cp = (char *)map;
+ for(i=0; i<spcl.c_count; i++) {
+ taprec(cp);
+ cp += BSIZE;
+ }
+}
+
+spclrec()
+{
+ register i, *ip, s;
+
+ spcl.c_inumber = ino;
+ spcl.c_magic = MAGIC;
+ spcl.c_checksum = 0;
+ ip = (int *)&spcl;
+ s = 0;
+ for(i=0; i<BSIZE/sizeof(*ip); i++)
+ s += *ip++;
+ spcl.c_checksum = CHECKSUM - s;
+ taprec((char *)&spcl);
+}
+
+dsrch(d)
+daddr_t d;
+{
+ register char *cp;
+ register i;
+ register ino_t in;
+ struct direct dblk[DIRPB];
+
+ if(dadded)
+ return;
+ bread(d, (char *)dblk, sizeof(dblk));
+ for(i=0; i<DIRPB; i++) {
+ in = dblk[i].d_ino;
+ if(in == 0)
+ continue;
+ cp = dblk[i].d_name;
+ if(cp[0] == '.') {
+ if(cp[1] == '\0')
+ continue;
+ if(cp[1] == '.' && cp[2] == '\0')
+ continue;
+ }
+ if(BIT(in, nodmap)) {
+ dadded++;
+ return;
+ }
+ if(BIT(in, dirmap))
+ nsubdir++;
+ }
+}
+
+nullf()
+{
+}
+
+bread(da, ba, c)
+daddr_t da;
+char *ba;
+{
+ register n;
+
+ lseek(fi, da*BSIZE, 0);
+ n = read(fi, ba, c);
+ if(n != c)
+ printf("asked %d; got %d\n", c, n);
+}
+
+CLR(map)
+register short *map;
+{
+ register n;
+
+ n = MSIZ;
+ do
+ *map++ = 0;
+ while(--n);
+}
+
+
+char tblock[NTREC][BSIZE];
+daddr_t tdaddr[NTREC];
+int trecno;
+
+taprec(dp)
+char *dp;
+{
+ register i;
+
+ for(i=0; i<BSIZE; i++)
+ tblock[trecno][i] = *dp++;
+ tdaddr[trecno] = 0;
+ trecno++;
+ spcl.c_tapea++;
+ if(trecno >= NTREC)
+ flusht();
+}
+
+tapsrec(d)
+daddr_t d;
+{
+
+ if(d == 0)
+ return;
+ tdaddr[trecno] = d;
+ trecno++;
+ spcl.c_tapea++;
+ if(trecno >= NTREC)
+ flusht();
+}
+
+flusht()
+{
+ char place[100];
+ register i, si;
+ daddr_t d;
+
+ while(trecno < NTREC)
+ tdaddr[trecno++] = 1;
+
+loop:
+ d = 0;
+ for(i=0; i<NTREC; i++)
+ if(tdaddr[i] != 0)
+ if(d == 0 || tdaddr[i] < d) {
+ si = i;
+ d = tdaddr[i];
+ }
+ if(d != 0) {
+ bread(d, tblock[si], BSIZE);
+ tdaddr[si] = 0;
+ goto loop;
+ }
+ trecno = 0;
+ write(to, tblock[0], sizeof(tblock));
+ asize += sizeof(tblock)/density;
+ asize += 7;
+ if(asize > tsize) {
+ close(to);
+ printf("change tapes\n");
+ read(0, place, sizeof(place));
+ otape();
+ }
+}
+
+otape()
+{
+ to = creat(tape, 0666);
+ if(to < 0) {
+ printf("dump: cannot create %s\n", tape);
+ exit(1);
+ }
+ asize = 0;
+ ntape++;
+ spcl.c_volume++;
+ spcl.c_type = TS_TAPE;
+ spclrec();
+}
+
+char *
+prdate(d)
+time_t d;
+{
+ char *p;
+
+ if(d == 0)
+ return("the epoch");
+ p = ctime(&d);
+ p[24] = 0;
+ return(p);
+}
+
+getitime()
+{
+ register i, df;
+ struct idates idbuf;
+ char *fname;
+
+ fname = disk;
+l1:
+ for(i=0; fname[i]; i++)
+ if(fname[i] == '/') {
+ fname += i+1;
+ goto l1;
+ }
+
+ spcl.c_ddate = 0;
+ df = open(increm, 0);
+ if(df < 0) {
+ printf("cannot open %s\n", increm);
+ exit(1);
+ }
+
+l2:
+ i = read(df, (char *)&idbuf, sizeof(idbuf));
+ if(i != sizeof(idbuf)) {
+ close(df);
+ return;
+ }
+ for(i=0;; i++) {
+ if(fname[i] != idbuf.id_name[i])
+ goto l2;
+ if(fname[i] == '\0')
+ break;
+ }
+ if(idbuf.id_incno >= incno)
+ goto l2;
+ if(idbuf.id_ddate <= spcl.c_ddate)
+ goto l2;
+ spcl.c_ddate = idbuf.id_ddate;
+ goto l2;
+}
+
+putitime()
+{
+ register i, n, df;
+ struct idates idbuf;
+ char *fname;
+
+ if(uflag == 0)
+ return;
+ fname = disk;
+l1:
+ for(i=0; fname[i]; i++)
+ if(fname[i] == '/') {
+ fname += i+1;
+ goto l1;
+ }
+
+ spcl.c_ddate = 0;
+ df = open(increm, 2);
+ if(df < 0) {
+ printf("cannot open %s\n", increm);
+ exit(1);
+ }
+ n = 0;
+l2:
+ i = read(df, (char *)&idbuf, sizeof(idbuf));
+ if(i != sizeof(idbuf))
+ goto l3;
+ n++;
+ for(i=0;; i++) {
+ if(fname[i] != idbuf.id_name[i])
+ goto l2;
+ if(fname[i] == '\0')
+ break;
+ }
+ if(idbuf.id_incno != incno)
+ goto l2;
+l3:
+ lseek(df, (long)n*sizeof(idbuf), 0);
+ for(i=0;; i++) {
+ idbuf.id_name[i] = fname[i];
+ if(fname[i] == '\0')
+ break;
+ }
+ idbuf.id_incno = incno;
+ idbuf.id_ddate = spcl.c_date;
+ write(df, (char *)&idbuf, sizeof(idbuf));
+ close(df);
+ printf("level %c dump on %s\n", incno, prdate(spcl.c_date));
+}
+
+est(ip)
+struct dinode *ip;
+{
+ long s;
+
+ esize++;
+ s = (ip->di_size + BSIZE-1) / BSIZE;
+ esize += s;
+ if(s > NADDR-3) {
+ s -= NADDR-3;
+ s = (s + (BSIZE/sizeof(daddr_t))-1) / (BSIZE/sizeof(daddr_t));
+ esize += s;
+ }
+}
+
+bmapest(map)
+short *map;
+{
+ register i, n;
+
+ n = -1;
+ for(i=0; i<MSIZ; i++)
+ if(map[i])
+ n = i;
+ if(n < 0)
+ return;
+ esize++;
+ esize += (n + (BSIZE/sizeof(short))-1) / (BSIZE/sizeof(short));
+}