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