]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/compress.c
ac0bfdfcd5feccad2e80e1e26a899ee57692ef34
[thirdparty/systemd.git] / src / basic / compress.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <inttypes.h>
4 #include <malloc.h>
5 #include <stdlib.h>
6 #include <sys/mman.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10
11 #if HAVE_XZ
12 #include <lzma.h>
13 #endif
14
15 #if HAVE_LZ4
16 #include <lz4.h>
17 #include <lz4frame.h>
18 #endif
19
20 #if HAVE_ZSTD
21 #include <zstd.h>
22 #include <zstd_errors.h>
23 #endif
24
25 #include "alloc-util.h"
26 #include "compress.h"
27 #include "fd-util.h"
28 #include "fileio.h"
29 #include "io-util.h"
30 #include "macro.h"
31 #include "sparse-endian.h"
32 #include "string-table.h"
33 #include "string-util.h"
34 #include "unaligned.h"
35
36 #if HAVE_LZ4
37 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(LZ4F_compressionContext_t, LZ4F_freeCompressionContext, NULL);
38 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext, NULL);
39 #endif
40
41 #if HAVE_ZSTD
42 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ZSTD_CCtx*, ZSTD_freeCCtx, NULL);
43 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ZSTD_DCtx*, ZSTD_freeDCtx, NULL);
44
45 static int zstd_ret_to_errno(size_t ret) {
46 switch (ZSTD_getErrorCode(ret)) {
47 case ZSTD_error_dstSize_tooSmall:
48 return -ENOBUFS;
49 case ZSTD_error_memory_allocation:
50 return -ENOMEM;
51 default:
52 return -EBADMSG;
53 }
54 }
55 #endif
56
57 #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
58
59 static const char* const compression_table[_COMPRESSION_MAX] = {
60 [COMPRESSION_NONE] = "NONE",
61 [COMPRESSION_XZ] = "XZ",
62 [COMPRESSION_LZ4] = "LZ4",
63 [COMPRESSION_ZSTD] = "ZSTD",
64 };
65
66 DEFINE_STRING_TABLE_LOOKUP(compression, Compression);
67
68 bool compression_supported(Compression c) {
69 static const unsigned supported =
70 (1U << COMPRESSION_NONE) |
71 (1U << COMPRESSION_XZ) * HAVE_XZ |
72 (1U << COMPRESSION_LZ4) * HAVE_LZ4 |
73 (1U << COMPRESSION_ZSTD) * HAVE_ZSTD;
74
75 return c >= 0 && c < _COMPRESSION_MAX && FLAGS_SET(supported, 1U << c);
76 }
77
78 int compress_blob_xz(const void *src, uint64_t src_size,
79 void *dst, size_t dst_alloc_size, size_t *dst_size) {
80 #if HAVE_XZ
81 static const lzma_options_lzma opt = {
82 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT,
83 LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4
84 };
85 static const lzma_filter filters[] = {
86 { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt },
87 { LZMA_VLI_UNKNOWN, NULL }
88 };
89 lzma_ret ret;
90 size_t out_pos = 0;
91
92 assert(src);
93 assert(src_size > 0);
94 assert(dst);
95 assert(dst_alloc_size > 0);
96 assert(dst_size);
97
98 /* Returns < 0 if we couldn't compress the data or the
99 * compressed result is longer than the original */
100
101 if (src_size < 80)
102 return -ENOBUFS;
103
104 ret = lzma_stream_buffer_encode((lzma_filter*) filters, LZMA_CHECK_NONE, NULL,
105 src, src_size, dst, &out_pos, dst_alloc_size);
106 if (ret != LZMA_OK)
107 return -ENOBUFS;
108
109 *dst_size = out_pos;
110 return 0;
111 #else
112 return -EPROTONOSUPPORT;
113 #endif
114 }
115
116 int compress_blob_lz4(const void *src, uint64_t src_size,
117 void *dst, size_t dst_alloc_size, size_t *dst_size) {
118 #if HAVE_LZ4
119 int r;
120
121 assert(src);
122 assert(src_size > 0);
123 assert(dst);
124 assert(dst_alloc_size > 0);
125 assert(dst_size);
126
127 /* Returns < 0 if we couldn't compress the data or the
128 * compressed result is longer than the original */
129
130 if (src_size < 9)
131 return -ENOBUFS;
132
133 r = LZ4_compress_default(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8);
134 if (r <= 0)
135 return -ENOBUFS;
136
137 unaligned_write_le64(dst, src_size);
138 *dst_size = r + 8;
139
140 return 0;
141 #else
142 return -EPROTONOSUPPORT;
143 #endif
144 }
145
146 int compress_blob_zstd(
147 const void *src, uint64_t src_size,
148 void *dst, size_t dst_alloc_size, size_t *dst_size) {
149 #if HAVE_ZSTD
150 size_t k;
151
152 assert(src);
153 assert(src_size > 0);
154 assert(dst);
155 assert(dst_alloc_size > 0);
156 assert(dst_size);
157
158 k = ZSTD_compress(dst, dst_alloc_size, src, src_size, 0);
159 if (ZSTD_isError(k))
160 return zstd_ret_to_errno(k);
161
162 *dst_size = k;
163 return 0;
164 #else
165 return -EPROTONOSUPPORT;
166 #endif
167 }
168
169 int decompress_blob_xz(
170 const void *src,
171 uint64_t src_size,
172 void **dst,
173 size_t* dst_size,
174 size_t dst_max) {
175
176 #if HAVE_XZ
177 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
178 lzma_ret ret;
179 size_t space;
180
181 assert(src);
182 assert(src_size > 0);
183 assert(dst);
184 assert(dst_size);
185
186 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
187 if (ret != LZMA_OK)
188 return -ENOMEM;
189
190 space = MIN(src_size * 2, dst_max ?: SIZE_MAX);
191 if (!greedy_realloc(dst, space, 1))
192 return -ENOMEM;
193
194 s.next_in = src;
195 s.avail_in = src_size;
196
197 s.next_out = *dst;
198 s.avail_out = space;
199
200 for (;;) {
201 size_t used;
202
203 ret = lzma_code(&s, LZMA_FINISH);
204
205 if (ret == LZMA_STREAM_END)
206 break;
207 else if (ret != LZMA_OK)
208 return -ENOMEM;
209
210 if (dst_max > 0 && (space - s.avail_out) >= dst_max)
211 break;
212 else if (dst_max > 0 && space == dst_max)
213 return -ENOBUFS;
214
215 used = space - s.avail_out;
216 space = MIN(2 * space, dst_max ?: SIZE_MAX);
217 if (!greedy_realloc(dst, space, 1))
218 return -ENOMEM;
219
220 s.avail_out = space - used;
221 s.next_out = *(uint8_t**)dst + used;
222 }
223
224 *dst_size = space - s.avail_out;
225 return 0;
226 #else
227 return -EPROTONOSUPPORT;
228 #endif
229 }
230
231 int decompress_blob_lz4(
232 const void *src,
233 uint64_t src_size,
234 void **dst,
235 size_t* dst_size,
236 size_t dst_max) {
237
238 #if HAVE_LZ4
239 char* out;
240 int r, size; /* LZ4 uses int for size */
241
242 assert(src);
243 assert(src_size > 0);
244 assert(dst);
245 assert(dst_size);
246
247 if (src_size <= 8)
248 return -EBADMSG;
249
250 size = unaligned_read_le64(src);
251 if (size < 0 || (unsigned) size != unaligned_read_le64(src))
252 return -EFBIG;
253 out = greedy_realloc(dst, size, 1);
254 if (!out)
255 return -ENOMEM;
256
257 r = LZ4_decompress_safe((char*)src + 8, out, src_size - 8, size);
258 if (r < 0 || r != size)
259 return -EBADMSG;
260
261 *dst_size = size;
262 return 0;
263 #else
264 return -EPROTONOSUPPORT;
265 #endif
266 }
267
268 int decompress_blob_zstd(
269 const void *src,
270 uint64_t src_size,
271 void **dst,
272 size_t *dst_size,
273 size_t dst_max) {
274
275 #if HAVE_ZSTD
276 uint64_t size;
277
278 assert(src);
279 assert(src_size > 0);
280 assert(dst);
281 assert(dst_size);
282
283 size = ZSTD_getFrameContentSize(src, src_size);
284 if (IN_SET(size, ZSTD_CONTENTSIZE_ERROR, ZSTD_CONTENTSIZE_UNKNOWN))
285 return -EBADMSG;
286
287 if (dst_max > 0 && size > dst_max)
288 size = dst_max;
289 if (size > SIZE_MAX)
290 return -E2BIG;
291
292 if (!(greedy_realloc(dst, MAX(ZSTD_DStreamOutSize(), size), 1)))
293 return -ENOMEM;
294
295 _cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = ZSTD_createDCtx();
296 if (!dctx)
297 return -ENOMEM;
298
299 ZSTD_inBuffer input = {
300 .src = src,
301 .size = src_size,
302 };
303 ZSTD_outBuffer output = {
304 .dst = *dst,
305 .size = MALLOC_SIZEOF_SAFE(*dst),
306 };
307
308 size_t k = ZSTD_decompressStream(dctx, &output, &input);
309 if (ZSTD_isError(k)) {
310 log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(k));
311 return zstd_ret_to_errno(k);
312 }
313 assert(output.pos >= size);
314
315 *dst_size = size;
316 return 0;
317 #else
318 return -EPROTONOSUPPORT;
319 #endif
320 }
321
322 int decompress_blob(
323 Compression compression,
324 const void *src,
325 uint64_t src_size,
326 void **dst,
327 size_t* dst_size,
328 size_t dst_max) {
329
330 if (compression == COMPRESSION_XZ)
331 return decompress_blob_xz(
332 src, src_size,
333 dst, dst_size, dst_max);
334 else if (compression == COMPRESSION_LZ4)
335 return decompress_blob_lz4(
336 src, src_size,
337 dst, dst_size, dst_max);
338 else if (compression == COMPRESSION_ZSTD)
339 return decompress_blob_zstd(
340 src, src_size,
341 dst, dst_size, dst_max);
342 else
343 return -EPROTONOSUPPORT;
344 }
345
346 int decompress_startswith_xz(
347 const void *src,
348 uint64_t src_size,
349 void **buffer,
350 const void *prefix,
351 size_t prefix_len,
352 uint8_t extra) {
353
354 #if HAVE_XZ
355 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
356 size_t allocated;
357 lzma_ret ret;
358
359 /* Checks whether the decompressed blob starts with the mentioned prefix. The byte extra needs to
360 * follow the prefix */
361
362 assert(src);
363 assert(src_size > 0);
364 assert(buffer);
365 assert(prefix);
366
367 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
368 if (ret != LZMA_OK)
369 return -EBADMSG;
370
371 if (!(greedy_realloc(buffer, ALIGN_8(prefix_len + 1), 1)))
372 return -ENOMEM;
373
374 allocated = MALLOC_SIZEOF_SAFE(*buffer);
375
376 s.next_in = src;
377 s.avail_in = src_size;
378
379 s.next_out = *buffer;
380 s.avail_out = allocated;
381
382 for (;;) {
383 ret = lzma_code(&s, LZMA_FINISH);
384
385 if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END))
386 return -EBADMSG;
387
388 if (allocated - s.avail_out >= prefix_len + 1)
389 return memcmp(*buffer, prefix, prefix_len) == 0 &&
390 ((const uint8_t*) *buffer)[prefix_len] == extra;
391
392 if (ret == LZMA_STREAM_END)
393 return 0;
394
395 s.avail_out += allocated;
396
397 if (!(greedy_realloc(buffer, allocated * 2, 1)))
398 return -ENOMEM;
399
400 allocated = MALLOC_SIZEOF_SAFE(*buffer);
401 s.next_out = *(uint8_t**)buffer + allocated - s.avail_out;
402 }
403
404 #else
405 return -EPROTONOSUPPORT;
406 #endif
407 }
408
409 int decompress_startswith_lz4(
410 const void *src,
411 uint64_t src_size,
412 void **buffer,
413 const void *prefix,
414 size_t prefix_len,
415 uint8_t extra) {
416
417 #if HAVE_LZ4
418 /* Checks whether the decompressed blob starts with the mentioned prefix. The byte extra needs to
419 * follow the prefix */
420
421 size_t allocated;
422 int r;
423
424 assert(src);
425 assert(src_size > 0);
426 assert(buffer);
427 assert(prefix);
428
429 if (src_size <= 8)
430 return -EBADMSG;
431
432 if (!(greedy_realloc(buffer, ALIGN_8(prefix_len + 1), 1)))
433 return -ENOMEM;
434 allocated = MALLOC_SIZEOF_SAFE(*buffer);
435
436 r = LZ4_decompress_safe_partial(
437 (char*)src + 8,
438 *buffer,
439 src_size - 8,
440 prefix_len + 1,
441 allocated);
442
443 /* One lz4 < 1.8.3, we might get "failure" (r < 0), or "success" where just a part of the buffer is
444 * decompressed. But if we get a smaller amount of bytes than requested, we don't know whether there
445 * isn't enough data to fill the requested size or whether we just got a partial answer.
446 */
447 if (r < 0 || (size_t) r < prefix_len + 1) {
448 size_t size;
449
450 if (LZ4_versionNumber() >= 10803)
451 /* We trust that the newer lz4 decompresses the number of bytes we
452 * requested if available in the compressed string. */
453 return 0;
454
455 if (r > 0)
456 /* Compare what we have first, in case of mismatch we can
457 * shortcut the full comparison. */
458 if (memcmp(*buffer, prefix, r) != 0)
459 return 0;
460
461 /* Before version 1.8.3, lz4 always tries to decode full a "sequence",
462 * so in pathological cases might need to decompress the full field. */
463 r = decompress_blob_lz4(src, src_size, buffer, &size, 0);
464 if (r < 0)
465 return r;
466
467 if (size < prefix_len + 1)
468 return 0;
469 }
470
471 return memcmp(*buffer, prefix, prefix_len) == 0 &&
472 ((const uint8_t*) *buffer)[prefix_len] == extra;
473 #else
474 return -EPROTONOSUPPORT;
475 #endif
476 }
477
478 int decompress_startswith_zstd(
479 const void *src,
480 uint64_t src_size,
481 void **buffer,
482 const void *prefix,
483 size_t prefix_len,
484 uint8_t extra) {
485 #if HAVE_ZSTD
486 assert(src);
487 assert(src_size > 0);
488 assert(buffer);
489 assert(prefix);
490
491 uint64_t size = ZSTD_getFrameContentSize(src, src_size);
492 if (IN_SET(size, ZSTD_CONTENTSIZE_ERROR, ZSTD_CONTENTSIZE_UNKNOWN))
493 return -EBADMSG;
494
495 if (size < prefix_len + 1)
496 return 0; /* Decompressed text too short to match the prefix and extra */
497
498 _cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = ZSTD_createDCtx();
499 if (!dctx)
500 return -ENOMEM;
501
502 if (!(greedy_realloc(buffer, MAX(ZSTD_DStreamOutSize(), prefix_len + 1), 1)))
503 return -ENOMEM;
504
505 ZSTD_inBuffer input = {
506 .src = src,
507 .size = src_size,
508 };
509 ZSTD_outBuffer output = {
510 .dst = *buffer,
511 .size = MALLOC_SIZEOF_SAFE(*buffer),
512 };
513 size_t k;
514
515 k = ZSTD_decompressStream(dctx, &output, &input);
516 if (ZSTD_isError(k)) {
517 log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(k));
518 return zstd_ret_to_errno(k);
519 }
520 assert(output.pos >= prefix_len + 1);
521
522 return memcmp(*buffer, prefix, prefix_len) == 0 &&
523 ((const uint8_t*) *buffer)[prefix_len] == extra;
524 #else
525 return -EPROTONOSUPPORT;
526 #endif
527 }
528
529 int decompress_startswith(
530 Compression compression,
531 const void *src,
532 uint64_t src_size,
533 void **buffer,
534 const void *prefix,
535 size_t prefix_len,
536 uint8_t extra) {
537
538 if (compression == COMPRESSION_XZ)
539 return decompress_startswith_xz(
540 src, src_size,
541 buffer,
542 prefix, prefix_len,
543 extra);
544
545 else if (compression == COMPRESSION_LZ4)
546 return decompress_startswith_lz4(
547 src, src_size,
548 buffer,
549 prefix, prefix_len,
550 extra);
551 else if (compression == COMPRESSION_ZSTD)
552 return decompress_startswith_zstd(
553 src, src_size,
554 buffer,
555 prefix, prefix_len,
556 extra);
557 else
558 return -EBADMSG;
559 }
560
561 int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_uncompressed_size) {
562 #if HAVE_XZ
563 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
564 lzma_ret ret;
565 uint8_t buf[BUFSIZ], out[BUFSIZ];
566 lzma_action action = LZMA_RUN;
567
568 assert(fdf >= 0);
569 assert(fdt >= 0);
570
571 ret = lzma_easy_encoder(&s, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
572 if (ret != LZMA_OK)
573 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
574 "Failed to initialize XZ encoder: code %u",
575 ret);
576
577 for (;;) {
578 if (s.avail_in == 0 && action == LZMA_RUN) {
579 size_t m = sizeof(buf);
580 ssize_t n;
581
582 if (max_bytes != UINT64_MAX && (uint64_t) m > max_bytes)
583 m = (size_t) max_bytes;
584
585 n = read(fdf, buf, m);
586 if (n < 0)
587 return -errno;
588 if (n == 0)
589 action = LZMA_FINISH;
590 else {
591 s.next_in = buf;
592 s.avail_in = n;
593
594 if (max_bytes != UINT64_MAX) {
595 assert(max_bytes >= (uint64_t) n);
596 max_bytes -= n;
597 }
598 }
599 }
600
601 if (s.avail_out == 0) {
602 s.next_out = out;
603 s.avail_out = sizeof(out);
604 }
605
606 ret = lzma_code(&s, action);
607 if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END))
608 return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
609 "Compression failed: code %u",
610 ret);
611
612 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
613 ssize_t n, k;
614
615 n = sizeof(out) - s.avail_out;
616
617 k = loop_write(fdt, out, n);
618 if (k < 0)
619 return k;
620
621 if (ret == LZMA_STREAM_END) {
622 if (ret_uncompressed_size)
623 *ret_uncompressed_size = s.total_in;
624
625 log_debug("XZ compression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)",
626 s.total_in, s.total_out,
627 (double) s.total_out / s.total_in * 100);
628
629 return 0;
630 }
631 }
632 }
633 #else
634 return -EPROTONOSUPPORT;
635 #endif
636 }
637
638 #define LZ4_BUFSIZE (512*1024u)
639
640 int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_uncompressed_size) {
641
642 #if HAVE_LZ4
643 LZ4F_errorCode_t c;
644 _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL;
645 _cleanup_free_ void *in_buff = NULL;
646 _cleanup_free_ char *out_buff = NULL;
647 size_t out_allocsize, n, offset = 0, frame_size;
648 uint64_t total_in = 0, total_out;
649 int r;
650 static const LZ4F_preferences_t preferences = {
651 .frameInfo.blockSizeID = 5,
652 };
653
654 c = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
655 if (LZ4F_isError(c))
656 return -ENOMEM;
657
658 frame_size = LZ4F_compressBound(LZ4_BUFSIZE, &preferences);
659 out_allocsize = frame_size + 64*1024; /* add some space for header and trailer */
660 out_buff = malloc(out_allocsize);
661 if (!out_buff)
662 return -ENOMEM;
663
664 in_buff = malloc(LZ4_BUFSIZE);
665 if (!in_buff)
666 return -ENOMEM;
667
668 n = offset = total_out = LZ4F_compressBegin(ctx, out_buff, out_allocsize, &preferences);
669 if (LZ4F_isError(n))
670 return -EINVAL;
671
672 log_debug("Buffer size is %zu bytes, header size %zu bytes.", out_allocsize, n);
673
674 for (;;) {
675 ssize_t k;
676
677 k = loop_read(fdf, in_buff, LZ4_BUFSIZE, true);
678 if (k < 0)
679 return k;
680 if (k == 0)
681 break;
682 n = LZ4F_compressUpdate(ctx, out_buff + offset, out_allocsize - offset,
683 in_buff, k, NULL);
684 if (LZ4F_isError(n))
685 return -ENOTRECOVERABLE;
686
687 total_in += k;
688 offset += n;
689 total_out += n;
690
691 if (max_bytes != UINT64_MAX && total_out > (size_t) max_bytes)
692 return log_debug_errno(SYNTHETIC_ERRNO(EFBIG),
693 "Compressed stream longer than %" PRIu64 " bytes", max_bytes);
694
695 if (out_allocsize - offset < frame_size + 4) {
696 k = loop_write(fdt, out_buff, offset);
697 if (k < 0)
698 return k;
699 offset = 0;
700 }
701 }
702
703 n = LZ4F_compressEnd(ctx, out_buff + offset, out_allocsize - offset, NULL);
704 if (LZ4F_isError(n))
705 return -ENOTRECOVERABLE;
706
707 offset += n;
708 total_out += n;
709 r = loop_write(fdt, out_buff, offset);
710 if (r < 0)
711 return r;
712
713 if (ret_uncompressed_size)
714 *ret_uncompressed_size = total_in;
715
716 log_debug("LZ4 compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
717 total_in, total_out,
718 (double) total_out / total_in * 100);
719
720 return 0;
721 #else
722 return -EPROTONOSUPPORT;
723 #endif
724 }
725
726 int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) {
727
728 #if HAVE_XZ
729 _cleanup_(lzma_end) lzma_stream s = LZMA_STREAM_INIT;
730 lzma_ret ret;
731
732 uint8_t buf[BUFSIZ], out[BUFSIZ];
733 lzma_action action = LZMA_RUN;
734
735 assert(fdf >= 0);
736 assert(fdt >= 0);
737
738 ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
739 if (ret != LZMA_OK)
740 return log_debug_errno(SYNTHETIC_ERRNO(ENOMEM),
741 "Failed to initialize XZ decoder: code %u",
742 ret);
743
744 for (;;) {
745 if (s.avail_in == 0 && action == LZMA_RUN) {
746 ssize_t n;
747
748 n = read(fdf, buf, sizeof(buf));
749 if (n < 0)
750 return -errno;
751 if (n == 0)
752 action = LZMA_FINISH;
753 else {
754 s.next_in = buf;
755 s.avail_in = n;
756 }
757 }
758
759 if (s.avail_out == 0) {
760 s.next_out = out;
761 s.avail_out = sizeof(out);
762 }
763
764 ret = lzma_code(&s, action);
765 if (!IN_SET(ret, LZMA_OK, LZMA_STREAM_END))
766 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
767 "Decompression failed: code %u",
768 ret);
769
770 if (s.avail_out == 0 || ret == LZMA_STREAM_END) {
771 ssize_t n, k;
772
773 n = sizeof(out) - s.avail_out;
774
775 if (max_bytes != UINT64_MAX) {
776 if (max_bytes < (uint64_t) n)
777 return -EFBIG;
778
779 max_bytes -= n;
780 }
781
782 k = loop_write(fdt, out, n);
783 if (k < 0)
784 return k;
785
786 if (ret == LZMA_STREAM_END) {
787 log_debug("XZ decompression finished (%"PRIu64" -> %"PRIu64" bytes, %.1f%%)",
788 s.total_in, s.total_out,
789 (double) s.total_out / s.total_in * 100);
790
791 return 0;
792 }
793 }
794 }
795 #else
796 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
797 "Cannot decompress file. Compiled without XZ support.");
798 #endif
799 }
800
801 int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
802 #if HAVE_LZ4
803 size_t c;
804 _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL;
805 _cleanup_free_ char *buf = NULL;
806 char *src;
807 struct stat st;
808 int r = 0;
809 size_t total_in = 0, total_out = 0;
810
811 c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
812 if (LZ4F_isError(c))
813 return -ENOMEM;
814
815 if (fstat(in, &st) < 0)
816 return log_debug_errno(errno, "fstat() failed: %m");
817
818 if (file_offset_beyond_memory_size(st.st_size))
819 return -EFBIG;
820
821 buf = malloc(LZ4_BUFSIZE);
822 if (!buf)
823 return -ENOMEM;
824
825 src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in, 0);
826 if (src == MAP_FAILED)
827 return -errno;
828
829 while (total_in < (size_t) st.st_size) {
830 size_t produced = LZ4_BUFSIZE;
831 size_t used = st.st_size - total_in;
832
833 c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL);
834 if (LZ4F_isError(c)) {
835 r = -EBADMSG;
836 goto cleanup;
837 }
838
839 total_in += used;
840 total_out += produced;
841
842 if (max_bytes != UINT64_MAX && total_out > (size_t) max_bytes) {
843 log_debug("Decompressed stream longer than %"PRIu64" bytes", max_bytes);
844 r = -EFBIG;
845 goto cleanup;
846 }
847
848 r = loop_write(out, buf, produced);
849 if (r < 0)
850 goto cleanup;
851 }
852
853 log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
854 total_in, total_out,
855 total_in > 0 ? (double) total_out / total_in * 100 : 0.0);
856 cleanup:
857 munmap(src, st.st_size);
858 return r;
859 #else
860 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
861 "Cannot decompress file. Compiled without LZ4 support.");
862 #endif
863 }
864
865 int compress_stream_zstd(int fdf, int fdt, uint64_t max_bytes, uint64_t *ret_uncompressed_size) {
866 #if HAVE_ZSTD
867 _cleanup_(ZSTD_freeCCtxp) ZSTD_CCtx *cctx = NULL;
868 _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
869 size_t in_allocsize, out_allocsize;
870 size_t z;
871 uint64_t left = max_bytes, in_bytes = 0;
872
873 assert(fdf >= 0);
874 assert(fdt >= 0);
875
876 /* Create the context and buffers */
877 in_allocsize = ZSTD_CStreamInSize();
878 out_allocsize = ZSTD_CStreamOutSize();
879 in_buff = malloc(in_allocsize);
880 out_buff = malloc(out_allocsize);
881 cctx = ZSTD_createCCtx();
882 if (!cctx || !out_buff || !in_buff)
883 return -ENOMEM;
884
885 z = ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, 1);
886 if (ZSTD_isError(z))
887 log_debug("Failed to enable ZSTD checksum, ignoring: %s", ZSTD_getErrorName(z));
888
889 /* This loop read from the input file, compresses that entire chunk,
890 * and writes all output produced to the output file.
891 */
892 for (;;) {
893 bool is_last_chunk;
894 ZSTD_inBuffer input = {
895 .src = in_buff,
896 .size = 0,
897 .pos = 0
898 };
899 ssize_t red;
900
901 red = loop_read(fdf, in_buff, in_allocsize, true);
902 if (red < 0)
903 return red;
904 is_last_chunk = red == 0;
905
906 in_bytes += (size_t) red;
907 input.size = (size_t) red;
908
909 for (bool finished = false; !finished;) {
910 ZSTD_outBuffer output = {
911 .dst = out_buff,
912 .size = out_allocsize,
913 .pos = 0
914 };
915 size_t remaining;
916 ssize_t wrote;
917
918 /* Compress into the output buffer and write all of the
919 * output to the file so we can reuse the buffer next
920 * iteration.
921 */
922 remaining = ZSTD_compressStream2(
923 cctx, &output, &input,
924 is_last_chunk ? ZSTD_e_end : ZSTD_e_continue);
925
926 if (ZSTD_isError(remaining)) {
927 log_debug("ZSTD encoder failed: %s", ZSTD_getErrorName(remaining));
928 return zstd_ret_to_errno(remaining);
929 }
930
931 if (left < output.pos)
932 return -EFBIG;
933
934 wrote = loop_write_full(fdt, output.dst, output.pos, USEC_INFINITY);
935 if (wrote < 0)
936 return wrote;
937
938 left -= output.pos;
939
940 /* If we're on the last chunk we're finished when zstd
941 * returns 0, which means its consumed all the input AND
942 * finished the frame. Otherwise, we're finished when
943 * we've consumed all the input.
944 */
945 finished = is_last_chunk ? (remaining == 0) : (input.pos == input.size);
946 }
947
948 /* zstd only returns 0 when the input is completely consumed */
949 assert(input.pos == input.size);
950 if (is_last_chunk)
951 break;
952 }
953
954 if (ret_uncompressed_size)
955 *ret_uncompressed_size = in_bytes;
956
957 if (in_bytes > 0)
958 log_debug("ZSTD compression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
959 in_bytes, max_bytes - left, (double) (max_bytes - left) / in_bytes * 100);
960 else
961 log_debug("ZSTD compression finished (%" PRIu64 " -> %" PRIu64 " bytes)",
962 in_bytes, max_bytes - left);
963
964 return 0;
965 #else
966 return -EPROTONOSUPPORT;
967 #endif
968 }
969
970 int decompress_stream_zstd(int fdf, int fdt, uint64_t max_bytes) {
971 #if HAVE_ZSTD
972 _cleanup_(ZSTD_freeDCtxp) ZSTD_DCtx *dctx = NULL;
973 _cleanup_free_ void *in_buff = NULL, *out_buff = NULL;
974 size_t in_allocsize, out_allocsize;
975 size_t last_result = 0;
976 uint64_t left = max_bytes, in_bytes = 0;
977
978 assert(fdf >= 0);
979 assert(fdt >= 0);
980
981 /* Create the context and buffers */
982 in_allocsize = ZSTD_DStreamInSize();
983 out_allocsize = ZSTD_DStreamOutSize();
984 in_buff = malloc(in_allocsize);
985 out_buff = malloc(out_allocsize);
986 dctx = ZSTD_createDCtx();
987 if (!dctx || !out_buff || !in_buff)
988 return -ENOMEM;
989
990 /* This loop assumes that the input file is one or more concatenated
991 * zstd streams. This example won't work if there is trailing non-zstd
992 * data at the end, but streaming decompression in general handles this
993 * case. ZSTD_decompressStream() returns 0 exactly when the frame is
994 * completed, and doesn't consume input after the frame.
995 */
996 for (;;) {
997 bool has_error = false;
998 ZSTD_inBuffer input = {
999 .src = in_buff,
1000 .size = 0,
1001 .pos = 0
1002 };
1003 ssize_t red;
1004
1005 red = loop_read(fdf, in_buff, in_allocsize, true);
1006 if (red < 0)
1007 return red;
1008 if (red == 0)
1009 break;
1010
1011 in_bytes += (size_t) red;
1012 input.size = (size_t) red;
1013 input.pos = 0;
1014
1015 /* Given a valid frame, zstd won't consume the last byte of the
1016 * frame until it has flushed all of the decompressed data of
1017 * the frame. So input.pos < input.size means frame is not done
1018 * or there is still output available.
1019 */
1020 while (input.pos < input.size) {
1021 ZSTD_outBuffer output = {
1022 .dst = out_buff,
1023 .size = out_allocsize,
1024 .pos = 0
1025 };
1026 ssize_t wrote;
1027 /* The return code is zero if the frame is complete, but
1028 * there may be multiple frames concatenated together.
1029 * Zstd will automatically reset the context when a
1030 * frame is complete. Still, calling ZSTD_DCtx_reset()
1031 * can be useful to reset the context to a clean state,
1032 * for instance if the last decompression call returned
1033 * an error.
1034 */
1035 last_result = ZSTD_decompressStream(dctx, &output, &input);
1036 if (ZSTD_isError(last_result)) {
1037 has_error = true;
1038 break;
1039 }
1040
1041 if (left < output.pos)
1042 return -EFBIG;
1043
1044 wrote = loop_write_full(fdt, output.dst, output.pos, USEC_INFINITY);
1045 if (wrote < 0)
1046 return wrote;
1047
1048 left -= output.pos;
1049 }
1050 if (has_error)
1051 break;
1052 }
1053
1054 if (in_bytes == 0)
1055 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "ZSTD decoder failed: no data read");
1056
1057 if (last_result != 0) {
1058 /* The last return value from ZSTD_decompressStream did not end
1059 * on a frame, but we reached the end of the file! We assume
1060 * this is an error, and the input was truncated.
1061 */
1062 log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(last_result));
1063 return zstd_ret_to_errno(last_result);
1064 }
1065
1066 log_debug(
1067 "ZSTD decompression finished (%" PRIu64 " -> %" PRIu64 " bytes, %.1f%%)",
1068 in_bytes,
1069 max_bytes - left,
1070 (double) (max_bytes - left) / in_bytes * 100);
1071 return 0;
1072 #else
1073 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT),
1074 "Cannot decompress file. Compiled without ZSTD support.");
1075 #endif
1076 }
1077
1078 int decompress_stream(const char *filename, int fdf, int fdt, uint64_t max_bytes) {
1079
1080 if (endswith(filename, ".lz4"))
1081 return decompress_stream_lz4(fdf, fdt, max_bytes);
1082 else if (endswith(filename, ".xz"))
1083 return decompress_stream_xz(fdf, fdt, max_bytes);
1084 else if (endswith(filename, ".zst"))
1085 return decompress_stream_zstd(fdf, fdt, max_bytes);
1086 else
1087 return -EPROTONOSUPPORT;
1088 }