Merge branch 'vendor/GMP'
[dragonfly.git] / contrib / bzip2 / 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.6 of 6 September 2010
11    Copyright (C) 1996-2010 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 /*---------------------------------------------*/
804 static 
805 void mySignalCatcher ( IntNative n )
806 {
807    fprintf ( stderr,
808              "\n%s: Control-C or similar caught, quitting.\n",
809              progName );
810    cleanUpAndFail(1);
811 }
812
813
814 /*---------------------------------------------*/
815 static 
816 void mySIGSEGVorSIGBUScatcher ( IntNative n )
817 {
818    if (opMode == OM_Z)
819       fprintf ( 
820       stderr,
821       "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
822       "\n"
823       "   Possible causes are (most likely first):\n"
824       "   (1) This computer has unreliable memory or cache hardware\n"
825       "       (a surprisingly common problem; try a different machine.)\n"
826       "   (2) A bug in the compiler used to create this executable\n"
827       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
828       "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
829       "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
830       "   \n"
831       "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
832       "   or (2), feel free to report it to me at: jseward@bzip.org.\n"
833       "   Section 4.3 of the user's manual describes the info a useful\n"
834       "   bug report should have.  If the manual is available on your\n"
835       "   system, please try and read it before mailing me.  If you don't\n"
836       "   have the manual or can't be bothered to read it, mail me anyway.\n"
837       "\n",
838       progName );
839       else
840       fprintf ( 
841       stderr,
842       "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
843       "\n"
844       "   Possible causes are (most likely first):\n"
845       "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
846       "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
847       "   (2) This computer has unreliable memory or cache hardware\n"
848       "       (a surprisingly common problem; try a different machine.)\n"
849       "   (3) A bug in the compiler used to create this executable\n"
850       "       (unlikely, if you didn't compile bzip2 yourself.)\n"
851       "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
852       "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
853       "   \n"
854       "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
855       "   or (3), feel free to report it to me at: jseward@bzip.org.\n"
856       "   Section 4.3 of the user's manual describes the info a useful\n"
857       "   bug report should have.  If the manual is available on your\n"
858       "   system, please try and read it before mailing me.  If you don't\n"
859       "   have the manual or can't be bothered to read it, mail me anyway.\n"
860       "\n",
861       progName );
862
863    showFileNames();
864    if (opMode == OM_Z)
865       cleanUpAndFail( 3 ); else
866       { cadvise(); cleanUpAndFail( 2 ); }
867 }
868
869
870 /*---------------------------------------------*/
871 static 
872 void outOfMemory ( void )
873 {
874    fprintf ( stderr,
875              "\n%s: couldn't allocate enough memory\n",
876              progName );
877    showFileNames();
878    cleanUpAndFail(1);
879 }
880
881
882 /*---------------------------------------------*/
883 static 
884 void configError ( void )
885 {
886    fprintf ( stderr,
887              "bzip2: I'm not configured correctly for this platform!\n"
888              "\tI require Int32, Int16 and Char to have sizes\n"
889              "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
890              "\tProbably you can fix this by defining them correctly,\n"
891              "\tand recompiling.  Bye!\n" );
892    setExit(3);
893    exit(exitValue);
894 }
895
896
897 /*---------------------------------------------------*/
898 /*--- The main driver machinery                   ---*/
899 /*---------------------------------------------------*/
900
901 /* All rather crufty.  The main problem is that input files
902    are stat()d multiple times before use.  This should be
903    cleaned up. 
904 */
905
906 /*---------------------------------------------*/
907 static 
908 void pad ( Char *s )
909 {
910    Int32 i;
911    if ( (Int32)strlen(s) >= longestFileName ) return;
912    for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
913       fprintf ( stderr, " " );
914 }
915
916
917 /*---------------------------------------------*/
918 static 
919 void copyFileName ( Char* to, Char* from ) 
920 {
921    if ( strlen(from) > FILE_NAME_LEN-10 )  {
922       fprintf (
923          stderr,
924          "bzip2: file name\n`%s'\n"
925          "is suspiciously (more than %d chars) long.\n"
926          "Try using a reasonable file name instead.  Sorry! :-)\n",
927          from, FILE_NAME_LEN-10
928       );
929       setExit(1);
930       exit(exitValue);
931    }
932
933   strncpy(to,from,FILE_NAME_LEN-10);
934   to[FILE_NAME_LEN-10]='\0';
935 }
936
937
938 /*---------------------------------------------*/
939 static 
940 Bool fileExists ( Char* name )
941 {
942    FILE *tmp   = fopen ( name, "rb" );
943    Bool exists = (tmp != NULL);
944    if (tmp != NULL) fclose ( tmp );
945    return exists;
946 }
947
948
949 /*---------------------------------------------*/
950 /* Open an output file safely with O_EXCL and good permissions.
951    This avoids a race condition in versions < 1.0.2, in which
952    the file was first opened and then had its interim permissions
953    set safely.  We instead use open() to create the file with
954    the interim permissions required. (--- --- rw-).
955
956    For non-Unix platforms, if we are not worrying about
957    security issues, simple this simply behaves like fopen.
958 */
959 static
960 FILE* fopen_output_safely ( Char* name, const char* mode )
961 {
962 #  if BZ_UNIX
963    FILE*     fp;
964    IntNative fh;
965    fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
966    if (fh == -1) return NULL;
967    fp = fdopen(fh, mode);
968    if (fp == NULL) close(fh);
969    return fp;
970 #  else
971    return fopen(name, mode);
972 #  endif
973 }
974
975
976 /*---------------------------------------------*/
977 /*--
978   if in doubt, return True
979 --*/
980 static 
981 Bool notAStandardFile ( Char* name )
982 {
983    IntNative      i;
984    struct MY_STAT statBuf;
985
986    i = MY_LSTAT ( name, &statBuf );
987    if (i != 0) return True;
988    if (MY_S_ISREG(statBuf.st_mode)) return False;
989    return True;
990 }
991
992
993 /*---------------------------------------------*/
994 /*--
995   rac 11/21/98 see if file has hard links to it
996 --*/
997 static 
998 Int32 countHardLinks ( Char* name )
999 {  
1000    IntNative      i;
1001    struct MY_STAT statBuf;
1002
1003    i = MY_LSTAT ( name, &statBuf );
1004    if (i != 0) return 0;
1005    return (statBuf.st_nlink - 1);
1006 }
1007
1008
1009 /*---------------------------------------------*/
1010 /* Copy modification date, access date, permissions and owner from the
1011    source to destination file.  We have to copy this meta-info off
1012    into fileMetaInfo before starting to compress / decompress it,
1013    because doing it afterwards means we get the wrong access time.
1014
1015    To complicate matters, in compress() and decompress() below, the
1016    sequence of tests preceding the call to saveInputFileMetaInfo()
1017    involves calling fileExists(), which in turn establishes its result
1018    by attempting to fopen() the file, and if successful, immediately
1019    fclose()ing it again.  So we have to assume that the fopen() call
1020    does not cause the access time field to be updated.
1021
1022    Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
1023    to imply that merely doing open() will not affect the access time.
1024    Therefore we merely need to hope that the C library only does
1025    open() as a result of fopen(), and not any kind of read()-ahead
1026    cleverness.
1027
1028    It sounds pretty fragile to me.  Whether this carries across
1029    robustly to arbitrary Unix-like platforms (or even works robustly
1030    on this one, RedHat 7.2) is unknown to me.  Nevertheless ...  
1031 */
1032 #if BZ_UNIX
1033 static 
1034 struct MY_STAT fileMetaInfo;
1035 #endif
1036
1037 static 
1038 void saveInputFileMetaInfo ( Char *srcName )
1039 {
1040 #  if BZ_UNIX
1041    IntNative retVal;
1042    /* Note use of stat here, not lstat. */
1043    retVal = MY_STAT( srcName, &fileMetaInfo );
1044    ERROR_IF_NOT_ZERO ( retVal );
1045 #  endif
1046 }
1047
1048
1049 static 
1050 void applySavedTimeInfoToOutputFile ( Char *dstName )
1051 {
1052 #  if BZ_UNIX
1053    IntNative      retVal;
1054    struct utimbuf uTimBuf;
1055
1056    uTimBuf.actime = fileMetaInfo.st_atime;
1057    uTimBuf.modtime = fileMetaInfo.st_mtime;
1058
1059    retVal = utime ( dstName, &uTimBuf );
1060    ERROR_IF_NOT_ZERO ( retVal );
1061 #  endif
1062 }
1063
1064 static 
1065 void applySavedFileAttrToOutputFile ( IntNative fd )
1066 {
1067 #  if BZ_UNIX
1068    IntNative retVal;
1069
1070    retVal = fchmod ( fd, fileMetaInfo.st_mode );
1071    ERROR_IF_NOT_ZERO ( retVal );
1072
1073    (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
1074    /* chown() will in many cases return with EPERM, which can
1075       be safely ignored.
1076    */
1077 #  endif
1078 }
1079
1080
1081 /*---------------------------------------------*/
1082 static 
1083 Bool containsDubiousChars ( Char* name )
1084 {
1085 #  if BZ_UNIX
1086    /* On unix, files can contain any characters and the file expansion
1087     * is performed by the shell.
1088     */
1089    return False;
1090 #  else /* ! BZ_UNIX */
1091    /* On non-unix (Win* platforms), wildcard characters are not allowed in 
1092     * filenames.
1093     */
1094    for (; *name != '\0'; name++)
1095       if (*name == '?' || *name == '*') return True;
1096    return False;
1097 #  endif /* BZ_UNIX */
1098 }
1099
1100
1101 /*---------------------------------------------*/
1102 #define BZ_N_SUFFIX_PAIRS 4
1103
1104 const Char* zSuffix[BZ_N_SUFFIX_PAIRS] 
1105    = { ".bz2", ".bz", ".tbz2", ".tbz" };
1106 const Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 
1107    = { "", "", ".tar", ".tar" };
1108
1109 static 
1110 Bool hasSuffix ( Char* s, const Char* suffix )
1111 {
1112    Int32 ns = strlen(s);
1113    Int32 nx = strlen(suffix);
1114    if (ns < nx) return False;
1115    if (strcmp(s + ns - nx, suffix) == 0) return True;
1116    return False;
1117 }
1118
1119 static 
1120 Bool mapSuffix ( Char* name, 
1121                  const Char* oldSuffix, 
1122                  const Char* newSuffix )
1123 {
1124    if (!hasSuffix(name,oldSuffix)) return False;
1125    name[strlen(name)-strlen(oldSuffix)] = 0;
1126    strcat ( name, newSuffix );
1127    return True;
1128 }
1129
1130
1131 /*---------------------------------------------*/
1132 static 
1133 void compress ( Char *name )
1134 {
1135    FILE  *inStr;
1136    FILE  *outStr;
1137    Int32 n, i;
1138    struct MY_STAT statBuf;
1139
1140    deleteOutputOnInterrupt = False;
1141
1142    if (name == NULL && srcMode != SM_I2O)
1143       panic ( "compress: bad modes\n" );
1144
1145    switch (srcMode) {
1146       case SM_I2O: 
1147          copyFileName ( inName, (Char*)"(stdin)" );
1148          copyFileName ( outName, (Char*)"(stdout)" ); 
1149          break;
1150       case SM_F2F: 
1151          copyFileName ( inName, name );
1152          copyFileName ( outName, name );
1153          strcat ( outName, ".bz2" ); 
1154          break;
1155       case SM_F2O: 
1156          copyFileName ( inName, name );
1157          copyFileName ( outName, (Char*)"(stdout)" ); 
1158          break;
1159    }
1160
1161    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1162       if (noisy)
1163       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1164                 progName, inName );
1165       setExit(1);
1166       return;
1167    }
1168    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1169       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1170                 progName, inName, strerror(errno) );
1171       setExit(1);
1172       return;
1173    }
1174    for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
1175       if (hasSuffix(inName, zSuffix[i])) {
1176          if (noisy)
1177          fprintf ( stderr, 
1178                    "%s: Input file %s already has %s suffix.\n",
1179                    progName, inName, zSuffix[i] );
1180          setExit(1);
1181          return;
1182       }
1183    }
1184    if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1185       MY_STAT(inName, &statBuf);
1186       if ( MY_S_ISDIR(statBuf.st_mode) ) {
1187          fprintf( stderr,
1188                   "%s: Input file %s is a directory.\n",
1189                   progName,inName);
1190          setExit(1);
1191          return;
1192       }
1193    }
1194    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1195       if (noisy)
1196       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1197                 progName, inName );
1198       setExit(1);
1199       return;
1200    }
1201    if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1202       if (forceOverwrite) {
1203          remove(outName);
1204       } else {
1205          fprintf ( stderr, "%s: Output file %s already exists.\n",
1206                    progName, outName );
1207          setExit(1);
1208          return;
1209       }
1210    }
1211    if ( srcMode == SM_F2F && !forceOverwrite &&
1212         (n=countHardLinks ( inName )) > 0) {
1213       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1214                 progName, inName, n, n > 1 ? "s" : "" );
1215       setExit(1);
1216       return;
1217    }
1218
1219    if ( srcMode == SM_F2F ) {
1220       /* Save the file's meta-info before we open it.  Doing it later
1221          means we mess up the access times. */
1222       saveInputFileMetaInfo ( inName );
1223    }
1224
1225    switch ( srcMode ) {
1226
1227       case SM_I2O:
1228          inStr = stdin;
1229          outStr = stdout;
1230          if ( isatty ( fileno ( stdout ) ) ) {
1231             fprintf ( stderr,
1232                       "%s: I won't write compressed data to a terminal.\n",
1233                       progName );
1234             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1235                               progName, progName );
1236             setExit(1);
1237             return;
1238          };
1239          break;
1240
1241       case SM_F2O:
1242          inStr = fopen ( inName, "rb" );
1243          outStr = stdout;
1244          if ( isatty ( fileno ( stdout ) ) ) {
1245             fprintf ( stderr,
1246                       "%s: I won't write compressed data to a terminal.\n",
1247                       progName );
1248             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1249                               progName, progName );
1250             if ( inStr != NULL ) fclose ( inStr );
1251             setExit(1);
1252             return;
1253          };
1254          if ( inStr == NULL ) {
1255             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1256                       progName, inName, strerror(errno) );
1257             setExit(1);
1258             return;
1259          };
1260          break;
1261
1262       case SM_F2F:
1263          inStr = fopen ( inName, "rb" );
1264          outStr = fopen_output_safely ( outName, "wb" );
1265          if ( outStr == NULL) {
1266             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1267                       progName, outName, strerror(errno) );
1268             if ( inStr != NULL ) fclose ( inStr );
1269             setExit(1);
1270             return;
1271          }
1272          if ( inStr == NULL ) {
1273             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1274                       progName, inName, strerror(errno) );
1275             if ( outStr != NULL ) fclose ( outStr );
1276             setExit(1);
1277             return;
1278          };
1279          break;
1280
1281       default:
1282          panic ( "compress: bad srcMode" );
1283          break;
1284    }
1285
1286    if (verbosity >= 1) {
1287       fprintf ( stderr,  "  %s: ", inName );
1288       pad ( inName );
1289       fflush ( stderr );
1290    }
1291
1292    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
1293    outputHandleJustInCase = outStr;
1294    deleteOutputOnInterrupt = True;
1295    compressStream ( inStr, outStr );
1296    outputHandleJustInCase = NULL;
1297
1298    /*--- If there was an I/O error, we won't get here. ---*/
1299    if ( srcMode == SM_F2F ) {
1300       applySavedTimeInfoToOutputFile ( outName );
1301       deleteOutputOnInterrupt = False;
1302       if ( !keepInputFiles ) {
1303          IntNative retVal = remove ( inName );
1304          ERROR_IF_NOT_ZERO ( retVal );
1305       }
1306    }
1307
1308    deleteOutputOnInterrupt = False;
1309 }
1310
1311
1312 /*---------------------------------------------*/
1313 static 
1314 void uncompress ( Char *name )
1315 {
1316    FILE  *inStr;
1317    FILE  *outStr;
1318    Int32 n, i;
1319    Bool  magicNumberOK;
1320    Bool  cantGuess;
1321    struct MY_STAT statBuf;
1322
1323    deleteOutputOnInterrupt = False;
1324
1325    if (name == NULL && srcMode != SM_I2O)
1326       panic ( "uncompress: bad modes\n" );
1327
1328    cantGuess = False;
1329    switch (srcMode) {
1330       case SM_I2O: 
1331          copyFileName ( inName, (Char*)"(stdin)" );
1332          copyFileName ( outName, (Char*)"(stdout)" ); 
1333          break;
1334       case SM_F2F: 
1335          copyFileName ( inName, name );
1336          copyFileName ( outName, name );
1337          for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
1338             if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
1339                goto zzz; 
1340          cantGuess = True;
1341          strcat ( outName, ".out" );
1342          break;
1343       case SM_F2O: 
1344          copyFileName ( inName, name );
1345          copyFileName ( outName, (Char*)"(stdout)" ); 
1346          break;
1347    }
1348
1349    zzz:
1350    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1351       if (noisy)
1352       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1353                 progName, inName );
1354       setExit(1);
1355       return;
1356    }
1357    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1358       fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1359                 progName, inName, strerror(errno) );
1360       setExit(1);
1361       return;
1362    }
1363    if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1364       MY_STAT(inName, &statBuf);
1365       if ( MY_S_ISDIR(statBuf.st_mode) ) {
1366          fprintf( stderr,
1367                   "%s: Input file %s is a directory.\n",
1368                   progName,inName);
1369          setExit(1);
1370          return;
1371       }
1372    }
1373    if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1374       if (noisy)
1375       fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1376                 progName, inName );
1377       setExit(1);
1378       return;
1379    }
1380    if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
1381       if (noisy)
1382       fprintf ( stderr, 
1383                 "%s: Can't guess original name for %s -- using %s\n",
1384                 progName, inName, outName );
1385       /* just a warning, no return */
1386    }   
1387    if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1388       if (forceOverwrite) {
1389         remove(outName);
1390       } else {
1391         fprintf ( stderr, "%s: Output file %s already exists.\n",
1392                   progName, outName );
1393         setExit(1);
1394         return;
1395       }
1396    }
1397    if ( srcMode == SM_F2F && !forceOverwrite &&
1398         (n=countHardLinks ( inName ) ) > 0) {
1399       fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1400                 progName, inName, n, n > 1 ? "s" : "" );
1401       setExit(1);
1402       return;
1403    }
1404
1405    if ( srcMode == SM_F2F ) {
1406       /* Save the file's meta-info before we open it.  Doing it later
1407          means we mess up the access times. */
1408       saveInputFileMetaInfo ( inName );
1409    }
1410
1411    switch ( srcMode ) {
1412
1413       case SM_I2O:
1414          inStr = stdin;
1415          outStr = stdout;
1416          if ( isatty ( fileno ( stdin ) ) ) {
1417             fprintf ( stderr,
1418                       "%s: I won't read compressed data from a terminal.\n",
1419                       progName );
1420             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1421                               progName, progName );
1422             setExit(1);
1423             return;
1424          };
1425          break;
1426
1427       case SM_F2O:
1428          inStr = fopen ( inName, "rb" );
1429          outStr = stdout;
1430          if ( inStr == NULL ) {
1431             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1432                       progName, inName, strerror(errno) );
1433             if ( inStr != NULL ) fclose ( inStr );
1434             setExit(1);
1435             return;
1436          };
1437          break;
1438
1439       case SM_F2F:
1440          inStr = fopen ( inName, "rb" );
1441          outStr = fopen_output_safely ( outName, "wb" );
1442          if ( outStr == NULL) {
1443             fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1444                       progName, outName, strerror(errno) );
1445             if ( inStr != NULL ) fclose ( inStr );
1446             setExit(1);
1447             return;
1448          }
1449          if ( inStr == NULL ) {
1450             fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1451                       progName, inName, strerror(errno) );
1452             if ( outStr != NULL ) fclose ( outStr );
1453             setExit(1);
1454             return;
1455          };
1456          break;
1457
1458       default:
1459          panic ( "uncompress: bad srcMode" );
1460          break;
1461    }
1462
1463    if (verbosity >= 1) {
1464       fprintf ( stderr, "  %s: ", inName );
1465       pad ( inName );
1466       fflush ( stderr );
1467    }
1468
1469    /*--- Now the input and output handles are sane.  Do the Biz. ---*/
1470    outputHandleJustInCase = outStr;
1471    deleteOutputOnInterrupt = True;
1472    magicNumberOK = uncompressStream ( inStr, outStr );
1473    outputHandleJustInCase = NULL;
1474
1475    /*--- If there was an I/O error, we won't get here. ---*/
1476    if ( magicNumberOK ) {
1477       if ( srcMode == SM_F2F ) {
1478          applySavedTimeInfoToOutputFile ( outName );
1479          deleteOutputOnInterrupt = False;
1480          if ( !keepInputFiles ) {
1481             IntNative retVal = remove ( inName );
1482             ERROR_IF_NOT_ZERO ( retVal );
1483          }
1484       }
1485    } else {
1486       unzFailsExist = True;
1487       deleteOutputOnInterrupt = False;
1488       if ( srcMode == SM_F2F ) {
1489          IntNative retVal = remove ( outName );
1490          ERROR_IF_NOT_ZERO ( retVal );
1491       }
1492    }
1493    deleteOutputOnInterrupt = False;
1494
1495    if ( magicNumberOK ) {
1496       if (verbosity >= 1)
1497          fprintf ( stderr, "done\n" );
1498    } else {
1499       setExit(2);
1500       if (verbosity >= 1)
1501          fprintf ( stderr, "not a bzip2 file.\n" ); else
1502          fprintf ( stderr,
1503                    "%s: %s is not a bzip2 file.\n",
1504                    progName, inName );
1505    }
1506
1507 }
1508
1509
1510 /*---------------------------------------------*/
1511 static 
1512 void testf ( Char *name )
1513 {
1514    FILE *inStr;
1515    Bool allOK;
1516    struct MY_STAT statBuf;
1517
1518    deleteOutputOnInterrupt = False;
1519
1520    if (name == NULL && srcMode != SM_I2O)
1521       panic ( "testf: bad modes\n" );
1522
1523    copyFileName ( outName, (Char*)"(none)" );
1524    switch (srcMode) {
1525       case SM_I2O: copyFileName ( inName, (Char*)"(stdin)" ); break;
1526       case SM_F2F: copyFileName ( inName, name ); break;
1527       case SM_F2O: copyFileName ( inName, name ); break;
1528    }
1529
1530    if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1531       if (noisy)
1532       fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1533                 progName, inName );
1534       setExit(1);
1535       return;
1536    }
1537    if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1538       fprintf ( stderr, "%s: Can't open input %s: %s.\n",
1539                 progName, inName, strerror(errno) );
1540       setExit(1);
1541       return;
1542    }
1543    if ( srcMode != SM_I2O ) {
1544       MY_STAT(inName, &statBuf);
1545       if ( MY_S_ISDIR(statBuf.st_mode) ) {
1546          fprintf( stderr,
1547                   "%s: Input file %s is a directory.\n",
1548                   progName,inName);
1549          setExit(1);
1550          return;
1551       }
1552    }
1553
1554    switch ( srcMode ) {
1555
1556       case SM_I2O:
1557          if ( isatty ( fileno ( stdin ) ) ) {
1558             fprintf ( stderr,
1559                       "%s: I won't read compressed data from a terminal.\n",
1560                       progName );
1561             fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1562                               progName, progName );
1563             setExit(1);
1564             return;
1565          };
1566          inStr = stdin;
1567          break;
1568
1569       case SM_F2O: case SM_F2F:
1570          inStr = fopen ( inName, "rb" );
1571          if ( inStr == NULL ) {
1572             fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1573                       progName, inName, strerror(errno) );
1574             setExit(1);
1575             return;
1576          };
1577          break;
1578
1579       default:
1580          panic ( "testf: bad srcMode" );
1581          break;
1582    }
1583
1584    if (verbosity >= 1) {
1585       fprintf ( stderr, "  %s: ", inName );
1586       pad ( inName );
1587       fflush ( stderr );
1588    }
1589
1590    /*--- Now the input handle is sane.  Do the Biz. ---*/
1591    outputHandleJustInCase = NULL;
1592    allOK = testStream ( inStr );
1593
1594    if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
1595    if (!allOK) testFailsExist = True;
1596 }
1597
1598
1599 /*---------------------------------------------*/
1600 static 
1601 void license ( void )
1602 {
1603    fprintf ( stderr,
1604
1605     "bzip2, a block-sorting file compressor.  "
1606     "Version %s.\n"
1607     "   \n"
1608     "   Copyright (C) 1996-2010 by Julian Seward.\n"
1609     "   \n"
1610     "   This program is free software; you can redistribute it and/or modify\n"
1611     "   it under the terms set out in the LICENSE file, which is included\n"
1612     "   in the bzip2-1.0.6 source distribution.\n"
1613     "   \n"
1614     "   This program is distributed in the hope that it will be useful,\n"
1615     "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1616     "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1617     "   LICENSE file for more details.\n"
1618     "   \n",
1619     BZ2_bzlibVersion()
1620    );
1621 }
1622
1623
1624 /*---------------------------------------------*/
1625 static 
1626 void usage ( Char *fullProgName )
1627 {
1628    fprintf (
1629       stderr,
1630       "bzip2, a block-sorting file compressor.  "
1631       "Version %s.\n"
1632       "\n   usage: %s [flags and input files in any order]\n"
1633       "\n"
1634       "   -h --help           print this message\n"
1635       "   -d --decompress     force decompression\n"
1636       "   -z --compress       force compression\n"
1637       "   -k --keep           keep (don't delete) input files\n"
1638       "   -f --force          overwrite existing output files\n"
1639       "   -t --test           test compressed file integrity\n"
1640       "   -c --stdout         output to standard out\n"
1641       "   -q --quiet          suppress noncritical error messages\n"
1642       "   -v --verbose        be verbose (a 2nd -v gives more)\n"
1643       "   -L --license        display software version & license\n"
1644       "   -V --version        display software version & license\n"
1645       "   -s --small          use less memory (at most 2500k)\n"
1646       "   -1 .. -9            set block size to 100k .. 900k\n"
1647       "   --fast              alias for -1\n"
1648       "   --best              alias for -9\n"
1649       "\n"
1650       "   If invoked as `bzip2', default action is to compress.\n"
1651       "              as `bunzip2',  default action is to decompress.\n"
1652       "              as `bzcat', default action is to decompress to stdout.\n"
1653       "\n"
1654       "   If no file names are given, bzip2 compresses or decompresses\n"
1655       "   from standard input to standard output.  You can combine\n"
1656       "   short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
1657 #     if BZ_UNIX
1658       "\n"
1659 #     endif
1660       ,
1661
1662       BZ2_bzlibVersion(),
1663       fullProgName
1664    );
1665 }
1666
1667
1668 /*---------------------------------------------*/
1669 static 
1670 void redundant ( Char* flag )
1671 {
1672    fprintf ( 
1673       stderr, 
1674       "%s: %s is redundant in versions 0.9.5 and above\n",
1675       progName, flag );
1676 }
1677
1678
1679 /*---------------------------------------------*/
1680 /*--
1681   All the garbage from here to main() is purely to
1682   implement a linked list of command-line arguments,
1683   into which main() copies argv[1 .. argc-1].
1684
1685   The purpose of this exercise is to facilitate 
1686   the expansion of wildcard characters * and ? in 
1687   filenames for OSs which don't know how to do it
1688   themselves, like MSDOS, Windows 95 and NT.
1689
1690   The actual Dirty Work is done by the platform-
1691   specific macro APPEND_FILESPEC.
1692 --*/
1693
1694 typedef
1695    struct zzzz {
1696       Char        *name;
1697       struct zzzz *link;
1698    }
1699    Cell;
1700
1701
1702 /*---------------------------------------------*/
1703 static 
1704 void *myMalloc ( Int32 n )
1705 {
1706    void* p;
1707
1708    p = malloc ( (size_t)n );
1709    if (p == NULL) outOfMemory ();
1710    return p;
1711 }
1712
1713
1714 /*---------------------------------------------*/
1715 static 
1716 Cell *mkCell ( void )
1717 {
1718    Cell *c;
1719
1720    c = (Cell*) myMalloc ( sizeof ( Cell ) );
1721    c->name = NULL;
1722    c->link = NULL;
1723    return c;
1724 }
1725
1726
1727 /*---------------------------------------------*/
1728 static 
1729 Cell *snocString ( Cell *root, Char *name )
1730 {
1731    if (root == NULL) {
1732       Cell *tmp = mkCell();
1733       tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
1734       strcpy ( tmp->name, name );
1735       return tmp;
1736    } else {
1737       Cell *tmp = root;
1738       while (tmp->link != NULL) tmp = tmp->link;
1739       tmp->link = snocString ( tmp->link, name );
1740       return root;
1741    }
1742 }
1743
1744
1745 /*---------------------------------------------*/
1746 static 
1747 void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 
1748 {
1749    Int32 i, j, k;
1750    Char *envbase, *p;
1751
1752    envbase = getenv(varName);
1753    if (envbase != NULL) {
1754       p = envbase;
1755       i = 0;
1756       while (True) {
1757          if (p[i] == 0) break;
1758          p += i;
1759          i = 0;
1760          while (isspace((Int32)(p[0]))) p++;
1761          while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
1762          if (i > 0) {
1763             k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
1764             for (j = 0; j < k; j++) tmpName[j] = p[j];
1765             tmpName[k] = 0;
1766             APPEND_FLAG(*argList, tmpName);
1767          }
1768       }
1769    }
1770 }
1771
1772
1773 /*---------------------------------------------*/
1774 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
1775
1776 IntNative main ( IntNative argc, Char *argv[] )
1777 {
1778    Int32  i, j;
1779    Char   *tmp;
1780    Cell   *argList;
1781    Cell   *aa;
1782    Bool   decode;
1783
1784    /*-- Be really really really paranoid :-) --*/
1785    if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
1786        sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
1787        sizeof(Char)  != 1 || sizeof(UChar)  != 1)
1788       configError();
1789
1790    /*-- Initialise --*/
1791    outputHandleJustInCase  = NULL;
1792    smallMode               = False;
1793    keepInputFiles          = False;
1794    forceOverwrite          = False;
1795    noisy                   = True;
1796    verbosity               = 0;
1797    blockSize100k           = 9;
1798    testFailsExist          = False;
1799    unzFailsExist           = False;
1800    numFileNames            = 0;
1801    numFilesProcessed       = 0;
1802    workFactor              = 30;
1803    deleteOutputOnInterrupt = False;
1804    exitValue               = 0;
1805    i = j = 0; /* avoid bogus warning from egcs-1.1.X */
1806
1807    /*-- Set up signal handlers for mem access errors --*/
1808    signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
1809 #  if BZ_UNIX
1810 #  ifndef __DJGPP__
1811    signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
1812 #  endif
1813 #  endif
1814
1815    copyFileName ( inName,  (Char*)"(none)" );
1816    copyFileName ( outName, (Char*)"(none)" );
1817
1818    copyFileName ( progNameReally, argv[0] );
1819    progName = &progNameReally[0];
1820    for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
1821       if (*tmp == PATH_SEP) progName = tmp + 1;
1822
1823
1824    /*-- Copy flags from env var BZIP2, and 
1825         expand filename wildcards in arg list.
1826    --*/
1827    argList = NULL;
1828    addFlagsFromEnvVar ( &argList,  (Char*)"BZIP2" );
1829    addFlagsFromEnvVar ( &argList,  (Char*)"BZIP" );
1830    for (i = 1; i <= argc-1; i++)
1831       APPEND_FILESPEC(argList, argv[i]);
1832
1833
1834    /*-- Find the length of the longest filename --*/
1835    longestFileName = 7;
1836    numFileNames    = 0;
1837    decode          = True;
1838    for (aa = argList; aa != NULL; aa = aa->link) {
1839       if (ISFLAG("--")) { decode = False; continue; }
1840       if (aa->name[0] == '-' && decode) continue;
1841       numFileNames++;
1842       if (longestFileName < (Int32)strlen(aa->name) )
1843          longestFileName = (Int32)strlen(aa->name);
1844    }
1845
1846
1847    /*-- Determine source modes; flag handling may change this too. --*/
1848    if (numFileNames == 0)
1849       srcMode = SM_I2O; else srcMode = SM_F2F;
1850
1851
1852    /*-- Determine what to do (compress/uncompress/test/cat). --*/
1853    /*-- Note that subsequent flag handling may change this. --*/
1854    opMode = OM_Z;
1855
1856    if ( (strstr ( progName, "unzip" ) != 0) ||
1857         (strstr ( progName, "UNZIP" ) != 0) )
1858       opMode = OM_UNZ;
1859
1860    if ( (strstr ( progName, "z2cat" ) != 0) ||
1861         (strstr ( progName, "Z2CAT" ) != 0) ||
1862         (strstr ( progName, "zcat" ) != 0)  ||
1863         (strstr ( progName, "ZCAT" ) != 0) )  {
1864       opMode = OM_UNZ;
1865       srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
1866    }
1867
1868
1869    /*-- Look at the flags. --*/
1870    for (aa = argList; aa != NULL; aa = aa->link) {
1871       if (ISFLAG("--")) break;
1872       if (aa->name[0] == '-' && aa->name[1] != '-') {
1873          for (j = 1; aa->name[j] != '\0'; j++) {
1874             switch (aa->name[j]) {
1875                case 'c': srcMode          = SM_F2O; break;
1876                case 'd': opMode           = OM_UNZ; break;
1877                case 'z': opMode           = OM_Z; break;
1878                case 'f': forceOverwrite   = True; break;
1879                case 't': opMode           = OM_TEST; break;
1880                case 'k': keepInputFiles   = True; break;
1881                case 's': smallMode        = True; break;
1882                case 'q': noisy            = False; break;
1883                case '1': blockSize100k    = 1; break;
1884                case '2': blockSize100k    = 2; break;
1885                case '3': blockSize100k    = 3; break;
1886                case '4': blockSize100k    = 4; break;
1887                case '5': blockSize100k    = 5; break;
1888                case '6': blockSize100k    = 6; break;
1889                case '7': blockSize100k    = 7; break;
1890                case '8': blockSize100k    = 8; break;
1891                case '9': blockSize100k    = 9; break;
1892                case 'V':
1893                case 'L': license();            break;
1894                case 'v': verbosity++; break;
1895                case 'h': usage ( progName );
1896                          exit ( 0 );
1897                          break;
1898                default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
1899                                    progName, aa->name );
1900                          usage ( progName );
1901                          exit ( 1 );
1902                          break;
1903             }
1904          }
1905       }
1906    }
1907    
1908    /*-- And again ... --*/
1909    for (aa = argList; aa != NULL; aa = aa->link) {
1910       if (ISFLAG("--")) break;
1911       if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
1912       if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
1913       if (ISFLAG("--compress"))          opMode           = OM_Z;    else
1914       if (ISFLAG("--force"))             forceOverwrite   = True;    else
1915       if (ISFLAG("--test"))              opMode           = OM_TEST; else
1916       if (ISFLAG("--keep"))              keepInputFiles   = True;    else
1917       if (ISFLAG("--small"))             smallMode        = True;    else
1918       if (ISFLAG("--quiet"))             noisy            = False;   else
1919       if (ISFLAG("--version"))           license();                  else
1920       if (ISFLAG("--license"))           license();                  else
1921       if (ISFLAG("--exponential"))       workFactor = 1;             else 
1922       if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
1923       if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
1924       if (ISFLAG("--fast"))              blockSize100k = 1;          else
1925       if (ISFLAG("--best"))              blockSize100k = 9;          else
1926       if (ISFLAG("--verbose"))           verbosity++;                else
1927       if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
1928          else
1929          if (strncmp ( aa->name, "--", 2) == 0) {
1930             fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
1931             usage ( progName );
1932             exit ( 1 );
1933          }
1934    }
1935
1936    if (verbosity > 4) verbosity = 4;
1937    if (opMode == OM_Z && smallMode && blockSize100k > 2) 
1938       blockSize100k = 2;
1939
1940    if (opMode == OM_TEST && srcMode == SM_F2O) {
1941       fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
1942                 progName );
1943       exit ( 1 );
1944    }
1945
1946    if (srcMode == SM_F2O && numFileNames == 0)
1947       srcMode = SM_I2O;
1948
1949    if (opMode != OM_Z) blockSize100k = 0;
1950
1951    if (srcMode == SM_F2F) {
1952       signal (SIGINT,  mySignalCatcher);
1953       signal (SIGTERM, mySignalCatcher);
1954 #     if BZ_UNIX
1955       signal (SIGHUP,  mySignalCatcher);
1956 #     endif
1957    }
1958
1959    if (opMode == OM_Z) {
1960      if (srcMode == SM_I2O) {
1961         compress ( NULL );
1962      } else {
1963         decode = True;
1964         for (aa = argList; aa != NULL; aa = aa->link) {
1965            if (ISFLAG("--")) { decode = False; continue; }
1966            if (aa->name[0] == '-' && decode) continue;
1967            numFilesProcessed++;
1968            compress ( aa->name );
1969         }
1970      }
1971    } 
1972    else
1973
1974    if (opMode == OM_UNZ) {
1975       unzFailsExist = False;
1976       if (srcMode == SM_I2O) {
1977          uncompress ( NULL );
1978       } else {
1979          decode = True;
1980          for (aa = argList; aa != NULL; aa = aa->link) {
1981             if (ISFLAG("--")) { decode = False; continue; }
1982             if (aa->name[0] == '-' && decode) continue;
1983             numFilesProcessed++;
1984             uncompress ( aa->name );
1985          }      
1986       }
1987       if (unzFailsExist) { 
1988          setExit(2); 
1989          exit(exitValue);
1990       }
1991    } 
1992
1993    else {
1994       testFailsExist = False;
1995       if (srcMode == SM_I2O) {
1996          testf ( NULL );
1997       } else {
1998          decode = True;
1999          for (aa = argList; aa != NULL; aa = aa->link) {
2000             if (ISFLAG("--")) { decode = False; continue; }
2001             if (aa->name[0] == '-' && decode) continue;
2002             numFilesProcessed++;
2003             testf ( aa->name );
2004          }
2005       }
2006       if (testFailsExist && noisy) {
2007          fprintf ( stderr,
2008            "\n"
2009            "You can use the `bzip2recover' program to attempt to recover\n"
2010            "data from undamaged sections of corrupted files.\n\n"
2011          );
2012          setExit(2);
2013          exit(exitValue);
2014       }
2015    }
2016
2017    /* Free the argument list memory to mollify leak detectors 
2018       (eg) Purify, Checker.  Serves no other useful purpose.
2019    */
2020    aa = argList;
2021    while (aa != NULL) {
2022       Cell* aa2 = aa->link;
2023       if (aa->name != NULL) free(aa->name);
2024       free(aa);
2025       aa = aa2;
2026    }
2027
2028    return exitValue;
2029 }
2030
2031
2032 /*-----------------------------------------------------------*/
2033 /*--- end                                         bzip2.c ---*/
2034 /*-----------------------------------------------------------*/