From 8f0bc5866467e26c945a597dc46e7c7daba373cd Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 24 Aug 2026 03:27:36 +0900 Subject: [PATCH 1/7] compress: introduce dlopen_compress() and friends --- src/basic/compress.c | 26 ++++++++++++++++++++++++++ src/basic/compress.h | 6 ++++++ test/test-dlopen-note.py | 3 +++ 3 files changed, 35 insertions(+) diff --git a/src/basic/compress.c b/src/basic/compress.c index 0f62fb95f5..55a204f9ce 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -424,6 +424,32 @@ int dlopen_bzip2(int log_level) { #endif } +int dlopen_compress_journal(Compression c, int log_level) { + switch (c) { + case COMPRESSION_NONE: + return 0; + case COMPRESSION_XZ: + return dlopen_xz(log_level); + case COMPRESSION_LZ4: + return dlopen_lz4(log_level); + case COMPRESSION_ZSTD: + return dlopen_zstd(log_level); + default: + return -EOPNOTSUPP; + } +} + +int dlopen_compress(Compression c, int log_level) { + switch (c) { + case COMPRESSION_GZIP: + return dlopen_zlib(log_level); + case COMPRESSION_BZIP2: + return dlopen_bzip2(log_level); + default: + return dlopen_compress_journal(c, log_level); + } +} + static int compress_blob_xz( const void *src, uint64_t src_size, diff --git a/src/basic/compress.h b/src/basic/compress.h index f46b787f0c..e20713a8b7 100644 --- a/src/basic/compress.h +++ b/src/basic/compress.h @@ -102,6 +102,12 @@ int dlopen_zstd(int log_level) _dlopen_loader_; int dlopen_zlib(int log_level) _dlopen_loader_; int dlopen_bzip2(int log_level) _dlopen_loader_; +int dlopen_compress(Compression c, int log_level); +int dlopen_compress_journal(Compression c, int log_level); +static inline int dlopen_compress_default(int log_level) { + return dlopen_compress_journal(DEFAULT_COMPRESSION, log_level); +} + static inline const char* default_compression_extension(void) { return compression_extension_to_string(DEFAULT_COMPRESSION) ?: ""; } diff --git a/test/test-dlopen-note.py b/test/test-dlopen-note.py index 295a0bc69c..5cb995eed7 100755 --- a/test/test-dlopen-note.py +++ b/test/test-dlopen-note.py @@ -33,6 +33,9 @@ except ImportError: # Function filter: Maps wrapper/sentinel symbols to real symbols or an empty list (ignore). FUNCTION_FILTER = { # Filtered out (internal helpers, verbose loggers, sentinels) + 'dlopen_compress': [], + 'dlopen_compress_journal': [], + 'dlopen_compress_default': [], 'dlopen_safe': [], 'dlopen_verbose': [], 'dlopen_many_sym_or_warn_sentinel': [], From 4e2cb2bdf19feb537f46bf8b0331d2736091fede Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 24 Aug 2026 03:28:11 +0900 Subject: [PATCH 2/7] compress: use dlopen_compress() in decompress_stream() --- src/basic/compress.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/basic/compress.c b/src/basic/compress.c index 55a204f9ce..7bacd65609 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -1702,7 +1702,7 @@ static int decompress_stream_write_callback(const void *data, size_t size, void } static int decompressor_new(Decompressor **ret, Compression type) { -#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD || HAVE_ZLIB || HAVE_BZIP2 +#if HAVE_ZLIB || HAVE_BZIP2 int r; #endif @@ -1718,10 +1718,6 @@ static int decompressor_new(Decompressor **ret, Compression type) { #if HAVE_XZ case COMPRESSION_XZ: - r = dlopen_xz(LOG_DEBUG); - if (r < 0) - return r; - if (sym_lzma_stream_decoder(&c->xz, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED) != LZMA_OK) return -EIO; break; @@ -1729,10 +1725,6 @@ static int decompressor_new(Decompressor **ret, Compression type) { #if HAVE_LZ4 case COMPRESSION_LZ4: { - r = dlopen_lz4(LOG_DEBUG); - if (r < 0) - return r; - size_t rc = sym_LZ4F_createDecompressionContext(&c->d_lz4, LZ4F_VERSION); if (sym_LZ4F_isError(rc)) return -ENOMEM; @@ -1743,10 +1735,6 @@ static int decompressor_new(Decompressor **ret, Compression type) { #if HAVE_ZSTD case COMPRESSION_ZSTD: - r = dlopen_zstd(LOG_DEBUG); - if (r < 0) - return r; - c->d_zstd = sym_ZSTD_createDCtx(); if (!c->d_zstd) return -ENOMEM; @@ -1755,10 +1743,6 @@ static int decompressor_new(Decompressor **ret, Compression type) { #if HAVE_ZLIB case COMPRESSION_GZIP: - r = dlopen_zlib(LOG_DEBUG); - if (r < 0) - return r; - r = sym_inflateInit2_(&c->gzip, /* windowBits= */ ZLIB_WBITS_GZIP, ZLIB_VERSION, (int) sizeof(c->gzip)); if (r != Z_OK) return -EIO; @@ -1767,10 +1751,6 @@ static int decompressor_new(Decompressor **ret, Compression type) { #if HAVE_BZIP2 case COMPRESSION_BZIP2: - r = dlopen_bzip2(LOG_DEBUG); - if (r < 0) - return r; - r = sym_BZ2_bzDecompressInit(&c->bzip2, /* verbosity= */ 0, /* small= */ 0); if (r != BZ_OK) return -EIO; @@ -1800,6 +1780,10 @@ int decompress_stream( assert(fdf >= 0); assert(fdt >= 0); + r = dlopen_compress(type, LOG_DEBUG); + if (r < 0) + return r; + r = decompressor_new(&c, type); if (r < 0) return r; From 87693c7073fb41c56fe974bc248e6bba67d60d29 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Aug 2026 06:33:01 +0900 Subject: [PATCH 3/7] compress: make decompressor_new() accept NONE --- src/basic/compress.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/basic/compress.c b/src/basic/compress.c index 7bacd65609..e557e59ca5 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -1715,6 +1715,8 @@ static int decompressor_new(Decompressor **ret, Compression type) { c->type = _COMPRESSION_INVALID; switch (type) { + case COMPRESSION_NONE: + break; #if HAVE_XZ case COMPRESSION_XZ: @@ -1758,7 +1760,7 @@ static int decompressor_new(Decompressor **ret, Compression type) { #endif default: - return -EOPNOTSUPP; + assert_not_reached(); } c->type = type; @@ -1780,6 +1782,9 @@ int decompress_stream( assert(fdf >= 0); assert(fdt >= 0); + if (type == COMPRESSION_NONE) + return -EOPNOTSUPP; + r = dlopen_compress(type, LOG_DEBUG); if (r < 0) return r; From 1e7a69ff8706ed5c14bdee89bf2edd5341ec9b9d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Aug 2026 06:46:59 +0900 Subject: [PATCH 4/7] compress: use decompressor_new() at several more places --- src/basic/compress.c | 122 ++++++------------------------------------- src/basic/compress.h | 4 +- 2 files changed, 19 insertions(+), 107 deletions(-) diff --git a/src/basic/compress.c b/src/basic/compress.c index e557e59ca5..3b52ad7ad6 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -1912,14 +1912,12 @@ Compression compressor_type(const Compressor *c) { return c ? c->type : _COMPRESSION_INVALID; } -int decompressor_detect(Decompressor **ret, const void *data, size_t size) { -#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD || HAVE_ZLIB || HAVE_BZIP2 +int decompressor_detect(Decompressor **decompressor, const void *data, size_t size) { int r; -#endif - assert(ret); + assert(decompressor); - if (*ret) + if (*decompressor) return 1; if (size < COMPRESSION_MAGIC_BYTES_MAX) @@ -1928,113 +1926,27 @@ int decompressor_detect(Decompressor **ret, const void *data, size_t size) { assert(data); Compression type = compression_detect_from_magic(data); - - _cleanup_(compressor_freep) Decompressor *c = new0(Decompressor, 1); - if (!c) - return -ENOMEM; - - switch (type) { - -#if HAVE_XZ - case COMPRESSION_XZ: { - r = dlopen_xz(LOG_DEBUG); - if (r < 0) - return r; - - lzma_ret xzr = sym_lzma_stream_decoder(&c->xz, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED); - if (xzr != LZMA_OK) - return -EIO; - - break; - } -#endif - -#if HAVE_LZ4 - case COMPRESSION_LZ4: { - r = dlopen_lz4(LOG_DEBUG); - if (r < 0) - return r; - - size_t rc = sym_LZ4F_createDecompressionContext(&c->d_lz4, LZ4F_VERSION); - if (sym_LZ4F_isError(rc)) - return -ENOMEM; - - break; - } -#endif - -#if HAVE_ZSTD - case COMPRESSION_ZSTD: { - r = dlopen_zstd(LOG_DEBUG); - if (r < 0) - return r; - - c->d_zstd = sym_ZSTD_createDCtx(); - if (!c->d_zstd) - return -ENOMEM; - - break; - } -#endif - -#if HAVE_ZLIB - case COMPRESSION_GZIP: { - r = dlopen_zlib(LOG_DEBUG); - if (r < 0) - return r; - - r = sym_inflateInit2_(&c->gzip, /* windowBits= */ ZLIB_WBITS_GZIP, ZLIB_VERSION, (int) sizeof(c->gzip)); - if (r != Z_OK) - return -EIO; - - break; - } -#endif - -#if HAVE_BZIP2 - case COMPRESSION_BZIP2: { - r = dlopen_bzip2(LOG_DEBUG); - if (r < 0) - return r; - - r = sym_BZ2_bzDecompressInit(&c->bzip2, /* verbosity= */ 0, /* small= */ 0); - if (r != BZ_OK) - return -EIO; - - break; - } -#endif - - default: - if (type != _COMPRESSION_INVALID) - return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "Detected %s compression, but support is not compiled in.", - compression_to_string(type)); + if (type == _COMPRESSION_INVALID) type = COMPRESSION_NONE; - break; - } - c->type = type; - c->encoding = false; + log_debug("Detected compression type: %s", compression_to_string(type)); + + r = dlopen_compress(type, LOG_DEBUG); + if (r < 0) + return r; + + r = decompressor_new(decompressor, type); + if (r < 0) + return r; - log_debug("Detected compression type: %s", compression_to_string(c->type)); - *ret = TAKE_PTR(c); return 1; } -int decompressor_force_off(Decompressor **ret) { - assert(ret); +int decompressor_force_off(Decompressor **decompressor) { + assert(decompressor); - *ret = compressor_free(*ret); - - Decompressor *c = new0(Decompressor, 1); - if (!c) - return -ENOMEM; - - c->type = COMPRESSION_NONE; - c->encoding = false; - *ret = c; - return 0; + *decompressor = compressor_free(*decompressor); + return decompressor_new(decompressor, COMPRESSION_NONE); } int decompressor_push(Decompressor *c, const void *data, size_t size, DecompressorCallback callback, void *userdata) { diff --git a/src/basic/compress.h b/src/basic/compress.h index e20713a8b7..8b183c193d 100644 --- a/src/basic/compress.h +++ b/src/basic/compress.h @@ -52,8 +52,8 @@ int compressor_new(Compressor **ret, Compression type); int compressor_start(Compressor *c, const void *data, size_t size, void **buffer, size_t *buffer_size, size_t *buffer_allocated); int compressor_finish(Compressor *c, void **buffer, size_t *buffer_size, size_t *buffer_allocated); -int decompressor_detect(Decompressor **ret, const void *data, size_t size); -int decompressor_force_off(Decompressor **ret); +int decompressor_detect(Decompressor **decompressor, const void *data, size_t size); +int decompressor_force_off(Decompressor **decompressor); int decompressor_push(Decompressor *c, const void *data, size_t size, DecompressorCallback callback, void *userdata); Compression compressor_type(const Compressor *c); From 7ea7833b86d243a2ff5cb8b63cb469be25579bbe Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Aug 2026 06:48:44 +0900 Subject: [PATCH 5/7] compress: shorten code a bit --- src/basic/compress.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/basic/compress.c b/src/basic/compress.c index 3b52ad7ad6..c4e9a4b5ef 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -1950,9 +1950,6 @@ int decompressor_force_off(Decompressor **decompressor) { } int decompressor_push(Decompressor *c, const void *data, size_t size, DecompressorCallback callback, void *userdata) { -#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD || HAVE_ZLIB || HAVE_BZIP2 - _cleanup_free_ uint8_t *buffer = NULL; -#endif int r; assert(c); @@ -1967,6 +1964,7 @@ int decompressor_push(Decompressor *c, const void *data, size_t size, Decompress assert(data); #if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD || HAVE_ZLIB || HAVE_BZIP2 + _cleanup_free_ uint8_t *buffer = NULL; if (c->type != COMPRESSION_NONE) { buffer = new(uint8_t, COMPRESS_PIPE_BUFFER_SIZE); if (!buffer) From 20923e8ddc284a69ada1f05a1ad861576e0a5be2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Aug 2026 06:55:41 +0900 Subject: [PATCH 6/7] compress: use dlopen_compress() at one more place --- src/basic/compress.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/basic/compress.c b/src/basic/compress.c index c4e9a4b5ef..8cbf22005d 100644 --- a/src/basic/compress.c +++ b/src/basic/compress.c @@ -2128,12 +2128,14 @@ int decompressor_push(Decompressor *c, const void *data, size_t size, Decompress } int compressor_new(Compressor **ret, Compression type) { -#if HAVE_XZ || HAVE_LZ4 || HAVE_ZSTD || HAVE_ZLIB || HAVE_BZIP2 int r; -#endif assert(ret); + r = dlopen_compress(type, LOG_DEBUG); + if (r < 0) + return r; + _cleanup_(compressor_freep) Compressor *c = new0(Compressor, 1); if (!c) return -ENOMEM; @@ -2148,10 +2150,6 @@ int compressor_new(Compressor **ret, Compression type) { #if HAVE_XZ case COMPRESSION_XZ: { - r = dlopen_xz(LOG_DEBUG); - if (r < 0) - return r; - lzma_ret xzr = sym_lzma_easy_encoder(&c->xz, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64); if (xzr != LZMA_OK) return -EIO; @@ -2163,10 +2161,6 @@ int compressor_new(Compressor **ret, Compression type) { #if HAVE_LZ4 case COMPRESSION_LZ4: { - r = dlopen_lz4(LOG_DEBUG); - if (r < 0) - return r; - size_t rc = sym_LZ4F_createCompressionContext(&c->c_lz4, LZ4F_VERSION); if (sym_LZ4F_isError(rc)) return -ENOMEM; @@ -2189,10 +2183,6 @@ int compressor_new(Compressor **ret, Compression type) { #if HAVE_ZSTD case COMPRESSION_ZSTD: - r = dlopen_zstd(LOG_DEBUG); - if (r < 0) - return r; - c->c_zstd = sym_ZSTD_createCCtx(); if (!c->c_zstd) return -ENOMEM; @@ -2212,10 +2202,6 @@ int compressor_new(Compressor **ret, Compression type) { #if HAVE_ZLIB case COMPRESSION_GZIP: - r = dlopen_zlib(LOG_DEBUG); - if (r < 0) - return r; - r = sym_deflateInit2_(&c->gzip, Z_DEFAULT_COMPRESSION, /* method= */ Z_DEFLATED, @@ -2232,10 +2218,6 @@ int compressor_new(Compressor **ret, Compression type) { #if HAVE_BZIP2 case COMPRESSION_BZIP2: - r = dlopen_bzip2(LOG_DEBUG); - if (r < 0) - return r; - r = sym_BZ2_bzCompressInit(&c->bzip2, /* blockSize100k= */ 9, /* verbosity= */ 0, /* workFactor= */ 0); if (r != BZ_OK) return -EIO; From e0360405299f0aea0be6f727aeaca2729d76ba64 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 23 Aug 2026 04:51:30 +0900 Subject: [PATCH 7/7] test-compress: extend buffer size Otherwise, random input cases are not tested: ``` /* test_compress_decompress_blob */ /* testing xz text blob compression/decompression */ Loaded shared library 'liblzma.so.5' via dlopen(). /* testing xz random blob compression/decompression */ compression failed: No buffer space available /* testing lz4 text blob compression/decompression */ Loaded shared library 'liblz4.so.1' via dlopen(). /* testing lz4 random blob compression/decompression */ compression failed: No buffer space available /* testing zstd text blob compression/decompression */ Loaded shared library 'libzstd.so.1' via dlopen(). /* testing zstd random blob compression/decompression */ compression failed: No buffer space available /* testing gzip text blob compression/decompression */ Loaded shared library 'libz.so.1' via dlopen(). /* testing gzip random blob compression/decompression */ compression failed: No buffer space available /* testing bzip2 text blob compression/decompression */ Loaded shared library 'libbz2.so.1' via dlopen(). /* testing bzip2 random blob compression/decompression */ compression failed: No buffer space available ``` --- src/test/test-compress.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/src/test/test-compress.c b/src/test/test-compress.c index 6e181c5b67..bfffcc4804 100644 --- a/src/test/test-compress.c +++ b/src/test/test-compress.c @@ -44,25 +44,18 @@ TEST(compress_decompress_blob) { for (size_t t = 0; t < 2; t++) { const char *input = t == 0 ? text : data; size_t input_len = t == 0 ? sizeof(text) : sizeof(data); - bool may_fail = t == 1; - char compressed[512]; + char compressed[sizeof(data) * 4]; size_t csize; _cleanup_free_ char *decompressed = NULL; - int r; log_info("/* testing %s %s blob compression/decompression */", label, input); - r = compress_blob(c, input, input_len, compressed, sizeof(compressed), &csize, -1); - if (r == -ENOBUFS) { - log_info_errno(r, "compression failed: %m"); - ASSERT_TRUE(may_fail); - } else { - ASSERT_OK(r); - ASSERT_OK_ZERO(decompress_blob(c, compressed, csize, (void **) &decompressed, &csize, 0)); - ASSERT_NOT_NULL(decompressed); - ASSERT_EQ(memcmp(decompressed, input, input_len), 0); - } + ASSERT_OK(compress_blob(c, input, input_len, compressed, sizeof(compressed), &csize, -1)); + + ASSERT_OK_ZERO(decompress_blob(c, compressed, csize, (void **) &decompressed, &csize, 0)); + ASSERT_NOT_NULL(decompressed); + ASSERT_EQ(memcmp(decompressed, input, input_len), 0); ASSERT_FAIL(decompress_blob(c, "garbage", 7, (void **) &decompressed, &csize, 0)); }