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