Merge branch 'vendor/DHCPCD'
[dragonfly.git] / contrib / libarchive / libarchive / archive_read_support_filter_lzop.c
1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
3  * Copyright (c) 2012 Michihiro NAKAJIMA
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
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_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #ifdef HAVE_ERRNO_H
35 #include <errno.h>
36 #endif
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #endif
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46 #ifdef HAVE_LZO_LZOCONF_H
47 #include <lzo/lzoconf.h>
48 #endif
49 #ifdef HAVE_LZO_LZO1X_H
50 #include <lzo/lzo1x.h>
51 #endif
52 #ifdef HAVE_ZLIB_H
53 #include <zlib.h> /* for crc32 and adler32 */
54 #endif
55
56 #include "archive.h"
57 #if !defined(HAVE_ZLIB_H) &&\
58      defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
59 #include "archive_crc32.h"
60 #endif
61 #include "archive_endian.h"
62 #include "archive_private.h"
63 #include "archive_read_private.h"
64
65 #ifndef HAVE_ZLIB_H
66 #define adler32 lzo_adler32
67 #endif
68
69 #define LZOP_HEADER_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
70 #define LZOP_HEADER_MAGIC_LEN 9
71
72 #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
73 struct read_lzop {
74         unsigned char   *out_block;
75         size_t           out_block_size;
76         int64_t          total_out;
77         int              flags;
78         uint32_t         compressed_cksum;
79         uint32_t         uncompressed_cksum;
80         size_t           compressed_size;
81         size_t           uncompressed_size;
82         size_t           unconsumed_bytes;
83         char             in_stream;
84         char             eof; /* True = found end of compressed data. */
85 };
86
87 #define FILTER                  0x0800
88 #define CRC32_HEADER            0x1000
89 #define EXTRA_FIELD             0x0040
90 #define ADLER32_UNCOMPRESSED    0x0001
91 #define ADLER32_COMPRESSED      0x0002
92 #define CRC32_UNCOMPRESSED      0x0100
93 #define CRC32_COMPRESSED        0x0200
94 #define MAX_BLOCK_SIZE          (64 * 1024 * 1024)
95
96 static ssize_t  lzop_filter_read(struct archive_read_filter *, const void **);
97 static int      lzop_filter_close(struct archive_read_filter *);
98 #endif
99
100 static int lzop_bidder_bid(struct archive_read_filter_bidder *,
101     struct archive_read_filter *);
102 static int lzop_bidder_init(struct archive_read_filter *);
103
104 static const struct archive_read_filter_bidder_vtable
105 lzop_bidder_vtable = {
106         .bid = lzop_bidder_bid,
107         .init = lzop_bidder_init,
108 };
109
110 int
111 archive_read_support_filter_lzop(struct archive *_a)
112 {
113         struct archive_read *a = (struct archive_read *)_a;
114
115         if (__archive_read_register_bidder(a, NULL, NULL,
116                                 &lzop_bidder_vtable) != ARCHIVE_OK)
117                 return (ARCHIVE_FATAL);
118
119         /* Signal the extent of lzop support with the return value here. */
120 #if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
121         return (ARCHIVE_OK);
122 #else
123         /* Return ARCHIVE_WARN since this always uses an external program. */
124         archive_set_error(_a, ARCHIVE_ERRNO_MISC,
125             "Using external lzop program for lzop decompression");
126         return (ARCHIVE_WARN);
127 #endif
128 }
129
130 /*
131  * Bidder just verifies the header and returns the number of verified bits.
132  */
133 static int
134 lzop_bidder_bid(struct archive_read_filter_bidder *self,
135     struct archive_read_filter *filter)
136 {
137         const unsigned char *p;
138         ssize_t avail;
139
140         (void)self; /* UNUSED */
141
142         p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
143         if (p == NULL || avail == 0)
144                 return (0);
145
146         if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
147                 return (0);
148
149         return (LZOP_HEADER_MAGIC_LEN * 8);
150 }
151
152 #if !defined(HAVE_LZO_LZOCONF_H) || !defined(HAVE_LZO_LZO1X_H)
153 /*
154  * If we don't have the library on this system, we can't do the
155  * decompression directly.  We can, however, try to run "lzop -d"
156  * in case that's available.
157  */
158 static int
159 lzop_bidder_init(struct archive_read_filter *self)
160 {
161         int r;
162
163         r = __archive_read_program(self, "lzop -d");
164         /* Note: We set the format here even if __archive_read_program()
165          * above fails.  We do, after all, know what the format is
166          * even if we weren't able to read it. */
167         self->code = ARCHIVE_FILTER_LZOP;
168         self->name = "lzop";
169         return (r);
170 }
171 #else
172
173 static const struct archive_read_filter_vtable
174 lzop_reader_vtable = {
175         .read = lzop_filter_read,
176         .close = lzop_filter_close
177 };
178
179 /*
180  * Initialize the filter object.
181  */
182 static int
183 lzop_bidder_init(struct archive_read_filter *self)
184 {
185         struct read_lzop *state;
186
187         self->code = ARCHIVE_FILTER_LZOP;
188         self->name = "lzop";
189
190         state = (struct read_lzop *)calloc(sizeof(*state), 1);
191         if (state == NULL) {
192                 archive_set_error(&self->archive->archive, ENOMEM,
193                     "Can't allocate data for lzop decompression");
194                 return (ARCHIVE_FATAL);
195         }
196
197         self->data = state;
198         self->vtable = &lzop_reader_vtable;
199
200         return (ARCHIVE_OK);
201 }
202
203 static int
204 consume_header(struct archive_read_filter *self)
205 {
206         struct read_lzop *state = (struct read_lzop *)self->data;
207         const unsigned char *p, *_p;
208         unsigned checksum, flags, len, method, version;
209
210         /*
211          * Check LZOP magic code.
212          */
213         p = __archive_read_filter_ahead(self->upstream,
214                 LZOP_HEADER_MAGIC_LEN, NULL);
215         if (p == NULL)
216                 return (ARCHIVE_EOF);
217
218         if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
219                 return (ARCHIVE_EOF);
220         __archive_read_filter_consume(self->upstream,
221             LZOP_HEADER_MAGIC_LEN);
222
223         p = __archive_read_filter_ahead(self->upstream, 29, NULL);
224         if (p == NULL)
225                 goto truncated;
226         _p = p;
227         version = archive_be16dec(p);
228         p += 4;/* version(2 bytes) + library version(2 bytes) */
229
230         if (version >= 0x940) {
231                 unsigned reqversion = archive_be16dec(p); p += 2;
232                 if (reqversion < 0x900) {
233                         archive_set_error(&self->archive->archive,
234                             ARCHIVE_ERRNO_MISC, "Invalid required version");
235                         return (ARCHIVE_FAILED);
236                 }
237         }
238
239         method = *p++;
240         if (method < 1 || method > 3) {
241                 archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
242                     "Unsupported method");
243                 return (ARCHIVE_FAILED);
244         }
245
246         if (version >= 0x940) {
247                 unsigned level = *p++;
248 #if 0
249                 unsigned default_level[] = {0, 3, 1, 9};
250 #endif
251                 if (level == 0)
252                         /* Method is 1..3 here due to check above. */
253 #if 0   /* Avoid an error Clang Static Analyzer claims
254           "Value stored to 'level' is never read". */
255                         level = default_level[method];
256 #else
257                         ;/* NOP */
258 #endif
259                 else if (level > 9) {
260                         archive_set_error(&self->archive->archive,
261                             ARCHIVE_ERRNO_MISC, "Invalid level");
262                         return (ARCHIVE_FAILED);
263                 }
264         }
265
266         flags = archive_be32dec(p); p += 4;
267
268         if (flags & FILTER)
269                 p += 4; /* Skip filter */
270         p += 4; /* Skip mode */
271         if (version >= 0x940)
272                 p += 8; /* Skip mtime */
273         else
274                 p += 4; /* Skip mtime */
275         len = *p++; /* Read filename length */
276         len += p - _p;
277         /* Make sure we have all bytes we need to calculate checksum. */
278         p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
279         if (p == NULL)
280                 goto truncated;
281         if (flags & CRC32_HEADER)
282                 checksum = crc32(crc32(0, NULL, 0), p, len);
283         else
284                 checksum = adler32(adler32(0, NULL, 0), p, len);
285         if (archive_be32dec(p + len) != checksum)
286                 goto corrupted;
287         __archive_read_filter_consume(self->upstream, len + 4);
288         if (flags & EXTRA_FIELD) {
289                 /* Skip extra field */
290                 p = __archive_read_filter_ahead(self->upstream, 4, NULL);
291                 if (p == NULL)
292                         goto truncated;
293                 len = archive_be32dec(p);
294                 __archive_read_filter_consume(self->upstream, len + 4 + 4);
295         }
296         state->flags = flags;
297         state->in_stream = 1;
298         return (ARCHIVE_OK);
299 truncated:
300         archive_set_error(&self->archive->archive,
301             ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
302         return (ARCHIVE_FAILED);
303 corrupted:
304         archive_set_error(&self->archive->archive,
305             ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
306         return (ARCHIVE_FAILED);
307 }
308
309 static int
310 consume_block_info(struct archive_read_filter *self)
311 {
312         struct read_lzop *state = (struct read_lzop *)self->data;
313         const unsigned char *p;
314         unsigned flags = state->flags;
315
316         p = __archive_read_filter_ahead(self->upstream, 4, NULL);
317         if (p == NULL)
318                 goto truncated;
319         state->uncompressed_size = archive_be32dec(p);
320         __archive_read_filter_consume(self->upstream, 4);
321         if (state->uncompressed_size == 0)
322                 return (ARCHIVE_EOF);
323         if (state->uncompressed_size > MAX_BLOCK_SIZE)
324                 goto corrupted;
325
326         p = __archive_read_filter_ahead(self->upstream, 4, NULL);
327         if (p == NULL)
328                 goto truncated;
329         state->compressed_size = archive_be32dec(p);
330         __archive_read_filter_consume(self->upstream, 4);
331         if (state->compressed_size > state->uncompressed_size)
332                 goto corrupted;
333
334         if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
335                 p = __archive_read_filter_ahead(self->upstream, 4, NULL);
336                 if (p == NULL)
337                         goto truncated;
338                 state->compressed_cksum = state->uncompressed_cksum =
339                     archive_be32dec(p);
340                 __archive_read_filter_consume(self->upstream, 4);
341         }
342         if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
343             state->compressed_size < state->uncompressed_size) {
344                 p = __archive_read_filter_ahead(self->upstream, 4, NULL);
345                 if (p == NULL)
346                         goto truncated;
347                 state->compressed_cksum = archive_be32dec(p);
348                 __archive_read_filter_consume(self->upstream, 4);
349         }
350         return (ARCHIVE_OK);
351 truncated:
352         archive_set_error(&self->archive->archive,
353             ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
354         return (ARCHIVE_FAILED);
355 corrupted:
356         archive_set_error(&self->archive->archive,
357             ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
358         return (ARCHIVE_FAILED);
359 }
360
361 static ssize_t
362 lzop_filter_read(struct archive_read_filter *self, const void **p)
363 {
364         struct read_lzop *state = (struct read_lzop *)self->data;
365         const void *b;
366         lzo_uint out_size;
367         uint32_t cksum;
368         int ret, r;
369
370         if (state->unconsumed_bytes) {
371                 __archive_read_filter_consume(self->upstream,
372                     state->unconsumed_bytes);
373                 state->unconsumed_bytes = 0;
374         }
375         if (state->eof)
376                 return (0);
377
378         for (;;) {
379                 if (!state->in_stream) {
380                         ret = consume_header(self);
381                         if (ret < ARCHIVE_OK)
382                                 return (ret);
383                         if (ret == ARCHIVE_EOF) {
384                                 state->eof = 1;
385                                 return (0);
386                         }
387                 }
388                 ret = consume_block_info(self);
389                 if (ret < ARCHIVE_OK)
390                         return (ret);
391                 if (ret == ARCHIVE_EOF)
392                         state->in_stream = 0;
393                 else
394                         break;
395         }
396
397         if (state->out_block == NULL ||
398             state->out_block_size < state->uncompressed_size) {
399                 void *new_block;
400
401                 new_block = realloc(state->out_block, state->uncompressed_size);
402                 if (new_block == NULL) {
403                         archive_set_error(&self->archive->archive, ENOMEM,
404                             "Can't allocate data for lzop decompression");
405                         return (ARCHIVE_FATAL);
406                 }
407                 state->out_block = new_block;
408                 state->out_block_size = state->uncompressed_size;
409         }
410
411         b = __archive_read_filter_ahead(self->upstream,
412                 state->compressed_size, NULL);
413         if (b == NULL) {
414                 archive_set_error(&self->archive->archive,
415                     ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
416                 return (ARCHIVE_FATAL);
417         }
418         if (state->flags & CRC32_COMPRESSED)
419                 cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
420         else if (state->flags & ADLER32_COMPRESSED)
421                 cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
422         else
423                 cksum = state->compressed_cksum;
424         if (cksum != state->compressed_cksum) {
425                 archive_set_error(&self->archive->archive,
426                     ARCHIVE_ERRNO_MISC, "Corrupted data");
427                 return (ARCHIVE_FATAL);
428         }
429
430         /*
431          * If the both uncompressed size and compressed size are the same,
432          * we do not decompress this block.
433          */
434         if (state->uncompressed_size == state->compressed_size) {
435                 *p = b;
436                 state->total_out += state->compressed_size;
437                 state->unconsumed_bytes = state->compressed_size;
438                 return ((ssize_t)state->uncompressed_size);
439         }
440
441         /*
442          * Drive lzo uncompression.
443          */
444         out_size = (lzo_uint)state->uncompressed_size;
445         r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
446                 state->out_block, &out_size, NULL);
447         switch (r) {
448         case LZO_E_OK:
449                 if (out_size == state->uncompressed_size)
450                         break;
451                 archive_set_error(&self->archive->archive,
452                     ARCHIVE_ERRNO_MISC, "Corrupted data");
453                 return (ARCHIVE_FATAL);
454         case LZO_E_OUT_OF_MEMORY:
455                 archive_set_error(&self->archive->archive, ENOMEM,
456                     "lzop decompression failed: out of memory");
457                 return (ARCHIVE_FATAL);
458         default:
459                 archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
460                     "lzop decompression failed: %d", r);
461                 return (ARCHIVE_FATAL);
462         }
463
464         if (state->flags & CRC32_UNCOMPRESSED)
465                 cksum = crc32(crc32(0, NULL, 0), state->out_block,
466                     state->uncompressed_size);
467         else if (state->flags & ADLER32_UNCOMPRESSED)
468                 cksum = adler32(adler32(0, NULL, 0), state->out_block,
469                     state->uncompressed_size);
470         else
471                 cksum = state->uncompressed_cksum;
472         if (cksum != state->uncompressed_cksum) {
473                 archive_set_error(&self->archive->archive,
474                     ARCHIVE_ERRNO_MISC, "Corrupted data");
475                 return (ARCHIVE_FATAL);
476         }
477
478         __archive_read_filter_consume(self->upstream, state->compressed_size);
479         *p = state->out_block;
480         state->total_out += out_size;
481         return ((ssize_t)out_size);
482 }
483
484 /*
485  * Clean up the decompressor.
486  */
487 static int
488 lzop_filter_close(struct archive_read_filter *self)
489 {
490         struct read_lzop *state = (struct read_lzop *)self->data;
491
492         free(state->out_block);
493         free(state);
494         return (ARCHIVE_OK);
495 }
496
497 #endif