| |
| /*-----------------------------------------------------------*/ |
| /*--- 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-0.1 program. |
| |
| Copyright (C) 1996, 1997 by Julian Seward. |
| Guildford, Surrey, UK |
| email: jseward@acm.org |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| |
| The GNU General Public License is contained in the file LICENSE. |
| --*/ |
| |
| |
| #include <stdio.h> |
| #include <errno.h> |
| #include <malloc.h> |
| #include <stdlib.h> |
| #include <strings.h> /*-- or try string.h --*/ |
| |
| #define UInt32 unsigned int |
| #define Int32 int |
| #define UChar unsigned char |
| #define Char char |
| #define Bool unsigned char |
| #define True 1 |
| #define False 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 |
| |
| Int32 main ( Int32 argc, Char** argv ) |
| { |
| FILE* inFile; |
| FILE* outFile; |
| BitStream* bsIn, *bsWr; |
| Int32 currBlock, b, wrBlock; |
| UInt32 bitsRead; |
| UInt32 bStart[20000]; |
| UInt32 bEnd[20000]; |
| UInt32 buffHi, buffLo, blockCRC; |
| Char* p; |
| |
| strcpy ( progName, argv[0] ); |
| inFileName[0] = outFileName[0] = 0; |
| |
| fprintf ( stderr, "bzip2recover: 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; |
| |
| 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) |
| fprintf ( stderr, " block %d runs from %d to %d\n", |
| currBlock, bStart[currBlock], bEnd[currBlock] ); |
| currBlock++; |
| bStart[currBlock] = bitsRead; |
| } |
| } |
| |
| bsClose ( bsIn ); |
| |
| /*-- identified blocks run from 1 to currBlock inclusive. --*/ |
| |
| if (currBlock < 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 = 1; |
| while (True) { |
| b = bsGetBit(bsIn); |
| if (b == 2) break; |
| buffHi = (buffHi << 1) | (buffLo >> 31); |
| buffLo = (buffLo << 1) | (b & 1); |
| if (bitsRead == 47+bStart[wrBlock]) |
| blockCRC = (buffHi << 16) | (buffLo >> 16); |
| |
| if (outFile != NULL && bitsRead >= bStart[wrBlock] |
| && bitsRead <= bEnd[wrBlock]) { |
| bsPutBit ( bsWr, b ); |
| } |
| |
| bitsRead++; |
| |
| if (bitsRead == bEnd[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 >= currBlock) break; |
| wrBlock++; |
| } else |
| if (bitsRead == bStart[wrBlock]) { |
| outFileName[0] = 0; |
| sprintf ( outFileName, "rec%4d", wrBlock ); |
| 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, 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 ---*/ |
| /*-----------------------------------------------------------*/ |