source: trunk/third/bzip2/bzip2.c @ 17062

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