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