VM: full munmap
[minix.git] / dist / bzip2 / bzip2.c
blob23ab3db4ae0b648d72d27e73fd530a04f3cd4b6b
1 /* $NetBSD: bzip2.c,v 1.8 2009/04/11 11:10:43 lukem Exp $ */
4 /*-----------------------------------------------------------*/
5 /*--- A block-sorting, lossless compressor bzip2.c ---*/
6 /*-----------------------------------------------------------*/
8 /* ------------------------------------------------------------------
9 This file is part of bzip2/libbzip2, a program and library for
10 lossless, block-sorting data compression.
12 bzip2/libbzip2 version 1.0.5 of 10 December 2007
13 Copyright (C) 1996-2007 Julian Seward <jseward@bzip.org>
15 Please read the WARNING, DISCLAIMER and PATENTS sections in the
16 README file.
18 This program is released under the terms of the license contained
19 in the file LICENSE.
20 ------------------------------------------------------------------ */
23 /* Place a 1 beside your platform, and 0 elsewhere.
24 Generic 32-bit Unix.
25 Also works on 64-bit Unix boxes.
26 This is the default.
28 #define BZ_UNIX 1
30 /*--
31 Win32, as seen by Jacob Navia's excellent
32 port of (Chris Fraser & David Hanson)'s excellent
33 lcc compiler. Or with MS Visual C.
34 This is selected automatically if compiled by a compiler which
35 defines _WIN32, not including the Cygwin GCC.
36 --*/
37 #define BZ_LCCWIN32 0
39 #if defined(_WIN32) && !defined(__CYGWIN__)
40 #undef BZ_LCCWIN32
41 #define BZ_LCCWIN32 1
42 #undef BZ_UNIX
43 #define BZ_UNIX 0
44 #endif
47 /*---------------------------------------------*/
48 /*--
49 Some stuff for all platforms.
50 --*/
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <signal.h>
56 #include <math.h>
57 #include <errno.h>
58 #include <ctype.h>
59 #include "bzlib.h"
61 #define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); }
62 #define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); }
63 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
66 /*---------------------------------------------*/
67 /*--
68 Platform-specific stuff.
69 --*/
71 #if BZ_UNIX
72 # include <fcntl.h>
73 # include <sys/types.h>
74 # include <utime.h>
75 # include <unistd.h>
76 # include <sys/stat.h>
77 # include <sys/times.h>
79 # define PATH_SEP '/'
80 # define MY_LSTAT lstat
81 # define MY_STAT stat
82 # define MY_S_ISREG S_ISREG
83 # define MY_S_ISDIR S_ISDIR
85 # define APPEND_FILESPEC(root, name) \
86 root=snocString((root), (name))
88 # define APPEND_FLAG(root, name) \
89 root=snocString((root), (name))
91 # define SET_BINARY_MODE(fd) /**/
93 # ifdef __GNUC__
94 # define NORETURN __attribute__ ((noreturn))
95 # else
96 # define NORETURN /**/
97 # endif
99 # ifdef __DJGPP__
100 # include <io.h>
101 # include <fcntl.h>
102 # undef MY_LSTAT
103 # undef MY_STAT
104 # define MY_LSTAT stat
105 # define MY_STAT stat
106 # undef SET_BINARY_MODE
107 # define SET_BINARY_MODE(fd) \
108 do { \
109 int retVal = setmode ( fileno ( fd ), \
110 O_BINARY ); \
111 ERROR_IF_MINUS_ONE ( retVal ); \
112 } while ( 0 )
113 # endif
115 # ifdef __CYGWIN__
116 # include <io.h>
117 # include <fcntl.h>
118 # undef SET_BINARY_MODE
119 # define SET_BINARY_MODE(fd) \
120 do { \
121 int retVal = setmode ( fileno ( fd ), \
122 O_BINARY ); \
123 ERROR_IF_MINUS_ONE ( retVal ); \
124 } while ( 0 )
125 # endif
126 #endif /* BZ_UNIX */
130 #if BZ_LCCWIN32
131 # include <io.h>
132 # include <fcntl.h>
133 # include <sys\stat.h>
135 # define NORETURN /**/
136 # define PATH_SEP '\\'
137 # define MY_LSTAT _stat
138 # define MY_STAT _stat
139 # define MY_S_ISREG(x) ((x) & _S_IFREG)
140 # define MY_S_ISDIR(x) ((x) & _S_IFDIR)
142 # define APPEND_FLAG(root, name) \
143 root=snocString((root), (name))
145 # define APPEND_FILESPEC(root, name) \
146 root = snocString ((root), (name))
148 # define SET_BINARY_MODE(fd) \
149 do { \
150 int retVal = setmode ( fileno ( fd ), \
151 O_BINARY ); \
152 ERROR_IF_MINUS_ONE ( retVal ); \
153 } while ( 0 )
155 #endif /* BZ_LCCWIN32 */
158 /*---------------------------------------------*/
159 /*--
160 Some more stuff for all platforms :-)
161 --*/
163 typedef char Char;
164 typedef unsigned char Bool;
165 typedef unsigned char UChar;
166 typedef int Int32;
167 typedef unsigned int UInt32;
168 typedef short Int16;
169 typedef unsigned short UInt16;
171 #define True ((Bool)1)
172 #define False ((Bool)0)
174 /*--
175 IntNative is your platform's `native' int size.
176 Only here to avoid probs with 64-bit platforms.
177 --*/
178 typedef int IntNative;
181 /*---------------------------------------------------*/
182 /*--- Misc (file handling) data decls ---*/
183 /*---------------------------------------------------*/
185 Int32 verbosity;
186 Bool keepInputFiles, smallMode, deleteOutputOnInterrupt;
187 Bool forceOverwrite, testFailsExist, unzFailsExist, noisy;
188 Int32 numFileNames, numFilesProcessed, blockSize100k;
189 Int32 exitValue;
191 /*-- source modes; F==file, I==stdin, O==stdout --*/
192 #define SM_I2O 1
193 #define SM_F2O 2
194 #define SM_F2F 3
196 /*-- operation modes --*/
197 #define OM_Z 1
198 #define OM_UNZ 2
199 #define OM_TEST 3
201 Int32 opMode;
202 Int32 srcMode;
204 #define FILE_NAME_LEN 1034
206 Int32 longestFileName;
207 Char inName [FILE_NAME_LEN];
208 Char outName[FILE_NAME_LEN];
209 Char tmpName[FILE_NAME_LEN];
210 Char *progName;
211 Char progNameReally[FILE_NAME_LEN];
212 FILE *outputHandleJustInCase;
213 Int32 workFactor;
215 static void panic ( const Char* ) NORETURN;
216 static void ioError ( void ) NORETURN;
217 static void outOfMemory ( void ) NORETURN;
218 static void configError ( void ) NORETURN;
219 static void crcError ( void ) NORETURN;
220 static void cleanUpAndFail ( Int32 ) NORETURN;
221 static void compressedStreamEOF ( void ) NORETURN;
223 static void copyFileName ( Char*, const Char* );
224 static void* myMalloc ( Int32 );
225 static void applySavedFileAttrToOutputFile ( IntNative fd );
228 static FILE* fopen_output_safely ( Char*, const char* );
230 /*---------------------------------------------------*/
231 /*--- An implementation of 64-bit ints. Sigh. ---*/
232 /*--- Roll on widespread deployment of ANSI C9X ! ---*/
233 /*---------------------------------------------------*/
235 typedef
236 struct { UChar b[8]; }
237 UInt64;
240 static
241 void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
243 n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
244 n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
245 n->b[5] = (UChar)((hi32 >> 8) & 0xFF);
246 n->b[4] = (UChar) (hi32 & 0xFF);
247 n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
248 n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
249 n->b[1] = (UChar)((lo32 >> 8) & 0xFF);
250 n->b[0] = (UChar) (lo32 & 0xFF);
254 static
255 double uInt64_to_double ( UInt64* n )
257 Int32 i;
258 double base = 1.0;
259 double sum = 0.0;
260 for (i = 0; i < 8; i++) {
261 sum += base * (double)(n->b[i]);
262 base *= 256.0;
264 return sum;
268 static
269 Bool uInt64_isZero ( UInt64* n )
271 Int32 i;
272 for (i = 0; i < 8; i++)
273 if (n->b[i] != 0) return 0;
274 return 1;
278 /* Divide *n by 10, and return the remainder. */
279 static
280 Int32 uInt64_qrm10 ( UInt64* n )
282 UInt32 rem, tmp;
283 Int32 i;
284 rem = 0;
285 for (i = 7; i >= 0; i--) {
286 tmp = rem * 256 + n->b[i];
287 n->b[i] = tmp / 10;
288 rem = tmp % 10;
290 return rem;
294 /* ... and the Whole Entire Point of all this UInt64 stuff is
295 so that we can supply the following function.
297 static
298 void uInt64_toAscii ( char* outbuf, UInt64* n )
300 Int32 i, q;
301 UChar buf[32];
302 Int32 nBuf = 0;
303 UInt64 n_copy = *n;
304 do {
305 q = uInt64_qrm10 ( &n_copy );
306 buf[nBuf] = q + '0';
307 nBuf++;
308 } while (!uInt64_isZero(&n_copy));
309 outbuf[nBuf] = 0;
310 for (i = 0; i < nBuf; i++)
311 outbuf[i] = buf[nBuf-i-1];
315 /*---------------------------------------------------*/
316 /*--- Processing of complete files and streams ---*/
317 /*---------------------------------------------------*/
319 /*---------------------------------------------*/
320 static
321 Bool myfeof ( FILE* f )
323 Int32 c = fgetc ( f );
324 if (c == EOF) return True;
325 ungetc ( c, f );
326 return False;
330 /*---------------------------------------------*/
331 static
332 void compressStream ( FILE *stream, FILE *zStream )
334 BZFILE* bzf = NULL;
335 UChar ibuf[5000];
336 Int32 nIbuf;
337 UInt32 nbytes_in_lo32, nbytes_in_hi32;
338 UInt32 nbytes_out_lo32, nbytes_out_hi32;
339 Int32 bzerr, bzerr_dummy, ret;
341 SET_BINARY_MODE(stream);
342 SET_BINARY_MODE(zStream);
344 if (ferror(stream)) goto errhandler_io;
345 if (ferror(zStream)) goto errhandler_io;
347 bzf = BZ2_bzWriteOpen ( &bzerr, zStream,
348 blockSize100k, verbosity, workFactor );
349 if (bzerr != BZ_OK) goto errhandler;
351 if (verbosity >= 2) fprintf ( stderr, "\n" );
353 while (True) {
355 if (myfeof(stream)) break;
356 nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
357 if (ferror(stream)) goto errhandler_io;
358 if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
359 if (bzerr != BZ_OK) goto errhandler;
363 BZ2_bzWriteClose64 ( &bzerr, bzf, 0,
364 &nbytes_in_lo32, &nbytes_in_hi32,
365 &nbytes_out_lo32, &nbytes_out_hi32 );
366 if (bzerr != BZ_OK) goto errhandler;
368 if (ferror(zStream)) goto errhandler_io;
369 ret = fflush ( zStream );
370 if (ret == EOF) goto errhandler_io;
371 if (zStream != stdout) {
372 Int32 fd = fileno ( zStream );
373 if (fd < 0) goto errhandler_io;
374 applySavedFileAttrToOutputFile ( fd );
375 ret = fclose ( zStream );
376 outputHandleJustInCase = NULL;
377 if (ret == EOF) goto errhandler_io;
379 outputHandleJustInCase = NULL;
380 if (ferror(stream)) goto errhandler_io;
381 ret = fclose ( stream );
382 if (ret == EOF) goto errhandler_io;
384 if (verbosity >= 1) {
385 if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
386 fprintf ( stderr, " no data compressed.\n");
387 } else {
388 Char buf_nin[32], buf_nout[32];
389 UInt64 nbytes_in, nbytes_out;
390 double nbytes_in_d, nbytes_out_d;
391 uInt64_from_UInt32s ( &nbytes_in,
392 nbytes_in_lo32, nbytes_in_hi32 );
393 uInt64_from_UInt32s ( &nbytes_out,
394 nbytes_out_lo32, nbytes_out_hi32 );
395 nbytes_in_d = uInt64_to_double ( &nbytes_in );
396 nbytes_out_d = uInt64_to_double ( &nbytes_out );
397 uInt64_toAscii ( buf_nin, &nbytes_in );
398 uInt64_toAscii ( buf_nout, &nbytes_out );
399 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
400 "%5.2f%% saved, %s in, %s out.\n",
401 nbytes_in_d / nbytes_out_d,
402 (8.0 * nbytes_out_d) / nbytes_in_d,
403 100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
404 buf_nin,
405 buf_nout
410 return;
412 errhandler:
413 BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1,
414 &nbytes_in_lo32, &nbytes_in_hi32,
415 &nbytes_out_lo32, &nbytes_out_hi32 );
416 switch (bzerr) {
417 case BZ_CONFIG_ERROR:
418 configError(); break;
419 case BZ_MEM_ERROR:
420 outOfMemory (); break;
421 case BZ_IO_ERROR:
422 errhandler_io:
423 ioError(); break;
424 default:
425 panic ( "compress:unexpected error" );
428 panic ( "compress:end" );
429 /*notreached*/
434 /*---------------------------------------------*/
435 static
436 Bool uncompressStream ( FILE *zStream, FILE *stream )
438 BZFILE* bzf = NULL;
439 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i;
440 UChar obuf[5000];
441 UChar unused[BZ_MAX_UNUSED];
442 Int32 nUnused;
443 void* unusedTmpV = NULL;
444 UChar* unusedTmp;
446 nUnused = 0;
447 streamNo = 0;
449 SET_BINARY_MODE(stream);
450 SET_BINARY_MODE(zStream);
452 if (ferror(stream)) goto errhandler_io;
453 if (ferror(zStream)) goto errhandler_io;
455 while (True) {
457 bzf = BZ2_bzReadOpen (
458 &bzerr, zStream, verbosity,
459 (int)smallMode, unused, nUnused
461 if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
462 streamNo++;
464 while (bzerr == BZ_OK) {
465 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
466 if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
467 if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
468 fwrite ( obuf, sizeof(UChar), nread, stream );
469 if (ferror(stream)) goto errhandler_io;
471 if (bzerr != BZ_STREAM_END) goto errhandler;
473 BZ2_bzReadGetUnused ( &bzerr, bzf, (void*)(&unusedTmpV), &nUnused );
474 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
476 unusedTmp = (UChar*)unusedTmpV;
477 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
479 BZ2_bzReadClose ( &bzerr, bzf );
480 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
482 if (nUnused == 0 && myfeof(zStream)) break;
485 closeok:
486 if (ferror(zStream)) goto errhandler_io;
487 if (stream != stdout) {
488 Int32 fd = fileno ( stream );
489 if (fd < 0) goto errhandler_io;
490 applySavedFileAttrToOutputFile ( fd );
492 ret = fclose ( zStream );
493 if (ret == EOF) goto errhandler_io;
495 if (ferror(stream)) goto errhandler_io;
496 ret = fflush ( stream );
497 if (ret != 0) goto errhandler_io;
498 if (stream != stdout) {
499 ret = fclose ( stream );
500 outputHandleJustInCase = NULL;
501 if (ret == EOF) goto errhandler_io;
503 outputHandleJustInCase = NULL;
504 if (verbosity >= 2) fprintf ( stderr, "\n " );
505 return True;
507 trycat:
508 if (forceOverwrite) {
509 rewind(zStream);
510 while (True) {
511 if (myfeof(zStream)) break;
512 nread = fread ( obuf, sizeof(UChar), 5000, zStream );
513 if (ferror(zStream)) goto errhandler_io;
514 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
515 if (ferror(stream)) goto errhandler_io;
517 goto closeok;
520 errhandler:
521 BZ2_bzReadClose ( &bzerr_dummy, bzf );
522 switch (bzerr) {
523 case BZ_CONFIG_ERROR:
524 configError(); break;
525 case BZ_IO_ERROR:
526 errhandler_io:
527 ioError(); break;
528 case BZ_DATA_ERROR:
529 crcError();
530 case BZ_MEM_ERROR:
531 outOfMemory();
532 case BZ_UNEXPECTED_EOF:
533 compressedStreamEOF();
534 case BZ_DATA_ERROR_MAGIC:
535 if (zStream != stdin) fclose(zStream);
536 if (stream != stdout) fclose(stream);
537 if (streamNo == 1) {
538 return False;
539 } else {
540 if (noisy)
541 fprintf ( stderr,
542 "\n%s: %s: trailing garbage after EOF ignored\n",
543 progName, inName );
544 return True;
546 default:
547 panic ( "decompress:unexpected error" );
550 panic ( "decompress:end" );
551 return True; /*notreached*/
555 /*---------------------------------------------*/
556 static
557 Bool testStream ( FILE *zStream )
559 BZFILE* bzf = NULL;
560 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i;
561 UChar obuf[5000];
562 UChar unused[BZ_MAX_UNUSED];
563 Int32 nUnused;
564 void* unusedTmpV = NULL;
565 UChar* unusedTmp = NULL;
567 nUnused = 0;
568 streamNo = 0;
570 SET_BINARY_MODE(zStream);
571 if (ferror(zStream)) goto errhandler_io;
573 while (True) {
575 bzf = BZ2_bzReadOpen (
576 &bzerr, zStream, verbosity,
577 (int)smallMode, unused, nUnused
579 if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
580 streamNo++;
582 while (bzerr == BZ_OK) {
583 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
584 if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
586 if (bzerr != BZ_STREAM_END) goto errhandler;
588 BZ2_bzReadGetUnused ( &bzerr, bzf, (void*)(&unusedTmpV), &nUnused );
589 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
591 unusedTmp = (UChar*)unusedTmpV;
592 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
594 BZ2_bzReadClose ( &bzerr, bzf );
595 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
596 if (nUnused == 0 && myfeof(zStream)) break;
600 if (ferror(zStream)) goto errhandler_io;
601 ret = fclose ( zStream );
602 if (ret == EOF) goto errhandler_io;
604 if (verbosity >= 2) fprintf ( stderr, "\n " );
605 return True;
607 errhandler:
608 BZ2_bzReadClose ( &bzerr_dummy, bzf );
609 if (verbosity == 0)
610 fprintf ( stderr, "%s: %s: ", progName, inName );
611 switch (bzerr) {
612 case BZ_CONFIG_ERROR:
613 configError(); break;
614 case BZ_IO_ERROR:
615 errhandler_io:
616 ioError(); break;
617 case BZ_DATA_ERROR:
618 fprintf ( stderr,
619 "data integrity (CRC) error in data\n" );
620 return False;
621 case BZ_MEM_ERROR:
622 outOfMemory();
623 case BZ_UNEXPECTED_EOF:
624 fprintf ( stderr,
625 "file ends unexpectedly\n" );
626 return False;
627 case BZ_DATA_ERROR_MAGIC:
628 if (zStream != stdin) fclose(zStream);
629 if (streamNo == 1) {
630 fprintf ( stderr,
631 "bad magic number (file not created by bzip2)\n" );
632 return False;
633 } else {
634 if (noisy)
635 fprintf ( stderr,
636 "trailing garbage after EOF ignored\n" );
637 return True;
639 default:
640 panic ( "test:unexpected error" );
643 panic ( "test:end" );
644 return True; /*notreached*/
648 /*---------------------------------------------------*/
649 /*--- Error [non-] handling grunge ---*/
650 /*---------------------------------------------------*/
652 /*---------------------------------------------*/
653 static
654 void setExit ( Int32 v )
656 if (v > exitValue) exitValue = v;
660 /*---------------------------------------------*/
661 static
662 void cadvise ( void )
664 if (noisy)
665 fprintf (
666 stderr,
667 "\nIt is possible that the compressed file(s) have become corrupted.\n"
668 "You can use the -tvv option to test integrity of such files.\n\n"
669 "You can use the `bzip2recover' program to attempt to recover\n"
670 "data from undamaged sections of corrupted files.\n\n"
675 /*---------------------------------------------*/
676 static
677 void showFileNames ( void )
679 if (noisy)
680 fprintf (
681 stderr,
682 "\tInput file = %s, output file = %s\n",
683 inName, outName
688 /*---------------------------------------------*/
689 static
690 void cleanUpAndFail ( Int32 ec )
692 IntNative retVal;
693 struct MY_STAT statBuf;
695 if ( srcMode == SM_F2F
696 && opMode != OM_TEST
697 && deleteOutputOnInterrupt ) {
699 /* Check whether input file still exists. Delete output file
700 only if input exists to avoid loss of data. Joerg Prante, 5
701 January 2002. (JRS 06-Jan-2002: other changes in 1.0.2 mean
702 this is less likely to happen. But to be ultra-paranoid, we
703 do the check anyway.) */
704 retVal = MY_STAT ( inName, &statBuf );
705 if (retVal == 0) {
706 if (noisy)
707 fprintf ( stderr,
708 "%s: Deleting output file %s, if it exists.\n",
709 progName, outName );
710 if (outputHandleJustInCase != NULL)
711 fclose ( outputHandleJustInCase );
712 retVal = remove ( outName );
713 if (retVal != 0)
714 fprintf ( stderr,
715 "%s: WARNING: deletion of output file "
716 "(apparently) failed.\n",
717 progName );
718 } else {
719 fprintf ( stderr,
720 "%s: WARNING: deletion of output file suppressed\n",
721 progName );
722 fprintf ( stderr,
723 "%s: since input file no longer exists. Output file\n",
724 progName );
725 fprintf ( stderr,
726 "%s: `%s' may be incomplete.\n",
727 progName, outName );
728 fprintf ( stderr,
729 "%s: I suggest doing an integrity test (bzip2 -tv)"
730 " of it.\n",
731 progName );
735 if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
736 fprintf ( stderr,
737 "%s: WARNING: some files have not been processed:\n"
738 "%s: %d specified on command line, %d not processed yet.\n\n",
739 progName, progName,
740 numFileNames, numFileNames - numFilesProcessed );
742 setExit(ec);
743 exit(exitValue);
747 /*---------------------------------------------*/
748 static
749 void panic ( const Char* s )
751 fprintf ( stderr,
752 "\n%s: PANIC -- internal consistency error:\n"
753 "\t%s\n"
754 "\tThis is a BUG. Please report it to me at:\n"
755 "\tjseward@bzip.org\n",
756 progName, s );
757 showFileNames();
758 cleanUpAndFail( 3 );
762 /*---------------------------------------------*/
763 static
764 void crcError ( void )
766 fprintf ( stderr,
767 "\n%s: Data integrity error when decompressing.\n",
768 progName );
769 showFileNames();
770 cadvise();
771 cleanUpAndFail( 2 );
775 /*---------------------------------------------*/
776 static
777 void compressedStreamEOF ( void )
779 if (noisy) {
780 fprintf ( stderr,
781 "\n%s: Compressed file ends unexpectedly;\n\t"
782 "perhaps it is corrupted? *Possible* reason follows.\n",
783 progName );
784 perror ( progName );
785 showFileNames();
786 cadvise();
788 cleanUpAndFail( 2 );
792 /*---------------------------------------------*/
793 static
794 void ioError ( void )
796 fprintf ( stderr,
797 "\n%s: I/O or other error, bailing out. "
798 "Possible reason follows.\n",
799 progName );
800 perror ( progName );
801 showFileNames();
802 cleanUpAndFail( 1 );
806 /*---------------------------------------------*/
807 static
808 void mySignalCatcher ( IntNative n )
810 fprintf ( stderr,
811 "\n%s: Control-C or similar caught, quitting.\n",
812 progName );
813 cleanUpAndFail(1);
817 /*---------------------------------------------*/
818 #ifndef SMALL
819 static
820 void mySIGSEGVorSIGBUScatcher ( IntNative n )
822 if (opMode == OM_Z)
823 fprintf (
824 stderr,
825 "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
826 "\n"
827 " Possible causes are (most likely first):\n"
828 " (1) This computer has unreliable memory or cache hardware\n"
829 " (a surprisingly common problem; try a different machine.)\n"
830 " (2) A bug in the compiler used to create this executable\n"
831 " (unlikely, if you didn't compile bzip2 yourself.)\n"
832 " (3) A real bug in bzip2 -- I hope this should never be the case.\n"
833 " The user's manual, Section 4.3, has more info on (1) and (2).\n"
834 " \n"
835 " If you suspect this is a bug in bzip2, or are unsure about (1)\n"
836 " or (2), feel free to report it to me at: jseward@bzip.org.\n"
837 " Section 4.3 of the user's manual describes the info a useful\n"
838 " bug report should have. If the manual is available on your\n"
839 " system, please try and read it before mailing me. If you don't\n"
840 " have the manual or can't be bothered to read it, mail me anyway.\n"
841 "\n",
842 progName );
843 else
844 fprintf (
845 stderr,
846 "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
847 "\n"
848 " Possible causes are (most likely first):\n"
849 " (1) The compressed data is corrupted, and bzip2's usual checks\n"
850 " failed to detect this. Try bzip2 -tvv my_file.bz2.\n"
851 " (2) This computer has unreliable memory or cache hardware\n"
852 " (a surprisingly common problem; try a different machine.)\n"
853 " (3) A bug in the compiler used to create this executable\n"
854 " (unlikely, if you didn't compile bzip2 yourself.)\n"
855 " (4) A real bug in bzip2 -- I hope this should never be the case.\n"
856 " The user's manual, Section 4.3, has more info on (2) and (3).\n"
857 " \n"
858 " If you suspect this is a bug in bzip2, or are unsure about (2)\n"
859 " or (3), feel free to report it to me at: jseward@bzip.org.\n"
860 " Section 4.3 of the user's manual describes the info a useful\n"
861 " bug report should have. If the manual is available on your\n"
862 " system, please try and read it before mailing me. If you don't\n"
863 " have the manual or can't be bothered to read it, mail me anyway.\n"
864 "\n",
865 progName );
867 showFileNames();
868 if (opMode == OM_Z)
869 cleanUpAndFail( 3 ); else
870 { cadvise(); cleanUpAndFail( 2 ); }
872 #endif
875 /*---------------------------------------------*/
876 static
877 void outOfMemory ( void )
879 fprintf ( stderr,
880 "\n%s: couldn't allocate enough memory\n",
881 progName );
882 showFileNames();
883 cleanUpAndFail(1);
887 /*---------------------------------------------*/
888 static
889 void configError ( void )
891 fprintf ( stderr,
892 "bzip2: I'm not configured correctly for this platform!\n"
893 "\tI require Int32, Int16 and Char to have sizes\n"
894 "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
895 "\tProbably you can fix this by defining them correctly,\n"
896 "\tand recompiling. Bye!\n" );
897 setExit(3);
898 exit(exitValue);
902 /*---------------------------------------------------*/
903 /*--- The main driver machinery ---*/
904 /*---------------------------------------------------*/
906 /* All rather crufty. The main problem is that input files
907 are stat()d multiple times before use. This should be
908 cleaned up.
911 /*---------------------------------------------*/
912 static
913 void pad ( Char *s )
915 Int32 i;
916 if ( (Int32)strlen(s) >= longestFileName ) return;
917 for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
918 fprintf ( stderr, " " );
922 /*---------------------------------------------*/
923 static
924 void copyFileName ( Char* to, const Char* from )
926 if ( strlen(from) > FILE_NAME_LEN-10 ) {
927 fprintf (
928 stderr,
929 "bzip2: file name\n`%s'\n"
930 "is suspiciously (more than %d chars) long.\n"
931 "Try using a reasonable file name instead. Sorry! :-)\n",
932 from, FILE_NAME_LEN-10
934 setExit(1);
935 exit(exitValue);
938 strncpy(to,from,FILE_NAME_LEN-10);
939 to[FILE_NAME_LEN-10]='\0';
943 /*---------------------------------------------*/
944 static
945 Bool fileExists ( Char* name )
947 FILE *tmp = fopen ( name, "rb" );
948 Bool exists = (tmp != NULL);
949 if (tmp != NULL) fclose ( tmp );
950 return exists;
954 /*---------------------------------------------*/
955 /* Open an output file safely with O_EXCL and good permissions.
956 This avoids a race condition in versions < 1.0.2, in which
957 the file was first opened and then had its interim permissions
958 set safely. We instead use open() to create the file with
959 the interim permissions required. (--- --- rw-).
961 For non-Unix platforms, if we are not worrying about
962 security issues, simple this simply behaves like fopen.
964 static
965 FILE* fopen_output_safely ( Char* name, const char* mode )
967 # if BZ_UNIX
968 FILE* fp;
969 IntNative fh;
970 fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
971 if (fh == -1) return NULL;
972 fp = fdopen(fh, mode);
973 if (fp == NULL) close(fh);
974 return fp;
975 # else
976 return fopen(name, mode);
977 # endif
981 /*---------------------------------------------*/
982 /*--
983 if in doubt, return True
984 --*/
985 static
986 Bool notAStandardFile ( Char* name )
988 IntNative i;
989 struct MY_STAT statBuf;
991 i = MY_LSTAT ( name, &statBuf );
992 if (i != 0) return True;
993 if (MY_S_ISREG(statBuf.st_mode)) return False;
994 return True;
998 /*---------------------------------------------*/
999 /*--
1000 rac 11/21/98 see if file has hard links to it
1001 --*/
1002 static
1003 Int32 countHardLinks ( Char* name )
1005 IntNative i;
1006 struct MY_STAT statBuf;
1008 i = MY_LSTAT ( name, &statBuf );
1009 if (i != 0) return 0;
1010 return (statBuf.st_nlink - 1);
1014 /*---------------------------------------------*/
1015 /* Copy modification date, access date, permissions and owner from the
1016 source to destination file. We have to copy this meta-info off
1017 into fileMetaInfo before starting to compress / decompress it,
1018 because doing it afterwards means we get the wrong access time.
1020 To complicate matters, in compress() and decompress() below, the
1021 sequence of tests preceding the call to saveInputFileMetaInfo()
1022 involves calling fileExists(), which in turn establishes its result
1023 by attempting to fopen() the file, and if successful, immediately
1024 fclose()ing it again. So we have to assume that the fopen() call
1025 does not cause the access time field to be updated.
1027 Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
1028 to imply that merely doing open() will not affect the access time.
1029 Therefore we merely need to hope that the C library only does
1030 open() as a result of fopen(), and not any kind of read()-ahead
1031 cleverness.
1033 It sounds pretty fragile to me. Whether this carries across
1034 robustly to arbitrary Unix-like platforms (or even works robustly
1035 on this one, RedHat 7.2) is unknown to me. Nevertheless ...
1037 #if BZ_UNIX
1038 static
1039 struct MY_STAT fileMetaInfo;
1040 #endif
1042 static
1043 void saveInputFileMetaInfo ( Char *srcName )
1045 # if BZ_UNIX
1046 IntNative retVal;
1047 /* Note use of stat here, not lstat. */
1048 retVal = MY_STAT( srcName, &fileMetaInfo );
1049 ERROR_IF_NOT_ZERO ( retVal );
1050 # endif
1054 static
1055 void applySavedTimeInfoToOutputFile ( Char *dstName )
1057 # if BZ_UNIX
1058 IntNative retVal;
1059 struct utimbuf uTimBuf;
1061 uTimBuf.actime = fileMetaInfo.st_atime;
1062 uTimBuf.modtime = fileMetaInfo.st_mtime;
1064 retVal = utime ( dstName, &uTimBuf );
1065 ERROR_IF_NOT_ZERO ( retVal );
1066 # endif
1069 static
1070 void applySavedFileAttrToOutputFile ( IntNative fd )
1072 # if BZ_UNIX
1073 IntNative retVal;
1075 retVal = fchmod ( fd, fileMetaInfo.st_mode );
1076 ERROR_IF_NOT_ZERO ( retVal );
1078 (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
1079 /* chown() will in many cases return with EPERM, which can
1080 be safely ignored.
1082 # endif
1086 /*---------------------------------------------*/
1087 static
1088 Bool containsDubiousChars ( Char* name )
1090 # if BZ_UNIX
1091 /* On unix, files can contain any characters and the file expansion
1092 * is performed by the shell.
1094 return False;
1095 # else /* ! BZ_UNIX */
1096 /* On non-unix (Win* platforms), wildcard characters are not allowed in
1097 * filenames.
1099 for (; *name != '\0'; name++)
1100 if (*name == '?' || *name == '*') return True;
1101 return False;
1102 # endif /* BZ_UNIX */
1106 /*---------------------------------------------*/
1107 #define BZ_N_SUFFIX_PAIRS 4
1109 const Char* zSuffix[BZ_N_SUFFIX_PAIRS]
1110 = { ".bz2", ".bz", ".tbz2", ".tbz" };
1111 const Char* unzSuffix[BZ_N_SUFFIX_PAIRS]
1112 = { "", "", ".tar", ".tar" };
1114 static
1115 Bool hasSuffix ( Char* s, const Char* suffix )
1117 Int32 ns = strlen(s);
1118 Int32 nx = strlen(suffix);
1119 if (ns < nx) return False;
1120 if (strcmp(s + ns - nx, suffix) == 0) return True;
1121 return False;
1124 static
1125 Bool mapSuffix ( Char* name,
1126 const Char* oldSuffix,
1127 const Char* newSuffix )
1129 if (!hasSuffix(name,oldSuffix)) return False;
1130 name[strlen(name)-strlen(oldSuffix)] = 0;
1131 strcat ( name, newSuffix );
1132 return True;
1136 /*---------------------------------------------*/
1137 static
1138 void compress ( Char *name )
1140 FILE *inStr;
1141 FILE *outStr;
1142 Int32 n, i;
1143 struct MY_STAT statBuf;
1145 deleteOutputOnInterrupt = False;
1147 if (name == NULL && srcMode != SM_I2O)
1148 panic ( "compress: bad modes\n" );
1150 switch (srcMode) {
1151 case SM_I2O:
1152 copyFileName ( inName, "(stdin)" );
1153 copyFileName ( outName, "(stdout)" );
1154 break;
1155 case SM_F2F:
1156 copyFileName ( inName, name );
1157 copyFileName ( outName, name );
1158 strcat ( outName, ".bz2" );
1159 break;
1160 case SM_F2O:
1161 copyFileName ( inName, name );
1162 copyFileName ( outName, "(stdout)" );
1163 break;
1166 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1167 if (noisy)
1168 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1169 progName, inName );
1170 setExit(1);
1171 return;
1173 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1174 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1175 progName, inName, strerror(errno) );
1176 setExit(1);
1177 return;
1179 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
1180 if (hasSuffix(inName, zSuffix[i])) {
1181 if (noisy)
1182 fprintf ( stderr,
1183 "%s: Input file %s already has %s suffix.\n",
1184 progName, inName, zSuffix[i] );
1185 setExit(1);
1186 return;
1189 if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1190 MY_STAT(inName, &statBuf);
1191 if ( MY_S_ISDIR(statBuf.st_mode) ) {
1192 fprintf( stderr,
1193 "%s: Input file %s is a directory.\n",
1194 progName,inName);
1195 setExit(1);
1196 return;
1199 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1200 if (noisy)
1201 fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1202 progName, inName );
1203 setExit(1);
1204 return;
1206 if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1207 if (forceOverwrite) {
1208 remove(outName);
1209 } else {
1210 fprintf ( stderr, "%s: Output file %s already exists.\n",
1211 progName, outName );
1212 setExit(1);
1213 return;
1216 if ( srcMode == SM_F2F && !forceOverwrite &&
1217 (n=countHardLinks ( inName )) > 0) {
1218 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1219 progName, inName, n, n > 1 ? "s" : "" );
1220 setExit(1);
1221 return;
1224 if ( srcMode == SM_F2F ) {
1225 /* Save the file's meta-info before we open it. Doing it later
1226 means we mess up the access times. */
1227 saveInputFileMetaInfo ( inName );
1230 switch ( srcMode ) {
1232 case SM_I2O:
1233 inStr = stdin;
1234 outStr = stdout;
1235 if ( isatty ( fileno ( stdout ) ) ) {
1236 fprintf ( stderr,
1237 "%s: I won't write compressed data to a terminal.\n",
1238 progName );
1239 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1240 progName, progName );
1241 setExit(1);
1242 return;
1244 break;
1246 case SM_F2O:
1247 inStr = fopen ( inName, "rb" );
1248 outStr = stdout;
1249 if ( isatty ( fileno ( stdout ) ) ) {
1250 fprintf ( stderr,
1251 "%s: I won't write compressed data to a terminal.\n",
1252 progName );
1253 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1254 progName, progName );
1255 if ( inStr != NULL ) fclose ( inStr );
1256 setExit(1);
1257 return;
1259 if ( inStr == NULL ) {
1260 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1261 progName, inName, strerror(errno) );
1262 setExit(1);
1263 return;
1265 break;
1267 case SM_F2F:
1268 inStr = fopen ( inName, "rb" );
1269 outStr = fopen_output_safely ( outName, "wb" );
1270 if ( outStr == NULL) {
1271 fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1272 progName, outName, strerror(errno) );
1273 if ( inStr != NULL ) fclose ( inStr );
1274 setExit(1);
1275 return;
1277 if ( inStr == NULL ) {
1278 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1279 progName, inName, strerror(errno) );
1280 if ( outStr != NULL ) fclose ( outStr );
1281 setExit(1);
1282 return;
1284 break;
1286 default:
1287 panic ( "compress: bad srcMode" );
1288 break;
1291 if (verbosity >= 1) {
1292 fprintf ( stderr, " %s: ", inName );
1293 pad ( inName );
1294 fflush ( stderr );
1297 /*--- Now the input and output handles are sane. Do the Biz. ---*/
1298 outputHandleJustInCase = outStr;
1299 deleteOutputOnInterrupt = True;
1300 compressStream ( inStr, outStr );
1301 outputHandleJustInCase = NULL;
1303 /*--- If there was an I/O error, we won't get here. ---*/
1304 if ( srcMode == SM_F2F ) {
1305 applySavedTimeInfoToOutputFile ( outName );
1306 deleteOutputOnInterrupt = False;
1307 if ( !keepInputFiles ) {
1308 IntNative retVal = remove ( inName );
1309 ERROR_IF_NOT_ZERO ( retVal );
1313 deleteOutputOnInterrupt = False;
1317 /*---------------------------------------------*/
1318 static
1319 void uncompress ( Char *name )
1321 FILE *inStr;
1322 FILE *outStr;
1323 Int32 n, i;
1324 Bool magicNumberOK;
1325 Bool cantGuess;
1326 struct MY_STAT statBuf;
1328 deleteOutputOnInterrupt = False;
1330 if (name == NULL && srcMode != SM_I2O)
1331 panic ( "uncompress: bad modes\n" );
1333 cantGuess = False;
1334 switch (srcMode) {
1335 case SM_I2O:
1336 copyFileName ( inName, "(stdin)" );
1337 copyFileName ( outName, "(stdout)" );
1338 break;
1339 case SM_F2F:
1340 copyFileName ( inName, name );
1341 copyFileName ( outName, name );
1342 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
1343 if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
1344 goto zzz;
1345 cantGuess = True;
1346 strcat ( outName, ".out" );
1347 break;
1348 case SM_F2O:
1349 copyFileName ( inName, name );
1350 copyFileName ( outName, "(stdout)" );
1351 break;
1354 zzz:
1355 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1356 if (noisy)
1357 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1358 progName, inName );
1359 setExit(1);
1360 return;
1362 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1363 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1364 progName, inName, strerror(errno) );
1365 setExit(1);
1366 return;
1368 if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1369 MY_STAT(inName, &statBuf);
1370 if ( MY_S_ISDIR(statBuf.st_mode) ) {
1371 fprintf( stderr,
1372 "%s: Input file %s is a directory.\n",
1373 progName,inName);
1374 setExit(1);
1375 return;
1378 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1379 if (noisy)
1380 fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1381 progName, inName );
1382 setExit(1);
1383 return;
1385 if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
1386 if (noisy)
1387 fprintf ( stderr,
1388 "%s: Can't guess original name for %s -- using %s\n",
1389 progName, inName, outName );
1390 /* just a warning, no return */
1392 if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1393 if (forceOverwrite) {
1394 remove(outName);
1395 } else {
1396 fprintf ( stderr, "%s: Output file %s already exists.\n",
1397 progName, outName );
1398 setExit(1);
1399 return;
1402 if ( srcMode == SM_F2F && !forceOverwrite &&
1403 (n=countHardLinks ( inName ) ) > 0) {
1404 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1405 progName, inName, n, n > 1 ? "s" : "" );
1406 setExit(1);
1407 return;
1410 if ( srcMode == SM_F2F ) {
1411 /* Save the file's meta-info before we open it. Doing it later
1412 means we mess up the access times. */
1413 saveInputFileMetaInfo ( inName );
1416 switch ( srcMode ) {
1418 case SM_I2O:
1419 inStr = stdin;
1420 outStr = stdout;
1421 if ( isatty ( fileno ( stdin ) ) ) {
1422 fprintf ( stderr,
1423 "%s: I won't read compressed data from a terminal.\n",
1424 progName );
1425 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1426 progName, progName );
1427 setExit(1);
1428 return;
1430 break;
1432 case SM_F2O:
1433 inStr = fopen ( inName, "rb" );
1434 outStr = stdout;
1435 if ( inStr == NULL ) {
1436 fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1437 progName, inName, strerror(errno) );
1438 if ( inStr != NULL ) fclose ( inStr );
1439 setExit(1);
1440 return;
1442 break;
1444 case SM_F2F:
1445 inStr = fopen ( inName, "rb" );
1446 outStr = fopen_output_safely ( outName, "wb" );
1447 if ( outStr == NULL) {
1448 fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1449 progName, outName, strerror(errno) );
1450 if ( inStr != NULL ) fclose ( inStr );
1451 setExit(1);
1452 return;
1454 if ( inStr == NULL ) {
1455 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1456 progName, inName, strerror(errno) );
1457 if ( outStr != NULL ) fclose ( outStr );
1458 setExit(1);
1459 return;
1461 break;
1463 default:
1464 panic ( "uncompress: bad srcMode" );
1465 break;
1468 if (verbosity >= 1) {
1469 fprintf ( stderr, " %s: ", inName );
1470 pad ( inName );
1471 fflush ( stderr );
1474 /*--- Now the input and output handles are sane. Do the Biz. ---*/
1475 outputHandleJustInCase = outStr;
1476 deleteOutputOnInterrupt = True;
1477 magicNumberOK = uncompressStream ( inStr, outStr );
1478 outputHandleJustInCase = NULL;
1480 /*--- If there was an I/O error, we won't get here. ---*/
1481 if ( magicNumberOK ) {
1482 if ( srcMode == SM_F2F ) {
1483 applySavedTimeInfoToOutputFile ( outName );
1484 deleteOutputOnInterrupt = False;
1485 if ( !keepInputFiles ) {
1486 IntNative retVal = remove ( inName );
1487 ERROR_IF_NOT_ZERO ( retVal );
1490 } else {
1491 unzFailsExist = True;
1492 deleteOutputOnInterrupt = False;
1493 if ( srcMode == SM_F2F ) {
1494 IntNative retVal = remove ( outName );
1495 ERROR_IF_NOT_ZERO ( retVal );
1498 deleteOutputOnInterrupt = False;
1500 if ( magicNumberOK ) {
1501 if (verbosity >= 1)
1502 fprintf ( stderr, "done\n" );
1503 } else {
1504 setExit(2);
1505 if (verbosity >= 1)
1506 fprintf ( stderr, "not a bzip2 file.\n" ); else
1507 fprintf ( stderr,
1508 "%s: %s is not a bzip2 file.\n",
1509 progName, inName );
1515 /*---------------------------------------------*/
1516 static
1517 void testf ( Char *name )
1519 FILE *inStr;
1520 Bool allOK;
1521 struct MY_STAT statBuf;
1523 deleteOutputOnInterrupt = False;
1525 if (name == NULL && srcMode != SM_I2O)
1526 panic ( "testf: bad modes\n" );
1528 copyFileName ( outName, "(none)" );
1529 switch (srcMode) {
1530 case SM_I2O: copyFileName ( inName, "(stdin)" ); break;
1531 case SM_F2F: copyFileName ( inName, name ); break;
1532 case SM_F2O: copyFileName ( inName, name ); break;
1535 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1536 if (noisy)
1537 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1538 progName, inName );
1539 setExit(1);
1540 return;
1542 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1543 fprintf ( stderr, "%s: Can't open input %s: %s.\n",
1544 progName, inName, strerror(errno) );
1545 setExit(1);
1546 return;
1548 if ( srcMode != SM_I2O ) {
1549 MY_STAT(inName, &statBuf);
1550 if ( MY_S_ISDIR(statBuf.st_mode) ) {
1551 fprintf( stderr,
1552 "%s: Input file %s is a directory.\n",
1553 progName,inName);
1554 setExit(1);
1555 return;
1559 switch ( srcMode ) {
1561 case SM_I2O:
1562 if ( isatty ( fileno ( stdin ) ) ) {
1563 fprintf ( stderr,
1564 "%s: I won't read compressed data from a terminal.\n",
1565 progName );
1566 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1567 progName, progName );
1568 setExit(1);
1569 return;
1571 inStr = stdin;
1572 break;
1574 case SM_F2O: case SM_F2F:
1575 inStr = fopen ( inName, "rb" );
1576 if ( inStr == NULL ) {
1577 fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1578 progName, inName, strerror(errno) );
1579 setExit(1);
1580 return;
1582 break;
1584 default:
1585 panic ( "testf: bad srcMode" );
1586 break;
1589 if (verbosity >= 1) {
1590 fprintf ( stderr, " %s: ", inName );
1591 pad ( inName );
1592 fflush ( stderr );
1595 /*--- Now the input handle is sane. Do the Biz. ---*/
1596 outputHandleJustInCase = NULL;
1597 allOK = testStream ( inStr );
1599 if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
1600 if (!allOK) testFailsExist = True;
1604 /*---------------------------------------------*/
1605 static
1606 void license ( void )
1608 fprintf ( stderr,
1610 "bzip2, a block-sorting file compressor. "
1611 "Version %s.\n"
1612 " \n"
1613 " Copyright (C) 1996-2007 by Julian Seward.\n"
1614 " \n"
1615 " This program is free software; you can redistribute it and/or modify\n"
1616 " it under the terms set out in the LICENSE file, which is included\n"
1617 " in the bzip2-1.0.5 source distribution.\n"
1618 " \n"
1619 " This program is distributed in the hope that it will be useful,\n"
1620 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1621 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1622 " LICENSE file for more details.\n"
1623 " \n",
1624 BZ2_bzlibVersion()
1629 /*---------------------------------------------*/
1630 static
1631 void usage ( Char *fullProgName )
1633 fprintf (
1634 stderr,
1635 "bzip2, a block-sorting file compressor. "
1636 "Version %s.\n"
1637 "\n usage: %s [flags and input files in any order]\n"
1638 "\n"
1639 " -h --help print this message\n"
1640 " -d --decompress force decompression\n"
1641 " -z --compress force compression\n"
1642 " -k --keep keep (don't delete) input files\n"
1643 " -f --force overwrite existing output files\n"
1644 " -t --test test compressed file integrity\n"
1645 " -c --stdout output to standard out\n"
1646 " -q --quiet suppress noncritical error messages\n"
1647 " -v --verbose be verbose (a 2nd -v gives more)\n"
1648 " -L --license display software version & license\n"
1649 " -V --version display software version & license\n"
1650 " -s --small use less memory (at most 2500k)\n"
1651 " -1 .. -9 set block size to 100k .. 900k\n"
1652 " --fast alias for -1\n"
1653 " --best alias for -9\n"
1654 "\n"
1655 " If invoked as `bzip2', default action is to compress.\n"
1656 " as `bunzip2', default action is to decompress.\n"
1657 " as `bzcat', default action is to decompress to stdout.\n"
1658 "\n"
1659 " If no file names are given, bzip2 compresses or decompresses\n"
1660 " from standard input to standard output. You can combine\n"
1661 " short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
1662 # if BZ_UNIX
1663 "\n"
1664 # endif
1667 BZ2_bzlibVersion(),
1668 fullProgName
1673 /*---------------------------------------------*/
1674 static
1675 void redundant ( Char* flag )
1677 fprintf (
1678 stderr,
1679 "%s: %s is redundant in versions 0.9.5 and above\n",
1680 progName, flag );
1684 /*---------------------------------------------*/
1685 /*--
1686 All the garbage from here to main() is purely to
1687 implement a linked list of command-line arguments,
1688 into which main() copies argv[1 .. argc-1].
1690 The purpose of this exercise is to facilitate
1691 the expansion of wildcard characters * and ? in
1692 filenames for OSs which don't know how to do it
1693 themselves, like MSDOS, Windows 95 and NT.
1695 The actual Dirty Work is done by the platform-
1696 specific macro APPEND_FILESPEC.
1697 --*/
1699 typedef
1700 struct zzzz {
1701 Char *name;
1702 struct zzzz *link;
1704 Cell;
1707 /*---------------------------------------------*/
1708 static
1709 void *myMalloc ( Int32 n )
1711 void* p;
1713 p = malloc ( (size_t)n );
1714 if (p == NULL) outOfMemory ();
1715 return p;
1719 /*---------------------------------------------*/
1720 static
1721 Cell *mkCell ( void )
1723 Cell *c;
1725 c = (Cell*) myMalloc ( sizeof ( Cell ) );
1726 c->name = NULL;
1727 c->link = NULL;
1728 return c;
1732 /*---------------------------------------------*/
1733 static
1734 Cell *snocString ( Cell *root, Char *name )
1736 if (root == NULL) {
1737 Cell *tmp = mkCell();
1738 tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
1739 strcpy ( tmp->name, name );
1740 return tmp;
1741 } else {
1742 Cell *tmp = root;
1743 while (tmp->link != NULL) tmp = tmp->link;
1744 tmp->link = snocString ( tmp->link, name );
1745 return root;
1750 /*---------------------------------------------*/
1751 static
1752 void addFlagsFromEnvVar ( Cell** argList, const Char* varName )
1754 Int32 i, j, k;
1755 Char *envbase, *p;
1757 envbase = getenv(varName);
1758 if (envbase != NULL) {
1759 p = envbase;
1760 i = 0;
1761 while (True) {
1762 if (p[i] == 0) break;
1763 p += i;
1764 i = 0;
1765 while (isspace((Int32)(p[0]))) p++;
1766 while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
1767 if (i > 0) {
1768 k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
1769 for (j = 0; j < k; j++) tmpName[j] = p[j];
1770 tmpName[k] = 0;
1771 APPEND_FLAG(*argList, tmpName);
1778 /*---------------------------------------------*/
1779 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
1781 IntNative main ( IntNative argc, Char *argv[] )
1783 Int32 i, j;
1784 Char *tmp;
1785 Cell *argList;
1786 Cell *aa;
1787 Bool decode;
1789 /*-- Be really really really paranoid :-) --*/
1790 if (sizeof(Int32) != 4 || sizeof(UInt32) != 4 ||
1791 sizeof(Int16) != 2 || sizeof(UInt16) != 2 ||
1792 sizeof(Char) != 1 || sizeof(UChar) != 1)
1793 configError();
1795 /*-- Initialise --*/
1796 outputHandleJustInCase = NULL;
1797 smallMode = False;
1798 keepInputFiles = False;
1799 forceOverwrite = False;
1800 noisy = True;
1801 verbosity = 0;
1802 blockSize100k = 9;
1803 testFailsExist = False;
1804 unzFailsExist = False;
1805 numFileNames = 0;
1806 numFilesProcessed = 0;
1807 workFactor = 30;
1808 deleteOutputOnInterrupt = False;
1809 exitValue = 0;
1810 i = j = 0; /* avoid bogus warning from egcs-1.1.X */
1812 #ifndef SMALL
1813 /*-- Set up signal handlers for mem access errors --*/
1814 signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
1815 # if BZ_UNIX
1816 # ifndef __DJGPP__
1817 signal (SIGBUS, mySIGSEGVorSIGBUScatcher);
1818 # endif
1819 # endif
1820 #endif
1822 copyFileName ( inName, "(none)" );
1823 copyFileName ( outName, "(none)" );
1825 copyFileName ( progNameReally, argv[0] );
1826 progName = &progNameReally[0];
1827 for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
1828 if (*tmp == PATH_SEP) progName = tmp + 1;
1831 /*-- Copy flags from env var BZIP2, and
1832 expand filename wildcards in arg list.
1833 --*/
1834 argList = NULL;
1835 addFlagsFromEnvVar ( &argList, "BZIP2" );
1836 addFlagsFromEnvVar ( &argList, "BZIP" );
1837 for (i = 1; i <= argc-1; i++)
1838 APPEND_FILESPEC(argList, argv[i]);
1841 /*-- Find the length of the longest filename --*/
1842 longestFileName = 7;
1843 numFileNames = 0;
1844 decode = True;
1845 for (aa = argList; aa != NULL; aa = aa->link) {
1846 if (ISFLAG("--")) { decode = False; continue; }
1847 if (aa->name[0] == '-' && decode) continue;
1848 numFileNames++;
1849 if (longestFileName < (Int32)strlen(aa->name) )
1850 longestFileName = (Int32)strlen(aa->name);
1854 /*-- Determine source modes; flag handling may change this too. --*/
1855 if (numFileNames == 0)
1856 srcMode = SM_I2O; else srcMode = SM_F2F;
1859 /*-- Determine what to do (compress/uncompress/test/cat). --*/
1860 /*-- Note that subsequent flag handling may change this. --*/
1861 opMode = OM_Z;
1863 if ( (strstr ( progName, "unzip" ) != 0) ||
1864 (strstr ( progName, "UNZIP" ) != 0) )
1865 opMode = OM_UNZ;
1867 if ( (strstr ( progName, "z2cat" ) != 0) ||
1868 (strstr ( progName, "Z2CAT" ) != 0) ||
1869 (strstr ( progName, "zcat" ) != 0) ||
1870 (strstr ( progName, "ZCAT" ) != 0) ) {
1871 opMode = OM_UNZ;
1872 srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
1876 /*-- Look at the flags. --*/
1877 for (aa = argList; aa != NULL; aa = aa->link) {
1878 if (ISFLAG("--")) break;
1879 if (aa->name[0] == '-' && aa->name[1] != '-') {
1880 for (j = 1; aa->name[j] != '\0'; j++) {
1881 switch (aa->name[j]) {
1882 case 'c': srcMode = SM_F2O; break;
1883 case 'd': opMode = OM_UNZ; break;
1884 case 'z': opMode = OM_Z; break;
1885 case 'f': forceOverwrite = True; break;
1886 case 't': opMode = OM_TEST; break;
1887 case 'k': keepInputFiles = True; break;
1888 case 's': smallMode = True; break;
1889 case 'q': noisy = False; break;
1890 case '1': blockSize100k = 1; break;
1891 case '2': blockSize100k = 2; break;
1892 case '3': blockSize100k = 3; break;
1893 case '4': blockSize100k = 4; break;
1894 case '5': blockSize100k = 5; break;
1895 case '6': blockSize100k = 6; break;
1896 case '7': blockSize100k = 7; break;
1897 case '8': blockSize100k = 8; break;
1898 case '9': blockSize100k = 9; break;
1899 case 'V':
1900 case 'L': license(); break;
1901 case 'v': verbosity++; break;
1902 case 'h': usage ( progName );
1903 exit ( 0 );
1904 break;
1905 default: fprintf ( stderr, "%s: Bad flag `%s'\n",
1906 progName, aa->name );
1907 usage ( progName );
1908 exit ( 1 );
1909 break;
1915 /*-- And again ... --*/
1916 for (aa = argList; aa != NULL; aa = aa->link) {
1917 if (ISFLAG("--")) break;
1918 if (ISFLAG("--stdout")) srcMode = SM_F2O; else
1919 if (ISFLAG("--decompress")) opMode = OM_UNZ; else
1920 if (ISFLAG("--compress")) opMode = OM_Z; else
1921 if (ISFLAG("--force")) forceOverwrite = True; else
1922 if (ISFLAG("--test")) opMode = OM_TEST; else
1923 if (ISFLAG("--keep")) keepInputFiles = True; else
1924 if (ISFLAG("--small")) smallMode = True; else
1925 if (ISFLAG("--quiet")) noisy = False; else
1926 if (ISFLAG("--version")) license(); else
1927 if (ISFLAG("--license")) license(); else
1928 if (ISFLAG("--exponential")) workFactor = 1; else
1929 if (ISFLAG("--repetitive-best")) redundant(aa->name); else
1930 if (ISFLAG("--repetitive-fast")) redundant(aa->name); else
1931 if (ISFLAG("--fast")) blockSize100k = 1; else
1932 if (ISFLAG("--best")) blockSize100k = 9; else
1933 if (ISFLAG("--verbose")) verbosity++; else
1934 if (ISFLAG("--help")) { usage ( progName ); exit ( 0 ); }
1935 else
1936 if (strncmp ( aa->name, "--", 2) == 0) {
1937 fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
1938 usage ( progName );
1939 exit ( 1 );
1943 if (verbosity > 4) verbosity = 4;
1944 if (opMode == OM_Z && smallMode && blockSize100k > 2)
1945 blockSize100k = 2;
1947 if (opMode == OM_TEST && srcMode == SM_F2O) {
1948 fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
1949 progName );
1950 exit ( 1 );
1953 if (srcMode == SM_F2O && numFileNames == 0)
1954 srcMode = SM_I2O;
1956 if (opMode != OM_Z) blockSize100k = 0;
1958 if (srcMode == SM_F2F) {
1959 signal (SIGINT, mySignalCatcher);
1960 signal (SIGTERM, mySignalCatcher);
1961 # if BZ_UNIX
1962 signal (SIGHUP, mySignalCatcher);
1963 # endif
1966 if (opMode == OM_Z) {
1967 if (srcMode == SM_I2O) {
1968 compress ( NULL );
1969 } else {
1970 decode = True;
1971 for (aa = argList; aa != NULL; aa = aa->link) {
1972 if (ISFLAG("--")) { decode = False; continue; }
1973 if (aa->name[0] == '-' && decode) continue;
1974 numFilesProcessed++;
1975 compress ( aa->name );
1979 else
1981 if (opMode == OM_UNZ) {
1982 unzFailsExist = False;
1983 if (srcMode == SM_I2O) {
1984 uncompress ( NULL );
1985 } else {
1986 decode = True;
1987 for (aa = argList; aa != NULL; aa = aa->link) {
1988 if (ISFLAG("--")) { decode = False; continue; }
1989 if (aa->name[0] == '-' && decode) continue;
1990 numFilesProcessed++;
1991 uncompress ( aa->name );
1994 if (unzFailsExist) {
1995 setExit(2);
1996 exit(exitValue);
2000 else {
2001 testFailsExist = False;
2002 if (srcMode == SM_I2O) {
2003 testf ( NULL );
2004 } else {
2005 decode = True;
2006 for (aa = argList; aa != NULL; aa = aa->link) {
2007 if (ISFLAG("--")) { decode = False; continue; }
2008 if (aa->name[0] == '-' && decode) continue;
2009 numFilesProcessed++;
2010 testf ( aa->name );
2013 if (testFailsExist && noisy) {
2014 fprintf ( stderr,
2015 "\n"
2016 "You can use the `bzip2recover' program to attempt to recover\n"
2017 "data from undamaged sections of corrupted files.\n\n"
2019 setExit(2);
2020 exit(exitValue);
2024 /* Free the argument list memory to mollify leak detectors
2025 (eg) Purify, Checker. Serves no other useful purpose.
2027 aa = argList;
2028 while (aa != NULL) {
2029 Cell* aa2 = aa->link;
2030 if (aa->name != NULL) free(aa->name);
2031 free(aa);
2032 aa = aa2;
2035 return exitValue;
2039 /*-----------------------------------------------------------*/
2040 /*--- end bzip2.c ---*/
2041 /*-----------------------------------------------------------*/