jac@yoko.rutgers.edu (Jonathan A. Chandross) (05/02/91)
Submitted-by: Andy McFadden (fadden@cory.berkeley.edu)
Posting-number: Volume 1, Source:34
Archive-name: archive/unix/nulib/part03.10
Architecture: UNIX
Version-number: 3.03
=nuread.c
-/*
- * nuread.c - read NuFX archives (header info only) into structures
- *
- * NuLib v3.0 February 1991 Freeware (distribute, don't sell)
- * By Andy McFadden (fadden@cory.berkeley.edu)
- */
-#ifdef APW
-segment "NuMain"
-#endif
-
-#include "nudefs.h"
-#include <stdio.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#ifdef MSDOS /* For file IO */
-# include <stdlib.h> /* errno, among others */
-# include <string.h>
-# include <io.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
-#ifdef CRC_TAB
-# include "crc.h" /* fast CRC lookup */
-#endif
-#include "nuread.h"
-#include "nupak.h" /* uses PAKBUFSIZ */
-#include "nuetc.h"
-
-#define UNKNOWN_FN "<No Filename>"
-
-/* quick proc to save x00 bytes of static storage */
-void OtherArc(str1, str2)
-{
- fprintf(stderr, "File may be %s; try \"%s\".\n", str1, str2);
-}
-
-/* swap two bytes if HiLo is TRUE */
-void HiSwap(ptr, a, b)
-onebyt *ptr;
-register onebyt a, b;
-{
- register onebyt tmp;
-
- if (HiLo) {
- tmp = ptr[a], ptr[a] = ptr[b], ptr[b] = tmp;
- }
-}
-
-
-/* copy bytes from buffer to buffer, reversing byte order if necessary */
-void BCopy(srcptr, destptr, num, order)
-onebyt *srcptr, *destptr;
-register int num;
-BOOLEAN order; /* true if byte ordering is important */
-{
- register int i = num--;
-
- if (order && HiLo) {
- while (i--) { /* copy & reverse */
- *(destptr+i) = *(srcptr + num - i); /* dest+3 = src + 3 - 3 .. */
- }
- } else if (order) {
- while (i--) { /* copy only */
- *(destptr+i) = *(srcptr + i);
- }
- } else {
- while (i--) { /* byte ordering not important; just copy */
- *(destptr+i) = *(srcptr+i);
- }
- }
-}
-
-
-/*
- * Calculate CRC on a region
- *
- * A CRC is the result of a mathematical operation based on the
- * coefficients of a polynomial when multiplied by X^16 then divided by
- * the generator polynomial (X^16 + X^12 + X^5 + 1) using modulo two
- * arithmetic.
- *
- * This routine is a slightly modified verison of one found in:
- * _Advanced Programming Techniques for the Apple //gs Toolbox_
- * By Morgan Davis and Dan Gookin (Compute! Publications, Inc.)
- * It can either calculate the CRC bit-by-bit or use a table.
- * [ one of the few //gs books worth the money +atm ]
- */
-twobyt CalcCRC(seed, ptr, count)
-twobyt seed; /* initial value for CRC */
-onebyt *ptr; /* pointer to start of data buffer */
-int count; /* number of bytes to scan through - note 64K max */
-{
- register int x;
- register twobyt CRC = seed;
-
- do {
-#ifndef CRC_TAB
- CRC ^= *ptr++ << 8; /* XOR hi-byte of CRC w/data */
- for (x = 8; x; --x) /* Then, for 8 bit shifts... */
- if (CRC & 0x8000) /* Test hi order bit of CRC */
- CRC = CRC << 1 ^ 0x1021; /* if set, shift & XOR w/$1021 */
- else
- CRC <<= 1; /* Else, just shift left once. */
-#else
- CRC = updcrc(*ptr++, CRC); /* look up new value in table */
-#endif
- } while (--count);
- return (CRC);
-}
-
-
-/*
- * Test an archive's integrity.
- *
- * Reads the entire file, and checks CRCs for certain things.
- */
-void NuTest(filename, options)
-char *filename;
-char *options;
-{
- ListHdr *archive;
- onebyt *copybuf; /* buffer for reading record */
- int partial; /* size for partial read */
- unsigned int rec;
- RNode *RNodePtr;
- MHblock *MHptr;
- TNode *TNodePtr;
- long hdr_size, total_size, thread_size;
- int srcfd; /* file descriptor */
- int thread;
- twobyt CRC, RecordCRC;
- long CRCsum = 0L; /* sum of CRCs for all records */
- BOOLEAN check_thread_crc; /* TRUE if we want to check a give thread */
- static char *procName = "NuTest";
-
- printf("Testing %s", filename);
- if (verbose) printf("\n");
- else { printf("..."); fflush(stdout); }
-
- archive = NuRead(filename); /* this catches most errors... */
-
- MHptr = archive->MHptr;
- RNodePtr = archive->RNodePtr;
- copybuf = (onebyt *) Malloc(PAKBUFSIZ);
- if ((srcfd = open(filename, O_RDONLY | O_BINARY)) < 0)
- Fatal("Unable to close archive", procName);
- if (lseek(srcfd, (long) MHsize, S_ABS) < 0) /* seek past master block */
- Fatal("Bad seek (MH)", procName);
-
- for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) {
- if (verbose) printf("Record %d (%s): ", rec, RNodePtr->filename);
- hdr_size = (long) RNodePtr->RHptr->attrib_count;
- hdr_size += (long) RNodePtr->filename_length;
- total_size = hdr_size;
- TNodePtr = RNodePtr->TNodePtr;
- for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){
- if (TNodePtr == (TNode *) NULL) {
- fprintf(stderr, "Internal error: Bad thread structure\n");
- Quit(-1);
- }
- hdr_size += (long) THsize;
- total_size += (long) THsize;
- total_size += TNodePtr->THptr->comp_thread_eof;
- TNodePtr = TNodePtr->TNext;
- }
- if (verbose) {
- printf("total record size = %ld (%d threads)\n", total_size,
- (int) RNodePtr->RHptr->total_threads);
- fflush(stdout);
- }
-
- /* read record header */
- RecordCRC = 0;
- while (hdr_size != 0L) {
- if (hdr_size > (long) PAKBUFSIZ) {
- partial = (unsigned int) PAKBUFSIZ;
- hdr_size -= (long) PAKBUFSIZ;
- } else {
- partial = (unsigned int) hdr_size;
- hdr_size = 0L;
- }
-
- if (read(srcfd, copybuf, partial) != partial) {
- fprintf(stderr, ">>> Read error");
- if (verbose) fprintf(stderr, "\n");
- else fprintf(stderr,
- " - record %d (%s)\n", rec, RNodePtr->filename);
- fprintf(stderr, "Operation aborted.\n");
- Quit(-1);
- }
- if (verbose) RecordCRC = CalcCRC(CRC, (onebyt *) copybuf, partial);
- }
-
- TNodePtr = RNodePtr->TNodePtr;
- for (thread=0; thread < (int)RNodePtr->RHptr->total_threads; thread++){
- if (lseek(srcfd, (long) TNodePtr->fileposn, S_ABS) < 0)
- Fatal("whoops!", procName);
- thread_size = TNodePtr->THptr->comp_thread_eof;
-
- /* decide whether or not to check thread CRCs */
- check_thread_crc = FALSE;
- if (RNodePtr->RHptr->version_number >= 2) /* valid CRCs */
- if (TNodePtr->THptr->thread_class == 2) /* data_thread */
- check_thread_crc = TRUE;
- if (RNodePtr->RHptr->version_number == 3) /* CRC of uncom data */
- if (TNodePtr->THptr->thread_format != 0x0000)
- check_thread_crc = FALSE; /* can't check comp */
-
- if (check_thread_crc) CRC = 0xffff;
- while (thread_size != 0L) {
- if (thread_size > (long) PAKBUFSIZ) {
- partial = (unsigned int) PAKBUFSIZ;
- thread_size -= (long) PAKBUFSIZ;
- } else {
- partial = (unsigned int) thread_size;
- thread_size = 0L;
- }
-
- if (read(srcfd, copybuf, partial) != partial) {
- fprintf(stderr, ">>> Read error in thread");
- if (verbose) fprintf(stderr, " %d\n", thread);
- else fprintf(stderr, " - record %d (%s), thread %d\n",
- rec, RNodePtr->filename, thread);
- fprintf(stderr, "Operation aborted.\n");
- Quit(-1);
- }
-
- if (verbose)
- RecordCRC = CalcCRC(RecordCRC, (onebyt *)copybuf, partial);
-
- /* calculate CRC for thread, and compare with thread_crc */
- if (check_thread_crc)
- CRC = CalcCRC(CRC, (onebyt *) copybuf, partial);
-#ifdef DEBUG
- printf(
-"At posn %ld: rec %d/thread %d (%ld bytes) CalcCRC = 0x%.4x (0x%.4x)\n",
-TNodePtr->fileposn, rec, thread, thread_size, CRC, TNodePtr->THptr->thread_crc
- );
-#endif
- }
-
- /* check and see if CRC matches */
- if (check_thread_crc) {
- if (CRC != TNodePtr->THptr->thread_crc) {
- fprintf(stderr, ">>> Bad CRC for thread %d",
- thread);
- if (verbose) fprintf(stderr, "\n");
- else fprintf(stderr, " in record %d\n", rec);
- } else {
- if (verbose) printf("--- CRC matched for thread %d\n",
- thread);
- }
- }
- TNodePtr = TNodePtr->TNext;
- }
-
- if (verbose) {
- printf("--- CRC for entire record was $%.4x\n", RecordCRC);
- CRCsum += RecordCRC;
- }
- RNodePtr = RNodePtr->RNext;
- }
- if (close(srcfd) < 0)
- Fatal("Unable to close archive", procName);
-
- free(copybuf);
- if (verbose) printf("Sum of CRCs = $%.8lx\n", CRCsum);
- printf("done.\n");
-}
-
-
-/*
- * Read thread header data, and skip data fields
- */
-
-static TNode *ReadThreads(fd, RHptr, RNodePtr, CRC_ptr)
-int fd;
-RHblock *RHptr;
-RNode *RNodePtr;
-twobyt *CRC_ptr; /* CRC seed; result is returned thru this */
-{
- int i;
- unsigned int size;
- BOOLEAN first;
- TNode *TNodePtr, *THeadPtr = (TNode *) NULL;
- THblock *THptr;
- char filebuf[THsize];
- twobyt CRC = *CRC_ptr;
- static char *procName = "ReadThreads";
-
- RNodePtr->unc_len = 0L;
- RNodePtr->comp_len = 0L;
- first = TRUE;
- for (i = 0; i < RHptr->total_threads; i++) {
- if (first) { /* create first block, or... */
- TNodePtr = (TNode *) Malloc(sizeof(TNode));
- THeadPtr = TNodePtr;
- first = FALSE;
- } else { /* create next block and go on */
- TNodePtr->TNext = (TNode *) Malloc(sizeof(TNode));
- TNodePtr = TNodePtr->TNext;
- }
- TNodePtr->TNext = (TNode *) NULL;
-
- /* Create the thread header block, and read it in */
- TNodePtr->THptr = (THblock *) Malloc(sizeof(THblock));
- THptr = TNodePtr->THptr;
-
- if (size = read(fd, filebuf, THsize) < THsize) { /* should be 16 */
- printf("read size = %d, THsize = %d\n", size, THsize);
- Fatal("ReadThread (THblock)", procName);
- }
- CRC = CalcCRC(CRC, (onebyt *) filebuf, 16); /* hdr CRC part(s) 5/5 */
-
- /* copy all fields... */
- BCopy(filebuf+0, (onebyt *) &THptr->thread_class, 2, TRUE);
- BCopy(filebuf+2, (onebyt *) &THptr->thread_format, 2, TRUE);
- BCopy(filebuf+4, (onebyt *) &THptr->thread_kind, 2, TRUE);
- BCopy(filebuf+6, (onebyt *) &THptr->thread_crc, 2, TRUE);
- BCopy(filebuf+8, (onebyt *) &THptr->thread_eof, 4, TRUE);
- BCopy(filebuf+12, (onebyt *) &THptr->comp_thread_eof, 4, TRUE);
-
- RNodePtr->unc_len += THptr->thread_eof;
- RNodePtr->comp_len += THptr->comp_thread_eof;
- if (THptr->comp_thread_eof > 2097152L) /* SANITY CHECK */
- fprintf(stderr, "Sanity check: found comp_thread_eof > 2MB\n");
- }
-
- /* skip the actual data */
- TNodePtr = THeadPtr;
- for (i = 0; i < RHptr->total_threads; i++) {
- THptr = TNodePtr->THptr;
- if ((TNodePtr->fileposn = lseek(fd, 0L, S_REL)) < 0)
- Fatal("Bad thread posn lseek()", procName);
-
- /* pull filenames out of threads, if present */
- if (THptr->thread_class == 0x0003) { /* filename thread */
- RNodePtr->filename = (char *) Malloc(THptr->thread_eof +1);
- if (read(fd, RNodePtr->filename, THptr->thread_eof) < 0) {
- fprintf(stderr, "Error on thread %d\n", i);
- Fatal("Unable to read filename", procName);
- }
- RNodePtr->filename[THptr->thread_eof] = '\0';
- RNodePtr->real_fn_length = THptr->thread_eof;
-
- { /* patch to fix bug in ShrinkIt v3.0.0 */
- int j, name_len = strlen(RNodePtr->filename);
-
- for (j = 0; j < name_len; j++) {
- RNodePtr->filename[j] &= 0x7f; /* clear hi bit */
- }
- }
-
- if (lseek(fd, TNodePtr->fileposn, S_ABS) < 0)
- Fatal("Unable to seek back after fn", procName);
- }
- if (lseek(fd, THptr->comp_thread_eof, S_REL) < 0)
- Fatal("Bad skip-thread seek", procName);
- TNodePtr = TNodePtr->TNext;
- }
- *CRC_ptr = CRC;
- return (THeadPtr);
-}
-
-
-/*
- * Read header data from a NuFX archive into memory
- */
-ListHdr *NuRead(filename)
-char *filename;
-{
- int fd; /* archive file descriptor */
- char namebuf[MAXFILENAME];
- int rec, num;
- BOOLEAN first;
- twobyt namelen;
- twobyt CRC;
- ListHdr *ListPtr; /* List Header struct */
- MHblock *MHptr; /* Master Header block */
- RNode *RNodePtr; /* Record Node */
- RHblock *RHptr; /* Record Header block */
- onebyt filebuf[RECBUFSIZ]; /* must be > RH, MH, or atts-RH size */
- static char *procName = "NuRead";
-
- ListPtr = (ListHdr *) Malloc(sizeof(ListHdr)); /* create head of list */
- ListPtr->arc_name = (char *) Malloc(strlen(filename)+1); /* archive fnam */
- strcpy(ListPtr->arc_name, filename);
- ListPtr->MHptr = (MHblock *) Malloc(sizeof(MHblock)); /* master block */
-
- if ((fd = open(filename, O_RDONLY | O_BINARY)) < 0) {
- if (errno == ENOENT) {
- fprintf(stderr, "%s: can't find file '%s'\n", prgName, filename);
- Quit (-1);
- } else
- Fatal("Unable to open archive", procName);
- }
-
- /* create and read the master header block */
- MHptr = ListPtr->MHptr;
- if (read(fd, filebuf, MHsize) < MHsize) {
- fprintf(stderr, "File '%s' may not be a NuFX archive\n", filename);
- Fatal("Unable to read Master Header Block", procName);
- }
-
- CRC = CalcCRC(0, (onebyt *) filebuf+8, MHsize-8); /* master header CRC */
-
- /* Copy data to structs, correcting byte ordering if necessary */
- BCopy(filebuf+0, (onebyt *) MHptr->ID, 6, FALSE);
- BCopy(filebuf+6, (onebyt *) &MHptr->master_crc, 2, TRUE);
- BCopy(filebuf+8, (onebyt *) &MHptr->total_records, 4, TRUE);
- BCopy(filebuf+12, (onebyt *) &MHptr->arc_create_when, sizeof(Time), FALSE);
- BCopy(filebuf+20, (onebyt *) &MHptr->arc_mod_when, sizeof(Time), FALSE);
- BCopy(filebuf+28, (onebyt *) &MHptr->master_version, 2, TRUE);
- BCopy(filebuf+30, (onebyt *) MHptr->reserved1, 8, FALSE);
- BCopy(filebuf+38, (onebyt *) &MHptr->master_eof, 4, TRUE); /* m_v $0001 */
- BCopy(filebuf+42, (onebyt *) MHptr->reserved2, 6, FALSE);
-
- if (strncmp(MHptr->ID, MasterID, 6)) {
- fprintf(stderr, "\nFile '%s' is not a NuFX archive\n", filename);
- if ((filebuf[0] == 10) && (filebuf[1] == 71) &&
- (filebuf[2] == 76) && (filebuf[18] == 2))
-#ifdef NO_BLU
- OtherArc("Binary II", "unblu");
-#else
- fprintf(stderr, "File may be Binary II; try 'B' option\n");
-#endif
- if ((filebuf[0] == '\037') && (filebuf[1] == '\036'))
- OtherArc("packed", "unpack");
- if ((filebuf[0] == (onebyt)'\377') && (filebuf[1] == '\037'))
- OtherArc("compacted", "uncompact");
- if ((filebuf[0] == '\037') && (filebuf[1] == (onebyt)'\235'))
- OtherArc("compressed", "uncompress");
- if ((filebuf[0] == 0x76) && (filebuf[1] == 0xff))
- OtherArc("SQueezed", "usq");
- if ((filebuf[0] == 0x04) && (filebuf[1] == 0x03) &&
- (filebuf[2] == 0x4b) && (filebuf[3] == 0x50))
- OtherArc("a ZIP archive", "UnZip");
- if (!strncmp((char *) filebuf, "ZOO", 3)) /* zoo */
- OtherArc("a ZOO archive", "zoo");
- if ((filebuf[0] == 0x1a) && (filebuf[1] == 0x08)) /* arc */
- OtherArc("an ARC archive", "arc");
- if (!strncmp((char *) filebuf, "SIT!", 4)) /* StuffIt */
- OtherArc("a StuffIt archive", "StuffIt (Macintosh)");
- if (!strncmp((char *) filebuf, "<ar>", 4)) /* system V arch */
- OtherArc("a library archive (Sys V)", "ar");
- if (!strncmp((char *) filebuf, "!<arch>", 7))
- OtherArc("a library archive", "ar");
- if (!strncmp((char *) filebuf, "#! /bin/sh", 10) ||
- !strncmp((char *) filebuf, "#!/bin/sh", 9))
- OtherArc("a shar archive", "/bin/sh");
- if (!strncmp((char *) filebuf, "GIF87a", 6))
- OtherArc("a GIF picture", "?!?");
- /* still need ZIP */
-
- Quit (-1);
- }
-
- if (CRC != MHptr->master_crc)
- printf("WARNING: Master Header block may be corrupted (bad CRC)\n");
-
- if (MHptr->master_version > MAXMVERS)
- printf("WARNING: unknown Master Header version, trying to continue\n");
-
- /* main record read loop */
- first = TRUE;
- for (rec = 0; rec < (unsigned int) MHptr->total_records; rec++) {
- if (first) { /* allocate first, or... */
- ListPtr->RNodePtr = (RNode *) Malloc(sizeof(RNode));
- RNodePtr = ListPtr->RNodePtr;
- first = FALSE;
- } else { /* allocate next, and go on */
- RNodePtr->RNext = (RNode *) Malloc(sizeof(RNode)); /* next Rnode */
- RNodePtr = RNodePtr->RNext; /* move on to next record */
- }
- RNodePtr->RNext = (RNode *) NULL;
-
- RNodePtr->RHptr = (RHblock *) Malloc(sizeof(RHblock)); /* alloc blk */
- /* expansion here */
- RHptr = RNodePtr->RHptr;
- if (read(fd, filebuf, RHsize) < RHsize) { /* get known stuff */
- fprintf(stderr,"%s: error in record %d (at EOF?)\n", prgName, rec);
- Fatal("Bad RHblock read", procName);
- }
-
- /* rec hdr CRC part 1/5 */
- CRC = CalcCRC(0, (onebyt *) filebuf+6, RHsize-6);
-
- BCopy(filebuf+0, (onebyt *) RHptr->ID, 4, FALSE);
- BCopy(filebuf+4, (onebyt *) &RHptr->header_crc, 2, TRUE);
- BCopy(filebuf+6, (onebyt *) &RHptr->attrib_count, 2, TRUE);
- BCopy(filebuf+8, (onebyt *) &RHptr->version_number, 2, TRUE);
- BCopy(filebuf+10, (onebyt *) &RHptr->total_threads, 2, TRUE);
- BCopy(filebuf+12, (onebyt *) &RHptr->reserved1, 2, TRUE);
- BCopy(filebuf+14, (onebyt *) &RHptr->file_sys_id, 2, TRUE);
- BCopy(filebuf+16, (onebyt *) &RHptr->file_sys_info, 1, TRUE);
- BCopy(filebuf+17, (onebyt *) &RHptr->reserved2, 1, TRUE);
- BCopy(filebuf+18, (onebyt *) &RHptr->access, 4, TRUE);
- BCopy(filebuf+22, (onebyt *) &RHptr->file_type, 4, TRUE);
- BCopy(filebuf+26, (onebyt *) &RHptr->extra_type, 4, TRUE);
- BCopy(filebuf+30, (onebyt *) &RHptr->storage_type, 2, TRUE);
- BCopy(filebuf+32, (onebyt *) &RHptr->create_when, sizeof(Time), FALSE);
- BCopy(filebuf+40, (onebyt *) &RHptr->mod_when, sizeof(Time), FALSE);
- BCopy(filebuf+48, (onebyt *) &RHptr->archive_when, sizeof(Time), FALSE);
- BCopy(filebuf+56, (onebyt *) &RHptr->option_size, 2, TRUE);
- /* expansion here */
-
- if (strncmp(RHptr->ID, RecordID, 4)) {
- fprintf(stderr, "%s: Found bad record ID (#%d) -- exiting\n",
- prgName, rec);
- Quit (-1);
- }
-
- /* read remaining (unknown) attributes into buffer, if any */
- num = RHptr->attrib_count - RHsize - 2;
- if (num > RECBUFSIZ) {
- fprintf(stderr, "ERROR: attrib_count > RECBUFSIZ\n");
- Quit (-1);
- }
- if (num > 0) {
- if (read(fd, filebuf, num) < num)
- Fatal("Bad xtra attr read", procName);
- CRC = CalcCRC(CRC, (onebyt *) filebuf, num); /* hdr CRC part 2/5 */
- }
-
- if (read(fd, (char *) &namelen, 2) < 2) /* read filename len */
- Fatal("Bad namelen read", procName);
- CRC = CalcCRC(CRC, (onebyt *) &namelen, 2); /* rec hdr CRC part 3/5 */
-
- HiSwap((onebyt *) &namelen, 0, 1);
- /* read filename, and store in struct */
- if (namelen > MAXFILENAME) {
- fprintf(stderr, "ERROR: namelen > MAXFILENAME\n");
- Quit (-1);
- }
- RNodePtr->filename_length = namelen;
-
- if (namelen > 0) {
- RNodePtr->real_fn_length = namelen;
- if (read(fd, namebuf, namelen) < namelen)
- Fatal("Bad namebuf read", procName);
- /* rec hdr CRC part 4/5 */
- CRC = CalcCRC(CRC, (onebyt *) namebuf, namelen);
-
- RNodePtr->filename = (char *) Malloc(namelen+1); /* store fname */
- BCopy(namebuf, (onebyt *) RNodePtr->filename, namelen, FALSE);
- RNodePtr->filename[namelen] = '\0';
- } else {
- RNodePtr->filename = UNKNOWN_FN;
- RNodePtr->real_fn_length = strlen(UNKNOWN_FN);
- }
-
- RNodePtr->TNodePtr = ReadThreads(fd, RHptr, RNodePtr, &CRC);
- /* rec hdr CRC part 5/5 calculated by ReadThreads */
-
- if (CRC != RHptr->header_crc) {
- printf("WARNING: Detected a bad record header CRC\n");
- printf(" Rec %d in file '%.60s'\n",rec,RNodePtr->filename);
- }
- }
-
- /* begin adding new files at this point */
- if ((ListPtr->nextposn = lseek(fd, 0L, S_REL)) < 0)
- Fatal("Bad final lseek()", procName);
-
- if (close(fd) < 0) {
- Fatal("Bad close", procName);
- }
-
- if (MHptr->master_version > 0x0000) {
- if (MHptr->master_eof != ListPtr->nextposn) {
- printf("WARNING: master_eof (stored)=%ld, nextposn (actual)=%ld\n",
- MHptr->master_eof, ListPtr->nextposn);
- printf(
- " (master_eof will be fixed if archive is changed)\n");
- }
- }
-
- return (ListPtr);
-}
-
=nuext.c
-/*
- * nuext.c - operations which extract from a NuFX archive
- *
- * NuLib v3.0 February 1991 Freeware (distribute, don't sell)
- * By Andy McFadden (fadden@cory.berkeley.edu)
- */
-#ifdef APW
-segment "NuMain"
-#endif
-
-#include "nudefs.h"
-#include <stdio.h>
-#ifdef BSD43
-# include <strings.h>
-#else /* SYSV, APW, MSC */
-# include <string.h>
-#endif
-#include <fcntl.h>
-
-#ifdef UNIX
-# include <errno.h>
-# include <time.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-#ifdef APW
-# include <types.h>
-# include <prodos.h>
-# include <shell.h>
-# include <strings.h>
-#endif
-#ifdef MSDOS
-# include <io.h>
-# include <time.h>
-# include <stdlib.h>
-# include <errno.h>
-# include <direct.h>
-# include <utime.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-#endif
-
-#include "nuread.h"
-#include "nuext.h"
-#include "nupak.h"
-#include "nuetc.h"
-
-static BOOLEAN extall; /* extract all files? */
-static BOOLEAN print; /* extract to screen rather than file? */
-
-
-/*
- * Get the answer to a yes/no question.
- *
- * Returns TRUE for yes, FALSE for no. May return additional things in the
- * future... (y/n/q)?
- */
-int AskYesNo()
-{
- char buf[16]; /* if user answers with >16 chars, bad things happen */
- char c;
-
- printf(" (y/n)? ");
- fflush(stdout);
- gets(buf);
- c = *buf;
- if ((c == 'y') || (c == 'Y'))
- return (TRUE);
- else
- return (FALSE);
-}
-
-
-/*
- * Convert a filename to one legal in the present file system.
- *
- * Does not allocate new space; alters string in place (so original string
- * will be "corrupted"). Assumes that it has been passed a filename without
- * the filename separators.
- */
-void ConvFileName(str)
-char *str;
-{
- int idx = 0;
-#ifdef UNIX
-
- while (*str != '\0') {
- if ((*str > 127) || (*str < 0)) *str &= 0x7f; /* clear hi bit */
- if (*str == '/') *str = '.';
- if (++idx > 255) { *str = '\0'; break; }
- str++;
- }
-#else
-# ifdef APW
- static char *legal =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.";
-
- /* assumes ProDOS limits, not GS/OS */
- if ( ((*str < 'A') && (*str > 'Z')) || ((*str < 'a') && (*str > 'z')) )
- *str = 'X'; /* must start with alpha char */
- while (*str != '\0') {
- if (!INDEX(legal, *str)) *str = '.';
- if (++idx > 15) { *str = '\0'; break; }
- str++;
- }
-# endif /* APW */
-# ifdef MSDOS
- while (*str != '\0') {
- if ((*str > 127) || (*str < 0)) *str &= 0x7f; /* clear hi bit */
- if (*str == '/') *str = '_';
- if (*str == '\\') *str = '_';
- if (*str == '!') *str = '_';
- if (*str == ':') *str = '_';
- if (++idx > 255) { *str = '\0'; break; }
- str++;
- }
-# endif /* MSDOS */
-
-# ifndef APW
-# ifndef MSDOS
- printf("Need [other] filename converter\n"); /* +PORT+ */
-# endif /* none2 */
-# endif /* none1 */
-#endif /*UNIX*/
-}
-
-/*
- * Set a file's attributes according to info in a record structure.
- */
-void SetFInfo(filename, RHptr)
-char *filename;
-RHblock *RHptr;
-{
- static char *procName = "SetFInfo";
-#ifdef UNIX
- long ltime;
- time_t timep[2];
-
- ltime = ReduceTime(&RHptr->mod_when); /* set both to mod time */
- timep[0] = ltime; /* accessed */
- timep[1] = ltime; /* modified */
- utime(filename, timep);
-
- if ((RHptr->access == 0xe3L) || (RHptr->access == 0xc3L)) /* unlocked */
- chmod(filename, S_IREAD | S_IWRITE | 044);
- if ((RHptr->access == 0x21L) || (RHptr->access == 0x01L)) /* locked */
- chmod(filename, S_IREAD | 044);
-
-#else /* UNIX */
-# ifdef APW
- /*
- * Call ProDOS SET_FILE_INFO to set attributes for a file.
- * Uses the information in the record header block.
- */
- FileRec finfo;
- OpenRec oinfo;
- twobyt date, time;
- long ltime;
-
- finfo.pathname = c2pstr(filename); /* temp storage...? */
- finfo.fAccess = (twobyt) RHptr->access;
- finfo.fileType = (twobyt) RHptr->file_type;
- finfo.auxType = RHptr->extra_type;
- finfo.storageType = 0; /* RHptr->storage_type otherwise */
- ltime = ReduceTime(&RHptr->create_when);
- date = (twobyt) ltime; /* date is lower 16 */
- time = (twobyt) (ltime >> 16); /* time is upper */
- finfo.createDate = date;
- finfo.createTime = time;
- ltime = ReduceTime(&RHptr->mod_when);
- date = (twobyt) ltime; /* date is lower 16 */
- time = (twobyt) (ltime >> 16); /* time is upper */
- finfo.modDate = date;
- finfo.modTime = time;
-
- SET_FILE_INFO( &finfo );
- ToolErrChk();
-# endif /* APW */
-# ifdef MSDOS
- long ltime;
- time_t timep[2];
-
- ltime = ReduceTime(&RHptr->mod_when);
- timep[0] = ltime; /* accessed */
- timep[1] = ltime; /* modified */
- utime(filename, timep);
-
- if ((RHptr->access == 0xe3L) || (RHptr->access == 0xc3L)) /* unlocked */
- chmod(filename, S_IREAD | S_IWRITE | 044);
- if ((RHptr->access == 0x21L) || (RHptr->access == 0x01L)) /* locked */
- chmod(filename, S_IREAD | 044);
-# endif /* MSDOS */
-
-# ifndef APW
-# ifndef MSDOS
- printf("need [other] SetFInfo stuff\n"); /* +PORT+ */
-# endif /* none2 */
-# endif /* none1 */
-#endif /* APW */
-}
-
-
-/*
- * Create a subdirectory
- *
- * This routine will exit on most errors, since generally more than one file
- * will be unpacked to a given subdirectory, and we don't want it charging
- * bravely onward if it's going to run into the same problem every time.
- */
-void CreateSubdir(pathname)
-char *pathname;
-{
- char *buffer = (char *) Malloc(MAXFILENAME+6);
- static char *procName = "CreateSubdir";
-#ifdef UNIX
- struct stat st;
-
- /* if no directory exists, then make one */
- if (stat(pathname, &st) < 0)
- if (errno == ENOENT) {
- sprintf(buffer, "mkdir %s", pathname);
- if (system(buffer) != 0) /* call UNIX mkdir to create subdir */
- Fatal("Unable to create subdir", procName);
- } else {
- Fatal("Unable to create dir", procName);
- }
-#else
-# ifdef APW
- static FileRec create_p = { "", 0x00e3, 0x000f, 0L, 0x000d, 0, 0 }; /*dir*/
- FileRec info_p; /* check if file exists, is dir */
- int err; /* holds _toolErr */
-
- strcpy(buffer, pathname);
- c2pstr(buffer);
- info_p.pathname = buffer;
- GET_FILE_INFO( &info_p );
-
- switch (_toolErr) {
- case 0x0000: /* no error */
- if (info_p.storageType != 0x000d) /* not a DIR? */
- Fatal("File in path exists, is not a directory.", procName);
- return; /* file exists, is directory, no need to create */
-
- case fileNotFound:
- create_p.pathname = buffer;
- CREATE( &create_p );
- if (!_toolErr) return; /* created okay? */
- else ToolErrChk();
-
- default: /* unknown error */
- ToolErrChk();
- Fatal("whoops!", procName); /* shouldn't get here */
- }
-# endif /* APW */
-# ifdef MSDOS
- struct stat st;
-
- /* if no directory exists, then make one */
- if (stat(pathname, &st) < 0)
- if (errno == ENOENT) {
- if (mkdir(pathname) != 0)
- Fatal("Unable to create subdir", procName);
- } else {
- Fatal("Unable to create dir", procName);
- }
-# endif /* MSDOS */
-
-# ifndef APW
-# ifndef MSDOS
-
- /* don't forget to check if it exists first... */ /* +PORT+ */
- printf("don't know how to create [other] subdirectories\n"); /* mkdir() */
-# endif /* none2 */
-# endif /* none1 */
-#endif /* UNIX */
- free(buffer);
-}
-
-
-/*
- * Given a pathname, create subdirectories as needed. All file names are run
- * through a system-dependent filename filter, which means that the pathname
- * has to be broken down, the subdirectory created, and then the pathname
- * reconstructed with the "legal" pathname. The converted filename is held
- * in a static buffer; subsequent calls will overwrite the previous string.
- *
- * This is useful when unpacking "dir1/dir2/fubar" and dir1 and dir2 don't
- * necessarily exist.
- *
- * It is assumed that all filenames are relative to the current directory.
- * According to the NuFX docs (revision 3 2/3/89), initial separators (like
- * "/", "\", or ":") should NOT be included. If they are, this routine may
- * break.
- */
-static char *CreatePath(pathname, fssep)
-char *pathname; /* full pathname; should not include ProDOS volume name */
-onebyt fssep; /* file system pathname separator, usually "/" or "\" */
-{
- int idx;
- char *ptr;
- static char workbuf[MAXFILENAME]; /* work buffer; must be static */
- static char *procName = "CreatePath";
-
- idx = 0;
- while (TRUE) { /* move through string */
- ptr = INDEX(pathname, fssep); /* find break */
- if (ptr) /* down to actual filename? */
- *ptr = '\0'; /* no, isolate this part of the string */
-
- strcpy(&workbuf[idx], pathname); /* copy component to buf */
- ConvFileName(&workbuf[idx]); /* convert to legal str; may be shorter */
- idx += strlen(&workbuf[idx]); /* advance index to end of string */
- if (!ptr) { /* down to actual filename? */
- workbuf[idx] = '\0'; /* yes, clean up */
- break; /* out of while */
- }
- workbuf[idx] = '\0';
-
- CreateSubdir(workbuf); /* system-dependent dir create */
-
-#ifdef UNIX
- workbuf[idx++] = '/'; /* tack a filename separator on, and advance */
- *ptr = '/'; /* be nice */
-#else
-# ifdef APW
- workbuf[idx++] = '/';
- *ptr = '/';
-# endif
-# ifdef MSDOS
- workbuf[idx++] = '\';
- *ptr = '\';
-# endif
-# ifndef APW /* +PORT+ */
-# ifndef MSDOS
- workbuf[idx++] = '/';
- *ptr = '/';
-# endif
-# endif
-#endif /*UNIX*/
-
-/* was: workbuf[idx++] = fssep; /* tack an fssep on the end, and advance */
-/* was: *ptr = fssep; /* be nice */
-
- pathname = ptr+1; /* go again with next component */
- }
-
- return (workbuf);
-}
-
-
-/*
- * Extract a thread, and place in a file.
- *
- * Returns TRUE if the extract was successful, FALSE otherwise. The most
- * common reason for a FALSE return value is a "no" answer when asked about
- * overwriting an existing file.
- */
-static BOOLEAN ExtractThread(arcfd, fileposn, destpn, THptr)
-int arcfd; /* source file descriptor (must be open) */
-long fileposn; /* position of data in source file */
-char *destpn; /* destination filename */
-THblock *THptr; /* pointer to thread info */
-{
- int dstfd; /* destination file descriptor */
- static char *procName = "ExtractThread";
-
- if (!print) {
- if (Exists(destpn)) {
- if (interact) {
- if (verbose) printf("file exists, overwite");
- else printf("%s exists, overwite", destpn);
- if (!AskYesNo()) { /* return w/o overwriting */
- return (FALSE);
- }
- }
- if (verbose) { printf("overwriting..."); fflush(stdout); }
- if (unlink(destpn) < 0)
- Fatal("Unable to remove existing file", procName);
- }
-
- if ((dstfd =
- open(destpn, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, WPERMS)) < 0)
- Fatal("Unable to open target path", procName);
-
- if (lseek(arcfd, fileposn, S_ABS) < 0)
- Fatal("Seek failed", procName);
-
- if (!UnpackFile(arcfd, dstfd, THptr,
- dopack ? THptr->thread_format : 0, pakbuf)) {
- if (close(dstfd) < 0)
- Fatal("Dest close failed", procName);
- unlink(destpn); /* some sys can't delete while file open */
- } else {
- if (close(dstfd) < 0)
- Fatal("Dest close failed", procName);
- }
-
- } else { /* print */
- if ((dstfd = fileno(stdout)) < 0)
- Fatal("Unable to get file for stdout", procName);
- if (lseek(arcfd, fileposn, S_ABS) < 0)
- Fatal("Seek failed", procName);
-
- if (!UnpackFile(arcfd, dstfd, THptr,
- dopack ? THptr->thread_format : 0, pakbuf)) {
- printf("Unpack failed.\n");
- return (FALSE);
- }
- fflush(stdout);
- }
-
- return (TRUE);
-}
-
-
-/*
- * Handle message_threads
- */
-static void message_thread(arcfd, RNodePtr, TNodePtr)
-int arcfd;
-RNode *RNodePtr;
-TNode *TNodePtr;
-{
- int i;
- int oldTo, oldFrom;
- static char *procName = "message_thread";
-
- switch (TNodePtr->THptr->thread_kind) {
- case 0x0000: /* ASCII text */
- printf("Found ASCII text thread\n");
- break;
- case 0x0001: /* ASCII text, predefined size */
- if (verbose && !print && TNodePtr->THptr->thread_eof) {
- printf("\n--- Comment for file '%s':\n", RNodePtr->filename);
- fflush(stdout);
- if (lseek(arcfd, TNodePtr->fileposn, S_ABS) < 0)
- Fatal("unable to seek to comment", procName);
- oldTo = transto;
- oldFrom = transfrom;
- transto = -1; /* switch to CR -> current mode */
- transfrom = 0; /* (assumes created under ProDOS) */
- /* may need to fix this later (but how?) */
- FCopy(arcfd, fileno(stdout), TNodePtr->THptr->thread_eof,
- pakbuf, TRUE);
-#ifdef FUBAR
- print = TRUE;
- verbose = FALSE; /* turn off "unshrinking..." messages */
- ExtractThread(arcfd,TNodePtr->fileposn, "stdout", TNodePtr->THptr);
- print = FALSE;
- verbose = TRUE;
-#endif
- transto = oldTo;
- transfrom = oldFrom;
- putchar('\n');
- }
- break;
- default:
- printf("Found unknown message_thread %.4x in '%s'\n",
- TNodePtr->THptr->thread_kind, RNodePtr->filename);
- break;
- }
-}
-
-/*
- * Handle control_threads
- */
-static void control_thread(arcfd, RNodePtr, TNodePtr)
-int arcfd;
-RNode *RNodePtr;
-TNode *TNodePtr;
-{
- switch (TNodePtr->THptr->thread_kind) {
- case 0x000: /* create dir */
- printf("Found create directory control thread\n");
- break;
- default:
- printf("Found unknown control_thread %.4x in '%s'\n",
- TNodePtr->THptr->thread_kind, RNodePtr->filename);
- break;
- }
-}
-
-
-/*
- * Handle data_threads
- *
- * Does not guarantee that the archive file position is anything rational;
- * the TNode's fileposn should be (and is) used here.
- */
-static void data_thread(arcfd, RNodePtr, TNodePtr)
-int arcfd;
-RNode *RNodePtr;
-TNode *TNodePtr;
-{
- long fileposn; /* absolute position of thread in file */
- long old_eof;
- char *fn;
- int ov;
-
- if (print) /* this is something of a hack... */
- if (TNodePtr->THptr->thread_kind != 0x0000) { /* not a data fork? */
- fprintf(stderr, "Can't print non-data fork for '%s'.\n",
- RNodePtr->filename);
- return; /* this hoses the file posn... */
- } else {
- if (verbose) printf("\n***** %s *****\n", RNodePtr->filename);
- fflush(stdout);
- ov = verbose;
- verbose = FALSE; /* turn off "unshrinking..." messages */
- fileposn = TNodePtr->fileposn;
- ExtractThread(arcfd,fileposn, "stdout", TNodePtr->THptr);
- verbose = ov;
- return;
- }
-
- switch (TNodePtr->THptr->thread_kind) {
- case 0x0000: /* data fork */
- if (verbose) {
- printf("Extracting '%s' (data)...", RNodePtr->filename);
- fflush(stdout);
- }
-
- /* create any needed subdirs */
- fn = CreatePath(RNodePtr->filename, RNodePtr->RHptr->file_sys_info);
-
- /* extract the file */
- if (ExtractThread(arcfd, TNodePtr->fileposn, fn, TNodePtr->THptr)) {
- SetFInfo(fn, RNodePtr->RHptr); /* set file attributes, dates... */
- if (verbose) printf("done.\n");
- }
- break;
-
- case 0x0001: /* disk image */
-/* printf("Found disk image (not extracted)\n");*/
-
- if (verbose) {
- printf("Extracting '%s' (disk image)...", RNodePtr->filename);
- fflush(stdout);
- }
-
- /* setup path (normalize file name) */
- fn = CreatePath(RNodePtr->filename, RNodePtr->RHptr->file_sys_info);
-
- /* thread_eof is invalid for disks, so figure it out */
- old_eof = TNodePtr->THptr->thread_eof;
- if (RNodePtr->RHptr->storage_type <= 3) { /* should be block */
- TNodePtr->THptr->thread_eof = /* size, but shk301 */
- RNodePtr->RHptr->extra_type * 512; /* stored it wrong */
- } else {
- TNodePtr->THptr->thread_eof =
- RNodePtr->RHptr->extra_type * RNodePtr->RHptr->storage_type;
- }
-
- /* extract the disk into a file */
- if (ExtractThread(arcfd, TNodePtr->fileposn, fn, TNodePtr->THptr)) {
- /*SetFInfo(fn, RNodePtr->RHptr);/* set file attributes, dates... */
- if (verbose) printf("done.\n");
- }
-
- TNodePtr->THptr->thread_eof = old_eof;
- break;
-
- case 0x0002: /* resource_fork */
- printf("Found resource_fork (not extracted)\n");
- break;
- default:
- printf("Found unknown data_thread %.4x in '%s'\n",
- TNodePtr->THptr->thread_kind, RNodePtr->filename);
- break;
- }
-}
-
-
-/*
- * Extract files from archive
- *
- * Scan archive, extracting files which start with the strings in "names".
- * Calls subroutines to handle the various thread_class types.
- */
-static void Extract(filename, namecount, names)
-char *filename;
-int namecount;
-char **names;
-{
- ListHdr *archive;
- int arcfd; /* archive file descriptor */
- int rec, idx;
- MHblock *MHptr; /* Master Header block */
- RNode *RNodePtr; /* Record Node */
- TNode *TNodePtr; /* Thread block */
- int len, *lentab; /* hold strlen() of all names */
- char *pn; /* archived pathname */
- int thread; /* current thread #; max 65535 threads */
- BOOLEAN gotone = FALSE;
- static char *procName = "Extract";
-
- archive = NuRead(filename);
- if ((arcfd = open(archive->arc_name, O_RDONLY | O_BINARY)) < 0)
- Fatal("Unable to open archive", procName);
-
- pakbuf = (onebyt *) Malloc(PAKBUFSIZ); /* allocate unpack buffer */
-
- lentab = (int *) Malloc( sizeof(int) * namecount ); /* calloc() is nicer */
- for (idx = 0; idx < namecount; idx++) /* calc. once (for efficiency) */
- lentab[idx] = strlen(names[idx]);
-
- MHptr = archive->MHptr;
- RNodePtr = archive->RNodePtr;
-
- if (!namecount)
- extall = TRUE;
-
- /* main record read loop */
- for (rec = 0; rec < MHptr->total_records; rec++) {
- pn = RNodePtr->filename;
- len = strlen(pn);
- if (RNodePtr->RHptr->version_number > MAXVERS) {
- printf("Unable to extract '%s': unknown record version_number\n",
- pn);
- continue; /* with for */
- }
-
- for (idx = 0; extall || idx < namecount; idx++) { /* find arced file */
- /* try to match argument with first few chars of stored filename */
- /* or the entire filename, depending on EXPAND flag */
- if (extall || ((len >= lentab[idx]) && doExpand ?
- (!strncasecmp(pn, names[idx], lentab[idx])) :
- (!strcasecmp(pn, names[idx])) )) {
-
- gotone = TRUE;
- /* go through all threads */
- TNodePtr = RNodePtr->TNodePtr;
- for (thread = 0; thread < (int) RNodePtr->RHptr->total_threads;
- thread++) {
- switch(TNodePtr->THptr->thread_class) {
- case 0x0000:
- message_thread(arcfd, RNodePtr, TNodePtr);
- break;
- case 0x0001:
- control_thread(arcfd, RNodePtr, TNodePtr);
- break;
- case 0x0002:
- /* don't extract if doMessages is set */
- if (!doMessages)
- data_thread(arcfd, RNodePtr, TNodePtr);
- break;
- case 0x0003:
- /* filename_thread; ignore */
- break;
- default:
- printf("Unknown thread_class %.4x for '%s'\n",
- TNodePtr->THptr->thread_class, RNodePtr->filename);
- break;
- }
- TNodePtr = TNodePtr->TNext;
- }
- break; /* out of filename matching (inner) FOR loop */
- }
- }
-
- RNodePtr = RNodePtr->RNext; /* move on to next record */
- }
- if (!gotone && verbose)
- printf("None selected\n");
- if (close(arcfd) < 0)
- Fatal("Source (archive) close failed", procName);
-
-}
-
-/*
- * Entry point to extract routines.
- */
-void NuExtract(filename, namecount, names, options)
-char *filename;
-int namecount;
-char **names;
-char *options;
-{
- static char *procName = "NuExtract";
-
- if (*options == 'p') { /* printing rather then extracting to file */
- print = TRUE;
- dopack = TRUE; /* no extract uncompressed! */
- } else print = FALSE;
-
- Extract(filename, namecount, names); /* do stuff */
-}
-
+ END OF ARCHIVE