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