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