]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libarchive/archive_read_support_compression_bzip2.c
This commit was generated by cvs2svn to compensate for changes in r164219,
[FreeBSD/FreeBSD.git] / lib / libarchive / archive_read_support_compression_bzip2.c
1 /*-
2  * Copyright (c) 2003-2004 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "archive_platform.h"
28
29 __FBSDID("$FreeBSD$");
30
31 #ifdef HAVE_ERRNO_H
32 #include <errno.h>
33 #endif
34 #include <stdio.h>
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 #ifdef HAVE_STRING_H
39 #include <string.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 #ifdef HAVE_BZLIB_H
45 #include <bzlib.h>
46 #endif
47
48 #include "archive.h"
49 #include "archive_private.h"
50
51 #if HAVE_BZLIB_H
52 struct private_data {
53         bz_stream        stream;
54         char            *uncompressed_buffer;
55         size_t           uncompressed_buffer_size;
56         char            *read_next;
57         int64_t          total_out;
58 };
59
60 static int      finish(struct archive *);
61 static ssize_t  read_ahead(struct archive *, const void **, size_t);
62 static ssize_t  read_consume(struct archive *, size_t);
63 static int      drive_decompressor(struct archive *a, struct private_data *);
64 #endif
65
66 /* These two functions are defined even if we lack bzlib.  See below. */
67 static int      bid(const void *, size_t);
68 static int      init(struct archive *, const void *, size_t);
69
70 int
71 archive_read_support_compression_bzip2(struct archive *a)
72 {
73         return (__archive_read_register_compression(a, bid, init));
74 }
75
76 /*
77  * Test whether we can handle this data.
78  *
79  * This logic returns zero if any part of the signature fails.  It
80  * also tries to Do The Right Thing if a very short buffer prevents us
81  * from verifying as much as we would like.
82  */
83 static int
84 bid(const void *buff, size_t len)
85 {
86         const unsigned char *buffer;
87         int bits_checked;
88
89         if (len < 1)
90                 return (0);
91
92         buffer = (const unsigned char *)buff;
93         bits_checked = 0;
94         if (buffer[0] != 'B')   /* Verify first ID byte. */
95                 return (0);
96         bits_checked += 8;
97         if (len < 2)
98                 return (bits_checked);
99
100         if (buffer[1] != 'Z')   /* Verify second ID byte. */
101                 return (0);
102         bits_checked += 8;
103         if (len < 3)
104                 return (bits_checked);
105
106         if (buffer[2] != 'h')   /* Verify third ID byte. */
107                 return (0);
108         bits_checked += 8;
109         if (len < 4)
110                 return (bits_checked);
111
112         if (buffer[3] < '1' || buffer[3] > '9')
113                 return (0);
114         bits_checked += 5;
115
116         /*
117          * Research Question: Can we do any more to verify that this
118          * really is BZip2 format??  For 99.9% of the time, the above
119          * test is sufficient, but it would be nice to do a more
120          * thorough check.  It's especially troubling that the BZip2
121          * signature begins with all ASCII characters; a tar archive
122          * whose first filename begins with 'BZh3' would potentially
123          * fool this logic.  (It may also be possible to gaurd against
124          * such anomalies in archive_read_support_compression_none.)
125          */
126
127         return (bits_checked);
128 }
129
130 #ifndef HAVE_BZLIB_H
131
132 /*
133  * If we don't have bzlib on this system, we can't actually do the
134  * decompression.  We can, however, still detect bzip2-compressed
135  * archives and emit a useful message.
136  */
137 static int
138 init(struct archive *a, const void *buff, size_t n)
139 {
140         (void)a;        /* UNUSED */
141         (void)buff;     /* UNUSED */
142         (void)n;        /* UNUSED */
143
144         archive_set_error(a, -1,
145             "This version of libarchive was compiled without bzip2 support");
146         return (ARCHIVE_FATAL);
147 }
148
149
150 #else
151
152 /*
153  * Setup the callbacks.
154  */
155 static int
156 init(struct archive *a, const void *buff, size_t n)
157 {
158         struct private_data *state;
159         int ret;
160
161         a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
162         a->compression_name = "bzip2";
163
164         state = (struct private_data *)malloc(sizeof(*state));
165         if (state == NULL) {
166                 archive_set_error(a, ENOMEM,
167                     "Can't allocate data for %s decompression",
168                     a->compression_name);
169                 return (ARCHIVE_FATAL);
170         }
171         memset(state, 0, sizeof(*state));
172
173         state->uncompressed_buffer_size = 64 * 1024;
174         state->uncompressed_buffer = (char *)malloc(state->uncompressed_buffer_size);
175         state->stream.next_out = state->uncompressed_buffer;
176         state->read_next = state->uncompressed_buffer;
177         state->stream.avail_out = state->uncompressed_buffer_size;
178
179         if (state->uncompressed_buffer == NULL) {
180                 archive_set_error(a, ENOMEM,
181                     "Can't allocate %s decompression buffers",
182                     a->compression_name);
183                 free(state);
184                 return (ARCHIVE_FATAL);
185         }
186
187         /*
188          * A bug in bzlib.h: stream.next_in should be marked 'const'
189          * but isn't (the library never alters data through the
190          * next_in pointer, only reads it).  The result: this ugly
191          * cast to remove 'const'.
192          */
193         state->stream.next_in = (char *)(uintptr_t)(const void *)buff;
194         state->stream.avail_in = n;
195
196         a->compression_read_ahead = read_ahead;
197         a->compression_read_consume = read_consume;
198         a->compression_skip = NULL; /* not supported */
199         a->compression_finish = finish;
200
201         /* Initialize compression library. */
202         ret = BZ2_bzDecompressInit(&(state->stream),
203             0 /* library verbosity */,
204             0 /* don't use slow low-mem algorithm */);
205
206         /* If init fails, try using low-memory algorithm instead. */
207         if (ret == BZ_MEM_ERROR) {
208                 ret = BZ2_bzDecompressInit(&(state->stream),
209                     0 /* library verbosity */,
210                     1 /* do use slow low-mem algorithm */);
211         }
212
213         if (ret == BZ_OK) {
214                 a->compression_data = state;
215                 return (ARCHIVE_OK);
216         }
217
218         /* Library setup failed: Clean up. */
219         archive_set_error(a, ARCHIVE_ERRNO_MISC,
220             "Internal error initializing %s library", a->compression_name);
221         free(state->uncompressed_buffer);
222         free(state);
223
224         /* Override the error message if we know what really went wrong. */
225         switch (ret) {
226         case BZ_PARAM_ERROR:
227                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
228                     "Internal error initializing compression library: "
229                     "invalid setup parameter");
230                 break;
231         case BZ_MEM_ERROR:
232                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
233                     "Internal error initializing compression library: "
234                     "out of memory");
235                 break;
236         case BZ_CONFIG_ERROR:
237                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
238                     "Internal error initializing compression library: "
239                     "mis-compiled library");
240                 break;
241         }
242
243         return (ARCHIVE_FATAL);
244 }
245
246 /*
247  * Return a block of data from the decompression buffer.  Decompress more
248  * as necessary.
249  */
250 static ssize_t
251 read_ahead(struct archive *a, const void **p, size_t min)
252 {
253         struct private_data *state;
254         int read_avail, was_avail, ret;
255
256         state = (struct private_data *)a->compression_data;
257         was_avail = -1;
258         if (!a->client_reader) {
259                 archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
260                     "No read callback is registered?  "
261                     "This is probably an internal programming error.");
262                 return (ARCHIVE_FATAL);
263         }
264
265         read_avail = state->stream.next_out - state->read_next;
266
267         if (read_avail + state->stream.avail_out < min) {
268                 memmove(state->uncompressed_buffer, state->read_next,
269                     read_avail);
270                 state->read_next = state->uncompressed_buffer;
271                 state->stream.next_out = state->read_next + read_avail;
272                 state->stream.avail_out
273                     = state->uncompressed_buffer_size - read_avail;
274         }
275
276         while (was_avail < read_avail &&        /* Made some progress. */
277             read_avail < (int)min &&            /* Haven't satisfied min. */
278             read_avail < (int)state->uncompressed_buffer_size) { /* !full */
279                 if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
280                         return (ret);
281                 was_avail = read_avail;
282                 read_avail = state->stream.next_out - state->read_next;
283         }
284
285         *p = state->read_next;
286         return (read_avail);
287 }
288
289 /*
290  * Mark a previously-returned block of data as read.
291  */
292 static ssize_t
293 read_consume(struct archive *a, size_t n)
294 {
295         struct private_data *state;
296
297         state = (struct private_data *)a->compression_data;
298         a->file_position += n;
299         state->read_next += n;
300         if (state->read_next > state->stream.next_out)
301                 __archive_errx(1, "Request to consume too many "
302                     "bytes from bzip2 decompressor");
303         return (n);
304 }
305
306 /*
307  * Clean up the decompressor.
308  */
309 static int
310 finish(struct archive *a)
311 {
312         struct private_data *state;
313         int ret;
314
315         state = (struct private_data *)a->compression_data;
316         ret = ARCHIVE_OK;
317         switch (BZ2_bzDecompressEnd(&(state->stream))) {
318         case BZ_OK:
319                 break;
320         default:
321                 archive_set_error(a, ARCHIVE_ERRNO_MISC,
322                     "Failed to clean up %s compressor", a->compression_name);
323                 ret = ARCHIVE_FATAL;
324         }
325
326         free(state->uncompressed_buffer);
327         free(state);
328
329         a->compression_data = NULL;
330         if (a->client_closer != NULL)
331                 (a->client_closer)(a, a->client_data);
332
333         return (ret);
334 }
335
336 /*
337  * Utility function to pull data through decompressor, reading input
338  * blocks as necessary.
339  */
340 static int
341 drive_decompressor(struct archive *a, struct private_data *state)
342 {
343         ssize_t ret;
344         int decompressed, total_decompressed;
345         char *output;
346
347         total_decompressed = 0;
348         for (;;) {
349                 if (state->stream.avail_in == 0) {
350                         ret = (a->client_reader)(a, a->client_data,
351                             (const void **)&state->stream.next_in);
352                         if (ret < 0) {
353                                 /*
354                                  * TODO: Find a better way to handle
355                                  * this read failure.
356                                  */
357                                 goto fatal;
358                         }
359                         if (ret == 0  &&  total_decompressed == 0) {
360                                 archive_set_error(a, EIO,
361                                     "Premature end of %s compressed data",
362                                     a->compression_name);
363                                 return (ARCHIVE_FATAL);
364                         }
365                         a->raw_position += ret;
366                         state->stream.avail_in = ret;
367                 }
368
369                 {
370                         output = state->stream.next_out;
371
372                         /* Decompress some data. */
373                         ret = BZ2_bzDecompress(&(state->stream));
374                         decompressed = state->stream.next_out - output;
375
376                         /* Accumulate the total bytes of output. */
377                         state->total_out += decompressed;
378                         total_decompressed += decompressed;
379
380                         switch (ret) {
381                         case BZ_OK: /* Decompressor made some progress. */
382                                 if (decompressed > 0)
383                                         return (ARCHIVE_OK);
384                                 break;
385                         case BZ_STREAM_END:     /* Found end of stream. */
386                                 return (ARCHIVE_OK);
387                         default:
388                                 /* Any other return value is an error. */
389                                 goto fatal;
390                         }
391                 }
392         }
393         return (ARCHIVE_OK);
394
395         /* Return a fatal error. */
396 fatal:
397         archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
398             a->compression_name);
399         return (ARCHIVE_FATAL);
400 }
401
402 #endif /* HAVE_BZLIB_H */