home *** CD-ROM | disk | FTP | other *** search
- /*
- * Macintosh Tar
- *
- * Modified by Craig Ruff for use on the Macintosh.
- */
- /*
- * Buffer management for public domain tar.
- *
- * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
- *
- * @(#) buffer.c 1.14 10/28/86 Public Domain - gnu
- *
- */
-
- #include "tar.h"
-
- Boolean FlushArchive();
-
- union record *arBlock; /* Start of block of archive */
- union record *arRecord; /* Current record of archive */
- union record *arLast; /* Last+1 record of archive block */
- char arReading; /* 0 writing, !0 reading archive */
-
- /*
- * The record pointed to by save_rec should not be overlaid
- * when reading in a new tape block. Copy it to record_save_area first, and
- * change the pointer in *save_rec to point to record_save_area.
- * Saved_recno records the record number at the time of the save.
- * This is used by annofile() to print the record number of a file's
- * header record.
- */
- static union record **saveRec;
- static union record recordSaveArea;
- static int savedRecno;
-
- /*
- * Record number of the start of this block of records
- */
- static int baseRec;
-
- /*
- * Return the location of the next available input or output record.
- */
- union record *
- FindRec()
- {
- if (arRecord == arLast) {
- if (FlushArchive())
- return((union record *) nil);
-
- if (arRecord == arLast)
- return((union record *) nil); /* EOF */
- }
-
- return(arRecord);
- }
-
- /*
- * Indicate that we have used all records up thru the argument.
- * (should the arg have an off-by-1? XXX FIXME)
- */
- void
- UseRec(rec)
- union record *rec;
- {
- while (rec >= arRecord)
- arRecord++;
- /*
- * Do NOT flush the archive here. If we do, the same
- * argument to userec() could mean the next record (if the
- * input block is exactly one record long), which is not what
- * is intended.
- */
- if (arRecord > arLast) {
- PgmAlert("\pUseRec", "\parRecord > arLast", nil);
- return;
- }
- }
-
- /*
- * Return a pointer to the end of the current records buffer.
- * All the space between findrec() and endofrecs() is available
- * for filling with data, or taking data from.
- */
- union record *
- EndOfRecs()
- {
- return(arLast);
- }
-
- /*
- * Open an archive file. The argument specifies whether we are
- * reading or writing.
- */
- Boolean
- OpenArchive(read)
- int read;
- {
- OSErr err;
- char *routine = "\pOpenArchive";
-
- /*
- * Get a block buffer for use later
- */
- arBlock = (union record *) NewPtr((Size) blockSize);
- if (arBlock == nil) {
- OSAlert(routine, "\pNewPtr", "\parBlock", MemError());
- return(true);
- }
-
- arRecord = arBlock;
- arLast = arBlock + blocking;
-
- /*
- * Try and open the archive file.
- */
- if (read) {
- err = FSOpen(arName, arVRefNum, &archive);
-
- } else {
- err = Create(arName, arVRefNum, (OSType)'TAR ', (OSType)'TARF');
- if ((err == noErr) || (err == dupFNErr)) {
- err = FSOpen(arName, arVRefNum, &archive);
- }
- }
-
- if (err != noErr) {
- OSAlert(routine, "\pFSOpen or FSCreate", arName, err);
- DisposPtr((Ptr) arBlock);
- archive = 0;
- return(true);
- }
-
- if (!read && ((err = SetEOF(archive, 0L)) != noErr)) {
- OSAlert(routine, "\pSetEOF", arName, err);
- DisposPtr((Ptr) arBlock);
- archive = 0;
- return(true);
- }
-
- arReading = read;
- if (read) {
- arLast = arBlock; /* Set up for 1st block = # 0 */
- FlushArchive();
- }
-
- return(false);
- }
-
- /*
- * Remember a union record * as pointing to something that we
- * need to keep when reading onward in the file. Only one such
- * thing can be remembered at once, and it only works when reading
- * an archive.
- */
- SaveRec(pointer)
- union record **pointer;
- {
- saveRec = pointer;
- savedRecno = baseRec + arRecord - arBlock;
- }
-
- /*
- * Perform a write to flush the buffer.
- */
- Boolean
- FlWrite()
- {
- OSErr err;
- long count;
-
- count = blockSize;
- err = FSWrite(archive, &count, arBlock->charptr);
- if ((err == noErr) && (count == blockSize))
- return(false);
-
- if ((count != blockSize) || (err == dskFulErr))
- DFAlert();
- else
- OSAlert("\pFLWrite", "\pFSWrite", "\pArchive write", err);
-
- return(true);
- }
-
- /*
- * Perform a read to flush the buffer.
- */
- Boolean
- FlRead()
- {
- OSErr err; /* Result from system call */
- long count;
- int left; /* Bytes left */
- char *more; /* Pointer to next byte to read */
- char *routine = "\pFlRead";
-
- /*
- * If we are about to wipe out a record that
- * somebody needs to keep, copy it out to a holding
- * area and adjust somebody's pointer to it.
- */
- if (saveRec &&
- *saveRec >= arRecord &&
- *saveRec < arLast) {
- recordSaveArea = **saveRec;
- *saveRec = &recordSaveArea;
- }
-
- count = blockSize;
- err = FSRead(archive, &count, arBlock->charptr);
- if ((err == noErr) && (count == blockSize))
- return(false);
-
- else if ((err != noErr) && (err != eofErr)) {
- OSAlert("\pReadError", "\pFSRead", "\pArchive read", err);
- return(true);
- }
-
- more = arBlock->charptr + count;
- left = blockSize - count;
-
- again:
- if (0 == (((unsigned)left) % RECORDSIZE)) {
- /* FIXME, for size=0, multi vol support */
- /* On the first block, warn about the problem */
- if (!reblock && baseRec == 0) {
- char buf[80];
-
- sprintf(&buf[1], "Blocksize = %ld records",
- count / (long) RECORDSIZE);
- buf[0] = strlen(&buf[1]);
- PgmAlert(routine, buf, nil);
- }
-
- arLast = arBlock + ((unsigned)(blockSize - left))/RECORDSIZE;
- return(false);
- }
-
- if (reblock) {
- /*
- * User warned us about this. Fix up.
- */
- if (left > 0) {
- count = left;
- err = FSRead(archive, &count, more);
- if ((err != noErr) && (err != eofErr)) {
- OSAlert("\pReadError", "\pFSRead",
- "\pArchive read 2", err);
- return(true);
- }
-
- if ((count == 0) || (err = eofErr)) {
- PgmAlert(routine, "\pEof not on block boundary",
- nil);
- return(true);
- }
-
- left -= count;
- more += count;
- goto again;
- }
- } else {
- PgmAlert(routine, "\pDid not read blocksize bytes", nil);
- return(true);
- }
- }
-
- /*
- * Flush the current buffer to/from the archive.
- */
- Boolean
- FlushArchive()
- {
- baseRec += arLast - arBlock;/* Keep track of block #s */
- arRecord = arBlock; /* Restore pointer to start */
- arLast = arBlock + blocking; /* Restore pointer to end */
-
- if (!arReading)
- return(FlWrite());
- else
- return(FlRead());
- }
-
- /*
- * Close the archive file.
- */
- CloseArchive()
- {
- if (!arReading)
- (void) FlushArchive();
-
- DisposPtr((Ptr) arBlock);
- if (archive != 0)
- (void) FSClose(archive);
-
- archive = 0;
- }
-
- /*
- * bcopy and bzero compatability routines.
- * These could (should) potentially be done with the Mac traps.
- */
- char *
- bcopy(s1, s2, n)
- char *s1, *s2;
- register int n;
- {
- register char *s = s1;
- register char *d = s2;
-
- while (--n >= 0)
- *d++ = *s++;
-
- return(s1);
- }
-
- void
- bzero (s1, n)
- register char *s1;
- register int n;
- {
- while (--n >= 0)
- *s1++ = 0;
- }
-