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 10351007Sdelphij bzip2/libbzip2 version 1.0.8 of 13 July 2019 11351007Sdelphij Copyright (C) 1996-2019 Julian Seward <jseward@acm.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 312349718Sdelphij strncpy ( progName, argv[0], BZ_MAX_FILENAME-1); 313349718Sdelphij progName[BZ_MAX_FILENAME-1]='\0'; 31478556Sobrien inFileName[0] = outFileName[0] = 0; 31578556Sobrien 31690067Ssobomax fprintf ( stderr, 317351007Sdelphij "bzip2recover 1.0.8: extracts blocks from damaged .bz2 files.\n" ); 31878556Sobrien 31978556Sobrien if (argc != 2) { 32078556Sobrien fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n", 32178556Sobrien progName, progName ); 32290067Ssobomax switch (sizeof(MaybeUInt64)) { 32390067Ssobomax case 8: 32490067Ssobomax fprintf(stderr, 32590067Ssobomax "\trestrictions on size of recovered file: None\n"); 32690067Ssobomax break; 32790067Ssobomax case 4: 32890067Ssobomax fprintf(stderr, 32990067Ssobomax "\trestrictions on size of recovered file: 512 MB\n"); 33090067Ssobomax fprintf(stderr, 33190067Ssobomax "\tto circumvent, recompile with MaybeUInt64 as an\n" 33290067Ssobomax "\tunsigned 64-bit int.\n"); 33390067Ssobomax break; 33490067Ssobomax default: 33590067Ssobomax fprintf(stderr, 33690067Ssobomax "\tsizeof(MaybeUInt64) is not 4 or 8 -- " 33790067Ssobomax "configuration error.\n"); 33890067Ssobomax break; 33990067Ssobomax } 34078556Sobrien exit(1); 34178556Sobrien } 34278556Sobrien 34390067Ssobomax if (strlen(argv[1]) >= BZ_MAX_FILENAME-20) { 34490067Ssobomax fprintf ( stderr, 34590067Ssobomax "%s: supplied filename is suspiciously (>= %d chars) long. Bye!\n", 346146293Sobrien progName, (int)strlen(argv[1]) ); 34790067Ssobomax exit(1); 34890067Ssobomax } 34990067Ssobomax 35078556Sobrien strcpy ( inFileName, argv[1] ); 35178556Sobrien 35278556Sobrien inFile = fopen ( inFileName, "rb" ); 35378556Sobrien if (inFile == NULL) { 35478556Sobrien fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName ); 35578556Sobrien exit(1); 35678556Sobrien } 35778556Sobrien 35878556Sobrien bsIn = bsOpenReadStream ( inFile ); 35978556Sobrien fprintf ( stderr, "%s: searching for block boundaries ...\n", progName ); 36078556Sobrien 36178556Sobrien bitsRead = 0; 36278556Sobrien buffHi = buffLo = 0; 36378556Sobrien currBlock = 0; 36478556Sobrien bStart[currBlock] = 0; 36578556Sobrien 36678556Sobrien rbCtr = 0; 36778556Sobrien 36878556Sobrien while (True) { 36978556Sobrien b = bsGetBit ( bsIn ); 37078556Sobrien bitsRead++; 37178556Sobrien if (b == 2) { 37278556Sobrien if (bitsRead >= bStart[currBlock] && 37378556Sobrien (bitsRead - bStart[currBlock]) >= 40) { 37478556Sobrien bEnd[currBlock] = bitsRead-1; 37578556Sobrien if (currBlock > 0) 37690067Ssobomax fprintf ( stderr, " block %d runs from " MaybeUInt64_FMT 37790067Ssobomax " to " MaybeUInt64_FMT " (incomplete)\n", 37878556Sobrien currBlock, bStart[currBlock], bEnd[currBlock] ); 37978556Sobrien } else 38078556Sobrien currBlock--; 38178556Sobrien break; 38278556Sobrien } 38378556Sobrien buffHi = (buffHi << 1) | (buffLo >> 31); 38478556Sobrien buffLo = (buffLo << 1) | (b & 1); 38578556Sobrien if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI 38678556Sobrien && buffLo == BLOCK_HEADER_LO) 38778556Sobrien || 38878556Sobrien ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI 38978556Sobrien && buffLo == BLOCK_ENDMARK_LO) 39078556Sobrien ) { 39190067Ssobomax if (bitsRead > 49) { 39290067Ssobomax bEnd[currBlock] = bitsRead-49; 39390067Ssobomax } else { 39478556Sobrien bEnd[currBlock] = 0; 39590067Ssobomax } 39678556Sobrien if (currBlock > 0 && 39778556Sobrien (bEnd[currBlock] - bStart[currBlock]) >= 130) { 39890067Ssobomax fprintf ( stderr, " block %d runs from " MaybeUInt64_FMT 39990067Ssobomax " to " MaybeUInt64_FMT "\n", 40078556Sobrien rbCtr+1, bStart[currBlock], bEnd[currBlock] ); 40178556Sobrien rbStart[rbCtr] = bStart[currBlock]; 40278556Sobrien rbEnd[rbCtr] = bEnd[currBlock]; 40378556Sobrien rbCtr++; 40478556Sobrien } 40590067Ssobomax if (currBlock >= BZ_MAX_HANDLED_BLOCKS) 40690067Ssobomax tooManyBlocks(BZ_MAX_HANDLED_BLOCKS); 40778556Sobrien currBlock++; 40878556Sobrien 40978556Sobrien bStart[currBlock] = bitsRead; 41078556Sobrien } 41178556Sobrien } 41278556Sobrien 41378556Sobrien bsClose ( bsIn ); 41478556Sobrien 41578556Sobrien /*-- identified blocks run from 1 to rbCtr inclusive. --*/ 41678556Sobrien 41778556Sobrien if (rbCtr < 1) { 41878556Sobrien fprintf ( stderr, 41978556Sobrien "%s: sorry, I couldn't find any block boundaries.\n", 42078556Sobrien progName ); 42178556Sobrien exit(1); 42278556Sobrien }; 42378556Sobrien 42478556Sobrien fprintf ( stderr, "%s: splitting into blocks\n", progName ); 42578556Sobrien 42678556Sobrien inFile = fopen ( inFileName, "rb" ); 42778556Sobrien if (inFile == NULL) { 42878556Sobrien fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName ); 42978556Sobrien exit(1); 43078556Sobrien } 43178556Sobrien bsIn = bsOpenReadStream ( inFile ); 43278556Sobrien 43378556Sobrien /*-- placate gcc's dataflow analyser --*/ 43478556Sobrien blockCRC = 0; bsWr = 0; 43578556Sobrien 43678556Sobrien bitsRead = 0; 43778556Sobrien outFile = NULL; 43878556Sobrien wrBlock = 0; 43978556Sobrien while (True) { 44078556Sobrien b = bsGetBit(bsIn); 44178556Sobrien if (b == 2) break; 44278556Sobrien buffHi = (buffHi << 1) | (buffLo >> 31); 44378556Sobrien buffLo = (buffLo << 1) | (b & 1); 44478556Sobrien if (bitsRead == 47+rbStart[wrBlock]) 44578556Sobrien blockCRC = (buffHi << 16) | (buffLo >> 16); 44678556Sobrien 44778556Sobrien if (outFile != NULL && bitsRead >= rbStart[wrBlock] 44878556Sobrien && bitsRead <= rbEnd[wrBlock]) { 44978556Sobrien bsPutBit ( bsWr, b ); 45078556Sobrien } 45178556Sobrien 45278556Sobrien bitsRead++; 45378556Sobrien 45478556Sobrien if (bitsRead == rbEnd[wrBlock]+1) { 45578556Sobrien if (outFile != NULL) { 45678556Sobrien bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 ); 45778556Sobrien bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 ); 45878556Sobrien bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 ); 45978556Sobrien bsPutUInt32 ( bsWr, blockCRC ); 46078556Sobrien bsClose ( bsWr ); 461349718Sdelphij outFile = NULL; 46278556Sobrien } 46378556Sobrien if (wrBlock >= rbCtr) break; 46478556Sobrien wrBlock++; 46578556Sobrien } else 46678556Sobrien if (bitsRead == rbStart[wrBlock]) { 46790067Ssobomax /* Create the output file name, correctly handling leading paths. 46890067Ssobomax (31.10.2001 by Sergey E. Kusikov) */ 46990067Ssobomax Char* split; 47090067Ssobomax Int32 ofs, k; 47190067Ssobomax for (k = 0; k < BZ_MAX_FILENAME; k++) 47290067Ssobomax outFileName[k] = 0; 47390067Ssobomax strcpy (outFileName, inFileName); 47490067Ssobomax split = strrchr (outFileName, BZ_SPLIT_SYM); 47590067Ssobomax if (split == NULL) { 47690067Ssobomax split = outFileName; 47790067Ssobomax } else { 47890067Ssobomax ++split; 47990067Ssobomax } 48090067Ssobomax /* Now split points to the start of the basename. */ 48190067Ssobomax ofs = split - outFileName; 48290067Ssobomax sprintf (split, "rec%5d", wrBlock+1); 48390067Ssobomax for (p = split; *p != 0; p++) if (*p == ' ') *p = '0'; 48490067Ssobomax strcat (outFileName, inFileName + ofs); 48590067Ssobomax 48678556Sobrien if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" ); 48778556Sobrien 48878556Sobrien fprintf ( stderr, " writing block %d to `%s' ...\n", 48978556Sobrien wrBlock+1, outFileName ); 49078556Sobrien 49178556Sobrien outFile = fopen ( outFileName, "wb" ); 49278556Sobrien if (outFile == NULL) { 49378556Sobrien fprintf ( stderr, "%s: can't write `%s'\n", 49478556Sobrien progName, outFileName ); 49578556Sobrien exit(1); 49678556Sobrien } 49778556Sobrien bsWr = bsOpenWriteStream ( outFile ); 49890067Ssobomax bsPutUChar ( bsWr, BZ_HDR_B ); 49990067Ssobomax bsPutUChar ( bsWr, BZ_HDR_Z ); 50090067Ssobomax bsPutUChar ( bsWr, BZ_HDR_h ); 50190067Ssobomax bsPutUChar ( bsWr, BZ_HDR_0 + 9 ); 50278556Sobrien bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 ); 50378556Sobrien bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 ); 50478556Sobrien bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 ); 50578556Sobrien } 50678556Sobrien } 50778556Sobrien 50878556Sobrien fprintf ( stderr, "%s: finished\n", progName ); 50978556Sobrien return 0; 51078556Sobrien} 51178556Sobrien 51278556Sobrien 51378556Sobrien 51478556Sobrien/*-----------------------------------------------------------*/ 51578556Sobrien/*--- end bzip2recover.c ---*/ 51678556Sobrien/*-----------------------------------------------------------*/ 517