1 /*-
2 * Copyright (c) 2009-2011 Sean Purcell
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 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26 #include "archive_platform.h"
27
28 __FBSDID("$FreeBSD$");
29
30 #ifdef HAVE_ERRNO_H
31 #include <errno.h>
32 #endif
33
34 #ifdef HAVE_ERRNO_H
35 #include <errno.h>
36 #endif
37 #include <stdio.h>
38 #ifdef HAVE_STDLIB_H
39 #include <stdlib.h>
40 #endif
41 #ifdef HAVE_STRING_H
42 #include <string.h>
43 #endif
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #if HAVE_ZSTD_H
48 #include <zstd.h>
49 #endif
50
51 #include "archive.h"
52 #include "archive_endian.h"
53 #include "archive_private.h"
54 #include "archive_read_private.h"
55
56 #if HAVE_ZSTD_H && HAVE_LIBZSTD
57
58 struct private_data {
59 ZSTD_DStream *dstream;
60 unsigned char *out_block;
61 size_t out_block_size;
62 int64_t total_out;
63 char in_frame; /* True = in the middle of a zstd frame. */
64 char eof; /* True = found end of compressed data. */
65 };
66
67 /* Zstd Filter. */
68 static ssize_t zstd_filter_read(struct archive_read_filter *, const void**);
69 static int zstd_filter_close(struct archive_read_filter *);
70 #endif
71
72 /*
73 * Note that we can detect zstd compressed files even if we can't decompress
74 * them. (In fact, we like detecting them because we can give better error
75 * messages.) So the bid framework here gets compiled even if no zstd library
76 * is available.
77 */
78 static int zstd_bidder_bid(struct archive_read_filter_bidder *,
79 struct archive_read_filter *);
80 static int zstd_bidder_init(struct archive_read_filter *);
81
82 static const struct archive_read_filter_bidder_vtable
83 zstd_bidder_vtable = {
84 .bid = zstd_bidder_bid,
85 .init = zstd_bidder_init,
86 };
87
88 int
archive_read_support_filter_zstd(struct archive * _a)89 archive_read_support_filter_zstd(struct archive *_a)
90 {
91 struct archive_read *a = (struct archive_read *)_a;
92
93 if (__archive_read_register_bidder(a, NULL, "zstd",
94 &zstd_bidder_vtable) != ARCHIVE_OK)
95 return (ARCHIVE_FATAL);
96
97 #if HAVE_ZSTD_H && HAVE_LIBZSTD
98 return (ARCHIVE_OK);
99 #else
100 archive_set_error(_a, ARCHIVE_ERRNO_MISC,
101 "Using external zstd program for zstd decompression");
102 return (ARCHIVE_WARN);
103 #endif
104 }
105
106 /*
107 * Test whether we can handle this data.
108 */
109 static int
zstd_bidder_bid(struct archive_read_filter_bidder * self,struct archive_read_filter * filter)110 zstd_bidder_bid(struct archive_read_filter_bidder *self,
111 struct archive_read_filter *filter)
112 {
113 const unsigned char *buffer;
114 ssize_t avail;
115 unsigned prefix;
116
117 /* Zstd frame magic values */
118 const unsigned zstd_magic = 0xFD2FB528U;
119 const unsigned zstd_magic_skippable_start = 0x184D2A50U;
120 const unsigned zstd_magic_skippable_mask = 0xFFFFFFF0;
121
122 (void) self; /* UNUSED */
123
124 buffer = __archive_read_filter_ahead(filter, 4, &avail);
125 if (buffer == NULL)
126 return (0);
127
128 prefix = archive_le32dec(buffer);
129 if (prefix == zstd_magic)
130 return (32);
131 if ((prefix & zstd_magic_skippable_mask) == zstd_magic_skippable_start)
132 return (32);
133
134 return (0);
135 }
136
137 #if !(HAVE_ZSTD_H && HAVE_LIBZSTD)
138
139 /*
140 * If we don't have the library on this system, we can't do the
141 * decompression directly. We can, however, try to run "zstd -d"
142 * in case that's available.
143 */
144 static int
zstd_bidder_init(struct archive_read_filter * self)145 zstd_bidder_init(struct archive_read_filter *self)
146 {
147 int r;
148
149 r = __archive_read_program(self, "zstd -d -qq");
150 /* Note: We set the format here even if __archive_read_program()
151 * above fails. We do, after all, know what the format is
152 * even if we weren't able to read it. */
153 self->code = ARCHIVE_FILTER_ZSTD;
154 self->name = "zstd";
155 return (r);
156 }
157
158 #else
159
160 static const struct archive_read_filter_vtable
161 zstd_reader_vtable = {
162 .read = zstd_filter_read,
163 .close = zstd_filter_close,
164 };
165
166 /*
167 * Initialize the filter object
168 */
169 static int
zstd_bidder_init(struct archive_read_filter * self)170 zstd_bidder_init(struct archive_read_filter *self)
171 {
172 struct private_data *state;
173 const size_t out_block_size = ZSTD_DStreamOutSize();
174 void *out_block;
175 ZSTD_DStream *dstream;
176
177 self->code = ARCHIVE_FILTER_ZSTD;
178 self->name = "zstd";
179
180 state = (struct private_data *)calloc(sizeof(*state), 1);
181 out_block = (unsigned char *)malloc(out_block_size);
182 dstream = ZSTD_createDStream();
183
184 if (state == NULL || out_block == NULL || dstream == NULL) {
185 free(out_block);
186 free(state);
187 ZSTD_freeDStream(dstream); /* supports free on NULL */
188 archive_set_error(&self->archive->archive, ENOMEM,
189 "Can't allocate data for zstd decompression");
190 return (ARCHIVE_FATAL);
191 }
192
193 self->data = state;
194
195 state->out_block_size = out_block_size;
196 state->out_block = out_block;
197 state->dstream = dstream;
198 self->vtable = &zstd_reader_vtable;
199
200 state->eof = 0;
201 state->in_frame = 0;
202
203 return (ARCHIVE_OK);
204 }
205
206 static ssize_t
zstd_filter_read(struct archive_read_filter * self,const void ** p)207 zstd_filter_read(struct archive_read_filter *self, const void **p)
208 {
209 struct private_data *state;
210 size_t decompressed;
211 ssize_t avail_in;
212 ZSTD_outBuffer out;
213 ZSTD_inBuffer in;
214
215 state = (struct private_data *)self->data;
216
217 out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };
218
219 /* Try to fill the output buffer. */
220 while (out.pos < out.size && !state->eof) {
221 if (!state->in_frame) {
222 const size_t ret = ZSTD_initDStream(state->dstream);
223 if (ZSTD_isError(ret)) {
224 archive_set_error(&self->archive->archive,
225 ARCHIVE_ERRNO_MISC,
226 "Error initializing zstd decompressor: %s",
227 ZSTD_getErrorName(ret));
228 return (ARCHIVE_FATAL);
229 }
230 }
231 in.src = __archive_read_filter_ahead(self->upstream, 1,
232 &avail_in);
233 if (avail_in < 0) {
234 return avail_in;
235 }
236 if (in.src == NULL && avail_in == 0) {
237 if (!state->in_frame) {
238 /* end of stream */
239 state->eof = 1;
240 break;
241 } else {
242 archive_set_error(&self->archive->archive,
243 ARCHIVE_ERRNO_MISC,
244 "Truncated zstd input");
245 return (ARCHIVE_FATAL);
246 }
247 }
248 in.size = avail_in;
249 in.pos = 0;
250
251 {
252 const size_t ret =
253 ZSTD_decompressStream(state->dstream, &out, &in);
254
255 if (ZSTD_isError(ret)) {
256 archive_set_error(&self->archive->archive,
257 ARCHIVE_ERRNO_MISC,
258 "Zstd decompression failed: %s",
259 ZSTD_getErrorName(ret));
260 return (ARCHIVE_FATAL);
261 }
262
263 /* Decompressor made some progress */
264 __archive_read_filter_consume(self->upstream, in.pos);
265
266 /* ret guaranteed to be > 0 if frame isn't done yet */
267 state->in_frame = (ret != 0);
268 }
269 }
270
271 decompressed = out.pos;
272 state->total_out += decompressed;
273 if (decompressed == 0)
274 *p = NULL;
275 else
276 *p = state->out_block;
277 return (decompressed);
278 }
279
280 /*
281 * Clean up the decompressor.
282 */
283 static int
zstd_filter_close(struct archive_read_filter * self)284 zstd_filter_close(struct archive_read_filter *self)
285 {
286 struct private_data *state;
287
288 state = (struct private_data *)self->data;
289
290 ZSTD_freeDStream(state->dstream);
291 free(state->out_block);
292 free(state);
293
294 return (ARCHIVE_OK);
295 }
296
297 #endif /* HAVE_ZLIB_H && HAVE_LIBZSTD */
298