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