home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / MSDOS / WATTCP / PISA_TAR.TAR / tar / olbuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-06-24  |  11.7 KB  |  526 lines

  1. /*
  2.  * Buffer management for public domain tar.
  3.  *
  4.  * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
  5.  *
  6.  * @(#) buffer.c 1.14 10/28/86 Public Domain - gnu
  7.  */
  8.  
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <sys/types.h>        /* For non-Berkeley systems */
  12. #include <fcntl.h>
  13. #include <signal.h>
  14.  
  15. #include "tar.h"
  16. #include "port.h"
  17.  
  18. #define    STDIN    0        /* Standard input  file descriptor */
  19. #define    STDOUT    1        /* Standard output file descriptor */
  20.  
  21. #define    PREAD    0        /* Read  file descriptor from pipe() */
  22. #define    PWRITE    1        /* Write file descriptor from pipe() */
  23.  
  24. extern char    *valloc();
  25.  
  26. /*
  27.  * V7 doesn't have a #define for this.
  28.  */
  29. #ifndef O_RDONLY
  30. #define    O_RDONLY    0
  31. #endif
  32.  
  33. #define    MAGIC_STAT    105    /* Magic status returned by child, if
  34.                    it can't exec compress.  We hope compress
  35.                    never returns this status! */
  36. /*
  37.  * The record pointed to by save_rec should not be overlaid
  38.  * when reading in a new tape block.  Copy it to record_save_area first, and
  39.  * change the pointer in *save_rec to point to record_save_area.
  40.  * Saved_recno records the record number at the time of the save.
  41.  * This is used by annofile() to print the record number of a file's
  42.  * header record.
  43.  */
  44. static union record **save_rec;
  45. static union record record_save_area;
  46. static int        saved_recno;
  47.  
  48. /*
  49.  * PID of child compress program, if f_compress.
  50.  */
  51. static int    compress_pid;
  52.  
  53. /*
  54.  * Record number of the start of this block of records
  55.  */
  56. static int    baserec;
  57.  
  58. /*
  59.  * Error recovery stuff
  60.  */
  61. static int    r_error_count;
  62.  
  63.  
  64. /*
  65.  * Return the location of the next available input or output record.
  66.  */
  67. union record *
  68. findrec()
  69. {
  70.     if (ar_record == ar_last) {
  71.         flush_archive();
  72.         if (ar_record == ar_last)
  73.             return (union record *)NULL;    /* EOF */
  74.     }
  75.     return ar_record;
  76. }
  77.  
  78.  
  79. /*
  80.  * Indicate that we have used all records up thru the argument.
  81.  * (should the arg have an off-by-1? XXX FIXME)
  82.  */
  83. void
  84. userec(rec)
  85.     union record *rec;
  86. {
  87.     while(rec >= ar_record)
  88.         ar_record++;
  89.     /*
  90.      * Do NOT flush the archive here.  If we do, the same
  91.      * argument to userec() could mean the next record (if the
  92.      * input block is exactly one record long), which is not what
  93.      * is intended.
  94.      */
  95.     if (ar_record > ar_last)
  96.         abort();
  97. }
  98.  
  99.  
  100. /*
  101.  * Return a pointer to the end of the current records buffer.
  102.  * All the space between findrec() and endofrecs() is available
  103.  * for filling with data, or taking data from.
  104.  */
  105. union record *
  106. endofrecs()
  107. {
  108.     return ar_last;
  109. }
  110.  
  111.  
  112. /*
  113.  * Open an archive file.  The argument specifies whether we are
  114.  * reading or writing.
  115.  */
  116. open_archive(read)
  117.     int read;
  118. {
  119.  
  120.     if (ar_file[0] == '-' && ar_file[1] == '\0') {
  121.         if (read)    archive = STDIN;
  122.         else        archive = STDOUT;
  123.     } else if (read) {
  124.         archive = open(ar_file, O_RDONLY);
  125.     } else {
  126.         archive = creat(ar_file, 0666);
  127.     }
  128.  
  129.     if (archive < 0) {
  130.         perror(ar_file);
  131.         exit(EX_BADARCH);
  132.     }
  133. #ifdef    MSDOS
  134.     setmode(archive, O_BINARY);
  135. #endif
  136.  
  137.     /*NOSTRICT*/
  138.     ar_block = (union record *) valloc((unsigned)blocksize);
  139.     if (!ar_block) {
  140.         fprintf(stderr,
  141.         "tar: could not allocate memory for blocking factor %d\n",
  142.             blocking);
  143.         exit(EX_ARGSBAD);
  144.     }
  145.  
  146.     ar_record = ar_block;
  147.     ar_last   = ar_block + blocking;
  148.  
  149. #ifndef    MSDOS
  150.     /*
  151.      * Handle compressed archives.
  152.      *
  153.      * FIXME, currently supported for reading only.
  154.      * FIXME, writing involves forking again for a small process
  155.      * that will reblock the output of compress to the user's specs.
  156.      */
  157.     if (f_compress) {
  158.         int pipes[2];
  159.         int err;
  160.  
  161.         if (!read) {
  162.             fprintf(stderr,
  163.                 "tar: cannot write compressed archives yet.\n");
  164.             exit(EX_ARGSBAD);
  165.         }
  166.  
  167.         /* Create a pipe to get compress's output to us */
  168.         err = pipe(pipes);
  169.         if (err < 0) {
  170.             perror ("tar: cannot create pipe to compress");
  171.             exit(EX_SYSTEM);
  172.         }
  173.         
  174.         /* Fork compress process */
  175.         compress_pid = fork();
  176.         if (compress_pid < 0) {
  177.             perror("tar: cannot fork compress");
  178.             exit(EX_SYSTEM);
  179.         }
  180.  
  181.         /*
  182.          * Child process.
  183.          * 
  184.           * Move input to stdin, write side of pipe to stdout,
  185.          * then exec compress.
  186.          */
  187.         if (compress_pid == 0) {
  188.             (void) close (pipes[PREAD]);    /* We won't use it */
  189.             if (archive != STDIN) {
  190.                 (void) close(STDIN);
  191.                 err = dup(archive);
  192.                 if (err != 0) {
  193.                     perror(
  194.                      "tar: cannot dup input to stdin");
  195.                     exit(EX_SYSTEM);
  196.                 }
  197.                 (void) close(archive);
  198.             }
  199.             if (pipes[PWRITE] != STDOUT) {
  200.                 (void) close (STDOUT);
  201.                 err = dup (pipes[PWRITE]);
  202.                 if (err != STDOUT) {
  203.                     perror(
  204.                       "tar: cannot dup pipe output");
  205.                     exit(MAGIC_STAT);
  206.                 }
  207.                 (void) close (pipes[PWRITE]);
  208.             }
  209.             execlp("compress", "compress", "-d", (char *)0);
  210.             perror("tar: cannot exec compress");
  211.             exit(MAGIC_STAT);
  212.         }
  213.  
  214.         /*
  215.          * Parent process.  Clean up.
  216.          * FIXME, note that this may leave standard input closed,
  217.          * if the compressed archive was on standard input.
  218.          */
  219.         (void) close (archive);        /* Close compressed archive */
  220.         (void) close (pipes[PWRITE]);    /* Close write side of pipe */
  221.         archive = pipes[PREAD];        /* Read side is our archive */
  222.  
  223. #ifdef BSD42
  224.         f_reblock++;        /* Pipe will give random # of bytes */
  225. #endif
  226.     }
  227. #endif
  228.  
  229.     ar_reading = read;
  230.     if (read) {
  231.         ar_last = ar_block;        /* Set up for 1st block = # 0 */
  232.         flush_archive();
  233.     }
  234. }
  235.  
  236.  
  237. /*
  238.  * Remember a union record * as pointing to something that we
  239.  * need to keep when reading onward in the file.  Only one such
  240.  * thing can be remembered at once, and it only works when reading
  241.  * an archive.
  242.  */
  243. saverec(pointer)
  244.     union record **pointer;
  245. {
  246.  
  247.     save_rec = pointer;
  248.     saved_recno = baserec + ar_record - ar_block;
  249. }
  250.  
  251. /*
  252.  * Perform a write to flush the buffer.
  253.  */
  254. #ifdef    XBUF
  255. fl_write(l)
  256. #else
  257. fl_write()
  258. #endif
  259. {
  260.     int err;
  261.  
  262. #ifdef    XBUF
  263.     static long seq = 0;
  264.     static int cnt = 0;
  265.     char nbuf[20];
  266.     err = write(archive, ar_block->charptr, blocksize);
  267.     if (err == blocksize) {
  268.         if(f_xbuf && (l || cnt++ > 20)) {
  269.             cnt = 0;
  270.             close(archive);
  271.             free(ar_block);
  272.             sprintf(nbuf, "N%07ld", seq++);
  273.             if(spawnlp(0, "tarsend", "tarsend", ar_file, nbuf, 0) &&
  274.             spawnlp(0, "tarsend", "tarsend", ar_file, nbuf, 0) &&
  275.             spawnlp(0, "tarsend", "tarsend", ar_file, nbuf, 0) &&
  276.             spawnlp(0, "tarsend", "tarsend", ar_file, nbuf, 0)) {
  277.                 fprintf(stderr, "File transfer failed.\n");
  278.                 exit(EX_BADARCH);
  279.             }
  280.             open_archive(0);
  281.         }
  282.         return;
  283.     }
  284. #else
  285.     err = write(archive, ar_block->charptr, blocksize);
  286.     if (err == blocksize) return;
  287. #endif
  288.     /* FIXME, multi volume support on write goes here */
  289.     if (err < 0)
  290.         perror(ar_file);
  291.     else
  292.         fprintf(stderr, "tar: %s: write failed, short %d bytes\n",
  293.             ar_file, blocksize - err);
  294.     exit(EX_BADARCH);
  295. }
  296.  
  297.  
  298. /*
  299.  * Handle read errors on the archive.
  300.  *
  301.  * If the read should be retried, readerror() returns to the caller.
  302.  */
  303. void
  304. readerror()
  305. {
  306. #    define    READ_ERROR_MAX    10
  307.  
  308.     read_error_flag++;        /* Tell callers */
  309.  
  310.     annorec(stderr, tar);
  311.     fprintf(stderr, "Read error on ");
  312.     perror(ar_file);
  313.  
  314.     if (baserec == 0) {
  315.         /* First block of tape.  Probably stupidity error */
  316.         exit(EX_BADARCH);
  317.     }    
  318.  
  319.     /*
  320.      * Read error in mid archive.  We retry up to READ_ERROR_MAX times
  321.      * and then give up on reading the archive.  We set read_error_flag
  322.      * for our callers, so they can cope if they want.
  323.      */
  324.     if (r_error_count++ > READ_ERROR_MAX) {
  325.         annorec(stderr, tar);
  326.         fprintf(stderr, "Too many errors, quitting.\n");
  327.         exit(EX_BADARCH);
  328.     }
  329.     return;
  330. }
  331.  
  332.  
  333. /*
  334.  * Perform a read to flush the buffer.
  335.  */
  336. fl_read()
  337. {
  338.     int err;        /* Result from system call */
  339.     int left;        /* Bytes left */
  340.     char *more;        /* Pointer to next byte to read */
  341.  
  342.     /*
  343.      * Clear the count of errors.  This only applies to a single
  344.      * call to fl_read.  We leave read_error_flag alone; it is
  345.      * only turned off by higher level software.
  346.      */
  347.     r_error_count = 0;    /* Clear error count */
  348.  
  349.     /*
  350.      * If we are about to wipe out a record that
  351.      * somebody needs to keep, copy it out to a holding
  352.      * area and adjust somebody's pointer to it.
  353.      */
  354.     if (save_rec &&
  355.         *save_rec >= ar_record &&
  356.         *save_rec < ar_last) {
  357.         record_save_area = **save_rec;
  358.         *save_rec = &record_save_area;
  359.     }
  360. error_loop:
  361.     err = read(archive, ar_block->charptr, blocksize);
  362.     if (err == blocksize) return;
  363.     if (err < 0) {
  364.         readerror();
  365.         goto error_loop;    /* Try again */
  366.     }
  367.  
  368.     more = ar_block->charptr + err;
  369.     left = blocksize - err;
  370.  
  371. again:
  372.     if (0 == (((unsigned)left) % RECORDSIZE)) {
  373.         /* FIXME, for size=0, multi vol support */
  374.         /* On the first block, warn about the problem */
  375.         if (!f_reblock && baserec == 0 && f_verbose) {
  376.             annorec(stderr, tar);
  377.             fprintf(stderr, "Blocksize = %d records\n",
  378.                 err / RECORDSIZE);
  379.         }
  380.         ar_last = ar_block + ((unsigned)(blocksize - left))/RECORDSIZE;
  381.         return;
  382.     }
  383.     if (f_reblock) {
  384.         /*
  385.          * User warned us about this.  Fix up.
  386.          */
  387.         if (left > 0) {
  388. error_loop_2:
  389.             err = read(archive, more, left);
  390.             if (err < 0) {
  391.                 readerror();
  392.                 goto error_loop_2;    /* Try again */
  393.             }
  394.             if (err == 0) {
  395.                 annorec(stderr, tar);
  396.                 fprintf(stderr,
  397.         "%s: eof not on block boundary, strange...\n",
  398.                     ar_file);
  399.                 exit(EX_BADARCH);
  400.             }
  401.             left -= err;
  402.             more += err;
  403.             goto again;
  404.         }
  405.     } else {
  406.         annorec(stderr, tar);
  407.         fprintf(stderr, "%s: read %d bytes, strange...\n",
  408.             ar_file, err);
  409.         exit(EX_BADARCH);
  410.     }
  411. }
  412.  
  413.  
  414. /*
  415.  * Flush the current buffer to/from the archive.
  416.  */
  417. flush_archive()
  418. {
  419.     baserec += ar_last - ar_block;/* Keep track of block #s */
  420.     ar_record = ar_block;        /* Restore pointer to start */
  421.     ar_last = ar_block + blocking;    /* Restore pointer to end */
  422.  
  423.     if (!ar_reading) 
  424. #ifdef    XBUF
  425.         fl_write(0);
  426. #else
  427.         fl_write();
  428. #endif
  429.     else
  430.         fl_read();
  431. }
  432.  
  433. /*
  434.  * Close the archive file.
  435.  */
  436. close_archive()
  437. {
  438.     int child;
  439.     int status;
  440.  
  441. #ifdef    XBUF
  442.     if (!ar_reading) {flush_archive(); fl_write(1);}
  443. #else
  444.     if (!ar_reading) flush_archive();
  445. #endif
  446.     (void) close(archive);
  447.  
  448. #ifndef    MSDOS
  449.     if (f_compress) {
  450.         /*
  451.          * Loop waiting for the right child to die, or for
  452.          * no more kids.
  453.          */
  454.         while (((child = wait(&status)) != compress_pid) && child != -1)
  455.             ;
  456.  
  457.         if (child != -1) {
  458.             switch (TERM_SIGNAL(status)) {
  459.             case 0:        /* Terminated by itself */
  460.                 if (TERM_VALUE(status) == MAGIC_STAT) {
  461.                     exit(EX_SYSTEM);/* Child had trouble */
  462.                 }
  463.                 if (TERM_VALUE(status))
  464.                     fprintf(stderr,
  465.                   "tar: compress child returned status %d\n",
  466.                         TERM_VALUE(status));
  467.             case SIGPIPE:
  468.                 break;        /* This is OK. */
  469.  
  470.             default:
  471.                 fprintf(stderr,
  472.                  "tar: compress child died with signal %d%s\n",
  473.                  TERM_SIGNAL(status),
  474.                  TERM_COREDUMP(status)? " (core dumped)": "");
  475.             }
  476.         }
  477.     }
  478. #endif
  479. }
  480.  
  481.  
  482. /*
  483.  * Message management.
  484.  *
  485.  * anno writes a message prefix on stream (eg stdout, stderr).
  486.  *
  487.  * The specified prefix is normally output followed by a colon and a space.
  488.  * However, if other command line options are set, more output can come
  489.  * out, such as the record # within the archive.
  490.  *
  491.  * If the specified prefix is NULL, no output is produced unless the
  492.  * command line option(s) are set.
  493.  *
  494.  * If the third argument is 1, the "saved" record # is used; if 0, the
  495.  * "current" record # is used.
  496.  */
  497. void
  498. anno(stream, prefix, savedp)
  499.     FILE    *stream;
  500.     char    *prefix;
  501.     int    savedp;
  502. {
  503. #    define    MAXANNO    50
  504.     char    buffer[MAXANNO];    /* Holds annorecment */
  505. #    define    ANNOWIDTH 13
  506.     int    space;
  507.  
  508.     if (f_sayblock) {
  509.         if (prefix) {
  510.             fputs(prefix, stream);
  511.             putc(' ', stream);
  512.         }
  513.         sprintf(buffer, "rec %d: ",
  514.             savedp?    saved_recno:
  515.                 baserec + ar_record - ar_block);
  516.         fputs(buffer, stream);
  517.         space = ANNOWIDTH - strlen(buffer);
  518.         if (space > 0) {
  519.             fprintf(stream, "%*s", space, "");
  520.         }
  521.     } else if (prefix) {
  522.         fputs(prefix, stream);
  523.         fputs(": ", stream);
  524.     }
  525. }
  526.