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