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