178556Sobrien 278556Sobrien/*-----------------------------------------------------------*/ 378556Sobrien/*--- A block-sorting, lossless compressor bzip2.c ---*/ 478556Sobrien/*-----------------------------------------------------------*/ 578556Sobrien 6167977Sdelphij/* ------------------------------------------------------------------ 7167977Sdelphij This file is part of bzip2/libbzip2, a program and library for 8167977Sdelphij lossless, block-sorting data compression. 978556Sobrien 10215041Sobrien bzip2/libbzip2 version 1.0.6 of 6 September 2010 11215041Sobrien Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> 1278556Sobrien 13167977Sdelphij Please read the WARNING, DISCLAIMER and PATENTS sections in the 14167977Sdelphij README file. 1578556Sobrien 16167977Sdelphij This program is released under the terms of the license contained 17167977Sdelphij in the file LICENSE. 18167977Sdelphij ------------------------------------------------------------------ */ 1978556Sobrien 2078556Sobrien 21167977Sdelphij/* Place a 1 beside your platform, and 0 elsewhere. 22167977Sdelphij Generic 32-bit Unix. 23167977Sdelphij Also works on 64-bit Unix boxes. 24167977Sdelphij This is the default. 25167977Sdelphij*/ 2678556Sobrien#define BZ_UNIX 1 2778556Sobrien 2878556Sobrien/*-- 2978556Sobrien Win32, as seen by Jacob Navia's excellent 3078556Sobrien port of (Chris Fraser & David Hanson)'s excellent 3190067Ssobomax lcc compiler. Or with MS Visual C. 3290067Ssobomax This is selected automatically if compiled by a compiler which 3390067Ssobomax defines _WIN32, not including the Cygwin GCC. 3478556Sobrien--*/ 3578556Sobrien#define BZ_LCCWIN32 0 3678556Sobrien 3778556Sobrien#if defined(_WIN32) && !defined(__CYGWIN__) 3878556Sobrien#undef BZ_LCCWIN32 3978556Sobrien#define BZ_LCCWIN32 1 4078556Sobrien#undef BZ_UNIX 4178556Sobrien#define BZ_UNIX 0 4278556Sobrien#endif 4378556Sobrien 4478556Sobrien 4578556Sobrien/*---------------------------------------------*/ 4678556Sobrien/*-- 4778556Sobrien Some stuff for all platforms. 4878556Sobrien--*/ 4978556Sobrien 5078556Sobrien#include <stdio.h> 5178556Sobrien#include <stdlib.h> 5278556Sobrien#include <string.h> 5378556Sobrien#include <signal.h> 5478556Sobrien#include <math.h> 5578556Sobrien#include <errno.h> 5678556Sobrien#include <ctype.h> 5778556Sobrien#include "bzlib.h" 5878556Sobrien 5978556Sobrien#define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); } 6078556Sobrien#define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); } 6178556Sobrien#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); } 6278556Sobrien 6378556Sobrien 6478556Sobrien/*---------------------------------------------*/ 6578556Sobrien/*-- 6678556Sobrien Platform-specific stuff. 6778556Sobrien--*/ 6878556Sobrien 6978556Sobrien#if BZ_UNIX 7090067Ssobomax# include <fcntl.h> 7178556Sobrien# include <sys/types.h> 7278556Sobrien# include <utime.h> 7378556Sobrien# include <unistd.h> 7478556Sobrien# include <sys/stat.h> 7578556Sobrien# include <sys/times.h> 7678556Sobrien 7778556Sobrien# define PATH_SEP '/' 7878556Sobrien# define MY_LSTAT lstat 7978556Sobrien# define MY_STAT stat 8090067Ssobomax# define MY_S_ISREG S_ISREG 8190067Ssobomax# define MY_S_ISDIR S_ISDIR 8278556Sobrien 8378556Sobrien# define APPEND_FILESPEC(root, name) \ 8478556Sobrien root=snocString((root), (name)) 8578556Sobrien 8678556Sobrien# define APPEND_FLAG(root, name) \ 8778556Sobrien root=snocString((root), (name)) 8878556Sobrien 8978556Sobrien# define SET_BINARY_MODE(fd) /**/ 9078556Sobrien 9178556Sobrien# ifdef __GNUC__ 9278556Sobrien# define NORETURN __attribute__ ((noreturn)) 9378556Sobrien# else 9478556Sobrien# define NORETURN /**/ 9578556Sobrien# endif 9690067Ssobomax 9778556Sobrien# ifdef __DJGPP__ 9878556Sobrien# include <io.h> 9978556Sobrien# include <fcntl.h> 10078556Sobrien# undef MY_LSTAT 10190067Ssobomax# undef MY_STAT 10278556Sobrien# define MY_LSTAT stat 10390067Ssobomax# define MY_STAT stat 10478556Sobrien# undef SET_BINARY_MODE 10578556Sobrien# define SET_BINARY_MODE(fd) \ 10678556Sobrien do { \ 10778556Sobrien int retVal = setmode ( fileno ( fd ), \ 10890067Ssobomax O_BINARY ); \ 10978556Sobrien ERROR_IF_MINUS_ONE ( retVal ); \ 11078556Sobrien } while ( 0 ) 11178556Sobrien# endif 11290067Ssobomax 11378556Sobrien# ifdef __CYGWIN__ 11478556Sobrien# include <io.h> 11578556Sobrien# include <fcntl.h> 11678556Sobrien# undef SET_BINARY_MODE 11778556Sobrien# define SET_BINARY_MODE(fd) \ 11878556Sobrien do { \ 11978556Sobrien int retVal = setmode ( fileno ( fd ), \ 12090067Ssobomax O_BINARY ); \ 12178556Sobrien ERROR_IF_MINUS_ONE ( retVal ); \ 12278556Sobrien } while ( 0 ) 12378556Sobrien# endif 12490067Ssobomax#endif /* BZ_UNIX */ 12578556Sobrien 12678556Sobrien 12778556Sobrien 12878556Sobrien#if BZ_LCCWIN32 12978556Sobrien# include <io.h> 13078556Sobrien# include <fcntl.h> 13178556Sobrien# include <sys\stat.h> 13278556Sobrien 13378556Sobrien# define NORETURN /**/ 13478556Sobrien# define PATH_SEP '\\' 13578556Sobrien# define MY_LSTAT _stat 13678556Sobrien# define MY_STAT _stat 13790067Ssobomax# define MY_S_ISREG(x) ((x) & _S_IFREG) 13890067Ssobomax# define MY_S_ISDIR(x) ((x) & _S_IFDIR) 13978556Sobrien 14078556Sobrien# define APPEND_FLAG(root, name) \ 14178556Sobrien root=snocString((root), (name)) 14278556Sobrien 14378556Sobrien# define APPEND_FILESPEC(root, name) \ 14478556Sobrien root = snocString ((root), (name)) 14578556Sobrien 14678556Sobrien# define SET_BINARY_MODE(fd) \ 14778556Sobrien do { \ 14878556Sobrien int retVal = setmode ( fileno ( fd ), \ 14990067Ssobomax O_BINARY ); \ 15078556Sobrien ERROR_IF_MINUS_ONE ( retVal ); \ 15178556Sobrien } while ( 0 ) 15278556Sobrien 15390067Ssobomax#endif /* BZ_LCCWIN32 */ 15478556Sobrien 15578556Sobrien 15678556Sobrien/*---------------------------------------------*/ 15778556Sobrien/*-- 15878556Sobrien Some more stuff for all platforms :-) 15978556Sobrien--*/ 16078556Sobrien 16178556Sobrientypedef char Char; 16278556Sobrientypedef unsigned char Bool; 16378556Sobrientypedef unsigned char UChar; 16478556Sobrientypedef int Int32; 16578556Sobrientypedef unsigned int UInt32; 16678556Sobrientypedef short Int16; 16778556Sobrientypedef unsigned short UInt16; 16878556Sobrien 16978556Sobrien#define True ((Bool)1) 17078556Sobrien#define False ((Bool)0) 17178556Sobrien 17278556Sobrien/*-- 17378556Sobrien IntNative is your platform's `native' int size. 17478556Sobrien Only here to avoid probs with 64-bit platforms. 17578556Sobrien--*/ 17678556Sobrientypedef int IntNative; 17778556Sobrien 17878556Sobrien 17978556Sobrien/*---------------------------------------------------*/ 18078556Sobrien/*--- Misc (file handling) data decls ---*/ 18178556Sobrien/*---------------------------------------------------*/ 18278556Sobrien 18378556SobrienInt32 verbosity; 18478556SobrienBool keepInputFiles, smallMode, deleteOutputOnInterrupt; 18578556SobrienBool forceOverwrite, testFailsExist, unzFailsExist, noisy; 18678556SobrienInt32 numFileNames, numFilesProcessed, blockSize100k; 18778556SobrienInt32 exitValue; 18878556Sobrien 18978556Sobrien/*-- source modes; F==file, I==stdin, O==stdout --*/ 19078556Sobrien#define SM_I2O 1 19178556Sobrien#define SM_F2O 2 19278556Sobrien#define SM_F2F 3 19378556Sobrien 19478556Sobrien/*-- operation modes --*/ 19578556Sobrien#define OM_Z 1 19678556Sobrien#define OM_UNZ 2 19778556Sobrien#define OM_TEST 3 19878556Sobrien 19978556SobrienInt32 opMode; 20078556SobrienInt32 srcMode; 20178556Sobrien 20278556Sobrien#define FILE_NAME_LEN 1034 20378556Sobrien 20478556SobrienInt32 longestFileName; 20578556SobrienChar inName [FILE_NAME_LEN]; 20678556SobrienChar outName[FILE_NAME_LEN]; 20778556SobrienChar tmpName[FILE_NAME_LEN]; 20878556SobrienChar *progName; 20978556SobrienChar progNameReally[FILE_NAME_LEN]; 21078556SobrienFILE *outputHandleJustInCase; 21178556SobrienInt32 workFactor; 21278556Sobrien 213167977Sdelphijstatic void panic ( const Char* ) NORETURN; 214167977Sdelphijstatic void ioError ( void ) NORETURN; 215167977Sdelphijstatic void outOfMemory ( void ) NORETURN; 216167977Sdelphijstatic void configError ( void ) NORETURN; 217167977Sdelphijstatic void crcError ( void ) NORETURN; 218167977Sdelphijstatic void cleanUpAndFail ( Int32 ) NORETURN; 219167977Sdelphijstatic void compressedStreamEOF ( void ) NORETURN; 22078556Sobrien 22178556Sobrienstatic void copyFileName ( Char*, Char* ); 22278556Sobrienstatic void* myMalloc ( Int32 ); 223167977Sdelphijstatic void applySavedFileAttrToOutputFile ( IntNative fd ); 22478556Sobrien 22578556Sobrien 22678556Sobrien 22778556Sobrien/*---------------------------------------------------*/ 22878556Sobrien/*--- An implementation of 64-bit ints. Sigh. ---*/ 22978556Sobrien/*--- Roll on widespread deployment of ANSI C9X ! ---*/ 23078556Sobrien/*---------------------------------------------------*/ 23178556Sobrien 23278556Sobrientypedef 23378556Sobrien struct { UChar b[8]; } 23478556Sobrien UInt64; 23578556Sobrien 23690067Ssobomax 23778556Sobrienstatic 23878556Sobrienvoid uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 ) 23978556Sobrien{ 24078556Sobrien n->b[7] = (UChar)((hi32 >> 24) & 0xFF); 24178556Sobrien n->b[6] = (UChar)((hi32 >> 16) & 0xFF); 24278556Sobrien n->b[5] = (UChar)((hi32 >> 8) & 0xFF); 24378556Sobrien n->b[4] = (UChar) (hi32 & 0xFF); 24478556Sobrien n->b[3] = (UChar)((lo32 >> 24) & 0xFF); 24578556Sobrien n->b[2] = (UChar)((lo32 >> 16) & 0xFF); 24678556Sobrien n->b[1] = (UChar)((lo32 >> 8) & 0xFF); 24778556Sobrien n->b[0] = (UChar) (lo32 & 0xFF); 24878556Sobrien} 24978556Sobrien 25090067Ssobomax 25178556Sobrienstatic 25278556Sobriendouble uInt64_to_double ( UInt64* n ) 25378556Sobrien{ 25478556Sobrien Int32 i; 25578556Sobrien double base = 1.0; 25678556Sobrien double sum = 0.0; 25778556Sobrien for (i = 0; i < 8; i++) { 25878556Sobrien sum += base * (double)(n->b[i]); 25978556Sobrien base *= 256.0; 26078556Sobrien } 26178556Sobrien return sum; 26278556Sobrien} 26378556Sobrien 26478556Sobrien 26578556Sobrienstatic 26678556SobrienBool uInt64_isZero ( UInt64* n ) 26778556Sobrien{ 26878556Sobrien Int32 i; 26978556Sobrien for (i = 0; i < 8; i++) 27078556Sobrien if (n->b[i] != 0) return 0; 27178556Sobrien return 1; 27278556Sobrien} 27378556Sobrien 27490067Ssobomax 27590067Ssobomax/* Divide *n by 10, and return the remainder. */ 27690067Ssobomaxstatic 27778556SobrienInt32 uInt64_qrm10 ( UInt64* n ) 27878556Sobrien{ 27990067Ssobomax UInt32 rem, tmp; 28078556Sobrien Int32 i; 28190067Ssobomax rem = 0; 28290067Ssobomax for (i = 7; i >= 0; i--) { 28390067Ssobomax tmp = rem * 256 + n->b[i]; 28490067Ssobomax n->b[i] = tmp / 10; 28590067Ssobomax rem = tmp % 10; 28690067Ssobomax } 28790067Ssobomax return rem; 28890067Ssobomax} 28978556Sobrien 29078556Sobrien 29178556Sobrien/* ... and the Whole Entire Point of all this UInt64 stuff is 29278556Sobrien so that we can supply the following function. 29378556Sobrien*/ 29478556Sobrienstatic 29578556Sobrienvoid uInt64_toAscii ( char* outbuf, UInt64* n ) 29678556Sobrien{ 29778556Sobrien Int32 i, q; 29878556Sobrien UChar buf[32]; 29978556Sobrien Int32 nBuf = 0; 30078556Sobrien UInt64 n_copy = *n; 30178556Sobrien do { 30278556Sobrien q = uInt64_qrm10 ( &n_copy ); 30378556Sobrien buf[nBuf] = q + '0'; 30478556Sobrien nBuf++; 30578556Sobrien } while (!uInt64_isZero(&n_copy)); 30678556Sobrien outbuf[nBuf] = 0; 30790067Ssobomax for (i = 0; i < nBuf; i++) 30890067Ssobomax outbuf[i] = buf[nBuf-i-1]; 30978556Sobrien} 31078556Sobrien 31178556Sobrien 31278556Sobrien/*---------------------------------------------------*/ 31378556Sobrien/*--- Processing of complete files and streams ---*/ 31478556Sobrien/*---------------------------------------------------*/ 31578556Sobrien 31678556Sobrien/*---------------------------------------------*/ 31778556Sobrienstatic 31878556SobrienBool myfeof ( FILE* f ) 31978556Sobrien{ 32078556Sobrien Int32 c = fgetc ( f ); 32178556Sobrien if (c == EOF) return True; 32278556Sobrien ungetc ( c, f ); 32378556Sobrien return False; 32478556Sobrien} 32578556Sobrien 32678556Sobrien 32778556Sobrien/*---------------------------------------------*/ 32878556Sobrienstatic 32978556Sobrienvoid compressStream ( FILE *stream, FILE *zStream ) 33078556Sobrien{ 33178556Sobrien BZFILE* bzf = NULL; 33278556Sobrien UChar ibuf[5000]; 33378556Sobrien Int32 nIbuf; 33478556Sobrien UInt32 nbytes_in_lo32, nbytes_in_hi32; 33578556Sobrien UInt32 nbytes_out_lo32, nbytes_out_hi32; 33678556Sobrien Int32 bzerr, bzerr_dummy, ret; 33778556Sobrien 33878556Sobrien SET_BINARY_MODE(stream); 33978556Sobrien SET_BINARY_MODE(zStream); 34078556Sobrien 34178556Sobrien if (ferror(stream)) goto errhandler_io; 34278556Sobrien if (ferror(zStream)) goto errhandler_io; 34378556Sobrien 34478556Sobrien bzf = BZ2_bzWriteOpen ( &bzerr, zStream, 34578556Sobrien blockSize100k, verbosity, workFactor ); 34678556Sobrien if (bzerr != BZ_OK) goto errhandler; 34778556Sobrien 34878556Sobrien if (verbosity >= 2) fprintf ( stderr, "\n" ); 34978556Sobrien 35078556Sobrien while (True) { 35178556Sobrien 35278556Sobrien if (myfeof(stream)) break; 35378556Sobrien nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream ); 35478556Sobrien if (ferror(stream)) goto errhandler_io; 35578556Sobrien if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf ); 35678556Sobrien if (bzerr != BZ_OK) goto errhandler; 35778556Sobrien 35878556Sobrien } 35978556Sobrien 36078556Sobrien BZ2_bzWriteClose64 ( &bzerr, bzf, 0, 36178556Sobrien &nbytes_in_lo32, &nbytes_in_hi32, 36278556Sobrien &nbytes_out_lo32, &nbytes_out_hi32 ); 36378556Sobrien if (bzerr != BZ_OK) goto errhandler; 36478556Sobrien 36578556Sobrien if (ferror(zStream)) goto errhandler_io; 36678556Sobrien ret = fflush ( zStream ); 36778556Sobrien if (ret == EOF) goto errhandler_io; 36878556Sobrien if (zStream != stdout) { 369167977Sdelphij Int32 fd = fileno ( zStream ); 370147666Ssimon if (fd < 0) goto errhandler_io; 371167977Sdelphij applySavedFileAttrToOutputFile ( fd ); 37278556Sobrien ret = fclose ( zStream ); 37390067Ssobomax outputHandleJustInCase = NULL; 37478556Sobrien if (ret == EOF) goto errhandler_io; 37578556Sobrien } 37690067Ssobomax outputHandleJustInCase = NULL; 37778556Sobrien if (ferror(stream)) goto errhandler_io; 37878556Sobrien ret = fclose ( stream ); 37978556Sobrien if (ret == EOF) goto errhandler_io; 38078556Sobrien 38178556Sobrien if (verbosity >= 1) { 38290067Ssobomax if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) { 38390067Ssobomax fprintf ( stderr, " no data compressed.\n"); 38490067Ssobomax } else { 38590067Ssobomax Char buf_nin[32], buf_nout[32]; 38690067Ssobomax UInt64 nbytes_in, nbytes_out; 38790067Ssobomax double nbytes_in_d, nbytes_out_d; 38890067Ssobomax uInt64_from_UInt32s ( &nbytes_in, 38990067Ssobomax nbytes_in_lo32, nbytes_in_hi32 ); 39090067Ssobomax uInt64_from_UInt32s ( &nbytes_out, 39190067Ssobomax nbytes_out_lo32, nbytes_out_hi32 ); 39290067Ssobomax nbytes_in_d = uInt64_to_double ( &nbytes_in ); 39390067Ssobomax nbytes_out_d = uInt64_to_double ( &nbytes_out ); 39490067Ssobomax uInt64_toAscii ( buf_nin, &nbytes_in ); 39590067Ssobomax uInt64_toAscii ( buf_nout, &nbytes_out ); 39690067Ssobomax fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, " 39790067Ssobomax "%5.2f%% saved, %s in, %s out.\n", 39890067Ssobomax nbytes_in_d / nbytes_out_d, 39990067Ssobomax (8.0 * nbytes_out_d) / nbytes_in_d, 40090067Ssobomax 100.0 * (1.0 - nbytes_out_d / nbytes_in_d), 40190067Ssobomax buf_nin, 40290067Ssobomax buf_nout 40390067Ssobomax ); 40490067Ssobomax } 40578556Sobrien } 40678556Sobrien 40778556Sobrien return; 40878556Sobrien 40978556Sobrien errhandler: 41078556Sobrien BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1, 41178556Sobrien &nbytes_in_lo32, &nbytes_in_hi32, 41278556Sobrien &nbytes_out_lo32, &nbytes_out_hi32 ); 41378556Sobrien switch (bzerr) { 41478556Sobrien case BZ_CONFIG_ERROR: 41578556Sobrien configError(); break; 41678556Sobrien case BZ_MEM_ERROR: 41778556Sobrien outOfMemory (); break; 41878556Sobrien case BZ_IO_ERROR: 41978556Sobrien errhandler_io: 42078556Sobrien ioError(); break; 42178556Sobrien default: 42278556Sobrien panic ( "compress:unexpected error" ); 42378556Sobrien } 42478556Sobrien 42578556Sobrien panic ( "compress:end" ); 42678556Sobrien /*notreached*/ 42778556Sobrien} 42878556Sobrien 42978556Sobrien 43078556Sobrien 43178556Sobrien/*---------------------------------------------*/ 43278556Sobrienstatic 43378556SobrienBool uncompressStream ( FILE *zStream, FILE *stream ) 43478556Sobrien{ 43578556Sobrien BZFILE* bzf = NULL; 43678556Sobrien Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i; 43778556Sobrien UChar obuf[5000]; 43878556Sobrien UChar unused[BZ_MAX_UNUSED]; 43978556Sobrien Int32 nUnused; 440146293Sobrien void* unusedTmpV; 44178556Sobrien UChar* unusedTmp; 44278556Sobrien 44378556Sobrien nUnused = 0; 44478556Sobrien streamNo = 0; 44578556Sobrien 44678556Sobrien SET_BINARY_MODE(stream); 44778556Sobrien SET_BINARY_MODE(zStream); 44878556Sobrien 44978556Sobrien if (ferror(stream)) goto errhandler_io; 45078556Sobrien if (ferror(zStream)) goto errhandler_io; 45178556Sobrien 45278556Sobrien while (True) { 45378556Sobrien 45478556Sobrien bzf = BZ2_bzReadOpen ( 45578556Sobrien &bzerr, zStream, verbosity, 45678556Sobrien (int)smallMode, unused, nUnused 45778556Sobrien ); 45878556Sobrien if (bzf == NULL || bzerr != BZ_OK) goto errhandler; 45978556Sobrien streamNo++; 46078556Sobrien 46178556Sobrien while (bzerr == BZ_OK) { 46278556Sobrien nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 ); 46390067Ssobomax if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat; 46478556Sobrien if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0) 46578556Sobrien fwrite ( obuf, sizeof(UChar), nread, stream ); 46678556Sobrien if (ferror(stream)) goto errhandler_io; 46778556Sobrien } 46878556Sobrien if (bzerr != BZ_STREAM_END) goto errhandler; 46978556Sobrien 470146293Sobrien BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused ); 47178556Sobrien if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" ); 47278556Sobrien 473146293Sobrien unusedTmp = (UChar*)unusedTmpV; 47478556Sobrien for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i]; 47578556Sobrien 47678556Sobrien BZ2_bzReadClose ( &bzerr, bzf ); 47778556Sobrien if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" ); 47878556Sobrien 47978556Sobrien if (nUnused == 0 && myfeof(zStream)) break; 48078556Sobrien } 48178556Sobrien 48290067Ssobomax closeok: 48378556Sobrien if (ferror(zStream)) goto errhandler_io; 484167977Sdelphij if (stream != stdout) { 485167977Sdelphij Int32 fd = fileno ( stream ); 486147666Ssimon if (fd < 0) goto errhandler_io; 487167977Sdelphij applySavedFileAttrToOutputFile ( fd ); 488147666Ssimon } 48978556Sobrien ret = fclose ( zStream ); 49078556Sobrien if (ret == EOF) goto errhandler_io; 49178556Sobrien 49278556Sobrien if (ferror(stream)) goto errhandler_io; 49378556Sobrien ret = fflush ( stream ); 49478556Sobrien if (ret != 0) goto errhandler_io; 49578556Sobrien if (stream != stdout) { 49678556Sobrien ret = fclose ( stream ); 49790067Ssobomax outputHandleJustInCase = NULL; 49878556Sobrien if (ret == EOF) goto errhandler_io; 49978556Sobrien } 50090067Ssobomax outputHandleJustInCase = NULL; 50178556Sobrien if (verbosity >= 2) fprintf ( stderr, "\n " ); 50278556Sobrien return True; 50378556Sobrien 50490067Ssobomax trycat: 50590067Ssobomax if (forceOverwrite) { 50690067Ssobomax rewind(zStream); 50790067Ssobomax while (True) { 50890067Ssobomax if (myfeof(zStream)) break; 50990067Ssobomax nread = fread ( obuf, sizeof(UChar), 5000, zStream ); 51090067Ssobomax if (ferror(zStream)) goto errhandler_io; 51190067Ssobomax if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream ); 51290067Ssobomax if (ferror(stream)) goto errhandler_io; 51390067Ssobomax } 51490067Ssobomax goto closeok; 51590067Ssobomax } 51690067Ssobomax 51778556Sobrien errhandler: 51878556Sobrien BZ2_bzReadClose ( &bzerr_dummy, bzf ); 51978556Sobrien switch (bzerr) { 52078556Sobrien case BZ_CONFIG_ERROR: 52178556Sobrien configError(); break; 52278556Sobrien case BZ_IO_ERROR: 52378556Sobrien errhandler_io: 52478556Sobrien ioError(); break; 52578556Sobrien case BZ_DATA_ERROR: 52678556Sobrien crcError(); 52778556Sobrien case BZ_MEM_ERROR: 52878556Sobrien outOfMemory(); 52978556Sobrien case BZ_UNEXPECTED_EOF: 53078556Sobrien compressedStreamEOF(); 53178556Sobrien case BZ_DATA_ERROR_MAGIC: 53278556Sobrien if (zStream != stdin) fclose(zStream); 53378556Sobrien if (stream != stdout) fclose(stream); 53478556Sobrien if (streamNo == 1) { 53578556Sobrien return False; 53678556Sobrien } else { 53778556Sobrien if (noisy) 53878556Sobrien fprintf ( stderr, 53978556Sobrien "\n%s: %s: trailing garbage after EOF ignored\n", 54078556Sobrien progName, inName ); 54178556Sobrien return True; 54278556Sobrien } 54378556Sobrien default: 54478556Sobrien panic ( "decompress:unexpected error" ); 54578556Sobrien } 54678556Sobrien 54778556Sobrien panic ( "decompress:end" ); 54878556Sobrien return True; /*notreached*/ 54978556Sobrien} 55078556Sobrien 55178556Sobrien 55278556Sobrien/*---------------------------------------------*/ 55378556Sobrienstatic 55478556SobrienBool testStream ( FILE *zStream ) 55578556Sobrien{ 55678556Sobrien BZFILE* bzf = NULL; 55778556Sobrien Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i; 55878556Sobrien UChar obuf[5000]; 55978556Sobrien UChar unused[BZ_MAX_UNUSED]; 56078556Sobrien Int32 nUnused; 561146293Sobrien void* unusedTmpV; 56278556Sobrien UChar* unusedTmp; 56378556Sobrien 56478556Sobrien nUnused = 0; 56578556Sobrien streamNo = 0; 56678556Sobrien 56778556Sobrien SET_BINARY_MODE(zStream); 56878556Sobrien if (ferror(zStream)) goto errhandler_io; 56978556Sobrien 57078556Sobrien while (True) { 57178556Sobrien 57278556Sobrien bzf = BZ2_bzReadOpen ( 57378556Sobrien &bzerr, zStream, verbosity, 57478556Sobrien (int)smallMode, unused, nUnused 57578556Sobrien ); 57678556Sobrien if (bzf == NULL || bzerr != BZ_OK) goto errhandler; 57778556Sobrien streamNo++; 57878556Sobrien 57978556Sobrien while (bzerr == BZ_OK) { 58078556Sobrien nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 ); 58178556Sobrien if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler; 58278556Sobrien } 58378556Sobrien if (bzerr != BZ_STREAM_END) goto errhandler; 58478556Sobrien 585146293Sobrien BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused ); 58678556Sobrien if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" ); 58778556Sobrien 588146293Sobrien unusedTmp = (UChar*)unusedTmpV; 58978556Sobrien for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i]; 59078556Sobrien 59178556Sobrien BZ2_bzReadClose ( &bzerr, bzf ); 59278556Sobrien if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" ); 59378556Sobrien if (nUnused == 0 && myfeof(zStream)) break; 59478556Sobrien 59578556Sobrien } 59678556Sobrien 59778556Sobrien if (ferror(zStream)) goto errhandler_io; 59878556Sobrien ret = fclose ( zStream ); 59978556Sobrien if (ret == EOF) goto errhandler_io; 60078556Sobrien 60178556Sobrien if (verbosity >= 2) fprintf ( stderr, "\n " ); 60278556Sobrien return True; 60378556Sobrien 60478556Sobrien errhandler: 60578556Sobrien BZ2_bzReadClose ( &bzerr_dummy, bzf ); 60678556Sobrien if (verbosity == 0) 60778556Sobrien fprintf ( stderr, "%s: %s: ", progName, inName ); 60878556Sobrien switch (bzerr) { 60978556Sobrien case BZ_CONFIG_ERROR: 61078556Sobrien configError(); break; 61178556Sobrien case BZ_IO_ERROR: 61278556Sobrien errhandler_io: 61378556Sobrien ioError(); break; 61478556Sobrien case BZ_DATA_ERROR: 61578556Sobrien fprintf ( stderr, 61678556Sobrien "data integrity (CRC) error in data\n" ); 61778556Sobrien return False; 61878556Sobrien case BZ_MEM_ERROR: 61978556Sobrien outOfMemory(); 62078556Sobrien case BZ_UNEXPECTED_EOF: 62178556Sobrien fprintf ( stderr, 62278556Sobrien "file ends unexpectedly\n" ); 62378556Sobrien return False; 62478556Sobrien case BZ_DATA_ERROR_MAGIC: 62578556Sobrien if (zStream != stdin) fclose(zStream); 62678556Sobrien if (streamNo == 1) { 62778556Sobrien fprintf ( stderr, 62878556Sobrien "bad magic number (file not created by bzip2)\n" ); 62978556Sobrien return False; 63078556Sobrien } else { 63178556Sobrien if (noisy) 63278556Sobrien fprintf ( stderr, 63378556Sobrien "trailing garbage after EOF ignored\n" ); 63478556Sobrien return True; 63578556Sobrien } 63678556Sobrien default: 63778556Sobrien panic ( "test:unexpected error" ); 63878556Sobrien } 63978556Sobrien 64078556Sobrien panic ( "test:end" ); 64178556Sobrien return True; /*notreached*/ 64278556Sobrien} 64378556Sobrien 64478556Sobrien 64578556Sobrien/*---------------------------------------------------*/ 64678556Sobrien/*--- Error [non-] handling grunge ---*/ 64778556Sobrien/*---------------------------------------------------*/ 64878556Sobrien 64978556Sobrien/*---------------------------------------------*/ 65078556Sobrienstatic 65178556Sobrienvoid setExit ( Int32 v ) 65278556Sobrien{ 65378556Sobrien if (v > exitValue) exitValue = v; 65478556Sobrien} 65578556Sobrien 65678556Sobrien 65778556Sobrien/*---------------------------------------------*/ 65878556Sobrienstatic 65978556Sobrienvoid cadvise ( void ) 66078556Sobrien{ 66178556Sobrien if (noisy) 66278556Sobrien fprintf ( 66378556Sobrien stderr, 66478556Sobrien "\nIt is possible that the compressed file(s) have become corrupted.\n" 66578556Sobrien "You can use the -tvv option to test integrity of such files.\n\n" 66690067Ssobomax "You can use the `bzip2recover' program to attempt to recover\n" 66778556Sobrien "data from undamaged sections of corrupted files.\n\n" 66878556Sobrien ); 66978556Sobrien} 67078556Sobrien 67178556Sobrien 67278556Sobrien/*---------------------------------------------*/ 67378556Sobrienstatic 67478556Sobrienvoid showFileNames ( void ) 67578556Sobrien{ 67678556Sobrien if (noisy) 67778556Sobrien fprintf ( 67878556Sobrien stderr, 67978556Sobrien "\tInput file = %s, output file = %s\n", 68078556Sobrien inName, outName 68178556Sobrien ); 68278556Sobrien} 68378556Sobrien 68478556Sobrien 68578556Sobrien/*---------------------------------------------*/ 68678556Sobrienstatic 68778556Sobrienvoid cleanUpAndFail ( Int32 ec ) 68878556Sobrien{ 68990067Ssobomax IntNative retVal; 69090067Ssobomax struct MY_STAT statBuf; 69178556Sobrien 69278556Sobrien if ( srcMode == SM_F2F 69378556Sobrien && opMode != OM_TEST 69478556Sobrien && deleteOutputOnInterrupt ) { 69590067Ssobomax 69690067Ssobomax /* Check whether input file still exists. Delete output file 69790067Ssobomax only if input exists to avoid loss of data. Joerg Prante, 5 69890067Ssobomax January 2002. (JRS 06-Jan-2002: other changes in 1.0.2 mean 69990067Ssobomax this is less likely to happen. But to be ultra-paranoid, we 70090067Ssobomax do the check anyway.) */ 70190067Ssobomax retVal = MY_STAT ( inName, &statBuf ); 70290067Ssobomax if (retVal == 0) { 70390067Ssobomax if (noisy) 70490067Ssobomax fprintf ( stderr, 70590067Ssobomax "%s: Deleting output file %s, if it exists.\n", 70690067Ssobomax progName, outName ); 70790067Ssobomax if (outputHandleJustInCase != NULL) 70890067Ssobomax fclose ( outputHandleJustInCase ); 70990067Ssobomax retVal = remove ( outName ); 71090067Ssobomax if (retVal != 0) 71190067Ssobomax fprintf ( stderr, 71290067Ssobomax "%s: WARNING: deletion of output file " 71390067Ssobomax "(apparently) failed.\n", 71490067Ssobomax progName ); 71590067Ssobomax } else { 71678556Sobrien fprintf ( stderr, 71790067Ssobomax "%s: WARNING: deletion of output file suppressed\n", 71890067Ssobomax progName ); 71990067Ssobomax fprintf ( stderr, 72090067Ssobomax "%s: since input file no longer exists. Output file\n", 72178556Sobrien progName ); 72290067Ssobomax fprintf ( stderr, 72390067Ssobomax "%s: `%s' may be incomplete.\n", 72490067Ssobomax progName, outName ); 72590067Ssobomax fprintf ( stderr, 72690067Ssobomax "%s: I suggest doing an integrity test (bzip2 -tv)" 72790067Ssobomax " of it.\n", 72890067Ssobomax progName ); 72990067Ssobomax } 73078556Sobrien } 73190067Ssobomax 73278556Sobrien if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) { 73378556Sobrien fprintf ( stderr, 73478556Sobrien "%s: WARNING: some files have not been processed:\n" 73590067Ssobomax "%s: %d specified on command line, %d not processed yet.\n\n", 73690067Ssobomax progName, progName, 73790067Ssobomax numFileNames, numFileNames - numFilesProcessed ); 73878556Sobrien } 73978556Sobrien setExit(ec); 74078556Sobrien exit(exitValue); 74178556Sobrien} 74278556Sobrien 74378556Sobrien 74478556Sobrien/*---------------------------------------------*/ 74578556Sobrienstatic 746167977Sdelphijvoid panic ( const Char* s ) 74778556Sobrien{ 74878556Sobrien fprintf ( stderr, 74978556Sobrien "\n%s: PANIC -- internal consistency error:\n" 75078556Sobrien "\t%s\n" 75178556Sobrien "\tThis is a BUG. Please report it to me at:\n" 752146293Sobrien "\tjseward@bzip.org\n", 75378556Sobrien progName, s ); 75478556Sobrien showFileNames(); 75578556Sobrien cleanUpAndFail( 3 ); 75678556Sobrien} 75778556Sobrien 75878556Sobrien 75978556Sobrien/*---------------------------------------------*/ 76078556Sobrienstatic 76178556Sobrienvoid crcError ( void ) 76278556Sobrien{ 76378556Sobrien fprintf ( stderr, 76478556Sobrien "\n%s: Data integrity error when decompressing.\n", 76578556Sobrien progName ); 76678556Sobrien showFileNames(); 76778556Sobrien cadvise(); 76878556Sobrien cleanUpAndFail( 2 ); 76978556Sobrien} 77078556Sobrien 77178556Sobrien 77278556Sobrien/*---------------------------------------------*/ 77378556Sobrienstatic 77478556Sobrienvoid compressedStreamEOF ( void ) 77578556Sobrien{ 77690067Ssobomax if (noisy) { 77790067Ssobomax fprintf ( stderr, 77890067Ssobomax "\n%s: Compressed file ends unexpectedly;\n\t" 77990067Ssobomax "perhaps it is corrupted? *Possible* reason follows.\n", 78090067Ssobomax progName ); 78190067Ssobomax perror ( progName ); 78290067Ssobomax showFileNames(); 78390067Ssobomax cadvise(); 78490067Ssobomax } 78590067Ssobomax cleanUpAndFail( 2 ); 78678556Sobrien} 78778556Sobrien 78878556Sobrien 78978556Sobrien/*---------------------------------------------*/ 79078556Sobrienstatic 79178556Sobrienvoid ioError ( void ) 79278556Sobrien{ 79378556Sobrien fprintf ( stderr, 79478556Sobrien "\n%s: I/O or other error, bailing out. " 79578556Sobrien "Possible reason follows.\n", 79678556Sobrien progName ); 79778556Sobrien perror ( progName ); 79878556Sobrien showFileNames(); 79978556Sobrien cleanUpAndFail( 1 ); 80078556Sobrien} 80178556Sobrien 80278556Sobrien 80378556Sobrien/*---------------------------------------------*/ 80478556Sobrienstatic 80578556Sobrienvoid mySignalCatcher ( IntNative n ) 80678556Sobrien{ 80778556Sobrien fprintf ( stderr, 80878556Sobrien "\n%s: Control-C or similar caught, quitting.\n", 80978556Sobrien progName ); 81078556Sobrien cleanUpAndFail(1); 81178556Sobrien} 81278556Sobrien 81378556Sobrien 81478556Sobrien/*---------------------------------------------*/ 81578556Sobrienstatic 81678556Sobrienvoid mySIGSEGVorSIGBUScatcher ( IntNative n ) 81778556Sobrien{ 81878556Sobrien if (opMode == OM_Z) 81978556Sobrien fprintf ( 82078556Sobrien stderr, 82178556Sobrien "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n" 82278556Sobrien "\n" 82378556Sobrien " Possible causes are (most likely first):\n" 82478556Sobrien " (1) This computer has unreliable memory or cache hardware\n" 82578556Sobrien " (a surprisingly common problem; try a different machine.)\n" 82678556Sobrien " (2) A bug in the compiler used to create this executable\n" 82778556Sobrien " (unlikely, if you didn't compile bzip2 yourself.)\n" 82878556Sobrien " (3) A real bug in bzip2 -- I hope this should never be the case.\n" 82978556Sobrien " The user's manual, Section 4.3, has more info on (1) and (2).\n" 83078556Sobrien " \n" 83178556Sobrien " If you suspect this is a bug in bzip2, or are unsure about (1)\n" 832146293Sobrien " or (2), feel free to report it to me at: jseward@bzip.org.\n" 83378556Sobrien " Section 4.3 of the user's manual describes the info a useful\n" 83478556Sobrien " bug report should have. If the manual is available on your\n" 83578556Sobrien " system, please try and read it before mailing me. If you don't\n" 83678556Sobrien " have the manual or can't be bothered to read it, mail me anyway.\n" 83778556Sobrien "\n", 83878556Sobrien progName ); 83978556Sobrien else 84078556Sobrien fprintf ( 84178556Sobrien stderr, 84278556Sobrien "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n" 84378556Sobrien "\n" 84478556Sobrien " Possible causes are (most likely first):\n" 84578556Sobrien " (1) The compressed data is corrupted, and bzip2's usual checks\n" 84678556Sobrien " failed to detect this. Try bzip2 -tvv my_file.bz2.\n" 84778556Sobrien " (2) This computer has unreliable memory or cache hardware\n" 84878556Sobrien " (a surprisingly common problem; try a different machine.)\n" 84978556Sobrien " (3) A bug in the compiler used to create this executable\n" 85078556Sobrien " (unlikely, if you didn't compile bzip2 yourself.)\n" 85178556Sobrien " (4) A real bug in bzip2 -- I hope this should never be the case.\n" 85278556Sobrien " The user's manual, Section 4.3, has more info on (2) and (3).\n" 85378556Sobrien " \n" 85478556Sobrien " If you suspect this is a bug in bzip2, or are unsure about (2)\n" 855146293Sobrien " or (3), feel free to report it to me at: jseward@bzip.org.\n" 85678556Sobrien " Section 4.3 of the user's manual describes the info a useful\n" 85778556Sobrien " bug report should have. If the manual is available on your\n" 85878556Sobrien " system, please try and read it before mailing me. If you don't\n" 85978556Sobrien " have the manual or can't be bothered to read it, mail me anyway.\n" 86078556Sobrien "\n", 86178556Sobrien progName ); 86278556Sobrien 86378556Sobrien showFileNames(); 86478556Sobrien if (opMode == OM_Z) 86578556Sobrien cleanUpAndFail( 3 ); else 86678556Sobrien { cadvise(); cleanUpAndFail( 2 ); } 86778556Sobrien} 86878556Sobrien 86978556Sobrien 87078556Sobrien/*---------------------------------------------*/ 87178556Sobrienstatic 87278556Sobrienvoid outOfMemory ( void ) 87378556Sobrien{ 87478556Sobrien fprintf ( stderr, 87578556Sobrien "\n%s: couldn't allocate enough memory\n", 87678556Sobrien progName ); 87778556Sobrien showFileNames(); 87878556Sobrien cleanUpAndFail(1); 87978556Sobrien} 88078556Sobrien 88178556Sobrien 88278556Sobrien/*---------------------------------------------*/ 88378556Sobrienstatic 88478556Sobrienvoid configError ( void ) 88578556Sobrien{ 88678556Sobrien fprintf ( stderr, 88778556Sobrien "bzip2: I'm not configured correctly for this platform!\n" 88878556Sobrien "\tI require Int32, Int16 and Char to have sizes\n" 88978556Sobrien "\tof 4, 2 and 1 bytes to run properly, and they don't.\n" 89078556Sobrien "\tProbably you can fix this by defining them correctly,\n" 89178556Sobrien "\tand recompiling. Bye!\n" ); 89278556Sobrien setExit(3); 89378556Sobrien exit(exitValue); 89478556Sobrien} 89578556Sobrien 89678556Sobrien 89778556Sobrien/*---------------------------------------------------*/ 89878556Sobrien/*--- The main driver machinery ---*/ 89978556Sobrien/*---------------------------------------------------*/ 90078556Sobrien 90190067Ssobomax/* All rather crufty. The main problem is that input files 90290067Ssobomax are stat()d multiple times before use. This should be 90390067Ssobomax cleaned up. 90490067Ssobomax*/ 90590067Ssobomax 90678556Sobrien/*---------------------------------------------*/ 90778556Sobrienstatic 90878556Sobrienvoid pad ( Char *s ) 90978556Sobrien{ 91078556Sobrien Int32 i; 91178556Sobrien if ( (Int32)strlen(s) >= longestFileName ) return; 91278556Sobrien for (i = 1; i <= longestFileName - (Int32)strlen(s); i++) 91378556Sobrien fprintf ( stderr, " " ); 91478556Sobrien} 91578556Sobrien 91678556Sobrien 91778556Sobrien/*---------------------------------------------*/ 91878556Sobrienstatic 91978556Sobrienvoid copyFileName ( Char* to, Char* from ) 92078556Sobrien{ 92178556Sobrien if ( strlen(from) > FILE_NAME_LEN-10 ) { 92278556Sobrien fprintf ( 92378556Sobrien stderr, 92478556Sobrien "bzip2: file name\n`%s'\n" 92578556Sobrien "is suspiciously (more than %d chars) long.\n" 92678556Sobrien "Try using a reasonable file name instead. Sorry! :-)\n", 92778556Sobrien from, FILE_NAME_LEN-10 92878556Sobrien ); 92978556Sobrien setExit(1); 93078556Sobrien exit(exitValue); 93178556Sobrien } 93278556Sobrien 93378556Sobrien strncpy(to,from,FILE_NAME_LEN-10); 93478556Sobrien to[FILE_NAME_LEN-10]='\0'; 93578556Sobrien} 93678556Sobrien 93778556Sobrien 93878556Sobrien/*---------------------------------------------*/ 93978556Sobrienstatic 94078556SobrienBool fileExists ( Char* name ) 94178556Sobrien{ 94278556Sobrien FILE *tmp = fopen ( name, "rb" ); 94378556Sobrien Bool exists = (tmp != NULL); 94478556Sobrien if (tmp != NULL) fclose ( tmp ); 94578556Sobrien return exists; 94678556Sobrien} 94778556Sobrien 94878556Sobrien 94978556Sobrien/*---------------------------------------------*/ 95090067Ssobomax/* Open an output file safely with O_EXCL and good permissions. 95190067Ssobomax This avoids a race condition in versions < 1.0.2, in which 95290067Ssobomax the file was first opened and then had its interim permissions 95390067Ssobomax set safely. We instead use open() to create the file with 95490067Ssobomax the interim permissions required. (--- --- rw-). 95590067Ssobomax 95690067Ssobomax For non-Unix platforms, if we are not worrying about 95790067Ssobomax security issues, simple this simply behaves like fopen. 95890067Ssobomax*/ 959167977Sdelphijstatic 96090067SsobomaxFILE* fopen_output_safely ( Char* name, const char* mode ) 96190067Ssobomax{ 96290067Ssobomax# if BZ_UNIX 96390067Ssobomax FILE* fp; 96490067Ssobomax IntNative fh; 96590067Ssobomax fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR); 96690067Ssobomax if (fh == -1) return NULL; 96790067Ssobomax fp = fdopen(fh, mode); 96890067Ssobomax if (fp == NULL) close(fh); 96990067Ssobomax return fp; 97090067Ssobomax# else 97190067Ssobomax return fopen(name, mode); 97290067Ssobomax# endif 97390067Ssobomax} 97490067Ssobomax 97590067Ssobomax 97690067Ssobomax/*---------------------------------------------*/ 97778556Sobrien/*-- 97878556Sobrien if in doubt, return True 97978556Sobrien--*/ 98078556Sobrienstatic 98178556SobrienBool notAStandardFile ( Char* name ) 98278556Sobrien{ 98378556Sobrien IntNative i; 98478556Sobrien struct MY_STAT statBuf; 98578556Sobrien 98678556Sobrien i = MY_LSTAT ( name, &statBuf ); 98778556Sobrien if (i != 0) return True; 98890067Ssobomax if (MY_S_ISREG(statBuf.st_mode)) return False; 98978556Sobrien return True; 99078556Sobrien} 99178556Sobrien 99278556Sobrien 99378556Sobrien/*---------------------------------------------*/ 99478556Sobrien/*-- 99578556Sobrien rac 11/21/98 see if file has hard links to it 99678556Sobrien--*/ 99778556Sobrienstatic 99878556SobrienInt32 countHardLinks ( Char* name ) 99978556Sobrien{ 100078556Sobrien IntNative i; 100178556Sobrien struct MY_STAT statBuf; 100278556Sobrien 100378556Sobrien i = MY_LSTAT ( name, &statBuf ); 100478556Sobrien if (i != 0) return 0; 100578556Sobrien return (statBuf.st_nlink - 1); 100678556Sobrien} 100778556Sobrien 100878556Sobrien 100978556Sobrien/*---------------------------------------------*/ 101090067Ssobomax/* Copy modification date, access date, permissions and owner from the 101190067Ssobomax source to destination file. We have to copy this meta-info off 101290067Ssobomax into fileMetaInfo before starting to compress / decompress it, 101390067Ssobomax because doing it afterwards means we get the wrong access time. 101490067Ssobomax 101590067Ssobomax To complicate matters, in compress() and decompress() below, the 101690067Ssobomax sequence of tests preceding the call to saveInputFileMetaInfo() 101790067Ssobomax involves calling fileExists(), which in turn establishes its result 101890067Ssobomax by attempting to fopen() the file, and if successful, immediately 101990067Ssobomax fclose()ing it again. So we have to assume that the fopen() call 102090067Ssobomax does not cause the access time field to be updated. 102190067Ssobomax 102290067Ssobomax Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems 102390067Ssobomax to imply that merely doing open() will not affect the access time. 102490067Ssobomax Therefore we merely need to hope that the C library only does 102590067Ssobomax open() as a result of fopen(), and not any kind of read()-ahead 102690067Ssobomax cleverness. 102790067Ssobomax 102890067Ssobomax It sounds pretty fragile to me. Whether this carries across 102990067Ssobomax robustly to arbitrary Unix-like platforms (or even works robustly 103090067Ssobomax on this one, RedHat 7.2) is unknown to me. Nevertheless ... 103190067Ssobomax*/ 103290067Ssobomax#if BZ_UNIX 103378556Sobrienstatic 103490067Ssobomaxstruct MY_STAT fileMetaInfo; 103590067Ssobomax#endif 103690067Ssobomax 103790067Ssobomaxstatic 103890067Ssobomaxvoid saveInputFileMetaInfo ( Char *srcName ) 103978556Sobrien{ 104090067Ssobomax# if BZ_UNIX 104190067Ssobomax IntNative retVal; 104290067Ssobomax /* Note use of stat here, not lstat. */ 104390067Ssobomax retVal = MY_STAT( srcName, &fileMetaInfo ); 104490067Ssobomax ERROR_IF_NOT_ZERO ( retVal ); 104590067Ssobomax# endif 104690067Ssobomax} 104790067Ssobomax 104890067Ssobomax 104990067Ssobomaxstatic 1050147666Ssimonvoid applySavedTimeInfoToOutputFile ( Char *dstName ) 105190067Ssobomax{ 105290067Ssobomax# if BZ_UNIX 105378556Sobrien IntNative retVal; 105478556Sobrien struct utimbuf uTimBuf; 105578556Sobrien 105690067Ssobomax uTimBuf.actime = fileMetaInfo.st_atime; 105790067Ssobomax uTimBuf.modtime = fileMetaInfo.st_mtime; 105878556Sobrien 105978556Sobrien retVal = utime ( dstName, &uTimBuf ); 106078556Sobrien ERROR_IF_NOT_ZERO ( retVal ); 1061147666Ssimon# endif 1062147666Ssimon} 106378556Sobrien 1064147666Ssimonstatic 1065167977Sdelphijvoid applySavedFileAttrToOutputFile ( IntNative fd ) 1066147666Ssimon{ 1067147666Ssimon# if BZ_UNIX 1068167977Sdelphij IntNative retVal; 1069147666Ssimon 1070147666Ssimon retVal = fchmod ( fd, fileMetaInfo.st_mode ); 1071167977Sdelphij ERROR_IF_NOT_ZERO ( retVal ); 1072147666Ssimon 1073147666Ssimon (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid ); 107478556Sobrien /* chown() will in many cases return with EPERM, which can 107578556Sobrien be safely ignored. 107678556Sobrien */ 107790067Ssobomax# endif 107878556Sobrien} 107978556Sobrien 108078556Sobrien 108178556Sobrien/*---------------------------------------------*/ 108278556Sobrienstatic 108378556SobrienBool containsDubiousChars ( Char* name ) 108478556Sobrien{ 108590067Ssobomax# if BZ_UNIX 108690067Ssobomax /* On unix, files can contain any characters and the file expansion 108790067Ssobomax * is performed by the shell. 108890067Ssobomax */ 108990067Ssobomax return False; 109090067Ssobomax# else /* ! BZ_UNIX */ 109190067Ssobomax /* On non-unix (Win* platforms), wildcard characters are not allowed in 109290067Ssobomax * filenames. 109390067Ssobomax */ 109478556Sobrien for (; *name != '\0'; name++) 109590067Ssobomax if (*name == '?' || *name == '*') return True; 109690067Ssobomax return False; 109790067Ssobomax# endif /* BZ_UNIX */ 109878556Sobrien} 109978556Sobrien 110078556Sobrien 110178556Sobrien/*---------------------------------------------*/ 110278556Sobrien#define BZ_N_SUFFIX_PAIRS 4 110378556Sobrien 1104167977Sdelphijconst Char* zSuffix[BZ_N_SUFFIX_PAIRS] 110578556Sobrien = { ".bz2", ".bz", ".tbz2", ".tbz" }; 1106167977Sdelphijconst Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 110778556Sobrien = { "", "", ".tar", ".tar" }; 110878556Sobrien 110978556Sobrienstatic 1110167977SdelphijBool hasSuffix ( Char* s, const Char* suffix ) 111178556Sobrien{ 111278556Sobrien Int32 ns = strlen(s); 111378556Sobrien Int32 nx = strlen(suffix); 111478556Sobrien if (ns < nx) return False; 111578556Sobrien if (strcmp(s + ns - nx, suffix) == 0) return True; 111678556Sobrien return False; 111778556Sobrien} 111878556Sobrien 111978556Sobrienstatic 112078556SobrienBool mapSuffix ( Char* name, 1121167977Sdelphij const Char* oldSuffix, 1122167977Sdelphij const Char* newSuffix ) 112378556Sobrien{ 112478556Sobrien if (!hasSuffix(name,oldSuffix)) return False; 112578556Sobrien name[strlen(name)-strlen(oldSuffix)] = 0; 112678556Sobrien strcat ( name, newSuffix ); 112778556Sobrien return True; 112878556Sobrien} 112978556Sobrien 113078556Sobrien 113178556Sobrien/*---------------------------------------------*/ 113278556Sobrienstatic 113378556Sobrienvoid compress ( Char *name ) 113478556Sobrien{ 113578556Sobrien FILE *inStr; 113678556Sobrien FILE *outStr; 113778556Sobrien Int32 n, i; 113890067Ssobomax struct MY_STAT statBuf; 113978556Sobrien 114078556Sobrien deleteOutputOnInterrupt = False; 114178556Sobrien 114278556Sobrien if (name == NULL && srcMode != SM_I2O) 114378556Sobrien panic ( "compress: bad modes\n" ); 114478556Sobrien 114578556Sobrien switch (srcMode) { 114678556Sobrien case SM_I2O: 1147167977Sdelphij copyFileName ( inName, (Char*)"(stdin)" ); 1148167977Sdelphij copyFileName ( outName, (Char*)"(stdout)" ); 114978556Sobrien break; 115078556Sobrien case SM_F2F: 115178556Sobrien copyFileName ( inName, name ); 115278556Sobrien copyFileName ( outName, name ); 115378556Sobrien strcat ( outName, ".bz2" ); 115478556Sobrien break; 115578556Sobrien case SM_F2O: 115678556Sobrien copyFileName ( inName, name ); 1157167977Sdelphij copyFileName ( outName, (Char*)"(stdout)" ); 115878556Sobrien break; 115978556Sobrien } 116078556Sobrien 116178556Sobrien if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) { 116278556Sobrien if (noisy) 116378556Sobrien fprintf ( stderr, "%s: There are no files matching `%s'.\n", 116478556Sobrien progName, inName ); 116578556Sobrien setExit(1); 116678556Sobrien return; 116778556Sobrien } 116878556Sobrien if ( srcMode != SM_I2O && !fileExists ( inName ) ) { 116978556Sobrien fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 117078556Sobrien progName, inName, strerror(errno) ); 117178556Sobrien setExit(1); 117278556Sobrien return; 117378556Sobrien } 117478556Sobrien for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) { 117578556Sobrien if (hasSuffix(inName, zSuffix[i])) { 117678556Sobrien if (noisy) 117778556Sobrien fprintf ( stderr, 117878556Sobrien "%s: Input file %s already has %s suffix.\n", 117978556Sobrien progName, inName, zSuffix[i] ); 118078556Sobrien setExit(1); 118178556Sobrien return; 118278556Sobrien } 118378556Sobrien } 118490067Ssobomax if ( srcMode == SM_F2F || srcMode == SM_F2O ) { 118590067Ssobomax MY_STAT(inName, &statBuf); 118690067Ssobomax if ( MY_S_ISDIR(statBuf.st_mode) ) { 118790067Ssobomax fprintf( stderr, 118890067Ssobomax "%s: Input file %s is a directory.\n", 118990067Ssobomax progName,inName); 119090067Ssobomax setExit(1); 119190067Ssobomax return; 119290067Ssobomax } 119390067Ssobomax } 119478556Sobrien if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) { 119578556Sobrien if (noisy) 119678556Sobrien fprintf ( stderr, "%s: Input file %s is not a normal file.\n", 119778556Sobrien progName, inName ); 119878556Sobrien setExit(1); 119978556Sobrien return; 120078556Sobrien } 120190067Ssobomax if ( srcMode == SM_F2F && fileExists ( outName ) ) { 120290067Ssobomax if (forceOverwrite) { 120390067Ssobomax remove(outName); 120490067Ssobomax } else { 120590067Ssobomax fprintf ( stderr, "%s: Output file %s already exists.\n", 120690067Ssobomax progName, outName ); 120790067Ssobomax setExit(1); 120890067Ssobomax return; 120990067Ssobomax } 121078556Sobrien } 121178556Sobrien if ( srcMode == SM_F2F && !forceOverwrite && 121278556Sobrien (n=countHardLinks ( inName )) > 0) { 121378556Sobrien fprintf ( stderr, "%s: Input file %s has %d other link%s.\n", 121478556Sobrien progName, inName, n, n > 1 ? "s" : "" ); 121578556Sobrien setExit(1); 121678556Sobrien return; 121778556Sobrien } 121878556Sobrien 121990067Ssobomax if ( srcMode == SM_F2F ) { 122090067Ssobomax /* Save the file's meta-info before we open it. Doing it later 122190067Ssobomax means we mess up the access times. */ 122290067Ssobomax saveInputFileMetaInfo ( inName ); 122390067Ssobomax } 122490067Ssobomax 122578556Sobrien switch ( srcMode ) { 122678556Sobrien 122778556Sobrien case SM_I2O: 122878556Sobrien inStr = stdin; 122978556Sobrien outStr = stdout; 123078556Sobrien if ( isatty ( fileno ( stdout ) ) ) { 123178556Sobrien fprintf ( stderr, 123278556Sobrien "%s: I won't write compressed data to a terminal.\n", 123378556Sobrien progName ); 123478556Sobrien fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 123578556Sobrien progName, progName ); 123678556Sobrien setExit(1); 123778556Sobrien return; 123878556Sobrien }; 123978556Sobrien break; 124078556Sobrien 124178556Sobrien case SM_F2O: 124278556Sobrien inStr = fopen ( inName, "rb" ); 124378556Sobrien outStr = stdout; 124478556Sobrien if ( isatty ( fileno ( stdout ) ) ) { 124578556Sobrien fprintf ( stderr, 124678556Sobrien "%s: I won't write compressed data to a terminal.\n", 124778556Sobrien progName ); 124878556Sobrien fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 124978556Sobrien progName, progName ); 125078556Sobrien if ( inStr != NULL ) fclose ( inStr ); 125178556Sobrien setExit(1); 125278556Sobrien return; 125378556Sobrien }; 125478556Sobrien if ( inStr == NULL ) { 125578556Sobrien fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 125678556Sobrien progName, inName, strerror(errno) ); 125778556Sobrien setExit(1); 125878556Sobrien return; 125978556Sobrien }; 126078556Sobrien break; 126178556Sobrien 126278556Sobrien case SM_F2F: 126378556Sobrien inStr = fopen ( inName, "rb" ); 126490067Ssobomax outStr = fopen_output_safely ( outName, "wb" ); 126578556Sobrien if ( outStr == NULL) { 126678556Sobrien fprintf ( stderr, "%s: Can't create output file %s: %s.\n", 126778556Sobrien progName, outName, strerror(errno) ); 126878556Sobrien if ( inStr != NULL ) fclose ( inStr ); 126978556Sobrien setExit(1); 127078556Sobrien return; 127178556Sobrien } 127278556Sobrien if ( inStr == NULL ) { 127378556Sobrien fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 127478556Sobrien progName, inName, strerror(errno) ); 127578556Sobrien if ( outStr != NULL ) fclose ( outStr ); 127678556Sobrien setExit(1); 127778556Sobrien return; 127878556Sobrien }; 127978556Sobrien break; 128078556Sobrien 128178556Sobrien default: 128278556Sobrien panic ( "compress: bad srcMode" ); 128378556Sobrien break; 128478556Sobrien } 128578556Sobrien 128678556Sobrien if (verbosity >= 1) { 128778556Sobrien fprintf ( stderr, " %s: ", inName ); 128878556Sobrien pad ( inName ); 128978556Sobrien fflush ( stderr ); 129078556Sobrien } 129178556Sobrien 129278556Sobrien /*--- Now the input and output handles are sane. Do the Biz. ---*/ 129378556Sobrien outputHandleJustInCase = outStr; 129478556Sobrien deleteOutputOnInterrupt = True; 129578556Sobrien compressStream ( inStr, outStr ); 129678556Sobrien outputHandleJustInCase = NULL; 129778556Sobrien 129878556Sobrien /*--- If there was an I/O error, we won't get here. ---*/ 129978556Sobrien if ( srcMode == SM_F2F ) { 1300147666Ssimon applySavedTimeInfoToOutputFile ( outName ); 130178556Sobrien deleteOutputOnInterrupt = False; 130278556Sobrien if ( !keepInputFiles ) { 130378556Sobrien IntNative retVal = remove ( inName ); 130478556Sobrien ERROR_IF_NOT_ZERO ( retVal ); 130578556Sobrien } 130678556Sobrien } 130778556Sobrien 130878556Sobrien deleteOutputOnInterrupt = False; 130978556Sobrien} 131078556Sobrien 131178556Sobrien 131278556Sobrien/*---------------------------------------------*/ 131378556Sobrienstatic 131478556Sobrienvoid uncompress ( Char *name ) 131578556Sobrien{ 131678556Sobrien FILE *inStr; 131778556Sobrien FILE *outStr; 131878556Sobrien Int32 n, i; 131978556Sobrien Bool magicNumberOK; 132078556Sobrien Bool cantGuess; 132190067Ssobomax struct MY_STAT statBuf; 132278556Sobrien 132378556Sobrien deleteOutputOnInterrupt = False; 132478556Sobrien 132578556Sobrien if (name == NULL && srcMode != SM_I2O) 132678556Sobrien panic ( "uncompress: bad modes\n" ); 132778556Sobrien 132878556Sobrien cantGuess = False; 132978556Sobrien switch (srcMode) { 133078556Sobrien case SM_I2O: 1331167977Sdelphij copyFileName ( inName, (Char*)"(stdin)" ); 1332167977Sdelphij copyFileName ( outName, (Char*)"(stdout)" ); 133378556Sobrien break; 133478556Sobrien case SM_F2F: 133578556Sobrien copyFileName ( inName, name ); 133678556Sobrien copyFileName ( outName, name ); 133778556Sobrien for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) 133878556Sobrien if (mapSuffix(outName,zSuffix[i],unzSuffix[i])) 133978556Sobrien goto zzz; 134078556Sobrien cantGuess = True; 134178556Sobrien strcat ( outName, ".out" ); 134278556Sobrien break; 134378556Sobrien case SM_F2O: 134478556Sobrien copyFileName ( inName, name ); 1345167977Sdelphij copyFileName ( outName, (Char*)"(stdout)" ); 134678556Sobrien break; 134778556Sobrien } 134878556Sobrien 134978556Sobrien zzz: 135078556Sobrien if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) { 135178556Sobrien if (noisy) 135278556Sobrien fprintf ( stderr, "%s: There are no files matching `%s'.\n", 135378556Sobrien progName, inName ); 135478556Sobrien setExit(1); 135578556Sobrien return; 135678556Sobrien } 135778556Sobrien if ( srcMode != SM_I2O && !fileExists ( inName ) ) { 135878556Sobrien fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 135978556Sobrien progName, inName, strerror(errno) ); 136078556Sobrien setExit(1); 136178556Sobrien return; 136278556Sobrien } 136390067Ssobomax if ( srcMode == SM_F2F || srcMode == SM_F2O ) { 136490067Ssobomax MY_STAT(inName, &statBuf); 136590067Ssobomax if ( MY_S_ISDIR(statBuf.st_mode) ) { 136690067Ssobomax fprintf( stderr, 136790067Ssobomax "%s: Input file %s is a directory.\n", 136890067Ssobomax progName,inName); 136990067Ssobomax setExit(1); 137090067Ssobomax return; 137190067Ssobomax } 137290067Ssobomax } 137378556Sobrien if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) { 137478556Sobrien if (noisy) 137578556Sobrien fprintf ( stderr, "%s: Input file %s is not a normal file.\n", 137678556Sobrien progName, inName ); 137778556Sobrien setExit(1); 137878556Sobrien return; 137978556Sobrien } 138078556Sobrien if ( /* srcMode == SM_F2F implied && */ cantGuess ) { 138178556Sobrien if (noisy) 138278556Sobrien fprintf ( stderr, 138378556Sobrien "%s: Can't guess original name for %s -- using %s\n", 138478556Sobrien progName, inName, outName ); 138578556Sobrien /* just a warning, no return */ 138678556Sobrien } 138790067Ssobomax if ( srcMode == SM_F2F && fileExists ( outName ) ) { 138890067Ssobomax if (forceOverwrite) { 138990067Ssobomax remove(outName); 139090067Ssobomax } else { 139190067Ssobomax fprintf ( stderr, "%s: Output file %s already exists.\n", 139290067Ssobomax progName, outName ); 139390067Ssobomax setExit(1); 139490067Ssobomax return; 139590067Ssobomax } 139678556Sobrien } 139778556Sobrien if ( srcMode == SM_F2F && !forceOverwrite && 139878556Sobrien (n=countHardLinks ( inName ) ) > 0) { 139978556Sobrien fprintf ( stderr, "%s: Input file %s has %d other link%s.\n", 140078556Sobrien progName, inName, n, n > 1 ? "s" : "" ); 140178556Sobrien setExit(1); 140278556Sobrien return; 140378556Sobrien } 140478556Sobrien 140590067Ssobomax if ( srcMode == SM_F2F ) { 140690067Ssobomax /* Save the file's meta-info before we open it. Doing it later 140790067Ssobomax means we mess up the access times. */ 140890067Ssobomax saveInputFileMetaInfo ( inName ); 140990067Ssobomax } 141090067Ssobomax 141178556Sobrien switch ( srcMode ) { 141278556Sobrien 141378556Sobrien case SM_I2O: 141478556Sobrien inStr = stdin; 141578556Sobrien outStr = stdout; 141678556Sobrien if ( isatty ( fileno ( stdin ) ) ) { 141778556Sobrien fprintf ( stderr, 141878556Sobrien "%s: I won't read compressed data from a terminal.\n", 141978556Sobrien progName ); 142078556Sobrien fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 142178556Sobrien progName, progName ); 142278556Sobrien setExit(1); 142378556Sobrien return; 142478556Sobrien }; 142578556Sobrien break; 142678556Sobrien 142778556Sobrien case SM_F2O: 142878556Sobrien inStr = fopen ( inName, "rb" ); 142978556Sobrien outStr = stdout; 143078556Sobrien if ( inStr == NULL ) { 143178556Sobrien fprintf ( stderr, "%s: Can't open input file %s:%s.\n", 143278556Sobrien progName, inName, strerror(errno) ); 143378556Sobrien if ( inStr != NULL ) fclose ( inStr ); 143478556Sobrien setExit(1); 143578556Sobrien return; 143678556Sobrien }; 143778556Sobrien break; 143878556Sobrien 143978556Sobrien case SM_F2F: 144078556Sobrien inStr = fopen ( inName, "rb" ); 144190067Ssobomax outStr = fopen_output_safely ( outName, "wb" ); 144278556Sobrien if ( outStr == NULL) { 144378556Sobrien fprintf ( stderr, "%s: Can't create output file %s: %s.\n", 144478556Sobrien progName, outName, strerror(errno) ); 144578556Sobrien if ( inStr != NULL ) fclose ( inStr ); 144678556Sobrien setExit(1); 144778556Sobrien return; 144878556Sobrien } 144978556Sobrien if ( inStr == NULL ) { 145078556Sobrien fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 145178556Sobrien progName, inName, strerror(errno) ); 145278556Sobrien if ( outStr != NULL ) fclose ( outStr ); 145378556Sobrien setExit(1); 145478556Sobrien return; 145578556Sobrien }; 145678556Sobrien break; 145778556Sobrien 145878556Sobrien default: 145978556Sobrien panic ( "uncompress: bad srcMode" ); 146078556Sobrien break; 146178556Sobrien } 146278556Sobrien 146378556Sobrien if (verbosity >= 1) { 146478556Sobrien fprintf ( stderr, " %s: ", inName ); 146578556Sobrien pad ( inName ); 146678556Sobrien fflush ( stderr ); 146778556Sobrien } 146878556Sobrien 146978556Sobrien /*--- Now the input and output handles are sane. Do the Biz. ---*/ 147078556Sobrien outputHandleJustInCase = outStr; 147178556Sobrien deleteOutputOnInterrupt = True; 147278556Sobrien magicNumberOK = uncompressStream ( inStr, outStr ); 147378556Sobrien outputHandleJustInCase = NULL; 147478556Sobrien 147578556Sobrien /*--- If there was an I/O error, we won't get here. ---*/ 147678556Sobrien if ( magicNumberOK ) { 147778556Sobrien if ( srcMode == SM_F2F ) { 1478147666Ssimon applySavedTimeInfoToOutputFile ( outName ); 147978556Sobrien deleteOutputOnInterrupt = False; 148078556Sobrien if ( !keepInputFiles ) { 148178556Sobrien IntNative retVal = remove ( inName ); 148278556Sobrien ERROR_IF_NOT_ZERO ( retVal ); 148378556Sobrien } 148478556Sobrien } 148578556Sobrien } else { 148678556Sobrien unzFailsExist = True; 148778556Sobrien deleteOutputOnInterrupt = False; 148878556Sobrien if ( srcMode == SM_F2F ) { 148978556Sobrien IntNative retVal = remove ( outName ); 149078556Sobrien ERROR_IF_NOT_ZERO ( retVal ); 149178556Sobrien } 149278556Sobrien } 149378556Sobrien deleteOutputOnInterrupt = False; 149478556Sobrien 149578556Sobrien if ( magicNumberOK ) { 149678556Sobrien if (verbosity >= 1) 149778556Sobrien fprintf ( stderr, "done\n" ); 149878556Sobrien } else { 149978556Sobrien setExit(2); 150078556Sobrien if (verbosity >= 1) 150178556Sobrien fprintf ( stderr, "not a bzip2 file.\n" ); else 150278556Sobrien fprintf ( stderr, 150378556Sobrien "%s: %s is not a bzip2 file.\n", 150478556Sobrien progName, inName ); 150578556Sobrien } 150678556Sobrien 150778556Sobrien} 150878556Sobrien 150978556Sobrien 151078556Sobrien/*---------------------------------------------*/ 151178556Sobrienstatic 151278556Sobrienvoid testf ( Char *name ) 151378556Sobrien{ 151478556Sobrien FILE *inStr; 151578556Sobrien Bool allOK; 151690067Ssobomax struct MY_STAT statBuf; 151778556Sobrien 151878556Sobrien deleteOutputOnInterrupt = False; 151978556Sobrien 152078556Sobrien if (name == NULL && srcMode != SM_I2O) 152178556Sobrien panic ( "testf: bad modes\n" ); 152278556Sobrien 1523167977Sdelphij copyFileName ( outName, (Char*)"(none)" ); 152478556Sobrien switch (srcMode) { 1525167977Sdelphij case SM_I2O: copyFileName ( inName, (Char*)"(stdin)" ); break; 152678556Sobrien case SM_F2F: copyFileName ( inName, name ); break; 152778556Sobrien case SM_F2O: copyFileName ( inName, name ); break; 152878556Sobrien } 152978556Sobrien 153078556Sobrien if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) { 153178556Sobrien if (noisy) 153278556Sobrien fprintf ( stderr, "%s: There are no files matching `%s'.\n", 153378556Sobrien progName, inName ); 153478556Sobrien setExit(1); 153578556Sobrien return; 153678556Sobrien } 153778556Sobrien if ( srcMode != SM_I2O && !fileExists ( inName ) ) { 153878556Sobrien fprintf ( stderr, "%s: Can't open input %s: %s.\n", 153978556Sobrien progName, inName, strerror(errno) ); 154078556Sobrien setExit(1); 154178556Sobrien return; 154278556Sobrien } 154390067Ssobomax if ( srcMode != SM_I2O ) { 154490067Ssobomax MY_STAT(inName, &statBuf); 154590067Ssobomax if ( MY_S_ISDIR(statBuf.st_mode) ) { 154690067Ssobomax fprintf( stderr, 154790067Ssobomax "%s: Input file %s is a directory.\n", 154890067Ssobomax progName,inName); 154990067Ssobomax setExit(1); 155090067Ssobomax return; 155190067Ssobomax } 155290067Ssobomax } 155378556Sobrien 155478556Sobrien switch ( srcMode ) { 155578556Sobrien 155678556Sobrien case SM_I2O: 155778556Sobrien if ( isatty ( fileno ( stdin ) ) ) { 155878556Sobrien fprintf ( stderr, 155978556Sobrien "%s: I won't read compressed data from a terminal.\n", 156078556Sobrien progName ); 156178556Sobrien fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 156278556Sobrien progName, progName ); 156378556Sobrien setExit(1); 156478556Sobrien return; 156578556Sobrien }; 156678556Sobrien inStr = stdin; 156778556Sobrien break; 156878556Sobrien 156978556Sobrien case SM_F2O: case SM_F2F: 157078556Sobrien inStr = fopen ( inName, "rb" ); 157178556Sobrien if ( inStr == NULL ) { 157278556Sobrien fprintf ( stderr, "%s: Can't open input file %s:%s.\n", 157378556Sobrien progName, inName, strerror(errno) ); 157478556Sobrien setExit(1); 157578556Sobrien return; 157678556Sobrien }; 157778556Sobrien break; 157878556Sobrien 157978556Sobrien default: 158078556Sobrien panic ( "testf: bad srcMode" ); 158178556Sobrien break; 158278556Sobrien } 158378556Sobrien 158478556Sobrien if (verbosity >= 1) { 158578556Sobrien fprintf ( stderr, " %s: ", inName ); 158678556Sobrien pad ( inName ); 158778556Sobrien fflush ( stderr ); 158878556Sobrien } 158978556Sobrien 159078556Sobrien /*--- Now the input handle is sane. Do the Biz. ---*/ 159190067Ssobomax outputHandleJustInCase = NULL; 159278556Sobrien allOK = testStream ( inStr ); 159378556Sobrien 159478556Sobrien if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" ); 159578556Sobrien if (!allOK) testFailsExist = True; 159678556Sobrien} 159778556Sobrien 159878556Sobrien 159978556Sobrien/*---------------------------------------------*/ 160078556Sobrienstatic 160178556Sobrienvoid license ( void ) 160278556Sobrien{ 160378556Sobrien fprintf ( stderr, 160478556Sobrien 160578556Sobrien "bzip2, a block-sorting file compressor. " 160678556Sobrien "Version %s.\n" 160778556Sobrien " \n" 1608215041Sobrien " Copyright (C) 1996-2010 by Julian Seward.\n" 160978556Sobrien " \n" 161078556Sobrien " This program is free software; you can redistribute it and/or modify\n" 161178556Sobrien " it under the terms set out in the LICENSE file, which is included\n" 1612215041Sobrien " in the bzip2-1.0.6 source distribution.\n" 161378556Sobrien " \n" 161478556Sobrien " This program is distributed in the hope that it will be useful,\n" 161578556Sobrien " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 161678556Sobrien " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 161778556Sobrien " LICENSE file for more details.\n" 161878556Sobrien " \n", 161978556Sobrien BZ2_bzlibVersion() 162078556Sobrien ); 162178556Sobrien} 162278556Sobrien 162378556Sobrien 162478556Sobrien/*---------------------------------------------*/ 162578556Sobrienstatic 162678556Sobrienvoid usage ( Char *fullProgName ) 162778556Sobrien{ 162878556Sobrien fprintf ( 162978556Sobrien stderr, 163078556Sobrien "bzip2, a block-sorting file compressor. " 163178556Sobrien "Version %s.\n" 163278556Sobrien "\n usage: %s [flags and input files in any order]\n" 163378556Sobrien "\n" 163478556Sobrien " -h --help print this message\n" 163578556Sobrien " -d --decompress force decompression\n" 163678556Sobrien " -z --compress force compression\n" 163778556Sobrien " -k --keep keep (don't delete) input files\n" 163878556Sobrien " -f --force overwrite existing output files\n" 163978556Sobrien " -t --test test compressed file integrity\n" 164078556Sobrien " -c --stdout output to standard out\n" 164178556Sobrien " -q --quiet suppress noncritical error messages\n" 164278556Sobrien " -v --verbose be verbose (a 2nd -v gives more)\n" 164378556Sobrien " -L --license display software version & license\n" 164478556Sobrien " -V --version display software version & license\n" 164578556Sobrien " -s --small use less memory (at most 2500k)\n" 164678556Sobrien " -1 .. -9 set block size to 100k .. 900k\n" 164790067Ssobomax " --fast alias for -1\n" 164890067Ssobomax " --best alias for -9\n" 164978556Sobrien "\n" 165078556Sobrien " If invoked as `bzip2', default action is to compress.\n" 165178556Sobrien " as `bunzip2', default action is to decompress.\n" 165278556Sobrien " as `bzcat', default action is to decompress to stdout.\n" 165378556Sobrien "\n" 165478556Sobrien " If no file names are given, bzip2 compresses or decompresses\n" 165578556Sobrien " from standard input to standard output. You can combine\n" 165678556Sobrien " short flags, so `-v -4' means the same as -v4 or -4v, &c.\n" 165790067Ssobomax# if BZ_UNIX 165878556Sobrien "\n" 165990067Ssobomax# endif 166078556Sobrien , 166178556Sobrien 166278556Sobrien BZ2_bzlibVersion(), 166378556Sobrien fullProgName 166478556Sobrien ); 166578556Sobrien} 166678556Sobrien 166778556Sobrien 166878556Sobrien/*---------------------------------------------*/ 166978556Sobrienstatic 167078556Sobrienvoid redundant ( Char* flag ) 167178556Sobrien{ 167278556Sobrien fprintf ( 167378556Sobrien stderr, 167478556Sobrien "%s: %s is redundant in versions 0.9.5 and above\n", 167578556Sobrien progName, flag ); 167678556Sobrien} 167778556Sobrien 167878556Sobrien 167978556Sobrien/*---------------------------------------------*/ 168078556Sobrien/*-- 168178556Sobrien All the garbage from here to main() is purely to 168278556Sobrien implement a linked list of command-line arguments, 168378556Sobrien into which main() copies argv[1 .. argc-1]. 168478556Sobrien 168578556Sobrien The purpose of this exercise is to facilitate 168678556Sobrien the expansion of wildcard characters * and ? in 168778556Sobrien filenames for OSs which don't know how to do it 168878556Sobrien themselves, like MSDOS, Windows 95 and NT. 168978556Sobrien 169078556Sobrien The actual Dirty Work is done by the platform- 169178556Sobrien specific macro APPEND_FILESPEC. 169278556Sobrien--*/ 169378556Sobrien 169478556Sobrientypedef 169578556Sobrien struct zzzz { 169678556Sobrien Char *name; 169778556Sobrien struct zzzz *link; 169878556Sobrien } 169978556Sobrien Cell; 170078556Sobrien 170178556Sobrien 170278556Sobrien/*---------------------------------------------*/ 170378556Sobrienstatic 170478556Sobrienvoid *myMalloc ( Int32 n ) 170578556Sobrien{ 170678556Sobrien void* p; 170778556Sobrien 170878556Sobrien p = malloc ( (size_t)n ); 170978556Sobrien if (p == NULL) outOfMemory (); 171078556Sobrien return p; 171178556Sobrien} 171278556Sobrien 171378556Sobrien 171478556Sobrien/*---------------------------------------------*/ 171578556Sobrienstatic 171678556SobrienCell *mkCell ( void ) 171778556Sobrien{ 171878556Sobrien Cell *c; 171978556Sobrien 172078556Sobrien c = (Cell*) myMalloc ( sizeof ( Cell ) ); 172178556Sobrien c->name = NULL; 172278556Sobrien c->link = NULL; 172378556Sobrien return c; 172478556Sobrien} 172578556Sobrien 172678556Sobrien 172778556Sobrien/*---------------------------------------------*/ 172878556Sobrienstatic 172978556SobrienCell *snocString ( Cell *root, Char *name ) 173078556Sobrien{ 173178556Sobrien if (root == NULL) { 173278556Sobrien Cell *tmp = mkCell(); 173378556Sobrien tmp->name = (Char*) myMalloc ( 5 + strlen(name) ); 173478556Sobrien strcpy ( tmp->name, name ); 173578556Sobrien return tmp; 173678556Sobrien } else { 173778556Sobrien Cell *tmp = root; 173878556Sobrien while (tmp->link != NULL) tmp = tmp->link; 173978556Sobrien tmp->link = snocString ( tmp->link, name ); 174078556Sobrien return root; 174178556Sobrien } 174278556Sobrien} 174378556Sobrien 174478556Sobrien 174578556Sobrien/*---------------------------------------------*/ 174678556Sobrienstatic 174778556Sobrienvoid addFlagsFromEnvVar ( Cell** argList, Char* varName ) 174878556Sobrien{ 174978556Sobrien Int32 i, j, k; 175078556Sobrien Char *envbase, *p; 175178556Sobrien 175278556Sobrien envbase = getenv(varName); 175378556Sobrien if (envbase != NULL) { 175478556Sobrien p = envbase; 175578556Sobrien i = 0; 175678556Sobrien while (True) { 175778556Sobrien if (p[i] == 0) break; 175878556Sobrien p += i; 175978556Sobrien i = 0; 176078556Sobrien while (isspace((Int32)(p[0]))) p++; 176178556Sobrien while (p[i] != 0 && !isspace((Int32)(p[i]))) i++; 176278556Sobrien if (i > 0) { 176378556Sobrien k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10; 176478556Sobrien for (j = 0; j < k; j++) tmpName[j] = p[j]; 176578556Sobrien tmpName[k] = 0; 176678556Sobrien APPEND_FLAG(*argList, tmpName); 176778556Sobrien } 176878556Sobrien } 176978556Sobrien } 177078556Sobrien} 177178556Sobrien 177278556Sobrien 177378556Sobrien/*---------------------------------------------*/ 177478556Sobrien#define ISFLAG(s) (strcmp(aa->name, (s))==0) 177578556Sobrien 177678556SobrienIntNative main ( IntNative argc, Char *argv[] ) 177778556Sobrien{ 177878556Sobrien Int32 i, j; 177978556Sobrien Char *tmp; 178078556Sobrien Cell *argList; 178178556Sobrien Cell *aa; 178278556Sobrien Bool decode; 178378556Sobrien 178478556Sobrien /*-- Be really really really paranoid :-) --*/ 178578556Sobrien if (sizeof(Int32) != 4 || sizeof(UInt32) != 4 || 178678556Sobrien sizeof(Int16) != 2 || sizeof(UInt16) != 2 || 178778556Sobrien sizeof(Char) != 1 || sizeof(UChar) != 1) 178878556Sobrien configError(); 178978556Sobrien 179078556Sobrien /*-- Initialise --*/ 179178556Sobrien outputHandleJustInCase = NULL; 179278556Sobrien smallMode = False; 179378556Sobrien keepInputFiles = False; 179478556Sobrien forceOverwrite = False; 179578556Sobrien noisy = True; 179678556Sobrien verbosity = 0; 179778556Sobrien blockSize100k = 9; 179878556Sobrien testFailsExist = False; 179978556Sobrien unzFailsExist = False; 180078556Sobrien numFileNames = 0; 180178556Sobrien numFilesProcessed = 0; 180278556Sobrien workFactor = 30; 180378556Sobrien deleteOutputOnInterrupt = False; 180478556Sobrien exitValue = 0; 180578556Sobrien i = j = 0; /* avoid bogus warning from egcs-1.1.X */ 180678556Sobrien 180778556Sobrien /*-- Set up signal handlers for mem access errors --*/ 180878556Sobrien signal (SIGSEGV, mySIGSEGVorSIGBUScatcher); 180990067Ssobomax# if BZ_UNIX 181090067Ssobomax# ifndef __DJGPP__ 181178556Sobrien signal (SIGBUS, mySIGSEGVorSIGBUScatcher); 181290067Ssobomax# endif 181390067Ssobomax# endif 181478556Sobrien 1815167977Sdelphij copyFileName ( inName, (Char*)"(none)" ); 1816167977Sdelphij copyFileName ( outName, (Char*)"(none)" ); 181778556Sobrien 181878556Sobrien copyFileName ( progNameReally, argv[0] ); 181978556Sobrien progName = &progNameReally[0]; 182078556Sobrien for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++) 182178556Sobrien if (*tmp == PATH_SEP) progName = tmp + 1; 182278556Sobrien 182378556Sobrien 182478556Sobrien /*-- Copy flags from env var BZIP2, and 182578556Sobrien expand filename wildcards in arg list. 182678556Sobrien --*/ 182778556Sobrien argList = NULL; 1828167977Sdelphij addFlagsFromEnvVar ( &argList, (Char*)"BZIP2" ); 1829167977Sdelphij addFlagsFromEnvVar ( &argList, (Char*)"BZIP" ); 183078556Sobrien for (i = 1; i <= argc-1; i++) 183178556Sobrien APPEND_FILESPEC(argList, argv[i]); 183278556Sobrien 183378556Sobrien 183478556Sobrien /*-- Find the length of the longest filename --*/ 183578556Sobrien longestFileName = 7; 183678556Sobrien numFileNames = 0; 183778556Sobrien decode = True; 183878556Sobrien for (aa = argList; aa != NULL; aa = aa->link) { 183978556Sobrien if (ISFLAG("--")) { decode = False; continue; } 184078556Sobrien if (aa->name[0] == '-' && decode) continue; 184178556Sobrien numFileNames++; 184278556Sobrien if (longestFileName < (Int32)strlen(aa->name) ) 184378556Sobrien longestFileName = (Int32)strlen(aa->name); 184478556Sobrien } 184578556Sobrien 184678556Sobrien 184778556Sobrien /*-- Determine source modes; flag handling may change this too. --*/ 184878556Sobrien if (numFileNames == 0) 184978556Sobrien srcMode = SM_I2O; else srcMode = SM_F2F; 185078556Sobrien 185178556Sobrien 185278556Sobrien /*-- Determine what to do (compress/uncompress/test/cat). --*/ 185378556Sobrien /*-- Note that subsequent flag handling may change this. --*/ 185478556Sobrien opMode = OM_Z; 185578556Sobrien 185678556Sobrien if ( (strstr ( progName, "unzip" ) != 0) || 185778556Sobrien (strstr ( progName, "UNZIP" ) != 0) ) 185878556Sobrien opMode = OM_UNZ; 185978556Sobrien 186078556Sobrien if ( (strstr ( progName, "z2cat" ) != 0) || 186178556Sobrien (strstr ( progName, "Z2CAT" ) != 0) || 186278556Sobrien (strstr ( progName, "zcat" ) != 0) || 186378556Sobrien (strstr ( progName, "ZCAT" ) != 0) ) { 186478556Sobrien opMode = OM_UNZ; 186578556Sobrien srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O; 186678556Sobrien } 186778556Sobrien 186878556Sobrien 186978556Sobrien /*-- Look at the flags. --*/ 187078556Sobrien for (aa = argList; aa != NULL; aa = aa->link) { 187178556Sobrien if (ISFLAG("--")) break; 187278556Sobrien if (aa->name[0] == '-' && aa->name[1] != '-') { 187378556Sobrien for (j = 1; aa->name[j] != '\0'; j++) { 187478556Sobrien switch (aa->name[j]) { 187578556Sobrien case 'c': srcMode = SM_F2O; break; 187678556Sobrien case 'd': opMode = OM_UNZ; break; 187778556Sobrien case 'z': opMode = OM_Z; break; 187878556Sobrien case 'f': forceOverwrite = True; break; 187978556Sobrien case 't': opMode = OM_TEST; break; 188078556Sobrien case 'k': keepInputFiles = True; break; 188178556Sobrien case 's': smallMode = True; break; 188278556Sobrien case 'q': noisy = False; break; 188378556Sobrien case '1': blockSize100k = 1; break; 188478556Sobrien case '2': blockSize100k = 2; break; 188578556Sobrien case '3': blockSize100k = 3; break; 188678556Sobrien case '4': blockSize100k = 4; break; 188778556Sobrien case '5': blockSize100k = 5; break; 188878556Sobrien case '6': blockSize100k = 6; break; 188978556Sobrien case '7': blockSize100k = 7; break; 189078556Sobrien case '8': blockSize100k = 8; break; 189178556Sobrien case '9': blockSize100k = 9; break; 189278556Sobrien case 'V': 189378556Sobrien case 'L': license(); break; 189478556Sobrien case 'v': verbosity++; break; 189578556Sobrien case 'h': usage ( progName ); 189678556Sobrien exit ( 0 ); 189778556Sobrien break; 189878556Sobrien default: fprintf ( stderr, "%s: Bad flag `%s'\n", 189978556Sobrien progName, aa->name ); 190078556Sobrien usage ( progName ); 190178556Sobrien exit ( 1 ); 190278556Sobrien break; 190378556Sobrien } 190478556Sobrien } 190578556Sobrien } 190678556Sobrien } 190778556Sobrien 190878556Sobrien /*-- And again ... --*/ 190978556Sobrien for (aa = argList; aa != NULL; aa = aa->link) { 191078556Sobrien if (ISFLAG("--")) break; 191178556Sobrien if (ISFLAG("--stdout")) srcMode = SM_F2O; else 191278556Sobrien if (ISFLAG("--decompress")) opMode = OM_UNZ; else 191378556Sobrien if (ISFLAG("--compress")) opMode = OM_Z; else 191478556Sobrien if (ISFLAG("--force")) forceOverwrite = True; else 191578556Sobrien if (ISFLAG("--test")) opMode = OM_TEST; else 191678556Sobrien if (ISFLAG("--keep")) keepInputFiles = True; else 191778556Sobrien if (ISFLAG("--small")) smallMode = True; else 191878556Sobrien if (ISFLAG("--quiet")) noisy = False; else 191978556Sobrien if (ISFLAG("--version")) license(); else 192078556Sobrien if (ISFLAG("--license")) license(); else 192178556Sobrien if (ISFLAG("--exponential")) workFactor = 1; else 192278556Sobrien if (ISFLAG("--repetitive-best")) redundant(aa->name); else 192378556Sobrien if (ISFLAG("--repetitive-fast")) redundant(aa->name); else 192490067Ssobomax if (ISFLAG("--fast")) blockSize100k = 1; else 192590067Ssobomax if (ISFLAG("--best")) blockSize100k = 9; else 192678556Sobrien if (ISFLAG("--verbose")) verbosity++; else 192778556Sobrien if (ISFLAG("--help")) { usage ( progName ); exit ( 0 ); } 192878556Sobrien else 192978556Sobrien if (strncmp ( aa->name, "--", 2) == 0) { 193078556Sobrien fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name ); 193178556Sobrien usage ( progName ); 193278556Sobrien exit ( 1 ); 193378556Sobrien } 193478556Sobrien } 193578556Sobrien 193678556Sobrien if (verbosity > 4) verbosity = 4; 193778556Sobrien if (opMode == OM_Z && smallMode && blockSize100k > 2) 193878556Sobrien blockSize100k = 2; 193978556Sobrien 194078556Sobrien if (opMode == OM_TEST && srcMode == SM_F2O) { 194178556Sobrien fprintf ( stderr, "%s: -c and -t cannot be used together.\n", 194278556Sobrien progName ); 194378556Sobrien exit ( 1 ); 194478556Sobrien } 194578556Sobrien 194678556Sobrien if (srcMode == SM_F2O && numFileNames == 0) 194778556Sobrien srcMode = SM_I2O; 194878556Sobrien 194978556Sobrien if (opMode != OM_Z) blockSize100k = 0; 195078556Sobrien 195178556Sobrien if (srcMode == SM_F2F) { 195278556Sobrien signal (SIGINT, mySignalCatcher); 195378556Sobrien signal (SIGTERM, mySignalCatcher); 195478556Sobrien# if BZ_UNIX 195578556Sobrien signal (SIGHUP, mySignalCatcher); 195678556Sobrien# endif 195778556Sobrien } 195878556Sobrien 195978556Sobrien if (opMode == OM_Z) { 196078556Sobrien if (srcMode == SM_I2O) { 196178556Sobrien compress ( NULL ); 196278556Sobrien } else { 196378556Sobrien decode = True; 196478556Sobrien for (aa = argList; aa != NULL; aa = aa->link) { 196578556Sobrien if (ISFLAG("--")) { decode = False; continue; } 196678556Sobrien if (aa->name[0] == '-' && decode) continue; 196778556Sobrien numFilesProcessed++; 196878556Sobrien compress ( aa->name ); 196978556Sobrien } 197078556Sobrien } 197178556Sobrien } 197278556Sobrien else 197378556Sobrien 197478556Sobrien if (opMode == OM_UNZ) { 197578556Sobrien unzFailsExist = False; 197678556Sobrien if (srcMode == SM_I2O) { 197778556Sobrien uncompress ( NULL ); 197878556Sobrien } else { 197978556Sobrien decode = True; 198078556Sobrien for (aa = argList; aa != NULL; aa = aa->link) { 198178556Sobrien if (ISFLAG("--")) { decode = False; continue; } 198278556Sobrien if (aa->name[0] == '-' && decode) continue; 198378556Sobrien numFilesProcessed++; 198478556Sobrien uncompress ( aa->name ); 198578556Sobrien } 198678556Sobrien } 198778556Sobrien if (unzFailsExist) { 198878556Sobrien setExit(2); 198978556Sobrien exit(exitValue); 199078556Sobrien } 199178556Sobrien } 199278556Sobrien 199378556Sobrien else { 199478556Sobrien testFailsExist = False; 199578556Sobrien if (srcMode == SM_I2O) { 199678556Sobrien testf ( NULL ); 199778556Sobrien } else { 199878556Sobrien decode = True; 199978556Sobrien for (aa = argList; aa != NULL; aa = aa->link) { 200078556Sobrien if (ISFLAG("--")) { decode = False; continue; } 200178556Sobrien if (aa->name[0] == '-' && decode) continue; 200278556Sobrien numFilesProcessed++; 200378556Sobrien testf ( aa->name ); 200478556Sobrien } 200578556Sobrien } 200678556Sobrien if (testFailsExist && noisy) { 200778556Sobrien fprintf ( stderr, 200878556Sobrien "\n" 200978556Sobrien "You can use the `bzip2recover' program to attempt to recover\n" 201078556Sobrien "data from undamaged sections of corrupted files.\n\n" 201178556Sobrien ); 201278556Sobrien setExit(2); 201378556Sobrien exit(exitValue); 201478556Sobrien } 201578556Sobrien } 201678556Sobrien 201778556Sobrien /* Free the argument list memory to mollify leak detectors 201878556Sobrien (eg) Purify, Checker. Serves no other useful purpose. 201978556Sobrien */ 202078556Sobrien aa = argList; 202178556Sobrien while (aa != NULL) { 202278556Sobrien Cell* aa2 = aa->link; 202378556Sobrien if (aa->name != NULL) free(aa->name); 202478556Sobrien free(aa); 202578556Sobrien aa = aa2; 202678556Sobrien } 202778556Sobrien 202878556Sobrien return exitValue; 202978556Sobrien} 203078556Sobrien 203178556Sobrien 203278556Sobrien/*-----------------------------------------------------------*/ 203378556Sobrien/*--- end bzip2.c ---*/ 203478556Sobrien/*-----------------------------------------------------------*/ 2035