home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / tarsrc.sit / buffer.c next >
Text File  |  1989-09-14  |  7KB  |  325 lines

  1. /*
  2.  * Macintosh Tar
  3.  *
  4.  * Modified by Craig Ruff for use on the Macintosh.
  5.  */
  6. /*
  7.  * Buffer management for public domain tar.
  8.  *
  9.  * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
  10.  *
  11.  * @(#) buffer.c 1.14 10/28/86 Public Domain - gnu
  12.  *
  13.  */
  14.  
  15. #include "tar.h"
  16.  
  17. Boolean        FlushArchive();
  18.  
  19. union record    *arBlock;    /* Start of block of archive */
  20. union record    *arRecord;    /* Current record of archive */
  21. union record    *arLast;    /* Last+1 record of archive block */
  22. char        arReading;    /* 0 writing, !0 reading archive */
  23.  
  24. /*
  25.  * The record pointed to by save_rec should not be overlaid
  26.  * when reading in a new tape block.  Copy it to record_save_area first, and
  27.  * change the pointer in *save_rec to point to record_save_area.
  28.  * Saved_recno records the record number at the time of the save.
  29.  * This is used by annofile() to print the record number of a file's
  30.  * header record.
  31.  */
  32. static union record **saveRec;
  33. static union record recordSaveArea;
  34. static int        savedRecno;
  35.  
  36. /*
  37.  * Record number of the start of this block of records
  38.  */
  39. static int    baseRec;
  40.  
  41. /*
  42.  * Return the location of the next available input or output record.
  43.  */
  44. union record *
  45. FindRec()
  46. {
  47.     if (arRecord == arLast) {
  48.         if (FlushArchive())
  49.             return((union record *) nil);
  50.             
  51.         if (arRecord == arLast)
  52.             return((union record *) nil);    /* EOF */
  53.     }
  54.  
  55.     return(arRecord);
  56. }
  57.  
  58. /*
  59.  * Indicate that we have used all records up thru the argument.
  60.  * (should the arg have an off-by-1? XXX FIXME)
  61.  */
  62. void
  63. UseRec(rec)
  64. union record *rec;
  65. {
  66.     while (rec >= arRecord)
  67.         arRecord++;
  68.     /*
  69.      * Do NOT flush the archive here.  If we do, the same
  70.      * argument to userec() could mean the next record (if the
  71.      * input block is exactly one record long), which is not what
  72.      * is intended.
  73.      */
  74.     if (arRecord > arLast) {
  75.         PgmAlert("\pUseRec", "\parRecord > arLast", nil);
  76.         return;
  77.     }
  78. }
  79.  
  80. /*
  81.  * Return a pointer to the end of the current records buffer.
  82.  * All the space between findrec() and endofrecs() is available
  83.  * for filling with data, or taking data from.
  84.  */
  85. union record *
  86. EndOfRecs()
  87. {
  88.     return(arLast);
  89. }
  90.  
  91. /*
  92.  * Open an archive file.  The argument specifies whether we are
  93.  * reading or writing.
  94.  */
  95. Boolean
  96. OpenArchive(read)
  97. int    read;
  98. {
  99.     OSErr    err;
  100.     char    *routine = "\pOpenArchive";
  101.  
  102.     /*
  103.      * Get a block buffer for use later
  104.      */
  105.     arBlock = (union record *) NewPtr((Size) blockSize);
  106.     if (arBlock == nil) {
  107.         OSAlert(routine, "\pNewPtr", "\parBlock", MemError());
  108.         return(true);
  109.     }
  110.  
  111.     arRecord = arBlock;
  112.     arLast   = arBlock + blocking;
  113.  
  114.     /*
  115.      * Try and open the archive file.
  116.      */
  117.     if (read) {
  118.         err = FSOpen(arName, arVRefNum, &archive);
  119.  
  120.     } else {
  121.         err = Create(arName, arVRefNum, (OSType)'TAR ', (OSType)'TARF');
  122.         if ((err == noErr) || (err == dupFNErr)) {
  123.             err = FSOpen(arName, arVRefNum, &archive);
  124.         }
  125.     }
  126.  
  127.     if (err != noErr) {
  128.         OSAlert(routine, "\pFSOpen or FSCreate", arName, err);
  129.         DisposPtr((Ptr) arBlock);
  130.         archive = 0;
  131.         return(true);
  132.     }
  133.  
  134.     if (!read && ((err = SetEOF(archive, 0L)) != noErr)) {
  135.         OSAlert(routine, "\pSetEOF", arName, err);
  136.         DisposPtr((Ptr) arBlock);
  137.         archive = 0;
  138.         return(true);
  139.     }
  140.     
  141.     arReading = read;
  142.     if (read) {
  143.         arLast = arBlock;        /* Set up for 1st block = # 0 */
  144.         FlushArchive();
  145.     }
  146.  
  147.     return(false);
  148. }
  149.  
  150. /*
  151.  * Remember a union record * as pointing to something that we
  152.  * need to keep when reading onward in the file.  Only one such
  153.  * thing can be remembered at once, and it only works when reading
  154.  * an archive.
  155.  */
  156. SaveRec(pointer)
  157. union record    **pointer;
  158. {
  159.     saveRec = pointer;
  160.     savedRecno = baseRec + arRecord - arBlock;
  161. }
  162.  
  163. /*
  164.  * Perform a write to flush the buffer.
  165.  */
  166. Boolean
  167. FlWrite()
  168. {
  169.     OSErr    err;
  170.     long    count;
  171.  
  172.     count = blockSize;
  173.     err = FSWrite(archive, &count, arBlock->charptr);
  174.     if ((err == noErr) && (count == blockSize))
  175.         return(false);
  176.  
  177.     if ((count != blockSize) || (err == dskFulErr))
  178.         DFAlert();
  179.     else
  180.         OSAlert("\pFLWrite", "\pFSWrite", "\pArchive write", err);
  181.         
  182.     return(true);
  183. }
  184.  
  185. /*
  186.  * Perform a read to flush the buffer.
  187.  */
  188. Boolean
  189. FlRead()
  190. {
  191.     OSErr    err;        /* Result from system call */
  192.     long    count;
  193.     int    left;        /* Bytes left */
  194.     char    *more;        /* Pointer to next byte to read */
  195.     char    *routine = "\pFlRead";
  196.  
  197.     /*
  198.      * If we are about to wipe out a record that
  199.      * somebody needs to keep, copy it out to a holding
  200.      * area and adjust somebody's pointer to it.
  201.      */
  202.     if (saveRec &&
  203.         *saveRec >= arRecord &&
  204.         *saveRec < arLast) {
  205.         recordSaveArea = **saveRec;
  206.         *saveRec = &recordSaveArea;
  207.     }
  208.  
  209.     count = blockSize;
  210.     err = FSRead(archive, &count, arBlock->charptr);
  211.     if ((err == noErr) && (count == blockSize))
  212.         return(false);
  213.  
  214.     else if ((err != noErr) && (err != eofErr)) {
  215.         OSAlert("\pReadError", "\pFSRead", "\pArchive read", err);
  216.         return(true);
  217.     }
  218.  
  219.     more = arBlock->charptr + count;
  220.     left = blockSize - count;
  221.  
  222. again:
  223.     if (0 == (((unsigned)left) % RECORDSIZE)) {
  224.         /* FIXME, for size=0, multi vol support */
  225.         /* On the first block, warn about the problem */
  226.         if (!reblock && baseRec == 0) {
  227.             char    buf[80];
  228.  
  229.             sprintf(&buf[1], "Blocksize = %ld records",
  230.                     count / (long) RECORDSIZE);
  231.             buf[0] = strlen(&buf[1]);
  232.             PgmAlert(routine, buf, nil);
  233.         }
  234.  
  235.         arLast = arBlock + ((unsigned)(blockSize - left))/RECORDSIZE;
  236.         return(false);
  237.     }
  238.  
  239.     if (reblock) {
  240.         /*
  241.          * User warned us about this.  Fix up.
  242.          */
  243.         if (left > 0) {
  244.             count = left;
  245.             err = FSRead(archive, &count, more);
  246.             if ((err != noErr) && (err != eofErr)) {
  247.                 OSAlert("\pReadError", "\pFSRead",
  248.                         "\pArchive read 2", err);
  249.                 return(true);
  250.             }
  251.             
  252.             if ((count == 0) || (err = eofErr)) {
  253.                 PgmAlert(routine, "\pEof not on block boundary",
  254.                         nil);
  255.                 return(true);
  256.             }
  257.             
  258.             left -= count;
  259.             more += count;
  260.             goto again;
  261.         }
  262.     } else {
  263.         PgmAlert(routine, "\pDid not read blocksize bytes", nil);
  264.         return(true);
  265.     }
  266. }
  267.  
  268. /*
  269.  * Flush the current buffer to/from the archive.
  270.  */
  271. Boolean
  272. FlushArchive()
  273. {
  274.     baseRec += arLast - arBlock;/* Keep track of block #s */
  275.     arRecord = arBlock;        /* Restore pointer to start */
  276.     arLast = arBlock + blocking;    /* Restore pointer to end */
  277.  
  278.     if (!arReading) 
  279.         return(FlWrite());
  280.     else
  281.         return(FlRead());
  282. }
  283.  
  284. /*
  285.  * Close the archive file.
  286.  */
  287. CloseArchive()
  288. {
  289.     if (!arReading)
  290.         (void) FlushArchive();
  291.  
  292.     DisposPtr((Ptr) arBlock);
  293.     if (archive != 0)
  294.         (void) FSClose(archive);
  295.  
  296.     archive = 0;
  297. }
  298.  
  299. /*
  300.  * bcopy and bzero compatability routines.
  301.  * These could (should) potentially be done with the Mac traps.
  302.  */
  303. char *
  304. bcopy(s1, s2, n)
  305. char *s1, *s2;
  306. register int n;
  307. {
  308.     register char *s = s1;
  309.     register char *d = s2;
  310.  
  311.     while (--n >= 0)
  312.         *d++ = *s++;
  313.  
  314.     return(s1);
  315. }
  316.  
  317. void
  318. bzero (s1, n)
  319. register char *s1;
  320. register int n;
  321. {
  322.     while (--n >= 0)
  323.         *s1++ = 0;
  324. }
  325.