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