Home | History | Annotate | Download | only in bzip2
      1 
      2 /*-----------------------------------------------------------*/
      3 /*--- A block-sorting, lossless compressor        bzip2.c ---*/
      4 /*-----------------------------------------------------------*/
      5 
      6 /* ------------------------------------------------------------------
      7    This file is part of bzip2/libbzip2, a program and library for
      8    lossless, block-sorting data compression.
      9 
     10    bzip2/libbzip2 version 1.0.6 of 6 September 2010
     11    Copyright (C) 1996-2010 Julian Seward <jseward (at) bzip.org>
     12 
     13    Please read the WARNING, DISCLAIMER and PATENTS sections in the
     14    README file.
     15 
     16    This program is released under the terms of the license contained
     17    in the file LICENSE.
     18    ------------------------------------------------------------------ */
     19 
     20 
     21 /* Place a 1 beside your platform, and 0 elsewhere.
     22    Generic 32-bit Unix.
     23    Also works on 64-bit Unix boxes.
     24    This is the default.
     25 */
     26 #define BZ_UNIX      1
     27 
     28 /*--
     29   Win32, as seen by Jacob Navia's excellent
     30   port of (Chris Fraser & David Hanson)'s excellent
     31   lcc compiler.  Or with MS Visual C.
     32   This is selected automatically if compiled by a compiler which
     33   defines _WIN32, not including the Cygwin GCC.
     34 --*/
     35 #define BZ_LCCWIN32  0
     36 
     37 #if defined(_WIN32) && !defined(__CYGWIN__)
     38 #undef  BZ_LCCWIN32
     39 #define BZ_LCCWIN32 1
     40 #undef  BZ_UNIX
     41 #define BZ_UNIX 0
     42 #endif
     43 
     44 
     45 /*---------------------------------------------*/
     46 /*--
     47   Some stuff for all platforms.
     48 --*/
     49 
     50 #include <stdio.h>
     51 #include <stdlib.h>
     52 #include <string.h>
     53 #include <signal.h>
     54 #include <math.h>
     55 #include <errno.h>
     56 #include <ctype.h>
     57 #include "bzlib.h"
     58 
     59 #define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
     60 #define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
     61 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
     62 
     63 
     64 /*---------------------------------------------*/
     65 /*--
     66    Platform-specific stuff.
     67 --*/
     68 
     69 #if BZ_UNIX
     70 #   include <fcntl.h>
     71 #   include <sys/types.h>
     72 #   include <utime.h>
     73 #   include <unistd.h>
     74 #   include <sys/stat.h>
     75 #   include <sys/times.h>
     76 
     77 #   define PATH_SEP    '/'
     78 #   define MY_LSTAT    lstat
     79 #   define MY_STAT     stat
     80 #   define MY_S_ISREG  S_ISREG
     81 #   define MY_S_ISDIR  S_ISDIR
     82 
     83 #   define APPEND_FILESPEC(root, name) \
     84       root=snocString((root), (name))
     85 
     86 #   define APPEND_FLAG(root, name) \
     87       root=snocString((root), (name))
     88 
     89 #   define SET_BINARY_MODE(fd) /**/
     90 
     91 #   ifdef __GNUC__
     92 #      define NORETURN __attribute__ ((noreturn))
     93 #   else
     94 #      define NORETURN /**/
     95 #   endif
     96 
     97 #   ifdef __DJGPP__
     98 #     include <io.h>
     99 #     include <fcntl.h>
    100 #     undef MY_LSTAT
    101 #     undef MY_STAT
    102 #     define MY_LSTAT stat
    103 #     define MY_STAT stat
    104 #     undef SET_BINARY_MODE
    105 #     define SET_BINARY_MODE(fd)                        \
    106         do {                                            \
    107            int retVal = setmode ( fileno ( fd ),        \
    108                                   O_BINARY );           \
    109            ERROR_IF_MINUS_ONE ( retVal );               \
    110         } while ( 0 )
    111 #   endif
    112 
    113 #   ifdef __CYGWIN__
    114 #     include <io.h>
    115 #     include <fcntl.h>
    116 #     undef SET_BINARY_MODE
    117 #     define SET_BINARY_MODE(fd)                        \
    118         do {                                            \
    119            int retVal = setmode ( fileno ( fd ),        \
    120                                   O_BINARY );           \
    121            ERROR_IF_MINUS_ONE ( retVal );               \
    122         } while ( 0 )
    123 #   endif
    124 #endif /* BZ_UNIX */
    125 
    126 
    127 
    128 #if BZ_LCCWIN32
    129 #   include <io.h>
    130 #   include <fcntl.h>
    131 #   include <sys\stat.h>
    132 
    133 #   define NORETURN       /**/
    134 #   define PATH_SEP       '\\'
    135 #   define MY_LSTAT       _stat
    136 #   define MY_STAT        _stat
    137 #   define MY_S_ISREG(x)  ((x) & _S_IFREG)
    138 #   define MY_S_ISDIR(x)  ((x) & _S_IFDIR)
    139 
    140 #   define APPEND_FLAG(root, name) \
    141       root=snocString((root), (name))
    142 
    143 #   define APPEND_FILESPEC(root, name)                \
    144       root = snocString ((root), (name))
    145 
    146 #   define SET_BINARY_MODE(fd)                        \
    147       do {                                            \
    148          int retVal = setmode ( fileno ( fd ),        \
    149                                 O_BINARY );           \
    150          ERROR_IF_MINUS_ONE ( retVal );               \
    151       } while ( 0 )
    152 
    153 #endif /* BZ_LCCWIN32 */
    154 
    155 
    156 /*---------------------------------------------*/
    157 /*--
    158   Some more stuff for all platforms :-)
    159 --*/
    160 
    161 typedef char            Char;
    162 typedef unsigned char   Bool;
    163 typedef unsigned char   UChar;
    164 typedef int             Int32;
    165 typedef unsigned int    UInt32;
    166 typedef short           Int16;
    167 typedef unsigned short  UInt16;
    168 
    169 #define True  ((Bool)1)
    170 #define False ((Bool)0)
    171 
    172 /*--
    173   IntNative is your platform's `native' int size.
    174   Only here to avoid probs with 64-bit platforms.
    175 --*/
    176 typedef int IntNative;
    177 
    178 
    179 /*---------------------------------------------------*/
    180 /*--- Misc (file handling) data decls             ---*/
    181 /*---------------------------------------------------*/
    182 
    183 Int32   verbosity;
    184 Bool    keepInputFiles, smallMode, deleteOutputOnInterrupt;
    185 Bool    forceOverwrite, testFailsExist, unzFailsExist, noisy;
    186 Int32   numFileNames, numFilesProcessed, blockSize100k;
    187 Int32   exitValue;
    188 
    189 /*-- source modes; F==file, I==stdin, O==stdout --*/
    190 #define SM_I2O           1
    191 #define SM_F2O           2
    192 #define SM_F2F           3
    193 
    194 /*-- operation modes --*/
    195 #define OM_Z             1
    196 #define OM_UNZ           2
    197 #define OM_TEST          3
    198 
    199 Int32   opMode;
    200 Int32   srcMode;
    201 
    202 #define FILE_NAME_LEN 1034
    203 
    204 Int32   longestFileName;
    205 Char    inName [FILE_NAME_LEN];
    206 Char    outName[FILE_NAME_LEN];
    207 Char    tmpName[FILE_NAME_LEN];
    208 Char    *progName;
    209 Char    progNameReally[FILE_NAME_LEN];
    210 FILE    *outputHandleJustInCase;
    211 Int32   workFactor;
    212 
    213 static void    panic                 ( const Char* ) NORETURN;
    214 static void    ioError               ( void )        NORETURN;
    215 static void    outOfMemory           ( void )        NORETURN;
    216 static void    configError           ( void )        NORETURN;
    217 static void    crcError              ( void )        NORETURN;
    218 static void    cleanUpAndFail        ( Int32 )       NORETURN;
    219 static void    compressedStreamEOF   ( void )        NORETURN;
    220 
    221 static void    copyFileName ( Char*, Char* );
    222 static void*   myMalloc     ( Int32 );
    223 static void    applySavedFileAttrToOutputFile ( IntNative fd );
    224 
    225 
    226 
    227 /*---------------------------------------------------*/
    228 /*--- An implementation of 64-bit ints.  Sigh.    ---*/
    229 /*--- Roll on widespread deployment of ANSI C9X ! ---*/
    230 /*---------------------------------------------------*/
    231 
    232 typedef
    233    struct { UChar b[8]; }
    234    UInt64;
    235 
    236 
    237 static
    238 void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
    239 {
    240    n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
    241    n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
    242    n->b[5] = (UChar)((hi32 >> 8)  & 0xFF);
    243    n->b[4] = (UChar) (hi32        & 0xFF);
    244    n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
    245    n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
    246    n->b[1] = (UChar)((lo32 >> 8)  & 0xFF);
    247    n->b[0] = (UChar) (lo32        & 0xFF);
    248 }
    249 
    250 
    251 static
    252 double uInt64_to_double ( UInt64* n )
    253 {
    254    Int32  i;
    255    double base = 1.0;
    256    double sum  = 0.0;
    257    for (i = 0; i < 8; i++) {
    258       sum  += base * (double)(n->b[i]);
    259       base *= 256.0;
    260    }
    261    return sum;
    262 }
    263 
    264 
    265 static
    266 Bool uInt64_isZero ( UInt64* n )
    267 {
    268    Int32 i;
    269    for (i = 0; i < 8; i++)
    270       if (n->b[i] != 0) return 0;
    271    return 1;
    272 }
    273 
    274 
    275 /* Divide *n by 10, and return the remainder.  */
    276 static
    277 Int32 uInt64_qrm10 ( UInt64* n )
    278 {
    279    UInt32 rem, tmp;
    280    Int32  i;
    281    rem = 0;
    282    for (i = 7; i >= 0; i--) {
    283       tmp = rem * 256 + n->b[i];
    284       n->b[i] = tmp / 10;
    285       rem = tmp % 10;
    286    }
    287    return rem;
    288 }
    289 
    290 
    291 /* ... and the Whole Entire Point of all this UInt64 stuff is
    292    so that we can supply the following function.
    293 */
    294 static
    295 void uInt64_toAscii ( char* outbuf, UInt64* n )
    296 {
    297    Int32  i, q;
    298    UChar  buf[32];
    299    Int32  nBuf   = 0;
    300    UInt64 n_copy = *n;
    301    do {
    302       q = uInt64_qrm10 ( &n_copy );
    303       buf[nBuf] = q + '0';
    304       nBuf++;
    305    } while (!uInt64_isZero(&n_copy));
    306    outbuf[nBuf] = 0;
    307    for (i = 0; i < nBuf; i++)
    308       outbuf[i] = buf[nBuf-i-1];
    309 }
    310 
    311 
    312 /*---------------------------------------------------*/
    313 /*--- Processing of complete files and streams    ---*/
    314 /*---------------------------------------------------*/
    315 
    316 /*---------------------------------------------*/
    317 static
    318 Bool myfeof ( FILE* f )
    319 {
    320    Int32 c = fgetc ( f );
    321    if (c == EOF) return True;
    322    ungetc ( c, f );
    323    return False;
    324 }
    325 
    326 
    327 /*---------------------------------------------*/
    328 static
    329 void compressStream ( FILE *stream, FILE *zStream )
    330 {
    331    BZFILE* bzf = NULL;
    332    UChar   ibuf[5000];
    333    Int32   nIbuf;
    334    UInt32  nbytes_in_lo32, nbytes_in_hi32;
    335    UInt32  nbytes_out_lo32, nbytes_out_hi32;
    336    Int32   bzerr, bzerr_dummy, ret;
    337 
    338    SET_BINARY_MODE(stream);
    339    SET_BINARY_MODE(zStream);
    340 
    341    if (ferror(stream)) goto errhandler_io;
    342    if (ferror(zStream)) goto errhandler_io;
    343 
    344    bzf = BZ2_bzWriteOpen ( &bzerr, zStream,
    345                            blockSize100k, verbosity, workFactor );
    346    if (bzerr != BZ_OK) goto errhandler;
    347 
    348    if (verbosity >= 2) fprintf ( stderr, "\n" );
    349 
    350    while (True) {
    351 
    352       if (myfeof(stream)) break;
    353       nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
    354       if (ferror(stream)) goto errhandler_io;
    355       if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
    356       if (bzerr != BZ_OK) goto errhandler;
    357 
    358    }
    359 
    360    BZ2_bzWriteClose64 ( &bzerr, bzf, 0,
    361                         &nbytes_in_lo32, &nbytes_in_hi32,
    362                         &nbytes_out_lo32, &nbytes_out_hi32 );
    363    if (bzerr != BZ_OK) goto errhandler;
    364 
    365    if (ferror(zStream)) goto errhandler_io;
    366    ret = fflush ( zStream );
    367    if (ret == EOF) goto errhandler_io;
    368    if (zStream != stdout) {
    369       Int32 fd = fileno ( zStream );
    370       if (fd < 0) goto errhandler_io;
    371       applySavedFileAttrToOutputFile ( fd );
    372       ret = fclose ( zStream );
    373       outputHandleJustInCase = NULL;
    374       if (ret == EOF) goto errhandler_io;
    375    }
    376    outputHandleJustInCase = NULL;
    377    if (ferror(stream)) goto errhandler_io;
    378    ret = fclose ( stream );
    379    if (ret == EOF) goto errhandler_io;
    380 
    381    if (verbosity >= 1) {
    382       if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
    383 	 fprintf ( stderr, " no data compressed.\n");
    384       } else {
    385 	 Char   buf_nin[32], buf_nout[32];
    386 	 UInt64 nbytes_in,   nbytes_out;
    387 	 double nbytes_in_d, nbytes_out_d;
    388 	 uInt64_from_UInt32s ( &nbytes_in,
    389 			       nbytes_in_lo32, nbytes_in_hi32 );
    390 	 uInt64_from_UInt32s ( &nbytes_out,
    391 			       nbytes_out_lo32, nbytes_out_hi32 );
    392 	 nbytes_in_d  = uInt64_to_double ( &nbytes_in );
    393 	 nbytes_out_d = uInt64_to_double ( &nbytes_out );
    394 	 uInt64_toAscii ( buf_nin, &nbytes_in );
    395 	 uInt64_toAscii ( buf_nout, &nbytes_out );
    396 	 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
    397 		   "%5.2f%% saved, %s in, %s out.\n",
    398 		   nbytes_in_d / nbytes_out_d,
    399 		   (8.0 * nbytes_out_d) / nbytes_in_d,
    400 		   100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
    401 		   buf_nin,
    402 		   buf_nout
    403 		 );
    404       }
    405    }
    406 
    407    return;
    408 
    409    errhandler:
    410    BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1,
    411                         &nbytes_in_lo32, &nbytes_in_hi32,
    412                         &nbytes_out_lo32, &nbytes_out_hi32 );
    413    switch (bzerr) {
    414       case BZ_CONFIG_ERROR:
    415          configError(); break;
    416       case BZ_MEM_ERROR:
    417          outOfMemory (); break;
    418       case BZ_IO_ERROR:
    419          errhandler_io:
    420          ioError(); break;
    421       default:
    422          panic ( "compress:unexpected error" );
    423    }
    424 
    425    panic ( "compress:end" );
    426    /*notreached*/
    427 }
    428 
    429 
    430 
    431 /*---------------------------------------------*/
    432 static
    433 Bool uncompressStream ( FILE *zStream, FILE *stream )
    434 {
    435    BZFILE* bzf = NULL;
    436    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
    437    UChar   obuf[5000];
    438    UChar   unused[BZ_MAX_UNUSED];
    439    Int32   nUnused;
    440    void*   unusedTmpV;
    441    UChar*  unusedTmp;
    442 
    443    nUnused = 0;
    444    streamNo = 0;
    445 
    446    SET_BINARY_MODE(stream);
    447    SET_BINARY_MODE(zStream);
    448 
    449    if (ferror(stream)) goto errhandler_io;
    450    if (ferror(zStream)) goto errhandler_io;
    451 
    452    while (True) {
    453 
    454       bzf = BZ2_bzReadOpen (
    455                &bzerr, zStream, verbosity,
    456                (int)smallMode, unused, nUnused
    457             );
    458       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
    459       streamNo++;
    460 
    461       while (bzerr == BZ_OK) {
    462          nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
    463          if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
    464          if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
    465             fwrite ( obuf, sizeof(UChar), nread, stream );
    466          if (ferror(stream)) goto errhandler_io;
    467       }
    468       if (bzerr != BZ_STREAM_END) goto errhandler;
    469 
    470       BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
    471       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
    472 
    473       unusedTmp = (UChar*)unusedTmpV;
    474       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
    475 
    476       BZ2_bzReadClose ( &bzerr, bzf );
    477       if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
    478 
    479       if (nUnused == 0 && myfeof(zStream)) break;
    480    }
    481 
    482    closeok:
    483    if (ferror(zStream)) goto errhandler_io;
    484    if (stream != stdout) {
    485       Int32 fd = fileno ( stream );
    486       if (fd < 0) goto errhandler_io;
    487       applySavedFileAttrToOutputFile ( fd );
    488    }
    489    ret = fclose ( zStream );
    490    if (ret == EOF) goto errhandler_io;
    491 
    492    if (ferror(stream)) goto errhandler_io;
    493    ret = fflush ( stream );
    494    if (ret != 0) goto errhandler_io;
    495    if (stream != stdout) {
    496       ret = fclose ( stream );
    497       outputHandleJustInCase = NULL;
    498       if (ret == EOF) goto errhandler_io;
    499    }
    500    outputHandleJustInCase = NULL;
    501    if (verbosity >= 2) fprintf ( stderr, "\n    " );
    502    return True;
    503 
    504    trycat:
    505    if (forceOverwrite) {
    506       rewind(zStream);
    507       while (True) {
    508       	 if (myfeof(zStream)) break;
    509       	 nread = fread ( obuf, sizeof(UChar), 5000, zStream );
    510       	 if (ferror(zStream)) goto errhandler_io;
    511       	 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
    512       	 if (ferror(stream)) goto errhandler_io;
    513       }
    514       goto closeok;
    515    }
    516 
    517    errhandler:
    518    BZ2_bzReadClose ( &bzerr_dummy, bzf );
    519    switch (bzerr) {
    520       case BZ_CONFIG_ERROR:
    521          configError(); break;
    522       case BZ_IO_ERROR:
    523          errhandler_io:
    524          ioError(); break;
    525       case BZ_DATA_ERROR:
    526          crcError();
    527       case BZ_MEM_ERROR:
    528          outOfMemory();
    529       case BZ_UNEXPECTED_EOF:
    530          compressedStreamEOF();
    531       case BZ_DATA_ERROR_MAGIC:
    532          if (zStream != stdin) fclose(zStream);
    533          if (stream != stdout) fclose(stream);
    534          if (streamNo == 1) {
    535             return False;
    536          } else {
    537             if (noisy)
    538             fprintf ( stderr,
    539                       "\n%s: %s: trailing garbage after EOF ignored\n",
    540                       progName, inName );
    541             return True;
    542          }
    543       default:
    544          panic ( "decompress:unexpected error" );
    545    }
    546 
    547    panic ( "decompress:end" );
    548    return True; /*notreached*/
    549 }
    550 
    551 
    552 /*---------------------------------------------*/
    553 static
    554 Bool testStream ( FILE *zStream )
    555 {
    556    BZFILE* bzf = NULL;
    557    Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
    558    UChar   obuf[5000];
    559    UChar   unused[BZ_MAX_UNUSED];
    560    Int32   nUnused;
    561    void*   unusedTmpV;
    562    UChar*  unusedTmp;
    563 
    564    nUnused = 0;
    565    streamNo = 0;
    566 
    567    SET_BINARY_MODE(zStream);
    568    if (ferror(zStream)) goto errhandler_io;
    569 
    570    while (True) {
    571 
    572       bzf = BZ2_bzReadOpen (
    573                &bzerr, zStream, verbosity,
    574                (int)smallMode, unused, nUnused
    575             );
    576       if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
    577       streamNo++;
    578 
    579       while (bzerr == BZ_OK) {
    580          nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
    581          if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
    582       }
    583       if (bzerr != BZ_STREAM_END) goto errhandler;
    584 
    585       BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
    586       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
    587 
    588       unusedTmp = (UChar*)unusedTmpV;
    589       for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
    590 
    591       BZ2_bzReadClose ( &bzerr, bzf );
    592       if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
    593       if (nUnused == 0 && myfeof(zStream)) break;
    594 
    595    }
    596 
    597    if (ferror(zStream)) goto errhandler_io;
    598    ret = fclose ( zStream );
    599    if (ret == EOF) goto errhandler_io;
    600 
    601    if (verbosity >= 2) fprintf ( stderr, "\n    " );
    602    return True;
    603 
    604    errhandler:
    605    BZ2_bzReadClose ( &bzerr_dummy, bzf );
    606    if (verbosity == 0)
    607       fprintf ( stderr, "%s: %s: ", progName, inName );
    608    switch (bzerr) {
    609       case BZ_CONFIG_ERROR:
    610          configError(); break;
    611       case BZ_IO_ERROR:
    612          errhandler_io:
    613          ioError(); break;
    614       case BZ_DATA_ERROR:
    615          fprintf ( stderr,
    616                    "data integrity (CRC) error in data\n" );
    617          return False;
    618       case BZ_MEM_ERROR:
    619          outOfMemory();
    620       case BZ_UNEXPECTED_EOF:
    621          fprintf ( stderr,
    622                    "file ends unexpectedly\n" );
    623          return False;
    624       case BZ_DATA_ERROR_MAGIC:
    625          if (zStream != stdin) fclose(zStream);
    626          if (streamNo == 1) {
    627           fprintf ( stderr,
    628                     "bad magic number (file not created by bzip2)\n" );
    629             return False;
    630          } else {
    631             if (noisy)
    632             fprintf ( stderr,
    633                       "trailing garbage after EOF ignored\n" );
    634             return True;
    635          }
    636       default:
    637          panic ( "test:unexpected error" );
    638    }
    639 
    640    panic ( "test:end" );
    641    return True; /*notreached*/
    642 }
    643 
    644 
    645 /*---------------------------------------------------*/
    646 /*--- Error [non-] handling grunge                ---*/
    647 /*---------------------------------------------------*/
    648 
    649 /*---------------------------------------------*/
    650 static
    651 void setExit ( Int32 v )
    652 {
    653    if (v > exitValue) exitValue = v;
    654 }
    655 
    656 
    657 /*---------------------------------------------*/
    658 static
    659 void cadvise ( void )
    660 {
    661    if (noisy)
    662    fprintf (
    663       stderr,
    664       "\nIt is possible that the compressed file(s) have become corrupted.\n"
    665         "You can use the -tvv option to test integrity of such files.\n\n"
    666         "You can use the `bzip2recover' program to attempt to recover\n"
    667         "data from undamaged sections of corrupted files.\n\n"
    668     );
    669 }
    670 
    671 
    672 /*---------------------------------------------*/
    673 static
    674 void showFileNames ( void )
    675 {
    676    if (noisy)
    677    fprintf (
    678       stderr,
    679       "\tInput file = %s, output file = %s\n",
    680       inName, outName
    681    );
    682 }
    683 
    684 
    685 /*---------------------------------------------*/
    686 static
    687 void cleanUpAndFail ( Int32 ec )
    688 {
    689    IntNative      retVal;
    690    struct MY_STAT statBuf;
    691 
    692    if ( srcMode == SM_F2F
    693         && opMode != OM_TEST
    694         && deleteOutputOnInterrupt ) {
    695 
    696       /* Check whether input file still exists.  Delete output file
    697          only if input exists to avoid loss of data.  Joerg Prante, 5
    698          January 2002.  (JRS 06-Jan-2002: other changes in 1.0.2 mean
    699          this is less likely to happen.  But to be ultra-paranoid, we
    700          do the check anyway.)  */
    701       retVal = MY_STAT ( inName, &statBuf );
    702       if (retVal == 0) {
    703          if (noisy)
    704             fprintf ( stderr,
    705                       "%s: Deleting output file %s, if it exists.\n",
    706                       progName, outName );
    707          if (outputHandleJustInCase != NULL)
    708             fclose ( outputHandleJustInCase );
    709          retVal = remove ( outName );
    710          if (retVal != 0)
    711             fprintf ( stderr,
    712                       "%s: WARNING: deletion of output file "
    713                       "(apparently) failed.\n",
    714                       progName );
    715       } else {
    716          fprintf ( stderr,
    717                    "%s: WARNING: deletion of output file suppressed\n",
    718                     progName );
    719          fprintf ( stderr,
    720                    "%s:    since input file no longer exists.  Output file\n",
    721                    progName );
    722          fprintf ( stderr,
    723                    "%s:    `%s' may be incomplete.\n",
    724                    progName, outName );
    725          fprintf ( stderr,
    726                    "%s:    I suggest doing an integrity test (bzip2 -tv)"
    727                    " of it.\n",
    728                    progName );
    729       }
    730    }
    731 
    732    if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
    733       fprintf ( stderr,
    734                 "%s: WARNING: some files have not been processed:\n"
    735                 "%s:    %d specified on command line, %d not processed yet.\n\n",
    736                 progName, progName,
    737                 numFileNames, numFileNames - numFilesProcessed );
    738    }
    739    setExit(ec);
    740    exit(exitValue);
    741 }
    742 
    743 
    744 /*---------------------------------------------*/
    745 static
    746 void panic ( const Char* s )
    747 {
    748    fprintf ( stderr,
    749              "\n%s: PANIC -- internal consistency error:\n"
    750              "\t%s\n"
    751              "\tThis is a BUG.  Please report it to me at:\n"
    752              "\tjseward (at) bzip.org\n",
    753              progName, s );
    754    showFileNames();
    755    cleanUpAndFail( 3 );
    756 }
    757 
    758 
    759 /*---------------------------------------------*/
    760 static
    761 void crcError ( void )
    762 {
    763    fprintf ( stderr,
    764              "\n%s: Data integrity error when decompressing.\n",
    765              progName );
    766    showFileNames();
    767    cadvise();
    768    cleanUpAndFail( 2 );
    769 }
    770 
    771 
    772 /*---------------------------------------------*/
    773 static
    774 void compressedStreamEOF ( void )
    775 {
    776   if (noisy) {
    777     fprintf ( stderr,
    778 	      "\n%s: Compressed file ends unexpectedly;\n\t"
    779 	      "perhaps it is corrupted?  *Possible* reason follows.\n",
    780 	      progName );
    781     perror ( progName );
    782     showFileNames();
    783     cadvise();
    784   }
    785   cleanUpAndFail( 2 );
    786 }
    787 
    788 
    789 /*---------------------------------------------*/
    790 static
    791 void ioError ( void )
    792 {
    793    fprintf ( stderr,
    794              "\n%s: I/O or other error, bailing out.  "
    795              "Possible reason follows.\n",
    796              progName );
    797    perror ( progName );
    798    showFileNames();
    799    cleanUpAndFail( 1 );
    800 }
    801 
    802 
    803 /*---------------------------------------------*/
    804 static
    805 void mySignalCatcher ( IntNative n )
    806 {
    807    fprintf ( stderr,
    808              "\n%s: Control-C or similar caught, quitting.\n",
    809              progName );
    810    cleanUpAndFail(1);
    811 }
    812 
    813 
    814 /*---------------------------------------------*/
    815 static
    816 void mySIGSEGVorSIGBUScatcher ( IntNative n )
    817 {
    818    if (opMode == OM_Z)
    819       fprintf (
    820       stderr,
    821       "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
    822       "\n"
    823       "   Possible causes are (most likely first):\n"
    824       "   (1) This computer has unreliable memory or cache hardware\n"
    825       "       (a surprisingly common problem; try a different machine.)\n"
    826       "   (2) A bug in the compiler used to create this executable\n"
    827       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
    828       "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
    829       "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
    830       "   \n"
    831       "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
    832       "   or (2), feel free to report it to me at: jseward (at) bzip.org.\n"
    833       "   Section 4.3 of the user's manual describes the info a useful\n"
    834       "   bug report should have.  If the manual is available on your\n"
    835       "   system, please try and read it before mailing me.  If you don't\n"
    836       "   have the manual or can't be bothered to read it, mail me anyway.\n"
    837       "\n",
    838       progName );
    839       else
    840       fprintf (
    841       stderr,
    842       "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
    843       "\n"
    844       "   Possible causes are (most likely first):\n"
    845       "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
    846       "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
    847       "   (2) This computer has unreliable memory or cache hardware\n"
    848       "       (a surprisingly common problem; try a different machine.)\n"
    849       "   (3) A bug in the compiler used to create this executable\n"
    850       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
    851       "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
    852       "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
    853       "   \n"
    854       "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
    855       "   or (3), feel free to report it to me at: jseward (at) bzip.org.\n"
    856       "   Section 4.3 of the user's manual describes the info a useful\n"
    857       "   bug report should have.  If the manual is available on your\n"
    858       "   system, please try and read it before mailing me.  If you don't\n"
    859       "   have the manual or can't be bothered to read it, mail me anyway.\n"
    860       "\n",
    861       progName );
    862 
    863    showFileNames();
    864    if (opMode == OM_Z)
    865       cleanUpAndFail( 3 ); else
    866       { cadvise(); cleanUpAndFail( 2 ); }
    867 }
    868 
    869 
    870 /*---------------------------------------------*/
    871 static
    872 void outOfMemory ( void )
    873 {
    874    fprintf ( stderr,
    875              "\n%s: couldn't allocate enough memory\n",
    876              progName );
    877    showFileNames();
    878    cleanUpAndFail(1);
    879 }
    880 
    881 
    882 /*---------------------------------------------*/
    883 static
    884 void configError ( void )
    885 {
    886    fprintf ( stderr,
    887              "bzip2: I'm not configured correctly for this platform!\n"
    888              "\tI require Int32, Int16 and Char to have sizes\n"
    889              "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
    890              "\tProbably you can fix this by defining them correctly,\n"
    891              "\tand recompiling.  Bye!\n" );
    892    setExit(3);
    893    exit(exitValue);
    894 }
    895 
    896 
    897 /*---------------------------------------------------*/
    898 /*--- The main driver machinery                   ---*/
    899 /*---------------------------------------------------*/
    900 
    901 /* All rather crufty.  The main problem is that input files
    902    are stat()d multiple times before use.  This should be
    903    cleaned up.
    904 */
    905 
    906 /*---------------------------------------------*/
    907 static
    908 void pad ( Char *s )
    909 {
    910    Int32 i;
    911    if ( (Int32)strlen(s) >= longestFileName ) return;
    912    for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
    913       fprintf ( stderr, " " );
    914 }
    915 
    916 
    917 /*---------------------------------------------*/
    918 static
    919 void copyFileName ( Char* to, Char* from )
    920 {
    921    if ( strlen(from) > FILE_NAME_LEN-10 )  {
    922       fprintf (
    923          stderr,
    924          "bzip2: file name\n`%s'\n"
    925          "is suspiciously (more than %d chars) long.\n"
    926          "Try using a reasonable file name instead.  Sorry! :-)\n",
    927          from, FILE_NAME_LEN-10
    928       );
    929       setExit(1);
    930       exit(exitValue);
    931    }
    932 
    933   strncpy(to,from,FILE_NAME_LEN-10);
    934   to[FILE_NAME_LEN-10]='\0';
    935 }
    936 
    937 
    938 /*---------------------------------------------*/
    939 static
    940 Bool fileExists ( Char* name )
    941 {
    942    FILE *tmp   = fopen ( name, "rb" );
    943    Bool exists = (tmp != NULL);
    944    if (tmp != NULL) fclose ( tmp );
    945    return exists;
    946 }
    947 
    948 
    949 /*---------------------------------------------*/
    950 /* Open an output file safely with O_EXCL and good permissions.
    951    This avoids a race condition in versions < 1.0.2, in which
    952    the file was first opened and then had its interim permissions
    953    set safely.  We instead use open() to create the file with
    954    the interim permissions required. (--- --- rw-).
    955 
    956    For non-Unix platforms, if we are not worrying about
    957    security issues, simple this simply behaves like fopen.
    958 */
    959 static
    960 FILE* fopen_output_safely ( Char* name, const char* mode )
    961 {
    962 #  if BZ_UNIX
    963    FILE*     fp;
    964    IntNative fh;
    965    fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
    966    if (fh == -1) return NULL;
    967    fp = fdopen(fh, mode);
    968    if (fp == NULL) close(fh);
    969    return fp;
    970 #  else
    971    return fopen(name, mode);
    972 #  endif
    973 }
    974 
    975 
    976 /*---------------------------------------------*/
    977 /*--
    978   if in doubt, return True
    979 --*/
    980 static
    981 Bool notAStandardFile ( Char* name )
    982 {
    983    IntNative      i;
    984    struct MY_STAT statBuf;
    985 
    986    i = MY_LSTAT ( name, &statBuf );
    987    if (i != 0) return True;
    988    if (MY_S_ISREG(statBuf.st_mode)) return False;
    989    return True;
    990 }
    991 
    992 
    993 /*---------------------------------------------*/
    994 /*--
    995   rac 11/21/98 see if file has hard links to it
    996 --*/
    997 static
    998 Int32 countHardLinks ( Char* name )
    999 {
   1000    IntNative      i;
   1001    struct MY_STAT statBuf;
   1002 
   1003    i = MY_LSTAT ( name, &statBuf );
   1004    if (i != 0) return 0;
   1005    return (statBuf.st_nlink - 1);
   1006 }
   1007 
   1008 
   1009 /*---------------------------------------------*/
   1010 /* Copy modification date, access date, permissions and owner from the
   1011    source to destination file.  We have to copy this meta-info off
   1012    into fileMetaInfo before starting to compress / decompress it,
   1013    because doing it afterwards means we get the wrong access time.
   1014 
   1015    To complicate matters, in compress() and decompress() below, the
   1016    sequence of tests preceding the call to saveInputFileMetaInfo()
   1017    involves calling fileExists(), which in turn establishes its result
   1018    by attempting to fopen() the file, and if successful, immediately
   1019    fclose()ing it again.  So we have to assume that the fopen() call
   1020    does not cause the access time field to be updated.
   1021 
   1022    Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
   1023    to imply that merely doing open() will not affect the access time.
   1024    Therefore we merely need to hope that the C library only does
   1025    open() as a result of fopen(), and not any kind of read()-ahead
   1026    cleverness.
   1027 
   1028    It sounds pretty fragile to me.  Whether this carries across
   1029    robustly to arbitrary Unix-like platforms (or even works robustly
   1030    on this one, RedHat 7.2) is unknown to me.  Nevertheless ...
   1031 */
   1032 #if BZ_UNIX
   1033 static
   1034 struct MY_STAT fileMetaInfo;
   1035 #endif
   1036 
   1037 static
   1038 void saveInputFileMetaInfo ( Char *srcName )
   1039 {
   1040 #  if BZ_UNIX
   1041    IntNative retVal;
   1042    /* Note use of stat here, not lstat. */
   1043    retVal = MY_STAT( srcName, &fileMetaInfo );
   1044    ERROR_IF_NOT_ZERO ( retVal );
   1045 #  endif
   1046 }
   1047 
   1048 
   1049 static
   1050 void applySavedTimeInfoToOutputFile ( Char *dstName )
   1051 {
   1052 #  if BZ_UNIX
   1053    IntNative      retVal;
   1054    struct utimbuf uTimBuf;
   1055 
   1056    uTimBuf.actime = fileMetaInfo.st_atime;
   1057    uTimBuf.modtime = fileMetaInfo.st_mtime;
   1058 
   1059    retVal = utime ( dstName, &uTimBuf );
   1060    ERROR_IF_NOT_ZERO ( retVal );
   1061 #  endif
   1062 }
   1063 
   1064 static
   1065 void applySavedFileAttrToOutputFile ( IntNative fd )
   1066 {
   1067 #  if BZ_UNIX
   1068    IntNative retVal;
   1069 
   1070    retVal = fchmod ( fd, fileMetaInfo.st_mode );
   1071    ERROR_IF_NOT_ZERO ( retVal );
   1072 
   1073    (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
   1074    /* chown() will in many cases return with EPERM, which can
   1075       be safely ignored.
   1076    */
   1077 #  endif
   1078 }
   1079 
   1080 
   1081 /*---------------------------------------------*/
   1082 static
   1083 Bool containsDubiousChars ( Char* name )
   1084 {
   1085 #  if BZ_UNIX
   1086    /* On unix, files can contain any characters and the file expansion
   1087     * is performed by the shell.
   1088     */
   1089    return False;
   1090 #  else /* ! BZ_UNIX */
   1091    /* On non-unix (Win* platforms), wildcard characters are not allowed in
   1092     * filenames.
   1093     */
   1094    for (; *name != '\0'; name++)
   1095       if (*name == '?' || *name == '*') return True;
   1096    return False;
   1097 #  endif /* BZ_UNIX */
   1098 }
   1099 
   1100 
   1101 /*---------------------------------------------*/
   1102 #define BZ_N_SUFFIX_PAIRS 4
   1103 
   1104 const Char* zSuffix[BZ_N_SUFFIX_PAIRS]
   1105    = { ".bz2", ".bz", ".tbz2", ".tbz" };
   1106 const Char* unzSuffix[BZ_N_SUFFIX_PAIRS]
   1107    = { "", "", ".tar", ".tar" };
   1108 
   1109 static
   1110 Bool hasSuffix ( Char* s, const Char* suffix )
   1111 {
   1112    Int32 ns = strlen(s);
   1113    Int32 nx = strlen(suffix);
   1114    if (ns < nx) return False;
   1115    if (strcmp(s + ns - nx, suffix) == 0) return True;
   1116    return False;
   1117 }
   1118 
   1119 static
   1120 Bool mapSuffix ( Char* name,
   1121                  const Char* oldSuffix,
   1122                  const Char* newSuffix )
   1123 {
   1124    if (!hasSuffix(name,oldSuffix)) return False;
   1125    name[strlen(name)-strlen(oldSuffix)] = 0;
   1126    strcat ( name, newSuffix );
   1127    return True;
   1128 }
   1129 
   1130 
   1131 /*---------------------------------------------*/
   1132 static
   1133 void compress ( Char *name )
   1134 {
   1135    FILE  *inStr;
   1136    FILE  *outStr;
   1137    Int32 n, i;
   1138    struct MY_STAT statBuf;
   1139 
   1140    deleteOutputOnInterrupt = False;
   1141 
   1142    if (name == NULL && srcMode != SM_I2O)
   1143       panic ( "compress: bad modes\n" );
   1144 
   1145    switch (srcMode) {
   1146       case SM_I2O:
   1147          copyFileName ( inName, (Char*)"(stdin)" );
   1148          copyFileName ( outName, (Char*)"(stdout)" );
   1149          break;
   1150       case SM_F2F:
   1151          copyFileName ( inName, name );
   1152          copyFileName ( outName, name );
   1153          strcat ( outName, ".bz2" );
   1154          break;
   1155       case SM_F2O:
   1156          copyFileName ( inName, name );
   1157          copyFileName ( outName, (Char*)"(stdout)" );
   1158          break;
   1159    }
   1160 
   1161    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
   1162       if (noisy)
   1163       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
   1164                 progName, inName );
   1165       setExit(1);
   1166       return;
   1167    }
   1168    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
   1169       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
   1170                 progName, inName, strerror(errno) );
   1171       setExit(1);
   1172       return;
   1173    }
   1174    for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
   1175       if (hasSuffix(inName, zSuffix[i])) {
   1176          if (noisy)
   1177          fprintf ( stderr,
   1178                    "%s: Input file %s already has %s suffix.\n",
   1179                    progName, inName, zSuffix[i] );
   1180          setExit(1);
   1181          return;
   1182       }
   1183    }
   1184    if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
   1185       MY_STAT(inName, &statBuf);
   1186       if ( MY_S_ISDIR(statBuf.st_mode) ) {
   1187          fprintf( stderr,
   1188                   "%s: Input file %s is a directory.\n",
   1189                   progName,inName);
   1190          setExit(1);
   1191          return;
   1192       }
   1193    }
   1194    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
   1195       if (noisy)
   1196       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
   1197                 progName, inName );
   1198       setExit(1);
   1199       return;
   1200    }
   1201    if ( srcMode == SM_F2F && fileExists ( outName ) ) {
   1202       if (forceOverwrite) {
   1203 	 remove(outName);
   1204       } else {
   1205 	 fprintf ( stderr, "%s: Output file %s already exists.\n",
   1206 		   progName, outName );
   1207 	 setExit(1);
   1208 	 return;
   1209       }
   1210    }
   1211    if ( srcMode == SM_F2F && !forceOverwrite &&
   1212         (n=countHardLinks ( inName )) > 0) {
   1213       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
   1214                 progName, inName, n, n > 1 ? "s" : "" );
   1215       setExit(1);
   1216       return;
   1217    }
   1218 
   1219    if ( srcMode == SM_F2F ) {
   1220       /* Save the file's meta-info before we open it.  Doing it later
   1221          means we mess up the access times. */
   1222       saveInputFileMetaInfo ( inName );
   1223    }
   1224 
   1225    switch ( srcMode ) {
   1226 
   1227       case SM_I2O:
   1228          inStr = stdin;
   1229          outStr = stdout;
   1230          if ( isatty ( fileno ( stdout ) ) ) {
   1231             fprintf ( stderr,
   1232                       "%s: I won't write compressed data to a terminal.\n",
   1233                       progName );
   1234             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
   1235                               progName, progName );
   1236             setExit(1);
   1237             return;
   1238          };
   1239          break;
   1240 
   1241       case SM_F2O:
   1242          inStr = fopen ( inName, "rb" );
   1243          outStr = stdout;
   1244          if ( isatty ( fileno ( stdout ) ) ) {
   1245             fprintf ( stderr,
   1246                       "%s: I won't write compressed data to a terminal.\n",
   1247                       progName );
   1248             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
   1249                               progName, progName );
   1250             if ( inStr != NULL ) fclose ( inStr );
   1251             setExit(1);
   1252             return;
   1253          };
   1254          if ( inStr == NULL ) {
   1255             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
   1256                       progName, inName, strerror(errno) );
   1257             setExit(1);
   1258             return;
   1259          };
   1260          break;
   1261 
   1262       case SM_F2F:
   1263          inStr = fopen ( inName, "rb" );
   1264          outStr = fopen_output_safely ( outName, "wb" );
   1265          if ( outStr == NULL) {
   1266             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
   1267                       progName, outName, strerror(errno) );
   1268             if ( inStr != NULL ) fclose ( inStr );
   1269             setExit(1);
   1270             return;
   1271          }
   1272          if ( inStr == NULL ) {
   1273             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
   1274                       progName, inName, strerror(errno) );
   1275             if ( outStr != NULL ) fclose ( outStr );
   1276             setExit(1);
   1277             return;
   1278          };
   1279          break;
   1280 
   1281       default:
   1282          panic ( "compress: bad srcMode" );
   1283          break;
   1284    }
   1285 
   1286    if (verbosity >= 1) {
   1287       fprintf ( stderr,  "  %s: ", inName );
   1288       pad ( inName );
   1289       fflush ( stderr );
   1290    }
   1291 
   1292    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
   1293    outputHandleJustInCase = outStr;
   1294    deleteOutputOnInterrupt = True;
   1295    compressStream ( inStr, outStr );
   1296    outputHandleJustInCase = NULL;
   1297 
   1298    /*--- If there was an I/O error, we won't get here. ---*/
   1299    if ( srcMode == SM_F2F ) {
   1300       applySavedTimeInfoToOutputFile ( outName );
   1301       deleteOutputOnInterrupt = False;
   1302       if ( !keepInputFiles ) {
   1303          IntNative retVal = remove ( inName );
   1304          ERROR_IF_NOT_ZERO ( retVal );
   1305       }
   1306    }
   1307 
   1308    deleteOutputOnInterrupt = False;
   1309 }
   1310 
   1311 
   1312 /*---------------------------------------------*/
   1313 static
   1314 void uncompress ( Char *name )
   1315 {
   1316    FILE  *inStr;
   1317    FILE  *outStr;
   1318    Int32 n, i;
   1319    Bool  magicNumberOK;
   1320    Bool  cantGuess;
   1321    struct MY_STAT statBuf;
   1322 
   1323    deleteOutputOnInterrupt = False;
   1324 
   1325    if (name == NULL && srcMode != SM_I2O)
   1326       panic ( "uncompress: bad modes\n" );
   1327 
   1328    cantGuess = False;
   1329    switch (srcMode) {
   1330       case SM_I2O:
   1331          copyFileName ( inName, (Char*)"(stdin)" );
   1332          copyFileName ( outName, (Char*)"(stdout)" );
   1333          break;
   1334       case SM_F2F:
   1335          copyFileName ( inName, name );
   1336          copyFileName ( outName, name );
   1337          for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
   1338             if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
   1339                goto zzz;
   1340          cantGuess = True;
   1341          strcat ( outName, ".out" );
   1342          break;
   1343       case SM_F2O:
   1344          copyFileName ( inName, name );
   1345          copyFileName ( outName, (Char*)"(stdout)" );
   1346          break;
   1347    }
   1348 
   1349    zzz:
   1350    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
   1351       if (noisy)
   1352       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
   1353                 progName, inName );
   1354       setExit(1);
   1355       return;
   1356    }
   1357    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
   1358       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
   1359                 progName, inName, strerror(errno) );
   1360       setExit(1);
   1361       return;
   1362    }
   1363    if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
   1364       MY_STAT(inName, &statBuf);
   1365       if ( MY_S_ISDIR(statBuf.st_mode) ) {
   1366          fprintf( stderr,
   1367                   "%s: Input file %s is a directory.\n",
   1368                   progName,inName);
   1369          setExit(1);
   1370          return;
   1371       }
   1372    }
   1373    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
   1374       if (noisy)
   1375       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
   1376                 progName, inName );
   1377       setExit(1);
   1378       return;
   1379    }
   1380    if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
   1381       if (noisy)
   1382       fprintf ( stderr,
   1383                 "%s: Can't guess original name for %s -- using %s\n",
   1384                 progName, inName, outName );
   1385       /* just a warning, no return */
   1386    }
   1387    if ( srcMode == SM_F2F && fileExists ( outName ) ) {
   1388       if (forceOverwrite) {
   1389 	remove(outName);
   1390       } else {
   1391         fprintf ( stderr, "%s: Output file %s already exists.\n",
   1392                   progName, outName );
   1393         setExit(1);
   1394         return;
   1395       }
   1396    }
   1397    if ( srcMode == SM_F2F && !forceOverwrite &&
   1398         (n=countHardLinks ( inName ) ) > 0) {
   1399       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
   1400                 progName, inName, n, n > 1 ? "s" : "" );
   1401       setExit(1);
   1402       return;
   1403    }
   1404 
   1405    if ( srcMode == SM_F2F ) {
   1406       /* Save the file's meta-info before we open it.  Doing it later
   1407          means we mess up the access times. */
   1408       saveInputFileMetaInfo ( inName );
   1409    }
   1410 
   1411    switch ( srcMode ) {
   1412 
   1413       case SM_I2O:
   1414          inStr = stdin;
   1415          outStr = stdout;
   1416          if ( isatty ( fileno ( stdin ) ) ) {
   1417             fprintf ( stderr,
   1418                       "%s: I won't read compressed data from a terminal.\n",
   1419                       progName );
   1420             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
   1421                               progName, progName );
   1422             setExit(1);
   1423             return;
   1424          };
   1425          break;
   1426 
   1427       case SM_F2O:
   1428          inStr = fopen ( inName, "rb" );
   1429          outStr = stdout;
   1430          if ( inStr == NULL ) {
   1431             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
   1432                       progName, inName, strerror(errno) );
   1433             if ( inStr != NULL ) fclose ( inStr );
   1434             setExit(1);
   1435             return;
   1436          };
   1437          break;
   1438 
   1439       case SM_F2F:
   1440          inStr = fopen ( inName, "rb" );
   1441          outStr = fopen_output_safely ( outName, "wb" );
   1442          if ( outStr == NULL) {
   1443             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
   1444                       progName, outName, strerror(errno) );
   1445             if ( inStr != NULL ) fclose ( inStr );
   1446             setExit(1);
   1447             return;
   1448          }
   1449          if ( inStr == NULL ) {
   1450             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
   1451                       progName, inName, strerror(errno) );
   1452             if ( outStr != NULL ) fclose ( outStr );
   1453             setExit(1);
   1454             return;
   1455          };
   1456          break;
   1457 
   1458       default:
   1459          panic ( "uncompress: bad srcMode" );
   1460          break;
   1461    }
   1462 
   1463    if (verbosity >= 1) {
   1464       fprintf ( stderr, "  %s: ", inName );
   1465       pad ( inName );
   1466       fflush ( stderr );
   1467    }
   1468 
   1469    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
   1470    outputHandleJustInCase = outStr;
   1471    deleteOutputOnInterrupt = True;
   1472    magicNumberOK = uncompressStream ( inStr, outStr );
   1473    outputHandleJustInCase = NULL;
   1474 
   1475    /*--- If there was an I/O error, we won't get here. ---*/
   1476    if ( magicNumberOK ) {
   1477       if ( srcMode == SM_F2F ) {
   1478          applySavedTimeInfoToOutputFile ( outName );
   1479          deleteOutputOnInterrupt = False;
   1480          if ( !keepInputFiles ) {
   1481             IntNative retVal = remove ( inName );
   1482             ERROR_IF_NOT_ZERO ( retVal );
   1483          }
   1484       }
   1485    } else {
   1486       unzFailsExist = True;
   1487       deleteOutputOnInterrupt = False;
   1488       if ( srcMode == SM_F2F ) {
   1489          IntNative retVal = remove ( outName );
   1490          ERROR_IF_NOT_ZERO ( retVal );
   1491       }
   1492    }
   1493    deleteOutputOnInterrupt = False;
   1494 
   1495    if ( magicNumberOK ) {
   1496       if (verbosity >= 1)
   1497          fprintf ( stderr, "done\n" );
   1498    } else {
   1499       setExit(2);
   1500       if (verbosity >= 1)
   1501          fprintf ( stderr, "not a bzip2 file.\n" ); else
   1502          fprintf ( stderr,
   1503                    "%s: %s is not a bzip2 file.\n",
   1504                    progName, inName );
   1505    }
   1506 
   1507 }
   1508 
   1509 
   1510 /*---------------------------------------------*/
   1511 static
   1512 void testf ( Char *name )
   1513 {
   1514    FILE *inStr;
   1515    Bool allOK;
   1516    struct MY_STAT statBuf;
   1517 
   1518    deleteOutputOnInterrupt = False;
   1519 
   1520    if (name == NULL && srcMode != SM_I2O)
   1521       panic ( "testf: bad modes\n" );
   1522 
   1523    copyFileName ( outName, (Char*)"(none)" );
   1524    switch (srcMode) {
   1525       case SM_I2O: copyFileName ( inName, (Char*)"(stdin)" ); break;
   1526       case SM_F2F: copyFileName ( inName, name ); break;
   1527       case SM_F2O: copyFileName ( inName, name ); break;
   1528    }
   1529 
   1530    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
   1531       if (noisy)
   1532       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
   1533                 progName, inName );
   1534       setExit(1);
   1535       return;
   1536    }
   1537    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
   1538       fprintf ( stderr, "%s: Can't open input %s: %s.\n",
   1539                 progName, inName, strerror(errno) );
   1540       setExit(1);
   1541       return;
   1542    }
   1543    if ( srcMode != SM_I2O ) {
   1544       MY_STAT(inName, &statBuf);
   1545       if ( MY_S_ISDIR(statBuf.st_mode) ) {
   1546          fprintf( stderr,
   1547                   "%s: Input file %s is a directory.\n",
   1548                   progName,inName);
   1549          setExit(1);
   1550          return;
   1551       }
   1552    }
   1553 
   1554    switch ( srcMode ) {
   1555 
   1556       case SM_I2O:
   1557          if ( isatty ( fileno ( stdin ) ) ) {
   1558             fprintf ( stderr,
   1559                       "%s: I won't read compressed data from a terminal.\n",
   1560                       progName );
   1561             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
   1562                               progName, progName );
   1563             setExit(1);
   1564             return;
   1565          };
   1566          inStr = stdin;
   1567          break;
   1568 
   1569       case SM_F2O: case SM_F2F:
   1570          inStr = fopen ( inName, "rb" );
   1571          if ( inStr == NULL ) {
   1572             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
   1573                       progName, inName, strerror(errno) );
   1574             setExit(1);
   1575             return;
   1576          };
   1577          break;
   1578 
   1579       default:
   1580          panic ( "testf: bad srcMode" );
   1581          break;
   1582    }
   1583 
   1584    if (verbosity >= 1) {
   1585       fprintf ( stderr, "  %s: ", inName );
   1586       pad ( inName );
   1587       fflush ( stderr );
   1588    }
   1589 
   1590    /*--- Now the input handle is sane.  Do the Biz. ---*/
   1591    outputHandleJustInCase = NULL;
   1592    allOK = testStream ( inStr );
   1593 
   1594    if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
   1595    if (!allOK) testFailsExist = True;
   1596 }
   1597 
   1598 
   1599 /*---------------------------------------------*/
   1600 static
   1601 void license ( void )
   1602 {
   1603    fprintf ( stderr,
   1604 
   1605     "bzip2, a block-sorting file compressor.  "
   1606     "Version %s.\n"
   1607     "   \n"
   1608     "   Copyright (C) 1996-2010 by Julian Seward.\n"
   1609     "   \n"
   1610     "   This program is free software; you can redistribute it and/or modify\n"
   1611     "   it under the terms set out in the LICENSE file, which is included\n"
   1612     "   in the bzip2-1.0.6 source distribution.\n"
   1613     "   \n"
   1614     "   This program is distributed in the hope that it will be useful,\n"
   1615     "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
   1616     "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
   1617     "   LICENSE file for more details.\n"
   1618     "   \n",
   1619     BZ2_bzlibVersion()
   1620    );
   1621 }
   1622 
   1623 
   1624 /*---------------------------------------------*/
   1625 static
   1626 void usage ( Char *fullProgName )
   1627 {
   1628    fprintf (
   1629       stderr,
   1630       "bzip2, a block-sorting file compressor.  "
   1631       "Version %s.\n"
   1632       "\n   usage: %s [flags and input files in any order]\n"
   1633       "\n"
   1634       "   -h --help           print this message\n"
   1635       "   -d --decompress     force decompression\n"
   1636       "   -z --compress       force compression\n"
   1637       "   -k --keep           keep (don't delete) input files\n"
   1638       "   -f --force          overwrite existing output files\n"
   1639       "   -t --test           test compressed file integrity\n"
   1640       "   -c --stdout         output to standard out\n"
   1641       "   -q --quiet          suppress noncritical error messages\n"
   1642       "   -v --verbose        be verbose (a 2nd -v gives more)\n"
   1643       "   -L --license        display software version & license\n"
   1644       "   -V --version        display software version & license\n"
   1645       "   -s --small          use less memory (at most 2500k)\n"
   1646       "   -1 .. -9            set block size to 100k .. 900k\n"
   1647       "   --fast              alias for -1\n"
   1648       "   --best              alias for -9\n"
   1649       "\n"
   1650       "   If invoked as `bzip2', default action is to compress.\n"
   1651       "              as `bunzip2',  default action is to decompress.\n"
   1652       "              as `bzcat', default action is to decompress to stdout.\n"
   1653       "\n"
   1654       "   If no file names are given, bzip2 compresses or decompresses\n"
   1655       "   from standard input to standard output.  You can combine\n"
   1656       "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
   1657 #     if BZ_UNIX
   1658       "\n"
   1659 #     endif
   1660       ,
   1661 
   1662       BZ2_bzlibVersion(),
   1663       fullProgName
   1664    );
   1665 }
   1666 
   1667 
   1668 /*---------------------------------------------*/
   1669 static
   1670 void redundant ( Char* flag )
   1671 {
   1672    fprintf (
   1673       stderr,
   1674       "%s: %s is redundant in versions 0.9.5 and above\n",
   1675       progName, flag );
   1676 }
   1677 
   1678 
   1679 /*---------------------------------------------*/
   1680 /*--
   1681   All the garbage from here to main() is purely to
   1682   implement a linked list of command-line arguments,
   1683   into which main() copies argv[1 .. argc-1].
   1684 
   1685   The purpose of this exercise is to facilitate
   1686   the expansion of wildcard characters * and ? in
   1687   filenames for OSs which don't know how to do it
   1688   themselves, like MSDOS, Windows 95 and NT.
   1689 
   1690   The actual Dirty Work is done by the platform-
   1691   specific macro APPEND_FILESPEC.
   1692 --*/
   1693 
   1694 typedef
   1695    struct zzzz {
   1696       Char        *name;
   1697       struct zzzz *link;
   1698    }
   1699    Cell;
   1700 
   1701 
   1702 /*---------------------------------------------*/
   1703 static
   1704 void *myMalloc ( Int32 n )
   1705 {
   1706    void* p;
   1707 
   1708    p = malloc ( (size_t)n );
   1709    if (p == NULL) outOfMemory ();
   1710    return p;
   1711 }
   1712 
   1713 
   1714 /*---------------------------------------------*/
   1715 static
   1716 Cell *mkCell ( void )
   1717 {
   1718    Cell *c;
   1719 
   1720    c = (Cell*) myMalloc ( sizeof ( Cell ) );
   1721    c->name = NULL;
   1722    c->link = NULL;
   1723    return c;
   1724 }
   1725 
   1726 
   1727 /*---------------------------------------------*/
   1728 static
   1729 Cell *snocString ( Cell *root, Char *name )
   1730 {
   1731    if (root == NULL) {
   1732       Cell *tmp = mkCell();
   1733       tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
   1734       strcpy ( tmp->name, name );
   1735       return tmp;
   1736    } else {
   1737       Cell *tmp = root;
   1738       while (tmp->link != NULL) tmp = tmp->link;
   1739       tmp->link = snocString ( tmp->link, name );
   1740       return root;
   1741    }
   1742 }
   1743 
   1744 
   1745 /*---------------------------------------------*/
   1746 static
   1747 void addFlagsFromEnvVar ( Cell** argList, Char* varName )
   1748 {
   1749    Int32 i, j, k;
   1750    Char *envbase, *p;
   1751 
   1752    envbase = getenv(varName);
   1753    if (envbase != NULL) {
   1754       p = envbase;
   1755       i = 0;
   1756       while (True) {
   1757          if (p[i] == 0) break;
   1758          p += i;
   1759          i = 0;
   1760          while (isspace((Int32)(p[0]))) p++;
   1761          while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
   1762          if (i > 0) {
   1763             k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
   1764             for (j = 0; j < k; j++) tmpName[j] = p[j];
   1765             tmpName[k] = 0;
   1766             APPEND_FLAG(*argList, tmpName);
   1767          }
   1768       }
   1769    }
   1770 }
   1771 
   1772 
   1773 /*---------------------------------------------*/
   1774 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
   1775 
   1776 IntNative main ( IntNative argc, Char *argv[] )
   1777 {
   1778    Int32  i, j;
   1779    Char   *tmp;
   1780    Cell   *argList;
   1781    Cell   *aa;
   1782    Bool   decode;
   1783 
   1784    /*-- Be really really really paranoid :-) --*/
   1785    if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
   1786        sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
   1787        sizeof(Char)  != 1 || sizeof(UChar)  != 1)
   1788       configError();
   1789 
   1790    /*-- Initialise --*/
   1791    outputHandleJustInCase  = NULL;
   1792    smallMode               = False;
   1793    keepInputFiles          = False;
   1794    forceOverwrite          = False;
   1795    noisy                   = True;
   1796    verbosity               = 0;
   1797    blockSize100k           = 9;
   1798    testFailsExist          = False;
   1799    unzFailsExist           = False;
   1800    numFileNames            = 0;
   1801    numFilesProcessed       = 0;
   1802    workFactor              = 30;
   1803    deleteOutputOnInterrupt = False;
   1804    exitValue               = 0;
   1805    i = j = 0; /* avoid bogus warning from egcs-1.1.X */
   1806 
   1807    /*-- Set up signal handlers for mem access errors --*/
   1808    signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
   1809 #  if BZ_UNIX
   1810 #  ifndef __DJGPP__
   1811    signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
   1812 #  endif
   1813 #  endif
   1814 
   1815    copyFileName ( inName,  (Char*)"(none)" );
   1816    copyFileName ( outName, (Char*)"(none)" );
   1817 
   1818    copyFileName ( progNameReally, argv[0] );
   1819    progName = &progNameReally[0];
   1820    for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
   1821       if (*tmp == PATH_SEP) progName = tmp + 1;
   1822 
   1823 
   1824    /*-- Copy flags from env var BZIP2, and
   1825         expand filename wildcards in arg list.
   1826    --*/
   1827    argList = NULL;
   1828    addFlagsFromEnvVar ( &argList,  (Char*)"BZIP2" );
   1829    addFlagsFromEnvVar ( &argList,  (Char*)"BZIP" );
   1830    for (i = 1; i <= argc-1; i++)
   1831       APPEND_FILESPEC(argList, argv[i]);
   1832 
   1833 
   1834    /*-- Find the length of the longest filename --*/
   1835    longestFileName = 7;
   1836    numFileNames    = 0;
   1837    decode          = True;
   1838    for (aa = argList; aa != NULL; aa = aa->link) {
   1839       if (ISFLAG("--")) { decode = False; continue; }
   1840       if (aa->name[0] == '-' && decode) continue;
   1841       numFileNames++;
   1842       if (longestFileName < (Int32)strlen(aa->name) )
   1843          longestFileName = (Int32)strlen(aa->name);
   1844    }
   1845 
   1846 
   1847    /*-- Determine source modes; flag handling may change this too. --*/
   1848    if (numFileNames == 0)
   1849       srcMode = SM_I2O; else srcMode = SM_F2F;
   1850 
   1851 
   1852    /*-- Determine what to do (compress/uncompress/test/cat). --*/
   1853    /*-- Note that subsequent flag handling may change this. --*/
   1854    opMode = OM_Z;
   1855 
   1856    if ( (strstr ( progName, "unzip" ) != 0) ||
   1857         (strstr ( progName, "UNZIP" ) != 0) )
   1858       opMode = OM_UNZ;
   1859 
   1860    if ( (strstr ( progName, "z2cat" ) != 0) ||
   1861         (strstr ( progName, "Z2CAT" ) != 0) ||
   1862         (strstr ( progName, "zcat" ) != 0)  ||
   1863         (strstr ( progName, "ZCAT" ) != 0) )  {
   1864       opMode = OM_UNZ;
   1865       srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
   1866    }
   1867 
   1868 
   1869    /*-- Look at the flags. --*/
   1870    for (aa = argList; aa != NULL; aa = aa->link) {
   1871       if (ISFLAG("--")) break;
   1872       if (aa->name[0] == '-' && aa->name[1] != '-') {
   1873          for (j = 1; aa->name[j] != '\0'; j++) {
   1874             switch (aa->name[j]) {
   1875                case 'c': srcMode          = SM_F2O; break;
   1876                case 'd': opMode           = OM_UNZ; break;
   1877                case 'z': opMode           = OM_Z; break;
   1878                case 'f': forceOverwrite   = True; break;
   1879                case 't': opMode           = OM_TEST; break;
   1880                case 'k': keepInputFiles   = True; break;
   1881                case 's': smallMode        = True; break;
   1882                case 'q': noisy            = False; break;
   1883                case '1': blockSize100k    = 1; break;
   1884                case '2': blockSize100k    = 2; break;
   1885                case '3': blockSize100k    = 3; break;
   1886                case '4': blockSize100k    = 4; break;
   1887                case '5': blockSize100k    = 5; break;
   1888                case '6': blockSize100k    = 6; break;
   1889                case '7': blockSize100k    = 7; break;
   1890                case '8': blockSize100k    = 8; break;
   1891                case '9': blockSize100k    = 9; break;
   1892                case 'V':
   1893                case 'L': license();            break;
   1894                case 'v': verbosity++; break;
   1895                case 'h': usage ( progName );
   1896                          exit ( 0 );
   1897                          break;
   1898                default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
   1899                                    progName, aa->name );
   1900                          usage ( progName );
   1901                          exit ( 1 );
   1902                          break;
   1903             }
   1904          }
   1905       }
   1906    }
   1907 
   1908    /*-- And again ... --*/
   1909    for (aa = argList; aa != NULL; aa = aa->link) {
   1910       if (ISFLAG("--")) break;
   1911       if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
   1912       if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
   1913       if (ISFLAG("--compress"))          opMode           = OM_Z;    else
   1914       if (ISFLAG("--force"))             forceOverwrite   = True;    else
   1915       if (ISFLAG("--test"))              opMode           = OM_TEST; else
   1916       if (ISFLAG("--keep"))              keepInputFiles   = True;    else
   1917       if (ISFLAG("--small"))             smallMode        = True;    else
   1918       if (ISFLAG("--quiet"))             noisy            = False;   else
   1919       if (ISFLAG("--version"))           license();                  else
   1920       if (ISFLAG("--license"))           license();                  else
   1921       if (ISFLAG("--exponential"))       workFactor = 1;             else
   1922       if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
   1923       if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
   1924       if (ISFLAG("--fast"))              blockSize100k = 1;          else
   1925       if (ISFLAG("--best"))              blockSize100k = 9;          else
   1926       if (ISFLAG("--verbose"))           verbosity++;                else
   1927       if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
   1928          else
   1929          if (strncmp ( aa->name, "--", 2) == 0) {
   1930             fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
   1931             usage ( progName );
   1932             exit ( 1 );
   1933          }
   1934    }
   1935 
   1936    if (verbosity > 4) verbosity = 4;
   1937    if (opMode == OM_Z && smallMode && blockSize100k > 2)
   1938       blockSize100k = 2;
   1939 
   1940    if (opMode == OM_TEST && srcMode == SM_F2O) {
   1941       fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
   1942                 progName );
   1943       exit ( 1 );
   1944    }
   1945 
   1946    if (srcMode == SM_F2O && numFileNames == 0)
   1947       srcMode = SM_I2O;
   1948 
   1949    if (opMode != OM_Z) blockSize100k = 0;
   1950 
   1951    if (srcMode == SM_F2F) {
   1952       signal (SIGINT,  mySignalCatcher);
   1953       signal (SIGTERM, mySignalCatcher);
   1954 #     if BZ_UNIX
   1955       signal (SIGHUP,  mySignalCatcher);
   1956 #     endif
   1957    }
   1958 
   1959    if (opMode == OM_Z) {
   1960      if (srcMode == SM_I2O) {
   1961         compress ( NULL );
   1962      } else {
   1963         decode = True;
   1964         for (aa = argList; aa != NULL; aa = aa->link) {
   1965            if (ISFLAG("--")) { decode = False; continue; }
   1966            if (aa->name[0] == '-' && decode) continue;
   1967            numFilesProcessed++;
   1968            compress ( aa->name );
   1969         }
   1970      }
   1971    }
   1972    else
   1973 
   1974    if (opMode == OM_UNZ) {
   1975       unzFailsExist = False;
   1976       if (srcMode == SM_I2O) {
   1977          uncompress ( NULL );
   1978       } else {
   1979          decode = True;
   1980          for (aa = argList; aa != NULL; aa = aa->link) {
   1981             if (ISFLAG("--")) { decode = False; continue; }
   1982             if (aa->name[0] == '-' && decode) continue;
   1983             numFilesProcessed++;
   1984             uncompress ( aa->name );
   1985          }
   1986       }
   1987       if (unzFailsExist) {
   1988          setExit(2);
   1989          exit(exitValue);
   1990       }
   1991    }
   1992 
   1993    else {
   1994       testFailsExist = False;
   1995       if (srcMode == SM_I2O) {
   1996          testf ( NULL );
   1997       } else {
   1998          decode = True;
   1999          for (aa = argList; aa != NULL; aa = aa->link) {
   2000 	    if (ISFLAG("--")) { decode = False; continue; }
   2001             if (aa->name[0] == '-' && decode) continue;
   2002             numFilesProcessed++;
   2003             testf ( aa->name );
   2004 	 }
   2005       }
   2006       if (testFailsExist && noisy) {
   2007          fprintf ( stderr,
   2008            "\n"
   2009            "You can use the `bzip2recover' program to attempt to recover\n"
   2010            "data from undamaged sections of corrupted files.\n\n"
   2011          );
   2012          setExit(2);
   2013          exit(exitValue);
   2014       }
   2015    }
   2016 
   2017    /* Free the argument list memory to mollify leak detectors
   2018       (eg) Purify, Checker.  Serves no other useful purpose.
   2019    */
   2020    aa = argList;
   2021    while (aa != NULL) {
   2022       Cell* aa2 = aa->link;
   2023       if (aa->name != NULL) free(aa->name);
   2024       free(aa);
   2025       aa = aa2;
   2026    }
   2027 
   2028    return exitValue;
   2029 }
   2030 
   2031 
   2032 /*-----------------------------------------------------------*/
   2033 /*--- end                                         bzip2.c ---*/
   2034 /*-----------------------------------------------------------*/
   2035