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