Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include "import-compress.h"
4 : : #include "string-table.h"
5 : : #include "util.h"
6 : :
7 : 0 : void import_compress_free(ImportCompress *c) {
8 [ # # ]: 0 : assert(c);
9 : :
10 [ # # ]: 0 : if (c->type == IMPORT_COMPRESS_XZ)
11 : 0 : lzma_end(&c->xz);
12 [ # # ]: 0 : else if (c->type == IMPORT_COMPRESS_GZIP) {
13 [ # # ]: 0 : if (c->encoding)
14 : 0 : deflateEnd(&c->gzip);
15 : : else
16 : 0 : inflateEnd(&c->gzip);
17 : : #if HAVE_BZIP2
18 [ # # ]: 0 : } else if (c->type == IMPORT_COMPRESS_BZIP2) {
19 [ # # ]: 0 : if (c->encoding)
20 : 0 : BZ2_bzCompressEnd(&c->bzip2);
21 : : else
22 : 0 : BZ2_bzDecompressEnd(&c->bzip2);
23 : : #endif
24 : : }
25 : :
26 : 0 : c->type = IMPORT_COMPRESS_UNKNOWN;
27 : 0 : }
28 : :
29 : 0 : int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) {
30 : : static const uint8_t xz_signature[] = {
31 : : 0xfd, '7', 'z', 'X', 'Z', 0x00
32 : : };
33 : : static const uint8_t gzip_signature[] = {
34 : : 0x1f, 0x8b
35 : : };
36 : : static const uint8_t bzip2_signature[] = {
37 : : 'B', 'Z', 'h'
38 : : };
39 : :
40 : : int r;
41 : :
42 [ # # ]: 0 : assert(c);
43 : :
44 [ # # ]: 0 : if (c->type != IMPORT_COMPRESS_UNKNOWN)
45 : 0 : return 1;
46 : :
47 [ # # ]: 0 : if (size < MAX3(sizeof(xz_signature),
48 : : sizeof(gzip_signature),
49 : : sizeof(bzip2_signature)))
50 : 0 : return 0;
51 : :
52 [ # # ]: 0 : assert(data);
53 : :
54 [ # # ]: 0 : if (memcmp(data, xz_signature, sizeof(xz_signature)) == 0) {
55 : : lzma_ret xzr;
56 : :
57 : 0 : xzr = lzma_stream_decoder(&c->xz, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED);
58 [ # # ]: 0 : if (xzr != LZMA_OK)
59 : 0 : return -EIO;
60 : :
61 : 0 : c->type = IMPORT_COMPRESS_XZ;
62 : :
63 [ # # ]: 0 : } else if (memcmp(data, gzip_signature, sizeof(gzip_signature)) == 0) {
64 : 0 : r = inflateInit2(&c->gzip, 15+16);
65 [ # # ]: 0 : if (r != Z_OK)
66 : 0 : return -EIO;
67 : :
68 : 0 : c->type = IMPORT_COMPRESS_GZIP;
69 : :
70 : : #if HAVE_BZIP2
71 [ # # ]: 0 : } else if (memcmp(data, bzip2_signature, sizeof(bzip2_signature)) == 0) {
72 : 0 : r = BZ2_bzDecompressInit(&c->bzip2, 0, 0);
73 [ # # ]: 0 : if (r != BZ_OK)
74 : 0 : return -EIO;
75 : :
76 : 0 : c->type = IMPORT_COMPRESS_BZIP2;
77 : : #endif
78 : : } else
79 : 0 : c->type = IMPORT_COMPRESS_UNCOMPRESSED;
80 : :
81 : 0 : c->encoding = false;
82 : :
83 : 0 : return 1;
84 : : }
85 : :
86 : 0 : int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCompressCallback callback, void *userdata) {
87 : : int r;
88 : :
89 [ # # ]: 0 : assert(c);
90 [ # # ]: 0 : assert(callback);
91 : :
92 : 0 : r = import_uncompress_detect(c, data, size);
93 [ # # ]: 0 : if (r <= 0)
94 : 0 : return r;
95 : :
96 [ # # ]: 0 : if (c->encoding)
97 : 0 : return -EINVAL;
98 : :
99 [ # # ]: 0 : if (size <= 0)
100 : 0 : return 1;
101 : :
102 [ # # ]: 0 : assert(data);
103 : :
104 [ # # # # : 0 : switch (c->type) {
# ]
105 : :
106 : 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
107 : 0 : r = callback(data, size, userdata);
108 [ # # ]: 0 : if (r < 0)
109 : 0 : return r;
110 : :
111 : 0 : break;
112 : :
113 : 0 : case IMPORT_COMPRESS_XZ:
114 : 0 : c->xz.next_in = data;
115 : 0 : c->xz.avail_in = size;
116 : :
117 [ # # ]: 0 : while (c->xz.avail_in > 0) {
118 : : uint8_t buffer[16 * 1024];
119 : : lzma_ret lzr;
120 : :
121 : 0 : c->xz.next_out = buffer;
122 : 0 : c->xz.avail_out = sizeof(buffer);
123 : :
124 : 0 : lzr = lzma_code(&c->xz, LZMA_RUN);
125 [ # # # # ]: 0 : if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END))
126 : 0 : return -EIO;
127 : :
128 : 0 : r = callback(buffer, sizeof(buffer) - c->xz.avail_out, userdata);
129 [ # # ]: 0 : if (r < 0)
130 : 0 : return r;
131 : : }
132 : :
133 : 0 : break;
134 : :
135 : 0 : case IMPORT_COMPRESS_GZIP:
136 : 0 : c->gzip.next_in = (void*) data;
137 : 0 : c->gzip.avail_in = size;
138 : :
139 [ # # ]: 0 : while (c->gzip.avail_in > 0) {
140 : : uint8_t buffer[16 * 1024];
141 : :
142 : 0 : c->gzip.next_out = buffer;
143 : 0 : c->gzip.avail_out = sizeof(buffer);
144 : :
145 : 0 : r = inflate(&c->gzip, Z_NO_FLUSH);
146 [ # # # # ]: 0 : if (!IN_SET(r, Z_OK, Z_STREAM_END))
147 : 0 : return -EIO;
148 : :
149 : 0 : r = callback(buffer, sizeof(buffer) - c->gzip.avail_out, userdata);
150 [ # # ]: 0 : if (r < 0)
151 : 0 : return r;
152 : : }
153 : :
154 : 0 : break;
155 : :
156 : : #if HAVE_BZIP2
157 : 0 : case IMPORT_COMPRESS_BZIP2:
158 : 0 : c->bzip2.next_in = (void*) data;
159 : 0 : c->bzip2.avail_in = size;
160 : :
161 [ # # ]: 0 : while (c->bzip2.avail_in > 0) {
162 : : uint8_t buffer[16 * 1024];
163 : :
164 : 0 : c->bzip2.next_out = (char*) buffer;
165 : 0 : c->bzip2.avail_out = sizeof(buffer);
166 : :
167 : 0 : r = BZ2_bzDecompress(&c->bzip2);
168 [ # # # # ]: 0 : if (!IN_SET(r, BZ_OK, BZ_STREAM_END))
169 : 0 : return -EIO;
170 : :
171 : 0 : r = callback(buffer, sizeof(buffer) - c->bzip2.avail_out, userdata);
172 [ # # ]: 0 : if (r < 0)
173 : 0 : return r;
174 : : }
175 : :
176 : 0 : break;
177 : : #endif
178 : :
179 : 0 : default:
180 : 0 : assert_not_reached("Unknown compression");
181 : : }
182 : :
183 : 0 : return 1;
184 : : }
185 : :
186 : 0 : int import_compress_init(ImportCompress *c, ImportCompressType t) {
187 : : int r;
188 : :
189 [ # # ]: 0 : assert(c);
190 : :
191 [ # # # # : 0 : switch (t) {
# ]
192 : :
193 : 0 : case IMPORT_COMPRESS_XZ: {
194 : : lzma_ret xzr;
195 : :
196 : 0 : xzr = lzma_easy_encoder(&c->xz, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
197 [ # # ]: 0 : if (xzr != LZMA_OK)
198 : 0 : return -EIO;
199 : :
200 : 0 : c->type = IMPORT_COMPRESS_XZ;
201 : 0 : break;
202 : : }
203 : :
204 : 0 : case IMPORT_COMPRESS_GZIP:
205 : 0 : r = deflateInit2(&c->gzip, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
206 [ # # ]: 0 : if (r != Z_OK)
207 : 0 : return -EIO;
208 : :
209 : 0 : c->type = IMPORT_COMPRESS_GZIP;
210 : 0 : break;
211 : :
212 : : #if HAVE_BZIP2
213 : 0 : case IMPORT_COMPRESS_BZIP2:
214 : 0 : r = BZ2_bzCompressInit(&c->bzip2, 9, 0, 0);
215 [ # # ]: 0 : if (r != BZ_OK)
216 : 0 : return -EIO;
217 : :
218 : 0 : c->type = IMPORT_COMPRESS_BZIP2;
219 : 0 : break;
220 : : #endif
221 : :
222 : 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
223 : 0 : c->type = IMPORT_COMPRESS_UNCOMPRESSED;
224 : 0 : break;
225 : :
226 : 0 : default:
227 : 0 : return -EOPNOTSUPP;
228 : : }
229 : :
230 : 0 : c->encoding = true;
231 : 0 : return 0;
232 : : }
233 : :
234 : 0 : static int enlarge_buffer(void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
235 : : size_t l;
236 : : void *p;
237 : :
238 [ # # ]: 0 : if (*buffer_allocated > *buffer_size)
239 : 0 : return 0;
240 : :
241 : 0 : l = MAX(16*1024U, (*buffer_size * 2));
242 : 0 : p = realloc(*buffer, l);
243 [ # # ]: 0 : if (!p)
244 : 0 : return -ENOMEM;
245 : :
246 : 0 : *buffer = p;
247 : 0 : *buffer_allocated = l;
248 : :
249 : 0 : return 1;
250 : : }
251 : :
252 : 0 : int import_compress(ImportCompress *c, const void *data, size_t size, void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
253 : : int r;
254 : :
255 [ # # ]: 0 : assert(c);
256 [ # # ]: 0 : assert(buffer);
257 [ # # ]: 0 : assert(buffer_size);
258 [ # # ]: 0 : assert(buffer_allocated);
259 : :
260 [ # # ]: 0 : if (!c->encoding)
261 : 0 : return -EINVAL;
262 : :
263 [ # # ]: 0 : if (size <= 0)
264 : 0 : return 0;
265 : :
266 [ # # ]: 0 : assert(data);
267 : :
268 : 0 : *buffer_size = 0;
269 : :
270 [ # # # # : 0 : switch (c->type) {
# ]
271 : :
272 : 0 : case IMPORT_COMPRESS_XZ:
273 : :
274 : 0 : c->xz.next_in = data;
275 : 0 : c->xz.avail_in = size;
276 : :
277 [ # # ]: 0 : while (c->xz.avail_in > 0) {
278 : : lzma_ret lzr;
279 : :
280 : 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
281 [ # # ]: 0 : if (r < 0)
282 : 0 : return r;
283 : :
284 : 0 : c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
285 : 0 : c->xz.avail_out = *buffer_allocated - *buffer_size;
286 : :
287 : 0 : lzr = lzma_code(&c->xz, LZMA_RUN);
288 [ # # ]: 0 : if (lzr != LZMA_OK)
289 : 0 : return -EIO;
290 : :
291 : 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
292 : : }
293 : :
294 : 0 : break;
295 : :
296 : 0 : case IMPORT_COMPRESS_GZIP:
297 : :
298 : 0 : c->gzip.next_in = (void*) data;
299 : 0 : c->gzip.avail_in = size;
300 : :
301 [ # # ]: 0 : while (c->gzip.avail_in > 0) {
302 : 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
303 [ # # ]: 0 : if (r < 0)
304 : 0 : return r;
305 : :
306 : 0 : c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
307 : 0 : c->gzip.avail_out = *buffer_allocated - *buffer_size;
308 : :
309 : 0 : r = deflate(&c->gzip, Z_NO_FLUSH);
310 [ # # ]: 0 : if (r != Z_OK)
311 : 0 : return -EIO;
312 : :
313 : 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
314 : : }
315 : :
316 : 0 : break;
317 : :
318 : : #if HAVE_BZIP2
319 : 0 : case IMPORT_COMPRESS_BZIP2:
320 : :
321 : 0 : c->bzip2.next_in = (void*) data;
322 : 0 : c->bzip2.avail_in = size;
323 : :
324 [ # # ]: 0 : while (c->bzip2.avail_in > 0) {
325 : 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
326 [ # # ]: 0 : if (r < 0)
327 : 0 : return r;
328 : :
329 : 0 : c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
330 : 0 : c->bzip2.avail_out = *buffer_allocated - *buffer_size;
331 : :
332 : 0 : r = BZ2_bzCompress(&c->bzip2, BZ_RUN);
333 [ # # ]: 0 : if (r != BZ_RUN_OK)
334 : 0 : return -EIO;
335 : :
336 : 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
337 : : }
338 : :
339 : 0 : break;
340 : : #endif
341 : :
342 : 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
343 : :
344 [ # # ]: 0 : if (*buffer_allocated < size) {
345 : : void *p;
346 : :
347 : 0 : p = realloc(*buffer, size);
348 [ # # ]: 0 : if (!p)
349 : 0 : return -ENOMEM;
350 : :
351 : 0 : *buffer = p;
352 : 0 : *buffer_allocated = size;
353 : : }
354 : :
355 : 0 : memcpy(*buffer, data, size);
356 : 0 : *buffer_size = size;
357 : 0 : break;
358 : :
359 : 0 : default:
360 : 0 : return -EOPNOTSUPP;
361 : : }
362 : :
363 : 0 : return 0;
364 : : }
365 : :
366 : 0 : int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
367 : : int r;
368 : :
369 [ # # ]: 0 : assert(c);
370 [ # # ]: 0 : assert(buffer);
371 [ # # ]: 0 : assert(buffer_size);
372 [ # # ]: 0 : assert(buffer_allocated);
373 : :
374 [ # # ]: 0 : if (!c->encoding)
375 : 0 : return -EINVAL;
376 : :
377 : 0 : *buffer_size = 0;
378 : :
379 [ # # # # : 0 : switch (c->type) {
# ]
380 : :
381 : 0 : case IMPORT_COMPRESS_XZ: {
382 : : lzma_ret lzr;
383 : :
384 : 0 : c->xz.avail_in = 0;
385 : :
386 : : do {
387 : 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
388 [ # # ]: 0 : if (r < 0)
389 : 0 : return r;
390 : :
391 : 0 : c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
392 : 0 : c->xz.avail_out = *buffer_allocated - *buffer_size;
393 : :
394 : 0 : lzr = lzma_code(&c->xz, LZMA_FINISH);
395 [ # # # # ]: 0 : if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END))
396 : 0 : return -EIO;
397 : :
398 : 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
399 [ # # ]: 0 : } while (lzr != LZMA_STREAM_END);
400 : :
401 : 0 : break;
402 : : }
403 : :
404 : 0 : case IMPORT_COMPRESS_GZIP:
405 : 0 : c->gzip.avail_in = 0;
406 : :
407 : : do {
408 : 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
409 [ # # ]: 0 : if (r < 0)
410 : 0 : return r;
411 : :
412 : 0 : c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
413 : 0 : c->gzip.avail_out = *buffer_allocated - *buffer_size;
414 : :
415 : 0 : r = deflate(&c->gzip, Z_FINISH);
416 [ # # # # ]: 0 : if (!IN_SET(r, Z_OK, Z_STREAM_END))
417 : 0 : return -EIO;
418 : :
419 : 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
420 [ # # ]: 0 : } while (r != Z_STREAM_END);
421 : :
422 : 0 : break;
423 : :
424 : : #if HAVE_BZIP2
425 : 0 : case IMPORT_COMPRESS_BZIP2:
426 : 0 : c->bzip2.avail_in = 0;
427 : :
428 : : do {
429 : 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
430 [ # # ]: 0 : if (r < 0)
431 : 0 : return r;
432 : :
433 : 0 : c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
434 : 0 : c->bzip2.avail_out = *buffer_allocated - *buffer_size;
435 : :
436 : 0 : r = BZ2_bzCompress(&c->bzip2, BZ_FINISH);
437 [ # # # # ]: 0 : if (!IN_SET(r, BZ_FINISH_OK, BZ_STREAM_END))
438 : 0 : return -EIO;
439 : :
440 : 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
441 [ # # ]: 0 : } while (r != BZ_STREAM_END);
442 : :
443 : 0 : break;
444 : : #endif
445 : :
446 : 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
447 : 0 : break;
448 : :
449 : 0 : default:
450 : 0 : return -EOPNOTSUPP;
451 : : }
452 : :
453 : 0 : return 0;
454 : : }
455 : :
456 : : static const char* const import_compress_type_table[_IMPORT_COMPRESS_TYPE_MAX] = {
457 : : [IMPORT_COMPRESS_UNKNOWN] = "unknown",
458 : : [IMPORT_COMPRESS_UNCOMPRESSED] = "uncompressed",
459 : : [IMPORT_COMPRESS_XZ] = "xz",
460 : : [IMPORT_COMPRESS_GZIP] = "gzip",
461 : : #if HAVE_BZIP2
462 : : [IMPORT_COMPRESS_BZIP2] = "bzip2",
463 : : #endif
464 : : };
465 : :
466 [ # # # # ]: 0 : DEFINE_STRING_TABLE_LOOKUP(import_compress_type, ImportCompressType);
|