diff --git a/src/basic/compress.c b/src/basic/compress.c index 61e87adddee..7f30fe61dae 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -8,6 +8,10 @@ #include #include +#if HAVE_LZ4 +#include +#endif + #if HAVE_XZ #include #endif @@ -43,6 +47,7 @@ static DLSYM_PROTOTYPE(LZ4F_freeCompressionContext) = NULL; static DLSYM_PROTOTYPE(LZ4F_freeDecompressionContext) = NULL; static DLSYM_PROTOTYPE(LZ4F_isError) = NULL; DLSYM_PROTOTYPE(LZ4_compress_default) = NULL; +DLSYM_PROTOTYPE(LZ4_compress_HC) = NULL; DLSYM_PROTOTYPE(LZ4_decompress_safe) = NULL; DLSYM_PROTOTYPE(LZ4_decompress_safe_partial) = NULL; DLSYM_PROTOTYPE(LZ4_versionNumber) = NULL; @@ -94,6 +99,7 @@ static DLSYM_PROTOTYPE(lzma_easy_encoder) = NULL; static DLSYM_PROTOTYPE(lzma_end) = NULL; static DLSYM_PROTOTYPE(lzma_stream_buffer_encode) = NULL; static DLSYM_PROTOTYPE(lzma_stream_decoder) = NULL; +static DLSYM_PROTOTYPE(lzma_lzma_preset) = NULL; /* We can't just do _cleanup_(sym_lzma_end) because a compiler bug makes * this fail with: @@ -145,12 +151,13 @@ int dlopen_lzma(void) { DLSYM_ARG(lzma_easy_encoder), DLSYM_ARG(lzma_end), DLSYM_ARG(lzma_stream_buffer_encode), + DLSYM_ARG(lzma_lzma_preset), DLSYM_ARG(lzma_stream_decoder)); } #endif int compress_blob_xz(const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size) { + void *dst, size_t dst_alloc_size, size_t *dst_size, int level) { assert(src); assert(src_size > 0); @@ -159,12 +166,12 @@ int compress_blob_xz(const void *src, uint64_t src_size, assert(dst_size); #if HAVE_XZ - static const lzma_options_lzma opt = { + lzma_options_lzma opt = { 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT, LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4 }; - static const lzma_filter filters[] = { - { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt }, + lzma_filter filters[] = { + { LZMA_FILTER_LZMA2, &opt }, { LZMA_VLI_UNKNOWN, NULL } }; lzma_ret ret; @@ -175,13 +182,19 @@ int compress_blob_xz(const void *src, uint64_t src_size, if (r < 0) return r; + if (level >= 0) { + r = sym_lzma_lzma_preset(&opt, (uint32_t) level); + if (r < 0) + return r; + } + /* Returns < 0 if we couldn't compress the data or the * compressed result is longer than the original */ if (src_size < 80) return -ENOBUFS; - ret = sym_lzma_stream_buffer_encode((lzma_filter*) filters, LZMA_CHECK_NONE, NULL, + ret = sym_lzma_stream_buffer_encode(filters, LZMA_CHECK_NONE, NULL, src, src_size, dst, &out_pos, dst_alloc_size); if (ret != LZMA_OK) return -ENOBUFS; @@ -214,6 +227,7 @@ int dlopen_lz4(void) { DLSYM_ARG(LZ4F_freeDecompressionContext), DLSYM_ARG(LZ4F_isError), DLSYM_ARG(LZ4_compress_default), + DLSYM_ARG(LZ4_compress_HC), DLSYM_ARG(LZ4_decompress_safe), DLSYM_ARG(LZ4_decompress_safe_partial), DLSYM_ARG(LZ4_versionNumber)); @@ -221,7 +235,7 @@ int dlopen_lz4(void) { #endif int compress_blob_lz4(const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size) { + void *dst, size_t dst_alloc_size, size_t *dst_size, int level) { assert(src); assert(src_size > 0); @@ -241,7 +255,10 @@ int compress_blob_lz4(const void *src, uint64_t src_size, if (src_size < 9) return -ENOBUFS; - r = sym_LZ4_compress_default(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8); + if (level <= 0) + r = sym_LZ4_compress_default(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8); + else + r = sym_LZ4_compress_HC(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8, level); if (r <= 0) return -ENOBUFS; @@ -285,7 +302,7 @@ int dlopen_zstd(void) { int compress_blob_zstd( const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size) { + void *dst, size_t dst_alloc_size, size_t *dst_size, int level) { assert(src); assert(src_size > 0); @@ -301,7 +318,7 @@ int compress_blob_zstd( if (r < 0) return r; - k = sym_ZSTD_compress(dst, dst_alloc_size, src, src_size, 0); + k = sym_ZSTD_compress(dst, dst_alloc_size, src, src_size, level < 0 ? 0 : level); if (sym_ZSTD_isError(k)) return zstd_ret_to_errno(k); diff --git a/src/basic/compress.h b/src/basic/compress.h index 1ad87ee8781..2f3ab2f39c9 100644 --- a/src/basic/compress.h +++ b/src/basic/compress.h @@ -28,11 +28,11 @@ Compression compression_from_string(const char *compression); bool compression_supported(Compression c); int compress_blob_xz(const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size); + void *dst, size_t dst_alloc_size, size_t *dst_size, int level); int compress_blob_lz4(const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size); + void *dst, size_t dst_alloc_size, size_t *dst_size, int level); int compress_blob_zstd(const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size); + void *dst, size_t dst_alloc_size, size_t *dst_size, int level); int decompress_blob_xz(const void *src, uint64_t src_size, void **dst, size_t* dst_size, size_t dst_max); @@ -90,15 +90,15 @@ int dlopen_lzma(void); static inline int compress_blob( Compression compression, const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size) { + void *dst, size_t dst_alloc_size, size_t *dst_size, int level) { switch (compression) { case COMPRESSION_ZSTD: - return compress_blob_zstd(src, src_size, dst, dst_alloc_size, dst_size); + return compress_blob_zstd(src, src_size, dst, dst_alloc_size, dst_size, level); case COMPRESSION_LZ4: - return compress_blob_lz4(src, src_size, dst, dst_alloc_size, dst_size); + return compress_blob_lz4(src, src_size, dst, dst_alloc_size, dst_size, level); case COMPRESSION_XZ: - return compress_blob_xz(src, src_size, dst, dst_alloc_size, dst_size); + return compress_blob_xz(src, src_size, dst, dst_alloc_size, dst_size, level); default: return -EOPNOTSUPP; } diff --git a/src/fuzz/fuzz-compress.c b/src/fuzz/fuzz-compress.c index c3f68f62dd2..6fcad736b18 100644 --- a/src/fuzz/fuzz-compress.c +++ b/src/fuzz/fuzz-compress.c @@ -42,7 +42,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { } size_t csize; - r = compress_blob(alg, h->data, data_len, buf, size, &csize); + r = compress_blob(alg, h->data, data_len, buf, size, &csize, /* level = */ -1); if (r < 0) { log_error_errno(r, "Compression failed: %m"); return 0; diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c index 508b47cbe78..97f65c561cb 100644 --- a/src/libsystemd/sd-journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -1810,7 +1810,7 @@ static int maybe_compress_payload(JournalFile *f, uint8_t *dst, const uint8_t *s if (c == COMPRESSION_NONE || size < f->compress_threshold_bytes) return 0; - r = compress_blob(c, src, size, dst, size - 1, rsize); + r = compress_blob(c, src, size, dst, size - 1, rsize, /* level = */ -1); if (r < 0) return log_debug_errno(r, "Failed to compress data object using %s, ignoring: %m", compression_to_string(c)); diff --git a/src/test/test-compress-benchmark.c b/src/test/test-compress-benchmark.c index 1727db8134d..c4e19f9256e 100644 --- a/src/test/test-compress-benchmark.c +++ b/src/test/test-compress-benchmark.c @@ -13,7 +13,7 @@ #include "tests.h" typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, - size_t dst_alloc_size, size_t *dst_size); + size_t dst_alloc_size, size_t *dst_size, int level); typedef int (decompress_t)(const void *src, uint64_t src_size, void **dst, size_t* dst_size, size_t dst_max); @@ -100,7 +100,7 @@ static void test_compress_decompress(const char* label, const char* type, memzero(buf, MIN(size + 1000, MAX_SIZE)); - r = compress(text, size, buf, size, &j); + r = compress(text, size, buf, size, &j, /* level = */ -1); /* assume compression must be successful except for small or random inputs */ assert_se(r >= 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random")); diff --git a/src/test/test-compress.c b/src/test/test-compress.c index 86311c6217e..9688e10df4a 100644 --- a/src/test/test-compress.c +++ b/src/test/test-compress.c @@ -33,7 +33,7 @@ #define HUGE_SIZE (4096*1024) typedef int (compress_blob_t)(const void *src, uint64_t src_size, - void *dst, size_t dst_alloc_size, size_t *dst_size); + void *dst, size_t dst_alloc_size, size_t *dst_size, int level); typedef int (decompress_blob_t)(const void *src, uint64_t src_size, void **dst, size_t* dst_size, size_t dst_max); @@ -62,7 +62,7 @@ _unused_ static void test_compress_decompress( log_info("/* testing %s %s blob compression/decompression */", compression, data); - r = compress(data, data_len, compressed, sizeof(compressed), &csize); + r = compress(data, data_len, compressed, sizeof(compressed), &csize, /* level = */ -1); if (r == -ENOBUFS) { log_info_errno(r, "compression failed: %m"); assert_se(may_fail); @@ -111,14 +111,14 @@ _unused_ static void test_decompress_startswith(const char *compression, compressed = compressed1 = malloc(BUFSIZE_1); assert_se(compressed1); - r = compress(data, data_len, compressed, BUFSIZE_1, &csize); + r = compress(data, data_len, compressed, BUFSIZE_1, &csize, /* level = */ -1); if (r == -ENOBUFS) { log_info_errno(r, "compression failed: %m"); assert_se(may_fail); compressed = compressed2 = malloc(BUFSIZE_2); assert_se(compressed2); - r = compress(data, data_len, compressed, BUFSIZE_2, &csize); + r = compress(data, data_len, compressed, BUFSIZE_2, &csize, /* level = */ -1); } assert_se(r >= 0); @@ -150,7 +150,7 @@ _unused_ static void test_decompress_startswith_short(const char *compression, log_info("/* %s with %s */", __func__, compression); - r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize); + r = compress(TEXT, sizeof TEXT, buf, sizeof buf, &csize, /* level = */ -1); assert_se(r >= 0); for (size_t i = 1; i < strlen(TEXT); i++) {