2 /*-----------------------------------------------------------*/
3 /*--- A block-sorting, lossless compressor bzip2.c ---*/
4 /*-----------------------------------------------------------*/
7 This file is a part of bzip2 and/or libbzip2, a program and
8 library for lossless, block-sorting data compression.
10 Copyright (C) 1996-2005 Julian R Seward. All rights reserved.
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions
16 1. Redistributions of source code must retain the above copyright
17 notice, this list of conditions and the following disclaimer.
19 2. The origin of this software must not be misrepresented; you must
20 not claim that you wrote the original software. If you use this
21 software in a product, an acknowledgment in the product
22 documentation would be appreciated but is not required.
24 3. Altered source versions must be plainly marked as such, and must
25 not be misrepresented as being the original software.
27 4. The name of the author may not be used to endorse or promote
28 products derived from this software without specific prior written
31 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
32 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
35 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
37 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
39 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
40 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 Julian Seward, Cambridge, UK.
45 bzip2/libbzip2 version 1.0 of 21 March 2000
47 This program is based on (at least) the work of:
57 For more information on these sources, see the manual.
61 /*----------------------------------------------------*/
63 /*----------------------------------------------------*/
67 This program and library (attempts to) compress data by
68 performing several non-trivial transformations on it.
69 Unless you are 100% familiar with *all* the algorithms
70 contained herein, and with the consequences of modifying them,
71 you should NOT meddle with the compression or decompression
72 machinery. Incorrect changes can and very likely *will*
73 lead to disasterous loss of data.
76 I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE
77 USE OF THIS PROGRAM, HOWSOEVER CAUSED.
79 Every compression of a file implies an assumption that the
80 compressed file can be decompressed to reproduce the original.
81 Great efforts in design, coding and testing have been made to
82 ensure that this program works correctly. However, the
83 complexity of the algorithms, and, in particular, the presence
84 of various special cases in the code which occur with very low
85 but non-zero probability make it impossible to rule out the
86 possibility of bugs remaining in the program. DO NOT COMPRESS
87 ANY DATA WITH THIS PROGRAM AND/OR LIBRARY UNLESS YOU ARE PREPARED
88 TO ACCEPT THE POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL
91 That is not to say this program is inherently unreliable.
92 Indeed, I very much hope the opposite is true. bzip2/libbzip2
93 has been carefully constructed and extensively tested.
96 To the best of my knowledge, bzip2/libbzip2 does not use any
97 patented algorithms. However, I do not have the resources
98 available to carry out a full patent search. Therefore I cannot
99 give any guarantee of the above statement.
105 /*----------------------------------------------------*/
106 /*--- and now for something much more pleasant :-) ---*/
107 /*----------------------------------------------------*/
109 /*---------------------------------------------*/
111 Place a 1 beside your platform, and 0 elsewhere.
116 Also works on 64-bit Unix boxes.
122 Win32, as seen by Jacob Navia's excellent
123 port of (Chris Fraser & David Hanson)'s excellent
124 lcc compiler. Or with MS Visual C.
125 This is selected automatically if compiled by a compiler which
126 defines _WIN32, not including the Cygwin GCC.
128 #define BZ_LCCWIN32 0
130 #if defined(_WIN32) && !defined(__CYGWIN__)
132 #define BZ_LCCWIN32 1
138 /*---------------------------------------------*/
140 Some stuff for all platforms.
152 #define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); }
153 #define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); }
154 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
157 /*---------------------------------------------*/
159 Platform-specific stuff.
164 # include <sys/types.h>
167 # include <sys/stat.h>
168 # include <sys/times.h>
170 # define PATH_SEP '/'
171 # define MY_LSTAT lstat
172 # define MY_STAT stat
173 # define MY_S_ISREG S_ISREG
174 # define MY_S_ISDIR S_ISDIR
176 # define APPEND_FILESPEC(root, name) \
177 root=snocString((root), (name))
179 # define APPEND_FLAG(root, name) \
180 root=snocString((root), (name))
182 # define SET_BINARY_MODE(fd) /**/
185 # define NORETURN __attribute__ ((noreturn))
187 # define NORETURN /**/
195 # define MY_LSTAT stat
196 # define MY_STAT stat
197 # undef SET_BINARY_MODE
198 # define SET_BINARY_MODE(fd) \
200 int retVal = setmode ( fileno ( fd ), \
202 ERROR_IF_MINUS_ONE ( retVal ); \
209 # undef SET_BINARY_MODE
210 # define SET_BINARY_MODE(fd) \
212 int retVal = setmode ( fileno ( fd ), \
214 ERROR_IF_MINUS_ONE ( retVal ); \
224 # include <sys\stat.h>
226 # define NORETURN /**/
227 # define PATH_SEP '\\'
228 # define MY_LSTAT _stat
229 # define MY_STAT _stat
230 # define MY_S_ISREG(x) ((x) & _S_IFREG)
231 # define MY_S_ISDIR(x) ((x) & _S_IFDIR)
233 # define APPEND_FLAG(root, name) \
234 root=snocString((root), (name))
236 # define APPEND_FILESPEC(root, name) \
237 root = snocString ((root), (name))
239 # define SET_BINARY_MODE(fd) \
241 int retVal = setmode ( fileno ( fd ), \
243 ERROR_IF_MINUS_ONE ( retVal ); \
246 #endif /* BZ_LCCWIN32 */
249 /*---------------------------------------------*/
251 Some more stuff for all platforms :-)
255 typedef unsigned char Bool;
256 typedef unsigned char UChar;
258 typedef unsigned int UInt32;
260 typedef unsigned short UInt16;
262 #define True ((Bool)1)
263 #define False ((Bool)0)
266 IntNative is your platform's `native' int size.
267 Only here to avoid probs with 64-bit platforms.
269 typedef int IntNative;
272 /*---------------------------------------------------*/
273 /*--- Misc (file handling) data decls ---*/
274 /*---------------------------------------------------*/
277 Bool keepInputFiles, smallMode, deleteOutputOnInterrupt;
278 Bool forceOverwrite, testFailsExist, unzFailsExist, noisy;
279 Int32 numFileNames, numFilesProcessed, blockSize100k;
282 /*-- source modes; F==file, I==stdin, O==stdout --*/
287 /*-- operation modes --*/
295 #define FILE_NAME_LEN 1034
297 Int32 longestFileName;
298 Char inName [FILE_NAME_LEN];
299 Char outName[FILE_NAME_LEN];
300 Char tmpName[FILE_NAME_LEN];
302 Char progNameReally[FILE_NAME_LEN];
303 FILE *outputHandleJustInCase;
306 static void panic ( Char* ) NORETURN;
307 static void ioError ( void ) NORETURN;
308 static void outOfMemory ( void ) NORETURN;
309 static void configError ( void ) NORETURN;
310 static void crcError ( void ) NORETURN;
311 static void cleanUpAndFail ( Int32 ) NORETURN;
312 static void compressedStreamEOF ( void ) NORETURN;
314 static void copyFileName ( Char*, Char* );
315 static void* myMalloc ( Int32 );
316 static int applySavedFileAttrToOutputFile ( int fd );
320 /*---------------------------------------------------*/
321 /*--- An implementation of 64-bit ints. Sigh. ---*/
322 /*--- Roll on widespread deployment of ANSI C9X ! ---*/
323 /*---------------------------------------------------*/
326 struct { UChar b[8]; }
331 void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
333 n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
334 n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
335 n->b[5] = (UChar)((hi32 >> 8) & 0xFF);
336 n->b[4] = (UChar) (hi32 & 0xFF);
337 n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
338 n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
339 n->b[1] = (UChar)((lo32 >> 8) & 0xFF);
340 n->b[0] = (UChar) (lo32 & 0xFF);
345 double uInt64_to_double ( UInt64* n )
350 for (i = 0; i < 8; i++) {
351 sum += base * (double)(n->b[i]);
359 Bool uInt64_isZero ( UInt64* n )
362 for (i = 0; i < 8; i++)
363 if (n->b[i] != 0) return 0;
368 /* Divide *n by 10, and return the remainder. */
370 Int32 uInt64_qrm10 ( UInt64* n )
375 for (i = 7; i >= 0; i--) {
376 tmp = rem * 256 + n->b[i];
384 /* ... and the Whole Entire Point of all this UInt64 stuff is
385 so that we can supply the following function.
388 void uInt64_toAscii ( char* outbuf, UInt64* n )
395 q = uInt64_qrm10 ( &n_copy );
398 } while (!uInt64_isZero(&n_copy));
400 for (i = 0; i < nBuf; i++)
401 outbuf[i] = buf[nBuf-i-1];
405 /*---------------------------------------------------*/
406 /*--- Processing of complete files and streams ---*/
407 /*---------------------------------------------------*/
409 /*---------------------------------------------*/
411 Bool myfeof ( FILE* f )
413 Int32 c = fgetc ( f );
414 if (c == EOF) return True;
420 /*---------------------------------------------*/
422 void compressStream ( FILE *stream, FILE *zStream )
427 UInt32 nbytes_in_lo32, nbytes_in_hi32;
428 UInt32 nbytes_out_lo32, nbytes_out_hi32;
429 Int32 bzerr, bzerr_dummy, ret;
431 SET_BINARY_MODE(stream);
432 SET_BINARY_MODE(zStream);
434 if (ferror(stream)) goto errhandler_io;
435 if (ferror(zStream)) goto errhandler_io;
437 bzf = BZ2_bzWriteOpen ( &bzerr, zStream,
438 blockSize100k, verbosity, workFactor );
439 if (bzerr != BZ_OK) goto errhandler;
441 if (verbosity >= 2) fprintf ( stderr, "\n" );
445 if (myfeof(stream)) break;
446 nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
447 if (ferror(stream)) goto errhandler_io;
448 if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
449 if (bzerr != BZ_OK) goto errhandler;
453 BZ2_bzWriteClose64 ( &bzerr, bzf, 0,
454 &nbytes_in_lo32, &nbytes_in_hi32,
455 &nbytes_out_lo32, &nbytes_out_hi32 );
456 if (bzerr != BZ_OK) goto errhandler;
458 if (ferror(zStream)) goto errhandler_io;
459 ret = fflush ( zStream );
460 if (ret == EOF) goto errhandler_io;
461 if (zStream != stdout) {
462 int fd = fileno ( zStream );
463 if (fd < 0) goto errhandler_io;
464 ret = applySavedFileAttrToOutputFile ( fd );
465 if (ret != 0) goto errhandler_io;
466 ret = fclose ( zStream );
467 outputHandleJustInCase = NULL;
468 if (ret == EOF) goto errhandler_io;
470 outputHandleJustInCase = NULL;
471 if (ferror(stream)) goto errhandler_io;
472 ret = fclose ( stream );
473 if (ret == EOF) goto errhandler_io;
475 if (verbosity >= 1) {
476 if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
477 fprintf ( stderr, " no data compressed.\n");
479 Char buf_nin[32], buf_nout[32];
480 UInt64 nbytes_in, nbytes_out;
481 double nbytes_in_d, nbytes_out_d;
482 uInt64_from_UInt32s ( &nbytes_in,
483 nbytes_in_lo32, nbytes_in_hi32 );
484 uInt64_from_UInt32s ( &nbytes_out,
485 nbytes_out_lo32, nbytes_out_hi32 );
486 nbytes_in_d = uInt64_to_double ( &nbytes_in );
487 nbytes_out_d = uInt64_to_double ( &nbytes_out );
488 uInt64_toAscii ( buf_nin, &nbytes_in );
489 uInt64_toAscii ( buf_nout, &nbytes_out );
490 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
491 "%5.2f%% saved, %s in, %s out.\n",
492 nbytes_in_d / nbytes_out_d,
493 (8.0 * nbytes_out_d) / nbytes_in_d,
494 100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
504 BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1,
505 &nbytes_in_lo32, &nbytes_in_hi32,
506 &nbytes_out_lo32, &nbytes_out_hi32 );
508 case BZ_CONFIG_ERROR:
509 configError(); break;
511 outOfMemory (); break;
516 panic ( "compress:unexpected error" );
519 panic ( "compress:end" );
525 /*---------------------------------------------*/
527 Bool uncompressStream ( FILE *zStream, FILE *stream )
530 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i;
532 UChar unused[BZ_MAX_UNUSED];
540 SET_BINARY_MODE(stream);
541 SET_BINARY_MODE(zStream);
543 if (ferror(stream)) goto errhandler_io;
544 if (ferror(zStream)) goto errhandler_io;
548 bzf = BZ2_bzReadOpen (
549 &bzerr, zStream, verbosity,
550 (int)smallMode, unused, nUnused
552 if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
555 while (bzerr == BZ_OK) {
556 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
557 if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
558 if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
559 fwrite ( obuf, sizeof(UChar), nread, stream );
560 if (ferror(stream)) goto errhandler_io;
562 if (bzerr != BZ_STREAM_END) goto errhandler;
564 BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
565 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
567 unusedTmp = (UChar*)unusedTmpV;
568 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
570 BZ2_bzReadClose ( &bzerr, bzf );
571 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
573 if (nUnused == 0 && myfeof(zStream)) break;
577 if (ferror(zStream)) goto errhandler_io;
578 if ( stream != stdout) {
579 int fd = fileno ( stream );
580 if (fd < 0) goto errhandler_io;
581 ret = applySavedFileAttrToOutputFile ( fd );
582 if (ret != 0) goto errhandler_io;
584 ret = fclose ( zStream );
585 if (ret == EOF) goto errhandler_io;
587 if (ferror(stream)) goto errhandler_io;
588 ret = fflush ( stream );
589 if (ret != 0) goto errhandler_io;
590 if (stream != stdout) {
591 ret = fclose ( stream );
592 outputHandleJustInCase = NULL;
593 if (ret == EOF) goto errhandler_io;
595 outputHandleJustInCase = NULL;
596 if (verbosity >= 2) fprintf ( stderr, "\n " );
600 if (forceOverwrite) {
603 if (myfeof(zStream)) break;
604 nread = fread ( obuf, sizeof(UChar), 5000, zStream );
605 if (ferror(zStream)) goto errhandler_io;
606 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
607 if (ferror(stream)) goto errhandler_io;
613 BZ2_bzReadClose ( &bzerr_dummy, bzf );
615 case BZ_CONFIG_ERROR:
616 configError(); break;
624 case BZ_UNEXPECTED_EOF:
625 compressedStreamEOF();
626 case BZ_DATA_ERROR_MAGIC:
627 if (zStream != stdin) fclose(zStream);
628 if (stream != stdout) fclose(stream);
634 "\n%s: %s: trailing garbage after EOF ignored\n",
639 panic ( "decompress:unexpected error" );
642 panic ( "decompress:end" );
643 return True; /*notreached*/
647 /*---------------------------------------------*/
649 Bool testStream ( FILE *zStream )
652 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i;
654 UChar unused[BZ_MAX_UNUSED];
662 SET_BINARY_MODE(zStream);
663 if (ferror(zStream)) goto errhandler_io;
667 bzf = BZ2_bzReadOpen (
668 &bzerr, zStream, verbosity,
669 (int)smallMode, unused, nUnused
671 if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
674 while (bzerr == BZ_OK) {
675 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
676 if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
678 if (bzerr != BZ_STREAM_END) goto errhandler;
680 BZ2_bzReadGetUnused ( &bzerr, bzf, &unusedTmpV, &nUnused );
681 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
683 unusedTmp = (UChar*)unusedTmpV;
684 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
686 BZ2_bzReadClose ( &bzerr, bzf );
687 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
688 if (nUnused == 0 && myfeof(zStream)) break;
692 if (ferror(zStream)) goto errhandler_io;
693 ret = fclose ( zStream );
694 if (ret == EOF) goto errhandler_io;
696 if (verbosity >= 2) fprintf ( stderr, "\n " );
700 BZ2_bzReadClose ( &bzerr_dummy, bzf );
702 fprintf ( stderr, "%s: %s: ", progName, inName );
704 case BZ_CONFIG_ERROR:
705 configError(); break;
711 "data integrity (CRC) error in data\n" );
715 case BZ_UNEXPECTED_EOF:
717 "file ends unexpectedly\n" );
719 case BZ_DATA_ERROR_MAGIC:
720 if (zStream != stdin) fclose(zStream);
723 "bad magic number (file not created by bzip2)\n" );
728 "trailing garbage after EOF ignored\n" );
732 panic ( "test:unexpected error" );
735 panic ( "test:end" );
736 return True; /*notreached*/
740 /*---------------------------------------------------*/
741 /*--- Error [non-] handling grunge ---*/
742 /*---------------------------------------------------*/
744 /*---------------------------------------------*/
746 void setExit ( Int32 v )
748 if (v > exitValue) exitValue = v;
752 /*---------------------------------------------*/
754 void cadvise ( void )
759 "\nIt is possible that the compressed file(s) have become corrupted.\n"
760 "You can use the -tvv option to test integrity of such files.\n\n"
761 "You can use the `bzip2recover' program to attempt to recover\n"
762 "data from undamaged sections of corrupted files.\n\n"
767 /*---------------------------------------------*/
769 void showFileNames ( void )
774 "\tInput file = %s, output file = %s\n",
780 /*---------------------------------------------*/
782 void cleanUpAndFail ( Int32 ec )
785 struct MY_STAT statBuf;
787 if ( srcMode == SM_F2F
789 && deleteOutputOnInterrupt ) {
791 /* Check whether input file still exists. Delete output file
792 only if input exists to avoid loss of data. Joerg Prante, 5
793 January 2002. (JRS 06-Jan-2002: other changes in 1.0.2 mean
794 this is less likely to happen. But to be ultra-paranoid, we
795 do the check anyway.) */
796 retVal = MY_STAT ( inName, &statBuf );
800 "%s: Deleting output file %s, if it exists.\n",
802 if (outputHandleJustInCase != NULL)
803 fclose ( outputHandleJustInCase );
804 retVal = remove ( outName );
807 "%s: WARNING: deletion of output file "
808 "(apparently) failed.\n",
812 "%s: WARNING: deletion of output file suppressed\n",
815 "%s: since input file no longer exists. Output file\n",
818 "%s: `%s' may be incomplete.\n",
821 "%s: I suggest doing an integrity test (bzip2 -tv)"
827 if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
829 "%s: WARNING: some files have not been processed:\n"
830 "%s: %d specified on command line, %d not processed yet.\n\n",
832 numFileNames, numFileNames - numFilesProcessed );
839 /*---------------------------------------------*/
841 void panic ( Char* s )
844 "\n%s: PANIC -- internal consistency error:\n"
846 "\tThis is a BUG. Please report it to me at:\n"
847 "\tjseward@bzip.org\n",
854 /*---------------------------------------------*/
856 void crcError ( void )
859 "\n%s: Data integrity error when decompressing.\n",
867 /*---------------------------------------------*/
869 void compressedStreamEOF ( void )
873 "\n%s: Compressed file ends unexpectedly;\n\t"
874 "perhaps it is corrupted? *Possible* reason follows.\n",
884 /*---------------------------------------------*/
886 void ioError ( void )
889 "\n%s: I/O or other error, bailing out. "
890 "Possible reason follows.\n",
898 /*---------------------------------------------*/
900 void mySignalCatcher ( IntNative n )
903 "\n%s: Control-C or similar caught, quitting.\n",
909 /*---------------------------------------------*/
911 void mySIGSEGVorSIGBUScatcher ( IntNative n )
916 "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
918 " Possible causes are (most likely first):\n"
919 " (1) This computer has unreliable memory or cache hardware\n"
920 " (a surprisingly common problem; try a different machine.)\n"
921 " (2) A bug in the compiler used to create this executable\n"
922 " (unlikely, if you didn't compile bzip2 yourself.)\n"
923 " (3) A real bug in bzip2 -- I hope this should never be the case.\n"
924 " The user's manual, Section 4.3, has more info on (1) and (2).\n"
926 " If you suspect this is a bug in bzip2, or are unsure about (1)\n"
927 " or (2), feel free to report it to me at: jseward@bzip.org.\n"
928 " Section 4.3 of the user's manual describes the info a useful\n"
929 " bug report should have. If the manual is available on your\n"
930 " system, please try and read it before mailing me. If you don't\n"
931 " have the manual or can't be bothered to read it, mail me anyway.\n"
937 "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
939 " Possible causes are (most likely first):\n"
940 " (1) The compressed data is corrupted, and bzip2's usual checks\n"
941 " failed to detect this. Try bzip2 -tvv my_file.bz2.\n"
942 " (2) This computer has unreliable memory or cache hardware\n"
943 " (a surprisingly common problem; try a different machine.)\n"
944 " (3) A bug in the compiler used to create this executable\n"
945 " (unlikely, if you didn't compile bzip2 yourself.)\n"
946 " (4) A real bug in bzip2 -- I hope this should never be the case.\n"
947 " The user's manual, Section 4.3, has more info on (2) and (3).\n"
949 " If you suspect this is a bug in bzip2, or are unsure about (2)\n"
950 " or (3), feel free to report it to me at: jseward@bzip.org.\n"
951 " Section 4.3 of the user's manual describes the info a useful\n"
952 " bug report should have. If the manual is available on your\n"
953 " system, please try and read it before mailing me. If you don't\n"
954 " have the manual or can't be bothered to read it, mail me anyway.\n"
960 cleanUpAndFail( 3 ); else
961 { cadvise(); cleanUpAndFail( 2 ); }
965 /*---------------------------------------------*/
967 void outOfMemory ( void )
970 "\n%s: couldn't allocate enough memory\n",
977 /*---------------------------------------------*/
979 void configError ( void )
982 "bzip2: I'm not configured correctly for this platform!\n"
983 "\tI require Int32, Int16 and Char to have sizes\n"
984 "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
985 "\tProbably you can fix this by defining them correctly,\n"
986 "\tand recompiling. Bye!\n" );
992 /*---------------------------------------------------*/
993 /*--- The main driver machinery ---*/
994 /*---------------------------------------------------*/
996 /* All rather crufty. The main problem is that input files
997 are stat()d multiple times before use. This should be
1001 /*---------------------------------------------*/
1003 void pad ( Char *s )
1006 if ( (Int32)strlen(s) >= longestFileName ) return;
1007 for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
1008 fprintf ( stderr, " " );
1012 /*---------------------------------------------*/
1014 void copyFileName ( Char* to, Char* from )
1016 if ( strlen(from) > FILE_NAME_LEN-10 ) {
1019 "bzip2: file name\n`%s'\n"
1020 "is suspiciously (more than %d chars) long.\n"
1021 "Try using a reasonable file name instead. Sorry! :-)\n",
1022 from, FILE_NAME_LEN-10
1028 strncpy(to,from,FILE_NAME_LEN-10);
1029 to[FILE_NAME_LEN-10]='\0';
1033 /*---------------------------------------------*/
1035 Bool fileExists ( Char* name )
1037 FILE *tmp = fopen ( name, "rb" );
1038 Bool exists = (tmp != NULL);
1039 if (tmp != NULL) fclose ( tmp );
1044 /*---------------------------------------------*/
1045 /* Open an output file safely with O_EXCL and good permissions.
1046 This avoids a race condition in versions < 1.0.2, in which
1047 the file was first opened and then had its interim permissions
1048 set safely. We instead use open() to create the file with
1049 the interim permissions required. (--- --- rw-).
1051 For non-Unix platforms, if we are not worrying about
1052 security issues, simple this simply behaves like fopen.
1054 FILE* fopen_output_safely ( Char* name, const char* mode )
1059 fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
1060 if (fh == -1) return NULL;
1061 fp = fdopen(fh, mode);
1062 if (fp == NULL) close(fh);
1065 return fopen(name, mode);
1070 /*---------------------------------------------*/
1072 if in doubt, return True
1075 Bool notAStandardFile ( Char* name )
1078 struct MY_STAT statBuf;
1080 i = MY_LSTAT ( name, &statBuf );
1081 if (i != 0) return True;
1082 if (MY_S_ISREG(statBuf.st_mode)) return False;
1087 /*---------------------------------------------*/
1089 rac 11/21/98 see if file has hard links to it
1092 Int32 countHardLinks ( Char* name )
1095 struct MY_STAT statBuf;
1097 i = MY_LSTAT ( name, &statBuf );
1098 if (i != 0) return 0;
1099 return (statBuf.st_nlink - 1);
1103 /*---------------------------------------------*/
1104 /* Copy modification date, access date, permissions and owner from the
1105 source to destination file. We have to copy this meta-info off
1106 into fileMetaInfo before starting to compress / decompress it,
1107 because doing it afterwards means we get the wrong access time.
1109 To complicate matters, in compress() and decompress() below, the
1110 sequence of tests preceding the call to saveInputFileMetaInfo()
1111 involves calling fileExists(), which in turn establishes its result
1112 by attempting to fopen() the file, and if successful, immediately
1113 fclose()ing it again. So we have to assume that the fopen() call
1114 does not cause the access time field to be updated.
1116 Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems
1117 to imply that merely doing open() will not affect the access time.
1118 Therefore we merely need to hope that the C library only does
1119 open() as a result of fopen(), and not any kind of read()-ahead
1122 It sounds pretty fragile to me. Whether this carries across
1123 robustly to arbitrary Unix-like platforms (or even works robustly
1124 on this one, RedHat 7.2) is unknown to me. Nevertheless ...
1128 struct MY_STAT fileMetaInfo;
1132 void saveInputFileMetaInfo ( Char *srcName )
1136 /* Note use of stat here, not lstat. */
1137 retVal = MY_STAT( srcName, &fileMetaInfo );
1138 ERROR_IF_NOT_ZERO ( retVal );
1144 void applySavedTimeInfoToOutputFile ( Char *dstName )
1148 struct utimbuf uTimBuf;
1150 uTimBuf.actime = fileMetaInfo.st_atime;
1151 uTimBuf.modtime = fileMetaInfo.st_mtime;
1153 retVal = utime ( dstName, &uTimBuf );
1154 ERROR_IF_NOT_ZERO ( retVal );
1159 int applySavedFileAttrToOutputFile ( int fd )
1164 retVal = fchmod ( fd, fileMetaInfo.st_mode );
1168 (void) fchown ( fd, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
1169 /* chown() will in many cases return with EPERM, which can
1177 /*---------------------------------------------*/
1179 Bool containsDubiousChars ( Char* name )
1182 /* On unix, files can contain any characters and the file expansion
1183 * is performed by the shell.
1186 # else /* ! BZ_UNIX */
1187 /* On non-unix (Win* platforms), wildcard characters are not allowed in
1190 for (; *name != '\0'; name++)
1191 if (*name == '?' || *name == '*') return True;
1193 # endif /* BZ_UNIX */
1197 /*---------------------------------------------*/
1198 #define BZ_N_SUFFIX_PAIRS 4
1200 Char* zSuffix[BZ_N_SUFFIX_PAIRS]
1201 = { ".bz2", ".bz", ".tbz2", ".tbz" };
1202 Char* unzSuffix[BZ_N_SUFFIX_PAIRS]
1203 = { "", "", ".tar", ".tar" };
1206 Bool hasSuffix ( Char* s, Char* suffix )
1208 Int32 ns = strlen(s);
1209 Int32 nx = strlen(suffix);
1210 if (ns < nx) return False;
1211 if (strcmp(s + ns - nx, suffix) == 0) return True;
1216 Bool mapSuffix ( Char* name,
1217 Char* oldSuffix, Char* newSuffix )
1219 if (!hasSuffix(name,oldSuffix)) return False;
1220 name[strlen(name)-strlen(oldSuffix)] = 0;
1221 strcat ( name, newSuffix );
1226 /*---------------------------------------------*/
1228 void compress ( Char *name )
1233 struct MY_STAT statBuf;
1235 deleteOutputOnInterrupt = False;
1237 if (name == NULL && srcMode != SM_I2O)
1238 panic ( "compress: bad modes\n" );
1242 copyFileName ( inName, "(stdin)" );
1243 copyFileName ( outName, "(stdout)" );
1246 copyFileName ( inName, name );
1247 copyFileName ( outName, name );
1248 strcat ( outName, ".bz2" );
1251 copyFileName ( inName, name );
1252 copyFileName ( outName, "(stdout)" );
1256 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1258 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1263 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1264 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1265 progName, inName, strerror(errno) );
1269 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
1270 if (hasSuffix(inName, zSuffix[i])) {
1273 "%s: Input file %s already has %s suffix.\n",
1274 progName, inName, zSuffix[i] );
1279 if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1280 MY_STAT(inName, &statBuf);
1281 if ( MY_S_ISDIR(statBuf.st_mode) ) {
1283 "%s: Input file %s is a directory.\n",
1289 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1291 fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1296 if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1297 if (forceOverwrite) {
1300 fprintf ( stderr, "%s: Output file %s already exists.\n",
1301 progName, outName );
1306 if ( srcMode == SM_F2F && !forceOverwrite &&
1307 (n=countHardLinks ( inName )) > 0) {
1308 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1309 progName, inName, n, n > 1 ? "s" : "" );
1314 if ( srcMode == SM_F2F ) {
1315 /* Save the file's meta-info before we open it. Doing it later
1316 means we mess up the access times. */
1317 saveInputFileMetaInfo ( inName );
1320 switch ( srcMode ) {
1325 if ( isatty ( fileno ( stdout ) ) ) {
1327 "%s: I won't write compressed data to a terminal.\n",
1329 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1330 progName, progName );
1337 inStr = fopen ( inName, "rb" );
1339 if ( isatty ( fileno ( stdout ) ) ) {
1341 "%s: I won't write compressed data to a terminal.\n",
1343 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1344 progName, progName );
1345 if ( inStr != NULL ) fclose ( inStr );
1349 if ( inStr == NULL ) {
1350 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1351 progName, inName, strerror(errno) );
1358 inStr = fopen ( inName, "rb" );
1359 outStr = fopen_output_safely ( outName, "wb" );
1360 if ( outStr == NULL) {
1361 fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1362 progName, outName, strerror(errno) );
1363 if ( inStr != NULL ) fclose ( inStr );
1367 if ( inStr == NULL ) {
1368 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1369 progName, inName, strerror(errno) );
1370 if ( outStr != NULL ) fclose ( outStr );
1377 panic ( "compress: bad srcMode" );
1381 if (verbosity >= 1) {
1382 fprintf ( stderr, " %s: ", inName );
1387 /*--- Now the input and output handles are sane. Do the Biz. ---*/
1388 outputHandleJustInCase = outStr;
1389 deleteOutputOnInterrupt = True;
1390 compressStream ( inStr, outStr );
1391 outputHandleJustInCase = NULL;
1393 /*--- If there was an I/O error, we won't get here. ---*/
1394 if ( srcMode == SM_F2F ) {
1395 applySavedTimeInfoToOutputFile ( outName );
1396 deleteOutputOnInterrupt = False;
1397 if ( !keepInputFiles ) {
1398 IntNative retVal = remove ( inName );
1399 ERROR_IF_NOT_ZERO ( retVal );
1403 deleteOutputOnInterrupt = False;
1407 /*---------------------------------------------*/
1409 void uncompress ( Char *name )
1416 struct MY_STAT statBuf;
1418 deleteOutputOnInterrupt = False;
1420 if (name == NULL && srcMode != SM_I2O)
1421 panic ( "uncompress: bad modes\n" );
1426 copyFileName ( inName, "(stdin)" );
1427 copyFileName ( outName, "(stdout)" );
1430 copyFileName ( inName, name );
1431 copyFileName ( outName, name );
1432 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
1433 if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
1436 strcat ( outName, ".out" );
1439 copyFileName ( inName, name );
1440 copyFileName ( outName, "(stdout)" );
1445 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1447 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1452 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1453 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1454 progName, inName, strerror(errno) );
1458 if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
1459 MY_STAT(inName, &statBuf);
1460 if ( MY_S_ISDIR(statBuf.st_mode) ) {
1462 "%s: Input file %s is a directory.\n",
1468 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
1470 fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
1475 if ( /* srcMode == SM_F2F implied && */ cantGuess ) {
1478 "%s: Can't guess original name for %s -- using %s\n",
1479 progName, inName, outName );
1480 /* just a warning, no return */
1482 if ( srcMode == SM_F2F && fileExists ( outName ) ) {
1483 if (forceOverwrite) {
1486 fprintf ( stderr, "%s: Output file %s already exists.\n",
1487 progName, outName );
1492 if ( srcMode == SM_F2F && !forceOverwrite &&
1493 (n=countHardLinks ( inName ) ) > 0) {
1494 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
1495 progName, inName, n, n > 1 ? "s" : "" );
1500 if ( srcMode == SM_F2F ) {
1501 /* Save the file's meta-info before we open it. Doing it later
1502 means we mess up the access times. */
1503 saveInputFileMetaInfo ( inName );
1506 switch ( srcMode ) {
1511 if ( isatty ( fileno ( stdin ) ) ) {
1513 "%s: I won't read compressed data from a terminal.\n",
1515 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1516 progName, progName );
1523 inStr = fopen ( inName, "rb" );
1525 if ( inStr == NULL ) {
1526 fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1527 progName, inName, strerror(errno) );
1528 if ( inStr != NULL ) fclose ( inStr );
1535 inStr = fopen ( inName, "rb" );
1536 outStr = fopen_output_safely ( outName, "wb" );
1537 if ( outStr == NULL) {
1538 fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
1539 progName, outName, strerror(errno) );
1540 if ( inStr != NULL ) fclose ( inStr );
1544 if ( inStr == NULL ) {
1545 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
1546 progName, inName, strerror(errno) );
1547 if ( outStr != NULL ) fclose ( outStr );
1554 panic ( "uncompress: bad srcMode" );
1558 if (verbosity >= 1) {
1559 fprintf ( stderr, " %s: ", inName );
1564 /*--- Now the input and output handles are sane. Do the Biz. ---*/
1565 outputHandleJustInCase = outStr;
1566 deleteOutputOnInterrupt = True;
1567 magicNumberOK = uncompressStream ( inStr, outStr );
1568 outputHandleJustInCase = NULL;
1570 /*--- If there was an I/O error, we won't get here. ---*/
1571 if ( magicNumberOK ) {
1572 if ( srcMode == SM_F2F ) {
1573 applySavedTimeInfoToOutputFile ( outName );
1574 deleteOutputOnInterrupt = False;
1575 if ( !keepInputFiles ) {
1576 IntNative retVal = remove ( inName );
1577 ERROR_IF_NOT_ZERO ( retVal );
1581 unzFailsExist = True;
1582 deleteOutputOnInterrupt = False;
1583 if ( srcMode == SM_F2F ) {
1584 IntNative retVal = remove ( outName );
1585 ERROR_IF_NOT_ZERO ( retVal );
1588 deleteOutputOnInterrupt = False;
1590 if ( magicNumberOK ) {
1592 fprintf ( stderr, "done\n" );
1596 fprintf ( stderr, "not a bzip2 file.\n" ); else
1598 "%s: %s is not a bzip2 file.\n",
1605 /*---------------------------------------------*/
1607 void testf ( Char *name )
1611 struct MY_STAT statBuf;
1613 deleteOutputOnInterrupt = False;
1615 if (name == NULL && srcMode != SM_I2O)
1616 panic ( "testf: bad modes\n" );
1618 copyFileName ( outName, "(none)" );
1620 case SM_I2O: copyFileName ( inName, "(stdin)" ); break;
1621 case SM_F2F: copyFileName ( inName, name ); break;
1622 case SM_F2O: copyFileName ( inName, name ); break;
1625 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
1627 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
1632 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
1633 fprintf ( stderr, "%s: Can't open input %s: %s.\n",
1634 progName, inName, strerror(errno) );
1638 if ( srcMode != SM_I2O ) {
1639 MY_STAT(inName, &statBuf);
1640 if ( MY_S_ISDIR(statBuf.st_mode) ) {
1642 "%s: Input file %s is a directory.\n",
1649 switch ( srcMode ) {
1652 if ( isatty ( fileno ( stdin ) ) ) {
1654 "%s: I won't read compressed data from a terminal.\n",
1656 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
1657 progName, progName );
1664 case SM_F2O: case SM_F2F:
1665 inStr = fopen ( inName, "rb" );
1666 if ( inStr == NULL ) {
1667 fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
1668 progName, inName, strerror(errno) );
1675 panic ( "testf: bad srcMode" );
1679 if (verbosity >= 1) {
1680 fprintf ( stderr, " %s: ", inName );
1685 /*--- Now the input handle is sane. Do the Biz. ---*/
1686 outputHandleJustInCase = NULL;
1687 allOK = testStream ( inStr );
1689 if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
1690 if (!allOK) testFailsExist = True;
1694 /*---------------------------------------------*/
1696 void license ( void )
1700 "bzip2, a block-sorting file compressor. "
1703 " Copyright (C) 1996-2005 by Julian Seward.\n"
1705 " This program is free software; you can redistribute it and/or modify\n"
1706 " it under the terms set out in the LICENSE file, which is included\n"
1707 " in the bzip2-1.0 source distribution.\n"
1709 " This program is distributed in the hope that it will be useful,\n"
1710 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
1711 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
1712 " LICENSE file for more details.\n"
1719 /*---------------------------------------------*/
1721 void usage ( Char *fullProgName )
1725 "bzip2, a block-sorting file compressor. "
1727 "\n usage: %s [flags and input files in any order]\n"
1729 " -h --help print this message\n"
1730 " -d --decompress force decompression\n"
1731 " -z --compress force compression\n"
1732 " -k --keep keep (don't delete) input files\n"
1733 " -f --force overwrite existing output files\n"
1734 " -t --test test compressed file integrity\n"
1735 " -c --stdout output to standard out\n"
1736 " -q --quiet suppress noncritical error messages\n"
1737 " -v --verbose be verbose (a 2nd -v gives more)\n"
1738 " -L --license display software version & license\n"
1739 " -V --version display software version & license\n"
1740 " -s --small use less memory (at most 2500k)\n"
1741 " -1 .. -9 set block size to 100k .. 900k\n"
1742 " --fast alias for -1\n"
1743 " --best alias for -9\n"
1745 " If invoked as `bzip2', default action is to compress.\n"
1746 " as `bunzip2', default action is to decompress.\n"
1747 " as `bzcat', default action is to decompress to stdout.\n"
1749 " If no file names are given, bzip2 compresses or decompresses\n"
1750 " from standard input to standard output. You can combine\n"
1751 " short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
1763 /*---------------------------------------------*/
1765 void redundant ( Char* flag )
1769 "%s: %s is redundant in versions 0.9.5 and above\n",
1774 /*---------------------------------------------*/
1776 All the garbage from here to main() is purely to
1777 implement a linked list of command-line arguments,
1778 into which main() copies argv[1 .. argc-1].
1780 The purpose of this exercise is to facilitate
1781 the expansion of wildcard characters * and ? in
1782 filenames for OSs which don't know how to do it
1783 themselves, like MSDOS, Windows 95 and NT.
1785 The actual Dirty Work is done by the platform-
1786 specific macro APPEND_FILESPEC.
1797 /*---------------------------------------------*/
1799 void *myMalloc ( Int32 n )
1803 p = malloc ( (size_t)n );
1804 if (p == NULL) outOfMemory ();
1809 /*---------------------------------------------*/
1811 Cell *mkCell ( void )
1815 c = (Cell*) myMalloc ( sizeof ( Cell ) );
1822 /*---------------------------------------------*/
1824 Cell *snocString ( Cell *root, Char *name )
1827 Cell *tmp = mkCell();
1828 tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
1829 strcpy ( tmp->name, name );
1833 while (tmp->link != NULL) tmp = tmp->link;
1834 tmp->link = snocString ( tmp->link, name );
1840 /*---------------------------------------------*/
1842 void addFlagsFromEnvVar ( Cell** argList, Char* varName )
1847 envbase = getenv(varName);
1848 if (envbase != NULL) {
1852 if (p[i] == 0) break;
1855 while (isspace((Int32)(p[0]))) p++;
1856 while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
1858 k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
1859 for (j = 0; j < k; j++) tmpName[j] = p[j];
1861 APPEND_FLAG(*argList, tmpName);
1868 /*---------------------------------------------*/
1869 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
1871 IntNative main ( IntNative argc, Char *argv[] )
1879 /*-- Be really really really paranoid :-) --*/
1880 if (sizeof(Int32) != 4 || sizeof(UInt32) != 4 ||
1881 sizeof(Int16) != 2 || sizeof(UInt16) != 2 ||
1882 sizeof(Char) != 1 || sizeof(UChar) != 1)
1885 /*-- Initialise --*/
1886 outputHandleJustInCase = NULL;
1888 keepInputFiles = False;
1889 forceOverwrite = False;
1893 testFailsExist = False;
1894 unzFailsExist = False;
1896 numFilesProcessed = 0;
1898 deleteOutputOnInterrupt = False;
1900 i = j = 0; /* avoid bogus warning from egcs-1.1.X */
1902 /*-- Set up signal handlers for mem access errors --*/
1903 signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
1906 signal (SIGBUS, mySIGSEGVorSIGBUScatcher);
1910 copyFileName ( inName, "(none)" );
1911 copyFileName ( outName, "(none)" );
1913 copyFileName ( progNameReally, argv[0] );
1914 progName = &progNameReally[0];
1915 for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
1916 if (*tmp == PATH_SEP) progName = tmp + 1;
1919 /*-- Copy flags from env var BZIP2, and
1920 expand filename wildcards in arg list.
1923 addFlagsFromEnvVar ( &argList, "BZIP2" );
1924 addFlagsFromEnvVar ( &argList, "BZIP" );
1925 for (i = 1; i <= argc-1; i++)
1926 APPEND_FILESPEC(argList, argv[i]);
1929 /*-- Find the length of the longest filename --*/
1930 longestFileName = 7;
1933 for (aa = argList; aa != NULL; aa = aa->link) {
1934 if (ISFLAG("--")) { decode = False; continue; }
1935 if (aa->name[0] == '-' && decode) continue;
1937 if (longestFileName < (Int32)strlen(aa->name) )
1938 longestFileName = (Int32)strlen(aa->name);
1942 /*-- Determine source modes; flag handling may change this too. --*/
1943 if (numFileNames == 0)
1944 srcMode = SM_I2O; else srcMode = SM_F2F;
1947 /*-- Determine what to do (compress/uncompress/test/cat). --*/
1948 /*-- Note that subsequent flag handling may change this. --*/
1951 if ( (strstr ( progName, "unzip" ) != 0) ||
1952 (strstr ( progName, "UNZIP" ) != 0) )
1955 if ( (strstr ( progName, "z2cat" ) != 0) ||
1956 (strstr ( progName, "Z2CAT" ) != 0) ||
1957 (strstr ( progName, "zcat" ) != 0) ||
1958 (strstr ( progName, "ZCAT" ) != 0) ) {
1960 srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
1964 /*-- Look at the flags. --*/
1965 for (aa = argList; aa != NULL; aa = aa->link) {
1966 if (ISFLAG("--")) break;
1967 if (aa->name[0] == '-' && aa->name[1] != '-') {
1968 for (j = 1; aa->name[j] != '\0'; j++) {
1969 switch (aa->name[j]) {
1970 case 'c': srcMode = SM_F2O; break;
1971 case 'd': opMode = OM_UNZ; break;
1972 case 'z': opMode = OM_Z; break;
1973 case 'f': forceOverwrite = True; break;
1974 case 't': opMode = OM_TEST; break;
1975 case 'k': keepInputFiles = True; break;
1976 case 's': smallMode = True; break;
1977 case 'q': noisy = False; break;
1978 case '1': blockSize100k = 1; break;
1979 case '2': blockSize100k = 2; break;
1980 case '3': blockSize100k = 3; break;
1981 case '4': blockSize100k = 4; break;
1982 case '5': blockSize100k = 5; break;
1983 case '6': blockSize100k = 6; break;
1984 case '7': blockSize100k = 7; break;
1985 case '8': blockSize100k = 8; break;
1986 case '9': blockSize100k = 9; break;
1988 case 'L': license(); break;
1989 case 'v': verbosity++; break;
1990 case 'h': usage ( progName );
1993 default: fprintf ( stderr, "%s: Bad flag `%s'\n",
1994 progName, aa->name );
2003 /*-- And again ... --*/
2004 for (aa = argList; aa != NULL; aa = aa->link) {
2005 if (ISFLAG("--")) break;
2006 if (ISFLAG("--stdout")) srcMode = SM_F2O; else
2007 if (ISFLAG("--decompress")) opMode = OM_UNZ; else
2008 if (ISFLAG("--compress")) opMode = OM_Z; else
2009 if (ISFLAG("--force")) forceOverwrite = True; else
2010 if (ISFLAG("--test")) opMode = OM_TEST; else
2011 if (ISFLAG("--keep")) keepInputFiles = True; else
2012 if (ISFLAG("--small")) smallMode = True; else
2013 if (ISFLAG("--quiet")) noisy = False; else
2014 if (ISFLAG("--version")) license(); else
2015 if (ISFLAG("--license")) license(); else
2016 if (ISFLAG("--exponential")) workFactor = 1; else
2017 if (ISFLAG("--repetitive-best")) redundant(aa->name); else
2018 if (ISFLAG("--repetitive-fast")) redundant(aa->name); else
2019 if (ISFLAG("--fast")) blockSize100k = 1; else
2020 if (ISFLAG("--best")) blockSize100k = 9; else
2021 if (ISFLAG("--verbose")) verbosity++; else
2022 if (ISFLAG("--help")) { usage ( progName ); exit ( 0 ); }
2024 if (strncmp ( aa->name, "--", 2) == 0) {
2025 fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
2031 if (verbosity > 4) verbosity = 4;
2032 if (opMode == OM_Z && smallMode && blockSize100k > 2)
2035 if (opMode == OM_TEST && srcMode == SM_F2O) {
2036 fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
2041 if (srcMode == SM_F2O && numFileNames == 0)
2044 if (opMode != OM_Z) blockSize100k = 0;
2046 if (srcMode == SM_F2F) {
2047 signal (SIGINT, mySignalCatcher);
2048 signal (SIGTERM, mySignalCatcher);
2050 signal (SIGHUP, mySignalCatcher);
2054 if (opMode == OM_Z) {
2055 if (srcMode == SM_I2O) {
2059 for (aa = argList; aa != NULL; aa = aa->link) {
2060 if (ISFLAG("--")) { decode = False; continue; }
2061 if (aa->name[0] == '-' && decode) continue;
2062 numFilesProcessed++;
2063 compress ( aa->name );
2069 if (opMode == OM_UNZ) {
2070 unzFailsExist = False;
2071 if (srcMode == SM_I2O) {
2072 uncompress ( NULL );
2075 for (aa = argList; aa != NULL; aa = aa->link) {
2076 if (ISFLAG("--")) { decode = False; continue; }
2077 if (aa->name[0] == '-' && decode) continue;
2078 numFilesProcessed++;
2079 uncompress ( aa->name );
2082 if (unzFailsExist) {
2089 testFailsExist = False;
2090 if (srcMode == SM_I2O) {
2094 for (aa = argList; aa != NULL; aa = aa->link) {
2095 if (ISFLAG("--")) { decode = False; continue; }
2096 if (aa->name[0] == '-' && decode) continue;
2097 numFilesProcessed++;
2101 if (testFailsExist && noisy) {
2104 "You can use the `bzip2recover' program to attempt to recover\n"
2105 "data from undamaged sections of corrupted files.\n\n"
2112 /* Free the argument list memory to mollify leak detectors
2113 (eg) Purify, Checker. Serves no other useful purpose.
2116 while (aa != NULL) {
2117 Cell* aa2 = aa->link;
2118 if (aa->name != NULL) free(aa->name);
2127 /*-----------------------------------------------------------*/
2128 /*--- end bzip2.c ---*/
2129 /*-----------------------------------------------------------*/