]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/import/import-compress.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[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
128 r = callback(buffer, sizeof(buffer) - c->xz.avail_out, userdata);
129 if (r < 0)
130 return r;
131 }
132
133 break;
134
135 case IMPORT_COMPRESS_GZIP:
136 c->gzip.next_in = (void*) data;
137 c->gzip.avail_in = size;
138
139 while (c->gzip.avail_in > 0) {
140 uint8_t buffer[16 * 1024];
141
142 c->gzip.next_out = buffer;
143 c->gzip.avail_out = sizeof(buffer);
144
145 r = inflate(&c->gzip, Z_NO_FLUSH);
ec2ce0c5 146 if (!IN_SET(r, Z_OK, Z_STREAM_END))
3e2cda69
LP
147 return -EIO;
148
149 r = callback(buffer, sizeof(buffer) - c->gzip.avail_out, userdata);
150 if (r < 0)
151 return r;
152 }
153
154 break;
155
044c2c7a 156#if HAVE_BZIP2
3e2cda69
LP
157 case IMPORT_COMPRESS_BZIP2:
158 c->bzip2.next_in = (void*) data;
159 c->bzip2.avail_in = size;
160
161 while (c->bzip2.avail_in > 0) {
162 uint8_t buffer[16 * 1024];
163
164 c->bzip2.next_out = (char*) buffer;
165 c->bzip2.avail_out = sizeof(buffer);
166
167 r = BZ2_bzDecompress(&c->bzip2);
ec2ce0c5 168 if (!IN_SET(r, BZ_OK, BZ_STREAM_END))
3e2cda69
LP
169 return -EIO;
170
171 r = callback(buffer, sizeof(buffer) - c->bzip2.avail_out, userdata);
172 if (r < 0)
173 return r;
174 }
175
176 break;
044c2c7a 177#endif
3e2cda69
LP
178
179 default:
180 assert_not_reached("Unknown compression");
181 }
182
183 return 1;
184}
185
587fec42
LP
186int import_compress_init(ImportCompress *c, ImportCompressType t) {
187 int r;
188
189 assert(c);
190
191 switch (t) {
192
193 case IMPORT_COMPRESS_XZ: {
194 lzma_ret xzr;
195
196 xzr = lzma_easy_encoder(&c->xz, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
197 if (xzr != LZMA_OK)
198 return -EIO;
199
200 c->type = IMPORT_COMPRESS_XZ;
201 break;
202 }
203
204 case IMPORT_COMPRESS_GZIP:
205 r = deflateInit2(&c->gzip, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
206 if (r != Z_OK)
207 return -EIO;
208
209 c->type = IMPORT_COMPRESS_GZIP;
210 break;
211
044c2c7a 212#if HAVE_BZIP2
587fec42
LP
213 case IMPORT_COMPRESS_BZIP2:
214 r = BZ2_bzCompressInit(&c->bzip2, 9, 0, 0);
215 if (r != BZ_OK)
216 return -EIO;
217
218 c->type = IMPORT_COMPRESS_BZIP2;
219 break;
044c2c7a 220#endif
587fec42
LP
221
222 case IMPORT_COMPRESS_UNCOMPRESSED:
223 c->type = IMPORT_COMPRESS_UNCOMPRESSED;
224 break;
225
226 default:
15411c0c 227 return -EOPNOTSUPP;
587fec42
LP
228 }
229
230 c->encoding = true;
231 return 0;
232}
233
234static int enlarge_buffer(void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
235 size_t l;
236 void *p;
237
238 if (*buffer_allocated > *buffer_size)
239 return 0;
240
241 l = MAX(16*1024U, (*buffer_size * 2));
242 p = realloc(*buffer, l);
243 if (!p)
244 return -ENOMEM;
245
246 *buffer = p;
247 *buffer_allocated = l;
248
249 return 1;
250}
251
252int 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 assert(c);
256 assert(buffer);
257 assert(buffer_size);
258 assert(buffer_allocated);
259
260 if (!c->encoding)
261 return -EINVAL;
262
263 if (size <= 0)
264 return 0;
265
266 assert(data);
267
268 *buffer_size = 0;
269
270 switch (c->type) {
271
272 case IMPORT_COMPRESS_XZ:
273
274 c->xz.next_in = data;
275 c->xz.avail_in = size;
276
277 while (c->xz.avail_in > 0) {
278 lzma_ret lzr;
279
280 r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
281 if (r < 0)
282 return r;
283
284 c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
285 c->xz.avail_out = *buffer_allocated - *buffer_size;
286
287 lzr = lzma_code(&c->xz, LZMA_RUN);
288 if (lzr != LZMA_OK)
289 return -EIO;
290
291 *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
292 }
293
294 break;
295
296 case IMPORT_COMPRESS_GZIP:
297
298 c->gzip.next_in = (void*) data;
299 c->gzip.avail_in = size;
300
301 while (c->gzip.avail_in > 0) {
302 r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
303 if (r < 0)
304 return r;
305
306 c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
307 c->gzip.avail_out = *buffer_allocated - *buffer_size;
308
309 r = deflate(&c->gzip, Z_NO_FLUSH);
310 if (r != Z_OK)
311 return -EIO;
312
313 *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
314 }
315
316 break;
317
044c2c7a 318#if HAVE_BZIP2
587fec42
LP
319 case IMPORT_COMPRESS_BZIP2:
320
321 c->bzip2.next_in = (void*) data;
322 c->bzip2.avail_in = size;
323
324 while (c->bzip2.avail_in > 0) {
325 r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
326 if (r < 0)
327 return r;
328
329 c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
330 c->bzip2.avail_out = *buffer_allocated - *buffer_size;
331
332 r = BZ2_bzCompress(&c->bzip2, BZ_RUN);
333 if (r != BZ_RUN_OK)
334 return -EIO;
335
336 *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
337 }
338
339 break;
044c2c7a 340#endif
587fec42
LP
341
342 case IMPORT_COMPRESS_UNCOMPRESSED:
343
344 if (*buffer_allocated < size) {
345 void *p;
346
347 p = realloc(*buffer, size);
348 if (!p)
349 return -ENOMEM;
350
351 *buffer = p;
352 *buffer_allocated = size;
353 }
354
355 memcpy(*buffer, data, size);
356 *buffer_size = size;
357 break;
358
359 default:
15411c0c 360 return -EOPNOTSUPP;
587fec42
LP
361 }
362
363 return 0;
364}
365
366int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
367 int r;
368
369 assert(c);
370 assert(buffer);
371 assert(buffer_size);
372 assert(buffer_allocated);
373
374 if (!c->encoding)
375 return -EINVAL;
376
377 *buffer_size = 0;
378
379 switch (c->type) {
380
381 case IMPORT_COMPRESS_XZ: {
382 lzma_ret lzr;
383
384 c->xz.avail_in = 0;
385
386 do {
387 r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
388 if (r < 0)
389 return r;
390
391 c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
392 c->xz.avail_out = *buffer_allocated - *buffer_size;
393
394 lzr = lzma_code(&c->xz, LZMA_FINISH);
ec2ce0c5 395 if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END))
587fec42
LP
396 return -EIO;
397
398 *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
399 } while (lzr != LZMA_STREAM_END);
400
401 break;
402 }
403
404 case IMPORT_COMPRESS_GZIP:
405 c->gzip.avail_in = 0;
406
407 do {
408 r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
409 if (r < 0)
410 return r;
411
412 c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
413 c->gzip.avail_out = *buffer_allocated - *buffer_size;
414
415 r = deflate(&c->gzip, Z_FINISH);
ec2ce0c5 416 if (!IN_SET(r, Z_OK, Z_STREAM_END))
587fec42
LP
417 return -EIO;
418
419 *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
420 } while (r != Z_STREAM_END);
421
422 break;
423
044c2c7a 424#if HAVE_BZIP2
587fec42
LP
425 case IMPORT_COMPRESS_BZIP2:
426 c->bzip2.avail_in = 0;
427
428 do {
429 r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
430 if (r < 0)
431 return r;
432
433 c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
434 c->bzip2.avail_out = *buffer_allocated - *buffer_size;
435
436 r = BZ2_bzCompress(&c->bzip2, BZ_FINISH);
ec2ce0c5 437 if (!IN_SET(r, BZ_FINISH_OK, BZ_STREAM_END))
587fec42
LP
438 return -EIO;
439
440 *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
441 } while (r != BZ_STREAM_END);
442
443 break;
044c2c7a 444#endif
587fec42
LP
445
446 case IMPORT_COMPRESS_UNCOMPRESSED:
447 break;
448
449 default:
15411c0c 450 return -EOPNOTSUPP;
587fec42
LP
451 }
452
453 return 0;
454}
455
3e2cda69
LP
456static 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",
044c2c7a 461#if HAVE_BZIP2
3e2cda69 462 [IMPORT_COMPRESS_BZIP2] = "bzip2",
044c2c7a 463#endif
3e2cda69
LP
464};
465
466DEFINE_STRING_TABLE_LOOKUP(import_compress_type, ImportCompressType);