+#define MAXINO 2000
+#define BITS 8
+#define MAXXTR 60
+#define NCACHE 3
+
+#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))
+
+int mt;
+char tapename[] = "/dev/rmt1";
+char *magtape = tapename;
+
+daddr_t seekpt;
+int ofile;
+FILE *df;
+char dirfile[] = "rstXXXXXX";
+
+struct {
+ ino_t t_ino;
+ daddr_t t_seekpt;
+} inotab[MAXINO];
+int ipos;
+
+#define ONTAPE 1
+#define XTRACTD 2
+#define XINUSE 4
+
+short dumpmap[MSIZ];
+short clrimap[MSIZ];
+
+
+int bct = NTREC+1;
+char tbf[NTREC*BSIZE];
+
+char prebuf[BUFSIZ];
+
+int volno;
+
+main(argc, argv)
+char *argv[];
+{
+ extern char *ctime();
+
+ mktemp(dirfile);
+ argv++;
+ if (argc>=3 && *argv[0] == 'f')
+ magtape = *++argv;
+ df = fopen(dirfile, "w");
+ if (df == NULL) {
+ printf("dumpdir: %s - cannot create directory temporary\n", dirfile);
+ exit(1);
+ }
+
+ if ((mt = open(magtape, 0)) < 0) {
+ printf("%s: cannot open tape\n", magtape);
+ exit(1);
+ }
+ if (readhdr(&spcl) == 0) {
+ printf("Tape is not a dump tape\n");
+ exit(1);
+ }
+ printf("Dump date: %s", ctime(&spcl.c_date));
+ printf("Dumped from: %s", ctime(&spcl.c_ddate));
+ if (checkvol(&spcl, 1) == 0) {
+ printf("Tape is not volume 1 of the dump\n");
+ exit(1);
+ }
+ pass1(); /* This sets the various maps on the way by */
+ freopen(dirfile, "r", df);
+ strcpy(prebuf, "/");
+ printem(prebuf, (ino_t) 2);
+ exit(0);
+}
+ i = 0;
+/*
+ * Read the tape, bulding up a directory structure for extraction
+ * by name
+ */
+pass1()
+{
+ register i;
+ struct dinode *ip;
+ int putdir(), null();
+
+ while (gethead(&spcl) == 0) {
+ printf("Can't find directory header!\n");
+ }
+ for (;;) {
+ if (checktype(&spcl, TS_BITS) == 1) {
+ readbits(dumpmap);
+ continue;
+ }
+ if (checktype(&spcl, TS_CLRI) == 1) {
+ readbits(clrimap);
+ continue;
+ }
+ if (checktype(&spcl, TS_INODE) == 0) {
+finish:
+ flsh();
+ close(mt);
+ return;
+ }
+ ip = &spcl.c_dinode;
+ i = ip->di_mode & IFMT;
+ if (i != IFDIR) {
+ goto finish;
+ }
+ inotab[ipos].t_ino = spcl.c_inumber;
+ inotab[ipos++].t_seekpt = seekpt;
+ getfile(spcl.c_inumber, putdir, null, spcl.c_dinode.di_size);
+ putent("\000\000/");
+ }
+}
+
+printem(prefix, inum)
+char *prefix;
+ino_t inum;
+{
+ struct direct dir;
+ register int i;
+
+ for (i = 0; i < MAXINO; i++)
+ if (inotab[i].t_ino == inum) {
+ goto found;
+ }
+ printf("PANIC - can't find directory %d\n", inum);
+ return;
+found:
+ mseek(inotab[i].t_seekpt);
+ for (;;) {
+ getent((char *) &dir);
+ if (direq(dir.d_name, "/"))
+ return;
+ if (search(dir.d_ino) != 0 && direq(dir.d_name, ".") == 0 && direq(dir.d_name, "..") == 0) {
+ int len;
+ FILE *tdf;
+
+ tdf = df;
+ df = fopen(dirfile, "r");
+ len = strlen(prefix);
+ strncat(prefix, dir.d_name, sizeof(dir.d_name));
+ strcat(prefix, "/");
+ printem(prefix, dir.d_ino);
+ prefix[len] = '\0';
+ fclose(df);
+ df = tdf;
+ }
+ else
+ if (BIT(dir.d_ino, dumpmap))
+ printf("%5d %s%-.14s\n", dir.d_ino, prefix, dir.d_name);
+ }
+}
+/*
+ * Do the file extraction, calling the supplied functions
+ * with the blocks
+ */
+getfile(n, f1, f2, size)
+ino_t n;
+int (*f2)(), (*f1)();
+long size;
+{
+ register i;
+ struct spcl addrblock;
+ char buf[BSIZE];
+
+ addrblock = spcl;
+ goto start;
+ for (;;) {
+ if (gethead(&addrblock) == 0) {
+ printf("Missing address (header) block\n");
+ goto eloop;
+ }
+ if (checktype(&addrblock, TS_ADDR) == 0) {
+ spcl = addrblock;
+ return;
+ }
+start:
+ for (i = 0; i < addrblock.c_count; i++) {
+ if (addrblock.c_addr[i]) {
+ readtape(buf);
+ (*f1)(buf, size > BSIZE ? (long) BSIZE : size);
+ }
+ else {
+ clearbuf(buf);
+ (*f2)(buf, size > BSIZE ? (long) BSIZE : size);
+ }
+ if ((size -= BSIZE) <= 0) {
+eloop:
+ while (gethead(&spcl) == 0)
+ ;
+ if (checktype(&spcl, TS_ADDR) == 1)
+ goto eloop;
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * Do the tape i\/o, dealling with volume changes
+ * etc..
+ */
+readtape(b)
+char *b;
+{
+ register i;
+ struct spcl tmpbuf;
+
+ if (bct >= NTREC) {
+ for (i = 0; i < NTREC; i++)
+ ((struct spcl *)&tbf[i*BSIZE])->c_magic = 0;
+ bct = 0;
+ if ((i = read(mt, tbf, NTREC*BSIZE)) < 0) {
+ exit(1);
+ }
+ if (i == 0) {
+ bct = NTREC + 1;
+ volno++;
+loop:
+ flsht();
+ close(mt);
+ printf("Mount volume %d\n", volno);
+ while (getchar() != '\n')
+ ;
+ if ((mt = open(magtape, 0)) == -1) {
+ printf("Cannot open tape!\n");
+ }
+ if (readhdr(&tmpbuf) == 0) {
+ printf("Not a dump tape.Try again\n");
+ goto loop;
+ }
+ if (checkvol(&tmpbuf, volno) == 0) {
+ printf("Wrong tape. Try again\n");
+ goto loop;
+ }
+ readtape(b);
+ return;
+ }
+ }
+ copy(&tbf[(bct++*BSIZE)], b, BSIZE);
+}
+
+flsht()
+{
+ bct = NTREC+1;
+}
+
+copy(f, t, s)
+register char *f, *t;
+{
+ register i;
+
+ i = s;
+ do
+ *t++ = *f++;
+ while (--i);
+}
+
+clearbuf(cp)
+register char *cp;
+{
+ register i;
+
+ i = BSIZE;
+ do
+ *cp++ = 0;
+ while (--i);
+}
+
+/*
+ * Put and get the directory entries from the compressed
+ * directory file
+ */
+putent(cp)
+char *cp;
+{
+ register i;
+
+ for (i = 0; i < sizeof(ino_t); i++)
+ writec(*cp++);
+ for (i = 0; i < DIRSIZ; i++) {
+ writec(*cp);
+ if (*cp++ == 0)
+ return;
+ }
+ return;
+}
+
+getent(bf)
+register char *bf;
+{
+ register i;
+
+ for (i = 0; i < sizeof(ino_t); i++)
+ *bf++ = readc();
+ for (i = 0; i < DIRSIZ; i++)
+ if ((*bf++ = readc()) == 0)
+ return;
+ return;
+}
+
+/*
+ * read/write te directory file
+ */
+writec(c)
+char c;
+{
+ seekpt++;
+ fwrite(&c, 1, 1, df);
+}
+
+readc()
+{
+ char c;
+
+ fread(&c, 1, 1, df);
+ return(c);
+}
+
+mseek(pt)
+daddr_t pt;
+{
+ fseek(df, pt, 0);
+}
+
+flsh()
+{
+ fflush(df);
+}
+
+/*
+ * search the directory inode ino
+ * looking for entry cp
+ */
+search(inum)
+ino_t inum;
+{
+ register low, high, probe;
+
+ low = 0;
+ high = ipos-1;
+
+ while (low != high) {
+ probe = (high - low + 1)/2 + low;
+/*
+printf("low = %d, high = %d, probe = %d, ino = %d, inum = %d\n", low, high, probe, inum, inotab[probe].t_ino);
+*/
+ if (inum >= inotab[probe].t_ino)
+ low = probe;
+ else
+ high = probe - 1;
+ }
+ return(inum == inotab[low].t_ino);
+}
+
+direq(s1, s2)
+register char *s1, *s2;
+{
+ register i;
+
+ for (i = 0; i < DIRSIZ; i++)
+ if (*s1++ == *s2) {
+ if (*s2++ == 0)
+ return(1);
+ } else
+ return(0);
+ return(1);
+}
+
+/*
+ * read the tape into buf, then return whether or
+ * or not it is a header block.
+ */
+gethead(buf)
+struct spcl *buf;
+{
+ readtape((char *)buf);
+ if (buf->c_magic != MAGIC || checksum((int *) buf) == 0)
+ return(0);
+ return(1);
+}
+
+/*
+ * return whether or not the buffer contains a header block
+ */
+checktype(b, t)
+struct spcl *b;
+int t;
+{
+ return(b->c_type == t);
+}
+
+
+checksum(b)
+int *b;
+{
+ register i, j;
+
+ j = BSIZE/sizeof(int);
+ i = 0;
+ do
+ i += *b++;
+ while (--j);
+ if (i != CHECKSUM) {
+ printf("Checksum error %o\n", i);
+ return(0);
+ }
+ return(1);
+}
+
+checkvol(b, t)
+struct spcl *b;
+int t;
+{
+ if (b->c_volume == t)
+ return(1);
+ return(0);
+}
+
+readhdr(b)
+struct spcl *b;
+{
+ if (gethead(b) == 0)
+ return(0);
+ if (checktype(b, TS_TAPE) == 0)
+ return(0);
+ return(1);
+}
+
+putdir(b)
+char *b;
+{
+ register struct direct *dp;
+ register i;
+
+ for (dp = (struct direct *) b, i = 0; i < BSIZE; dp++, i += sizeof(*dp)) {
+ if (dp->d_ino == 0)
+ continue;
+ putent((char *) dp);
+ }
+}
+
+/*
+ * read a bit mask from the tape into m.
+ */
+readbits(m)
+short *m;
+{
+ register i;
+
+ i = spcl.c_count;
+
+ while (i--) {
+ readtape((char *) m);
+ m += (BSIZE/(MLEN/BITS));
+ }
+ while (gethead(&spcl) == 0)
+ ;
+}
+
+null() { ; }