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