annotate src/bzip2-1.0.6/bzip2.c @ 83:ae30d91d2ffe

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