home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / restor.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-05-24  |  18.6 KB  |  1,148 lines

  1. #define MAXINO    3000
  2. #define BITS    8
  3. #define MAXXTR    60
  4. #define NCACHE    3
  5.  
  6. #ifndef STANDALONE
  7. #include <stdio.h>
  8. #include <signal.h>
  9. #endif
  10. #include <sys/param.h>
  11. #include <sys/inode.h>
  12. #include <sys/ino.h>
  13. #include <sys/fblk.h>
  14. #include <sys/filsys.h>
  15. #include <sys/dir.h>
  16. #include <dumprestor.h>
  17.  
  18. #define    MWORD(m,i) (m[(unsigned)(i-1)/MLEN])
  19. #define    MBIT(i)    (1<<((unsigned)(i-1)%MLEN))
  20. #define    BIS(i,w)    (MWORD(w,i) |=  MBIT(i))
  21. #define    BIC(i,w)    (MWORD(w,i) &= ~MBIT(i))
  22. #define    BIT(i,w)    (MWORD(w,i) & MBIT(i))
  23.  
  24. struct    filsys    sblock;
  25.  
  26. int    fi;
  27. ino_t    ino, maxi, curino;
  28.  
  29. int    mt;
  30. char    tapename[] = "/dev/rmt1";
  31. char    *magtape = tapename;
  32. #ifdef STANDALONE
  33. char    mbuf[50];
  34. #endif
  35.  
  36. #ifndef STANDALONE
  37. daddr_t    seekpt;
  38. int    df, ofile;
  39. char    dirfile[] = "rstXXXXXX";
  40.  
  41. struct {
  42.     ino_t    t_ino;
  43.     daddr_t    t_seekpt;
  44. } inotab[MAXINO];
  45. int    ipos;
  46.  
  47. #define ONTAPE    1
  48. #define XTRACTD    2
  49. #define XINUSE    4
  50. struct xtrlist {
  51.     ino_t    x_ino;
  52.     char    x_flags;
  53. } xtrlist[MAXXTR];
  54.  
  55. char    name[12];
  56.  
  57. char    drblock[BSIZE];
  58. int    bpt;
  59. #endif
  60.  
  61. int    eflag;
  62.  
  63. int    volno = 1;
  64.  
  65. struct dinode tino, dino;
  66. daddr_t    taddr[NADDR];
  67.  
  68. daddr_t    curbno;
  69.  
  70. short    dumpmap[MSIZ];
  71. short    clrimap[MSIZ];
  72.  
  73.  
  74. int bct = NTREC+1;
  75. char tbf[NTREC*BSIZE];
  76.  
  77. struct    cache {
  78.     daddr_t    c_bno;
  79.     int    c_time;
  80.     char    c_block[BSIZE];
  81. } cache[NCACHE];
  82. int    curcache;
  83.  
  84. main(argc, argv)
  85. char *argv[];
  86. {
  87.     register char *cp;
  88.     char command;
  89.     int done();
  90.  
  91. #ifndef STANDALONE
  92.     mktemp(dirfile);
  93.     if (argc < 2) {
  94. usage:
  95.         printf("Usage: restor x file file..., restor r filesys, or restor t\n");
  96.         exit(1);
  97.     }
  98.     argv++;
  99.     argc -= 2;
  100.     for (cp = *argv++; *cp; cp++) {
  101.         switch (*cp) {
  102.         case '-':
  103.             break;
  104.         case 'f':
  105.             magtape = *argv++;
  106.             argc--;
  107.             break;
  108.         case 'r':
  109.         case 'R':
  110.         case 't':
  111.         case 'x':
  112.             command = *cp;
  113.             break;
  114.         default:
  115.             printf("Bad key character %c\n", *cp);
  116.             goto usage;
  117.         }
  118.     }
  119.     if (command == 'x') {
  120.         if (signal(SIGINT, done) == SIG_IGN)
  121.             signal(SIGINT, SIG_IGN);
  122.         if (signal(SIGTERM, done) == SIG_IGN)
  123.             signal(SIGTERM, SIG_IGN);
  124.  
  125.         df = creat(dirfile, 0666);
  126.         if (df < 0) {
  127.             printf("restor: %s - cannot create directory temporary\n", dirfile);
  128.             exit(1);
  129.         }
  130.         close(df);
  131.         df = open(dirfile, 2);
  132.     }
  133.     doit(command, argc, argv);
  134.     if (command == 'x')
  135.         unlink(dirfile);
  136.     exit(0);
  137. #else
  138.     magtape = "tape";
  139.     doit('r', 1, 0);
  140. #endif
  141. }
  142.  
  143. doit(command, argc, argv)
  144. char    command;
  145. int    argc;
  146. char    *argv[];
  147. {
  148.     extern char *ctime();
  149.     register i, k;
  150.     ino_t    d;
  151. #ifndef STANDALONE
  152.     int    xtrfile(), skip();
  153. #endif
  154.     int    rstrfile(), rstrskip();
  155.     struct dinode *ip, *ip1;
  156.  
  157. #ifndef STANDALONE
  158.     if ((mt = open(magtape, 0)) < 0) {
  159.         printf("%s: cannot open tape\n", magtape);
  160.         exit(1);
  161.     }
  162. #else
  163.     do {
  164.         printf("Tape? ");
  165.         gets(mbuf);
  166.         mt = open(mbuf, 0);
  167.     } while (mt == -1);
  168.     magtape = mbuf;
  169. #endif
  170.     switch(command) {
  171. #ifndef STANDALONE
  172.     case 't':
  173.         if (readhdr(&spcl) == 0) {
  174.             printf("Tape is not a dump tape\n");
  175.             exit(1);
  176.         }
  177.         printf("Dump   date: %s", ctime(&spcl.c_date));
  178.         printf("Dumped from: %s", ctime(&spcl.c_ddate));
  179.         return;
  180.     case 'x':
  181.         if (readhdr(&spcl) == 0) {
  182.             printf("Tape is not a dump tape\n");
  183.             exit(1);
  184.         }
  185.         if (checkvol(&spcl, 1) == 0) {
  186.             printf("Tape is not volume 1 of the dump\n");
  187.             exit(1);
  188.         }
  189.         pass1();  /* This sets the various maps on the way by */
  190.         i = 0;
  191.         while (i < MAXXTR-1 && argc--) {
  192.             if ((d = psearch(*argv)) == 0 || BIT(d, dumpmap) == 0) {
  193.                 printf("%s: not on the tape\n", *argv++);
  194.                 continue;
  195.             }
  196.             xtrlist[i].x_ino = d;
  197.             xtrlist[i].x_flags |= XINUSE;
  198.             printf("%s: inode %u\n", *argv, d);
  199.             argv++;
  200.             i++;
  201.         }
  202. newvol:
  203.         flsht();
  204.         close(mt);
  205. getvol:
  206.         printf("Mount desired tape volume: Specify volume #: ");
  207.         if (gets(tbf) == NULL)
  208.             return;
  209.         volno = atoi(tbf);
  210.         if (volno <= 0) {
  211.             printf("Volume numbers are positive numerics\n");
  212.             goto getvol;
  213.         }
  214.         mt = open(magtape, 0);
  215.         if (readhdr(&spcl) == 0) {
  216.             printf("tape is not dump tape\n");
  217.             goto newvol;
  218.         }
  219.         if (checkvol(&spcl, volno) == 0) {
  220.             printf("Wrong volume (%d)\n", spcl.c_volume);
  221.             goto newvol;
  222.         }
  223. rbits:
  224.         while (gethead(&spcl) == 0)
  225.             ;
  226.         if (checktype(&spcl, TS_INODE) == 1) {
  227.             printf("Can't find inode mask!\n");
  228.             goto newvol;
  229.         }
  230.         if (checktype(&spcl, TS_BITS) == 0)
  231.             goto rbits;
  232.         readbits(dumpmap);
  233.         i = 0;
  234.         for (k = 0; xtrlist[k].x_flags; k++) {
  235.             if (BIT(xtrlist[k].x_ino, dumpmap)) {
  236.                 xtrlist[k].x_flags |= ONTAPE;
  237.                 i++;
  238.             }
  239.         }
  240.         while (i > 0) {
  241. again:
  242.             if (ishead(&spcl) == 0)
  243.                 while(gethead(&spcl) == 0)
  244.                     ;
  245.             if (checktype(&spcl, TS_END) == 1) {
  246.                 printf("end of tape\n");
  247. checkdone:
  248.                 for (k = 0; xtrlist[k].x_flags; k++)
  249.                     if ((xtrlist[k].x_flags&XTRACTD) == 0)
  250.                         goto newvol;
  251.                     return;
  252.             }
  253.             if (checktype(&spcl, TS_INODE) == 0) {
  254.                 gethead(&spcl);
  255.                 goto again;
  256.             }
  257.             d = spcl.c_inumber;
  258.             for (k = 0; xtrlist[k].x_flags; k++) {
  259.                 if (d == xtrlist[k].x_ino) {
  260.                     printf("extract file %u\n", xtrlist[k].x_ino);
  261.                     sprintf(name, "%u", xtrlist[k].x_ino);
  262.                     if ((ofile = creat(name, 0666)) < 0) {
  263.                         printf("%s: cannot create file\n", name);
  264.                         i--;
  265.                         continue;
  266.                     }
  267.                     chown(name, spcl.c_dinode.di_uid, spcl.c_dinode.di_gid);
  268.                     getfile(ino, xtrfile, skip, spcl.c_dinode.di_size);
  269.                     i--;
  270.                     xtrlist[k].x_flags |= XTRACTD;
  271.                     close(ofile);
  272.                     goto done;
  273.                 }
  274.             }
  275.             gethead(&spcl);
  276. done:
  277.             ;
  278.         }
  279.         goto checkdone;
  280. #endif
  281.     case 'r':
  282.     case 'R':
  283. #ifndef STANDALONE
  284.         if ((fi = open(*argv, 2)) < 0) {
  285.             printf("%s: cannot open\n", *argv);
  286.             exit(1);
  287.         }
  288. #else
  289.         do {
  290.             char charbuf[50];
  291.  
  292.             printf("Disk? ");
  293.             gets(charbuf);
  294.             fi = open(charbuf, 2);
  295.         } while (fi == -1);
  296. #endif
  297. #ifndef STANDALONE
  298.         if (command == 'R') {
  299.             printf("Enter starting volume number: ");
  300.             if (gets(tbf) == EOF) {
  301.                 volno = 1;
  302.                 printf("\n");
  303.             }
  304.             else
  305.                 volno = atoi(tbf);
  306.         }
  307.         else
  308. #endif
  309.             volno = 1;
  310.         printf("Last chance before scribbling on %s. ",
  311. #ifdef STANDALONE
  312.                                 "disk");
  313. #else
  314.                                 *argv);
  315. #endif
  316.         while (getchar() != '\n');
  317.         dread((daddr_t)1, (char *)&sblock, sizeof(sblock));
  318.         maxi = (sblock.s_isize-2)*INOPB;
  319.         if (readhdr(&spcl) == 0) {
  320.             printf("Missing volume record\n");
  321.             exit(1);
  322.         }
  323.         if (checkvol(&spcl, volno) == 0) {
  324.             printf("Tape is not volume %d\n", volno);
  325.             exit(1);
  326.         }
  327.         gethead(&spcl);
  328.         for (;;) {
  329. ragain:
  330.             if (ishead(&spcl) == 0) {
  331.                 printf("Missing header block\n");
  332.                 while (gethead(&spcl) == 0)
  333.                     ;
  334.                 eflag++;
  335.             }
  336.             if (checktype(&spcl, TS_END) == 1) {
  337.                 printf("End of tape\n");
  338.                 close(mt);
  339.                 dwrite( (daddr_t) 1, (char *) &sblock);
  340.                 return;
  341.             }
  342.             if (checktype(&spcl, TS_CLRI) == 1) {
  343.                 readbits(clrimap);
  344.                 for (ino = 1; ino <= maxi; ino++)
  345.                     if (BIT(ino, clrimap) == 0) {
  346.                         getdino(ino, &tino);
  347.                         if (tino.di_mode == 0)
  348.                             continue;
  349.                         itrunc(&tino);
  350.                         clri(&tino);
  351.                         putdino(ino, &tino);
  352.                     }
  353.                 dwrite( (daddr_t) 1, (char *) &sblock);
  354.                 goto ragain;
  355.             }
  356.             if (checktype(&spcl, TS_BITS) == 1) {
  357.                 readbits(dumpmap);
  358.                 goto ragain;
  359.             }
  360.             if (checktype(&spcl, TS_INODE) == 0) {
  361.                 printf("Unknown header type\n");
  362.                 eflag++;
  363.                 gethead(&spcl);
  364.                 goto ragain;
  365.             }
  366.             ino = spcl.c_inumber;
  367.             if (eflag)
  368.                 printf("Resynced at inode %u\n", ino);
  369.             eflag = 0;
  370.             if (ino > maxi) {
  371.                 printf("%u: ilist too small\n", ino);
  372.                 gethead(&spcl);
  373.                 goto ragain;
  374.             }
  375.             dino = spcl.c_dinode;
  376.             getdino(ino, &tino);
  377.             curbno = 0;
  378.             itrunc(&tino);
  379.             clri(&tino);
  380.             for (i = 0; i < NADDR; i++)
  381.                 taddr[i] = 0;
  382.             l3tol(taddr, dino.di_addr, 1);
  383.             getfile(ino, rstrfile, rstrskip, dino.di_size);
  384.             ip = &tino;
  385.             ltol3(ip->di_addr, taddr, NADDR);
  386.             ip1 = &dino;
  387.             ip->di_mode = ip1->di_mode;
  388.             ip->di_nlink = ip1->di_nlink;
  389.             ip->di_uid = ip1->di_uid;
  390.             ip->di_gid = ip1->di_gid;
  391.             ip->di_size = ip1->di_size;
  392.             ip->di_atime = ip1->di_atime;
  393.             ip->di_mtime = ip1->di_mtime;
  394.             ip->di_ctime = ip1->di_ctime;
  395.             putdino(ino, &tino);
  396.         }
  397.     }
  398. }
  399.  
  400. /*
  401.  * Read the tape, bulding up a directory structure for extraction
  402.  * by name
  403.  */
  404. #ifndef STANDALONE
  405. pass1()
  406. {
  407.     register i;
  408.     struct dinode *ip;
  409.     int    putdir(), null();
  410.  
  411.     while (gethead(&spcl) == 0) {
  412.         printf("Can't find directory header!\n");
  413.     }
  414.     for (;;) {
  415.         if (checktype(&spcl, TS_BITS) == 1) {
  416.             readbits(dumpmap);
  417.             continue;
  418.         }
  419.         if (checktype(&spcl, TS_CLRI) == 1) {
  420.             readbits(clrimap);
  421.             continue;
  422.         }
  423.         if (checktype(&spcl, TS_INODE) == 0) {
  424. finish:
  425.             flsh();
  426.             close(mt);
  427.             return;
  428.         }
  429.         ip = &spcl.c_dinode;
  430.         i = ip->di_mode & IFMT;
  431.         if (i != IFDIR) {
  432.             goto finish;
  433.         }
  434.         inotab[ipos].t_ino = spcl.c_inumber;
  435.         inotab[ipos++].t_seekpt = seekpt;
  436.         getfile(spcl.c_inumber, putdir, null, spcl.c_dinode.di_size);
  437.         putent("\000\000/");
  438.     }
  439. }
  440. #endif
  441.  
  442. /*
  443.  * Do the file extraction, calling the supplied functions
  444.  * with the blocks
  445.  */
  446. getfile(n, f1, f2, size)
  447. ino_t    n;
  448. int    (*f2)(), (*f1)();
  449. long    size;
  450. {
  451.     register i;
  452.     struct spcl addrblock;
  453.     char buf[BSIZE];
  454.  
  455.     addrblock = spcl;
  456.     curino = n;
  457.     goto start;
  458.     for (;;) {
  459.         if (gethead(&addrblock) == 0) {
  460.             printf("Missing address (header) block\n");
  461.             goto eloop;
  462.         }
  463.         if (checktype(&addrblock, TS_ADDR) == 0) {
  464.             spcl = addrblock;
  465.             curino = 0;
  466.             return;
  467.         }
  468. start:
  469.         for (i = 0; i < addrblock.c_count; i++) {
  470.             if (addrblock.c_addr[i]) {
  471.                 readtape(buf);
  472.                 (*f1)(buf, size > BSIZE ? (long) BSIZE : size);
  473.             }
  474.             else {
  475.                 clearbuf(buf);
  476.                 (*f2)(buf, size > BSIZE ? (long) BSIZE : size);
  477.             }
  478.             if ((size -= BSIZE) <= 0) {
  479. eloop:
  480.                 while (gethead(&spcl) == 0)
  481.                     ;
  482.                 if (checktype(&spcl, TS_ADDR) == 1)
  483.                     goto eloop;
  484.                 curino = 0;
  485.                 return;
  486.             }
  487.         }
  488.     }
  489. }
  490.  
  491. /*
  492.  * Do the tape i\/o, dealling with volume changes
  493.  * etc..
  494.  */
  495. readtape(b)
  496. char *b;
  497. {
  498.     register i;
  499.     struct spcl tmpbuf;
  500.  
  501.     if (bct >= NTREC) {
  502.         for (i = 0; i < NTREC; i++)
  503.             ((struct spcl *)&tbf[i*BSIZE])->c_magic = 0;
  504.         bct = 0;
  505.         if ((i = read(mt, tbf, NTREC*BSIZE)) < 0) {
  506.             printf("Tape read error: inode %u\n", curino);
  507.             eflag++;
  508.             for (i = 0; i < NTREC; i++)
  509.                 clearbuf(&tbf[i*BSIZE]);
  510.         }
  511.         if (i == 0) {
  512.             bct = NTREC + 1;
  513.             volno++;
  514. loop:
  515.             flsht();
  516.             close(mt);
  517.             printf("Mount volume %d\n", volno);
  518.             while (getchar() != '\n')
  519.                 ;
  520.             if ((mt = open(magtape, 0)) == -1) {
  521.                 printf("Cannot open tape!\n");
  522.                 goto loop;
  523.             }
  524.             if (readhdr(&tmpbuf) == 0) {
  525.                 printf("Not a dump tape.Try again\n");
  526.                 goto loop;
  527.             }
  528.             if (checkvol(&tmpbuf, volno) == 0) {
  529.                 printf("Wrong tape. Try again\n");
  530.                 goto loop;
  531.             }
  532.             readtape(b);
  533.             return;
  534.         }
  535.     }
  536.     copy(&tbf[(bct++*BSIZE)], b, BSIZE);
  537. }
  538.  
  539. flsht()
  540. {
  541.     bct = NTREC+1;
  542. }
  543.  
  544. copy(f, t, s)
  545. register char *f, *t;
  546. {
  547.     register i;
  548.  
  549.     i = s;
  550.     do
  551.         *t++ = *f++;
  552.     while (--i);
  553. }
  554.  
  555. clearbuf(cp)
  556. register char *cp;
  557. {
  558.     register i;
  559.  
  560.     i = BSIZE;
  561.     do
  562.         *cp++ = 0;
  563.     while (--i);
  564. }
  565.  
  566. /*
  567.  * Put and get the directory entries from the compressed
  568.  * directory file
  569.  */
  570. #ifndef STANDALONE
  571. putent(cp)
  572. char    *cp;
  573. {
  574.     register i;
  575.  
  576.     for (i = 0; i < sizeof(ino_t); i++)
  577.         writec(*cp++);
  578.     for (i = 0; i < DIRSIZ; i++) {
  579.         writec(*cp);
  580.         if (*cp++ == 0)
  581.             return;
  582.     }
  583.     return;
  584. }
  585.  
  586. getent(bf)
  587. register char *bf;
  588. {
  589.     register i;
  590.  
  591.     for (i = 0; i < sizeof(ino_t); i++)
  592.         *bf++ = readc();
  593.     for (i = 0; i < DIRSIZ; i++)
  594.         if ((*bf++ = readc()) == 0)
  595.             return;
  596.     return;
  597. }
  598.  
  599. /*
  600.  * read/write te directory file
  601.  */
  602. writec(c)
  603. char c;
  604. {
  605.     drblock[bpt++] = c;
  606.     seekpt++;
  607.     if (bpt >= BSIZE) {
  608.         bpt = 0;
  609.         write(df, drblock, BSIZE);
  610.     }
  611. }
  612.  
  613. readc()
  614. {
  615.     if (bpt >= BSIZE) {
  616.         read(df, drblock, BSIZE);
  617.         bpt = 0;
  618.     }
  619.     return(drblock[bpt++]);
  620. }
  621.  
  622. mseek(pt)
  623. daddr_t pt;
  624. {
  625.     bpt = BSIZE;
  626.     lseek(df, pt, 0);
  627. }
  628.  
  629. flsh()
  630. {
  631.     write(df, drblock, bpt+1);
  632. }
  633.  
  634. /*
  635.  * search the directory inode ino
  636.  * looking for entry cp
  637.  */
  638. ino_t
  639. search(inum, cp)
  640. ino_t    inum;
  641. char    *cp;
  642. {
  643.     register i;
  644.     struct direct dir;
  645.  
  646.     for (i = 0; i < MAXINO; i++)
  647.         if (inotab[i].t_ino == inum) {
  648.             goto found;
  649.         }
  650.     return(0);
  651. found:
  652.     mseek(inotab[i].t_seekpt);
  653.     do {
  654.         getent((char *)&dir);
  655.         if (direq(dir.d_name, "/"))
  656.             return(0);
  657.     } while (direq(dir.d_name, cp) == 0);
  658.     return(dir.d_ino);
  659. }
  660.  
  661. /*
  662.  * Search the directory tree rooted at inode 2
  663.  * for the path pointed at by n
  664.  */
  665. psearch(n)
  666. char    *n;
  667. {
  668.     register char *cp, *cp1;
  669.     char c;
  670.  
  671.     ino = 2;
  672.     if (*(cp = n) == '/')
  673.         cp++;
  674. next:
  675.     cp1 = cp + 1;
  676.     while (*cp1 != '/' && *cp1)
  677.         cp1++;
  678.     c = *cp1;
  679.     *cp1 = 0;
  680.     ino = search(ino, cp);
  681.     if (ino == 0) {
  682.         *cp1 = c;
  683.         return(0);
  684.     }
  685.     *cp1 = c;
  686.     if (c == '/') {
  687.         cp = cp1+1;
  688.         goto next;
  689.     }
  690.     return(ino);
  691. }
  692.  
  693. direq(s1, s2)
  694. register char *s1, *s2;
  695. {
  696.     register i;
  697.  
  698.     for (i = 0; i < DIRSIZ; i++)
  699.         if (*s1++ == *s2) {
  700.             if (*s2++ == 0)
  701.                 return(1);
  702.         } else
  703.             return(0);
  704.     return(1);
  705. }
  706. #endif
  707.  
  708. /*
  709.  * read/write a disk block, be sure to update the buffer
  710.  * cache if needed.
  711.  */
  712. dwrite(bno, b)
  713. daddr_t    bno;
  714. char    *b;
  715. {
  716.     register i;
  717.  
  718.     for (i = 0; i < NCACHE; i++) {
  719.         if (cache[i].c_bno == bno) {
  720.             copy(b, cache[i].c_block, BSIZE);
  721.             cache[i].c_time = 0;
  722.             break;
  723.         }
  724.         else
  725.             cache[i].c_time++;
  726.     }
  727.     lseek(fi, bno*BSIZE, 0);
  728.     if(write(fi, b, BSIZE) != BSIZE) {
  729. #ifdef STANDALONE
  730.         printf("disk write error %D\n", bno);
  731. #else
  732.         fprintf(stderr, "disk write error %ld\n", bno);
  733. #endif
  734.         exit(1);
  735.     }
  736. }
  737.  
  738. dread(bno, buf, cnt)
  739. daddr_t bno;
  740. char *buf;
  741. {
  742.     register i, j;
  743.  
  744.     j = 0;
  745.     for (i = 0; i < NCACHE; i++) {
  746.         if (++curcache >= NCACHE)
  747.             curcache = 0;
  748.         if (cache[curcache].c_bno == bno) {
  749.             copy(cache[curcache].c_block, buf, cnt);
  750.             cache[curcache].c_time = 0;
  751.             return;
  752.         }
  753.         else {
  754.             cache[curcache].c_time++;
  755.             if (cache[j].c_time < cache[curcache].c_time)
  756.                 j = curcache;
  757.         }
  758.     }
  759.  
  760.     lseek(fi, bno*BSIZE, 0);
  761.     if (read(fi, cache[j].c_block, BSIZE) != BSIZE) {
  762. #ifdef STANDALONE
  763.         printf("read error %D\n", bno);
  764. #else
  765.         printf("read error %ld\n", bno);
  766. #endif
  767.         exit(1);
  768.     }
  769.     copy(cache[j].c_block, buf, cnt);
  770.     cache[j].c_time = 0;
  771.     cache[j].c_bno = bno;
  772. }
  773.  
  774. /*
  775.  * the inode manpulation routines. Like the system.
  776.  *
  777.  * clri zeros the inode
  778.  */
  779. clri(ip)
  780. struct dinode *ip;
  781. {
  782.     int i, *p;
  783.     i = sizeof(struct dinode)/sizeof(int);
  784.     p = (int *)ip;
  785.     do
  786.         *p++ = 0;
  787.     while(--i);
  788. }
  789.  
  790. /*
  791.  * itrunc/tloop/bfree free all of the blocks pointed at by the inode
  792.  */
  793. itrunc(ip)
  794. register struct dinode *ip;
  795. {
  796.     register i;
  797.     daddr_t bn, iaddr[NADDR];
  798.  
  799.     if (ip->di_mode == 0)
  800.         return;
  801.     i = ip->di_mode & IFMT;
  802.     if (i != IFDIR && i != IFREG)
  803.         return;
  804.     l3tol(iaddr, ip->di_addr, NADDR);
  805.     for(i=NADDR-1;i>=0;i--) {
  806.         bn = iaddr[i];
  807.         if(bn == 0) continue;
  808.         switch(i) {
  809.  
  810.         default:
  811.             bfree(bn);
  812.             break;
  813.  
  814.         case NADDR-3:
  815.             tloop(bn, 0, 0);
  816.             break;
  817.  
  818.         case NADDR-2:
  819.             tloop(bn, 1, 0);
  820.             break;
  821.  
  822.         case NADDR-1:
  823.             tloop(bn, 1, 1);
  824.         }
  825.     }
  826.     ip->di_size = 0;
  827. }
  828.  
  829. tloop(bn, f1, f2)
  830. daddr_t    bn;
  831. int    f1, f2;
  832. {
  833.     register i;
  834.     daddr_t nb;
  835.     union {
  836.         char    data[BSIZE];
  837.         daddr_t    indir[NINDIR];
  838.     } ibuf;
  839.  
  840.     dread(bn, ibuf.data, BSIZE);
  841.     for(i=NINDIR-1;i>=0;i--) {
  842.         nb = ibuf.indir[i];
  843.         if(nb) {
  844.             if(f1)
  845.                 tloop(nb, f2, 0);
  846.             else
  847.                 bfree(nb);
  848.         }
  849.     }
  850.     bfree(bn);
  851. }
  852.  
  853. bfree(bn)
  854. daddr_t    bn;
  855. {
  856.     register i;
  857.     union {
  858.         char    data[BSIZE];
  859.         struct    fblk frees;
  860.     } fbuf;
  861.  
  862.     if(sblock.s_nfree >= NICFREE) {
  863.         fbuf.df_nfree = sblock.s_nfree;
  864.         for(i=0;i<NICFREE;i++)
  865.             fbuf.df_free[i] = sblock.s_free[i];
  866.         sblock.s_nfree = 0;
  867.         dwrite(bn, fbuf.data);
  868.     }
  869.     sblock.s_free[sblock.s_nfree++] = bn;
  870. }
  871.  
  872. /*
  873.  * allocate a block off the free list.
  874.  */
  875. daddr_t
  876. balloc()
  877. {
  878.     daddr_t    bno;
  879.     register i;
  880.     static char zeroes[BSIZE];
  881.     union {
  882.         char    data[BSIZE];
  883.         struct    fblk frees;
  884.     } fbuf;
  885.  
  886.     if(sblock.s_nfree == 0 || (bno=sblock.s_free[--sblock.s_nfree]) == 0) {
  887. #ifdef STANDALONE
  888.         printf("Out of space\n");
  889. #else
  890.         fprintf(stderr, "Out of space.\n");
  891. #endif
  892.         exit(1);
  893.     }
  894.     if(sblock.s_nfree == 0) {
  895.         dread(bno, fbuf.data, BSIZE);
  896.         sblock.s_nfree = fbuf.df_nfree;
  897.         for(i=0;i<NICFREE;i++)
  898.             sblock.s_free[i] = fbuf.df_free[i];
  899.     }
  900.     dwrite(bno, zeroes);
  901.     return(bno);
  902. }
  903.  
  904. /*
  905.  * map a block number into a block address, ensuring
  906.  * all of the correct indirect blocks are around. Allocate
  907.  * the block requested.
  908.  */
  909. daddr_t
  910. bmap(iaddr, bn)
  911. daddr_t    iaddr[NADDR];
  912. daddr_t    bn;
  913. {
  914.     register i;
  915.     int j, sh;
  916.     daddr_t nb, nnb;
  917.     daddr_t indir[NINDIR];
  918.  
  919.     /*
  920.      * blocks 0..NADDR-4 are direct blocks
  921.      */
  922.     if(bn < NADDR-3) {
  923.         iaddr[bn] = nb = balloc();
  924.         return(nb);
  925.     }
  926.  
  927.     /*
  928.      * addresses NADDR-3, NADDR-2, and NADDR-1
  929.      * have single, double, triple indirect blocks.
  930.      * the first step is to determine
  931.      * how many levels of indirection.
  932.      */
  933.     sh = 0;
  934.     nb = 1;
  935.     bn -= NADDR-3;
  936.     for(j=3; j>0; j--) {
  937.         sh += NSHIFT;
  938.         nb <<= NSHIFT;
  939.         if(bn < nb)
  940.             break;
  941.         bn -= nb;
  942.     }
  943.     if(j == 0) {
  944.         return((daddr_t)0);
  945.     }
  946.  
  947.     /*
  948.      * fetch the address from the inode
  949.      */
  950.     if((nb = iaddr[NADDR-j]) == 0) {
  951.         iaddr[NADDR-j] = nb = balloc();
  952.     }
  953.  
  954.     /*
  955.      * fetch through the indirect blocks
  956.      */
  957.     for(; j<=3; j++) {
  958.         dread(nb, (char *)indir, BSIZE);
  959.         sh -= NSHIFT;
  960.         i = (bn>>sh) & NMASK;
  961.         nnb = indir[i];
  962.         if(nnb == 0) {
  963.             nnb = balloc();
  964.             indir[i] = nnb;
  965.             dwrite(nb, (char *)indir);
  966.         }
  967.         nb = nnb;
  968.     }
  969.     return(nb);
  970. }
  971.  
  972. /*
  973.  * read the tape into buf, then return whether or
  974.  * or not it is a header block.
  975.  */
  976. gethead(buf)
  977. struct spcl *buf;
  978. {
  979.     readtape((char *)buf);
  980.     if (buf->c_magic != MAGIC || checksum((int *) buf) == 0)
  981.         return(0);
  982.     return(1);
  983. }
  984.  
  985. /*
  986.  * return whether or not the buffer contains a header block
  987.  */
  988. ishead(buf)
  989. struct spcl *buf;
  990. {
  991.     if (buf->c_magic != MAGIC || checksum((int *) buf) == 0)
  992.         return(0);
  993.     return(1);
  994. }
  995.  
  996. checktype(b, t)
  997. struct    spcl *b;
  998. int    t;
  999. {
  1000.     return(b->c_type == t);
  1001. }
  1002.  
  1003.  
  1004. checksum(b)
  1005. int *b;
  1006. {
  1007.     register i, j;
  1008.  
  1009.     j = BSIZE/sizeof(int);
  1010.     i = 0;
  1011.     do
  1012.         i += *b++;
  1013.     while (--j);
  1014.     if (i != CHECKSUM) {
  1015.         printf("Checksum error %o\n", i);
  1016.         return(0);
  1017.     }
  1018.     return(1);
  1019. }
  1020.  
  1021. checkvol(b, t)
  1022. struct spcl *b;
  1023. int t;
  1024. {
  1025.     if (b->c_volume == t)
  1026.         return(1);
  1027.     return(0);
  1028. }
  1029.  
  1030. readhdr(b)
  1031. struct    spcl *b;
  1032. {
  1033.     if (gethead(b) == 0)
  1034.         return(0);
  1035.     if (checktype(b, TS_TAPE) == 0)
  1036.         return(0);
  1037.     return(1);
  1038. }
  1039.  
  1040. /*
  1041.  * The next routines are called during file extraction to
  1042.  * put the data into the right form and place.
  1043.  */
  1044. #ifndef STANDALONE
  1045. xtrfile(b, size)
  1046. char    *b;
  1047. long    size;
  1048. {
  1049.     write(ofile, b, (int) size);
  1050. }
  1051.  
  1052. null() {;}
  1053.  
  1054. skip()
  1055. {
  1056.     lseek(ofile, (long) BSIZE, 1);
  1057. }
  1058. #endif
  1059.  
  1060.  
  1061. rstrfile(b, s)
  1062. char *b;
  1063. long s;
  1064. {
  1065.     daddr_t d;
  1066.  
  1067.     d = bmap(taddr, curbno);
  1068.     dwrite(d, b);
  1069.     curbno += 1;
  1070. }
  1071.  
  1072. rstrskip(b, s)
  1073. char *b;
  1074. long s;
  1075. {
  1076.     curbno += 1;
  1077. }
  1078.  
  1079. #ifndef STANDALONE
  1080. putdir(b)
  1081. char *b;
  1082. {
  1083.     register struct direct *dp;
  1084.     register i;
  1085.  
  1086.     for (dp = (struct direct *) b, i = 0; i < BSIZE; dp++, i += sizeof(*dp)) {
  1087.         if (dp->d_ino == 0)
  1088.             continue;
  1089.         putent((char *) dp);
  1090.     }
  1091. }
  1092. #endif
  1093.  
  1094. /*
  1095.  * read/write an inode from the disk
  1096.  */
  1097. getdino(inum, b)
  1098. ino_t    inum;
  1099. struct    dinode *b;
  1100. {
  1101.     daddr_t    bno;
  1102.     char buf[BSIZE];
  1103.  
  1104.     bno = (ino - 1)/INOPB;
  1105.     bno += 2;
  1106.     dread(bno, buf, BSIZE);
  1107.     copy(&buf[((inum-1)%INOPB)*sizeof(struct dinode)], (char *) b, sizeof(struct dinode));
  1108. }
  1109.  
  1110. putdino(inum, b)
  1111. ino_t    inum;
  1112. struct    dinode *b;
  1113. {
  1114.     daddr_t bno;
  1115.     char buf[BSIZE];
  1116.  
  1117.     bno = ((ino - 1)/INOPB) + 2;
  1118.     dread(bno, buf, BSIZE);
  1119.     copy((char *) b, &buf[((inum-1)%INOPB)*sizeof(struct dinode)], sizeof(struct dinode));
  1120.     dwrite(bno, buf);
  1121. }
  1122.  
  1123. /*
  1124.  * read a bit mask from the tape into m.
  1125.  */
  1126. readbits(m)
  1127. short    *m;
  1128. {
  1129.     register i;
  1130.  
  1131.     i = spcl.c_count;
  1132.  
  1133.     while (i--) {
  1134.         readtape((char *) m);
  1135.         m += (BSIZE/(MLEN/BITS));
  1136.     }
  1137.     while (gethead(&spcl) == 0)
  1138.         ;
  1139. }
  1140.  
  1141. done()
  1142. {
  1143. #ifndef STANDALONE
  1144.     unlink(dirfile);
  1145. #endif
  1146.     exit(0);
  1147. }
  1148.