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