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