home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * *
- * HPACK Multi-System Archiver *
- * =========================== *
- * *
- * Archive Directory I/O Routines *
- * ARCDIRIO.C Updated 20/08/92 *
- * *
- * This program is protected by copyright and as such any use or copying of *
- * this code for your own purposes directly or indirectly is highly uncool *
- * and if you do so there will be....trubble. *
- * And remember: We know where your kids go to school. *
- * *
- * Copyright 1989 - 1992 Peter C.Gutmann. All rights reserved *
- * *
- ****************************************************************************/
-
- #include <ctype.h>
- #include <stdlib.h>
- #include <string.h>
- #ifdef __MAC__
- #include "defs.h"
- #include "arcdir.h"
- #include "choice.h"
- #include "error.h"
- #include "flags.h"
- #include "frontend.h"
- #include "hpacklib.h"
- #include "hpaktext.h"
- #include "system.h"
- #include "crc16.h"
- #include "crypt.h"
- #include "fastio.h"
- #include "hpackio.h"
- #include "store.h"
- #else
- #include "defs.h"
- #include "arcdir.h"
- #include "choice.h"
- #include "error.h"
- #include "flags.h"
- #include "frontend.h"
- #include "hpacklib.h"
- #include "system.h"
- #include "crc/crc16.h"
- #include "crypt/crypt.h"
- #include "io/fastio.h"
- #include "io/hpackio.h"
- #include "language/hpaktext.h"
- #include "store/store.h"
- #endif /* __MAC__ */
-
- /* Prototypes for functions in ARCDIR.C */
-
- void addDirHdrToList( DIRHDRLIST *theHeader );
- void fixEverything( void );
-
- /* Prototypes for functions in ARCHIVE.C */
-
- void blankLine( int length );
- void idiotBox( const char *message );
- BOOLEAN confirmAction( const char *message );
-
- /* The following are declared in ARCDIR.C */
-
- extern BOOLEAN doFixEverything;
- extern LONG fileDataOffset, dirDataOffset;
- extern DIRHDRLIST **dirHdrList;
- extern int currDirHdrListIndex, lastEntry;
-
- /* The size of the memory buffer for archive information */
-
- #if ARCHIVE_TYPE == 1
- #define MEM_BUFSIZE 1000 /* More modest memory usage in test vers. */
- #else
- #define MEM_BUFSIZE 8000
- #endif /* ARCHIVE_TYPE == 1 */
-
- /* The structure which holds the archive trailer info. The checksum field
- overlays the security field length for secured archives */
-
- typedef struct {
- WORD noDirHdrs; /* No.of directory headers */
- WORD noFileHdrs; /* No.of file headers */
- LONG dirInfoSize; /* Length of dir.info.block */
- WORD checksum; /* CRC16 of all preceding dir.data */
- BYTE specialInfo; /* The kludge byte */
- BYTE archiveID[ 4 ]; /* 'HPAK' */
- } ARCHIVE_TRAILER;
-
- #define TRAILER_SIZE ( sizeof( WORD ) + sizeof( WORD ) + sizeof( LONG ) + \
- sizeof( WORD ) + sizeof( BYTE ) + HPACK_ID_SIZE )
-
- /* The size of the trailer for multipart and/or secured archives, and the
- magic bit set in the multipart trailer which indicates that the
- segmentation info and final trailer are on a seperate disk */
-
- #define SHORT_TRAILER_SIZE ( sizeof( WORD ) + sizeof( WORD ) + sizeof( LONG ) + \
- sizeof( WORD ) )
-
- #define MULTIPART_SEPERATE_DISK 0x8000
-
- /* The size of the checksummable information in the trailer */
-
- #define TRAILER_CHK_SIZE ( sizeof( WORD ) + sizeof( WORD ) + sizeof( LONG ) )
-
- /* The size of the multipart/secured archive final trailer */
-
- #define MULTIPART_TRAILER_SIZE ( sizeof( WORD ) + sizeof( BYTE ) + HPACK_ID_SIZE )
- #define SECURED_TRAILER_SIZE MULTIPART_TRAILER_SIZE
-
- /* The magic ID and temporary name extensions for HPACK archives */
-
- char HPACK_ID[] = "HPAK";
- #ifdef __ARC__
- char TEMP_EXT[] = "?1";
- char DIRTEMP_EXT[] = "?2";
- char SECTEMP_EXT[] = "?3";
- #else
- char TEMP_EXT[] = "$$1";
- char DIRTEMP_EXT[] = "$$2";
- char SECTEMP_EXT[] = "$$3";
- #endif /* __ARC__ */
-
- /* A special value for the fileKludge to indicate the prototype versions of
- either the LZW, LZA, or MBWA versions of HPACK */
-
- #if ARCHIVE_TYPE == 1
- #define PROTOTYPE 0x20 /* LZW development version */
- #elif ARCHIVE_TYPE == 2
- #define PROTOTYPE 0x40 /* LZA development version */
- #elif ARCHIVE_TYPE == 3
- #define PROTOTYPE 0x60 /* LZA' release version */
- #elif ARCHIVE_TYPE == 4
- #define PROTOTYPE 0x80 /* LZA" release version */
- #elif ARCHIVE_TYPE == 5
- #define PROTOTYPE 0xA0 /* MBWA prototype version 1 */
- #elif ARCHIVE_TYPE == 6
- #define PROTOTYPE 0xC0 /* MBWA prototype version 2 */
- #else
- #error "Need to define ARCHIVE_TYPE"
- #endif /* Various ARCHIVE_TYPE-specific defines */
-
- #define isPrototype(value) ( ( value ) & 0xE0 )/* Whether this archive was
- created by a proto-HPACK */
-
- /* Symbolic defines to specify whether we want getArchiveInfo() to read in
- the ID bytes or not */
-
- #define READ_ID TRUE
- #define NO_READ_ID FALSE
-
- /* Defines to handle the ^Z padding which some versions of Xmodem/Ymodem do */
-
- #define CPM_EOF 0x1A
- #define YMODEM_BLOCKSIZE 1024 /* We can have up to this many ^Z's
- appended */
-
- /****************************************************************************
- * *
- * Global Variables *
- * *
- ****************************************************************************/
-
- PARTSIZELIST *partSizeStartPtr, *partSizeCurrPtr;
- /* Start and current position in the list of archive parts */
-
- int currPart; /* Current part no.of multipart archive */
- int lastPart; /* Last part no.of multipart archive */
- long segmentEnd; /* End of current archive segment */
- long endPosition; /* Virtual end of archive */
-
- static ARCHIVE_TRAILER archiveInfo; /* The archive trailer info */
-
- /****************************************************************************
- * *
- * Read a Directory from a File *
- * *
- ****************************************************************************/
-
- /* Whether the archive directory passes a sanity check when we read it.
- Note that each of the four routines which reads in file and directory
- headers and names contains a sanity check exit-condition in case we
- run out of input data. In addition, various routines in ARCDIR.C also
- perform sanity checking. It may be useful at some point to change the
- BOOLEAN to an int which is incremented each time a check fails to indicate
- the seriousness of the problem */
-
- BOOLEAN arcdirCorrupted;
-
- /* Read the file headers from a file */
-
- static void readFileHeaders( WORD noFileHdrs )
- {
- FILEHDR theHeader;
- WORD hType, linkID;
- BYTE extraInfo;
- int extraInfoLen = 0, extraInfoIndex;
-
- while( noFileHdrs-- )
- {
- /* Assemble each header and add it to the directory tree, with
- sanity check */
- hType = TYPE_NORMAL; /* Reset header hType */
- extraInfo = linkID = 0; /* Reset extraInfo and linkID */
- if( ( theHeader.archiveInfo = fgetWord() ) == ( WORD ) FEOF )
- {
- arcdirCorrupted = TRUE;
- return;
- }
- switch( theHeader.archiveInfo & ARCH_OTHER_LEN )
- {
- case ARCH_OTHER_ZERO_ZERO:
- /* dirIndex = ROOT_DIR, auxDataLen = 0 */
- theHeader.dirIndex = ROOT_DIR;
- theHeader.auxDataLen = 0L;
- break;
-
- case ARCH_OTHER_BYTE_BYTE:
- /* dirIndex = BYTE, auxDataLen = BYTE */
- theHeader.dirIndex = ( WORD ) fgetByte();
- theHeader.auxDataLen = ( LONG ) fgetByte();
- break;
-
- case ARCH_OTHER_BYTE_WORD:
- /* dirIndex = BYTE, auxDataLen = WORD */
- theHeader.dirIndex = ( WORD ) fgetByte();
- theHeader.auxDataLen = ( LONG ) fgetWord();
- break;
-
- case ARCH_OTHER_WORD_LONG:
- /* dirIndex = WORD, auxDataLen = LONG */
- theHeader.dirIndex = fgetWord();
- theHeader.auxDataLen = fgetLong();
- }
-
- theHeader.fileTime = fgetLong();
- if( theHeader.archiveInfo & ARCH_ORIG_LEN )
- theHeader.fileLen = fgetLong();
- else
- theHeader.fileLen = ( LONG ) fgetWord();
- if( theHeader.archiveInfo & ARCH_COPR_LEN )
- theHeader.dataLen = fgetLong();
- else
- theHeader.dataLen = ( LONG ) fgetWord();
-
- /* Handle type SPECIAL files by reading in the extra WORD giving
- the file's hType */
- if( theHeader.archiveInfo & ARCH_SPECIAL )
- hType = fgetWord();
-
- /* Handle any extra information attached to the header */
- if( theHeader.archiveInfo & ARCH_EXTRAINFO )
- {
- /* Get extra info.byte and extract length information */
- extraInfo = fgetByte();
- extraInfoLen = getExtraInfoLen( extraInfo );
- extraInfoIndex = 1; /* Data follows extraInfo byte */
- }
-
- /* Read link ID if there is one */
- if( extraInfo & EXTRA_LINKED )
- linkID = fgetWord();
-
- addFileHeader( &theHeader, hType, extraInfo, linkID );
- fileHdrCurrPtr->tagged = FALSE;
-
- /* Read in any extra information attached to the header if necessary */
- if( extraInfoLen )
- {
- #if defined( __MSDOS__ )
- /* Fix stupid compiler bug */
- #elif defined( __ARC__ )
- if( ( theHeader.archiveInfo & ARCH_SYSTEM ) == OS_ARCHIMEDES )
- {
- /* Read in file type */
- extraInfoLen -= sizeof( WORD );
- if( extraInfoLen < 0 )
- {
- /* Length info has been corrupted */
- extraInfoLen = 0;
- fileHdrCurrPtr->type = 0;
- }
- else
- fileHdrCurrPtr->type = fgetWord();
- }
- else
- /* File type is unknown */
- fileHdrCurrPtr->type = 0;
- #elif defined( __IIGS__ )
- if( ( theHeader.archiveInfo & ARCH_SYSTEM ) == OS_IIGS )
- {
- /* Read in file type and auxiliary type */
- extraInfoLen -= sizeof( WORD ) + sizeof( LONG );
- if( extraInfoLen < 0 )
- {
- /* Length info has been corrupted */
- extraInfoLen = 0;
- fileHdrCurrPtr->type = 0;
- fileHdrCurrPtr->auxType = 0L;
- }
- else
- {
- fileHdrCurrPtr->type = fgetWord();
- fileHdrCurrPtr->auxType = fgetLong();
- }
- }
- else
- {
- /* File type and auxiliary type are unknown */
- fileHdrCurrPtr->type = 0;
- fileHdrCurrPtr->auxType = 0L;
- }
- #elif defined( __MAC__ )
- if( ( theHeader.archiveInfo & ARCH_SYSTEM ) == OS_MAC )
- {
- /* Read in file type and creator */
- extraInfoLen -= sizeof( LONG ) + sizeof( LONG );
- if( extraInfoLen < 0 )
- {
- /* Length info has been corrupted, default to type 'TEXT' */
- extraInfoLen = 0;
- fileHdrCurrPtr->type = fileHdrCurrPtr->creator = 'TEXT';
- }
- else
- {
- fileHdrCurrPtr->type = fgetLong();
- fileHdrCurrPtr->creator = fgetLong();
- }
- }
- else
- /* File type and creator are unknown. Note that we set the
- type to 0L rather than 'TEXT' since we may be able to
- pick up type information later on */
- fileHdrCurrPtr->type = fileHdrCurrPtr->creator = 0L;
- #elif defined( __UNIX__ )
- if( ( theHeader.archiveInfo & ARCH_SYSTEM ) == OS_UNIX )
- {
- /* Read in link ID */
- extraInfoLen -= sizeof( WORD );
- if( extraInfoLen < 0 )
- {
- /* Length info has been corrupted */
- extraInfoLen = 0;
- fileHdrCurrPtr->fileLinkID = 0;
- }
- else
- fileHdrCurrPtr->fileLinkID = fgetWord();
- }
- else
- /* No linkID given */
- fileHdrCurrPtr->fileLinkID = 0;
- fileHdrCurrPtr->linkID = 0L; /* No dev/inode for this file */
- #endif /* Various OS-dependant extraInfo reads */
-
- /* Read in any remaining information */
- while( extraInfoLen-- )
- fileHdrCurrPtr->extraInfo[ extraInfoIndex++ ] = fgetByte();
- extraInfoLen = 0; /* Fix fencepost error */
- }
- else
- {
- #if defined( __AMIGA__ ) || defined( __ATARI__ ) || defined( __MSDOS__ )
- ; /* Nothing */
- #elif defined( __ARC__ )
- /* No file type */
- fileHdrCurrPtr->type = 0;
- #elif defined( __IIGS__ )
- /* No file type and auxiliary type */
- fileHdrCurrPtr->type = 0;
- fileHdrCurrPtr->auxType = 0L;
- #elif defined( __MAC__ )
- /* No type/creator information */
- fileHdrCurrPtr->type = fileHdrCurrPtr->creator = 0L;
- #elif defined( __UNIX__ )
- /* No link information */
- fileHdrCurrPtr->linkID = 0L;
- #endif /* Various OS-dependant extraInfo initializations */
- }
- }
- }
-
- /* Read the filenames from a file */
-
- static void readFileNames( void )
- {
- FILEHDRLIST *prevPtr = NULL;
-
- /* Step along the chain of headers reading in the corresponding filenames */
- for( fileHdrCurrPtr = fileHdrStartPtr; fileHdrCurrPtr != NULL; \
- prevPtr = fileHdrCurrPtr, fileHdrCurrPtr = fileHdrCurrPtr->next )
- addFileName( fileHdrCurrPtr->data.dirIndex, fileHdrCurrPtr->hType, NULL );
-
- fileHdrCurrPtr = prevPtr; /* Reset currPos to last header */
- }
-
- /* Read the directory headers from a file */
-
- static void readDirHeaders( WORD noDirHdrs )
- {
- WORD theEntry = ( WORD ) FEOF;
- DIRHDRLIST *dirInfoPtr;
- DIRHDR *theHeader;
- int dirInfoFlags;
-
- if( noDirHdrs )
- {
- while( noDirHdrs-- )
- {
- /* Add each header to the directory tree */
- if( ( dirInfoPtr = ( DIRHDRLIST * ) hmalloc( sizeof( DIRHDRLIST ) ) ) == NULL )
- error( OUT_OF_MEMORY );
- currDirHdrListIndex++;
- if( currDirHdrListIndex >= MEM_BUFSIZE )
- error( OUT_OF_MEMORY );
- theHeader = &dirInfoPtr->data;
-
- /* Set up housekeeping info for the header */
- dirHdrList[ currEntry ]->next = currEntry + 1;
- dirHdrList[ ++currEntry ] = dirInfoPtr;
- dirInfoPtr->offset = dirDataOffset;
- dirInfoPtr->dirIndex = currEntry;
- dirInfoPtr->hType = DIRTYPE_NORMAL;
- dirInfoPtr->linkID = NO_LINK;
-
- /* Read the header information off disk, with sanity check */
- if( ( dirInfoFlags = fgetByte() ) == FEOF )
- {
- arcdirCorrupted = TRUE;
- return;
- }
- theHeader->dirInfo = dirInfoFlags;
- switch( theHeader->dirInfo & DIR_OTHER_LEN )
- {
- case DIR_OTHER_ZERO_ZERO:
- /* parentIndex = ROOT_DIR, dataLen = 0 */
- theHeader->parentIndex = ROOT_DIR;
- theHeader->dataLen = 0L;
- break;
-
- case DIR_OTHER_BYTE_BYTE:
- /* parentIndex = BYTE, dataLen = BYTE */
- theHeader->parentIndex = ( WORD ) fgetByte();
- theHeader->dataLen = ( LONG ) fgetByte();
- break;
-
- case DIR_OTHER_BYTE_WORD:
- /* parentIndex = BYTE, dataLen = WORD */
- theHeader->parentIndex = ( WORD ) fgetByte();
- theHeader->dataLen = ( LONG ) fgetWord();
- break;
-
- case DIR_OTHER_WORD_LONG:
- /* parentIndex = WORD, dataLen = LONG */
- theHeader->parentIndex = fgetWord();
- theHeader->dataLen = fgetLong();
- }
- theHeader->dirTime = fgetLong();
-
- /* Read in type SPECIAL word and linkID if necessary */
- if( theHeader->dirInfo & DIR_SPECIAL )
- dirInfoPtr->hType = fgetWord();
- if( theHeader->dirInfo & DIR_LINKED )
- dirInfoPtr->linkID = fgetWord();
-
- dirInfoPtr->fileInDirListHead = dirInfoPtr->fileInDirListTail = NULL;
- dirInfoPtr->dirInDirListHead = dirInfoPtr->dirInDirListTail = NULL;
- dirInfoPtr->tagged = FALSE;
- dirDataOffset += dirInfoPtr->data.dataLen;
- }
- dirInfoPtr->next = END_MARKER;
- }
- lastEntry = currEntry;
-
- /* We've read in all the directories, now create the list of directories
- inside directories (this has to be done after all the directories are
- read in since they will not necessarily be in the correct order as they
- are read) */
- for( theEntry = dirHdrList[ ROOT_DIR ]->next; theEntry != END_MARKER; \
- theEntry = dirHdrList[ theEntry ]->next )
- addDirHdrToList( dirHdrList[ theEntry ] );
- }
-
- /* Read the directory names from a file */
-
- static void readDirNames( void )
- {
- WORD *wordPtr = ( WORD * ) mrglBuffer;
- WORD theEntry;
- int dirNameLength, ch;
-
- /* Read in directory names */
- for( theEntry = dirHdrList[ ROOT_DIR ]->next; theEntry != END_MARKER; \
- theEntry = dirHdrList[ theEntry ]->next )
- {
- /* Read in directory name with sanity check */
- dirNameLength = 0;
- if( dirHdrList[ theEntry ]->data.dirInfo & DIR_UNICODE )
- {
- /* Read Unicode directory name */
- while( ch = fgetWord() )
- {
- /* Perform a sanity check for end of data or excessively
- long string */
- if( ch == FEOF || dirNameLength > ( DIRBUFSIZE / sizeof( WORD ) ) )
- {
- arcdirCorrupted = TRUE;
- return;
- }
-
- wordPtr[ dirNameLength++ ] = ch;
- }
-
- wordPtr[ dirNameLength++ ] = 0x0000;
- }
- else
- {
- /* Read ASCII directory name */
- while( ch = fgetByte() )
- {
- /* Perform a sanity check for end of data or excessively
- long string */
- if( ch == FEOF || dirNameLength > DIRBUFSIZE )
- {
- arcdirCorrupted = TRUE;
- return;
- }
-
- #if defined( __AMIGA__ ) || defined( __ARC__ ) || defined( __MAC__ ) || \
- defined( __OS2__ ) || defined( __UNIX__ )
- /* Check if we want to smash case */
- if( sysSpecFlags & SYSPEC_FORCELOWER )
- mrglBuffer[ dirNameLength++ ] = tolower( ch );
- else
- #endif /* __AMIGA__ || __ARC__ ||__MAC__ || __OS2__ || __UNIX__ */
- mrglBuffer[ dirNameLength++ ] = ch;
- }
-
- mrglBuffer[ dirNameLength++ ] = '\0';
- }
-
- if( ( dirHdrList[ theEntry ]->dirName = \
- ( char * ) hmalloc( dirNameLength ) ) == NULL )
- error( OUT_OF_MEMORY );
- strcpy( dirHdrList[ theEntry ]->dirName, ( char * ) mrglBuffer );
- }
- }
-
- /* Read in the section sizes for a multipart archive */
-
- static void readPartSizes( void )
- {
- int count = lastPart;
-
- /* Read in each sections size and set the current part to the last part
- read */
- while( count-- )
- addPartSize( fgetLong() );
- currPart = lastPart;
- }
-
- /* Read the archive trailer information from a file */
-
- static void getArchiveInfo( const BOOLEAN readID )
- {
- archiveInfo.noDirHdrs = fgetWord();
- archiveInfo.noFileHdrs = fgetWord();
- archiveInfo.dirInfoSize = fgetLong();
- archiveInfo.checksum = fgetWord();
-
- if( readID )
- {
- archiveInfo.specialInfo = fgetByte();
-
- /* We must use fgetByte() to get the archive ID since fgetLong() will
- do endianness conversion */
- archiveInfo.archiveID[ 0 ] = fgetByte();
- archiveInfo.archiveID[ 1 ] = fgetByte();
- archiveInfo.archiveID[ 2 ] = fgetByte();
- archiveInfo.archiveID[ 3 ] = fgetByte();
- }
- }
-
- /* Save the directory data to a temporary file */
-
- static void saveDirData( void )
- {
- WORD multipartFlagSave = multipartFlags;
-
- /* Turn off multipart writes when saving the directory data */
- multipartFlags &= ~MULTIPART_WRITE;
-
- /* Open a temporary file (with the same reason given in FRONTEND.C for
- using the archive name with the DIRTEMP_EXT suffix) and move the
- directory data to it */
- strcpy( dirFileName, archiveFileName );
- strcpy( dirFileName + strlen( dirFileName ) - 3, DIRTEMP_EXT );
- if( ( dirFileFD = hcreat( dirFileName, CREAT_ATTR ) ) == IO_ERROR )
- error( CANNOT_OPEN_TEMPFILE );
- setOutputFD( dirFileFD );
- hlseek( archiveFD, fileDataOffset + HPACK_ID_SIZE, SEEK_SET );
- moveData( dirDataOffset );
- flushBuffer();
- setOutputFD( archiveFD );
-
- multipartFlags = multipartFlagSave;
- }
-
- /* Save the security data and final trailer to a temporary file */
-
- static void saveSecData( void )
- {
- WORD multipartFlagSave = multipartFlags;
-
- /* Turn off multipart writes when saving the security data */
- multipartFlags &= ~MULTIPART_WRITE;
-
- /* Open a temporary file and move the data as above */
- strcpy( secFileName, archiveFileName );
- strcpy( secFileName + strlen( secFileName ) - 3, SECTEMP_EXT );
- if( ( secFileFD = hcreat( secFileName, CREAT_ATTR ) ) == IO_ERROR )
- error( CANNOT_OPEN_TEMPFILE );
- setOutputFD( secFileFD );
- memcpy( _outBuffer, _inBuffer + SHORT_TRAILER_SIZE, \
- secInfoLen + SECURED_TRAILER_SIZE );
- writeBuffer( secInfoLen + SECURED_TRAILER_SIZE );
- setOutputFD( archiveFD );
-
- multipartFlags = multipartFlagSave;
- }
-
- /* Read in the trailer information at the very end of an archive */
-
- static int paddingSize; /* No.bytes ^Z padding found by readArcTrailer() */
-
- void readArcTrailer( void )
- {
- WORD multipartFlagSave, cryptFlagSave;
- BOOLEAN notArchive;
- int inByteCountSave, bytesRead;
- #ifdef GUI
- char string[ 10 ];
- #endif /* GUI */
-
- /* If we are reading in the trailer of a multipart archive, move any data
- in the input buffer which may be overwritten to a safe area and turn
- off multipart reads */
- if( flags & MULTIPART_ARCH )
- {
- memcpy( mrglBuffer, _inBuffer, HPACK_ID_SIZE + YMODEM_BLOCKSIZE );
- multipartFlagSave = multipartFlags;
- multipartFlags &= ~MULTIPART_READ;
- cryptFlagSave = cryptFlags;
- cryptFlags = 0;
- inByteCountSave = _inByteCount;
- }
-
- /* Make sure this is an HPACK archive */
- paddingSize = 0;
- hlseek( archiveFD, -( LONG ) TRAILER_SIZE, SEEK_END );
- resetFastIn();
- getArchiveInfo( READ_ID );
- if( memcmp( archiveInfo.archiveID, HPACK_ID, HPACK_ID_SIZE ) )
- {
- notArchive = TRUE;
- if( archiveInfo.archiveID[ 3 ] == CPM_EOF )
- {
- /* This may be a valid archive with CPM EOF's added to the end.
- Try and find a valid HPACK ID before the ^Z's */
- hlseek( archiveFD, -( LONG ) ( HPACK_ID_SIZE + YMODEM_BLOCKSIZE ), SEEK_END );
- if( htell( archiveFD ) < 0L )
- /* We've gone past the start of the file; just seek to the
- start */
- hlseek( archiveFD, 0L, SEEK_SET );
- bytesRead = hread( archiveFD, _inBuffer, HPACK_ID_SIZE + YMODEM_BLOCKSIZE );
- for( paddingSize = bytesRead - 1; paddingSize >= HPACK_ID_SIZE && \
- _inBuffer[ paddingSize ] == CPM_EOF; paddingSize-- );
- paddingSize++; /* Fix fencepost error */
- if( !memcmp( _inBuffer + paddingSize - HPACK_ID_SIZE, HPACK_ID, HPACK_ID_SIZE ) )
- {
- /* It is an HPACK archive, try to truncate the ^Z padding. If
- we can't, remember the offset of the start of any useful data */
- notArchive = FALSE;
- paddingSize = bytesRead - paddingSize;
- hlseek( archiveFD, -( LONG ) paddingSize, SEEK_END );
- if( htruncate( archiveFD ) != IO_ERROR )
- {
- #ifdef GUI
- itoa( paddingSize, string, 10 );
- alert( ALERT_TRUNCATED_PADDING, string );
- #else
- hprintf( WARN_TRUNCATED_u_BYTES_EOF_PADDING, paddingSize );
- #endif /* GUI */
- paddingSize = 0;
- }
-
- /* Re-read the trailer info */
- hlseek( archiveFD, -( long ) ( TRAILER_SIZE + paddingSize ), SEEK_END );
- resetFastIn();
- getArchiveInfo( READ_ID );
- }
- }
-
- if( notArchive )
- error( NOT_HPACK_ARCHIVE );
- }
-
- /* If this is part of a multipart archive, set the correct part number */
- if( archiveInfo.specialInfo & SPECIAL_MULTIPART )
- currPart = archiveInfo.checksum;
- if( archiveInfo.specialInfo & SPECIAL_MULTIEND )
- currPart = lastPart;
-
- /* Restore the input buffer and turn multipart reads on again if necessary */
- if( flags & MULTIPART_ARCH )
- {
- memcpy( _inBuffer, mrglBuffer, HPACK_ID_SIZE + YMODEM_BLOCKSIZE );
- multipartFlags = multipartFlagSave;
- cryptFlags = cryptFlagSave;
- _inByteCount = inByteCountSave;
- }
- }
-
- /* Read the archive directory into memory */
-
- void readArcDir( const BOOLEAN doSaveDirData )
- {
- long securedDataLen;
- int cryptInfoLen;
-
- /* Read in the trailer information */
- readArcTrailer();
- if( archiveInfo.specialInfo & SPECIAL_MULTIPART )
- /* This is part of a multipart archive, prompt for the last part */
- while( !( archiveInfo.specialInfo & SPECIAL_MULTIEND ) )
- {
- hclose( archiveFD );
- archiveFD = IO_ERROR; /* Mark it as invalid */
- multipartWait( WAIT_PARTNO | WAIT_LASTPART, archiveInfo.checksum );
- if( ( archiveFD = hopen( archiveFileName, O_RDONLY | S_DENYWR | A_RANDSEQ ) ) == ERROR )
- error( CANNOT_OPEN_ARCHFILE, archiveFileName );
- setInputFD( archiveFD );
- readArcTrailer();
- }
-
- /* Perform bootstrap read for multipart archives */
- if( archiveInfo.specialInfo & SPECIAL_MULTIEND )
- {
- /* Set special status flag */
- flags |= MULTIPART_ARCH;
-
- /* Move the information from the archiveInfo fields into the segment
- information which they overlay */
- lastPart = archiveInfo.noFileHdrs & ~MULTIPART_SEPERATE_DISK;
-
- /* Read in the segmentation information */
- hlseek( archiveFD, -( LONG ) ( ( lastPart * sizeof( LONG ) ) + TRAILER_SIZE ), SEEK_CUR );
- resetFastIn();
- checksumSetInput( ( lastPart * sizeof( LONG ) ) + TRAILER_CHK_SIZE, RESET_CHECKSUM );
- readPartSizes();
- getArchiveInfo( NO_READ_ID ); /* For checksumming purposes */
- if( crc16 != archiveInfo.checksum )
- /* Directory data was corrupted, confirm to continue */
- idiotBox( MESG_ARCHIVE_DIRECTORY_CORRUPTED );
-
- /* We have segmentation information in memory, turn on virtual read
- mode, establish current and end positions in archive */
- setCurrPosition( archiveInfo.dirInfoSize );
- endPosition = archiveInfo.dirInfoSize;
- multipartFlags |= MULTIPART_READ;
-
- /* Get length of security info in correct field in case it's needed
- later on */
- archiveInfo.checksum = archiveInfo.noDirHdrs;
-
- /* If the multipart information is on a seperate disk, get the disk
- with the archive itself */
- if( archiveInfo.noFileHdrs & MULTIPART_SEPERATE_DISK )
- getPart( lastPart );
- }
-
- /* Set the block-mode flag if necessary */
- if( archiveInfo.specialInfo & SPECIAL_BLOCK )
- {
- /* Make sure we don't try and change an archive using unified compression */
- if( choice == ADD || choice == DELETE || choice == FRESHEN || \
- choice == REPLACE || choice == UPDATE || ( flags & MOVE_FILES ) )
- error( CANNOT_CHANGE_UNIFIED_ARCH );
-
- flags |= BLOCK_MODE;
- }
- else
- flags &= ~BLOCK_MODE;
-
- /* Handle archive security if secured archive */
- if( archiveInfo.specialInfo & SPECIAL_SECURED )
- {
- /* Read in archive trailer and security/encryption info. The length
- of this field is given by archiveTrailer.checksum, which overlays
- the length field. The length of the secured data is the current
- position plus the trailer size minus the size of the ID at the
- start and the ID and kludge bytes which aren't part of the trailer
- any more but are at the end of the archive */
- secInfoLen = archiveInfo.checksum;
- vlseek( -( LONG ) ( sizeof( WORD ) + secInfoLen + \
- ( TRAILER_SIZE ) + paddingSize ), SEEK_END );
- securedDataLen = vtell() + SHORT_TRAILER_SIZE - HPACK_ID_SIZE;
- resetFastIn();
- getArchiveInfo( NO_READ_ID );
-
- /* If it's a multipart archive the security info check can take
- a while, so we ask the luser whether they want to do it or not */
- if( !( flags & MULTIPART_ARCH ) || \
- confirmAction( MESG_VERIFY_SECURITY_INFO ) )
- {
- if( choice == EXTRACT || choice == TEST || choice == DISPLAY )
- {
- /* Check the entire archive */
- #ifndef GUI
- hputs( MESG_VERIFYING_ARCHIVE_AUTHENTICITY );
- #endif /* !GUI */
- if( !checkSignature( 0L, securedDataLen ) )
- idiotBox( MESG_AUTH_CHECK_FAILED );
- #ifndef GUI
- hputchar( '\n' );
- #endif /* !GUI */
- }
- else
- {
- /* Make sure the user wants to overwrite the security info */
- if( choice != VIEW )
- idiotBox( MESG_SECURITY_INFO_WILL_BE_DESTROYED );
-
- /* Save the information for later recovery if necessary */
- if( choice == ADD )
- saveSecData();
- }
- }
-
- /* Now treat security info as padding */
- paddingSize += secInfoLen + sizeof( WORD );
- }
- else
- if( flags & MULTIPART_ARCH )
- {
- /* We still need to read in the archive trailer */
- vlseek( -( LONG ) SHORT_TRAILER_SIZE, SEEK_END );
- resetFastIn();
- getArchiveInfo( NO_READ_ID );
-
- /* Adjust the padding size by the difference between the full
- trailer and the shortened trailer */
- paddingSize -= ( TRAILER_SIZE - SHORT_TRAILER_SIZE );
- }
-
- /* Handle encrypted archive */
- if( archiveInfo.specialInfo & SPECIAL_ENCRYPTED )
- {
- /* Make sure we don't try to update an encrypted archive */
- if( choice == ADD || choice == DELETE || \
- choice == FRESHEN || choice == UPDATE || ( flags & MOVE_FILES ) )
- error( CANNOT_CHANGE_ENCRYPTED_ARCH );
-
- /* If the luser didn't specify decryption, try it anyway */
- if( !( flags & CRYPT ) )
- flags |= CRYPT;
-
- /* Assume conventional-key encryption for now. This may be changed
- later when we read in the encryption header */
- if( !( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) ) )
- cryptFlags = CRYPT_CKE_ALL;
- }
- else
- if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
- if( choice == DISPLAY || choice == TEST || choice == EXTRACT || choice == VIEW )
- /* The archive isn't encrypted, try processing individual
- encrypted files. Assume conventional-key encryption for now */
- cryptFlags = CRYPT_CKE;
- else
- /* Make sure we don't try to block-encrypt an unencrypted archive */
- error( CANNOT_CHANGE_UNENCRYPTED_ARCH );
-
- /* Check this is the correct version of archive/HPACK */
- if( !isPrototype( archiveInfo.specialInfo ) )
- idiotBox( "Please upgrade to a non-prototype HPACK release" );
- else
- if( ( archiveInfo.specialInfo & 0xE0 ) != PROTOTYPE )
- /* This archive was created by a different prototype version,
- confirm to continue */
- idiotBox( "Peter has been messing with the filekludge again" );
-
- /* Read in archive directory */
- if( ( ( long ) archiveInfo.dirInfoSize < 0L ) || \
- ( vlseek( -( ( long ) ( archiveInfo.dirInfoSize + \
- TRAILER_SIZE + paddingSize ) ), SEEK_END ) < HPACK_ID_SIZE ) )
- /* dirInfoSize has impossible value or tried to seek past archive
- start, trailer information corrupted. Note that we can actually
- seek right up to the HPACK_ID at the start if the archive contains
- only directories */
- error( ARCHIVE_DIRECTORY_CORRUPTED );
- #ifndef GUI
- if( flags & MULTIPART_ARCH )
- hprintfs( MESG_PROCESSING_ARCHIVE_DIRECTORY );
- #endif /* !GUI */
- arcdirCorrupted = FALSE;
- resetFastIn();
- if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
- {
- preemptCryptChecksum( archiveInfo.dirInfoSize + TRAILER_CHK_SIZE );
- if( !cryptSetInput( archiveInfo.dirInfoSize, &cryptInfoLen ) )
- error( CANNOT_PROCESS_CRYPT_ARCH );
- archiveInfo.dirInfoSize -= cryptInfoLen;
- }
- else
- checksumSetInput( archiveInfo.dirInfoSize + TRAILER_CHK_SIZE, RESET_CHECKSUM );
- readDirHeaders( archiveInfo.noDirHdrs );
- readFileHeaders( archiveInfo.noFileHdrs );
- readDirNames();
- readFileNames();
- getArchiveInfo( NO_READ_ID ); /* For checksumming purposes */
- #ifndef GUI
- if( flags & MULTIPART_ARCH )
- blankLine( 60 );
- #endif /* !GUI */
- if( crc16 != archiveInfo.checksum || arcdirCorrupted )
- {
- /* Directory data was corrupted, confirm to continue */
- if( cryptFlags & CRYPT_CKE_ALL )
- idiotBox( MESG_ARCHIVE_DIRECTORY_WRONG_PASSWORD );
- else
- idiotBox( MESG_ARCHIVE_DIRECTORY_CORRUPTED );
- }
-
- /* Move directory data to a temporary file if necessary since it will be
- overwritten later */
- if( doSaveDirData && dirDataOffset )
- saveDirData();
-
- /* Only go back to the start of the archive if we have to */
- if( !( flags & MULTIPART_READ ) || \
- ( choice == EXTRACT || choice == TEST || choice == DISPLAY ) )
- vlseek( 0L, SEEK_SET );
- }
-
- /****************************************************************************
- * *
- * Write a Directory to a File *
- * *
- ****************************************************************************/
-
- /* The sizes of the encryption headers for the file and directory data */
-
- int cryptFileDataLength, cryptDirDataLength;
-
- /* Write the file headers to a file. This function is split into two seperate
- routines, one of which steps through the list of headers and one which
- writes the headers themselves; the latter is also called to write the
- error recovery information */
-
- int writeFileHeader( FILEHDRLIST *theHeader )
- {
- FILEHDR *fileHeader = &theHeader->data;
- WORD archInfo = fileHeader->archiveInfo;
- int bytesWritten = sizeof( WORD ) + sizeof( LONG ); /* Constant fields */
- int extraInfoIndex, extraInfoLen;
-
- /* Set the field length bits depending on the field's contents */
- archInfo |= ( fileHeader->fileLen > 0xFFFF ) ? ARCH_ORIG_LEN : 0;
- archInfo |= ( fileHeader->dataLen > 0xFFFF ) ? ARCH_COPR_LEN : 0;
- archInfo |= ( fileHeader->dirIndex > 0xFF ) ? ARCH_OTHER_LEN : \
- ( fileHeader->auxDataLen > 0xFF ) ? ARCH_OTHER_HI : \
- ( fileHeader->dirIndex || fileHeader->auxDataLen ) ? \
- ARCH_OTHER_LO : 0;
-
- /* Write the header itself */
- fputWord( archInfo );
- switch( archInfo & ARCH_OTHER_LEN )
- {
- case ARCH_OTHER_BYTE_BYTE:
- /* dirIndex = BYTE, auxDataLen = BYTE */
- fputByte( ( BYTE ) fileHeader->dirIndex );
- fputByte( ( BYTE ) fileHeader->auxDataLen );
- bytesWritten += sizeof( BYTE ) + sizeof( BYTE );
- break;
-
- case ARCH_OTHER_BYTE_WORD:
- /* dirIndex = BYTE, auxDataLen = WORD */
- fputByte( ( BYTE ) fileHeader->dirIndex );
- fputWord( ( WORD ) fileHeader->auxDataLen );
- bytesWritten += sizeof( BYTE ) + sizeof( WORD );
- break;
-
- case ARCH_OTHER_WORD_LONG:
- /* dirIndex = WORD, auxDataLen = LONG */
- fputWord( fileHeader->dirIndex );
- fputLong( fileHeader->auxDataLen );
- bytesWritten += sizeof( WORD ) + sizeof( LONG );
- }
- fputLong( fileHeader->fileTime );
- if( archInfo & ARCH_ORIG_LEN )
- {
- fputLong( fileHeader->fileLen );
- bytesWritten += sizeof( LONG );
- }
- else
- {
- fputWord( ( WORD ) fileHeader->fileLen );
- bytesWritten += sizeof( WORD );
- }
- if( archInfo & ARCH_COPR_LEN )
- {
- fputLong( fileHeader->dataLen );
- bytesWritten += sizeof( LONG );
- }
- else
- {
- fputWord( ( WORD ) fileHeader->dataLen );
- bytesWritten += sizeof( WORD );
- }
-
- /* Handle type SPECIAL files by writing an additional WORD containing
- the file's hType */
- if( archInfo & ARCH_SPECIAL )
- {
- fputWord( theHeader->hType );
- bytesWritten += sizeof( WORD );
- }
-
- /* Handle any extra info attached to the header */
- if( archInfo & ARCH_EXTRAINFO )
- {
- /* Write out extraInfo byte */
- extraInfoIndex = 1;
- extraInfoLen = getExtraInfoLen( *theHeader->extraInfo );
- fputByte( *theHeader->extraInfo );
- bytesWritten += sizeof( BYTE ) + extraInfoLen;
-
- #if defined( __MSDOS__ )
- /* Fix compiler bug */
- #elif defined( __ARC__ )
- /* Write file type */
- if( extraInfoLen >= sizeof( WORD ) )
- {
- extraInfoLen -= sizeof( WORD );
- extraInfoIndex += sizeof( WORD );
- }
- fputWord( theHeader->type );
- #elif defined( __IIGS__ )
- /* Write file type and auxiliary type */
- if( extraInfoLen >= sizeof( WORD ) + sizeof( LONG ) )
- {
- extraInfoLen -= sizeof( WORD ) + sizeof( LONG );
- extraInfoIndex += sizeof( WORD ) + sizeof( LONG );
- }
- fputWord( theHeader->type );
- fputLong( theHeader->auxType );
- #elif defined( __MAC__ )
- /* Write file type and creator */
- if( extraInfoLen >= sizeof( LONG ) + sizeof( LONG ) )
- {
- extraInfoLen -= sizeof( LONG ) + sizeof( LONG );
- extraInfoIndex += sizeof( LONG ) + sizeof( LONG );
- }
- fputLong( theHeader->type );
- fputLong( theHeader->creator );
- #elif defined( __UNIX__ )
- /* Write link ID */
- if( extraInfoLen >= sizeof( WORD ) )
- {
- extraInfoLen -= sizeof( WORD );
- extraInfoIndex += sizeof( WORD );
- }
- fputWord( theHeader->fileLinkID );
- #endif /* Various OS-dependant extraInfo reads */
-
- /* Write out any remaining info */
- while( extraInfoLen-- )
- fputByte( theHeader->extraInfo[ extraInfoIndex++ ] );
- }
-
- return( bytesWritten );
- }
-
- static LONG writeFileHeaders( void )
- {
- LONG bytesWritten = 0L;
-
- archiveInfo.noFileHdrs = 0;
-
- /* Write a dummy header for the encryption information if necessary */
- if( cryptFileDataLength )
- {
- fputWord( ARCH_SPECIAL );
- fputLong( getStrongRandomLong() );
- fputWord( getStrongRandomWord() );
- fputWord( cryptFileDataLength );
- fputWord( TYPE_DUMMY );
- bytesWritten += sizeof( WORD ) + sizeof( LONG ) + sizeof( WORD ) + \
- sizeof( WORD ) + sizeof( WORD );
- archiveInfo.noFileHdrs++;
- }
-
- /* Write the file headers themselves */
- for( fileHdrCurrPtr = fileHdrStartPtr; fileHdrCurrPtr != NULL; \
- fileHdrCurrPtr = fileHdrCurrPtr->next )
- {
- bytesWritten += writeFileHeader( fileHdrCurrPtr );
- archiveInfo.noFileHdrs++;
- }
-
- return( bytesWritten );
- }
-
- /* Write the filenames to a file */
-
- static LONG writeFileNames( void )
- {
- LONG bytesWritten = 0L;
- char *strPtr;
-
- /* Write a dummy name for the encryption header if necessary */
- if( cryptFileDataLength )
- {
- fputByte( '\0' );
- bytesWritten++;
- }
-
- /* Write file names */
- for( fileHdrCurrPtr = fileHdrStartPtr; fileHdrCurrPtr != NULL; \
- fileHdrCurrPtr = fileHdrCurrPtr->next )
- {
- strPtr = fileHdrCurrPtr->fileName;
- do
- {
- fputByte( *strPtr );
- bytesWritten++;
- }
- while( *strPtr++ );
- }
-
- return( bytesWritten );
- }
-
- /* Write the directory headers to a file */
-
- static LONG writeDirHeaders( void )
- {
- WORD theEntry, hType, linkID;
- LONG bytesWritten = 0L;
- DIRHDR *dirHeader;
- BYTE dirInfo;
-
- archiveInfo.noDirHdrs = 0;
-
- /* Write a dummy header for the encryption information if necessary */
- if( cryptDirDataLength )
- {
- fputByte( DIR_OTHER_BYTE_BYTE | DIR_SPECIAL );
- fputByte( ROOT_DIR );
- fputByte( cryptDirDataLength );
- fputLong( getStrongRandomLong() );
- fputWord( DIRTYPE_DUMMY );
- bytesWritten += sizeof( BYTE ) + sizeof( BYTE ) + sizeof( BYTE ) + \
- sizeof( LONG ) + sizeof( WORD );
- archiveInfo.noDirHdrs++;
- }
-
- /* Write the directory headers themselves */
- for( theEntry = dirHdrList[ ROOT_DIR ]->next; theEntry != END_MARKER; \
- theEntry = dirHdrList[ theEntry ]->next )
- {
- /* Pull out relevant info from directory header */
- dirHeader = &dirHdrList[ theEntry ]->data;
- hType = dirHdrList[ theEntry ]->hType;
- linkID = dirHdrList[ theEntry ]->linkID;
-
- /* Set the field length bits depending on the field's contents */
- dirInfo = dirHeader->dirInfo;
- dirInfo |= ( dirHeader->parentIndex > 0xFF ) ? DIR_OTHER_LEN : \
- ( dirHeader->dataLen > 0xFF ) ? DIR_OTHER_HI : \
- ( dirHeader->parentIndex || dirHeader->dataLen ) ? \
- DIR_OTHER_LO : 0;
-
- /* Write the header itself */
- fputByte( dirInfo );
- switch( dirInfo & DIR_OTHER_LEN )
- {
- case DIR_OTHER_BYTE_BYTE:
- /* parentIndex = BYTE, dataLen = BYTE */
- fputByte( ( BYTE ) dirHeader->parentIndex );
- fputByte( ( BYTE ) dirHeader->dataLen );
- bytesWritten += sizeof( BYTE ) + sizeof( BYTE );
- break;
-
- case DIR_OTHER_BYTE_WORD:
- /* parentIndex = BYTE, dataLen = WORD */
- fputByte( ( BYTE ) dirHeader->parentIndex );
- fputWord( ( WORD ) dirHeader->dataLen );
- bytesWritten += sizeof( BYTE ) + sizeof( WORD );
- break;
-
- case DIR_OTHER_WORD_LONG:
- /* dirIndex = WORD, auxDataLen = LONG */
- fputWord( dirHeader->parentIndex );
- fputLong( dirHeader->dataLen );
- bytesWritten += sizeof( WORD ) + sizeof( LONG );
- }
- fputLong( dirHeader->dirTime );
- bytesWritten += sizeof( BYTE ) + sizeof( LONG );
-
- /* Handle type SPECIAL directories by writing an additional WORD
- containing the directories's hType */
- if( dirInfo & DIR_SPECIAL )
- {
- fputWord( hType );
- bytesWritten += sizeof( WORD );
- }
-
- /* Handle linked directories by writing the linkID */
- if( dirInfo & DIR_LINKED )
- {
- fputWord( linkID );
- bytesWritten += sizeof( WORD );
- }
-
- archiveInfo.noDirHdrs++;
- }
-
- return( bytesWritten );
- }
-
- /* Write the directory names to a file */
-
- static LONG writeDirNames( void )
- {
- LONG bytesWritten = 0L;
- WORD theEntry;
- WORD *wordPtr;
- char *strPtr;
-
- /* Write a dummy name for the encryption header if necessary */
- if( cryptDirDataLength )
- {
- fputByte( '\0' );
- bytesWritten++;
- }
-
- /* Write directory names */
- for( theEntry = dirHdrList[ ROOT_DIR ]->next; theEntry != END_MARKER; \
- theEntry = dirHdrList[ theEntry ]->next )
- if( dirHdrList[ theEntry ]->data.dirInfo & DIR_UNICODE )
- {
- /* Write Unicode string */
- wordPtr = ( WORD * ) dirHdrList[ theEntry ]->dirName;
- do
- {
- fputWord( *wordPtr );
- bytesWritten += sizeof( WORD );
- }
- while( *wordPtr++ );
- }
- else
- {
- /* Write ASCII/EBCDIC string */
- strPtr = dirHdrList[ theEntry ]->dirName;
- do
- {
- fputByte( *strPtr );
- bytesWritten++;
- }
- while( *strPtr++ );
- }
-
- return( bytesWritten );
- }
-
- /* Write the size of each part in a multi-part archive */
-
- static void writePartSizes( void )
- {
- if( flags & MULTIPART_ARCH )
- {
- /* Flag the fact that this is the last part of a multipart archive */
- archiveInfo.specialInfo |= SPECIAL_MULTIEND;
-
- /* Remember where the segmentation information starts */
- segmentEnd = getCurrPosition();
-
- /* Write out the size of each section */
- checksumBegin( RESET_CHECKSUM );
- for( partSizeCurrPtr = partSizeStartPtr; partSizeCurrPtr != NULL; \
- partSizeCurrPtr = partSizeCurrPtr->next )
- fputLong( partSizeCurrPtr->segEnd );
- }
- }
-
- /* Write the directory size information */
-
- static void writeArchiveInfo( void )
- {
- fputWord( archiveInfo.noDirHdrs );
- fputWord( archiveInfo.noFileHdrs );
- fputLong( archiveInfo.dirInfoSize );
-
- /* Calculate checksum for any remaining archive directory data before
- this point and write it */
- checksumEnd();
- fputWord( crc16 );
- }
-
- /* Write the final archive trailer */
-
- static WORD savedCRC;
- static BOOLEAN saveCRC;
-
- static void writeArchiveTrailer( void )
- {
- /* Write the information for the multipart read bootstrap if necessary */
- if( flags & MULTIPART_ARCH )
- {
- /* In case we call writeArchiveTrailer() a second time with altered
- trailer info we calculate the data checksum to this point and save
- it now */
- if( saveCRC )
- {
- checksumEnd();
- savedCRC = crc16;
- }
- else
- crc16 = savedCRC;
-
- /* Write length of authentication/encryption info, total number of
- segments, and end of last segment */
- checksumBegin( NO_RESET_CHECKSUM );
- fputWord( 0 );
- fputWord( lastPart );
- fputLong( segmentEnd );
- checksumEnd();
-
- /* Calculate checksum for any remaining segment data before
- this point and write it */
- fputWord( crc16 );
- }
-
- /* Write the kludge byte */
- if( flags & BLOCK_MODE )
- archiveInfo.specialInfo |= SPECIAL_BLOCK;
- if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
- archiveInfo.specialInfo |= SPECIAL_ENCRYPTED;
- if( cryptFlags & CRYPT_SIGN_ALL )
- archiveInfo.specialInfo |= SPECIAL_SECURED;
- fputByte( archiveInfo.specialInfo );
-
- /* We must use fputByte() to put the archive ID since fputLong() will do
- endianness conversion */
- fputByte( HPACK_ID[ 0 ] );
- fputByte( HPACK_ID[ 1 ] );
- fputByte( HPACK_ID[ 2 ] );
- fputByte( HPACK_ID[ 3 ] );
- }
-
- /* Write the directory data to the archive */
-
- static void writeDirData( void )
- {
- LONG position = 0L, offset, delta, dataLen;
- WORD theEntry, multipartFlagSave = multipartFlags;
-
- /* Turn off multipart reads when saving the directory data */
- multipartFlags &= ~MULTIPART_READ;
-
- /* Write out any data still in the buffer */
- flushDirBuffer();
-
- /* Move the directory data from the temporary file to the archive file.
- We use a loop with fputByte() instead of a moveData() call to take care
- of buffering and handle encryption for us */
- if( dirDataOffset )
- {
- if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
- cryptFileDataLength = cryptBegin( ( cryptFlags & CRYPT_SEC ) ? \
- SECONDARY_KEY : MAIN_KEY );
-
- /* Step through the list of headers moving the data corresponding to
- the header from the dirFile to the archive file. Doing things
- this way is necessary since fixEverything() may have reordered the
- directory headers so that their order no longer corresponds to the
- data in the dirFile */
- setInputFD( dirFileFD );
- hlseek( dirFileFD, 0L, SEEK_SET );
- forceRead();
- for( theEntry = dirHdrList[ ROOT_DIR ]->next; theEntry != END_MARKER; \
- theEntry = dirHdrList[ theEntry ]->next )
- /* Only do the move if there's something to move */
- if( dataLen = dirHdrList[ theEntry ]->data.dataLen )
- {
- if( ( offset = dirHdrList[ theEntry ]->offset ) < position )
- {
- /* Data is behind us, move backwards in dirFile */
- delta = position - offset;
- if( _inByteCount >= delta )
- /* Data is still in buffer; move backwards to it */
- _inByteCount -= ( int ) delta;
- else
- {
- /* Data is outside buffer, go to position */
- hlseek( dirFileFD, offset, SEEK_SET );
- forceRead();
- }
- }
- else
- /* Data is ahead of us; skipSeek to it if necessary */
- if( offset - position )
- skipSeek( offset - position );
-
- /* Move the data across and update position */
- position = offset + dataLen;
- while( dataLen-- )
- /* Not very elegant but it nicely takes care of buffering */
- fputByte( fgetByte() );
- }
-
- if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
- cryptEnd();
- }
- else
- /* Reset encryption header status */
- cryptDirDataLength = 0;
-
- multipartFlags = multipartFlagSave;
-
- /* Zap the dirFile if it exists */
- if( dirFileFD != IO_ERROR )
- {
- hclose( dirFileFD );
- hunlink( dirFileName );
- dirFileFD = IO_ERROR; /* Mark it as invalid */
- }
- }
-
- /* Write the archive directory to a file */
-
- void writeArcDir( void )
- {
- /* Initially we have no crypt information */
- cryptFileDataLength = cryptDirDataLength = 0;
-
- /* Clean up the directory structure if it's safe to do so */
- if( doFixEverything )
- fixEverything();
-
- /* Write the directory data (if any) to the archive */
- writeDirData();
-
- /* Build up archive trailer information and write it. Note that the
- cryptBegin() call must be before the checksumBegin() call since the
- encryption information is covered by its own checksum */
- archiveInfo.specialInfo = 0;
- archiveInfo.dirInfoSize = 0L;
- if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
- archiveInfo.dirInfoSize = ( LONG ) cryptBegin( MAIN_KEY );
- checksumBegin( RESET_CHECKSUM );
- archiveInfo.dirInfoSize += writeDirHeaders();
- archiveInfo.dirInfoSize += writeFileHeaders();
- archiveInfo.dirInfoSize += writeDirNames();
- archiveInfo.dirInfoSize += writeFileNames();
- if( cryptFlags & ( CRYPT_CKE_ALL | CRYPT_PKE_ALL ) )
- cryptEnd();
- archiveInfo.specialInfo |= PROTOTYPE;
- writeArchiveInfo(); /* Write directory size information */
- if( multipartFlags & MULTIPART_WRITE )
- {
- /* Force the evaluation of lastPart and try and write the
- segmentation information and final trailer as one block */
- setWriteType( SAFE_WRITE );
- flushBuffer(); /* Force lastPart evaluation */
- saveCRC = TRUE;
- writePartSizes();
- writeArchiveTrailer(); /* Put info in buffer */
- setWriteType( ATOMIC_WRITE );
- flushBuffer(); /* Write info as one block */
-
- if( !atomicWriteOK )
- {
- /* We need to put the information on a seperate disk. Set the
- high bit of lastPart to flag the fact */
- _outByteCount -= SHORT_TRAILER_SIZE + sizeof( BYTE ) + HPACK_ID_SIZE;
- lastPart |= MULTIPART_SEPERATE_DISK;
- saveCRC = FALSE;
- writeArchiveTrailer(); /* Re-put trailer info in buffer */
- flushBuffer(); /* Write data to single block on disk */
- saveCRC = TRUE;
- }
-
- setWriteType( STD_WRITE );
- }
- else
- {
- /* Sign the archive if required */
- if( cryptFlags & CRYPT_SIGN_ALL )
- {
- flushBuffer(); /* Get all info to sign out of buffers */
- fputWord( createSignature( 0L, getCurrPosition(), signerID ) );
- }
-
- /* Write final trailer information */
- writeArchiveTrailer();
- flushBuffer();
- }
-
- /* If we've ended up deleting all the files in the archive, delete
- the archive itself */
- if( ( archiveInfo.noDirHdrs | archiveInfo.noFileHdrs ) == 0 )
- {
- errorFD = ERROR;
- hunlink( errorFileName );
- }
-
- /* If it's a multipart archive and there is only one part, redo it
- as a normal archive */
- if( ( flags & MULTIPART_ARCH ) && !lastPart )
- {
- /* Move back over output padding and trailer and truncate archive */
- hlseek( archiveFD, -( long ) ( MULTIPART_TRAILER_SIZE + SHORT_TRAILER_SIZE + \
- sizeof( BYTE ) + HPACK_ID_SIZE ), SEEK_END );
- htruncate( archiveFD );
-
- /* Reset its status to a normal single-part archive and rewrite
- the trailer */
- resetFastOut();
- flags &= ~MULTIPART_ARCH;
- multipartFlags = 0;
- archiveInfo.specialInfo &= ~SPECIAL_MULTIEND;
- writeArchiveTrailer();
- flushBuffer();
- }
- }
-