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
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
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
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
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
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
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