1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
22 #include <zstd_errors.h>
25 #include "alloc-util.h"
31 #include "sparse-endian.h"
32 #include "string-table.h"
33 #include "string-util.h"
34 #include "unaligned.h"
37 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(LZ4F_compressionContext_t
, LZ4F_freeCompressionContext
, NULL
);
38 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(LZ4F_decompressionContext_t
, LZ4F_freeDecompressionContext
, NULL
);
42 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ZSTD_CCtx
*, ZSTD_freeCCtx
, NULL
);
43 DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ZSTD_DCtx
*, ZSTD_freeDCtx
, NULL
);
45 static int zstd_ret_to_errno(size_t ret
) {
46 switch (ZSTD_getErrorCode(ret
)) {
47 case ZSTD_error_dstSize_tooSmall
:
49 case ZSTD_error_memory_allocation
:
57 #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t))
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",
66 DEFINE_STRING_TABLE_LOOKUP(compression
, Compression
);
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
;
75 return c
>= 0 && c
< _COMPRESSION_MAX
&& FLAGS_SET(supported
, 1U << c
);
78 int compress_blob_xz(const void *src
, uint64_t src_size
,
79 void *dst
, size_t dst_alloc_size
, size_t *dst_size
) {
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
85 static const lzma_filter filters
[] = {
86 { LZMA_FILTER_LZMA2
, (lzma_options_lzma
*) &opt
},
87 { LZMA_VLI_UNKNOWN
, NULL
}
95 assert(dst_alloc_size
> 0);
98 /* Returns < 0 if we couldn't compress the data or the
99 * compressed result is longer than the original */
104 ret
= lzma_stream_buffer_encode((lzma_filter
*) filters
, LZMA_CHECK_NONE
, NULL
,
105 src
, src_size
, dst
, &out_pos
, dst_alloc_size
);
112 return -EPROTONOSUPPORT
;
116 int compress_blob_lz4(const void *src
, uint64_t src_size
,
117 void *dst
, size_t dst_alloc_size
, size_t *dst_size
) {
122 assert(src_size
> 0);
124 assert(dst_alloc_size
> 0);
127 /* Returns < 0 if we couldn't compress the data or the
128 * compressed result is longer than the original */
133 r
= LZ4_compress_default(src
, (char*)dst
+ 8, src_size
, (int) dst_alloc_size
- 8);
137 unaligned_write_le64(dst
, src_size
);
142 return -EPROTONOSUPPORT
;
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
) {
153 assert(src_size
> 0);
155 assert(dst_alloc_size
> 0);
158 k
= ZSTD_compress(dst
, dst_alloc_size
, src
, src_size
, 0);
160 return zstd_ret_to_errno(k
);
165 return -EPROTONOSUPPORT
;
169 int decompress_blob_xz(
177 _cleanup_(lzma_end
) lzma_stream s
= LZMA_STREAM_INIT
;
182 assert(src_size
> 0);
186 ret
= lzma_stream_decoder(&s
, UINT64_MAX
, 0);
190 space
= MIN(src_size
* 2, dst_max
?: SIZE_MAX
);
191 if (!greedy_realloc(dst
, space
, 1))
195 s
.avail_in
= src_size
;
203 ret
= lzma_code(&s
, LZMA_FINISH
);
205 if (ret
== LZMA_STREAM_END
)
207 else if (ret
!= LZMA_OK
)
210 if (dst_max
> 0 && (space
- s
.avail_out
) >= dst_max
)
212 else if (dst_max
> 0 && space
== dst_max
)
215 used
= space
- s
.avail_out
;
216 space
= MIN(2 * space
, dst_max
?: SIZE_MAX
);
217 if (!greedy_realloc(dst
, space
, 1))
220 s
.avail_out
= space
- used
;
221 s
.next_out
= *(uint8_t**)dst
+ used
;
224 *dst_size
= space
- s
.avail_out
;
227 return -EPROTONOSUPPORT
;
231 int decompress_blob_lz4(
240 int r
, size
; /* LZ4 uses int for size */
243 assert(src_size
> 0);
250 size
= unaligned_read_le64(src
);
251 if (size
< 0 || (unsigned) size
!= unaligned_read_le64(src
))
253 out
= greedy_realloc(dst
, size
, 1);
257 r
= LZ4_decompress_safe((char*)src
+ 8, out
, src_size
- 8, size
);
258 if (r
< 0 || r
!= size
)
264 return -EPROTONOSUPPORT
;
268 int decompress_blob_zstd(
279 assert(src_size
> 0);
283 size
= ZSTD_getFrameContentSize(src
, src_size
);
284 if (IN_SET(size
, ZSTD_CONTENTSIZE_ERROR
, ZSTD_CONTENTSIZE_UNKNOWN
))
287 if (dst_max
> 0 && size
> dst_max
)
292 if (!(greedy_realloc(dst
, MAX(ZSTD_DStreamOutSize(), size
), 1)))
295 _cleanup_(ZSTD_freeDCtxp
) ZSTD_DCtx
*dctx
= ZSTD_createDCtx();
299 ZSTD_inBuffer input
= {
303 ZSTD_outBuffer output
= {
305 .size
= MALLOC_SIZEOF_SAFE(*dst
),
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
);
313 assert(output
.pos
>= size
);
318 return -EPROTONOSUPPORT
;
323 Compression compression
,
330 if (compression
== COMPRESSION_XZ
)
331 return decompress_blob_xz(
333 dst
, dst_size
, dst_max
);
334 else if (compression
== COMPRESSION_LZ4
)
335 return decompress_blob_lz4(
337 dst
, dst_size
, dst_max
);
338 else if (compression
== COMPRESSION_ZSTD
)
339 return decompress_blob_zstd(
341 dst
, dst_size
, dst_max
);
343 return -EPROTONOSUPPORT
;
346 int decompress_startswith_xz(
355 _cleanup_(lzma_end
) lzma_stream s
= LZMA_STREAM_INIT
;
359 /* Checks whether the decompressed blob starts with the mentioned prefix. The byte extra needs to
360 * follow the prefix */
363 assert(src_size
> 0);
367 ret
= lzma_stream_decoder(&s
, UINT64_MAX
, 0);
371 if (!(greedy_realloc(buffer
, ALIGN_8(prefix_len
+ 1), 1)))
374 allocated
= MALLOC_SIZEOF_SAFE(*buffer
);
377 s
.avail_in
= src_size
;
379 s
.next_out
= *buffer
;
380 s
.avail_out
= allocated
;
383 ret
= lzma_code(&s
, LZMA_FINISH
);
385 if (!IN_SET(ret
, LZMA_OK
, LZMA_STREAM_END
))
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
;
392 if (ret
== LZMA_STREAM_END
)
395 s
.avail_out
+= allocated
;
397 if (!(greedy_realloc(buffer
, allocated
* 2, 1)))
400 allocated
= MALLOC_SIZEOF_SAFE(*buffer
);
401 s
.next_out
= *(uint8_t**)buffer
+ allocated
- s
.avail_out
;
405 return -EPROTONOSUPPORT
;
409 int decompress_startswith_lz4(
418 /* Checks whether the decompressed blob starts with the mentioned prefix. The byte extra needs to
419 * follow the prefix */
425 assert(src_size
> 0);
432 if (!(greedy_realloc(buffer
, ALIGN_8(prefix_len
+ 1), 1)))
434 allocated
= MALLOC_SIZEOF_SAFE(*buffer
);
436 r
= LZ4_decompress_safe_partial(
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.
447 if (r
< 0 || (size_t) r
< prefix_len
+ 1) {
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. */
456 /* Compare what we have first, in case of mismatch we can
457 * shortcut the full comparison. */
458 if (memcmp(*buffer
, prefix
, r
) != 0)
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);
467 if (size
< prefix_len
+ 1)
471 return memcmp(*buffer
, prefix
, prefix_len
) == 0 &&
472 ((const uint8_t*) *buffer
)[prefix_len
] == extra
;
474 return -EPROTONOSUPPORT
;
478 int decompress_startswith_zstd(
487 assert(src_size
> 0);
491 uint64_t size
= ZSTD_getFrameContentSize(src
, src_size
);
492 if (IN_SET(size
, ZSTD_CONTENTSIZE_ERROR
, ZSTD_CONTENTSIZE_UNKNOWN
))
495 if (size
< prefix_len
+ 1)
496 return 0; /* Decompressed text too short to match the prefix and extra */
498 _cleanup_(ZSTD_freeDCtxp
) ZSTD_DCtx
*dctx
= ZSTD_createDCtx();
502 if (!(greedy_realloc(buffer
, MAX(ZSTD_DStreamOutSize(), prefix_len
+ 1), 1)))
505 ZSTD_inBuffer input
= {
509 ZSTD_outBuffer output
= {
511 .size
= MALLOC_SIZEOF_SAFE(*buffer
),
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
);
520 assert(output
.pos
>= prefix_len
+ 1);
522 return memcmp(*buffer
, prefix
, prefix_len
) == 0 &&
523 ((const uint8_t*) *buffer
)[prefix_len
] == extra
;
525 return -EPROTONOSUPPORT
;
529 int decompress_startswith(
530 Compression compression
,
538 if (compression
== COMPRESSION_XZ
)
539 return decompress_startswith_xz(
545 else if (compression
== COMPRESSION_LZ4
)
546 return decompress_startswith_lz4(
551 else if (compression
== COMPRESSION_ZSTD
)
552 return decompress_startswith_zstd(
561 int compress_stream_xz(int fdf
, int fdt
, uint64_t max_bytes
, uint64_t *ret_uncompressed_size
) {
563 _cleanup_(lzma_end
) lzma_stream s
= LZMA_STREAM_INIT
;
565 uint8_t buf
[BUFSIZ
], out
[BUFSIZ
];
566 lzma_action action
= LZMA_RUN
;
571 ret
= lzma_easy_encoder(&s
, LZMA_PRESET_DEFAULT
, LZMA_CHECK_CRC64
);
573 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
574 "Failed to initialize XZ encoder: code %u",
578 if (s
.avail_in
== 0 && action
== LZMA_RUN
) {
579 size_t m
= sizeof(buf
);
582 if (max_bytes
!= UINT64_MAX
&& (uint64_t) m
> max_bytes
)
583 m
= (size_t) max_bytes
;
585 n
= read(fdf
, buf
, m
);
589 action
= LZMA_FINISH
;
594 if (max_bytes
!= UINT64_MAX
) {
595 assert(max_bytes
>= (uint64_t) n
);
601 if (s
.avail_out
== 0) {
603 s
.avail_out
= sizeof(out
);
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",
612 if (s
.avail_out
== 0 || ret
== LZMA_STREAM_END
) {
615 n
= sizeof(out
) - s
.avail_out
;
617 k
= loop_write(fdt
, out
, n
);
621 if (ret
== LZMA_STREAM_END
) {
622 if (ret_uncompressed_size
)
623 *ret_uncompressed_size
= s
.total_in
;
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);
634 return -EPROTONOSUPPORT
;
638 #define LZ4_BUFSIZE (512*1024u)
640 int compress_stream_lz4(int fdf
, int fdt
, uint64_t max_bytes
, uint64_t *ret_uncompressed_size
) {
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
;
650 static const LZ4F_preferences_t preferences
= {
651 .frameInfo
.blockSizeID
= 5,
654 c
= LZ4F_createCompressionContext(&ctx
, LZ4F_VERSION
);
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
);
664 in_buff
= malloc(LZ4_BUFSIZE
);
668 n
= offset
= total_out
= LZ4F_compressBegin(ctx
, out_buff
, out_allocsize
, &preferences
);
672 log_debug("Buffer size is %zu bytes, header size %zu bytes.", out_allocsize
, n
);
677 k
= loop_read(fdf
, in_buff
, LZ4_BUFSIZE
, true);
682 n
= LZ4F_compressUpdate(ctx
, out_buff
+ offset
, out_allocsize
- offset
,
685 return -ENOTRECOVERABLE
;
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
);
695 if (out_allocsize
- offset
< frame_size
+ 4) {
696 k
= loop_write(fdt
, out_buff
, offset
);
703 n
= LZ4F_compressEnd(ctx
, out_buff
+ offset
, out_allocsize
- offset
, NULL
);
705 return -ENOTRECOVERABLE
;
709 r
= loop_write(fdt
, out_buff
, offset
);
713 if (ret_uncompressed_size
)
714 *ret_uncompressed_size
= total_in
;
716 log_debug("LZ4 compression finished (%" PRIu64
" -> %" PRIu64
" bytes, %.1f%%)",
718 (double) total_out
/ total_in
* 100);
722 return -EPROTONOSUPPORT
;
726 int decompress_stream_xz(int fdf
, int fdt
, uint64_t max_bytes
) {
729 _cleanup_(lzma_end
) lzma_stream s
= LZMA_STREAM_INIT
;
732 uint8_t buf
[BUFSIZ
], out
[BUFSIZ
];
733 lzma_action action
= LZMA_RUN
;
738 ret
= lzma_stream_decoder(&s
, UINT64_MAX
, 0);
740 return log_debug_errno(SYNTHETIC_ERRNO(ENOMEM
),
741 "Failed to initialize XZ decoder: code %u",
745 if (s
.avail_in
== 0 && action
== LZMA_RUN
) {
748 n
= read(fdf
, buf
, sizeof(buf
));
752 action
= LZMA_FINISH
;
759 if (s
.avail_out
== 0) {
761 s
.avail_out
= sizeof(out
);
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",
770 if (s
.avail_out
== 0 || ret
== LZMA_STREAM_END
) {
773 n
= sizeof(out
) - s
.avail_out
;
775 if (max_bytes
!= UINT64_MAX
) {
776 if (max_bytes
< (uint64_t) n
)
782 k
= loop_write(fdt
, out
, n
);
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);
796 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT
),
797 "Cannot decompress file. Compiled without XZ support.");
801 int decompress_stream_lz4(int in
, int out
, uint64_t max_bytes
) {
804 _cleanup_(LZ4F_freeDecompressionContextp
) LZ4F_decompressionContext_t ctx
= NULL
;
805 _cleanup_free_
char *buf
= NULL
;
809 size_t total_in
= 0, total_out
= 0;
811 c
= LZ4F_createDecompressionContext(&ctx
, LZ4F_VERSION
);
815 if (fstat(in
, &st
) < 0)
816 return log_debug_errno(errno
, "fstat() failed: %m");
818 if (file_offset_beyond_memory_size(st
.st_size
))
821 buf
= malloc(LZ4_BUFSIZE
);
825 src
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_PRIVATE
, in
, 0);
826 if (src
== MAP_FAILED
)
829 while (total_in
< (size_t) st
.st_size
) {
830 size_t produced
= LZ4_BUFSIZE
;
831 size_t used
= st
.st_size
- total_in
;
833 c
= LZ4F_decompress(ctx
, buf
, &produced
, src
+ total_in
, &used
, NULL
);
834 if (LZ4F_isError(c
)) {
840 total_out
+= produced
;
842 if (max_bytes
!= UINT64_MAX
&& total_out
> (size_t) max_bytes
) {
843 log_debug("Decompressed stream longer than %"PRIu64
" bytes", max_bytes
);
848 r
= loop_write(out
, buf
, produced
);
853 log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)",
855 total_in
> 0 ? (double) total_out
/ total_in
* 100 : 0.0);
857 munmap(src
, st
.st_size
);
860 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT
),
861 "Cannot decompress file. Compiled without LZ4 support.");
865 int compress_stream_zstd(int fdf
, int fdt
, uint64_t max_bytes
, uint64_t *ret_uncompressed_size
) {
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
;
871 uint64_t left
= max_bytes
, in_bytes
= 0;
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
)
885 z
= ZSTD_CCtx_setParameter(cctx
, ZSTD_c_checksumFlag
, 1);
887 log_debug("Failed to enable ZSTD checksum, ignoring: %s", ZSTD_getErrorName(z
));
889 /* This loop read from the input file, compresses that entire chunk,
890 * and writes all output produced to the output file.
894 ZSTD_inBuffer input
= {
901 red
= loop_read(fdf
, in_buff
, in_allocsize
, true);
904 is_last_chunk
= red
== 0;
906 in_bytes
+= (size_t) red
;
907 input
.size
= (size_t) red
;
909 for (bool finished
= false; !finished
;) {
910 ZSTD_outBuffer output
= {
912 .size
= out_allocsize
,
918 /* Compress into the output buffer and write all of the
919 * output to the file so we can reuse the buffer next
922 remaining
= ZSTD_compressStream2(
923 cctx
, &output
, &input
,
924 is_last_chunk
? ZSTD_e_end
: ZSTD_e_continue
);
926 if (ZSTD_isError(remaining
)) {
927 log_debug("ZSTD encoder failed: %s", ZSTD_getErrorName(remaining
));
928 return zstd_ret_to_errno(remaining
);
931 if (left
< output
.pos
)
934 wrote
= loop_write_full(fdt
, output
.dst
, output
.pos
, USEC_INFINITY
);
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.
945 finished
= is_last_chunk
? (remaining
== 0) : (input
.pos
== input
.size
);
948 /* zstd only returns 0 when the input is completely consumed */
949 assert(input
.pos
== input
.size
);
954 if (ret_uncompressed_size
)
955 *ret_uncompressed_size
= in_bytes
;
958 log_debug("ZSTD compression finished (%" PRIu64
" -> %" PRIu64
" bytes, %.1f%%)",
959 in_bytes
, max_bytes
- left
, (double) (max_bytes
- left
) / in_bytes
* 100);
961 log_debug("ZSTD compression finished (%" PRIu64
" -> %" PRIu64
" bytes)",
962 in_bytes
, max_bytes
- left
);
966 return -EPROTONOSUPPORT
;
970 int decompress_stream_zstd(int fdf
, int fdt
, uint64_t max_bytes
) {
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;
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
)
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.
997 bool has_error
= false;
998 ZSTD_inBuffer input
= {
1005 red
= loop_read(fdf
, in_buff
, in_allocsize
, true);
1011 in_bytes
+= (size_t) red
;
1012 input
.size
= (size_t) red
;
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.
1020 while (input
.pos
< input
.size
) {
1021 ZSTD_outBuffer output
= {
1023 .size
= out_allocsize
,
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
1035 last_result
= ZSTD_decompressStream(dctx
, &output
, &input
);
1036 if (ZSTD_isError(last_result
)) {
1041 if (left
< output
.pos
)
1044 wrote
= loop_write_full(fdt
, output
.dst
, output
.pos
, USEC_INFINITY
);
1055 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "ZSTD decoder failed: no data read");
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.
1062 log_debug("ZSTD decoder failed: %s", ZSTD_getErrorName(last_result
));
1063 return zstd_ret_to_errno(last_result
);
1067 "ZSTD decompression finished (%" PRIu64
" -> %" PRIu64
" bytes, %.1f%%)",
1070 (double) (max_bytes
- left
) / in_bytes
* 100);
1073 return log_debug_errno(SYNTHETIC_ERRNO(EPROTONOSUPPORT
),
1074 "Cannot decompress file. Compiled without ZSTD support.");
1078 int decompress_stream(const char *filename
, int fdf
, int fdt
, uint64_t max_bytes
) {
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
);
1087 return -EPROTONOSUPPORT
;