PageRenderTime 96ms CodeModel.GetById 18ms app.highlight 66ms RepoModel.GetById 2ms app.codeStats 0ms

/StormLib/stormlib/bzip2/bzip2.c

http://ghostcb.googlecode.com/
C | 2034 lines | 1561 code | 272 blank | 201 comment | 478 complexity | 386040a1766c9d14d876ec78fbb0f662 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file