178556Sobrien/*-----------------------------------------------------------*/ 278556Sobrien/*--- Block recoverer program for bzip2 ---*/ 378556Sobrien/*--- bzip2recover.c ---*/ 478556Sobrien/*-----------------------------------------------------------*/ 578556Sobrien 6167974Sdelphij/* ------------------------------------------------------------------ 7167974Sdelphij This file is part of bzip2/libbzip2, a program and library for 8167974Sdelphij lossless, block-sorting data compression. 978556Sobrien 10215041Sobrien bzip2/libbzip2 version 1.0.6 of 6 September 2010 11215041Sobrien Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org> 1278556Sobrien 13167974Sdelphij Please read the WARNING, DISCLAIMER and PATENTS sections in the 14167974Sdelphij README file. 1578556Sobrien 16167974Sdelphij This program is released under the terms of the license contained 17167974Sdelphij in the file LICENSE. 18167974Sdelphij ------------------------------------------------------------------ */ 1978556Sobrien 20167974Sdelphij/* This program is a complete hack and should be rewritten properly. 21167974Sdelphij It isn't very complicated. */ 2278556Sobrien 2378556Sobrien#include <stdio.h> 2478556Sobrien#include <errno.h> 2578556Sobrien#include <stdlib.h> 2678556Sobrien#include <string.h> 2778556Sobrien 2890067Ssobomax 2990067Ssobomax/* This program records bit locations in the file to be recovered. 3090067Ssobomax That means that if 64-bit ints are not supported, we will not 3190067Ssobomax be able to recover .bz2 files over 512MB (2^32 bits) long. 3290067Ssobomax On GNU supported platforms, we take advantage of the 64-bit 3390067Ssobomax int support to circumvent this problem. Ditto MSVC. 3490067Ssobomax 3590067Ssobomax This change occurred in version 1.0.2; all prior versions have 3690067Ssobomax the 512MB limitation. 3790067Ssobomax*/ 3890067Ssobomax#ifdef __GNUC__ 3990067Ssobomax typedef unsigned long long int MaybeUInt64; 40228624Sdim# define MaybeUInt64_FMT "%llu" 4190067Ssobomax#else 4290067Ssobomax#ifdef _MSC_VER 4390067Ssobomax typedef unsigned __int64 MaybeUInt64; 4490067Ssobomax# define MaybeUInt64_FMT "%I64u" 4590067Ssobomax#else 4690067Ssobomax typedef unsigned int MaybeUInt64; 4790067Ssobomax# define MaybeUInt64_FMT "%u" 4890067Ssobomax#endif 4990067Ssobomax#endif 5090067Ssobomax 5178556Sobrientypedef unsigned int UInt32; 5278556Sobrientypedef int Int32; 5378556Sobrientypedef unsigned char UChar; 5478556Sobrientypedef char Char; 5578556Sobrientypedef unsigned char Bool; 5678556Sobrien#define True ((Bool)1) 5778556Sobrien#define False ((Bool)0) 5878556Sobrien 5978556Sobrien 6090067Ssobomax#define BZ_MAX_FILENAME 2000 6178556Sobrien 6290067SsobomaxChar inFileName[BZ_MAX_FILENAME]; 6390067SsobomaxChar outFileName[BZ_MAX_FILENAME]; 6490067SsobomaxChar progName[BZ_MAX_FILENAME]; 6578556Sobrien 6690067SsobomaxMaybeUInt64 bytesOut = 0; 6790067SsobomaxMaybeUInt64 bytesIn = 0; 6878556Sobrien 6990067Ssobomax 7078556Sobrien/*---------------------------------------------------*/ 7190067Ssobomax/*--- Header bytes ---*/ 7290067Ssobomax/*---------------------------------------------------*/ 7390067Ssobomax 7490067Ssobomax#define BZ_HDR_B 0x42 /* 'B' */ 7590067Ssobomax#define BZ_HDR_Z 0x5a /* 'Z' */ 7690067Ssobomax#define BZ_HDR_h 0x68 /* 'h' */ 7790067Ssobomax#define BZ_HDR_0 0x30 /* '0' */ 7890067Ssobomax 7990067Ssobomax 8090067Ssobomax/*---------------------------------------------------*/ 8178556Sobrien/*--- I/O errors ---*/ 8278556Sobrien/*---------------------------------------------------*/ 8378556Sobrien 8478556Sobrien/*---------------------------------------------*/ 85167974Sdelphijstatic void readError ( void ) 8678556Sobrien{ 8778556Sobrien fprintf ( stderr, 8878556Sobrien "%s: I/O error reading `%s', possible reason follows.\n", 8978556Sobrien progName, inFileName ); 9078556Sobrien perror ( progName ); 9178556Sobrien fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", 9278556Sobrien progName ); 9378556Sobrien exit ( 1 ); 9478556Sobrien} 9578556Sobrien 9678556Sobrien 9778556Sobrien/*---------------------------------------------*/ 98167974Sdelphijstatic void writeError ( void ) 9978556Sobrien{ 10078556Sobrien fprintf ( stderr, 10178556Sobrien "%s: I/O error reading `%s', possible reason follows.\n", 10278556Sobrien progName, inFileName ); 10378556Sobrien perror ( progName ); 10478556Sobrien fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", 10578556Sobrien progName ); 10678556Sobrien exit ( 1 ); 10778556Sobrien} 10878556Sobrien 10978556Sobrien 11078556Sobrien/*---------------------------------------------*/ 111167974Sdelphijstatic void mallocFail ( Int32 n ) 11278556Sobrien{ 11378556Sobrien fprintf ( stderr, 11478556Sobrien "%s: malloc failed on request for %d bytes.\n", 11578556Sobrien progName, n ); 11678556Sobrien fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n", 11778556Sobrien progName ); 11878556Sobrien exit ( 1 ); 11978556Sobrien} 12078556Sobrien 12178556Sobrien 12290067Ssobomax/*---------------------------------------------*/ 123167974Sdelphijstatic void tooManyBlocks ( Int32 max_handled_blocks ) 12490067Ssobomax{ 12590067Ssobomax fprintf ( stderr, 12690067Ssobomax "%s: `%s' appears to contain more than %d blocks\n", 12790067Ssobomax progName, inFileName, max_handled_blocks ); 12890067Ssobomax fprintf ( stderr, 12990067Ssobomax "%s: and cannot be handled. To fix, increase\n", 13090067Ssobomax progName ); 13190067Ssobomax fprintf ( stderr, 13290067Ssobomax "%s: BZ_MAX_HANDLED_BLOCKS in bzip2recover.c, and recompile.\n", 13390067Ssobomax progName ); 13490067Ssobomax exit ( 1 ); 13590067Ssobomax} 13690067Ssobomax 13790067Ssobomax 13890067Ssobomax 13978556Sobrien/*---------------------------------------------------*/ 14078556Sobrien/*--- Bit stream I/O ---*/ 14178556Sobrien/*---------------------------------------------------*/ 14278556Sobrien 14378556Sobrientypedef 14478556Sobrien struct { 14578556Sobrien FILE* handle; 14678556Sobrien Int32 buffer; 14778556Sobrien Int32 buffLive; 14878556Sobrien Char mode; 14978556Sobrien } 15078556Sobrien BitStream; 15178556Sobrien 15278556Sobrien 15378556Sobrien/*---------------------------------------------*/ 154167974Sdelphijstatic BitStream* bsOpenReadStream ( FILE* stream ) 15578556Sobrien{ 15678556Sobrien BitStream *bs = malloc ( sizeof(BitStream) ); 15778556Sobrien if (bs == NULL) mallocFail ( sizeof(BitStream) ); 15878556Sobrien bs->handle = stream; 15978556Sobrien bs->buffer = 0; 16078556Sobrien bs->buffLive = 0; 16178556Sobrien bs->mode = 'r'; 16278556Sobrien return bs; 16378556Sobrien} 16478556Sobrien 16578556Sobrien 16678556Sobrien/*---------------------------------------------*/ 167167974Sdelphijstatic BitStream* bsOpenWriteStream ( FILE* stream ) 16878556Sobrien{ 16978556Sobrien BitStream *bs = malloc ( sizeof(BitStream) ); 17078556Sobrien if (bs == NULL) mallocFail ( sizeof(BitStream) ); 17178556Sobrien bs->handle = stream; 17278556Sobrien bs->buffer = 0; 17378556Sobrien bs->buffLive = 0; 17478556Sobrien bs->mode = 'w'; 17578556Sobrien return bs; 17678556Sobrien} 17778556Sobrien 17878556Sobrien 17978556Sobrien/*---------------------------------------------*/ 180167974Sdelphijstatic void bsPutBit ( BitStream* bs, Int32 bit ) 18178556Sobrien{ 18278556Sobrien if (bs->buffLive == 8) { 18378556Sobrien Int32 retVal = putc ( (UChar) bs->buffer, bs->handle ); 18478556Sobrien if (retVal == EOF) writeError(); 18578556Sobrien bytesOut++; 18678556Sobrien bs->buffLive = 1; 18778556Sobrien bs->buffer = bit & 0x1; 18878556Sobrien } else { 18978556Sobrien bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) ); 19078556Sobrien bs->buffLive++; 19178556Sobrien }; 19278556Sobrien} 19378556Sobrien 19478556Sobrien 19578556Sobrien/*---------------------------------------------*/ 19678556Sobrien/*-- 19778556Sobrien Returns 0 or 1, or 2 to indicate EOF. 19878556Sobrien--*/ 199167974Sdelphijstatic Int32 bsGetBit ( BitStream* bs ) 20078556Sobrien{ 20178556Sobrien if (bs->buffLive > 0) { 20278556Sobrien bs->buffLive --; 20378556Sobrien return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 ); 20478556Sobrien } else { 20578556Sobrien Int32 retVal = getc ( bs->handle ); 20678556Sobrien if ( retVal == EOF ) { 20778556Sobrien if (errno != 0) readError(); 20878556Sobrien return 2; 20978556Sobrien } 21078556Sobrien bs->buffLive = 7; 21178556Sobrien bs->buffer = retVal; 21278556Sobrien return ( ((bs->buffer) >> 7) & 0x1 ); 21378556Sobrien } 21478556Sobrien} 21578556Sobrien 21678556Sobrien 21778556Sobrien/*---------------------------------------------*/ 218167974Sdelphijstatic void bsClose ( BitStream* bs ) 21978556Sobrien{ 22078556Sobrien Int32 retVal; 22178556Sobrien 22278556Sobrien if ( bs->mode == 'w' ) { 22378556Sobrien while ( bs->buffLive < 8 ) { 22478556Sobrien bs->buffLive++; 22578556Sobrien bs->buffer <<= 1; 22678556Sobrien }; 22778556Sobrien retVal = putc ( (UChar) (bs->buffer), bs->handle ); 22878556Sobrien if (retVal == EOF) writeError(); 22978556Sobrien bytesOut++; 23078556Sobrien retVal = fflush ( bs->handle ); 23178556Sobrien if (retVal == EOF) writeError(); 23278556Sobrien } 23378556Sobrien retVal = fclose ( bs->handle ); 23478556Sobrien if (retVal == EOF) { 23578556Sobrien if (bs->mode == 'w') writeError(); else readError(); 23678556Sobrien } 23778556Sobrien free ( bs ); 23878556Sobrien} 23978556Sobrien 24078556Sobrien 24178556Sobrien/*---------------------------------------------*/ 242167974Sdelphijstatic void bsPutUChar ( BitStream* bs, UChar c ) 24378556Sobrien{ 24478556Sobrien Int32 i; 24578556Sobrien for (i = 7; i >= 0; i--) 24678556Sobrien bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 ); 24778556Sobrien} 24878556Sobrien 24978556Sobrien 25078556Sobrien/*---------------------------------------------*/ 251167974Sdelphijstatic void bsPutUInt32 ( BitStream* bs, UInt32 c ) 25278556Sobrien{ 25378556Sobrien Int32 i; 25478556Sobrien 25578556Sobrien for (i = 31; i >= 0; i--) 25678556Sobrien bsPutBit ( bs, (c >> i) & 0x1 ); 25778556Sobrien} 25878556Sobrien 25978556Sobrien 26078556Sobrien/*---------------------------------------------*/ 261167974Sdelphijstatic Bool endsInBz2 ( Char* name ) 26278556Sobrien{ 26378556Sobrien Int32 n = strlen ( name ); 26478556Sobrien if (n <= 4) return False; 26578556Sobrien return 26678556Sobrien (name[n-4] == '.' && 26778556Sobrien name[n-3] == 'b' && 26878556Sobrien name[n-2] == 'z' && 26978556Sobrien name[n-1] == '2'); 27078556Sobrien} 27178556Sobrien 27278556Sobrien 27378556Sobrien/*---------------------------------------------------*/ 27478556Sobrien/*--- ---*/ 27578556Sobrien/*---------------------------------------------------*/ 27678556Sobrien 27790067Ssobomax/* This logic isn't really right when it comes to Cygwin. */ 27890067Ssobomax#ifdef _WIN32 27990067Ssobomax# define BZ_SPLIT_SYM '\\' /* path splitter on Windows platform */ 28090067Ssobomax#else 28190067Ssobomax# define BZ_SPLIT_SYM '/' /* path splitter on Unix platform */ 28290067Ssobomax#endif 28390067Ssobomax 28478556Sobrien#define BLOCK_HEADER_HI 0x00003141UL 28578556Sobrien#define BLOCK_HEADER_LO 0x59265359UL 28678556Sobrien 28778556Sobrien#define BLOCK_ENDMARK_HI 0x00001772UL 28878556Sobrien#define BLOCK_ENDMARK_LO 0x45385090UL 28978556Sobrien 29090067Ssobomax/* Increase if necessary. However, a .bz2 file with > 50000 blocks 29190067Ssobomax would have an uncompressed size of at least 40GB, so the chances 29290067Ssobomax are low you'll need to up this. 29390067Ssobomax*/ 29490067Ssobomax#define BZ_MAX_HANDLED_BLOCKS 50000 29578556Sobrien 29690067SsobomaxMaybeUInt64 bStart [BZ_MAX_HANDLED_BLOCKS]; 29790067SsobomaxMaybeUInt64 bEnd [BZ_MAX_HANDLED_BLOCKS]; 29890067SsobomaxMaybeUInt64 rbStart[BZ_MAX_HANDLED_BLOCKS]; 29990067SsobomaxMaybeUInt64 rbEnd [BZ_MAX_HANDLED_BLOCKS]; 30078556Sobrien 30178556SobrienInt32 main ( Int32 argc, Char** argv ) 30278556Sobrien{ 30378556Sobrien FILE* inFile; 30478556Sobrien FILE* outFile; 30578556Sobrien BitStream* bsIn, *bsWr; 30690067Ssobomax Int32 b, wrBlock, currBlock, rbCtr; 30790067Ssobomax MaybeUInt64 bitsRead; 30878556Sobrien 30978556Sobrien UInt32 buffHi, buffLo, blockCRC; 31078556Sobrien Char* p; 31178556Sobrien 31278556Sobrien strcpy ( progName, argv[0] ); 31378556Sobrien inFileName[0] = outFileName[0] = 0; 31478556Sobrien 31590067Ssobomax fprintf ( stderr, 316215041Sobrien "bzip2recover 1.0.6: extracts blocks from damaged .bz2 files.\n" ); 31778556Sobrien 31878556Sobrien if (argc != 2) { 31978556Sobrien fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n", 32078556Sobrien progName, progName ); 32190067Ssobomax switch (sizeof(MaybeUInt64)) { 32290067Ssobomax case 8: 32390067Ssobomax fprintf(stderr, 32490067Ssobomax "\trestrictions on size of recovered file: None\n"); 32590067Ssobomax break; 32690067Ssobomax case 4: 32790067Ssobomax fprintf(stderr, 32890067Ssobomax "\trestrictions on size of recovered file: 512 MB\n"); 32990067Ssobomax fprintf(stderr, 33090067Ssobomax "\tto circumvent, recompile with MaybeUInt64 as an\n" 33190067Ssobomax "\tunsigned 64-bit int.\n"); 33290067Ssobomax break; 33390067Ssobomax default: 33490067Ssobomax fprintf(stderr, 33590067Ssobomax "\tsizeof(MaybeUInt64) is not 4 or 8 -- " 33690067Ssobomax "configuration error.\n"); 33790067Ssobomax break; 33890067Ssobomax } 33978556Sobrien exit(1); 34078556Sobrien } 34178556Sobrien 34290067Ssobomax if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) { 34390067Ssobomax fprintf ( stderr, 34490067Ssobomax "%s: supplied filename is suspiciously (>= %d chars) long. Bye!\n", 345146293Sobrien progName, (int)strlen(argv[1]) ); 34690067Ssobomax exit(1); 34790067Ssobomax } 34890067Ssobomax 34978556Sobrien strcpy ( inFileName, argv[1] ); 35078556Sobrien 35178556Sobrien inFile = fopen ( inFileName, "rb" ); 35278556Sobrien if (inFile == NULL) { 35378556Sobrien fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName ); 35478556Sobrien exit(1); 35578556Sobrien } 35678556Sobrien 35778556Sobrien bsIn = bsOpenReadStream ( inFile ); 35878556Sobrien fprintf ( stderr, "%s: searching for block boundaries ...\n", progName ); 35978556Sobrien 36078556Sobrien bitsRead = 0; 36178556Sobrien buffHi = buffLo = 0; 36278556Sobrien currBlock = 0; 36378556Sobrien bStart[currBlock] = 0; 36478556Sobrien 36578556Sobrien rbCtr = 0; 36678556Sobrien 36778556Sobrien while (True) { 36878556Sobrien b = bsGetBit ( bsIn ); 36978556Sobrien bitsRead++; 37078556Sobrien if (b == 2) { 37178556Sobrien if (bitsRead >= bStart[currBlock] && 37278556Sobrien (bitsRead - bStart[currBlock]) >= 40) { 37378556Sobrien bEnd[currBlock] = bitsRead-1; 37478556Sobrien if (currBlock > 0) 37590067Ssobomax fprintf ( stderr, " block %d runs from " MaybeUInt64_FMT 37690067Ssobomax " to " MaybeUInt64_FMT " (incomplete)\n", 37778556Sobrien currBlock, bStart[currBlock], bEnd[currBlock] ); 37878556Sobrien } else 37978556Sobrien currBlock--; 38078556Sobrien break; 38178556Sobrien } 38278556Sobrien buffHi = (buffHi << 1) | (buffLo >> 31); 38378556Sobrien buffLo = (buffLo << 1) | (b & 1); 38478556Sobrien if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI 38578556Sobrien && buffLo == BLOCK_HEADER_LO) 38678556Sobrien || 38778556Sobrien ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI 38878556Sobrien && buffLo == BLOCK_ENDMARK_LO) 38978556Sobrien ) { 39090067Ssobomax if (bitsRead > 49) { 39190067Ssobomax bEnd[currBlock] = bitsRead-49; 39290067Ssobomax } else { 39378556Sobrien bEnd[currBlock] = 0; 39490067Ssobomax } 39578556Sobrien if (currBlock > 0 && 39678556Sobrien (bEnd[currBlock] - bStart[currBlock]) >= 130) { 39790067Ssobomax fprintf ( stderr, " block %d runs from " MaybeUInt64_FMT 39890067Ssobomax " to " MaybeUInt64_FMT "\n", 39978556Sobrien rbCtr+1, bStart[currBlock], bEnd[currBlock] ); 40078556Sobrien rbStart[rbCtr] = bStart[currBlock]; 40178556Sobrien rbEnd[rbCtr] = bEnd[currBlock]; 40278556Sobrien rbCtr++; 40378556Sobrien } 40490067Ssobomax if (currBlock >= BZ_MAX_HANDLED_BLOCKS) 40590067Ssobomax tooManyBlocks(BZ_MAX_HANDLED_BLOCKS); 40678556Sobrien currBlock++; 40778556Sobrien 40878556Sobrien bStart[currBlock] = bitsRead; 40978556Sobrien } 41078556Sobrien } 41178556Sobrien 41278556Sobrien bsClose ( bsIn ); 41378556Sobrien 41478556Sobrien /*-- identified blocks run from 1 to rbCtr inclusive. --*/ 41578556Sobrien 41678556Sobrien if (rbCtr < 1) { 41778556Sobrien fprintf ( stderr, 41878556Sobrien "%s: sorry, I couldn't find any block boundaries.\n", 41978556Sobrien progName ); 42078556Sobrien exit(1); 42178556Sobrien }; 42278556Sobrien 42378556Sobrien fprintf ( stderr, "%s: splitting into blocks\n", progName ); 42478556Sobrien 42578556Sobrien inFile = fopen ( inFileName, "rb" ); 42678556Sobrien if (inFile == NULL) { 42778556Sobrien fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName ); 42878556Sobrien exit(1); 42978556Sobrien } 43078556Sobrien bsIn = bsOpenReadStream ( inFile ); 43178556Sobrien 43278556Sobrien /*-- placate gcc's dataflow analyser --*/ 43378556Sobrien blockCRC = 0; bsWr = 0; 43478556Sobrien 43578556Sobrien bitsRead = 0; 43678556Sobrien outFile = NULL; 43778556Sobrien wrBlock = 0; 43878556Sobrien while (True) { 43978556Sobrien b = bsGetBit(bsIn); 44078556Sobrien if (b == 2) break; 44178556Sobrien buffHi = (buffHi << 1) | (buffLo >> 31); 44278556Sobrien buffLo = (buffLo << 1) | (b & 1); 44378556Sobrien if (bitsRead == 47+rbStart[wrBlock]) 44478556Sobrien blockCRC = (buffHi << 16) | (buffLo >> 16); 44578556Sobrien 44678556Sobrien if (outFile != NULL && bitsRead >= rbStart[wrBlock] 44778556Sobrien && bitsRead <= rbEnd[wrBlock]) { 44878556Sobrien bsPutBit ( bsWr, b ); 44978556Sobrien } 45078556Sobrien 45178556Sobrien bitsRead++; 45278556Sobrien 45378556Sobrien if (bitsRead == rbEnd[wrBlock]+1) { 45478556Sobrien if (outFile != NULL) { 45578556Sobrien bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 ); 45678556Sobrien bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 ); 45778556Sobrien bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 ); 45878556Sobrien bsPutUInt32 ( bsWr, blockCRC ); 45978556Sobrien bsClose ( bsWr ); 46078556Sobrien } 46178556Sobrien if (wrBlock >= rbCtr) break; 46278556Sobrien wrBlock++; 46378556Sobrien } else 46478556Sobrien if (bitsRead == rbStart[wrBlock]) { 46590067Ssobomax /* Create the output file name, correctly handling leading paths. 46690067Ssobomax (31.10.2001 by Sergey E. Kusikov) */ 46790067Ssobomax Char* split; 46890067Ssobomax Int32 ofs, k; 46990067Ssobomax for (k = 0; k < BZ_MAX_FILENAME; k++) 47090067Ssobomax outFileName[k] = 0; 47190067Ssobomax strcpy (outFileName, inFileName); 47290067Ssobomax split = strrchr (outFileName, BZ_SPLIT_SYM); 47390067Ssobomax if (split == NULL) { 47490067Ssobomax split = outFileName; 47590067Ssobomax } else { 47690067Ssobomax ++split; 47790067Ssobomax } 47890067Ssobomax /* Now split points to the start of the basename. */ 47990067Ssobomax ofs = split - outFileName; 48090067Ssobomax sprintf (split, "rec%5d", wrBlock+1); 48190067Ssobomax for (p = split; *p != 0; p++) if (*p == ' ') *p = '0'; 48290067Ssobomax strcat (outFileName, inFileName + ofs); 48390067Ssobomax 48478556Sobrien if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" ); 48578556Sobrien 48678556Sobrien fprintf ( stderr, " writing block %d to `%s' ...\n", 48778556Sobrien wrBlock+1, outFileName ); 48878556Sobrien 48978556Sobrien outFile = fopen ( outFileName, "wb" ); 49078556Sobrien if (outFile == NULL) { 49178556Sobrien fprintf ( stderr, "%s: can't write `%s'\n", 49278556Sobrien progName, outFileName ); 49378556Sobrien exit(1); 49478556Sobrien } 49578556Sobrien bsWr = bsOpenWriteStream ( outFile ); 49690067Ssobomax bsPutUChar ( bsWr, BZ_HDR_B ); 49790067Ssobomax bsPutUChar ( bsWr, BZ_HDR_Z ); 49890067Ssobomax bsPutUChar ( bsWr, BZ_HDR_h ); 49990067Ssobomax bsPutUChar ( bsWr, BZ_HDR_0 + 9 ); 50078556Sobrien bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 ); 50178556Sobrien bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 ); 50278556Sobrien bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 ); 50378556Sobrien } 50478556Sobrien } 50578556Sobrien 50678556Sobrien fprintf ( stderr, "%s: finished\n", progName ); 50778556Sobrien return 0; 50878556Sobrien} 50978556Sobrien 51078556Sobrien 51178556Sobrien 51278556Sobrien/*-----------------------------------------------------------*/ 51378556Sobrien/*--- end bzip2recover.c ---*/ 51478556Sobrien/*-----------------------------------------------------------*/ 515