|  | 
 | /*-----------------------------------------------------------*/ | 
 | /*--- Block recoverer program for bzip2                   ---*/ | 
 | /*---                                      bzip2recover.c ---*/ | 
 | /*-----------------------------------------------------------*/ | 
 |  | 
 | /*-- | 
 |   This program is bzip2recover, a program to attempt data  | 
 |   salvage from damaged files created by the accompanying | 
 |   bzip2-1.0 program. | 
 |  | 
 |   Copyright (C) 1996-2000 Julian R Seward.  All rights reserved. | 
 |  | 
 |   Redistribution and use in source and binary forms, with or without | 
 |   modification, are permitted provided that the following conditions | 
 |   are met: | 
 |  | 
 |   1. Redistributions of source code must retain the above copyright | 
 |      notice, this list of conditions and the following disclaimer. | 
 |  | 
 |   2. The origin of this software must not be misrepresented; you must  | 
 |      not claim that you wrote the original software.  If you use this  | 
 |      software in a product, an acknowledgment in the product  | 
 |      documentation would be appreciated but is not required. | 
 |  | 
 |   3. Altered source versions must be plainly marked as such, and must | 
 |      not be misrepresented as being the original software. | 
 |  | 
 |   4. The name of the author may not be used to endorse or promote  | 
 |      products derived from this software without specific prior written  | 
 |      permission. | 
 |  | 
 |   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS | 
 |   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 
 |   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
 |   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | 
 |   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
 |   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE | 
 |   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
 |   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | 
 |   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | 
 |   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 
 |   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  | 
 |   Julian Seward, Cambridge, UK. | 
 |   jseward@acm.org | 
 |   bzip2/libbzip2 version 1.0 of 21 March 2000 | 
 | --*/ | 
 |  | 
 | /*-- | 
 |   This program is a complete hack and should be rewritten | 
 |   properly.  It isn't very complicated. | 
 | --*/ | 
 |  | 
 | #include <stdio.h> | 
 | #include <errno.h> | 
 | #include <stdlib.h> | 
 | #include <string.h> | 
 |  | 
 | typedef  unsigned int   UInt32; | 
 | typedef  int            Int32; | 
 | typedef  unsigned char  UChar; | 
 | typedef  char           Char; | 
 | typedef  unsigned char  Bool; | 
 | #define True    ((Bool)1) | 
 | #define False   ((Bool)0) | 
 |  | 
 |  | 
 | Char inFileName[2000]; | 
 | Char outFileName[2000]; | 
 | Char progName[2000]; | 
 |  | 
 | UInt32 bytesOut = 0; | 
 | UInt32 bytesIn  = 0; | 
 |  | 
 |  | 
 | /*---------------------------------------------------*/ | 
 | /*--- I/O errors                                  ---*/ | 
 | /*---------------------------------------------------*/ | 
 |  | 
 | /*---------------------------------------------*/ | 
 | void readError ( void ) | 
 | { | 
 |    fprintf ( stderr, | 
 |              "%s: I/O error reading `%s', possible reason follows.\n", | 
 |             progName, inFileName ); | 
 |    perror ( progName ); | 
 |    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", | 
 |              progName ); | 
 |    exit ( 1 ); | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | void writeError ( void ) | 
 | { | 
 |    fprintf ( stderr, | 
 |              "%s: I/O error reading `%s', possible reason follows.\n", | 
 |             progName, inFileName ); | 
 |    perror ( progName ); | 
 |    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", | 
 |              progName ); | 
 |    exit ( 1 ); | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | void mallocFail ( Int32 n ) | 
 | { | 
 |    fprintf ( stderr, | 
 |              "%s: malloc failed on request for %d bytes.\n", | 
 |             progName, n ); | 
 |    fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", | 
 |              progName ); | 
 |    exit ( 1 ); | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------------*/ | 
 | /*--- Bit stream I/O                              ---*/ | 
 | /*---------------------------------------------------*/ | 
 |  | 
 | typedef | 
 |    struct { | 
 |       FILE*  handle; | 
 |       Int32  buffer; | 
 |       Int32  buffLive; | 
 |       Char   mode; | 
 |    } | 
 |    BitStream; | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | BitStream* bsOpenReadStream ( FILE* stream ) | 
 | { | 
 |    BitStream *bs = malloc ( sizeof(BitStream) ); | 
 |    if (bs == NULL) mallocFail ( sizeof(BitStream) ); | 
 |    bs->handle = stream; | 
 |    bs->buffer = 0; | 
 |    bs->buffLive = 0; | 
 |    bs->mode = 'r'; | 
 |    return bs; | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | BitStream* bsOpenWriteStream ( FILE* stream ) | 
 | { | 
 |    BitStream *bs = malloc ( sizeof(BitStream) ); | 
 |    if (bs == NULL) mallocFail ( sizeof(BitStream) ); | 
 |    bs->handle = stream; | 
 |    bs->buffer = 0; | 
 |    bs->buffLive = 0; | 
 |    bs->mode = 'w'; | 
 |    return bs; | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | void bsPutBit ( BitStream* bs, Int32 bit ) | 
 | { | 
 |    if (bs->buffLive == 8) { | 
 |       Int32 retVal = putc ( (UChar) bs->buffer, bs->handle ); | 
 |       if (retVal == EOF) writeError(); | 
 |       bytesOut++; | 
 |       bs->buffLive = 1; | 
 |       bs->buffer = bit & 0x1; | 
 |    } else { | 
 |       bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) ); | 
 |       bs->buffLive++; | 
 |    }; | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | /*-- | 
 |    Returns 0 or 1, or 2 to indicate EOF. | 
 | --*/ | 
 | Int32 bsGetBit ( BitStream* bs ) | 
 | { | 
 |    if (bs->buffLive > 0) { | 
 |       bs->buffLive --; | 
 |       return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 ); | 
 |    } else { | 
 |       Int32 retVal = getc ( bs->handle ); | 
 |       if ( retVal == EOF ) { | 
 |          if (errno != 0) readError(); | 
 |          return 2; | 
 |       } | 
 |       bs->buffLive = 7; | 
 |       bs->buffer = retVal; | 
 |       return ( ((bs->buffer) >> 7) & 0x1 ); | 
 |    } | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | void bsClose ( BitStream* bs ) | 
 | { | 
 |    Int32 retVal; | 
 |  | 
 |    if ( bs->mode == 'w' ) { | 
 |       while ( bs->buffLive < 8 ) { | 
 |          bs->buffLive++; | 
 |          bs->buffer <<= 1; | 
 |       }; | 
 |       retVal = putc ( (UChar) (bs->buffer), bs->handle ); | 
 |       if (retVal == EOF) writeError(); | 
 |       bytesOut++; | 
 |       retVal = fflush ( bs->handle ); | 
 |       if (retVal == EOF) writeError(); | 
 |    } | 
 |    retVal = fclose ( bs->handle ); | 
 |    if (retVal == EOF) { | 
 |       if (bs->mode == 'w') writeError(); else readError(); | 
 |    } | 
 |    free ( bs ); | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | void bsPutUChar ( BitStream* bs, UChar c ) | 
 | { | 
 |    Int32 i; | 
 |    for (i = 7; i >= 0; i--) | 
 |       bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 ); | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | void bsPutUInt32 ( BitStream* bs, UInt32 c ) | 
 | { | 
 |    Int32 i; | 
 |  | 
 |    for (i = 31; i >= 0; i--) | 
 |       bsPutBit ( bs, (c >> i) & 0x1 ); | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------*/ | 
 | Bool endsInBz2 ( Char* name ) | 
 | { | 
 |    Int32 n = strlen ( name ); | 
 |    if (n <= 4) return False; | 
 |    return | 
 |       (name[n-4] == '.' && | 
 |        name[n-3] == 'b' && | 
 |        name[n-2] == 'z' && | 
 |        name[n-1] == '2'); | 
 | } | 
 |  | 
 |  | 
 | /*---------------------------------------------------*/ | 
 | /*---                                             ---*/ | 
 | /*---------------------------------------------------*/ | 
 |  | 
 | #define BLOCK_HEADER_HI  0x00003141UL | 
 | #define BLOCK_HEADER_LO  0x59265359UL | 
 |  | 
 | #define BLOCK_ENDMARK_HI 0x00001772UL | 
 | #define BLOCK_ENDMARK_LO 0x45385090UL | 
 |  | 
 |  | 
 | UInt32 bStart[20000]; | 
 | UInt32 bEnd[20000]; | 
 | UInt32 rbStart[20000]; | 
 | UInt32 rbEnd[20000]; | 
 |  | 
 | Int32 main ( Int32 argc, Char** argv ) | 
 | { | 
 |    FILE*       inFile; | 
 |    FILE*       outFile; | 
 |    BitStream*  bsIn, *bsWr; | 
 |    Int32       currBlock, b, wrBlock; | 
 |    UInt32      bitsRead; | 
 |    Int32       rbCtr; | 
 |  | 
 |  | 
 |    UInt32      buffHi, buffLo, blockCRC; | 
 |    Char*       p; | 
 |  | 
 |    strcpy ( progName, argv[0] ); | 
 |    inFileName[0] = outFileName[0] = 0; | 
 |  | 
 |    fprintf ( stderr, "bzip2recover 1.0: extracts blocks from damaged .bz2 files.\n" ); | 
 |  | 
 |    if (argc != 2) { | 
 |       fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n", | 
 |                         progName, progName ); | 
 |       exit(1); | 
 |    } | 
 |  | 
 |    strcpy ( inFileName, argv[1] ); | 
 |  | 
 |    inFile = fopen ( inFileName, "rb" ); | 
 |    if (inFile == NULL) { | 
 |       fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName ); | 
 |       exit(1); | 
 |    } | 
 |  | 
 |    bsIn = bsOpenReadStream ( inFile ); | 
 |    fprintf ( stderr, "%s: searching for block boundaries ...\n", progName ); | 
 |  | 
 |    bitsRead = 0; | 
 |    buffHi = buffLo = 0; | 
 |    currBlock = 0; | 
 |    bStart[currBlock] = 0; | 
 |  | 
 |    rbCtr = 0; | 
 |  | 
 |    while (True) { | 
 |       b = bsGetBit ( bsIn ); | 
 |       bitsRead++; | 
 |       if (b == 2) { | 
 |          if (bitsRead >= bStart[currBlock] && | 
 |             (bitsRead - bStart[currBlock]) >= 40) { | 
 |             bEnd[currBlock] = bitsRead-1; | 
 |             if (currBlock > 0) | 
 |                fprintf ( stderr, "   block %d runs from %d to %d (incomplete)\n", | 
 |                          currBlock,  bStart[currBlock], bEnd[currBlock] ); | 
 |          } else | 
 |             currBlock--; | 
 |          break; | 
 |       } | 
 |       buffHi = (buffHi << 1) | (buffLo >> 31); | 
 |       buffLo = (buffLo << 1) | (b & 1); | 
 |       if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI  | 
 |              && buffLo == BLOCK_HEADER_LO) | 
 |            ||  | 
 |            ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI  | 
 |              && buffLo == BLOCK_ENDMARK_LO) | 
 |          ) { | 
 |          if (bitsRead > 49) | 
 |             bEnd[currBlock] = bitsRead-49; else | 
 |             bEnd[currBlock] = 0; | 
 |          if (currBlock > 0 && | 
 | 	     (bEnd[currBlock] - bStart[currBlock]) >= 130) { | 
 |             fprintf ( stderr, "   block %d runs from %d to %d\n", | 
 |                       rbCtr+1,  bStart[currBlock], bEnd[currBlock] ); | 
 |             rbStart[rbCtr] = bStart[currBlock]; | 
 |             rbEnd[rbCtr] = bEnd[currBlock]; | 
 |             rbCtr++; | 
 |          } | 
 |          currBlock++; | 
 |  | 
 |          bStart[currBlock] = bitsRead; | 
 |       } | 
 |    } | 
 |  | 
 |    bsClose ( bsIn ); | 
 |  | 
 |    /*-- identified blocks run from 1 to rbCtr inclusive. --*/ | 
 |  | 
 |    if (rbCtr < 1) { | 
 |       fprintf ( stderr, | 
 |                 "%s: sorry, I couldn't find any block boundaries.\n", | 
 |                 progName ); | 
 |       exit(1); | 
 |    }; | 
 |  | 
 |    fprintf ( stderr, "%s: splitting into blocks\n", progName ); | 
 |  | 
 |    inFile = fopen ( inFileName, "rb" ); | 
 |    if (inFile == NULL) { | 
 |       fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName ); | 
 |       exit(1); | 
 |    } | 
 |    bsIn = bsOpenReadStream ( inFile ); | 
 |  | 
 |    /*-- placate gcc's dataflow analyser --*/ | 
 |    blockCRC = 0; bsWr = 0; | 
 |  | 
 |    bitsRead = 0; | 
 |    outFile = NULL; | 
 |    wrBlock = 0; | 
 |    while (True) { | 
 |       b = bsGetBit(bsIn); | 
 |       if (b == 2) break; | 
 |       buffHi = (buffHi << 1) | (buffLo >> 31); | 
 |       buffLo = (buffLo << 1) | (b & 1); | 
 |       if (bitsRead == 47+rbStart[wrBlock])  | 
 |          blockCRC = (buffHi << 16) | (buffLo >> 16); | 
 |  | 
 |       if (outFile != NULL && bitsRead >= rbStart[wrBlock] | 
 |                           && bitsRead <= rbEnd[wrBlock]) { | 
 |          bsPutBit ( bsWr, b ); | 
 |       } | 
 |  | 
 |       bitsRead++; | 
 |  | 
 |       if (bitsRead == rbEnd[wrBlock]+1) { | 
 |          if (outFile != NULL) { | 
 |             bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 ); | 
 |             bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 ); | 
 |             bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 ); | 
 |             bsPutUInt32 ( bsWr, blockCRC ); | 
 |             bsClose ( bsWr ); | 
 |          } | 
 |          if (wrBlock >= rbCtr) break; | 
 |          wrBlock++; | 
 |       } else | 
 |       if (bitsRead == rbStart[wrBlock]) { | 
 |          outFileName[0] = 0; | 
 |          sprintf ( outFileName, "rec%4d", wrBlock+1 ); | 
 |          for (p = outFileName; *p != 0; p++) if (*p == ' ') *p = '0'; | 
 |          strcat ( outFileName, inFileName ); | 
 |          if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" ); | 
 |  | 
 |          fprintf ( stderr, "   writing block %d to `%s' ...\n", | 
 |                            wrBlock+1, outFileName ); | 
 |  | 
 |          outFile = fopen ( outFileName, "wb" ); | 
 |          if (outFile == NULL) { | 
 |             fprintf ( stderr, "%s: can't write `%s'\n", | 
 |                       progName, outFileName ); | 
 |             exit(1); | 
 |          } | 
 |          bsWr = bsOpenWriteStream ( outFile ); | 
 |          bsPutUChar ( bsWr, 'B' ); bsPutUChar ( bsWr, 'Z' ); | 
 |          bsPutUChar ( bsWr, 'h' ); bsPutUChar ( bsWr, '9' ); | 
 |          bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 ); | 
 |          bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 ); | 
 |          bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 ); | 
 |       } | 
 |    } | 
 |  | 
 |    fprintf ( stderr, "%s: finished\n", progName ); | 
 |    return 0; | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /*-----------------------------------------------------------*/ | 
 | /*--- end                                  bzip2recover.c ---*/ | 
 | /*-----------------------------------------------------------*/ |