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