Thread View: comp.sources.apple2
1 messages
1 total messages
Started by Jonathan A. Chandross
Wed, 01 May 1991 22:09
v001SRC034: Nulib - Archive Library Tools (Unix) 03/10
Author: Jonathan A. Chandross
Date: Wed, 01 May 1991 22:09
Date: Wed, 01 May 1991 22:09
1281 lines
41071 bytes
41071 bytes
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
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads