aboutsummaryrefslogtreecommitdiff
path: root/bzip2recover.c
diff options
context:
space:
mode:
Diffstat (limited to 'bzip2recover.c')
-rw-r--r--bzip2recover.c399
1 files changed, 399 insertions, 0 deletions
diff --git a/bzip2recover.c b/bzip2recover.c
new file mode 100644
index 0000000..efdfb3c
--- /dev/null
+++ b/bzip2recover.c
@@ -0,0 +1,399 @@
1
2/*-----------------------------------------------------------*/
3/*--- Block recoverer program for bzip2 ---*/
4/*--- bzip2recover.c ---*/
5/*-----------------------------------------------------------*/
6
7/*--
8 This program is bzip2recover, a program to attempt data
9 salvage from damaged files created by the accompanying
10 bzip2 program.
11
12 Copyright (C) 1996, 1997 by Julian Seward.
13 Guildford, Surrey, UK
14 email: jseward@acm.org
15
16 This program is free software; you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation; either version 2 of the License, or
19 (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29
30 The GNU General Public License is contained in the file LICENSE.
31--*/
32
33
34#include <stdio.h>
35#include <errno.h>
36#include <malloc.h>
37#include <stdlib.h>
38#include <strings.h> /*-- or try string.h --*/
39
40#define UInt32 unsigned int
41#define Int32 int
42#define UChar unsigned char
43#define Char char
44#define Bool unsigned char
45#define True 1
46#define False 0
47
48
49Char inFileName[2000];
50Char outFileName[2000];
51Char progName[2000];
52
53UInt32 bytesOut = 0;
54UInt32 bytesIn = 0;
55
56
57/*---------------------------------------------------*/
58/*--- I/O errors ---*/
59/*---------------------------------------------------*/
60
61/*---------------------------------------------*/
62void readError ( void )
63{
64 fprintf ( stderr,
65 "%s: I/O error reading `%s', possible reason follows.\n",
66 progName, inFileName );
67 perror ( progName );
68 fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
69 progName );
70 exit ( 1 );
71}
72
73
74/*---------------------------------------------*/
75void writeError ( void )
76{
77 fprintf ( stderr,
78 "%s: I/O error reading `%s', possible reason follows.\n",
79 progName, inFileName );
80 perror ( progName );
81 fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
82 progName );
83 exit ( 1 );
84}
85
86
87/*---------------------------------------------*/
88void mallocFail ( Int32 n )
89{
90 fprintf ( stderr,
91 "%s: malloc failed on request for %d bytes.\n",
92 progName, n );
93 fprintf ( stderr, "%s: warning: output file(s) may be incomplete.\n",
94 progName );
95 exit ( 1 );
96}
97
98
99/*---------------------------------------------------*/
100/*--- Bit stream I/O ---*/
101/*---------------------------------------------------*/
102
103typedef
104 struct {
105 FILE* handle;
106 Int32 buffer;
107 Int32 buffLive;
108 Char mode;
109 }
110 BitStream;
111
112
113/*---------------------------------------------*/
114BitStream* bsOpenReadStream ( FILE* stream )
115{
116 BitStream *bs = malloc ( sizeof(BitStream) );
117 if (bs == NULL) mallocFail ( sizeof(BitStream) );
118 bs->handle = stream;
119 bs->buffer = 0;
120 bs->buffLive = 0;
121 bs->mode = 'r';
122 return bs;
123}
124
125
126/*---------------------------------------------*/
127BitStream* bsOpenWriteStream ( FILE* stream )
128{
129 BitStream *bs = malloc ( sizeof(BitStream) );
130 if (bs == NULL) mallocFail ( sizeof(BitStream) );
131 bs->handle = stream;
132 bs->buffer = 0;
133 bs->buffLive = 0;
134 bs->mode = 'w';
135 return bs;
136}
137
138
139/*---------------------------------------------*/
140void bsPutBit ( BitStream* bs, Int32 bit )
141{
142 if (bs->buffLive == 8) {
143 Int32 retVal = putc ( (UChar) bs->buffer, bs->handle );
144 if (retVal == EOF) writeError();
145 bytesOut++;
146 bs->buffLive = 1;
147 bs->buffer = bit & 0x1;
148 } else {
149 bs->buffer = ( (bs->buffer << 1) | (bit & 0x1) );
150 bs->buffLive++;
151 };
152}
153
154
155/*---------------------------------------------*/
156/*--
157 Returns 0 or 1, or 2 to indicate EOF.
158--*/
159Int32 bsGetBit ( BitStream* bs )
160{
161 if (bs->buffLive > 0) {
162 bs->buffLive --;
163 return ( ((bs->buffer) >> (bs->buffLive)) & 0x1 );
164 } else {
165 Int32 retVal = getc ( bs->handle );
166 if ( retVal == EOF ) {
167 if (errno != 0) readError();
168 return 2;
169 }
170 bs->buffLive = 7;
171 bs->buffer = retVal;
172 return ( ((bs->buffer) >> 7) & 0x1 );
173 }
174}
175
176
177/*---------------------------------------------*/
178void bsClose ( BitStream* bs )
179{
180 Int32 retVal;
181
182 if ( bs->mode == 'w' ) {
183 while ( bs->buffLive < 8 ) {
184 bs->buffLive++;
185 bs->buffer <<= 1;
186 };
187 retVal = putc ( (UChar) (bs->buffer), bs->handle );
188 if (retVal == EOF) writeError();
189 bytesOut++;
190 retVal = fflush ( bs->handle );
191 if (retVal == EOF) writeError();
192 }
193 retVal = fclose ( bs->handle );
194 if (retVal == EOF)
195 if (bs->mode == 'w') writeError(); else readError();
196 free ( bs );
197}
198
199
200/*---------------------------------------------*/
201void bsPutUChar ( BitStream* bs, UChar c )
202{
203 Int32 i;
204 for (i = 7; i >= 0; i--)
205 bsPutBit ( bs, (((UInt32) c) >> i) & 0x1 );
206}
207
208
209/*---------------------------------------------*/
210void bsPutUInt32 ( BitStream* bs, UInt32 c )
211{
212 Int32 i;
213
214 for (i = 31; i >= 0; i--)
215 bsPutBit ( bs, (c >> i) & 0x1 );
216}
217
218
219/*---------------------------------------------*/
220Bool endsInBz2 ( Char* name )
221{
222 Int32 n = strlen ( name );
223 if (n <= 4) return False;
224 return
225 (name[n-4] == '.' &&
226 name[n-3] == 'b' &&
227 name[n-2] == 'z' &&
228 name[n-1] == '2');
229}
230
231
232/*---------------------------------------------------*/
233/*--- ---*/
234/*---------------------------------------------------*/
235
236#define BLOCK_HEADER_HI 0x00003141UL
237#define BLOCK_HEADER_LO 0x59265359UL
238
239#define BLOCK_ENDMARK_HI 0x00001772UL
240#define BLOCK_ENDMARK_LO 0x45385090UL
241
242Int32 main ( Int32 argc, Char** argv )
243{
244 FILE* inFile;
245 FILE* outFile;
246 BitStream* bsIn, *bsWr;
247 Int32 currBlock, b, wrBlock;
248 UInt32 bitsRead;
249 UInt32 bStart[20000];
250 UInt32 bEnd[20000];
251 UInt32 buffHi, buffLo, blockCRC;
252 Char* p;
253
254 strcpy ( progName, argv[0] );
255 inFileName[0] = outFileName[0] = 0;
256
257 fprintf ( stderr, "bzip2recover: extracts blocks from damaged .bz2 files.\n" );
258
259 if (argc != 2) {
260 fprintf ( stderr, "%s: usage is `%s damaged_file_name'.\n",
261 progName, progName );
262 exit(1);
263 }
264
265 strcpy ( inFileName, argv[1] );
266
267 inFile = fopen ( inFileName, "rb" );
268 if (inFile == NULL) {
269 fprintf ( stderr, "%s: can't read `%s'\n", progName, inFileName );
270 exit(1);
271 }
272
273 bsIn = bsOpenReadStream ( inFile );
274 fprintf ( stderr, "%s: searching for block boundaries ...\n", progName );
275
276 bitsRead = 0;
277 buffHi = buffLo = 0;
278 currBlock = 0;
279 bStart[currBlock] = 0;
280
281 while (True) {
282 b = bsGetBit ( bsIn );
283 bitsRead++;
284 if (b == 2) {
285 if (bitsRead >= bStart[currBlock] &&
286 (bitsRead - bStart[currBlock]) >= 40) {
287 bEnd[currBlock] = bitsRead-1;
288 if (currBlock > 0)
289 fprintf ( stderr, " block %d runs from %d to %d (incomplete)\n",
290 currBlock, bStart[currBlock], bEnd[currBlock] );
291 } else
292 currBlock--;
293 break;
294 }
295 buffHi = (buffHi << 1) | (buffLo >> 31);
296 buffLo = (buffLo << 1) | (b & 1);
297 if ( ( (buffHi & 0x0000ffff) == BLOCK_HEADER_HI
298 && buffLo == BLOCK_HEADER_LO)
299 ||
300 ( (buffHi & 0x0000ffff) == BLOCK_ENDMARK_HI
301 && buffLo == BLOCK_ENDMARK_LO)
302 ) {
303 if (bitsRead > 49)
304 bEnd[currBlock] = bitsRead-49; else
305 bEnd[currBlock] = 0;
306 if (currBlock > 0)
307 fprintf ( stderr, " block %d runs from %d to %d\n",
308 currBlock, bStart[currBlock], bEnd[currBlock] );
309 currBlock++;
310 bStart[currBlock] = bitsRead;
311 }
312 }
313
314 bsClose ( bsIn );
315
316 /*-- identified blocks run from 1 to currBlock inclusive. --*/
317
318 if (currBlock < 1) {
319 fprintf ( stderr,
320 "%s: sorry, I couldn't find any block boundaries.\n",
321 progName );
322 exit(1);
323 };
324
325 fprintf ( stderr, "%s: splitting into blocks\n", progName );
326
327 inFile = fopen ( inFileName, "rb" );
328 if (inFile == NULL) {
329 fprintf ( stderr, "%s: can't open `%s'\n", progName, inFileName );
330 exit(1);
331 }
332 bsIn = bsOpenReadStream ( inFile );
333
334 /*-- placate gcc's dataflow analyser --*/
335 blockCRC = 0; bsWr = 0;
336
337 bitsRead = 0;
338 outFile = NULL;
339 wrBlock = 1;
340 while (True) {
341 b = bsGetBit(bsIn);
342 if (b == 2) break;
343 buffHi = (buffHi << 1) | (buffLo >> 31);
344 buffLo = (buffLo << 1) | (b & 1);
345 if (bitsRead == 47+bStart[wrBlock])
346 blockCRC = (buffHi << 16) | (buffLo >> 16);
347
348 if (outFile != NULL && bitsRead >= bStart[wrBlock]
349 && bitsRead <= bEnd[wrBlock]) {
350 bsPutBit ( bsWr, b );
351 }
352
353 bitsRead++;
354
355 if (bitsRead == bEnd[wrBlock]+1) {
356 if (outFile != NULL) {
357 bsPutUChar ( bsWr, 0x17 ); bsPutUChar ( bsWr, 0x72 );
358 bsPutUChar ( bsWr, 0x45 ); bsPutUChar ( bsWr, 0x38 );
359 bsPutUChar ( bsWr, 0x50 ); bsPutUChar ( bsWr, 0x90 );
360 bsPutUInt32 ( bsWr, blockCRC );
361 bsClose ( bsWr );
362 }
363 if (wrBlock >= currBlock) break;
364 wrBlock++;
365 } else
366 if (bitsRead == bStart[wrBlock]) {
367 outFileName[0] = 0;
368 sprintf ( outFileName, "rec%4d", wrBlock );
369 for (p = outFileName; *p != 0; p++) if (*p == ' ') *p = '0';
370 strcat ( outFileName, inFileName );
371 if ( !endsInBz2(outFileName)) strcat ( outFileName, ".bz2" );
372
373 fprintf ( stderr, " writing block %d to `%s' ...\n",
374 wrBlock, outFileName );
375
376 outFile = fopen ( outFileName, "wb" );
377 if (outFile == NULL) {
378 fprintf ( stderr, "%s: can't write `%s'\n",
379 progName, outFileName );
380 exit(1);
381 }
382 bsWr = bsOpenWriteStream ( outFile );
383 bsPutUChar ( bsWr, 'B' ); bsPutUChar ( bsWr, 'Z' );
384 bsPutUChar ( bsWr, 'h' ); bsPutUChar ( bsWr, '9' );
385 bsPutUChar ( bsWr, 0x31 ); bsPutUChar ( bsWr, 0x41 );
386 bsPutUChar ( bsWr, 0x59 ); bsPutUChar ( bsWr, 0x26 );
387 bsPutUChar ( bsWr, 0x53 ); bsPutUChar ( bsWr, 0x59 );
388 }
389 }
390
391 fprintf ( stderr, "%s: finished\n", progName );
392 return 0;
393}
394
395
396
397/*-----------------------------------------------------------*/
398/*--- end bzip2recover.c ---*/
399/*-----------------------------------------------------------*/