1
2/*-----------------------------------------------------------*/
3/*--- A block-sorting, lossless compressor        bzip2.c ---*/
4/*-----------------------------------------------------------*/
5
6/* ------------------------------------------------------------------
7   This file is part of bzip2/libbzip2, a program and library for
8   lossless, block-sorting data compression.
9
10   bzip2/libbzip2 version 1.0.6 of 6 September 2010
11   Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
12
13   Please read the WARNING, DISCLAIMER and PATENTS sections in the
14   README file.
15
16   This program is released under the terms of the license contained
17   in the file LICENSE.
18   ------------------------------------------------------------------ */
19
20
21/* Place a 1 beside your platform, and 0 elsewhere.
22   Generic 32-bit Unix.
23   Also works on 64-bit Unix boxes.
24   This is the default.
25*/
26#define BZ_UNIX      1
27
28/*--
29  Win32, as seen by Jacob Navia's excellent
30  port of (Chris Fraser & David Hanson)'s excellent
31  lcc compiler.  Or with MS Visual C.
32  This is selected automatically if compiled by a compiler which
33  defines _WIN32, not including the Cygwin GCC.
34--*/
35#define BZ_LCCWIN32  0
36
37#if defined(_WIN32) && !defined(__CYGWIN__)
38#undef  BZ_LCCWIN32
39#define BZ_LCCWIN32 1
40#undef  BZ_UNIX
41#define BZ_UNIX 0
42#endif
43
44
45/*---------------------------------------------*/
46/*--
47  Some stuff for all platforms.
48--*/
49
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <signal.h>
54#include <math.h>
55#include <errno.h>
56#include <ctype.h>
57#include "bzlib.h"
58
59#define ERROR_IF_EOF(i)       { if ((i) == EOF)  ioError(); }
60#define ERROR_IF_NOT_ZERO(i)  { if ((i) != 0)    ioError(); }
61#define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
62
63
64/*---------------------------------------------*/
65/*--
66   Platform-specific stuff.
67--*/
68
69#if BZ_UNIX
70#   include <fcntl.h>
71#   include <sys/types.h>
72#   include <utime.h>
73#   include <unistd.h>
74#   include <sys/stat.h>
75#   include <sys/times.h>
76
77#   define PATH_SEP    '/'
78#   define MY_LSTAT    lstat
79#   define MY_STAT     stat
80#   define MY_S_ISREG  S_ISREG
81#   define MY_S_ISDIR  S_ISDIR
82
83#   define APPEND_FILESPEC(root, name) \
84      root=snocString((root), (name))
85
86#   define APPEND_FLAG(root, name) \
87      root=snocString((root), (name))
88
89#   define SET_BINARY_MODE(fd) /**/
90
91#   ifdef __GNUC__
92#      define NORETURN __attribute__ ((noreturn))
93#   else
94#      define NORETURN /**/
95#   endif
96
97#   ifdef __DJGPP__
98#     include <io.h>
99#     include <fcntl.h>
100#     undef MY_LSTAT
101#     undef MY_STAT
102#     define MY_LSTAT stat
103#     define MY_STAT stat
104#     undef SET_BINARY_MODE
105#     define SET_BINARY_MODE(fd)                        \
106        do {                                            \
107           int retVal = setmode ( fileno ( fd ),        \
108                                  O_BINARY );           \
109           ERROR_IF_MINUS_ONE ( retVal );               \
110        } while ( 0 )
111#   endif
112
113#   ifdef __CYGWIN__
114#     include <io.h>
115#     include <fcntl.h>
116#     undef SET_BINARY_MODE
117#     define SET_BINARY_MODE(fd)                        \
118        do {                                            \
119           int retVal = setmode ( fileno ( fd ),        \
120                                  O_BINARY );           \
121           ERROR_IF_MINUS_ONE ( retVal );               \
122        } while ( 0 )
123#   endif
124#endif /* BZ_UNIX */
125
126
127
128#if BZ_LCCWIN32
129#   include <io.h>
130#   include <fcntl.h>
131#   include <sys\stat.h>
132
133#   define NORETURN       /**/
134#   define PATH_SEP       '\\'
135#   define MY_LSTAT       _stat
136#   define MY_STAT        _stat
137#   define MY_S_ISREG(x)  ((x) & _S_IFREG)
138#   define MY_S_ISDIR(x)  ((x) & _S_IFDIR)
139
140#   define APPEND_FLAG(root, name) \
141      root=snocString((root), (name))
142
143#   define APPEND_FILESPEC(root, name)                \
144      root = snocString ((root), (name))
145
146#   define SET_BINARY_MODE(fd)                        \
147      do {                                            \
148         int retVal = setmode ( fileno ( fd ),        \
149                                O_BINARY );           \
150         ERROR_IF_MINUS_ONE ( retVal );               \
151      } while ( 0 )
152
153#endif /* BZ_LCCWIN32 */
154
155
156/*---------------------------------------------*/
157/*--
158  Some more stuff for all platforms :-)
159--*/
160
161typedef char            Char;
162typedef unsigned char   Bool;
163typedef unsigned char   UChar;
164typedef int             Int32;
165typedef unsigned int    UInt32;
166typedef short           Int16;
167typedef 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--*/
176typedef int IntNative;
177
178
179/*---------------------------------------------------*/
180/*--- Misc (file handling) data decls             ---*/
181/*---------------------------------------------------*/
182
183Int32   verbosity;
184Bool    keepInputFiles, smallMode, deleteOutputOnInterrupt;
185Bool    forceOverwrite, testFailsExist, unzFailsExist, noisy;
186Int32   numFileNames, numFilesProcessed, blockSize100k;
187Int32   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
199Int32   opMode;
200Int32   srcMode;
201
202#define FILE_NAME_LEN 1034
203
204Int32   longestFileName;
205Char    inName [FILE_NAME_LEN];
206Char    outName[FILE_NAME_LEN];
207Char    tmpName[FILE_NAME_LEN];
208Char    *progName;
209Char    progNameReally[FILE_NAME_LEN];
210FILE    *outputHandleJustInCase;
211Int32   workFactor;
212
213static void    panic                 ( const Char* ) NORETURN;
214static void    ioError               ( void )        NORETURN;
215static void    outOfMemory           ( void )        NORETURN;
216static void    configError           ( void )        NORETURN;
217static void    crcError              ( void )        NORETURN;
218static void    cleanUpAndFail        ( Int32 )       NORETURN;
219static void    compressedStreamEOF   ( void )        NORETURN;
220
221static void    copyFileName ( Char*, Char* );
222static void*   myMalloc     ( Int32 );
223static 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
232typedef
233   struct { UChar b[8]; }
234   UInt64;
235
236
237static
238void 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
251static
252double 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
265static
266Bool 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.  */
276static
277Int32 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*/
294static
295void 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/*---------------------------------------------*/
317static
318Bool 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/*---------------------------------------------*/
328static
329void 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/*---------------------------------------------*/
432static
433Bool 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/*---------------------------------------------*/
553static
554Bool testStream ( FILE *zStream )
555{
556   BZFILE* bzf = NULL;
557   Int32   bzerr, bzerr_dummy, ret, nread, streamNo, i;
558   UChar   obuf[5000];
559   UChar   unused[BZ_MAX_UNUSED];
560   Int32   nUnused;
561   void*   unusedTmpV;
562   UChar*  unusedTmp;
563
564   nUnused = 0;
565   streamNo = 0;
566
567   SET_BINARY_MODE(zStream);
568   if (ferror(zStream)) goto errhandler_io;
569
570   while (True) {
571
572      bzf = BZ2_bzReadOpen (
573               &bzerr, zStream, verbosity,
574               (int)smallMode, unused, nUnused
575            );
576      if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
577      streamNo++;
578
579      while (bzerr == BZ_OK) {
580         nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
581         if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
582      }
583      if (bzerr != BZ_STREAM_END) goto errhandler;
584
585      BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
586      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
587
588      unusedTmp = (UChar*)unusedTmpV;
589      for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
590
591      BZ2_bzReadClose ( &bzerr, bzf );
592      if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
593      if (nUnused == 0 && myfeof(zStream)) break;
594
595   }
596
597   if (ferror(zStream)) goto errhandler_io;
598   ret = fclose ( zStream );
599   if (ret == EOF) goto errhandler_io;
600
601   if (verbosity >= 2) fprintf ( stderr, "\n    " );
602   return True;
603
604   errhandler:
605   BZ2_bzReadClose ( &bzerr_dummy, bzf );
606   if (verbosity == 0)
607      fprintf ( stderr, "%s: %s: ", progName, inName );
608   switch (bzerr) {
609      case BZ_CONFIG_ERROR:
610         configError(); break;
611      case BZ_IO_ERROR:
612         errhandler_io:
613         ioError(); break;
614      case BZ_DATA_ERROR:
615         fprintf ( stderr,
616                   "data integrity (CRC) error in data\n" );
617         return False;
618      case BZ_MEM_ERROR:
619         outOfMemory();
620      case BZ_UNEXPECTED_EOF:
621         fprintf ( stderr,
622                   "file ends unexpectedly\n" );
623         return False;
624      case BZ_DATA_ERROR_MAGIC:
625         if (zStream != stdin) fclose(zStream);
626         if (streamNo == 1) {
627          fprintf ( stderr,
628                    "bad magic number (file not created by bzip2)\n" );
629            return False;
630         } else {
631            if (noisy)
632            fprintf ( stderr,
633                      "trailing garbage after EOF ignored\n" );
634            return True;
635         }
636      default:
637         panic ( "test:unexpected error" );
638   }
639
640   panic ( "test:end" );
641   return True; /*notreached*/
642}
643
644
645/*---------------------------------------------------*/
646/*--- Error [non-] handling grunge                ---*/
647/*---------------------------------------------------*/
648
649/*---------------------------------------------*/
650static
651void setExit ( Int32 v )
652{
653   if (v > exitValue) exitValue = v;
654}
655
656
657/*---------------------------------------------*/
658static
659void 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/*---------------------------------------------*/
673static
674void 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/*---------------------------------------------*/
686static
687void 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/*---------------------------------------------*/
745static
746void panic ( const Char* s )
747{
748   fprintf ( stderr,
749             "\n%s: PANIC -- internal consistency error:\n"
750             "\t%s\n"
751             "\tThis is a BUG.  Please report it to me at:\n"
752             "\tjseward@bzip.org\n",
753             progName, s );
754   showFileNames();
755   cleanUpAndFail( 3 );
756}
757
758
759/*---------------------------------------------*/
760static
761void 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/*---------------------------------------------*/
773static
774void 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/*---------------------------------------------*/
790static
791void 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/*---------------------------------------------*/
804static
805void 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/*---------------------------------------------*/
815static
816void mySIGSEGVorSIGBUScatcher ( IntNative n )
817{
818   if (opMode == OM_Z)
819      fprintf (
820      stderr,
821      "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
822      "\n"
823      "   Possible causes are (most likely first):\n"
824      "   (1) This computer has unreliable memory or cache hardware\n"
825      "       (a surprisingly common problem; try a different machine.)\n"
826      "   (2) A bug in the compiler used to create this executable\n"
827      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
828      "   (3) A real bug in bzip2 -- I hope this should never be the case.\n"
829      "   The user's manual, Section 4.3, has more info on (1) and (2).\n"
830      "   \n"
831      "   If you suspect this is a bug in bzip2, or are unsure about (1)\n"
832      "   or (2), feel free to report it to me at: jseward@bzip.org.\n"
833      "   Section 4.3 of the user's manual describes the info a useful\n"
834      "   bug report should have.  If the manual is available on your\n"
835      "   system, please try and read it before mailing me.  If you don't\n"
836      "   have the manual or can't be bothered to read it, mail me anyway.\n"
837      "\n",
838      progName );
839      else
840      fprintf (
841      stderr,
842      "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
843      "\n"
844      "   Possible causes are (most likely first):\n"
845      "   (1) The compressed data is corrupted, and bzip2's usual checks\n"
846      "       failed to detect this.  Try bzip2 -tvv my_file.bz2.\n"
847      "   (2) This computer has unreliable memory or cache hardware\n"
848      "       (a surprisingly common problem; try a different machine.)\n"
849      "   (3) A bug in the compiler used to create this executable\n"
850      "       (unlikely, if you didn't compile bzip2 yourself.)\n"
851      "   (4) A real bug in bzip2 -- I hope this should never be the case.\n"
852      "   The user's manual, Section 4.3, has more info on (2) and (3).\n"
853      "   \n"
854      "   If you suspect this is a bug in bzip2, or are unsure about (2)\n"
855      "   or (3), feel free to report it to me at: jseward@bzip.org.\n"
856      "   Section 4.3 of the user's manual describes the info a useful\n"
857      "   bug report should have.  If the manual is available on your\n"
858      "   system, please try and read it before mailing me.  If you don't\n"
859      "   have the manual or can't be bothered to read it, mail me anyway.\n"
860      "\n",
861      progName );
862
863   showFileNames();
864   if (opMode == OM_Z)
865      cleanUpAndFail( 3 ); else
866      { cadvise(); cleanUpAndFail( 2 ); }
867}
868
869
870/*---------------------------------------------*/
871static
872void 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/*---------------------------------------------*/
883static
884void 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/*---------------------------------------------*/
907static
908void 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/*---------------------------------------------*/
918static
919void 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/*---------------------------------------------*/
939static
940Bool 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*/
959static
960FILE* 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--*/
980static
981Bool 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--*/
997static
998Int32 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
1033static
1034struct MY_STAT fileMetaInfo;
1035#endif
1036
1037static
1038void 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
1049static
1050void 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
1064static
1065void 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/*---------------------------------------------*/
1082static
1083Bool 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
1104const Char* zSuffix[BZ_N_SUFFIX_PAIRS]
1105   = { ".bz2", ".bz", ".tbz2", ".tbz" };
1106const Char* unzSuffix[BZ_N_SUFFIX_PAIRS]
1107   = { "", "", ".tar", ".tar" };
1108
1109static
1110Bool 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
1119static
1120Bool 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/*---------------------------------------------*/
1132static
1133void 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/*---------------------------------------------*/
1313static
1314void 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/*---------------------------------------------*/
1511static
1512void 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/*---------------------------------------------*/
1600static
1601void license ( void )
1602{
1603   fprintf ( stderr,
1604
1605    "bzip2, a block-sorting file compressor.  "
1606    "Version %s.\n"
1607    "   \n"
1608    "   Copyright (C) 1996-2010 by Julian Seward.\n"
1609    "   \n"
1610    "   This program is free software; you can redistribute it and/or modify\n"
1611    "   it under the terms set out in the LICENSE file, which is included\n"
1612    "   in the bzip2-1.0.6 source distribution.\n"
1613    "   \n"
1614    "   This program is distributed in the hope that it will be useful,\n"
1615    "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1616    "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
1617    "   LICENSE file for more details.\n"
1618    "   \n",
1619    BZ2_bzlibVersion()
1620   );
1621}
1622
1623
1624/*---------------------------------------------*/
1625static
1626void 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/*---------------------------------------------*/
1669static
1670void 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
1694typedef
1695   struct zzzz {
1696      Char        *name;
1697      struct zzzz *link;
1698   }
1699   Cell;
1700
1701
1702/*---------------------------------------------*/
1703static
1704void *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/*---------------------------------------------*/
1715static
1716Cell *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/*---------------------------------------------*/
1728static
1729Cell *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/*---------------------------------------------*/
1746static
1747void 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
1776IntNative main ( IntNative argc, Char *argv[] )
1777{
1778   Int32  i, j;
1779   Char   *tmp;
1780   Cell   *argList;
1781   Cell   *aa;
1782   Bool   decode;
1783
1784   /*-- Be really really really paranoid :-) --*/
1785   if (sizeof(Int32) != 4 || sizeof(UInt32) != 4  ||
1786       sizeof(Int16) != 2 || sizeof(UInt16) != 2  ||
1787       sizeof(Char)  != 1 || sizeof(UChar)  != 1)
1788      configError();
1789
1790   /*-- Initialise --*/
1791   outputHandleJustInCase  = NULL;
1792   smallMode               = False;
1793   keepInputFiles          = False;
1794   forceOverwrite          = False;
1795   noisy                   = True;
1796   verbosity               = 0;
1797   blockSize100k           = 9;
1798   testFailsExist          = False;
1799   unzFailsExist           = False;
1800   numFileNames            = 0;
1801   numFilesProcessed       = 0;
1802   workFactor              = 30;
1803   deleteOutputOnInterrupt = False;
1804   exitValue               = 0;
1805   i = j = 0; /* avoid bogus warning from egcs-1.1.X */
1806
1807   /*-- Set up signal handlers for mem access errors --*/
1808   signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
1809#  if BZ_UNIX
1810#  ifndef __DJGPP__
1811   signal (SIGBUS,  mySIGSEGVorSIGBUScatcher);
1812#  endif
1813#  endif
1814
1815   copyFileName ( inName,  (Char*)"(none)" );
1816   copyFileName ( outName, (Char*)"(none)" );
1817
1818   copyFileName ( progNameReally, argv[0] );
1819   progName = &progNameReally[0];
1820   for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
1821      if (*tmp == PATH_SEP) progName = tmp + 1;
1822
1823
1824   /*-- Copy flags from env var BZIP2, and
1825        expand filename wildcards in arg list.
1826   --*/
1827   argList = NULL;
1828   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP2" );
1829   addFlagsFromEnvVar ( &argList,  (Char*)"BZIP" );
1830   for (i = 1; i <= argc-1; i++)
1831      APPEND_FILESPEC(argList, argv[i]);
1832
1833
1834   /*-- Find the length of the longest filename --*/
1835   longestFileName = 7;
1836   numFileNames    = 0;
1837   decode          = True;
1838   for (aa = argList; aa != NULL; aa = aa->link) {
1839      if (ISFLAG("--")) { decode = False; continue; }
1840      if (aa->name[0] == '-' && decode) continue;
1841      numFileNames++;
1842      if (longestFileName < (Int32)strlen(aa->name) )
1843         longestFileName = (Int32)strlen(aa->name);
1844   }
1845
1846
1847   /*-- Determine source modes; flag handling may change this too. --*/
1848   if (numFileNames == 0)
1849      srcMode = SM_I2O; else srcMode = SM_F2F;
1850
1851
1852   /*-- Determine what to do (compress/uncompress/test/cat). --*/
1853   /*-- Note that subsequent flag handling may change this. --*/
1854   opMode = OM_Z;
1855
1856   if ( (strstr ( progName, "unzip" ) != 0) ||
1857        (strstr ( progName, "UNZIP" ) != 0) )
1858      opMode = OM_UNZ;
1859
1860   if ( (strstr ( progName, "z2cat" ) != 0) ||
1861        (strstr ( progName, "Z2CAT" ) != 0) ||
1862        (strstr ( progName, "zcat" ) != 0)  ||
1863        (strstr ( progName, "ZCAT" ) != 0) )  {
1864      opMode = OM_UNZ;
1865      srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
1866   }
1867
1868
1869   /*-- Look at the flags. --*/
1870   for (aa = argList; aa != NULL; aa = aa->link) {
1871      if (ISFLAG("--")) break;
1872      if (aa->name[0] == '-' && aa->name[1] != '-') {
1873         for (j = 1; aa->name[j] != '\0'; j++) {
1874            switch (aa->name[j]) {
1875               case 'c': srcMode          = SM_F2O; break;
1876               case 'd': opMode           = OM_UNZ; break;
1877               case 'z': opMode           = OM_Z; break;
1878               case 'f': forceOverwrite   = True; break;
1879               case 't': opMode           = OM_TEST; break;
1880               case 'k': keepInputFiles   = True; break;
1881               case 's': smallMode        = True; break;
1882               case 'q': noisy            = False; break;
1883               case '1': blockSize100k    = 1; break;
1884               case '2': blockSize100k    = 2; break;
1885               case '3': blockSize100k    = 3; break;
1886               case '4': blockSize100k    = 4; break;
1887               case '5': blockSize100k    = 5; break;
1888               case '6': blockSize100k    = 6; break;
1889               case '7': blockSize100k    = 7; break;
1890               case '8': blockSize100k    = 8; break;
1891               case '9': blockSize100k    = 9; break;
1892               case 'V':
1893               case 'L': license();            break;
1894               case 'v': verbosity++; break;
1895               case 'h': usage ( progName );
1896                         exit ( 0 );
1897                         break;
1898               default:  fprintf ( stderr, "%s: Bad flag `%s'\n",
1899                                   progName, aa->name );
1900                         usage ( progName );
1901                         exit ( 1 );
1902                         break;
1903            }
1904         }
1905      }
1906   }
1907
1908   /*-- And again ... --*/
1909   for (aa = argList; aa != NULL; aa = aa->link) {
1910      if (ISFLAG("--")) break;
1911      if (ISFLAG("--stdout"))            srcMode          = SM_F2O;  else
1912      if (ISFLAG("--decompress"))        opMode           = OM_UNZ;  else
1913      if (ISFLAG("--compress"))          opMode           = OM_Z;    else
1914      if (ISFLAG("--force"))             forceOverwrite   = True;    else
1915      if (ISFLAG("--test"))              opMode           = OM_TEST; else
1916      if (ISFLAG("--keep"))              keepInputFiles   = True;    else
1917      if (ISFLAG("--small"))             smallMode        = True;    else
1918      if (ISFLAG("--quiet"))             noisy            = False;   else
1919      if (ISFLAG("--version"))           license();                  else
1920      if (ISFLAG("--license"))           license();                  else
1921      if (ISFLAG("--exponential"))       workFactor = 1;             else
1922      if (ISFLAG("--repetitive-best"))   redundant(aa->name);        else
1923      if (ISFLAG("--repetitive-fast"))   redundant(aa->name);        else
1924      if (ISFLAG("--fast"))              blockSize100k = 1;          else
1925      if (ISFLAG("--best"))              blockSize100k = 9;          else
1926      if (ISFLAG("--verbose"))           verbosity++;                else
1927      if (ISFLAG("--help"))              { usage ( progName ); exit ( 0 ); }
1928         else
1929         if (strncmp ( aa->name, "--", 2) == 0) {
1930            fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
1931            usage ( progName );
1932            exit ( 1 );
1933         }
1934   }
1935
1936   if (verbosity > 4) verbosity = 4;
1937   if (opMode == OM_Z && smallMode && blockSize100k > 2)
1938      blockSize100k = 2;
1939
1940   if (opMode == OM_TEST && srcMode == SM_F2O) {
1941      fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
1942                progName );
1943      exit ( 1 );
1944   }
1945
1946   if (srcMode == SM_F2O && numFileNames == 0)
1947      srcMode = SM_I2O;
1948
1949   if (opMode != OM_Z) blockSize100k = 0;
1950
1951   if (srcMode == SM_F2F) {
1952      signal (SIGINT,  mySignalCatcher);
1953      signal (SIGTERM, mySignalCatcher);
1954#     if BZ_UNIX
1955      signal (SIGHUP,  mySignalCatcher);
1956#     endif
1957   }
1958
1959   if (opMode == OM_Z) {
1960     if (srcMode == SM_I2O) {
1961        compress ( NULL );
1962     } else {
1963        decode = True;
1964        for (aa = argList; aa != NULL; aa = aa->link) {
1965           if (ISFLAG("--")) { decode = False; continue; }
1966           if (aa->name[0] == '-' && decode) continue;
1967           numFilesProcessed++;
1968           compress ( aa->name );
1969        }
1970     }
1971   }
1972   else
1973
1974   if (opMode == OM_UNZ) {
1975      unzFailsExist = False;
1976      if (srcMode == SM_I2O) {
1977         uncompress ( NULL );
1978      } else {
1979         decode = True;
1980         for (aa = argList; aa != NULL; aa = aa->link) {
1981            if (ISFLAG("--")) { decode = False; continue; }
1982            if (aa->name[0] == '-' && decode) continue;
1983            numFilesProcessed++;
1984            uncompress ( aa->name );
1985         }
1986      }
1987      if (unzFailsExist) {
1988         setExit(2);
1989         exit(exitValue);
1990      }
1991   }
1992
1993   else {
1994      testFailsExist = False;
1995      if (srcMode == SM_I2O) {
1996         testf ( NULL );
1997      } else {
1998         decode = True;
1999         for (aa = argList; aa != NULL; aa = aa->link) {
2000	    if (ISFLAG("--")) { decode = False; continue; }
2001            if (aa->name[0] == '-' && decode) continue;
2002            numFilesProcessed++;
2003            testf ( aa->name );
2004	 }
2005      }
2006      if (testFailsExist && noisy) {
2007         fprintf ( stderr,
2008           "\n"
2009           "You can use the `bzip2recover' program to attempt to recover\n"
2010           "data from undamaged sections of corrupted files.\n\n"
2011         );
2012         setExit(2);
2013         exit(exitValue);
2014      }
2015   }
2016
2017   /* Free the argument list memory to mollify leak detectors
2018      (eg) Purify, Checker.  Serves no other useful purpose.
2019   */
2020   aa = argList;
2021   while (aa != NULL) {
2022      Cell* aa2 = aa->link;
2023      if (aa->name != NULL) free(aa->name);
2024      free(aa);
2025      aa = aa2;
2026   }
2027
2028   return exitValue;
2029}
2030
2031
2032/*-----------------------------------------------------------*/
2033/*--- end                                         bzip2.c ---*/
2034/*-----------------------------------------------------------*/
2035