2 /*-----------------------------------------------------------*/
3 /*--- Block recoverer program for bzip2 ---*/
4 /*--- bzip2recover.c ---*/
5 /*-----------------------------------------------------------*/
8 This program is bzip2recover, a program to attempt data
9 salvage from damaged files created by the accompanying
12 Copyright (C) 1996-2000 Julian R Seward. All rights reserved.
14 Redistribution and use in source and binary forms, with or without
15 modification, are permitted provided that the following conditions
18 1. Redistributions of source code must retain the above copyright
19 notice, this list of conditions and the following disclaimer.
21 2. The origin of this software must not be misrepresented; you must
22 not claim that you wrote the original software. If you use this
23 software in a product, an acknowledgment in the product
24 documentation would be appreciated but is not required.
26 3. Altered source versions must be plainly marked as such, and must
27 not be misrepresented as being the original software.
29 4. The name of the author may not be used to endorse or promote
30 products derived from this software without specific prior written
33 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34 OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
39 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
41 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
43 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 Julian Seward, Cambridge, UK.
47 bzip2/libbzip2 version 1.0 of 21 March 2000
51 This program is a complete hack and should be rewritten
52 properly. It isn't very complicated.
60 typedef unsigned int UInt32;
62 typedef unsigned char UChar;
64 typedef unsigned char Bool;
65 #define True ((Bool)1)
66 #define False ((Bool)0)
69 Char inFileName[2000];
70 Char outFileName[2000];
77 /*---------------------------------------------------*/
78 /*--- I/O errors ---*/
79 /*---------------------------------------------------*/
81 /*---------------------------------------------*/
82 void readError ( void )
85 "%s: I/O error reading `%s', possible reason follows.\n",
86 progName, inFileName );
88 fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
94 /*---------------------------------------------*/
95 void writeError ( void )
98 "%s: I/O error reading `%s', possible reason follows.\n",
99 progName, inFileName );
101 fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
107 /*---------------------------------------------*/
108 void mallocFail ( Int32 n )
111 "%s: malloc failed on request for %d bytes.\n",
113 fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
119 /*---------------------------------------------------*/
120 /*--- Bit stream I/O ---*/
121 /*---------------------------------------------------*/
133 /*---------------------------------------------*/
134 BitStream* bsOpenReadStream ( FILE* stream )
136 BitStream *bs = malloc ( sizeof(BitStream) );
137 if (bs == NULL) mallocFail ( sizeof(BitStream) );
146 /*---------------------------------------------*/
147 BitStream* bsOpenWriteStream ( FILE* stream )
149 BitStream *bs = malloc ( sizeof(BitStream) );
150 if (bs == NULL) mallocFail ( sizeof(BitStream) );
159 /*---------------------------------------------*/
160 void bsPutBit ( BitStream* bs, Int32 bit )
162 if (bs->buffLive == 8) {
163 Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
164 if (retVal == EOF) writeError();
167 bs->buffer = bit & 0x1;
169 bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
175 /*---------------------------------------------*/
177 Returns 0 or 1, or 2 to indicate EOF.
179 Int32 bsGetBit ( BitStream* bs )
181 if (bs->buffLive > 0) {
183 return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
185 Int32 retVal = getc ( bs->handle );
186 if ( retVal == EOF ) {
187 if (errno != 0) readError();
192 return ( ((bs->buffer) >> 7) & 0x1 );
197 /*---------------------------------------------*/
198 void bsClose ( BitStream* bs )
202 if ( bs->mode == 'w' ) {
203 while ( bs->buffLive < 8 ) {
207 retVal = putc ( (UChar) (bs->buffer), bs->handle );
208 if (retVal == EOF) writeError();
210 retVal = fflush ( bs->handle );
211 if (retVal == EOF) writeError();
213 retVal = fclose ( bs->handle );
215 if (bs->mode == 'w') writeError(); else readError();
221 /*---------------------------------------------*/
222 void bsPutUChar ( BitStream* bs, UChar c )
225 for (i = 7; i >= 0; i--)
226 bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
230 /*---------------------------------------------*/
231 void bsPutUInt32 ( BitStream* bs, UInt32 c )
235 for (i = 31; i >= 0; i--)
236 bsPutBit ( bs, (c >> i) & 0x1 );
240 /*---------------------------------------------*/
241 Bool endsInBz2 ( Char* name )
243 Int32 n = strlen ( name );
244 if (n <= 4) return False;
253 /*---------------------------------------------------*/
255 /*---------------------------------------------------*/
257 #define BLOCK_HEADER_HI 0x00003141UL
258 #define BLOCK_HEADER_LO 0x59265359UL
260 #define BLOCK_ENDMARK_HI 0x00001772UL
261 #define BLOCK_ENDMARK_LO 0x45385090UL
264 UInt32 bStart[20000];
266 UInt32 rbStart[20000];
269 Int32 main ( Int32 argc, Char** argv )
273 BitStream* bsIn, *bsWr;
274 Int32 currBlock, b, wrBlock;
279 UInt32 buffHi, buffLo, blockCRC;
282 strcpy ( progName, argv[0] );
283 inFileName[0] = outFileName[0] = 0;
285 fprintf ( stderr, "bzip2recover 1.0: extracts blocks from damaged .bz2 files.\n" );
288 fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
289 progName, progName );
293 strcpy ( inFileName, argv[1] );
295 inFile = fopen ( inFileName, "rb" );
296 if (inFile == NULL) {
297 fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
301 bsIn = bsOpenReadStream ( inFile );
302 fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
307 bStart[currBlock] = 0;
312 b = bsGetBit ( bsIn );
315 if (bitsRead >= bStart[currBlock] &&
316 (bitsRead - bStart[currBlock]) >= 40) {
317 bEnd[currBlock] = bitsRead-1;
319 fprintf ( stderr, " block %d runs from %d to %d (incomplete)\n",
320 currBlock, bStart[currBlock], bEnd[currBlock] );
325 buffHi = (buffHi << 1) | (buffLo >> 31);
326 buffLo = (buffLo << 1) | (b & 1);
327 if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI
328 && buffLo == BLOCK_HEADER_LO)
330 ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI
331 && buffLo == BLOCK_ENDMARK_LO)
334 bEnd[currBlock] = bitsRead-49; else
337 (bEnd[currBlock] - bStart[currBlock]) >= 130) {
338 fprintf ( stderr, " block %d runs from %d to %d\n",
339 rbCtr+1, bStart[currBlock], bEnd[currBlock] );
340 rbStart[rbCtr] = bStart[currBlock];
341 rbEnd[rbCtr] = bEnd[currBlock];
346 bStart[currBlock] = bitsRead;
352 /*-- identified blocks run from 1 to rbCtr inclusive. --*/
356 "%s: sorry, I couldn't find any block boundaries.\n",
361 fprintf ( stderr, "%s: splitting into blocks\n", progName );
363 inFile = fopen ( inFileName, "rb" );
364 if (inFile == NULL) {
365 fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
368 bsIn = bsOpenReadStream ( inFile );
370 /*-- placate gcc's dataflow analyser --*/
371 blockCRC = 0; bsWr = 0;
379 buffHi = (buffHi << 1) | (buffLo >> 31);
380 buffLo = (buffLo << 1) | (b & 1);
381 if (bitsRead == 47+rbStart[wrBlock])
382 blockCRC = (buffHi << 16) | (buffLo >> 16);
384 if (outFile != NULL && bitsRead >= rbStart[wrBlock]
385 && bitsRead <= rbEnd[wrBlock]) {
386 bsPutBit ( bsWr, b );
391 if (bitsRead == rbEnd[wrBlock]+1) {
392 if (outFile != NULL) {
393 bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
394 bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
395 bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
396 bsPutUInt32 ( bsWr, blockCRC );
399 if (wrBlock >= rbCtr) break;
402 if (bitsRead == rbStart[wrBlock]) {
404 sprintf ( outFileName, "rec%4d", wrBlock+1 );
405 for (p = outFileName; *p != 0; p++) if (*p == ' ') *p = '0';
406 strcat ( outFileName, inFileName );
407 if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
409 fprintf ( stderr, " writing block %d to `%s' ...\n",
410 wrBlock+1, outFileName );
412 outFile = fopen ( outFileName, "wb" );
413 if (outFile == NULL) {
414 fprintf ( stderr, "%s: can't write `%s'\n",
415 progName, outFileName );
418 bsWr = bsOpenWriteStream ( outFile );
419 bsPutUChar ( bsWr, 'B' ); bsPutUChar ( bsWr, 'Z' );
420 bsPutUChar ( bsWr, 'h' ); bsPutUChar ( bsWr, '9' );
421 bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
422 bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
423 bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
427 fprintf ( stderr, "%s: finished\n", progName );
433 /*-----------------------------------------------------------*/
434 /*--- end bzip2recover.c ---*/
435 /*-----------------------------------------------------------*/