xref: /dragonfly/contrib/bzip2/bzip2.c (revision 86954436)
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.8 of 13 July 2019
11    Copyright (C) 1996-2019 Julian Seward <jseward@acm.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       _stati64
136 #   define MY_STAT        _stati64
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
uInt64_from_UInt32s(UInt64 * n,UInt32 lo32,UInt32 hi32)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
uInt64_to_double(UInt64 * n)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
uInt64_isZero(UInt64 * n)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
uInt64_qrm10(UInt64 * n)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
uInt64_toAscii(char * outbuf,UInt64 * n)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
myfeof(FILE * f)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
compressStream(FILE * stream,FILE * zStream)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
uncompressStream(FILE * zStream,FILE * stream)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
testStream(FILE * zStream)554 Bool testStream ( FILE *zStream )
555 {
556    BZFILE* bzf = NULL;
557    Int32   bzerr, bzerr_dummy, ret, 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          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
setExit(Int32 v)651 void setExit ( Int32 v )
652 {
653    if (v > exitValue) exitValue = v;
654 }
655 
656 
657 /*---------------------------------------------*/
658 static
cadvise(void)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
showFileNames(void)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
cleanUpAndFail(Int32 ec)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
panic(const Char * s)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:\n"
752              "\tbzip2-devel@sourceware.org\n",
753              progName, s );
754    showFileNames();
755    cleanUpAndFail( 3 );
756 }
757 
758 
759 /*---------------------------------------------*/
760 static
crcError(void)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
compressedStreamEOF(void)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
ioError(void)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
mySignalCatcher(IntNative n)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
mySIGSEGVorSIGBUScatcher(IntNative n)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: bzip2-devel@sourceware.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: bzip2-devel@sourceware.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
outOfMemory(void)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
configError(void)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
pad(Char * s)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
copyFileName(Char * to,Char * from)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
fileExists(Char * name)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
fopen_output_safely(Char * name,const char * mode)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
notAStandardFile(Char * name)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
countHardLinks(Char * name)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
saveInputFileMetaInfo(Char * srcName)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
applySavedTimeInfoToOutputFile(Char * dstName)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
applySavedFileAttrToOutputFile(IntNative fd)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
containsDubiousChars(Char * name)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
hasSuffix(Char * s,const Char * suffix)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
mapSuffix(Char * name,const Char * oldSuffix,const Char * newSuffix)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
compress(Char * name)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
uncompress(Char * name)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
testf(Char * name)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
license(void)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-2019 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 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
usage(Char * fullProgName)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
redundant(Char * flag)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
myMalloc(Int32 n)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
mkCell(void)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
snocString(Cell * root,Char * name)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
addFlagsFromEnvVar(Cell ** argList,Char * varName)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 
main(IntNative argc,Char * argv[])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) {
2007 	 if (noisy) {
2008             fprintf ( stderr,
2009                "\n"
2010                "You can use the `bzip2recover' program to attempt to recover\n"
2011                "data from undamaged sections of corrupted files.\n\n"
2012             );
2013 	 }
2014          setExit(2);
2015          exit(exitValue);
2016       }
2017    }
2018 
2019    /* Free the argument list memory to mollify leak detectors
2020       (eg) Purify, Checker.  Serves no other useful purpose.
2021    */
2022    aa = argList;
2023    while (aa != NULL) {
2024       Cell* aa2 = aa->link;
2025       if (aa->name != NULL) free(aa->name);
2026       free(aa);
2027       aa = aa2;
2028    }
2029 
2030    return exitValue;
2031 }
2032 
2033 
2034 /*-----------------------------------------------------------*/
2035 /*--- end                                         bzip2.c ---*/
2036 /*-----------------------------------------------------------*/
2037