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