1 2 /*-----------------------------------------------------------*/ 3 /*--- A block-sorting, lossless compressor bzip2.c ---*/ 4 /*-----------------------------------------------------------*/ 5 6 /*-- 7 This file is a part of bzip2 and/or libbzip2, a program and 8 library for lossless, block-sorting data compression. 9 10 Copyright (C) 1996-2002 Julian R Seward. All rights reserved. 11 12 Redistribution and use in source and binary forms, with or without 13 modification, are permitted provided that the following conditions 14 are met: 15 16 1. Redistributions of source code must retain the above copyright 17 notice, this list of conditions and the following disclaimer. 18 19 2. The origin of this software must not be misrepresented; you must 20 not claim that you wrote the original software. If you use this 21 software in a product, an acknowledgment in the product 22 documentation would be appreciated but is not required. 23 24 3. Altered source versions must be plainly marked as such, and must 25 not be misrepresented as being the original software. 26 27 4. The name of the author may not be used to endorse or promote 28 products derived from this software without specific prior written 29 permission. 30 31 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 32 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 33 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 34 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 35 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 37 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 38 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 39 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 43 Julian Seward, Cambridge, UK. 44 jseward@acm.org 45 bzip2/libbzip2 version 1.0 of 21 March 2000 46 47 This program is based on (at least) the work of: 48 Mike Burrows 49 David Wheeler 50 Peter Fenwick 51 Alistair Moffat 52 Radford Neal 53 Ian H. Witten 54 Robert Sedgewick 55 Jon L. Bentley 56 57 For more information on these sources, see the manual. 58 --*/ 59 60 61 /*----------------------------------------------------*/ 62 /*--- IMPORTANT ---*/ 63 /*----------------------------------------------------*/ 64 65 /*-- 66 WARNING: 67 This program and library (attempts to) compress data by 68 performing several non-trivial transformations on it. 69 Unless you are 100% familiar with *all* the algorithms 70 contained herein, and with the consequences of modifying them, 71 you should NOT meddle with the compression or decompression 72 machinery. Incorrect changes can and very likely *will* 73 lead to disasterous loss of data. 74 75 DISCLAIMER: 76 I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE 77 USE OF THIS PROGRAM, HOWSOEVER CAUSED. 78 79 Every compression of a file implies an assumption that the 80 compressed file can be decompressed to reproduce the original. 81 Great efforts in design, coding and testing have been made to 82 ensure that this program works correctly. However, the 83 complexity of the algorithms, and, in particular, the presence 84 of various special cases in the code which occur with very low 85 but non-zero probability make it impossible to rule out the 86 possibility of bugs remaining in the program. DO NOT COMPRESS 87 ANY DATA WITH THIS PROGRAM AND/OR LIBRARY UNLESS YOU ARE PREPARED 88 TO ACCEPT THE POSSIBILITY, HOWEVER SMALL, THAT THE DATA WILL 89 NOT BE RECOVERABLE. 90 91 That is not to say this program is inherently unreliable. 92 Indeed, I very much hope the opposite is true. bzip2/libbzip2 93 has been carefully constructed and extensively tested. 94 95 PATENTS: 96 To the best of my knowledge, bzip2/libbzip2 does not use any 97 patented algorithms. However, I do not have the resources 98 available to carry out a full patent search. Therefore I cannot 99 give any guarantee of the above statement. 100 --*/ 101 102 103 104 /*----------------------------------------------------*/ 105 /*--- and now for something much more pleasant :-) ---*/ 106 /*----------------------------------------------------*/ 107 108 /*---------------------------------------------*/ 109 /*-- 110 Place a 1 beside your platform, and 0 elsewhere. 111 --*/ 112 113 /*-- 114 Generic 32-bit Unix. 115 Also works on 64-bit Unix boxes. 116 This is the default. 117 --*/ 118 #define BZ_UNIX 1 119 120 /*-- 121 Win32, as seen by Jacob Navia's excellent 122 port of (Chris Fraser & David Hanson)'s excellent 123 lcc compiler. Or with MS Visual C. 124 This is selected automatically if compiled by a compiler which 125 defines _WIN32, not including the Cygwin GCC. 126 --*/ 127 #define BZ_LCCWIN32 0 128 129 #if defined(_WIN32) && !defined(__CYGWIN__) 130 #undef BZ_LCCWIN32 131 #define BZ_LCCWIN32 1 132 #undef BZ_UNIX 133 #define BZ_UNIX 0 134 #endif 135 136 137 /*---------------------------------------------*/ 138 /*-- 139 Some stuff for all platforms. 140 --*/ 141 142 #include <stdio.h> 143 #include <stdlib.h> 144 #include <string.h> 145 #include <signal.h> 146 #include <math.h> 147 #include <errno.h> 148 #include <ctype.h> 149 #include "bzlib.h" 150 151 #define ERROR_IF_EOF(i) { if ((i) == EOF) ioError(); } 152 #define ERROR_IF_NOT_ZERO(i) { if ((i) != 0) ioError(); } 153 #define ERROR_IF_MINUS_ONE(i) { if ((i) == (-1)) ioError(); } 154 155 156 /*---------------------------------------------*/ 157 /*-- 158 Platform-specific stuff. 159 --*/ 160 161 #if BZ_UNIX 162 # include <fcntl.h> 163 # include <sys/types.h> 164 # include <utime.h> 165 # include <unistd.h> 166 # include <sys/stat.h> 167 # include <sys/times.h> 168 169 # define PATH_SEP '/' 170 # define MY_LSTAT lstat 171 # define MY_STAT stat 172 # define MY_S_ISREG S_ISREG 173 # define MY_S_ISDIR S_ISDIR 174 175 # define APPEND_FILESPEC(root, name) \ 176 root=snocString((root), (name)) 177 178 # define APPEND_FLAG(root, name) \ 179 root=snocString((root), (name)) 180 181 # define SET_BINARY_MODE(fd) /**/ 182 183 # ifdef __GNUC__ 184 # define NORETURN __attribute__ ((noreturn)) 185 # else 186 # define NORETURN /**/ 187 # endif 188 189 # ifdef __DJGPP__ 190 # include <io.h> 191 # include <fcntl.h> 192 # undef MY_LSTAT 193 # undef MY_STAT 194 # define MY_LSTAT stat 195 # define MY_STAT stat 196 # undef SET_BINARY_MODE 197 # define SET_BINARY_MODE(fd) \ 198 do { \ 199 int retVal = setmode ( fileno ( fd ), \ 200 O_BINARY ); \ 201 ERROR_IF_MINUS_ONE ( retVal ); \ 202 } while ( 0 ) 203 # endif 204 205 # ifdef __CYGWIN__ 206 # include <io.h> 207 # include <fcntl.h> 208 # undef SET_BINARY_MODE 209 # define SET_BINARY_MODE(fd) \ 210 do { \ 211 int retVal = setmode ( fileno ( fd ), \ 212 O_BINARY ); \ 213 ERROR_IF_MINUS_ONE ( retVal ); \ 214 } while ( 0 ) 215 # endif 216 #endif /* BZ_UNIX */ 217 218 219 220 #if BZ_LCCWIN32 221 # include <io.h> 222 # include <fcntl.h> 223 # include <sys\stat.h> 224 225 # define NORETURN /**/ 226 # define PATH_SEP '\\' 227 # define MY_LSTAT _stat 228 # define MY_STAT _stat 229 # define MY_S_ISREG(x) ((x) & _S_IFREG) 230 # define MY_S_ISDIR(x) ((x) & _S_IFDIR) 231 232 # define APPEND_FLAG(root, name) \ 233 root=snocString((root), (name)) 234 235 # define APPEND_FILESPEC(root, name) \ 236 root = snocString ((root), (name)) 237 238 # define SET_BINARY_MODE(fd) \ 239 do { \ 240 int retVal = setmode ( fileno ( fd ), \ 241 O_BINARY ); \ 242 ERROR_IF_MINUS_ONE ( retVal ); \ 243 } while ( 0 ) 244 245 #endif /* BZ_LCCWIN32 */ 246 247 248 /*---------------------------------------------*/ 249 /*-- 250 Some more stuff for all platforms :-) 251 --*/ 252 253 typedef char Char; 254 typedef unsigned char Bool; 255 typedef unsigned char UChar; 256 typedef int Int32; 257 typedef unsigned int UInt32; 258 typedef short Int16; 259 typedef unsigned short UInt16; 260 261 #define True ((Bool)1) 262 #define False ((Bool)0) 263 264 /*-- 265 IntNative is your platform's `native' int size. 266 Only here to avoid probs with 64-bit platforms. 267 --*/ 268 typedef int IntNative; 269 270 271 /*---------------------------------------------------*/ 272 /*--- Misc (file handling) data decls ---*/ 273 /*---------------------------------------------------*/ 274 275 Int32 verbosity; 276 Bool keepInputFiles, smallMode, deleteOutputOnInterrupt; 277 Bool forceOverwrite, testFailsExist, unzFailsExist, noisy; 278 Int32 numFileNames, numFilesProcessed, blockSize100k; 279 Int32 exitValue; 280 281 /*-- source modes; F==file, I==stdin, O==stdout --*/ 282 #define SM_I2O 1 283 #define SM_F2O 2 284 #define SM_F2F 3 285 286 /*-- operation modes --*/ 287 #define OM_Z 1 288 #define OM_UNZ 2 289 #define OM_TEST 3 290 291 Int32 opMode; 292 Int32 srcMode; 293 294 #define FILE_NAME_LEN 1034 295 296 Int32 longestFileName; 297 Char inName [FILE_NAME_LEN]; 298 Char outName[FILE_NAME_LEN]; 299 Char tmpName[FILE_NAME_LEN]; 300 Char *progName; 301 Char progNameReally[FILE_NAME_LEN]; 302 FILE *outputHandleJustInCase; 303 Int32 workFactor; 304 305 static void panic ( Char* ) NORETURN; 306 static void ioError ( void ) NORETURN; 307 static void outOfMemory ( void ) NORETURN; 308 static void configError ( void ) NORETURN; 309 static void crcError ( void ) NORETURN; 310 static void cleanUpAndFail ( Int32 ) NORETURN; 311 static void compressedStreamEOF ( void ) NORETURN; 312 313 static void copyFileName ( Char*, Char* ); 314 static void* myMalloc ( Int32 ); 315 316 317 318 /*---------------------------------------------------*/ 319 /*--- An implementation of 64-bit ints. Sigh. ---*/ 320 /*--- Roll on widespread deployment of ANSI C9X ! ---*/ 321 /*---------------------------------------------------*/ 322 323 typedef 324 struct { UChar b[8]; } 325 UInt64; 326 327 328 static 329 void uInt64_from_UInt32s ( UInt64* n, UInt32 lo32, UInt32 hi32 ) 330 { 331 n->b[7] = (UChar)((hi32 >> 24) & 0xFF); 332 n->b[6] = (UChar)((hi32 >> 16) & 0xFF); 333 n->b[5] = (UChar)((hi32 >> 8) & 0xFF); 334 n->b[4] = (UChar) (hi32 & 0xFF); 335 n->b[3] = (UChar)((lo32 >> 24) & 0xFF); 336 n->b[2] = (UChar)((lo32 >> 16) & 0xFF); 337 n->b[1] = (UChar)((lo32 >> 8) & 0xFF); 338 n->b[0] = (UChar) (lo32 & 0xFF); 339 } 340 341 342 static 343 double uInt64_to_double ( UInt64* n ) 344 { 345 Int32 i; 346 double base = 1.0; 347 double sum = 0.0; 348 for (i = 0; i < 8; i++) { 349 sum += base * (double)(n->b[i]); 350 base *= 256.0; 351 } 352 return sum; 353 } 354 355 356 static 357 Bool uInt64_isZero ( UInt64* n ) 358 { 359 Int32 i; 360 for (i = 0; i < 8; i++) 361 if (n->b[i] != 0) return 0; 362 return 1; 363 } 364 365 366 /* Divide *n by 10, and return the remainder. */ 367 static 368 Int32 uInt64_qrm10 ( UInt64* n ) 369 { 370 UInt32 rem, tmp; 371 Int32 i; 372 rem = 0; 373 for (i = 7; i >= 0; i--) { 374 tmp = rem * 256 + n->b[i]; 375 n->b[i] = tmp / 10; 376 rem = tmp % 10; 377 } 378 return rem; 379 } 380 381 382 /* ... and the Whole Entire Point of all this UInt64 stuff is 383 so that we can supply the following function. 384 */ 385 static 386 void uInt64_toAscii ( char* outbuf, UInt64* n ) 387 { 388 Int32 i, q; 389 UChar buf[32]; 390 Int32 nBuf = 0; 391 UInt64 n_copy = *n; 392 do { 393 q = uInt64_qrm10 ( &n_copy ); 394 buf[nBuf] = q + '0'; 395 nBuf++; 396 } while (!uInt64_isZero(&n_copy)); 397 outbuf[nBuf] = 0; 398 for (i = 0; i < nBuf; i++) 399 outbuf[i] = buf[nBuf-i-1]; 400 } 401 402 403 /*---------------------------------------------------*/ 404 /*--- Processing of complete files and streams ---*/ 405 /*---------------------------------------------------*/ 406 407 /*---------------------------------------------*/ 408 static 409 Bool myfeof ( FILE* f ) 410 { 411 Int32 c = fgetc ( f ); 412 if (c == EOF) return True; 413 ungetc ( c, f ); 414 return False; 415 } 416 417 418 /*---------------------------------------------*/ 419 static 420 void compressStream ( FILE *stream, FILE *zStream ) 421 { 422 BZFILE* bzf = NULL; 423 UChar ibuf[5000]; 424 Int32 nIbuf; 425 UInt32 nbytes_in_lo32, nbytes_in_hi32; 426 UInt32 nbytes_out_lo32, nbytes_out_hi32; 427 Int32 bzerr, bzerr_dummy, ret; 428 429 SET_BINARY_MODE(stream); 430 SET_BINARY_MODE(zStream); 431 432 if (ferror(stream)) goto errhandler_io; 433 if (ferror(zStream)) goto errhandler_io; 434 435 bzf = BZ2_bzWriteOpen ( &bzerr, zStream, 436 blockSize100k, verbosity, workFactor ); 437 if (bzerr != BZ_OK) goto errhandler; 438 439 if (verbosity >= 2) fprintf ( stderr, "\n" ); 440 441 while (True) { 442 443 if (myfeof(stream)) break; 444 nIbuf = fread ( ibuf, sizeof(UChar), 5000, stream ); 445 if (ferror(stream)) goto errhandler_io; 446 if (nIbuf > 0) BZ2_bzWrite ( &bzerr, bzf, (void*)ibuf, nIbuf ); 447 if (bzerr != BZ_OK) goto errhandler; 448 449 } 450 451 BZ2_bzWriteClose64 ( &bzerr, bzf, 0, 452 &nbytes_in_lo32, &nbytes_in_hi32, 453 &nbytes_out_lo32, &nbytes_out_hi32 ); 454 if (bzerr != BZ_OK) goto errhandler; 455 456 if (ferror(zStream)) goto errhandler_io; 457 ret = fflush ( zStream ); 458 if (ret == EOF) goto errhandler_io; 459 if (zStream != stdout) { 460 ret = fclose ( zStream ); 461 outputHandleJustInCase = NULL; 462 if (ret == EOF) goto errhandler_io; 463 } 464 outputHandleJustInCase = NULL; 465 if (ferror(stream)) goto errhandler_io; 466 ret = fclose ( stream ); 467 if (ret == EOF) goto errhandler_io; 468 469 if (verbosity >= 1) { 470 if (nbytes_in_lo32 == 0 && nbytes_in_hi32 == 0) { 471 fprintf ( stderr, " no data compressed.\n"); 472 } else { 473 Char buf_nin[32], buf_nout[32]; 474 UInt64 nbytes_in, nbytes_out; 475 double nbytes_in_d, nbytes_out_d; 476 uInt64_from_UInt32s ( &nbytes_in, 477 nbytes_in_lo32, nbytes_in_hi32 ); 478 uInt64_from_UInt32s ( &nbytes_out, 479 nbytes_out_lo32, nbytes_out_hi32 ); 480 nbytes_in_d = uInt64_to_double ( &nbytes_in ); 481 nbytes_out_d = uInt64_to_double ( &nbytes_out ); 482 uInt64_toAscii ( buf_nin, &nbytes_in ); 483 uInt64_toAscii ( buf_nout, &nbytes_out ); 484 fprintf ( stderr, "%6.3f:1, %6.3f bits/byte, " 485 "%5.2f%% saved, %s in, %s out.\n", 486 nbytes_in_d / nbytes_out_d, 487 (8.0 * nbytes_out_d) / nbytes_in_d, 488 100.0 * (1.0 - nbytes_out_d / nbytes_in_d), 489 buf_nin, 490 buf_nout 491 ); 492 } 493 } 494 495 return; 496 497 errhandler: 498 BZ2_bzWriteClose64 ( &bzerr_dummy, bzf, 1, 499 &nbytes_in_lo32, &nbytes_in_hi32, 500 &nbytes_out_lo32, &nbytes_out_hi32 ); 501 switch (bzerr) { 502 case BZ_CONFIG_ERROR: 503 configError(); break; 504 case BZ_MEM_ERROR: 505 outOfMemory (); break; 506 case BZ_IO_ERROR: 507 errhandler_io: 508 ioError(); break; 509 default: 510 panic ( "compress:unexpected error" ); 511 } 512 513 panic ( "compress:end" ); 514 /*notreached*/ 515 } 516 517 518 519 /*---------------------------------------------*/ 520 static 521 Bool uncompressStream ( FILE *zStream, FILE *stream ) 522 { 523 BZFILE* bzf = NULL; 524 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i; 525 UChar obuf[5000]; 526 UChar unused[BZ_MAX_UNUSED]; 527 Int32 nUnused; 528 UChar* unusedTmp; 529 530 nUnused = 0; 531 streamNo = 0; 532 533 SET_BINARY_MODE(stream); 534 SET_BINARY_MODE(zStream); 535 536 if (ferror(stream)) goto errhandler_io; 537 if (ferror(zStream)) goto errhandler_io; 538 539 while (True) { 540 541 bzf = BZ2_bzReadOpen ( 542 &bzerr, zStream, verbosity, 543 (int)smallMode, unused, nUnused 544 ); 545 if (bzf == NULL || bzerr != BZ_OK) goto errhandler; 546 streamNo++; 547 548 while (bzerr == BZ_OK) { 549 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 ); 550 if (bzerr == BZ_DATA_ERROR_MAGIC) goto trycat; 551 if ((bzerr == BZ_OK || bzerr == BZ_STREAM_END) && nread > 0) 552 fwrite ( obuf, sizeof(UChar), nread, stream ); 553 if (ferror(stream)) goto errhandler_io; 554 } 555 if (bzerr != BZ_STREAM_END) goto errhandler; 556 557 BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused ); 558 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" ); 559 560 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i]; 561 562 BZ2_bzReadClose ( &bzerr, bzf ); 563 if (bzerr != BZ_OK) panic ( "decompress:bzReadGetUnused" ); 564 565 if (nUnused == 0 && myfeof(zStream)) break; 566 } 567 568 closeok: 569 if (ferror(zStream)) goto errhandler_io; 570 ret = fclose ( zStream ); 571 if (ret == EOF) goto errhandler_io; 572 573 if (ferror(stream)) goto errhandler_io; 574 ret = fflush ( stream ); 575 if (ret != 0) goto errhandler_io; 576 if (stream != stdout) { 577 ret = fclose ( stream ); 578 outputHandleJustInCase = NULL; 579 if (ret == EOF) goto errhandler_io; 580 } 581 outputHandleJustInCase = NULL; 582 if (verbosity >= 2) fprintf ( stderr, "\n " ); 583 return True; 584 585 trycat: 586 if (forceOverwrite) { 587 rewind(zStream); 588 while (True) { 589 if (myfeof(zStream)) break; 590 nread = fread ( obuf, sizeof(UChar), 5000, zStream ); 591 if (ferror(zStream)) goto errhandler_io; 592 if (nread > 0) fwrite ( obuf, sizeof(UChar), nread, stream ); 593 if (ferror(stream)) goto errhandler_io; 594 } 595 goto closeok; 596 } 597 598 errhandler: 599 BZ2_bzReadClose ( &bzerr_dummy, bzf ); 600 switch (bzerr) { 601 case BZ_CONFIG_ERROR: 602 configError(); break; 603 case BZ_IO_ERROR: 604 errhandler_io: 605 ioError(); break; 606 case BZ_DATA_ERROR: 607 crcError(); 608 case BZ_MEM_ERROR: 609 outOfMemory(); 610 case BZ_UNEXPECTED_EOF: 611 compressedStreamEOF(); 612 case BZ_DATA_ERROR_MAGIC: 613 if (zStream != stdin) fclose(zStream); 614 if (stream != stdout) fclose(stream); 615 if (streamNo == 1) { 616 return False; 617 } else { 618 if (noisy) 619 fprintf ( stderr, 620 "\n%s: %s: trailing garbage after EOF ignored\n", 621 progName, inName ); 622 return True; 623 } 624 default: 625 panic ( "decompress:unexpected error" ); 626 } 627 628 panic ( "decompress:end" ); 629 return True; /*notreached*/ 630 } 631 632 633 /*---------------------------------------------*/ 634 static 635 Bool testStream ( FILE *zStream ) 636 { 637 BZFILE* bzf = NULL; 638 Int32 bzerr, bzerr_dummy, ret, nread, streamNo, i; 639 UChar obuf[5000]; 640 UChar unused[BZ_MAX_UNUSED]; 641 Int32 nUnused; 642 UChar* unusedTmp; 643 644 nUnused = 0; 645 streamNo = 0; 646 647 SET_BINARY_MODE(zStream); 648 if (ferror(zStream)) goto errhandler_io; 649 650 while (True) { 651 652 bzf = BZ2_bzReadOpen ( 653 &bzerr, zStream, verbosity, 654 (int)smallMode, unused, nUnused 655 ); 656 if (bzf == NULL || bzerr != BZ_OK) goto errhandler; 657 streamNo++; 658 659 while (bzerr == BZ_OK) { 660 nread = BZ2_bzRead ( &bzerr, bzf, obuf, 5000 ); 661 if (bzerr == BZ_DATA_ERROR_MAGIC) goto errhandler; 662 } 663 if (bzerr != BZ_STREAM_END) goto errhandler; 664 665 BZ2_bzReadGetUnused ( &bzerr, bzf, (void**)(&unusedTmp), &nUnused ); 666 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" ); 667 668 for (i = 0; i < nUnused; i++) unused[i] = unusedTmp[i]; 669 670 BZ2_bzReadClose ( &bzerr, bzf ); 671 if (bzerr != BZ_OK) panic ( "test:bzReadGetUnused" ); 672 if (nUnused == 0 && myfeof(zStream)) break; 673 674 } 675 676 if (ferror(zStream)) goto errhandler_io; 677 ret = fclose ( zStream ); 678 if (ret == EOF) goto errhandler_io; 679 680 if (verbosity >= 2) fprintf ( stderr, "\n " ); 681 return True; 682 683 errhandler: 684 BZ2_bzReadClose ( &bzerr_dummy, bzf ); 685 if (verbosity == 0) 686 fprintf ( stderr, "%s: %s: ", progName, inName ); 687 switch (bzerr) { 688 case BZ_CONFIG_ERROR: 689 configError(); break; 690 case BZ_IO_ERROR: 691 errhandler_io: 692 ioError(); break; 693 case BZ_DATA_ERROR: 694 fprintf ( stderr, 695 "data integrity (CRC) error in data\n" ); 696 return False; 697 case BZ_MEM_ERROR: 698 outOfMemory(); 699 case BZ_UNEXPECTED_EOF: 700 fprintf ( stderr, 701 "file ends unexpectedly\n" ); 702 return False; 703 case BZ_DATA_ERROR_MAGIC: 704 if (zStream != stdin) fclose(zStream); 705 if (streamNo == 1) { 706 fprintf ( stderr, 707 "bad magic number (file not created by bzip2)\n" ); 708 return False; 709 } else { 710 if (noisy) 711 fprintf ( stderr, 712 "trailing garbage after EOF ignored\n" ); 713 return True; 714 } 715 default: 716 panic ( "test:unexpected error" ); 717 } 718 719 panic ( "test:end" ); 720 return True; /*notreached*/ 721 } 722 723 724 /*---------------------------------------------------*/ 725 /*--- Error [non-] handling grunge ---*/ 726 /*---------------------------------------------------*/ 727 728 /*---------------------------------------------*/ 729 static 730 void setExit ( Int32 v ) 731 { 732 if (v > exitValue) exitValue = v; 733 } 734 735 736 /*---------------------------------------------*/ 737 static 738 void cadvise ( void ) 739 { 740 if (noisy) 741 fprintf ( 742 stderr, 743 "\nIt is possible that the compressed file(s) have become corrupted.\n" 744 "You can use the -tvv option to test integrity of such files.\n\n" 745 "You can use the `bzip2recover' program to attempt to recover\n" 746 "data from undamaged sections of corrupted files.\n\n" 747 ); 748 } 749 750 751 /*---------------------------------------------*/ 752 static 753 void showFileNames ( void ) 754 { 755 if (noisy) 756 fprintf ( 757 stderr, 758 "\tInput file = %s, output file = %s\n", 759 inName, outName 760 ); 761 } 762 763 764 /*---------------------------------------------*/ 765 static 766 void cleanUpAndFail ( Int32 ec ) 767 { 768 IntNative retVal; 769 struct MY_STAT statBuf; 770 771 if ( srcMode == SM_F2F 772 && opMode != OM_TEST 773 && deleteOutputOnInterrupt ) { 774 775 /* Check whether input file still exists. Delete output file 776 only if input exists to avoid loss of data. Joerg Prante, 5 777 January 2002. (JRS 06-Jan-2002: other changes in 1.0.2 mean 778 this is less likely to happen. But to be ultra-paranoid, we 779 do the check anyway.) */ 780 retVal = MY_STAT ( inName, &statBuf ); 781 if (retVal == 0) { 782 if (noisy) 783 fprintf ( stderr, 784 "%s: Deleting output file %s, if it exists.\n", 785 progName, outName ); 786 if (outputHandleJustInCase != NULL) 787 fclose ( outputHandleJustInCase ); 788 retVal = remove ( outName ); 789 if (retVal != 0) 790 fprintf ( stderr, 791 "%s: WARNING: deletion of output file " 792 "(apparently) failed.\n", 793 progName ); 794 } else { 795 fprintf ( stderr, 796 "%s: WARNING: deletion of output file suppressed\n", 797 progName ); 798 fprintf ( stderr, 799 "%s: since input file no longer exists. Output file\n", 800 progName ); 801 fprintf ( stderr, 802 "%s: `%s' may be incomplete.\n", 803 progName, outName ); 804 fprintf ( stderr, 805 "%s: I suggest doing an integrity test (bzip2 -tv)" 806 " of it.\n", 807 progName ); 808 } 809 } 810 811 if (noisy && numFileNames > 0 && numFilesProcessed < numFileNames) { 812 fprintf ( stderr, 813 "%s: WARNING: some files have not been processed:\n" 814 "%s: %d specified on command line, %d not processed yet.\n\n", 815 progName, progName, 816 numFileNames, numFileNames - numFilesProcessed ); 817 } 818 setExit(ec); 819 exit(exitValue); 820 } 821 822 823 /*---------------------------------------------*/ 824 static 825 void panic ( Char* s ) 826 { 827 fprintf ( stderr, 828 "\n%s: PANIC -- internal consistency error:\n" 829 "\t%s\n" 830 "\tThis is a BUG. Please report it to me at:\n" 831 "\tjseward@acm.org\n", 832 progName, s ); 833 showFileNames(); 834 cleanUpAndFail( 3 ); 835 } 836 837 838 /*---------------------------------------------*/ 839 static 840 void crcError ( void ) 841 { 842 fprintf ( stderr, 843 "\n%s: Data integrity error when decompressing.\n", 844 progName ); 845 showFileNames(); 846 cadvise(); 847 cleanUpAndFail( 2 ); 848 } 849 850 851 /*---------------------------------------------*/ 852 static 853 void compressedStreamEOF ( void ) 854 { 855 if (noisy) { 856 fprintf ( stderr, 857 "\n%s: Compressed file ends unexpectedly;\n\t" 858 "perhaps it is corrupted? *Possible* reason follows.\n", 859 progName ); 860 perror ( progName ); 861 showFileNames(); 862 cadvise(); 863 } 864 cleanUpAndFail( 2 ); 865 } 866 867 868 /*---------------------------------------------*/ 869 static 870 void ioError ( void ) 871 { 872 fprintf ( stderr, 873 "\n%s: I/O or other error, bailing out. " 874 "Possible reason follows.\n", 875 progName ); 876 perror ( progName ); 877 showFileNames(); 878 cleanUpAndFail( 1 ); 879 } 880 881 882 /*---------------------------------------------*/ 883 static 884 void mySignalCatcher ( IntNative n ) 885 { 886 fprintf ( stderr, 887 "\n%s: Control-C or similar caught, quitting.\n", 888 progName ); 889 cleanUpAndFail(1); 890 } 891 892 893 /*---------------------------------------------*/ 894 static 895 void mySIGSEGVorSIGBUScatcher ( IntNative n ) 896 { 897 if (opMode == OM_Z) 898 fprintf ( 899 stderr, 900 "\n%s: Caught a SIGSEGV or SIGBUS whilst compressing.\n" 901 "\n" 902 " Possible causes are (most likely first):\n" 903 " (1) This computer has unreliable memory or cache hardware\n" 904 " (a surprisingly common problem; try a different machine.)\n" 905 " (2) A bug in the compiler used to create this executable\n" 906 " (unlikely, if you didn't compile bzip2 yourself.)\n" 907 " (3) A real bug in bzip2 -- I hope this should never be the case.\n" 908 " The user's manual, Section 4.3, has more info on (1) and (2).\n" 909 " \n" 910 " If you suspect this is a bug in bzip2, or are unsure about (1)\n" 911 " or (2), feel free to report it to me at: jseward@acm.org.\n" 912 " Section 4.3 of the user's manual describes the info a useful\n" 913 " bug report should have. If the manual is available on your\n" 914 " system, please try and read it before mailing me. If you don't\n" 915 " have the manual or can't be bothered to read it, mail me anyway.\n" 916 "\n", 917 progName ); 918 else 919 fprintf ( 920 stderr, 921 "\n%s: Caught a SIGSEGV or SIGBUS whilst decompressing.\n" 922 "\n" 923 " Possible causes are (most likely first):\n" 924 " (1) The compressed data is corrupted, and bzip2's usual checks\n" 925 " failed to detect this. Try bzip2 -tvv my_file.bz2.\n" 926 " (2) This computer has unreliable memory or cache hardware\n" 927 " (a surprisingly common problem; try a different machine.)\n" 928 " (3) A bug in the compiler used to create this executable\n" 929 " (unlikely, if you didn't compile bzip2 yourself.)\n" 930 " (4) A real bug in bzip2 -- I hope this should never be the case.\n" 931 " The user's manual, Section 4.3, has more info on (2) and (3).\n" 932 " \n" 933 " If you suspect this is a bug in bzip2, or are unsure about (2)\n" 934 " or (3), feel free to report it to me at: jseward@acm.org.\n" 935 " Section 4.3 of the user's manual describes the info a useful\n" 936 " bug report should have. If the manual is available on your\n" 937 " system, please try and read it before mailing me. If you don't\n" 938 " have the manual or can't be bothered to read it, mail me anyway.\n" 939 "\n", 940 progName ); 941 942 showFileNames(); 943 if (opMode == OM_Z) 944 cleanUpAndFail( 3 ); else 945 { cadvise(); cleanUpAndFail( 2 ); } 946 } 947 948 949 /*---------------------------------------------*/ 950 static 951 void outOfMemory ( void ) 952 { 953 fprintf ( stderr, 954 "\n%s: couldn't allocate enough memory\n", 955 progName ); 956 showFileNames(); 957 cleanUpAndFail(1); 958 } 959 960 961 /*---------------------------------------------*/ 962 static 963 void configError ( void ) 964 { 965 fprintf ( stderr, 966 "bzip2: I'm not configured correctly for this platform!\n" 967 "\tI require Int32, Int16 and Char to have sizes\n" 968 "\tof 4, 2 and 1 bytes to run properly, and they don't.\n" 969 "\tProbably you can fix this by defining them correctly,\n" 970 "\tand recompiling. Bye!\n" ); 971 setExit(3); 972 exit(exitValue); 973 } 974 975 976 /*---------------------------------------------------*/ 977 /*--- The main driver machinery ---*/ 978 /*---------------------------------------------------*/ 979 980 /* All rather crufty. The main problem is that input files 981 are stat()d multiple times before use. This should be 982 cleaned up. 983 */ 984 985 /*---------------------------------------------*/ 986 static 987 void pad ( Char *s ) 988 { 989 Int32 i; 990 if ( (Int32)strlen(s) >= longestFileName ) return; 991 for (i = 1; i <= longestFileName - (Int32)strlen(s); i++) 992 fprintf ( stderr, " " ); 993 } 994 995 996 /*---------------------------------------------*/ 997 static 998 void copyFileName ( Char* to, Char* from ) 999 { 1000 if ( strlen(from) > FILE_NAME_LEN-10 ) { 1001 fprintf ( 1002 stderr, 1003 "bzip2: file name\n`%s'\n" 1004 "is suspiciously (more than %d chars) long.\n" 1005 "Try using a reasonable file name instead. Sorry! :-)\n", 1006 from, FILE_NAME_LEN-10 1007 ); 1008 setExit(1); 1009 exit(exitValue); 1010 } 1011 1012 strncpy(to,from,FILE_NAME_LEN-10); 1013 to[FILE_NAME_LEN-10]='\0'; 1014 } 1015 1016 1017 /*---------------------------------------------*/ 1018 static 1019 Bool fileExists ( Char* name ) 1020 { 1021 FILE *tmp = fopen ( name, "rb" ); 1022 Bool exists = (tmp != NULL); 1023 if (tmp != NULL) fclose ( tmp ); 1024 return exists; 1025 } 1026 1027 1028 /*---------------------------------------------*/ 1029 /* Open an output file safely with O_EXCL and good permissions. 1030 This avoids a race condition in versions < 1.0.2, in which 1031 the file was first opened and then had its interim permissions 1032 set safely. We instead use open() to create the file with 1033 the interim permissions required. (--- --- rw-). 1034 1035 For non-Unix platforms, if we are not worrying about 1036 security issues, simple this simply behaves like fopen. 1037 */ 1038 FILE* fopen_output_safely ( Char* name, const char* mode ) 1039 { 1040 # if BZ_UNIX 1041 FILE* fp; 1042 IntNative fh; 1043 fh = open(name, O_WRONLY|O_CREAT|O_EXCL, S_IWUSR|S_IRUSR); 1044 if (fh == -1) return NULL; 1045 fp = fdopen(fh, mode); 1046 if (fp == NULL) close(fh); 1047 return fp; 1048 # else 1049 return fopen(name, mode); 1050 # endif 1051 } 1052 1053 1054 /*---------------------------------------------*/ 1055 /*-- 1056 if in doubt, return True 1057 --*/ 1058 static 1059 Bool notAStandardFile ( Char* name ) 1060 { 1061 IntNative i; 1062 struct MY_STAT statBuf; 1063 1064 i = MY_LSTAT ( name, &statBuf ); 1065 if (i != 0) return True; 1066 if (MY_S_ISREG(statBuf.st_mode)) return False; 1067 return True; 1068 } 1069 1070 1071 /*---------------------------------------------*/ 1072 /*-- 1073 rac 11/21/98 see if file has hard links to it 1074 --*/ 1075 static 1076 Int32 countHardLinks ( Char* name ) 1077 { 1078 IntNative i; 1079 struct MY_STAT statBuf; 1080 1081 i = MY_LSTAT ( name, &statBuf ); 1082 if (i != 0) return 0; 1083 return (statBuf.st_nlink - 1); 1084 } 1085 1086 1087 /*---------------------------------------------*/ 1088 /* Copy modification date, access date, permissions and owner from the 1089 source to destination file. We have to copy this meta-info off 1090 into fileMetaInfo before starting to compress / decompress it, 1091 because doing it afterwards means we get the wrong access time. 1092 1093 To complicate matters, in compress() and decompress() below, the 1094 sequence of tests preceding the call to saveInputFileMetaInfo() 1095 involves calling fileExists(), which in turn establishes its result 1096 by attempting to fopen() the file, and if successful, immediately 1097 fclose()ing it again. So we have to assume that the fopen() call 1098 does not cause the access time field to be updated. 1099 1100 Reading of the man page for stat() (man 2 stat) on RedHat 7.2 seems 1101 to imply that merely doing open() will not affect the access time. 1102 Therefore we merely need to hope that the C library only does 1103 open() as a result of fopen(), and not any kind of read()-ahead 1104 cleverness. 1105 1106 It sounds pretty fragile to me. Whether this carries across 1107 robustly to arbitrary Unix-like platforms (or even works robustly 1108 on this one, RedHat 7.2) is unknown to me. Nevertheless ... 1109 */ 1110 #if BZ_UNIX 1111 static 1112 struct MY_STAT fileMetaInfo; 1113 #endif 1114 1115 static 1116 void saveInputFileMetaInfo ( Char *srcName ) 1117 { 1118 # if BZ_UNIX 1119 IntNative retVal; 1120 /* Note use of stat here, not lstat. */ 1121 retVal = MY_STAT( srcName, &fileMetaInfo ); 1122 ERROR_IF_NOT_ZERO ( retVal ); 1123 # endif 1124 } 1125 1126 1127 static 1128 void applySavedMetaInfoToOutputFile ( Char *dstName ) 1129 { 1130 # if BZ_UNIX 1131 IntNative retVal; 1132 struct utimbuf uTimBuf; 1133 1134 uTimBuf.actime = fileMetaInfo.st_atime; 1135 uTimBuf.modtime = fileMetaInfo.st_mtime; 1136 1137 retVal = chmod ( dstName, fileMetaInfo.st_mode ); 1138 ERROR_IF_NOT_ZERO ( retVal ); 1139 1140 retVal = utime ( dstName, &uTimBuf ); 1141 ERROR_IF_NOT_ZERO ( retVal ); 1142 1143 retVal = chown ( dstName, fileMetaInfo.st_uid, fileMetaInfo.st_gid ); 1144 /* chown() will in many cases return with EPERM, which can 1145 be safely ignored. 1146 */ 1147 # endif 1148 } 1149 1150 1151 /*---------------------------------------------*/ 1152 static 1153 Bool containsDubiousChars ( Char* name ) 1154 { 1155 # if BZ_UNIX 1156 /* On unix, files can contain any characters and the file expansion 1157 * is performed by the shell. 1158 */ 1159 return False; 1160 # else /* ! BZ_UNIX */ 1161 /* On non-unix (Win* platforms), wildcard characters are not allowed in 1162 * filenames. 1163 */ 1164 for (; *name != '\0'; name++) 1165 if (*name == '?' || *name == '*') return True; 1166 return False; 1167 # endif /* BZ_UNIX */ 1168 } 1169 1170 1171 /*---------------------------------------------*/ 1172 #define BZ_N_SUFFIX_PAIRS 4 1173 1174 Char* zSuffix[BZ_N_SUFFIX_PAIRS] 1175 = { ".bz2", ".bz", ".tbz2", ".tbz" }; 1176 Char* unzSuffix[BZ_N_SUFFIX_PAIRS] 1177 = { "", "", ".tar", ".tar" }; 1178 1179 static 1180 Bool hasSuffix ( Char* s, Char* suffix ) 1181 { 1182 Int32 ns = strlen(s); 1183 Int32 nx = strlen(suffix); 1184 if (ns < nx) return False; 1185 if (strcmp(s + ns - nx, suffix) == 0) return True; 1186 return False; 1187 } 1188 1189 static 1190 Bool mapSuffix ( Char* name, 1191 Char* oldSuffix, Char* newSuffix ) 1192 { 1193 if (!hasSuffix(name,oldSuffix)) return False; 1194 name[strlen(name)-strlen(oldSuffix)] = 0; 1195 strcat ( name, newSuffix ); 1196 return True; 1197 } 1198 1199 1200 /*---------------------------------------------*/ 1201 static 1202 void compress ( Char *name ) 1203 { 1204 FILE *inStr; 1205 FILE *outStr; 1206 Int32 n, i; 1207 struct MY_STAT statBuf; 1208 1209 deleteOutputOnInterrupt = False; 1210 1211 if (name == NULL && srcMode != SM_I2O) 1212 panic ( "compress: bad modes\n" ); 1213 1214 switch (srcMode) { 1215 case SM_I2O: 1216 copyFileName ( inName, "(stdin)" ); 1217 copyFileName ( outName, "(stdout)" ); 1218 break; 1219 case SM_F2F: 1220 copyFileName ( inName, name ); 1221 copyFileName ( outName, name ); 1222 strcat ( outName, ".bz2" ); 1223 break; 1224 case SM_F2O: 1225 copyFileName ( inName, name ); 1226 copyFileName ( outName, "(stdout)" ); 1227 break; 1228 } 1229 1230 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) { 1231 if (noisy) 1232 fprintf ( stderr, "%s: There are no files matching `%s'.\n", 1233 progName, inName ); 1234 setExit(1); 1235 return; 1236 } 1237 if ( srcMode != SM_I2O && !fileExists ( inName ) ) { 1238 fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 1239 progName, inName, strerror(errno) ); 1240 setExit(1); 1241 return; 1242 } 1243 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) { 1244 if (hasSuffix(inName, zSuffix[i])) { 1245 if (noisy) 1246 fprintf ( stderr, 1247 "%s: Input file %s already has %s suffix.\n", 1248 progName, inName, zSuffix[i] ); 1249 setExit(1); 1250 return; 1251 } 1252 } 1253 if ( srcMode == SM_F2F || srcMode == SM_F2O ) { 1254 MY_STAT(inName, &statBuf); 1255 if ( MY_S_ISDIR(statBuf.st_mode) ) { 1256 fprintf( stderr, 1257 "%s: Input file %s is a directory.\n", 1258 progName,inName); 1259 setExit(1); 1260 return; 1261 } 1262 } 1263 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) { 1264 if (noisy) 1265 fprintf ( stderr, "%s: Input file %s is not a normal file.\n", 1266 progName, inName ); 1267 setExit(1); 1268 return; 1269 } 1270 if ( srcMode == SM_F2F && fileExists ( outName ) ) { 1271 if (forceOverwrite) { 1272 remove(outName); 1273 } else { 1274 fprintf ( stderr, "%s: Output file %s already exists.\n", 1275 progName, outName ); 1276 setExit(1); 1277 return; 1278 } 1279 } 1280 if ( srcMode == SM_F2F && !forceOverwrite && 1281 (n=countHardLinks ( inName )) > 0) { 1282 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n", 1283 progName, inName, n, n > 1 ? "s" : "" ); 1284 setExit(1); 1285 return; 1286 } 1287 1288 if ( srcMode == SM_F2F ) { 1289 /* Save the file's meta-info before we open it. Doing it later 1290 means we mess up the access times. */ 1291 saveInputFileMetaInfo ( inName ); 1292 } 1293 1294 switch ( srcMode ) { 1295 1296 case SM_I2O: 1297 inStr = stdin; 1298 outStr = stdout; 1299 if ( isatty ( fileno ( stdout ) ) ) { 1300 fprintf ( stderr, 1301 "%s: I won't write compressed data to a terminal.\n", 1302 progName ); 1303 fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 1304 progName, progName ); 1305 setExit(1); 1306 return; 1307 }; 1308 break; 1309 1310 case SM_F2O: 1311 inStr = fopen ( inName, "rb" ); 1312 outStr = stdout; 1313 if ( isatty ( fileno ( stdout ) ) ) { 1314 fprintf ( stderr, 1315 "%s: I won't write compressed data to a terminal.\n", 1316 progName ); 1317 fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 1318 progName, progName ); 1319 if ( inStr != NULL ) fclose ( inStr ); 1320 setExit(1); 1321 return; 1322 }; 1323 if ( inStr == NULL ) { 1324 fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 1325 progName, inName, strerror(errno) ); 1326 setExit(1); 1327 return; 1328 }; 1329 break; 1330 1331 case SM_F2F: 1332 inStr = fopen ( inName, "rb" ); 1333 outStr = fopen_output_safely ( outName, "wb" ); 1334 if ( outStr == NULL) { 1335 fprintf ( stderr, "%s: Can't create output file %s: %s.\n", 1336 progName, outName, strerror(errno) ); 1337 if ( inStr != NULL ) fclose ( inStr ); 1338 setExit(1); 1339 return; 1340 } 1341 if ( inStr == NULL ) { 1342 fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 1343 progName, inName, strerror(errno) ); 1344 if ( outStr != NULL ) fclose ( outStr ); 1345 setExit(1); 1346 return; 1347 }; 1348 break; 1349 1350 default: 1351 panic ( "compress: bad srcMode" ); 1352 break; 1353 } 1354 1355 if (verbosity >= 1) { 1356 fprintf ( stderr, " %s: ", inName ); 1357 pad ( inName ); 1358 fflush ( stderr ); 1359 } 1360 1361 /*--- Now the input and output handles are sane. Do the Biz. ---*/ 1362 outputHandleJustInCase = outStr; 1363 deleteOutputOnInterrupt = True; 1364 compressStream ( inStr, outStr ); 1365 outputHandleJustInCase = NULL; 1366 1367 /*--- If there was an I/O error, we won't get here. ---*/ 1368 if ( srcMode == SM_F2F ) { 1369 applySavedMetaInfoToOutputFile ( outName ); 1370 deleteOutputOnInterrupt = False; 1371 if ( !keepInputFiles ) { 1372 IntNative retVal = remove ( inName ); 1373 ERROR_IF_NOT_ZERO ( retVal ); 1374 } 1375 } 1376 1377 deleteOutputOnInterrupt = False; 1378 } 1379 1380 1381 /*---------------------------------------------*/ 1382 static 1383 void uncompress ( Char *name ) 1384 { 1385 FILE *inStr; 1386 FILE *outStr; 1387 Int32 n, i; 1388 Bool magicNumberOK; 1389 Bool cantGuess; 1390 struct MY_STAT statBuf; 1391 1392 deleteOutputOnInterrupt = False; 1393 1394 if (name == NULL && srcMode != SM_I2O) 1395 panic ( "uncompress: bad modes\n" ); 1396 1397 cantGuess = False; 1398 switch (srcMode) { 1399 case SM_I2O: 1400 copyFileName ( inName, "(stdin)" ); 1401 copyFileName ( outName, "(stdout)" ); 1402 break; 1403 case SM_F2F: 1404 copyFileName ( inName, name ); 1405 copyFileName ( outName, name ); 1406 for (i = 0; i < BZ_N_SUFFIX_PAIRS; i++) 1407 if (mapSuffix(outName,zSuffix[i],unzSuffix[i])) 1408 goto zzz; 1409 cantGuess = True; 1410 strcat ( outName, ".out" ); 1411 break; 1412 case SM_F2O: 1413 copyFileName ( inName, name ); 1414 copyFileName ( outName, "(stdout)" ); 1415 break; 1416 } 1417 1418 zzz: 1419 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) { 1420 if (noisy) 1421 fprintf ( stderr, "%s: There are no files matching `%s'.\n", 1422 progName, inName ); 1423 setExit(1); 1424 return; 1425 } 1426 if ( srcMode != SM_I2O && !fileExists ( inName ) ) { 1427 fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 1428 progName, inName, strerror(errno) ); 1429 setExit(1); 1430 return; 1431 } 1432 if ( srcMode == SM_F2F || srcMode == SM_F2O ) { 1433 MY_STAT(inName, &statBuf); 1434 if ( MY_S_ISDIR(statBuf.st_mode) ) { 1435 fprintf( stderr, 1436 "%s: Input file %s is a directory.\n", 1437 progName,inName); 1438 setExit(1); 1439 return; 1440 } 1441 } 1442 if ( srcMode == SM_F2F && !forceOverwrite && notAStandardFile ( inName )) { 1443 if (noisy) 1444 fprintf ( stderr, "%s: Input file %s is not a normal file.\n", 1445 progName, inName ); 1446 setExit(1); 1447 return; 1448 } 1449 if ( /* srcMode == SM_F2F implied && */ cantGuess ) { 1450 if (noisy) 1451 fprintf ( stderr, 1452 "%s: Can't guess original name for %s -- using %s\n", 1453 progName, inName, outName ); 1454 /* just a warning, no return */ 1455 } 1456 if ( srcMode == SM_F2F && fileExists ( outName ) ) { 1457 if (forceOverwrite) { 1458 remove(outName); 1459 } else { 1460 fprintf ( stderr, "%s: Output file %s already exists.\n", 1461 progName, outName ); 1462 setExit(1); 1463 return; 1464 } 1465 } 1466 if ( srcMode == SM_F2F && !forceOverwrite && 1467 (n=countHardLinks ( inName ) ) > 0) { 1468 fprintf ( stderr, "%s: Input file %s has %d other link%s.\n", 1469 progName, inName, n, n > 1 ? "s" : "" ); 1470 setExit(1); 1471 return; 1472 } 1473 1474 if ( srcMode == SM_F2F ) { 1475 /* Save the file's meta-info before we open it. Doing it later 1476 means we mess up the access times. */ 1477 saveInputFileMetaInfo ( inName ); 1478 } 1479 1480 switch ( srcMode ) { 1481 1482 case SM_I2O: 1483 inStr = stdin; 1484 outStr = stdout; 1485 if ( isatty ( fileno ( stdin ) ) ) { 1486 fprintf ( stderr, 1487 "%s: I won't read compressed data from a terminal.\n", 1488 progName ); 1489 fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 1490 progName, progName ); 1491 setExit(1); 1492 return; 1493 }; 1494 break; 1495 1496 case SM_F2O: 1497 inStr = fopen ( inName, "rb" ); 1498 outStr = stdout; 1499 if ( inStr == NULL ) { 1500 fprintf ( stderr, "%s: Can't open input file %s:%s.\n", 1501 progName, inName, strerror(errno) ); 1502 if ( inStr != NULL ) fclose ( inStr ); 1503 setExit(1); 1504 return; 1505 }; 1506 break; 1507 1508 case SM_F2F: 1509 inStr = fopen ( inName, "rb" ); 1510 outStr = fopen_output_safely ( outName, "wb" ); 1511 if ( outStr == NULL) { 1512 fprintf ( stderr, "%s: Can't create output file %s: %s.\n", 1513 progName, outName, strerror(errno) ); 1514 if ( inStr != NULL ) fclose ( inStr ); 1515 setExit(1); 1516 return; 1517 } 1518 if ( inStr == NULL ) { 1519 fprintf ( stderr, "%s: Can't open input file %s: %s.\n", 1520 progName, inName, strerror(errno) ); 1521 if ( outStr != NULL ) fclose ( outStr ); 1522 setExit(1); 1523 return; 1524 }; 1525 break; 1526 1527 default: 1528 panic ( "uncompress: bad srcMode" ); 1529 break; 1530 } 1531 1532 if (verbosity >= 1) { 1533 fprintf ( stderr, " %s: ", inName ); 1534 pad ( inName ); 1535 fflush ( stderr ); 1536 } 1537 1538 /*--- Now the input and output handles are sane. Do the Biz. ---*/ 1539 outputHandleJustInCase = outStr; 1540 deleteOutputOnInterrupt = True; 1541 magicNumberOK = uncompressStream ( inStr, outStr ); 1542 outputHandleJustInCase = NULL; 1543 1544 /*--- If there was an I/O error, we won't get here. ---*/ 1545 if ( magicNumberOK ) { 1546 if ( srcMode == SM_F2F ) { 1547 applySavedMetaInfoToOutputFile ( outName ); 1548 deleteOutputOnInterrupt = False; 1549 if ( !keepInputFiles ) { 1550 IntNative retVal = remove ( inName ); 1551 ERROR_IF_NOT_ZERO ( retVal ); 1552 } 1553 } 1554 } else { 1555 unzFailsExist = True; 1556 deleteOutputOnInterrupt = False; 1557 if ( srcMode == SM_F2F ) { 1558 IntNative retVal = remove ( outName ); 1559 ERROR_IF_NOT_ZERO ( retVal ); 1560 } 1561 } 1562 deleteOutputOnInterrupt = False; 1563 1564 if ( magicNumberOK ) { 1565 if (verbosity >= 1) 1566 fprintf ( stderr, "done\n" ); 1567 } else { 1568 setExit(2); 1569 if (verbosity >= 1) 1570 fprintf ( stderr, "not a bzip2 file.\n" ); else 1571 fprintf ( stderr, 1572 "%s: %s is not a bzip2 file.\n", 1573 progName, inName ); 1574 } 1575 1576 } 1577 1578 1579 /*---------------------------------------------*/ 1580 static 1581 void testf ( Char *name ) 1582 { 1583 FILE *inStr; 1584 Bool allOK; 1585 struct MY_STAT statBuf; 1586 1587 deleteOutputOnInterrupt = False; 1588 1589 if (name == NULL && srcMode != SM_I2O) 1590 panic ( "testf: bad modes\n" ); 1591 1592 copyFileName ( outName, "(none)" ); 1593 switch (srcMode) { 1594 case SM_I2O: copyFileName ( inName, "(stdin)" ); break; 1595 case SM_F2F: copyFileName ( inName, name ); break; 1596 case SM_F2O: copyFileName ( inName, name ); break; 1597 } 1598 1599 if ( srcMode != SM_I2O && containsDubiousChars ( inName ) ) { 1600 if (noisy) 1601 fprintf ( stderr, "%s: There are no files matching `%s'.\n", 1602 progName, inName ); 1603 setExit(1); 1604 return; 1605 } 1606 if ( srcMode != SM_I2O && !fileExists ( inName ) ) { 1607 fprintf ( stderr, "%s: Can't open input %s: %s.\n", 1608 progName, inName, strerror(errno) ); 1609 setExit(1); 1610 return; 1611 } 1612 if ( srcMode != SM_I2O ) { 1613 MY_STAT(inName, &statBuf); 1614 if ( MY_S_ISDIR(statBuf.st_mode) ) { 1615 fprintf( stderr, 1616 "%s: Input file %s is a directory.\n", 1617 progName,inName); 1618 setExit(1); 1619 return; 1620 } 1621 } 1622 1623 switch ( srcMode ) { 1624 1625 case SM_I2O: 1626 if ( isatty ( fileno ( stdin ) ) ) { 1627 fprintf ( stderr, 1628 "%s: I won't read compressed data from a terminal.\n", 1629 progName ); 1630 fprintf ( stderr, "%s: For help, type: `%s --help'.\n", 1631 progName, progName ); 1632 setExit(1); 1633 return; 1634 }; 1635 inStr = stdin; 1636 break; 1637 1638 case SM_F2O: case SM_F2F: 1639 inStr = fopen ( inName, "rb" ); 1640 if ( inStr == NULL ) { 1641 fprintf ( stderr, "%s: Can't open input file %s:%s.\n", 1642 progName, inName, strerror(errno) ); 1643 setExit(1); 1644 return; 1645 }; 1646 break; 1647 1648 default: 1649 panic ( "testf: bad srcMode" ); 1650 break; 1651 } 1652 1653 if (verbosity >= 1) { 1654 fprintf ( stderr, " %s: ", inName ); 1655 pad ( inName ); 1656 fflush ( stderr ); 1657 } 1658 1659 /*--- Now the input handle is sane. Do the Biz. ---*/ 1660 outputHandleJustInCase = NULL; 1661 allOK = testStream ( inStr ); 1662 1663 if (allOK && verbosity >= 1) fprintf ( stderr, "ok\n" ); 1664 if (!allOK) testFailsExist = True; 1665 } 1666 1667 1668 /*---------------------------------------------*/ 1669 static 1670 void license ( void ) 1671 { 1672 fprintf ( stderr, 1673 1674 "bzip2, a block-sorting file compressor. " 1675 "Version %s.\n" 1676 " \n" 1677 " Copyright (C) 1996-2002 by Julian Seward.\n" 1678 " \n" 1679 " This program is free software; you can redistribute it and/or modify\n" 1680 " it under the terms set out in the LICENSE file, which is included\n" 1681 " in the bzip2-1.0 source distribution.\n" 1682 " \n" 1683 " This program is distributed in the hope that it will be useful,\n" 1684 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 1685 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 1686 " LICENSE file for more details.\n" 1687 " \n", 1688 BZ2_bzlibVersion() 1689 ); 1690 } 1691 1692 1693 /*---------------------------------------------*/ 1694 static 1695 void usage ( Char *fullProgName ) 1696 { 1697 fprintf ( 1698 stderr, 1699 "bzip2, a block-sorting file compressor. " 1700 "Version %s.\n" 1701 "\n usage: %s [flags and input files in any order]\n" 1702 "\n" 1703 " -h --help print this message\n" 1704 " -d --decompress force decompression\n" 1705 " -z --compress force compression\n" 1706 " -k --keep keep (don't delete) input files\n" 1707 " -f --force overwrite existing output files\n" 1708 " -t --test test compressed file integrity\n" 1709 " -c --stdout output to standard out\n" 1710 " -q --quiet suppress noncritical error messages\n" 1711 " -v --verbose be verbose (a 2nd -v gives more)\n" 1712 " -L --license display software version & license\n" 1713 " -V --version display software version & license\n" 1714 " -s --small use less memory (at most 2500k)\n" 1715 " -1 .. -9 set block size to 100k .. 900k\n" 1716 " --fast alias for -1\n" 1717 " --best alias for -9\n" 1718 "\n" 1719 " If invoked as `bzip2', default action is to compress.\n" 1720 " as `bunzip2', default action is to decompress.\n" 1721 " as `bzcat', default action is to decompress to stdout.\n" 1722 "\n" 1723 " If no file names are given, bzip2 compresses or decompresses\n" 1724 " from standard input to standard output. You can combine\n" 1725 " short flags, so `-v -4' means the same as -v4 or -4v, &c.\n" 1726 # if BZ_UNIX 1727 "\n" 1728 # endif 1729 , 1730 1731 BZ2_bzlibVersion(), 1732 fullProgName 1733 ); 1734 } 1735 1736 1737 /*---------------------------------------------*/ 1738 static 1739 void redundant ( Char* flag ) 1740 { 1741 fprintf ( 1742 stderr, 1743 "%s: %s is redundant in versions 0.9.5 and above\n", 1744 progName, flag ); 1745 } 1746 1747 1748 /*---------------------------------------------*/ 1749 /*-- 1750 All the garbage from here to main() is purely to 1751 implement a linked list of command-line arguments, 1752 into which main() copies argv[1 .. argc-1]. 1753 1754 The purpose of this exercise is to facilitate 1755 the expansion of wildcard characters * and ? in 1756 filenames for OSs which don't know how to do it 1757 themselves, like MSDOS, Windows 95 and NT. 1758 1759 The actual Dirty Work is done by the platform- 1760 specific macro APPEND_FILESPEC. 1761 --*/ 1762 1763 typedef 1764 struct zzzz { 1765 Char *name; 1766 struct zzzz *link; 1767 } 1768 Cell; 1769 1770 1771 /*---------------------------------------------*/ 1772 static 1773 void *myMalloc ( Int32 n ) 1774 { 1775 void* p; 1776 1777 p = malloc ( (size_t)n ); 1778 if (p == NULL) outOfMemory (); 1779 return p; 1780 } 1781 1782 1783 /*---------------------------------------------*/ 1784 static 1785 Cell *mkCell ( void ) 1786 { 1787 Cell *c; 1788 1789 c = (Cell*) myMalloc ( sizeof ( Cell ) ); 1790 c->name = NULL; 1791 c->link = NULL; 1792 return c; 1793 } 1794 1795 1796 /*---------------------------------------------*/ 1797 static 1798 Cell *snocString ( Cell *root, Char *name ) 1799 { 1800 if (root == NULL) { 1801 Cell *tmp = mkCell(); 1802 tmp->name = (Char*) myMalloc ( 5 + strlen(name) ); 1803 strcpy ( tmp->name, name ); 1804 return tmp; 1805 } else { 1806 Cell *tmp = root; 1807 while (tmp->link != NULL) tmp = tmp->link; 1808 tmp->link = snocString ( tmp->link, name ); 1809 return root; 1810 } 1811 } 1812 1813 1814 /*---------------------------------------------*/ 1815 static 1816 void addFlagsFromEnvVar ( Cell** argList, Char* varName ) 1817 { 1818 Int32 i, j, k; 1819 Char *envbase, *p; 1820 1821 envbase = getenv(varName); 1822 if (envbase != NULL) { 1823 p = envbase; 1824 i = 0; 1825 while (True) { 1826 if (p[i] == 0) break; 1827 p += i; 1828 i = 0; 1829 while (isspace((Int32)(p[0]))) p++; 1830 while (p[i] != 0 && !isspace((Int32)(p[i]))) i++; 1831 if (i > 0) { 1832 k = i; if (k > FILE_NAME_LEN-10) k = FILE_NAME_LEN-10; 1833 for (j = 0; j < k; j++) tmpName[j] = p[j]; 1834 tmpName[k] = 0; 1835 APPEND_FLAG(*argList, tmpName); 1836 } 1837 } 1838 } 1839 } 1840 1841 1842 /*---------------------------------------------*/ 1843 #define ISFLAG(s) (strcmp(aa->name, (s))==0) 1844 1845 IntNative main ( IntNative argc, Char *argv[] ) 1846 { 1847 Int32 i, j; 1848 Char *tmp; 1849 Cell *argList; 1850 Cell *aa; 1851 Bool decode; 1852 1853 /*-- Be really really really paranoid :-) --*/ 1854 if (sizeof(Int32) != 4 || sizeof(UInt32) != 4 || 1855 sizeof(Int16) != 2 || sizeof(UInt16) != 2 || 1856 sizeof(Char) != 1 || sizeof(UChar) != 1) 1857 configError(); 1858 1859 /*-- Initialise --*/ 1860 outputHandleJustInCase = NULL; 1861 smallMode = False; 1862 keepInputFiles = False; 1863 forceOverwrite = False; 1864 noisy = True; 1865 verbosity = 0; 1866 blockSize100k = 9; 1867 testFailsExist = False; 1868 unzFailsExist = False; 1869 numFileNames = 0; 1870 numFilesProcessed = 0; 1871 workFactor = 30; 1872 deleteOutputOnInterrupt = False; 1873 exitValue = 0; 1874 i = j = 0; /* avoid bogus warning from egcs-1.1.X */ 1875 1876 /*-- Set up signal handlers for mem access errors --*/ 1877 signal (SIGSEGV, mySIGSEGVorSIGBUScatcher); 1878 # if BZ_UNIX 1879 # ifndef __DJGPP__ 1880 signal (SIGBUS, mySIGSEGVorSIGBUScatcher); 1881 # endif 1882 # endif 1883 1884 copyFileName ( inName, "(none)" ); 1885 copyFileName ( outName, "(none)" ); 1886 1887 copyFileName ( progNameReally, argv[0] ); 1888 progName = &progNameReally[0]; 1889 for (tmp = &progNameReally[0]; *tmp != '\0'; tmp++) 1890 if (*tmp == PATH_SEP) progName = tmp + 1; 1891 1892 1893 /*-- Copy flags from env var BZIP2, and 1894 expand filename wildcards in arg list. 1895 --*/ 1896 argList = NULL; 1897 addFlagsFromEnvVar ( &argList, "BZIP2" ); 1898 addFlagsFromEnvVar ( &argList, "BZIP" ); 1899 for (i = 1; i <= argc-1; i++) 1900 APPEND_FILESPEC(argList, argv[i]); 1901 1902 1903 /*-- Find the length of the longest filename --*/ 1904 longestFileName = 7; 1905 numFileNames = 0; 1906 decode = True; 1907 for (aa = argList; aa != NULL; aa = aa->link) { 1908 if (ISFLAG("--")) { decode = False; continue; } 1909 if (aa->name[0] == '-' && decode) continue; 1910 numFileNames++; 1911 if (longestFileName < (Int32)strlen(aa->name) ) 1912 longestFileName = (Int32)strlen(aa->name); 1913 } 1914 1915 1916 /*-- Determine source modes; flag handling may change this too. --*/ 1917 if (numFileNames == 0) 1918 srcMode = SM_I2O; else srcMode = SM_F2F; 1919 1920 1921 /*-- Determine what to do (compress/uncompress/test/cat). --*/ 1922 /*-- Note that subsequent flag handling may change this. --*/ 1923 opMode = OM_Z; 1924 1925 if ( (strstr ( progName, "unzip" ) != 0) || 1926 (strstr ( progName, "UNZIP" ) != 0) ) 1927 opMode = OM_UNZ; 1928 1929 if ( (strstr ( progName, "z2cat" ) != 0) || 1930 (strstr ( progName, "Z2CAT" ) != 0) || 1931 (strstr ( progName, "zcat" ) != 0) || 1932 (strstr ( progName, "ZCAT" ) != 0) ) { 1933 opMode = OM_UNZ; 1934 srcMode = (numFileNames == 0) ? SM_I2O : SM_F2O; 1935 } 1936 1937 1938 /*-- Look at the flags. --*/ 1939 for (aa = argList; aa != NULL; aa = aa->link) { 1940 if (ISFLAG("--")) break; 1941 if (aa->name[0] == '-' && aa->name[1] != '-') { 1942 for (j = 1; aa->name[j] != '\0'; j++) { 1943 switch (aa->name[j]) { 1944 case 'c': srcMode = SM_F2O; break; 1945 case 'd': opMode = OM_UNZ; break; 1946 case 'z': opMode = OM_Z; break; 1947 case 'f': forceOverwrite = True; break; 1948 case 't': opMode = OM_TEST; break; 1949 case 'k': keepInputFiles = True; break; 1950 case 's': smallMode = True; break; 1951 case 'q': noisy = False; break; 1952 case '1': blockSize100k = 1; break; 1953 case '2': blockSize100k = 2; break; 1954 case '3': blockSize100k = 3; break; 1955 case '4': blockSize100k = 4; break; 1956 case '5': blockSize100k = 5; break; 1957 case '6': blockSize100k = 6; break; 1958 case '7': blockSize100k = 7; break; 1959 case '8': blockSize100k = 8; break; 1960 case '9': blockSize100k = 9; break; 1961 case 'V': 1962 case 'L': license(); break; 1963 case 'v': verbosity++; break; 1964 case 'h': usage ( progName ); 1965 exit ( 0 ); 1966 break; 1967 default: fprintf ( stderr, "%s: Bad flag `%s'\n", 1968 progName, aa->name ); 1969 usage ( progName ); 1970 exit ( 1 ); 1971 break; 1972 } 1973 } 1974 } 1975 } 1976 1977 /*-- And again ... --*/ 1978 for (aa = argList; aa != NULL; aa = aa->link) { 1979 if (ISFLAG("--")) break; 1980 if (ISFLAG("--stdout")) srcMode = SM_F2O; else 1981 if (ISFLAG("--decompress")) opMode = OM_UNZ; else 1982 if (ISFLAG("--compress")) opMode = OM_Z; else 1983 if (ISFLAG("--force")) forceOverwrite = True; else 1984 if (ISFLAG("--test")) opMode = OM_TEST; else 1985 if (ISFLAG("--keep")) keepInputFiles = True; else 1986 if (ISFLAG("--small")) smallMode = True; else 1987 if (ISFLAG("--quiet")) noisy = False; else 1988 if (ISFLAG("--version")) license(); else 1989 if (ISFLAG("--license")) license(); else 1990 if (ISFLAG("--exponential")) workFactor = 1; else 1991 if (ISFLAG("--repetitive-best")) redundant(aa->name); else 1992 if (ISFLAG("--repetitive-fast")) redundant(aa->name); else 1993 if (ISFLAG("--fast")) blockSize100k = 1; else 1994 if (ISFLAG("--best")) blockSize100k = 9; else 1995 if (ISFLAG("--verbose")) verbosity++; else 1996 if (ISFLAG("--help")) { usage ( progName ); exit ( 0 ); } 1997 else 1998 if (strncmp ( aa->name, "--", 2) == 0) { 1999 fprintf ( stderr, "%s: Bad flag `%s'\n", progName, aa->name ); 2000 usage ( progName ); 2001 exit ( 1 ); 2002 } 2003 } 2004 2005 if (verbosity > 4) verbosity = 4; 2006 if (opMode == OM_Z && smallMode && blockSize100k > 2) 2007 blockSize100k = 2; 2008 2009 if (opMode == OM_TEST && srcMode == SM_F2O) { 2010 fprintf ( stderr, "%s: -c and -t cannot be used together.\n", 2011 progName ); 2012 exit ( 1 ); 2013 } 2014 2015 if (srcMode == SM_F2O && numFileNames == 0) 2016 srcMode = SM_I2O; 2017 2018 if (opMode != OM_Z) blockSize100k = 0; 2019 2020 if (srcMode == SM_F2F) { 2021 signal (SIGINT, mySignalCatcher); 2022 signal (SIGTERM, mySignalCatcher); 2023 # if BZ_UNIX 2024 signal (SIGHUP, mySignalCatcher); 2025 # endif 2026 } 2027 2028 if (opMode == OM_Z) { 2029 if (srcMode == SM_I2O) { 2030 compress ( NULL ); 2031 } else { 2032 decode = True; 2033 for (aa = argList; aa != NULL; aa = aa->link) { 2034 if (ISFLAG("--")) { decode = False; continue; } 2035 if (aa->name[0] == '-' && decode) continue; 2036 numFilesProcessed++; 2037 compress ( aa->name ); 2038 } 2039 } 2040 } 2041 else 2042 2043 if (opMode == OM_UNZ) { 2044 unzFailsExist = False; 2045 if (srcMode == SM_I2O) { 2046 uncompress ( NULL ); 2047 } else { 2048 decode = True; 2049 for (aa = argList; aa != NULL; aa = aa->link) { 2050 if (ISFLAG("--")) { decode = False; continue; } 2051 if (aa->name[0] == '-' && decode) continue; 2052 numFilesProcessed++; 2053 uncompress ( aa->name ); 2054 } 2055 } 2056 if (unzFailsExist) { 2057 setExit(2); 2058 exit(exitValue); 2059 } 2060 } 2061 2062 else { 2063 testFailsExist = False; 2064 if (srcMode == SM_I2O) { 2065 testf ( NULL ); 2066 } else { 2067 decode = True; 2068 for (aa = argList; aa != NULL; aa = aa->link) { 2069 if (ISFLAG("--")) { decode = False; continue; } 2070 if (aa->name[0] == '-' && decode) continue; 2071 numFilesProcessed++; 2072 testf ( aa->name ); 2073 } 2074 } 2075 if (testFailsExist && noisy) { 2076 fprintf ( stderr, 2077 "\n" 2078 "You can use the `bzip2recover' program to attempt to recover\n" 2079 "data from undamaged sections of corrupted files.\n\n" 2080 ); 2081 setExit(2); 2082 exit(exitValue); 2083 } 2084 } 2085 2086 /* Free the argument list memory to mollify leak detectors 2087 (eg) Purify, Checker. Serves no other useful purpose. 2088 */ 2089 aa = argList; 2090 while (aa != NULL) { 2091 Cell* aa2 = aa->link; 2092 if (aa->name != NULL) free(aa->name); 2093 free(aa); 2094 aa = aa2; 2095 } 2096 2097 return exitValue; 2098 } 2099 2100 2101 /*-----------------------------------------------------------*/ 2102 /*--- end bzip2.c ---*/ 2103 /*-----------------------------------------------------------*/ 2104