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