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