home *** CD-ROM | disk | FTP | other *** search
/ kermit.columbia.edu / kermit.columbia.edu.tar / kermit.columbia.edu / tu / tuvwta.c < prev    next >
C/C++ Source or Header  |  1988-08-16  |  14KB  |  606 lines

  1. #include <stdio.h>
  2. #define    NOKNET
  3. #define    import_spp
  4. #define    import_finfo
  5. #define    import_knames
  6. #include <iraf.h>
  7.  
  8. /*
  9.  * WTAR -- Write a UNIX tar format file (on disk, tape, or to stdout)
  10.  *
  11.  * Switches:
  12.  *        f    write to named file, otherwise write to stdout
  13.  *        t    print name of each file written
  14.  *        v    verbose; print full description of each file
  15.  *        d    print debug messages
  16.  *        o    omit binary files (e.g. when foreign host has
  17.  *              incompatible binary file format)
  18.  */
  19.  
  20. #define TBLOCK        512
  21. #define NBLOCK        20
  22. #define NAMSIZ        100
  23. #define    MAXERR        20
  24. #define    MAXTRYS        100
  25. #define    SZ_TAPEBUFFER    (TBLOCK * NBLOCK)
  26. #define    RWXR_XR_X    0755
  27.  
  28. /* File header structure.  One of these precedes each file on the tape.
  29.  * Each file occupies an integral number of TBLOCK size logical blocks
  30.  * on the tape.  The number of logical blocks per physical block is variable,
  31.  * with at most NBLOCK logical blocks per physical tape block.  Two zero
  32.  * blocks mark the end of the tar file.
  33.  */
  34. union hblock {
  35.     char dummy[TBLOCK];
  36.     struct header {
  37.         char name[NAMSIZ];    /* NULL delimited        */
  38.         char mode[8];        /* octal, ascii            */
  39.         char uid[8];
  40.         char gid[8];
  41.         char size[12];
  42.         char mtime[12];
  43.         char chksum[8];
  44.         char linkflag;
  45.         char linkname[NAMSIZ];
  46.     } dbuf;
  47. };
  48.  
  49. /* Decoded file header.
  50.  */
  51. struct fheader {
  52.     char    name[NAMSIZ];
  53.     int    mode;
  54.     int    uid;
  55.     int    gid;
  56.     int    isdir;
  57.     long    size;
  58.     long    mtime;
  59.     long    chksum;
  60.     int    linkflag;
  61.     char    linkname[NAMSIZ];
  62. };
  63.  
  64. /* Map TAR file mode bits into characters for printed output.
  65.  */
  66. struct _modebits {
  67.     int    code;
  68.     char    ch;
  69. } modebits[] = {
  70.     040000,    'd',
  71.     0400,    'r',
  72.     0200,    'w',
  73.     0100,    'x',
  74.     040,    'r',
  75.     020,    'w',
  76.     010,    'x',
  77.     04,    'r',
  78.     02,    'w',
  79.     01,    'x',
  80.     0,    0
  81. };
  82.  
  83. int    debug=NO;        /* Print debugging messages        */
  84. int    omitbinary;        /* omit binary files             */
  85. int    printfnames;        /* Print file names            */
  86. int    verbose;        /* Print everything            */
  87.  
  88. struct    fheader *curfil;
  89. int    nerrs;
  90. char    *first_file;
  91. char    tapeblock[SZ_TAPEBUFFER];
  92. char    *nextblock = NULL;
  93. int    nblocks;
  94. int    in;
  95. int    out = EOF;
  96.  
  97. extern    char *vfn2osfn();
  98. long    os_utime();
  99.  
  100.  
  101. /* MAIN -- "wtar [-tvdo] [-f tarfile] [files]".  If no files are listed the
  102.  * current directory tree is used as input.  If no output file is specified
  103.  * output is to the standard output.
  104.  */
  105. main (argc, argv)
  106. int    argc;
  107. char    *argv[];
  108. {
  109.     static    char    *def_flist[2] = { ".", NULL };
  110.     char    *argp, **flist;
  111.     int    argno, ftype, i;
  112.  
  113.     ZZSTRT();
  114.  
  115.     flist       = def_flist;
  116.     omitbinary  = NO;
  117.     printfnames = debug;
  118.     verbose     = debug;
  119.  
  120.     if (debug) {
  121.         printf ("wtar called with %d arguments:", argc);
  122.         for (argno=1;  (argp = argv[argno]) != NULL;  argno++)
  123.         printf (" %s", argp);
  124.         printf ("\n");
  125.     }
  126.  
  127.     /* Process the argument list.
  128.      */
  129.     for (argno=1;  (argp = argv[argno]) != NULL;  argno++) {
  130.         if (*argp != '-') {
  131.         flist = &argv[argno];
  132.         break;
  133.  
  134.         } else {
  135.         for (argp++;  *argp;  argp++) {
  136.             switch (*argp) {
  137.             case 'd':
  138.             debug++;
  139.             printfnames++;
  140.             verbose++;
  141.             break;
  142.             case 't':
  143.             printfnames++;
  144.             break;
  145.             case 'v':
  146.             verbose++;
  147.             break;
  148.             case 'o':
  149.             omitbinary++;
  150.             break;
  151.  
  152.             case 'f':
  153.             if (argv[argno+1]) {
  154.                 argno++;
  155.                 if (debug)
  156.                 printf ("open output file `%s'\n", argv[argno]);
  157.                 out = tape_open (argv[argno], 1);
  158.                 if (out == ERR) {
  159.                 fprintf (stderr,
  160.                     "cannot open `%s'\n", argv[argno]);
  161.                 ZZSTOP();
  162.                 exit (OSOK+1);
  163.                 }
  164.             }
  165.             break;
  166.  
  167.             default:
  168.             fprintf (stderr,
  169.                 "Warning: unknown switch -%c\n", *argp);
  170.             fflush (stderr);
  171.             }
  172.         }
  173.         }
  174.     }
  175.  
  176.     /* Write to the standard output if no output file specified.
  177.      * The filename "stdin" is reserved.
  178.      */
  179.     if (out == ERR) {
  180.         if (debug)
  181.         printf ("output defaults to stdout\n");
  182.         out = tape_open ("stdout", 1);
  183.     }
  184.  
  185.     nextblock = tapeblock;
  186.     nblocks = 0;
  187.  
  188.     /* Put each directory and file listed on the command line to 
  189.      * the tarfile.
  190.      */
  191.     for (i=0;  (argp = flist[i]) != NULL;  i++)
  192.         if ((ftype = os_filetype (argp)) == DIRECTORY_FILE)
  193.         putfiles (argp, out, "");
  194.         else
  195.         tarfileout (argp, out, ftype, "");
  196.  
  197.     /* Close the tarfile.
  198.      */
  199.     endtar (out);
  200.     tape_close (out);
  201.  
  202.     ZZSTOP();
  203.     exit (OSOK);
  204. }
  205.  
  206.  
  207. /* PUTFILES -- Put the named directory tree to the output tarfile.  We chdir
  208.  * to each subdirectory to minimize path searches and speed up execution.
  209.  */
  210. putfiles (dir, out, path)
  211. char    *dir;            /* directory name        */
  212. int    out;            /* output file            */
  213. char    *path;            /* pathname of curr. directory    */
  214. {
  215.     char    newpath[SZ_PATHNAME+1];
  216.     char    fname[SZ_PATHNAME+1];
  217.     int    ftype, dp;
  218.  
  219.     if (debug)
  220.         printf ("putfiles (%s, %d, %s)\n", dir, out, path);
  221.  
  222.     /* Put the directory file itself to the output as a file.
  223.      */
  224.     tarfileout (dir, out, DIRECTORY_FILE, path);
  225.  
  226.     if ((dp = os_diropen (dir)) == ERR) {
  227.         fprintf (stderr, "cannot open subdirectory `%s%s'\n", path, dir);
  228.         fflush (stderr);
  229.         return;
  230.     }
  231.  
  232.     sprintf (newpath, "%s%s/", path, dir);
  233.     if (debug)
  234.         printf ("change directory to %s\n", newpath);
  235.     if (os_chdir (dir) == ERR) {
  236.         os_dirclose (dp);
  237.         fprintf (stderr, "cannot change directory to `%s'\n", newpath);
  238.         fflush (stderr);
  239.         return;
  240.     }
  241.  
  242.     /* Put each file in the directory to the output file.  Recursively
  243.      * read any directories encountered.
  244.      */
  245.     while (os_gfdir (dp, fname, SZ_PATHNAME) > 0)
  246.         if ((ftype = os_filetype (fname)) == DIRECTORY_FILE)
  247.         putfiles (fname, out, newpath);
  248.         else
  249.         tarfileout (fname, out, ftype, newpath);
  250.  
  251.     if (debug)
  252.         printf ("return from subdirectory %s\n", newpath);
  253.     if (os_chdir ("..") == ERR) {
  254.         fprintf (stderr, "cannot return from subdirectory `%s'\n", newpath);
  255.         fflush (stderr);
  256.     }
  257.  
  258.     os_dirclose (dp);
  259. }
  260.  
  261.  
  262. /* TARFILEOUT -- Write the named file to the output in tar format.
  263.  */
  264. tarfileout (fname, out, ftype, path)
  265. char    *fname;            /* file to be output    */
  266. int    out;            /* output stream    */
  267. int    ftype;            /* file type        */
  268. char    *path;            /* current path        */
  269. {
  270.     struct    _finfo fi;
  271.     struct    fheader fh;
  272.     int    status;
  273.  
  274.     if (debug)
  275.         printf ("put file `%s', type %d\n", fname, ftype);
  276.  
  277.     if (ftype == BINARY_FILE && omitbinary) {
  278.         if (printfnames) {
  279.         fprintf (stderr, "omit binary file `%s'\n", fname);
  280.         fflush (stderr);
  281.         }
  282.         return;
  283.     }
  284.  
  285.     /* Get info on file to make file header.
  286.      */
  287.     ZFINFO ((PKCHAR *)vfn2osfn(fname,0), &fi, &status);
  288.     if (status == XERR) {
  289.         fprintf (stderr, "Warning: can't get info on file `%s'\n", fname);
  290.         fflush (stderr);
  291.         return;
  292.     }
  293.  
  294.     /* Format and output the file header.
  295.      */
  296.     strcpy (fh.name, path);
  297.     strcat (fh.name, fname);
  298.  
  299.     if (ftype == DIRECTORY_FILE) {
  300.         strcat (fh.name, "/");
  301.         fh.size  = 0;
  302.         fh.isdir = 1;
  303.     } else {
  304.         fh.size  = fi.fi_size;
  305.         fh.isdir = 0;
  306.     }
  307.  
  308.     os_getowner (fname, &fh.uid, &fh.gid);
  309.     fh.linkflag = 0;            /* no links allowed */
  310.     strcpy (fh.linkname, "");
  311.     fh.mode  = u_fmode  (fi.fi_perm, fi.fi_type);
  312.     fh.mtime = os_utime (fi.fi_mtime);
  313.  
  314.     if (putheader (&fh, out) == EOF)  {
  315.         fprintf (stderr, 
  316.         "Warning: could not write file header for `%s'\n", fname);
  317.         fflush (stderr);
  318.         return;
  319.     }
  320.  
  321.     /* Copy the file data.
  322.      */
  323.     if (fh.size > 0 && !fh.isdir)
  324.         copyfile (fname, &fh, ftype, out);
  325.  
  326.     if (printfnames) {
  327.         printheader (stdout, &fh, verbose);
  328.         fflush (stdout);
  329.     }
  330. }
  331.  
  332.  
  333. /* PUTHEADER -- Encode and write the file header to the output tarfile.
  334.  */
  335. putheader (fh, out)
  336. register struct    fheader *fh;    /* (input) file header        */
  337. int     out;            /* output file descriptor    */
  338. {
  339.     register char    *ip, *op;
  340.     register int    n;
  341.     union    hblock    hb;
  342.  
  343.     /* Clear the header block. */
  344.     for (n=0;  n < TBLOCK;  n++)
  345.         hb.dummy[n] = '\0';
  346.  
  347.     /* Encode the file header.
  348.      */
  349.     strcpy  (hb.dbuf.name,  fh->name);
  350.     sprintf (hb.dbuf.mode,  "%6o ",   fh->mode);
  351.     sprintf (hb.dbuf.uid,   "%6o ",   fh->uid);
  352.     sprintf (hb.dbuf.gid,   "%6o ",   fh->gid);
  353.     sprintf (hb.dbuf.size,  "%11lo ", fh->size);
  354.     sprintf (hb.dbuf.mtime, "%11lo ", fh->mtime);
  355.  
  356.     n = fh->linkflag;
  357.     if (n >= '0' && n <= '9')
  358.         hb.dbuf.linkflag = n - '0';
  359.     else
  360.         hb.dbuf.linkflag = 0;
  361.     strcpy (hb.dbuf.linkname, fh->linkname);
  362.  
  363.     /* Encode the checksum value for the file header and then
  364.      * write the field.  Calculate the checksum with the checksum
  365.      * field blanked out. Compute the actual checksum as the sum of 
  366.      * all bytes in the header block.  A sum of zero indicates the 
  367.      * end of the tar file.
  368.      */
  369.     for (n=0;  n < 8;  n++)
  370.         hb.dbuf.chksum[n] = ' ';
  371.  
  372.     sprintf (hb.dbuf.chksum, "%6.8o", cchksum (hb.dummy, TBLOCK));
  373.  
  374.     if (debug) {
  375.         printf ("File header:\n");
  376.         printf ("      name = %s\n", hb.dbuf.name);
  377.         printf ("      mode = %s\n", hb.dbuf.mode);
  378.         printf ("       uid = %s\n", hb.dbuf.uid);
  379.         printf ("       gid = %s\n", hb.dbuf.gid);
  380.         printf ("      size = %-12.12s\n", hb.dbuf.size);
  381.         printf ("     mtime = %-12.12s\n", hb.dbuf.mtime);
  382.         printf ("    chksum = %s\n", hb.dbuf.chksum);
  383.         printf ("  linkflag = %c\n", hb.dbuf.linkflag);
  384.         printf ("  linkname = %s\n", hb.dbuf.linkname);
  385.         fflush (stdout);
  386.     }
  387.  
  388.     /* Write the header to the tarfile.
  389.      */
  390.     return (putblock (out, hb.dummy));
  391. }
  392.  
  393.  
  394. /* CCHKSUM -- Compute the checksum of a byte array.
  395.  */
  396. cchksum (p, nbytes)
  397. register char    *p;
  398. register int    nbytes;
  399. {
  400.     register int    sum;
  401.  
  402.     for (sum=0;  --nbytes >= 0;  )
  403.         sum += *p++;
  404.  
  405.     return (sum);
  406. }
  407.  
  408.  
  409. /* PRINTHEADER -- Print the file header in either short or long (verbose)
  410.  * format, e.g.:
  411.  *        drwxr-xr-x  9 tody         1024 Nov  3 17:53 .
  412.  */
  413. printheader (fp, fh, verbose)
  414. FILE    *fp;            /* output file            */
  415. register struct fheader *fh;    /* file header struct        */
  416. int    verbose;        /* long format output        */
  417. {
  418.     register struct    _modebits *mp;
  419.     char    *tp, *ctime();
  420.  
  421.     if (!verbose) {
  422.         fprintf (fp, "%s\n", fh->name);
  423.         return;
  424.     }
  425.  
  426.     for (mp=modebits;  mp->code;  mp++)
  427.         fprintf (fp, "%c", mp->code & fh->mode ? mp->ch : '-');
  428.  
  429.     tp = ctime (&fh->mtime);
  430.     fprintf (fp, "%3d %4d %2d %8d %-12.12s %-4.4s %s",
  431.         fh->linkflag,
  432.         fh->uid,
  433.         fh->gid,
  434.         fh->size,
  435.         tp + 4, tp + 20,
  436.         fh->name);
  437.  
  438.     if (fh->linkflag)
  439.         fprintf (fp, " -> %s\n", fh->linkname);
  440.     else
  441.         fprintf (fp, "\n");
  442. }
  443.  
  444.  
  445. /* COPYFILE -- Copy bytes from the input file to the output file.  Each file
  446.  * consists of a integral number of TBLOCK size blocks on the output file.
  447.  */
  448. copyfile (fname, fh, ftype, out)
  449. char    *fname;            /* file being read from        */
  450. struct    fheader *fh;        /* file header structure    */
  451. int    ftype;            /* file type, text or binary    */
  452. int    out;            /* output file            */
  453. {
  454.     register char    *bp;
  455.     register int    i;
  456.     int    nbytes, nleft, blocks, fd, count, total, ch;
  457.     char    buf[TBLOCK*2];
  458.  
  459.     bp = buf;
  460.     total = nbytes = 0;
  461.     blocks = (fh->size + TBLOCK - 1 ) / TBLOCK;
  462.  
  463.     if ((fd = os_open (fname, 0, ftype)) == ERR) {
  464.         fprintf (stderr, "Warning: cannot open file `%s'\n", fname);
  465.         fflush (stderr);
  466.         goto pad_;
  467.     }
  468.  
  469.     while (blocks > 0) {
  470.         if ((count = os_read (fd, bp, TBLOCK)) == ERR || count > TBLOCK) {
  471.         fprintf (stderr, "Warning: file read error on `%s'\n", fname);
  472.         fflush (stderr);
  473.         if (nerrs++ > MAXERR) {
  474.             fprintf (stderr, "Too many errors\n");
  475.             exit (OSOK+1);
  476.         }
  477.         } else {
  478.         /* Buffer input to TBLOCK blocks.
  479.          */
  480.         if (count == 0)        /* EOF */
  481.             break;
  482.         else if ((nbytes += count) < TBLOCK)
  483.             bp += count;
  484.         else {    
  485.             putblock (out, buf);
  486.             blocks--;
  487.  
  488.             /* Copy overflow back to beginning... */
  489.             if (nbytes > TBLOCK) {
  490.             nleft = nbytes - TBLOCK;
  491.             os_amovb (&buf[TBLOCK], buf, nbytes - TBLOCK);
  492.             } else
  493.             nleft = 0;
  494.  
  495.             bp = (char *) ((int)buf + nleft);
  496.             total += nbytes;
  497.             nbytes = nleft;
  498.         }
  499.         }
  500.     }
  501.  
  502.     os_close (fd);
  503.  
  504.     /* Fill current block and subsequent full blocks until the number of
  505.      * bytes specified in the file header have been output.  All files
  506.      * occupy an integral number of 512 byte blocks on tape.  For text
  507.      * files, pad with spaces, otherwise pad with nulls.  Also, for text
  508.      * files, add newlines to avoid excessively long lines.
  509.      */
  510. pad_:
  511.     ch = (ftype == TEXT_FILE) ? ' ' : '\0';
  512.     while (blocks > 0) {
  513.         for (i=nbytes;  i < TBLOCK;  i++)
  514.         if (ftype == TEXT_FILE && i % 64 == 0)
  515.             buf[i] = '\n';
  516.         else
  517.             buf[i] = ch;
  518.  
  519.         if (ftype == TEXT_FILE)
  520.         buf[TBLOCK-1] = '\n';
  521.  
  522.         putblock (out, buf);
  523.         blocks--;
  524.         nbytes = 0;
  525.     }
  526. }
  527.  
  528.  
  529. /* PUTBLOCK -- Write a block to tape (buffered).
  530.  */
  531. putblock (out, buf)
  532. int    out;
  533. char    *buf;
  534. {
  535.     int    nbytes = 0;
  536.  
  537.     if (buf) {
  538.         os_amovb (buf, nextblock, TBLOCK);
  539.         nextblock += TBLOCK;
  540.         if (++nblocks == NBLOCK)
  541.         nbytes = SZ_TAPEBUFFER;
  542.     } else
  543.         nbytes = nblocks * TBLOCK;
  544.  
  545.     if (nbytes > 0) {
  546.         if (tape_write (out, tapeblock, nbytes) < nbytes) {
  547.         fprintf (stderr, "Warning: write error on tarfile\n");
  548.         fflush (stderr);
  549.         }
  550.  
  551.         nextblock = tapeblock;
  552.         nblocks = 0;
  553.     }
  554.  
  555.     return (TBLOCK);
  556. }
  557.  
  558.  
  559. /* ENDTAR -- Write the end of the tar file, i.e., two zero blocks.
  560.  */
  561. endtar (out)
  562. int    out;
  563. {
  564.     register int  i;
  565.     union    hblock hb;
  566.  
  567.     if (debug)
  568.         printf ("write end of tar file\n");
  569.  
  570.     for (i=0;  i < TBLOCK;  i++)
  571.         hb.dummy[i] = '\0';
  572.  
  573.     putblock (out, hb.dummy);    /* write 2 null blocks */
  574.     putblock (out, hb.dummy);
  575.     putblock (out, 0);        /* flush tape buffer */
  576. }
  577.  
  578.  
  579. /* U_FMODE -- Convert the IRAF file mode bits to the corresponding UNIX bits
  580.  * for the tar file header.
  581.  */
  582. u_fmode (iraf_fmode, ftype)
  583. int    iraf_fmode;
  584. int    ftype;
  585. {
  586.     register int    in = iraf_fmode;
  587.     register int    m = 0;
  588.     int    exec;
  589.  
  590.     exec = (ftype == FI_DIRECTORY || ftype == FI_EXECUTABLE);
  591.  
  592.     if (in & 001)    m |= 0400;    /* Owner READ  */
  593.     if (in & 002)      m |= 0200;    /*       WRITE */
  594.     if (exec)    m |= 0100;    /*       EXECUTE */
  595.  
  596.     if (in & 004)    m |= 040;    /* Group READ  */
  597.     if (in & 010)    m |= 020;    /*       WRITE */
  598.     if (exec)    m |= 010;    /*       EXECUTE */
  599.  
  600.     if (in & 020)    m |= 004;    /* World READ  */
  601.     if (in & 040)    m |= 002;    /*       WRITE */
  602.     if (exec)    m |= 001;    /*       EXECUTE */
  603.  
  604.     return (m);
  605. }
  606.