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