00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 #define BZ_UNIX 1
00119
00120
00121
00122
00123
00124
00125
00126
00127 #define BZ_LCCWIN32 0
00128
00129 #if defined(_WIN32) && !defined(__CYGWIN__)
00130 #undef BZ_LCCWIN32
00131 #define BZ_LCCWIN32 1
00132 #undef BZ_UNIX
00133 #define BZ_UNIX 0
00134 #endif
00135
00136
00137
00138
00139
00140
00141
00142 #include <stdio.h>
00143 #include <stdlib.h>
00144 #include <string.h>
00145 #include <signal.h>
00146 #include <math.h>
00147 #include <errno.h>
00148 #include <ctype.h>
00149 #include "bzlib.h"
00150
00151 #define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); }
00152 #define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); }
00153 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); }
00154
00155
00156
00157
00158
00159
00160
00161 #if BZ_UNIX
00162 # include <fcntl.h>
00163 # include <sys/types.h>
00164 # include <utime.h>
00165 # include <unistd.h>
00166 # include <sys/stat.h>
00167 # include <sys/times.h>
00168
00169 # define PATH_SEP '/'
00170 # define MY_LSTAT lstat
00171 # define MY_STAT stat
00172 # define MY_S_ISREG S_ISREG
00173 # define MY_S_ISDIR S_ISDIR
00174
00175 # define APPEND_FILESPEC(root, name) \
00176 root=snocString((root), (name))
00177
00178 # define APPEND_FLAG(root, name) \
00179 root=snocString((root), (name))
00180
00181 # define SET_BINARY_MODE(fd)
00182
00183 # ifdef __GNUC__
00184 # define NORETURN __attribute__ ((noreturn))
00185 # else
00186 # define NORETURN
00187 # endif
00188
00189 # ifdef __DJGPP__
00190 # include <io.h>
00191 # include <fcntl.h>
00192 # undef MY_LSTAT
00193 # undef MY_STAT
00194 # define MY_LSTAT stat
00195 # define MY_STAT stat
00196 # undef SET_BINARY_MODE
00197 # define SET_BINARY_MODE(fd) \
00198 do { \
00199 int retVal = setmode ( fileno ( fd ), \
00200 O_BINARY ); \
00201 ERROR_IF_MINUS_ONE ( retVal ); \
00202 } while ( 0 )
00203 # endif
00204
00205 # ifdef __CYGWIN__
00206 # include <io.h>
00207 # include <fcntl.h>
00208 # undef SET_BINARY_MODE
00209 # define SET_BINARY_MODE(fd) \
00210 do { \
00211 int retVal = setmode ( fileno ( fd ), \
00212 O_BINARY ); \
00213 ERROR_IF_MINUS_ONE ( retVal ); \
00214 } while ( 0 )
00215 # endif
00216 #endif
00217
00218
00219
00220 #if BZ_LCCWIN32
00221 # include <io.h>
00222 # include <fcntl.h>
00223 # include <sys\stat.h>
00224
00225 # define NORETURN
00226 # define PATH_SEP '\\'
00227 # define MY_LSTAT _stat
00228 # define MY_STAT _stat
00229 # define MY_S_ISREG(x) ((x) & _S_IFREG)
00230 # define MY_S_ISDIR(x) ((x) & _S_IFDIR)
00231
00232 # define APPEND_FLAG(root, name) \
00233 root=snocString((root), (name))
00234
00235 # define APPEND_FILESPEC(root, name) \
00236 root = snocString ((root), (name))
00237
00238 # define SET_BINARY_MODE(fd) \
00239 do { \
00240 int retVal = setmode ( fileno ( fd ), \
00241 O_BINARY ); \
00242 ERROR_IF_MINUS_ONE ( retVal ); \
00243 } while ( 0 )
00244
00245 #endif
00246
00247
00248
00249
00250
00251
00252
00253 typedef char Char;
00254 typedef unsigned char Bool;
00255 typedef unsigned char UChar;
00256 typedef int Int32;
00257 typedef unsigned int UInt32;
00258 typedef short Int16;
00259 typedef unsigned short UInt16;
00260
00261 #define True ((Bool)1)
00262 #define False ((Bool)0)
00263
00264
00265
00266
00267
00268 typedef int IntNative;
00269
00270
00271
00272
00273
00274
00275 Int32 verbosity;
00276 Bool keepInputFiles, smallMode, deleteOutputOnInterrupt;
00277 Bool forceOverwrite, testFailsExist, unzFailsExist, noisy;
00278 Int32 numFileNames, numFilesProcessed, blockSize100k;
00279 Int32 exitValue;
00280
00281
00282 #define SM_I2O 1
00283 #define SM_F2O 2
00284 #define SM_F2F 3
00285
00286
00287 #define OM_Z 1
00288 #define OM_UNZ 2
00289 #define OM_TEST 3
00290
00291 Int32 opMode;
00292 Int32 srcMode;
00293
00294 #define FILE_NAME_LEN 1034
00295
00296 Int32 longestFileName;
00297 Char inName [FILE_NAME_LEN];
00298 Char outName[FILE_NAME_LEN];
00299 Char tmpName[FILE_NAME_LEN];
00300 Char *progName;
00301 Char progNameReally[FILE_NAME_LEN];
00302 FILE *outputHandleJustInCase;
00303 Int32 workFactor;
00304
00305 static void panic ( Char* ) NORETURN;
00306 static void ioError ( void ) NORETURN;
00307 static void outOfMemory ( void ) NORETURN;
00308 static void configError ( void ) NORETURN;
00309 static void crcError ( void ) NORETURN;
00310 static void cleanUpAndFail ( Int32 ) NORETURN;
00311 static void compressedStreamEOF ( void ) NORETURN;
00312
00313 static void copyFileName ( Char*, Char* );
00314 static void* myMalloc ( Int32 );
00315
00316
00317
00318
00319
00320
00321
00322
00323 typedef
00324 struct { UChar b[8]; }
00325 UInt64;
00326
00327
00328 static
00329 void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 )
00330 {
00331 n->b[7] = (UChar)((hi32 >> 24) & 0xFF);
00332 n->b[6] = (UChar)((hi32 >> 16) & 0xFF);
00333 n->b[5] = (UChar)((hi32 >> 8) & 0xFF);
00334 n->b[4] = (UChar) (hi32 & 0xFF);
00335 n->b[3] = (UChar)((lo32 >> 24) & 0xFF);
00336 n->b[2] = (UChar)((lo32 >> 16) & 0xFF);
00337 n->b[1] = (UChar)((lo32 >> 8) & 0xFF);
00338 n->b[0] = (UChar) (lo32 & 0xFF);
00339 }
00340
00341
00342 static
00343 double uInt64_to_double ( UInt64* n )
00344 {
00345 Int32 i;
00346 double base = 1.0;
00347 double sum = 0.0;
00348 for (i = 0; i < 8; i++) {
00349 sum += base * (double)(n->b[i]);
00350 base *= 256.0;
00351 }
00352 return sum;
00353 }
00354
00355
00356 static
00357 Bool uInt64_isZero ( UInt64* n )
00358 {
00359 Int32 i;
00360 for (i = 0; i < 8; i++)
00361 if (n->b[i] != 0) return 0;
00362 return 1;
00363 }
00364
00365
00366
00367 static
00368 Int32 uInt64_qrm10 ( UInt64* n )
00369 {
00370 UInt32 rem, tmp;
00371 Int32 i;
00372 rem = 0;
00373 for (i = 7; i >= 0; i--) {
00374 tmp = rem * 256 + n->b[i];
00375 n->b[i] = tmp / 10;
00376 rem = tmp % 10;
00377 }
00378 return rem;
00379 }
00380
00381
00382
00383
00384
00385 static
00386 void uInt64_toAscii ( char* outbuf, UInt64* n )
00387 {
00388 Int32 i, q;
00389 UChar buf[32];
00390 Int32 nBuf = 0;
00391 UInt64 n_copy = *n;
00392 do {
00393 q = uInt64_qrm10 ( &n_copy );
00394 buf[nBuf] = q + '0';
00395 nBuf++;
00396 } while (!uInt64_isZero(&n_copy));
00397 outbuf[nBuf] = 0;
00398 for (i = 0; i < nBuf; i++)
00399 outbuf[i] = buf[nBuf-i-1];
00400 }
00401
00402
00403
00404
00405
00406
00407
00408 static
00409 Bool myfeof ( FILE* f )
00410 {
00411 Int32 c = fgetc ( f );
00412 if (c == EOF) return True;
00413 ungetc ( c, f );
00414 return False;
00415 }
00416
00417
00418
00419 static
00420 void compressStream ( FILE *stream, FILE *zStream )
00421 {
00422 BZFILE* bzf = NULL;
00423 UChar ibuf[5000];
00424 Int32 nIbuf;
00425 UInt32 nbytes_in_lo32, nbytes_in_hi32;
00426 UInt32 nbytes_out_lo32, nbytes_out_hi32;
00427 Int32 bzerr, bzerr_dummy, ret;
00428
00429 SET_BINARY_MODE(stream);
00430 SET_BINARY_MODE(zStream);
00431
00432 if (ferror(stream)) goto errhandler_io;
00433 if (ferror(zStream)) goto errhandler_io;
00434
00435 bzf = BZ2_bzWriteOpen ( &bzerr, zStream,
00436 blockSize100k, verbosity, workFactor );
00437 if (bzerr != BZ_OK) goto errhandler;
00438
00439 if (verbosity >= 2) fprintf ( stderr, "\n" );
00440
00441 while (True) {
00442
00443 if (myfeof(stream)) break;
00444 nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream );
00445 if (ferror(stream)) goto errhandler_io;
00446 if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf );
00447 if (bzerr != BZ_OK) goto errhandler;
00448
00449 }
00450
00451 BZ2_bzWriteClose64 ( &bzerr, bzf, 0,
00452 &nbytes_in_lo32, &nbytes_in_hi32,
00453 &nbytes_out_lo32, &nbytes_out_hi32 );
00454 if (bzerr != BZ_OK) goto errhandler;
00455
00456 if (ferror(zStream)) goto errhandler_io;
00457 ret = fflush ( zStream );
00458 if (ret == EOF) goto errhandler_io;
00459 if (zStream != stdout) {
00460 ret = fclose ( zStream );
00461 outputHandleJustInCase = NULL;
00462 if (ret == EOF) goto errhandler_io;
00463 }
00464 outputHandleJustInCase = NULL;
00465 if (ferror(stream)) goto errhandler_io;
00466 ret = fclose ( stream );
00467 if (ret == EOF) goto errhandler_io;
00468
00469 if (verbosity >= 1) {
00470 if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) {
00471 fprintf ( stderr, " no data compressed.\n");
00472 } else {
00473 Char buf_nin[32], buf_nout[32];
00474 UInt64 nbytes_in, nbytes_out;
00475 double nbytes_in_d, nbytes_out_d;
00476 uInt64_from_UInt32s ( &nbytes_in,
00477 nbytes_in_lo32, nbytes_in_hi32 );
00478 uInt64_from_UInt32s ( &nbytes_out,
00479 nbytes_out_lo32, nbytes_out_hi32 );
00480 nbytes_in_d = uInt64_to_double ( &nbytes_in );
00481 nbytes_out_d = uInt64_to_double ( &nbytes_out );
00482 uInt64_toAscii ( buf_nin, &nbytes_in );
00483 uInt64_toAscii ( buf_nout, &nbytes_out );
00484 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, "
00485 "%5.2f%% saved, %s in, %s out.\n",
00486 nbytes_in_d / nbytes_out_d,
00487 (8.0 * nbytes_out_d) / nbytes_in_d,
00488 100.0 * (1.0 - nbytes_out_d / nbytes_in_d),
00489 buf_nin,
00490 buf_nout
00491 );
00492 }
00493 }
00494
00495 return;
00496
00497 errhandler:
00498 BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1,
00499 &nbytes_in_lo32, &nbytes_in_hi32,
00500 &nbytes_out_lo32, &nbytes_out_hi32 );
00501 switch (bzerr) {
00502 case BZ_CONFIG_ERROR:
00503 configError(); break;
00504 case BZ_MEM_ERROR:
00505 outOfMemory (); break;
00506 case BZ_IO_ERROR:
00507 errhandler_io:
00508 ioError(); break;
00509 default:
00510 panic ( "compress:unexpected error" );
00511 }
00512
00513 panic ( "compress:end" );
00514
00515 }
00516
00517
00518
00519
00520 static
00521 Bool uncompressStream ( FILE *zStream, FILE *stream )
00522 {
00523 BZFILE* bzf = NULL;
00524 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i;
00525 UChar obuf[5000];
00526 UChar unused[BZ_MAX_UNUSED];
00527 Int32 nUnused;
00528 UChar* unusedTmp;
00529
00530 nUnused = 0;
00531 streamNo = 0;
00532
00533 SET_BINARY_MODE(stream);
00534 SET_BINARY_MODE(zStream);
00535
00536 if (ferror(stream)) goto errhandler_io;
00537 if (ferror(zStream)) goto errhandler_io;
00538
00539 while (True) {
00540
00541 bzf = BZ2_bzReadOpen (
00542 &bzerr, zStream, verbosity,
00543 (int)smallMode, unused, nUnused
00544 );
00545 if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
00546 streamNo++;
00547
00548 while (bzerr == BZ_OK) {
00549 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
00550 if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat;
00551 if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0)
00552 fwrite ( obuf, sizeof(UChar), nread, stream );
00553 if (ferror(stream)) goto errhandler_io;
00554 }
00555 if (bzerr != BZ_STREAM_END) goto errhandler;
00556
00557 BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
00558 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
00559
00560 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
00561
00562 BZ2_bzReadClose ( &bzerr, bzf );
00563 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" );
00564
00565 if (nUnused == 0 && myfeof(zStream)) break;
00566 }
00567
00568 closeok:
00569 if (ferror(zStream)) goto errhandler_io;
00570 ret = fclose ( zStream );
00571 if (ret == EOF) goto errhandler_io;
00572
00573 if (ferror(stream)) goto errhandler_io;
00574 ret = fflush ( stream );
00575 if (ret != 0) goto errhandler_io;
00576 if (stream != stdout) {
00577 ret = fclose ( stream );
00578 outputHandleJustInCase = NULL;
00579 if (ret == EOF) goto errhandler_io;
00580 }
00581 outputHandleJustInCase = NULL;
00582 if (verbosity >= 2) fprintf ( stderr, "\n " );
00583 return True;
00584
00585 trycat:
00586 if (forceOverwrite) {
00587 rewind(zStream);
00588 while (True) {
00589 if (myfeof(zStream)) break;
00590 nread = fread ( obuf, sizeof(UChar), 5000, zStream );
00591 if (ferror(zStream)) goto errhandler_io;
00592 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream );
00593 if (ferror(stream)) goto errhandler_io;
00594 }
00595 goto closeok;
00596 }
00597
00598 errhandler:
00599 BZ2_bzReadClose ( &bzerr_dummy, bzf );
00600 switch (bzerr) {
00601 case BZ_CONFIG_ERROR:
00602 configError(); break;
00603 case BZ_IO_ERROR:
00604 errhandler_io:
00605 ioError(); break;
00606 case BZ_DATA_ERROR:
00607 crcError();
00608 case BZ_MEM_ERROR:
00609 outOfMemory();
00610 case BZ_UNEXPECTED_EOF:
00611 compressedStreamEOF();
00612 case BZ_DATA_ERROR_MAGIC:
00613 if (zStream != stdin) fclose(zStream);
00614 if (stream != stdout) fclose(stream);
00615 if (streamNo == 1) {
00616 return False;
00617 } else {
00618 if (noisy)
00619 fprintf ( stderr,
00620 "\n%s: %s: trailing garbage after EOF ignored\n",
00621 progName, inName );
00622 return True;
00623 }
00624 default:
00625 panic ( "decompress:unexpected error" );
00626 }
00627
00628 panic ( "decompress:end" );
00629 return True;
00630 }
00631
00632
00633
00634 static
00635 Bool testStream ( FILE *zStream )
00636 {
00637 BZFILE* bzf = NULL;
00638 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i;
00639 UChar obuf[5000];
00640 UChar unused[BZ_MAX_UNUSED];
00641 Int32 nUnused;
00642 UChar* unusedTmp;
00643
00644 nUnused = 0;
00645 streamNo = 0;
00646
00647 SET_BINARY_MODE(zStream);
00648 if (ferror(zStream)) goto errhandler_io;
00649
00650 while (True) {
00651
00652 bzf = BZ2_bzReadOpen (
00653 &bzerr, zStream, verbosity,
00654 (int)smallMode, unused, nUnused
00655 );
00656 if (bzf == NULL || bzerr != BZ_OK) goto errhandler;
00657 streamNo++;
00658
00659 while (bzerr == BZ_OK) {
00660 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 );
00661 if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler;
00662 }
00663 if (bzerr != BZ_STREAM_END) goto errhandler;
00664
00665 BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused );
00666 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
00667
00668 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i];
00669
00670 BZ2_bzReadClose ( &bzerr, bzf );
00671 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" );
00672 if (nUnused == 0 && myfeof(zStream)) break;
00673
00674 }
00675
00676 if (ferror(zStream)) goto errhandler_io;
00677 ret = fclose ( zStream );
00678 if (ret == EOF) goto errhandler_io;
00679
00680 if (verbosity >= 2) fprintf ( stderr, "\n " );
00681 return True;
00682
00683 errhandler:
00684 BZ2_bzReadClose ( &bzerr_dummy, bzf );
00685 if (verbosity == 0)
00686 fprintf ( stderr, "%s: %s: ", progName, inName );
00687 switch (bzerr) {
00688 case BZ_CONFIG_ERROR:
00689 configError(); break;
00690 case BZ_IO_ERROR:
00691 errhandler_io:
00692 ioError(); break;
00693 case BZ_DATA_ERROR:
00694 fprintf ( stderr,
00695 "data integrity (CRC) error in data\n" );
00696 return False;
00697 case BZ_MEM_ERROR:
00698 outOfMemory();
00699 case BZ_UNEXPECTED_EOF:
00700 fprintf ( stderr,
00701 "file ends unexpectedly\n" );
00702 return False;
00703 case BZ_DATA_ERROR_MAGIC:
00704 if (zStream != stdin) fclose(zStream);
00705 if (streamNo == 1) {
00706 fprintf ( stderr,
00707 "bad magic number (file not created by bzip2)\n" );
00708 return False;
00709 } else {
00710 if (noisy)
00711 fprintf ( stderr,
00712 "trailing garbage after EOF ignored\n" );
00713 return True;
00714 }
00715 default:
00716 panic ( "test:unexpected error" );
00717 }
00718
00719 panic ( "test:end" );
00720 return True;
00721 }
00722
00723
00724
00725
00726
00727
00728
00729 static
00730 void setExit ( Int32 v )
00731 {
00732 if (v > exitValue) exitValue = v;
00733 }
00734
00735
00736
00737 static
00738 void cadvise ( void )
00739 {
00740 if (noisy)
00741 fprintf (
00742 stderr,
00743 "\nIt is possible that the compressed file(s) have become corrupted.\n"
00744 "You can use the -tvv option to test integrity of such files.\n\n"
00745 "You can use the `bzip2recover' program to attempt to recover\n"
00746 "data from undamaged sections of corrupted files.\n\n"
00747 );
00748 }
00749
00750
00751
00752 static
00753 void showFileNames ( void )
00754 {
00755 if (noisy)
00756 fprintf (
00757 stderr,
00758 "\tInput file = %s, output file = %s\n",
00759 inName, outName
00760 );
00761 }
00762
00763
00764
00765 static
00766 void cleanUpAndFail ( Int32 ec )
00767 {
00768 IntNative retVal;
00769 struct MY_STAT statBuf;
00770
00771 if ( srcMode == SM_F2F
00772 && opMode != OM_TEST
00773 && deleteOutputOnInterrupt ) {
00774
00775
00776
00777
00778
00779
00780 retVal = MY_STAT ( inName, &statBuf );
00781 if (retVal == 0) {
00782 if (noisy)
00783 fprintf ( stderr,
00784 "%s: Deleting output file %s, if it exists.\n",
00785 progName, outName );
00786 if (outputHandleJustInCase != NULL)
00787 fclose ( outputHandleJustInCase );
00788 retVal = remove ( outName );
00789 if (retVal != 0)
00790 fprintf ( stderr,
00791 "%s: WARNING: deletion of output file "
00792 "(apparently) failed.\n",
00793 progName );
00794 } else {
00795 fprintf ( stderr,
00796 "%s: WARNING: deletion of output file suppressed\n",
00797 progName );
00798 fprintf ( stderr,
00799 "%s: since input file no longer exists. Output file\n",
00800 progName );
00801 fprintf ( stderr,
00802 "%s: `%s' may be incomplete.\n",
00803 progName, outName );
00804 fprintf ( stderr,
00805 "%s: I suggest doing an integrity test (bzip2 -tv)"
00806 " of it.\n",
00807 progName );
00808 }
00809 }
00810
00811 if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) {
00812 fprintf ( stderr,
00813 "%s: WARNING: some files have not been processed:\n"
00814 "%s: %d specified on command line, %d not processed yet.\n\n",
00815 progName, progName,
00816 numFileNames, numFileNames - numFilesProcessed );
00817 }
00818 setExit(ec);
00819 exit(exitValue);
00820 }
00821
00822
00823
00824 static
00825 void panic ( Char* s )
00826 {
00827 fprintf ( stderr,
00828 "\n%s: PANIC -- internal consistency error:\n"
00829 "\t%s\n"
00830 "\tThis is a BUG. Please report it to me at:\n"
00831 "\tjseward@acm.org\n",
00832 progName, s );
00833 showFileNames();
00834 cleanUpAndFail( 3 );
00835 }
00836
00837
00838
00839 static
00840 void crcError ( void )
00841 {
00842 fprintf ( stderr,
00843 "\n%s: Data integrity error when decompressing.\n",
00844 progName );
00845 showFileNames();
00846 cadvise();
00847 cleanUpAndFail( 2 );
00848 }
00849
00850
00851
00852 static
00853 void compressedStreamEOF ( void )
00854 {
00855 if (noisy) {
00856 fprintf ( stderr,
00857 "\n%s: Compressed file ends unexpectedly;\n\t"
00858 "perhaps it is corrupted? *Possible* reason follows.\n",
00859 progName );
00860 perror ( progName );
00861 showFileNames();
00862 cadvise();
00863 }
00864 cleanUpAndFail( 2 );
00865 }
00866
00867
00868
00869 static
00870 void ioError ( void )
00871 {
00872 fprintf ( stderr,
00873 "\n%s: I/O or other error, bailing out. "
00874 "Possible reason follows.\n",
00875 progName );
00876 perror ( progName );
00877 showFileNames();
00878 cleanUpAndFail( 1 );
00879 }
00880
00881
00882
00883 static
00884 void mySignalCatcher ( IntNative n )
00885 {
00886 fprintf ( stderr,
00887 "\n%s: Control-C or similar caught, quitting.\n",
00888 progName );
00889 cleanUpAndFail(1);
00890 }
00891
00892
00893
00894 static
00895 void mySIGSEGVorSIGBUScatcher ( IntNative n )
00896 {
00897 if (opMode == OM_Z)
00898 fprintf (
00899 stderr,
00900 "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n"
00901 "\n"
00902 " Possible causes are (most likely first):\n"
00903 " (1) This computer has unreliable memory or cache hardware\n"
00904 " (a surprisingly common problem; try a different machine.)\n"
00905 " (2) A bug in the compiler used to create this executable\n"
00906 " (unlikely, if you didn't compile bzip2 yourself.)\n"
00907 " (3) A real bug in bzip2 -- I hope this should never be the case.\n"
00908 " The user's manual, Section 4.3, has more info on (1) and (2).\n"
00909 " \n"
00910 " If you suspect this is a bug in bzip2, or are unsure about (1)\n"
00911 " or (2), feel free to report it to me at: jseward@acm.org.\n"
00912 " Section 4.3 of the user's manual describes the info a useful\n"
00913 " bug report should have. If the manual is available on your\n"
00914 " system, please try and read it before mailing me. If you don't\n"
00915 " have the manual or can't be bothered to read it, mail me anyway.\n"
00916 "\n",
00917 progName );
00918 else
00919 fprintf (
00920 stderr,
00921 "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n"
00922 "\n"
00923 " Possible causes are (most likely first):\n"
00924 " (1) The compressed data is corrupted, and bzip2's usual checks\n"
00925 " failed to detect this. Try bzip2 -tvv my_file.bz2.\n"
00926 " (2) This computer has unreliable memory or cache hardware\n"
00927 " (a surprisingly common problem; try a different machine.)\n"
00928 " (3) A bug in the compiler used to create this executable\n"
00929 " (unlikely, if you didn't compile bzip2 yourself.)\n"
00930 " (4) A real bug in bzip2 -- I hope this should never be the case.\n"
00931 " The user's manual, Section 4.3, has more info on (2) and (3).\n"
00932 " \n"
00933 " If you suspect this is a bug in bzip2, or are unsure about (2)\n"
00934 " or (3), feel free to report it to me at: jseward@acm.org.\n"
00935 " Section 4.3 of the user's manual describes the info a useful\n"
00936 " bug report should have. If the manual is available on your\n"
00937 " system, please try and read it before mailing me. If you don't\n"
00938 " have the manual or can't be bothered to read it, mail me anyway.\n"
00939 "\n",
00940 progName );
00941
00942 showFileNames();
00943 if (opMode == OM_Z)
00944 cleanUpAndFail( 3 ); else
00945 { cadvise(); cleanUpAndFail( 2 ); }
00946 }
00947
00948
00949
00950 static
00951 void outOfMemory ( void )
00952 {
00953 fprintf ( stderr,
00954 "\n%s: couldn't allocate enough memory\n",
00955 progName );
00956 showFileNames();
00957 cleanUpAndFail(1);
00958 }
00959
00960
00961
00962 static
00963 void configError ( void )
00964 {
00965 fprintf ( stderr,
00966 "bzip2: I'm not configured correctly for this platform!\n"
00967 "\tI require Int32, Int16 and Char to have sizes\n"
00968 "\tof 4, 2 and 1 bytes to run properly, and they don't.\n"
00969 "\tProbably you can fix this by defining them correctly,\n"
00970 "\tand recompiling. Bye!\n" );
00971 setExit(3);
00972 exit(exitValue);
00973 }
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986 static
00987 void pad ( Char *s )
00988 {
00989 Int32 i;
00990 if ( (Int32)strlen(s) >= longestFileName ) return;
00991 for (i = 1; i <= longestFileName - (Int32)strlen(s); i++)
00992 fprintf ( stderr, " " );
00993 }
00994
00995
00996
00997 static
00998 void copyFileName ( Char* to, Char* from )
00999 {
01000 if ( strlen(from) > FILE_NAME_LEN-10 ) {
01001 fprintf (
01002 stderr,
01003 "bzip2: file name\n`%s'\n"
01004 "is suspiciously (more than %d chars) long.\n"
01005 "Try using a reasonable file name instead. Sorry! :-)\n",
01006 from, FILE_NAME_LEN-10
01007 );
01008 setExit(1);
01009 exit(exitValue);
01010 }
01011
01012 strncpy(to,from,FILE_NAME_LEN-10);
01013 to[FILE_NAME_LEN-10]='\0';
01014 }
01015
01016
01017
01018 static
01019 Bool fileExists ( Char* name )
01020 {
01021 FILE *tmp = fopen ( name, "rb" );
01022 Bool exists = (tmp != NULL);
01023 if (tmp != NULL) fclose ( tmp );
01024 return exists;
01025 }
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038 FILE* fopen_output_safely ( Char* name, const char* mode )
01039 {
01040 # if BZ_UNIX
01041 FILE* fp;
01042 IntNative fh;
01043 fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR);
01044 if (fh == -1) return NULL;
01045 fp = fdopen(fh, mode);
01046 if (fp == NULL) close(fh);
01047 return fp;
01048 # else
01049 return fopen(name, mode);
01050 # endif
01051 }
01052
01053
01054
01055
01056
01057
01058 static
01059 Bool notAStandardFile ( Char* name )
01060 {
01061 IntNative i;
01062 struct MY_STAT statBuf;
01063
01064 i = MY_LSTAT ( name, &statBuf );
01065 if (i != 0) return True;
01066 if (MY_S_ISREG(statBuf.st_mode)) return False;
01067 return True;
01068 }
01069
01070
01071
01072
01073
01074
01075 static
01076 Int32 countHardLinks ( Char* name )
01077 {
01078 IntNative i;
01079 struct MY_STAT statBuf;
01080
01081 i = MY_LSTAT ( name, &statBuf );
01082 if (i != 0) return 0;
01083 return (statBuf.st_nlink - 1);
01084 }
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109
01110 #if BZ_UNIX
01111 static
01112 struct MY_STAT fileMetaInfo;
01113 #endif
01114
01115 static
01116 void saveInputFileMetaInfo ( Char *srcName )
01117 {
01118 # if BZ_UNIX
01119 IntNative retVal;
01120
01121 retVal = MY_STAT( srcName, &fileMetaInfo );
01122 ERROR_IF_NOT_ZERO ( retVal );
01123 # endif
01124 }
01125
01126
01127 static
01128 void applySavedMetaInfoToOutputFile ( Char *dstName )
01129 {
01130 # if BZ_UNIX
01131 IntNative retVal;
01132 struct utimbuf uTimBuf;
01133
01134 uTimBuf.actime = fileMetaInfo.st_atime;
01135 uTimBuf.modtime = fileMetaInfo.st_mtime;
01136
01137 retVal = chmod ( dstName, fileMetaInfo.st_mode );
01138 ERROR_IF_NOT_ZERO ( retVal );
01139
01140 retVal = utime ( dstName, &uTimBuf );
01141 ERROR_IF_NOT_ZERO ( retVal );
01142
01143 retVal = chown ( dstName, fileMetaInfo.st_uid, fileMetaInfo.st_gid );
01144
01145
01146
01147 # endif
01148 }
01149
01150
01151
01152 static
01153 Bool containsDubiousChars ( Char* name )
01154 {
01155 # if BZ_UNIX
01156
01157
01158
01159 return False;
01160 # else
01161
01162
01163
01164 for (; *name != '\0'; name++)
01165 if (*name == '?' || *name == '*') return True;
01166 return False;
01167 # endif
01168 }
01169
01170
01171
01172 #define BZ_N_SUFFIX_PAIRS 4
01173
01174 Char* zSuffix[BZ_N_SUFFIX_PAIRS]
01175 = { ".bz2", ".bz", ".tbz2", ".tbz" };
01176 Char* unzSuffix[BZ_N_SUFFIX_PAIRS]
01177 = { "", "", ".tar", ".tar" };
01178
01179 static
01180 Bool hasSuffix ( Char* s, Char* suffix )
01181 {
01182 Int32 ns = strlen(s);
01183 Int32 nx = strlen(suffix);
01184 if (ns < nx) return False;
01185 if (strcmp(s + ns - nx, suffix) == 0) return True;
01186 return False;
01187 }
01188
01189 static
01190 Bool mapSuffix ( Char* name,
01191 Char* oldSuffix, Char* newSuffix )
01192 {
01193 if (!hasSuffix(name,oldSuffix)) return False;
01194 name[strlen(name)-strlen(oldSuffix)] = 0;
01195 strcat ( name, newSuffix );
01196 return True;
01197 }
01198
01199
01200
01201 static
01202 void compress ( Char *name )
01203 {
01204 FILE *inStr;
01205 FILE *outStr;
01206 Int32 n, i;
01207 struct MY_STAT statBuf;
01208
01209 deleteOutputOnInterrupt = False;
01210
01211 if (name == NULL && srcMode != SM_I2O)
01212 panic ( "compress: bad modes\n" );
01213
01214 switch (srcMode) {
01215 case SM_I2O:
01216 copyFileName ( inName, "(stdin)" );
01217 copyFileName ( outName, "(stdout)" );
01218 break;
01219 case SM_F2F:
01220 copyFileName ( inName, name );
01221 copyFileName ( outName, name );
01222 strcat ( outName, ".bz2" );
01223 break;
01224 case SM_F2O:
01225 copyFileName ( inName, name );
01226 copyFileName ( outName, "(stdout)" );
01227 break;
01228 }
01229
01230 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
01231 if (noisy)
01232 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
01233 progName, inName );
01234 setExit(1);
01235 return;
01236 }
01237 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
01238 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01239 progName, inName, strerror(errno) );
01240 setExit(1);
01241 return;
01242 }
01243 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) {
01244 if (hasSuffix(inName, zSuffix[i])) {
01245 if (noisy)
01246 fprintf ( stderr,
01247 "%s: Input file %s already has %s suffix.\n",
01248 progName, inName, zSuffix[i] );
01249 setExit(1);
01250 return;
01251 }
01252 }
01253 if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
01254 MY_STAT(inName, &statBuf);
01255 if ( MY_S_ISDIR(statBuf.st_mode) ) {
01256 fprintf( stderr,
01257 "%s: Input file %s is a directory.\n",
01258 progName,inName);
01259 setExit(1);
01260 return;
01261 }
01262 }
01263 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
01264 if (noisy)
01265 fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
01266 progName, inName );
01267 setExit(1);
01268 return;
01269 }
01270 if ( srcMode == SM_F2F && fileExists ( outName ) ) {
01271 if (forceOverwrite) {
01272 remove(outName);
01273 } else {
01274 fprintf ( stderr, "%s: Output file %s already exists.\n",
01275 progName, outName );
01276 setExit(1);
01277 return;
01278 }
01279 }
01280 if ( srcMode == SM_F2F && !forceOverwrite &&
01281 (n=countHardLinks ( inName )) > 0) {
01282 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
01283 progName, inName, n, n > 1 ? "s" : "" );
01284 setExit(1);
01285 return;
01286 }
01287
01288 if ( srcMode == SM_F2F ) {
01289
01290
01291 saveInputFileMetaInfo ( inName );
01292 }
01293
01294 switch ( srcMode ) {
01295
01296 case SM_I2O:
01297 inStr = stdin;
01298 outStr = stdout;
01299 if ( isatty ( fileno ( stdout ) ) ) {
01300 fprintf ( stderr,
01301 "%s: I won't write compressed data to a terminal.\n",
01302 progName );
01303 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
01304 progName, progName );
01305 setExit(1);
01306 return;
01307 };
01308 break;
01309
01310 case SM_F2O:
01311 inStr = fopen ( inName, "rb" );
01312 outStr = stdout;
01313 if ( isatty ( fileno ( stdout ) ) ) {
01314 fprintf ( stderr,
01315 "%s: I won't write compressed data to a terminal.\n",
01316 progName );
01317 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
01318 progName, progName );
01319 if ( inStr != NULL ) fclose ( inStr );
01320 setExit(1);
01321 return;
01322 };
01323 if ( inStr == NULL ) {
01324 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01325 progName, inName, strerror(errno) );
01326 setExit(1);
01327 return;
01328 };
01329 break;
01330
01331 case SM_F2F:
01332 inStr = fopen ( inName, "rb" );
01333 outStr = fopen_output_safely ( outName, "wb" );
01334 if ( outStr == NULL) {
01335 fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
01336 progName, outName, strerror(errno) );
01337 if ( inStr != NULL ) fclose ( inStr );
01338 setExit(1);
01339 return;
01340 }
01341 if ( inStr == NULL ) {
01342 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01343 progName, inName, strerror(errno) );
01344 if ( outStr != NULL ) fclose ( outStr );
01345 setExit(1);
01346 return;
01347 };
01348 break;
01349
01350 default:
01351 panic ( "compress: bad srcMode" );
01352 break;
01353 }
01354
01355 if (verbosity >= 1) {
01356 fprintf ( stderr, " %s: ", inName );
01357 pad ( inName );
01358 fflush ( stderr );
01359 }
01360
01361
01362 outputHandleJustInCase = outStr;
01363 deleteOutputOnInterrupt = True;
01364 compressStream ( inStr, outStr );
01365 outputHandleJustInCase = NULL;
01366
01367
01368 if ( srcMode == SM_F2F ) {
01369 applySavedMetaInfoToOutputFile ( outName );
01370 deleteOutputOnInterrupt = False;
01371 if ( !keepInputFiles ) {
01372 IntNative retVal = remove ( inName );
01373 ERROR_IF_NOT_ZERO ( retVal );
01374 }
01375 }
01376
01377 deleteOutputOnInterrupt = False;
01378 }
01379
01380
01381
01382 static
01383 void uncompress ( Char *name )
01384 {
01385 FILE *inStr;
01386 FILE *outStr;
01387 Int32 n, i;
01388 Bool magicNumberOK;
01389 Bool cantGuess;
01390 struct MY_STAT statBuf;
01391
01392 deleteOutputOnInterrupt = False;
01393
01394 if (name == NULL && srcMode != SM_I2O)
01395 panic ( "uncompress: bad modes\n" );
01396
01397 cantGuess = False;
01398 switch (srcMode) {
01399 case SM_I2O:
01400 copyFileName ( inName, "(stdin)" );
01401 copyFileName ( outName, "(stdout)" );
01402 break;
01403 case SM_F2F:
01404 copyFileName ( inName, name );
01405 copyFileName ( outName, name );
01406 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++)
01407 if (mapSuffix(outName,zSuffix[i],unzSuffix[i]))
01408 goto zzz;
01409 cantGuess = True;
01410 strcat ( outName, ".out" );
01411 break;
01412 case SM_F2O:
01413 copyFileName ( inName, name );
01414 copyFileName ( outName, "(stdout)" );
01415 break;
01416 }
01417
01418 zzz:
01419 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
01420 if (noisy)
01421 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
01422 progName, inName );
01423 setExit(1);
01424 return;
01425 }
01426 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
01427 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01428 progName, inName, strerror(errno) );
01429 setExit(1);
01430 return;
01431 }
01432 if ( srcMode == SM_F2F || srcMode == SM_F2O ) {
01433 MY_STAT(inName, &statBuf);
01434 if ( MY_S_ISDIR(statBuf.st_mode) ) {
01435 fprintf( stderr,
01436 "%s: Input file %s is a directory.\n",
01437 progName,inName);
01438 setExit(1);
01439 return;
01440 }
01441 }
01442 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) {
01443 if (noisy)
01444 fprintf ( stderr, "%s: Input file %s is not a normal file.\n",
01445 progName, inName );
01446 setExit(1);
01447 return;
01448 }
01449 if ( cantGuess ) {
01450 if (noisy)
01451 fprintf ( stderr,
01452 "%s: Can't guess original name for %s -- using %s\n",
01453 progName, inName, outName );
01454
01455 }
01456 if ( srcMode == SM_F2F && fileExists ( outName ) ) {
01457 if (forceOverwrite) {
01458 remove(outName);
01459 } else {
01460 fprintf ( stderr, "%s: Output file %s already exists.\n",
01461 progName, outName );
01462 setExit(1);
01463 return;
01464 }
01465 }
01466 if ( srcMode == SM_F2F && !forceOverwrite &&
01467 (n=countHardLinks ( inName ) ) > 0) {
01468 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n",
01469 progName, inName, n, n > 1 ? "s" : "" );
01470 setExit(1);
01471 return;
01472 }
01473
01474 if ( srcMode == SM_F2F ) {
01475
01476
01477 saveInputFileMetaInfo ( inName );
01478 }
01479
01480 switch ( srcMode ) {
01481
01482 case SM_I2O:
01483 inStr = stdin;
01484 outStr = stdout;
01485 if ( isatty ( fileno ( stdin ) ) ) {
01486 fprintf ( stderr,
01487 "%s: I won't read compressed data from a terminal.\n",
01488 progName );
01489 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
01490 progName, progName );
01491 setExit(1);
01492 return;
01493 };
01494 break;
01495
01496 case SM_F2O:
01497 inStr = fopen ( inName, "rb" );
01498 outStr = stdout;
01499 if ( inStr == NULL ) {
01500 fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
01501 progName, inName, strerror(errno) );
01502 if ( inStr != NULL ) fclose ( inStr );
01503 setExit(1);
01504 return;
01505 };
01506 break;
01507
01508 case SM_F2F:
01509 inStr = fopen ( inName, "rb" );
01510 outStr = fopen_output_safely ( outName, "wb" );
01511 if ( outStr == NULL) {
01512 fprintf ( stderr, "%s: Can't create output file %s: %s.\n",
01513 progName, outName, strerror(errno) );
01514 if ( inStr != NULL ) fclose ( inStr );
01515 setExit(1);
01516 return;
01517 }
01518 if ( inStr == NULL ) {
01519 fprintf ( stderr, "%s: Can't open input file %s: %s.\n",
01520 progName, inName, strerror(errno) );
01521 if ( outStr != NULL ) fclose ( outStr );
01522 setExit(1);
01523 return;
01524 };
01525 break;
01526
01527 default:
01528 panic ( "uncompress: bad srcMode" );
01529 break;
01530 }
01531
01532 if (verbosity >= 1) {
01533 fprintf ( stderr, " %s: ", inName );
01534 pad ( inName );
01535 fflush ( stderr );
01536 }
01537
01538
01539 outputHandleJustInCase = outStr;
01540 deleteOutputOnInterrupt = True;
01541 magicNumberOK = uncompressStream ( inStr, outStr );
01542 outputHandleJustInCase = NULL;
01543
01544
01545 if ( magicNumberOK ) {
01546 if ( srcMode == SM_F2F ) {
01547 applySavedMetaInfoToOutputFile ( outName );
01548 deleteOutputOnInterrupt = False;
01549 if ( !keepInputFiles ) {
01550 IntNative retVal = remove ( inName );
01551 ERROR_IF_NOT_ZERO ( retVal );
01552 }
01553 }
01554 } else {
01555 unzFailsExist = True;
01556 deleteOutputOnInterrupt = False;
01557 if ( srcMode == SM_F2F ) {
01558 IntNative retVal = remove ( outName );
01559 ERROR_IF_NOT_ZERO ( retVal );
01560 }
01561 }
01562 deleteOutputOnInterrupt = False;
01563
01564 if ( magicNumberOK ) {
01565 if (verbosity >= 1)
01566 fprintf ( stderr, "done\n" );
01567 } else {
01568 setExit(2);
01569 if (verbosity >= 1)
01570 fprintf ( stderr, "not a bzip2 file.\n" ); else
01571 fprintf ( stderr,
01572 "%s: %s is not a bzip2 file.\n",
01573 progName, inName );
01574 }
01575
01576 }
01577
01578
01579
01580 static
01581 void testf ( Char *name )
01582 {
01583 FILE *inStr;
01584 Bool allOK;
01585 struct MY_STAT statBuf;
01586
01587 deleteOutputOnInterrupt = False;
01588
01589 if (name == NULL && srcMode != SM_I2O)
01590 panic ( "testf: bad modes\n" );
01591
01592 copyFileName ( outName, "(none)" );
01593 switch (srcMode) {
01594 case SM_I2O: copyFileName ( inName, "(stdin)" ); break;
01595 case SM_F2F: copyFileName ( inName, name ); break;
01596 case SM_F2O: copyFileName ( inName, name ); break;
01597 }
01598
01599 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) {
01600 if (noisy)
01601 fprintf ( stderr, "%s: There are no files matching `%s'.\n",
01602 progName, inName );
01603 setExit(1);
01604 return;
01605 }
01606 if ( srcMode != SM_I2O && !fileExists ( inName ) ) {
01607 fprintf ( stderr, "%s: Can't open input %s: %s.\n",
01608 progName, inName, strerror(errno) );
01609 setExit(1);
01610 return;
01611 }
01612 if ( srcMode != SM_I2O ) {
01613 MY_STAT(inName, &statBuf);
01614 if ( MY_S_ISDIR(statBuf.st_mode) ) {
01615 fprintf( stderr,
01616 "%s: Input file %s is a directory.\n",
01617 progName,inName);
01618 setExit(1);
01619 return;
01620 }
01621 }
01622
01623 switch ( srcMode ) {
01624
01625 case SM_I2O:
01626 if ( isatty ( fileno ( stdin ) ) ) {
01627 fprintf ( stderr,
01628 "%s: I won't read compressed data from a terminal.\n",
01629 progName );
01630 fprintf ( stderr, "%s: For help, type: `%s --help'.\n",
01631 progName, progName );
01632 setExit(1);
01633 return;
01634 };
01635 inStr = stdin;
01636 break;
01637
01638 case SM_F2O: case SM_F2F:
01639 inStr = fopen ( inName, "rb" );
01640 if ( inStr == NULL ) {
01641 fprintf ( stderr, "%s: Can't open input file %s:%s.\n",
01642 progName, inName, strerror(errno) );
01643 setExit(1);
01644 return;
01645 };
01646 break;
01647
01648 default:
01649 panic ( "testf: bad srcMode" );
01650 break;
01651 }
01652
01653 if (verbosity >= 1) {
01654 fprintf ( stderr, " %s: ", inName );
01655 pad ( inName );
01656 fflush ( stderr );
01657 }
01658
01659
01660 outputHandleJustInCase = NULL;
01661 allOK = testStream ( inStr );
01662
01663 if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" );
01664 if (!allOK) testFailsExist = True;
01665 }
01666
01667
01668
01669 static
01670 void license ( void )
01671 {
01672 fprintf ( stderr,
01673
01674 "bzip2, a block-sorting file compressor. "
01675 "Version %s.\n"
01676 " \n"
01677 " Copyright (C) 1996-2002 by Julian Seward.\n"
01678 " \n"
01679 " This program is free software; you can redistribute it and/or modify\n"
01680 " it under the terms set out in the LICENSE file, which is included\n"
01681 " in the bzip2-1.0 source distribution.\n"
01682 " \n"
01683 " This program is distributed in the hope that it will be useful,\n"
01684 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
01685 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
01686 " LICENSE file for more details.\n"
01687 " \n",
01688 BZ2_bzlibVersion()
01689 );
01690 }
01691
01692
01693
01694 static
01695 void usage ( Char *fullProgName )
01696 {
01697 fprintf (
01698 stderr,
01699 "bzip2, a block-sorting file compressor. "
01700 "Version %s.\n"
01701 "\n usage: %s [flags and input files in any order]\n"
01702 "\n"
01703 " -h --help print this message\n"
01704 " -d --decompress force decompression\n"
01705 " -z --compress force compression\n"
01706 " -k --keep keep (don't delete) input files\n"
01707 " -f --force overwrite existing output files\n"
01708 " -t --test test compressed file integrity\n"
01709 " -c --stdout output to standard out\n"
01710 " -q --quiet suppress noncritical error messages\n"
01711 " -v --verbose be verbose (a 2nd -v gives more)\n"
01712 " -L --license display software version & license\n"
01713 " -V --version display software version & license\n"
01714 " -s --small use less memory (at most 2500k)\n"
01715 " -1 .. -9 set block size to 100k .. 900k\n"
01716 " --fast alias for -1\n"
01717 " --best alias for -9\n"
01718 "\n"
01719 " If invoked as `bzip2', default action is to compress.\n"
01720 " as `bunzip2', default action is to decompress.\n"
01721 " as `bzcat', default action is to decompress to stdout.\n"
01722 "\n"
01723 " If no file names are given, bzip2 compresses or decompresses\n"
01724 " from standard input to standard output. You can combine\n"
01725 " short flags, so `-v -4' means the same as -v4 or -4v, &c.\n"
01726 # if BZ_UNIX
01727 "\n"
01728 # endif
01729 ,
01730
01731 BZ2_bzlibVersion(),
01732 fullProgName
01733 );
01734 }
01735
01736
01737
01738 static
01739 void redundant ( Char* flag )
01740 {
01741 fprintf (
01742 stderr,
01743 "%s: %s is redundant in versions 0.9.5 and above\n",
01744 progName, flag );
01745 }
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763 typedef
01764 struct zzzz {
01765 Char *name;
01766 struct zzzz *link;
01767 }
01768 Cell;
01769
01770
01771
01772 static
01773 void *myMalloc ( Int32 n )
01774 {
01775 void* p;
01776
01777 p = malloc ( (size_t)n );
01778 if (p == NULL) outOfMemory ();
01779 return p;
01780 }
01781
01782
01783
01784 static
01785 Cell *mkCell ( void )
01786 {
01787 Cell *c;
01788
01789 c = (Cell*) myMalloc ( sizeof ( Cell ) );
01790 c->name = NULL;
01791 c->link = NULL;
01792 return c;
01793 }
01794
01795
01796
01797 static
01798 Cell *snocString ( Cell *root, Char *name )
01799 {
01800 if (root == NULL) {
01801 Cell *tmp = mkCell();
01802 tmp->name = (Char*) myMalloc ( 5 + strlen(name) );
01803 strcpy ( tmp->name, name );
01804 return tmp;
01805 } else {
01806 Cell *tmp = root;
01807 while (tmp->link != NULL) tmp = tmp->link;
01808 tmp->link = snocString ( tmp->link, name );
01809 return root;
01810 }
01811 }
01812
01813
01814
01815 static
01816 void addFlagsFromEnvVar ( Cell** argList, Char* varName )
01817 {
01818 Int32 i, j, k;
01819 Char *envbase, *p;
01820
01821 envbase = getenv(varName);
01822 if (envbase != NULL) {
01823 p = envbase;
01824 i = 0;
01825 while (True) {
01826 if (p[i] == 0) break;
01827 p += i;
01828 i = 0;
01829 while (isspace((Int32)(p[0]))) p++;
01830 while (p[i] != 0 && !isspace((Int32)(p[i]))) i++;
01831 if (i > 0) {
01832 k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10;
01833 for (j = 0; j < k; j++) tmpName[j] = p[j];
01834 tmpName[k] = 0;
01835 APPEND_FLAG(*argList, tmpName);
01836 }
01837 }
01838 }
01839 }
01840
01841
01842
01843 #define ISFLAG(s) (strcmp(aa->name, (s))==0)
01844
01845 IntNative main ( IntNative argc, Char *argv[] )
01846 {
01847 Int32 i, j;
01848 Char *tmp;
01849 Cell *argList;
01850 Cell *aa;
01851 Bool decode;
01852
01853
01854 if (sizeof(Int32) != 4 || sizeof(UInt32) != 4 ||
01855 sizeof(Int16) != 2 || sizeof(UInt16) != 2 ||
01856 sizeof(Char) != 1 || sizeof(UChar) != 1)
01857 configError();
01858
01859
01860 outputHandleJustInCase = NULL;
01861 smallMode = False;
01862 keepInputFiles = False;
01863 forceOverwrite = False;
01864 noisy = True;
01865 verbosity = 0;
01866 blockSize100k = 9;
01867 testFailsExist = False;
01868 unzFailsExist = False;
01869 numFileNames = 0;
01870 numFilesProcessed = 0;
01871 workFactor = 30;
01872 deleteOutputOnInterrupt = False;
01873 exitValue = 0;
01874 i = j = 0;
01875
01876
01877 signal (SIGSEGV, mySIGSEGVorSIGBUScatcher);
01878 # if BZ_UNIX
01879 # ifndef __DJGPP__
01880 signal (SIGBUS, mySIGSEGVorSIGBUScatcher);
01881 # endif
01882 # endif
01883
01884 copyFileName ( inName, "(none)" );
01885 copyFileName ( outName, "(none)" );
01886
01887 copyFileName ( progNameReally, argv[0] );
01888 progName = &progNameReally[0];
01889 for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++)
01890 if (*tmp == PATH_SEP) progName = tmp + 1;
01891
01892
01893
01894
01895
01896 argList = NULL;
01897 addFlagsFromEnvVar ( &argList, "BZIP2" );
01898 addFlagsFromEnvVar ( &argList, "BZIP" );
01899 for (i = 1; i <= argc-1; i++)
01900 APPEND_FILESPEC(argList, argv[i]);
01901
01902
01903
01904 longestFileName = 7;
01905 numFileNames = 0;
01906 decode = True;
01907 for (aa = argList; aa != NULL; aa = aa->link) {
01908 if (ISFLAG("--")) { decode = False; continue; }
01909 if (aa->name[0] == '-' && decode) continue;
01910 numFileNames++;
01911 if (longestFileName < (Int32)strlen(aa->name) )
01912 longestFileName = (Int32)strlen(aa->name);
01913 }
01914
01915
01916
01917 if (numFileNames == 0)
01918 srcMode = SM_I2O; else srcMode = SM_F2F;
01919
01920
01921
01922
01923 opMode = OM_Z;
01924
01925 if ( (strstr ( progName, "unzip" ) != 0) ||
01926 (strstr ( progName, "UNZIP" ) != 0) )
01927 opMode = OM_UNZ;
01928
01929 if ( (strstr ( progName, "z2cat" ) != 0) ||
01930 (strstr ( progName, "Z2CAT" ) != 0) ||
01931 (strstr ( progName, "zcat" ) != 0) ||
01932 (strstr ( progName, "ZCAT" ) != 0) ) {
01933 opMode = OM_UNZ;
01934 srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O;
01935 }
01936
01937
01938
01939 for (aa = argList; aa != NULL; aa = aa->link) {
01940 if (ISFLAG("--")) break;
01941 if (aa->name[0] == '-' && aa->name[1] != '-') {
01942 for (j = 1; aa->name[j] != '\0'; j++) {
01943 switch (aa->name[j]) {
01944 case 'c': srcMode = SM_F2O; break;
01945 case 'd': opMode = OM_UNZ; break;
01946 case 'z': opMode = OM_Z; break;
01947 case 'f': forceOverwrite = True; break;
01948 case 't': opMode = OM_TEST; break;
01949 case 'k': keepInputFiles = True; break;
01950 case 's': smallMode = True; break;
01951 case 'q': noisy = False; break;
01952 case '1': blockSize100k = 1; break;
01953 case '2': blockSize100k = 2; break;
01954 case '3': blockSize100k = 3; break;
01955 case '4': blockSize100k = 4; break;
01956 case '5': blockSize100k = 5; break;
01957 case '6': blockSize100k = 6; break;
01958 case '7': blockSize100k = 7; break;
01959 case '8': blockSize100k = 8; break;
01960 case '9': blockSize100k = 9; break;
01961 case 'V':
01962 case 'L': license(); break;
01963 case 'v': verbosity++; break;
01964 case 'h': usage ( progName );
01965 exit ( 0 );
01966 break;
01967 default: fprintf ( stderr, "%s: Bad flag `%s'\n",
01968 progName, aa->name );
01969 usage ( progName );
01970 exit ( 1 );
01971 break;
01972 }
01973 }
01974 }
01975 }
01976
01977
01978 for (aa = argList; aa != NULL; aa = aa->link) {
01979 if (ISFLAG("--")) break;
01980 if (ISFLAG("--stdout")) srcMode = SM_F2O; else
01981 if (ISFLAG("--decompress")) opMode = OM_UNZ; else
01982 if (ISFLAG("--compress")) opMode = OM_Z; else
01983 if (ISFLAG("--force")) forceOverwrite = True; else
01984 if (ISFLAG("--test")) opMode = OM_TEST; else
01985 if (ISFLAG("--keep")) keepInputFiles = True; else
01986 if (ISFLAG("--small")) smallMode = True; else
01987 if (ISFLAG("--quiet")) noisy = False; else
01988 if (ISFLAG("--version")) license(); else
01989 if (ISFLAG("--license")) license(); else
01990 if (ISFLAG("--exponential")) workFactor = 1; else
01991 if (ISFLAG("--repetitive-best")) redundant(aa->name); else
01992 if (ISFLAG("--repetitive-fast")) redundant(aa->name); else
01993 if (ISFLAG("--fast")) blockSize100k = 1; else
01994 if (ISFLAG("--best")) blockSize100k = 9; else
01995 if (ISFLAG("--verbose")) verbosity++; else
01996 if (ISFLAG("--help")) { usage ( progName ); exit ( 0 ); }
01997 else
01998 if (strncmp ( aa->name, "--", 2) == 0) {
01999 fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name );
02000 usage ( progName );
02001 exit ( 1 );
02002 }
02003 }
02004
02005 if (verbosity > 4) verbosity = 4;
02006 if (opMode == OM_Z && smallMode && blockSize100k > 2)
02007 blockSize100k = 2;
02008
02009 if (opMode == OM_TEST && srcMode == SM_F2O) {
02010 fprintf ( stderr, "%s: -c and -t cannot be used together.\n",
02011 progName );
02012 exit ( 1 );
02013 }
02014
02015 if (srcMode == SM_F2O && numFileNames == 0)
02016 srcMode = SM_I2O;
02017
02018 if (opMode != OM_Z) blockSize100k = 0;
02019
02020 if (srcMode == SM_F2F) {
02021 signal (SIGINT, mySignalCatcher);
02022 signal (SIGTERM, mySignalCatcher);
02023 # if BZ_UNIX
02024 signal (SIGHUP, mySignalCatcher);
02025 # endif
02026 }
02027
02028 if (opMode == OM_Z) {
02029 if (srcMode == SM_I2O) {
02030 compress ( NULL );
02031 } else {
02032 decode = True;
02033 for (aa = argList; aa != NULL; aa = aa->link) {
02034 if (ISFLAG("--")) { decode = False; continue; }
02035 if (aa->name[0] == '-' && decode) continue;
02036 numFilesProcessed++;
02037 compress ( aa->name );
02038 }
02039 }
02040 }
02041 else
02042
02043 if (opMode == OM_UNZ) {
02044 unzFailsExist = False;
02045 if (srcMode == SM_I2O) {
02046 uncompress ( NULL );
02047 } else {
02048 decode = True;
02049 for (aa = argList; aa != NULL; aa = aa->link) {
02050 if (ISFLAG("--")) { decode = False; continue; }
02051 if (aa->name[0] == '-' && decode) continue;
02052 numFilesProcessed++;
02053 uncompress ( aa->name );
02054 }
02055 }
02056 if (unzFailsExist) {
02057 setExit(2);
02058 exit(exitValue);
02059 }
02060 }
02061
02062 else {
02063 testFailsExist = False;
02064 if (srcMode == SM_I2O) {
02065 testf ( NULL );
02066 } else {
02067 decode = True;
02068 for (aa = argList; aa != NULL; aa = aa->link) {
02069 if (ISFLAG("--")) { decode = False; continue; }
02070 if (aa->name[0] == '-' && decode) continue;
02071 numFilesProcessed++;
02072 testf ( aa->name );
02073 }
02074 }
02075 if (testFailsExist && noisy) {
02076 fprintf ( stderr,
02077 "\n"
02078 "You can use the `bzip2recover' program to attempt to recover\n"
02079 "data from undamaged sections of corrupted files.\n\n"
02080 );
02081 setExit(2);
02082 exit(exitValue);
02083 }
02084 }
02085
02086
02087
02088
02089 aa = argList;
02090 while (aa != NULL) {
02091 Cell* aa2 = aa->link;
02092 if (aa->name != NULL) free(aa->name);
02093 free(aa);
02094 aa = aa2;
02095 }
02096
02097 return exitValue;
02098 }
02099
02100
02101
02102
02103
02104
02105