From c0cdbb1f15ddef2962dbae1228f25db9555e9d7b Mon Sep 17 00:00:00 2001 From: tomaThomas Date: Wed, 6 Sep 2023 15:24:58 +0200 Subject: [PATCH] Add --long write option for zstd (#1962) Fixes #1795 --- libarchive/archive_write_add_filter_zstd.c | 36 ++++++++++++++++++++++ libarchive/archive_write_set_options.3 | 4 +++ libarchive/test/test_write_filter_zstd.c | 6 ++++ 3 files changed, 46 insertions(+) diff --git a/libarchive/archive_write_add_filter_zstd.c b/libarchive/archive_write_add_filter_zstd.c index 584cfb668..c78e840d8 100644 --- a/libarchive/archive_write_add_filter_zstd.c +++ b/libarchive/archive_write_add_filter_zstd.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); struct private_data { int compression_level; int threads; + int long_distance; #if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR enum { running, @@ -81,8 +82,11 @@ struct private_data { #define CLEVEL_STD_MAX 19 /* without using --ultra */ #define CLEVEL_MAX 22 +#define LONG_STD 27 + #define MINVER_NEGCLEVEL 10304 #define MINVER_MINCLEVEL 10306 +#define MINVER_LONG 10302 static int archive_compressor_zstd_options(struct archive_write_filter *, const char *, const char *); @@ -125,6 +129,7 @@ archive_write_add_filter_zstd(struct archive *_a) f->name = "zstd"; data->compression_level = CLEVEL_DEFAULT; data->threads = 0; + data->long_distance = 0; #if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR data->frame_per_file = 0; data->min_frame_size = 0; @@ -252,6 +257,29 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key, return (ARCHIVE_OK); #endif } + else if (strcmp(key, "long") == 0) { + intmax_t long_distance; + if (string_to_number(value, &long_distance) != ARCHIVE_OK) { + return (ARCHIVE_WARN); + } +#if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR && ZSTD_VERSION_NUMBER >= MINVER_LONG + ZSTD_bounds bounds = ZSTD_cParam_getBounds(ZSTD_c_windowLog); + if (ZSTD_isError(bounds.error)) { + int max_distance = ((int)(sizeof(size_t) == 4 ? 30 : 31)); + if (((int)long_distance) < 10 || (int)long_distance > max_distance) + return (ARCHIVE_WARN); + } else { + if ((int)long_distance < bounds.lowerBound || (int)long_distance > bounds.upperBound) + return (ARCHIVE_WARN); + } +#else + int max_distance = ((int)(sizeof(size_t) == 4 ? 30 : 31)); + if (((int)long_distance) < 10 || (int)long_distance > max_distance) + return (ARCHIVE_WARN); +#endif + data->long_distance = (int)long_distance; + return (ARCHIVE_OK); + } /* Note: The "warn" return is just to inform the options * supervisor that we didn't handle it. It will generate @@ -301,6 +329,10 @@ archive_compressor_zstd_open(struct archive_write_filter *f) ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_nbWorkers, data->threads); +#if ZSTD_VERSION_NUMBER >= MINVER_LONG + ZSTD_CCtx_setParameter(data->cstream, ZSTD_c_windowLog, data->long_distance); +#endif + return (ARCHIVE_OK); } @@ -433,6 +465,10 @@ archive_compressor_zstd_open(struct archive_write_filter *f) archive_string_sprintf(&as, " --threads=%d", data->threads); } + if (data->long_distance != 0) { + archive_string_sprintf(&as, " --long=%d", data->long_distance); + } + f->write = archive_compressor_zstd_write; r = __archive_write_program_open(f, data->pdata, as.s); archive_string_free(&as); diff --git a/libarchive/archive_write_set_options.3 b/libarchive/archive_write_set_options.3 index 86079bfbf..f4b5081e2 100644 --- a/libarchive/archive_write_set_options.3 +++ b/libarchive/archive_write_set_options.3 @@ -257,6 +257,10 @@ If supported, the default value is read from The value is interpreted as a decimal integer specifying the compression level. Supported values depend on the library version, common values are from 1 to 22. +.It Cm long +Enables long distance matching. The value is interpreted as a +decimal integer specifying log2 window size in bytes. Values from +10 to 30 for 32 bit, or 31 for 64 bit, are supported. .It Cm threads The value is interpreted as a decimal integer specifying the number of threads for multi-threaded zstd compression. diff --git a/libarchive/test/test_write_filter_zstd.c b/libarchive/test/test_write_filter_zstd.c index aa77b4986..3cdbd812a 100644 --- a/libarchive/test/test_write_filter_zstd.c +++ b/libarchive/test/test_write_filter_zstd.c @@ -159,6 +159,12 @@ DEFINE_TEST(test_write_filter_zstd) archive_write_set_filter_option(a, NULL, "max-frame-size", "1024")); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_filter_option(a, NULL, "max-frame-size", "1048576")); +#endif +#if ZSTD_VERSION_NUMBER >= MINVER_LONG + assertEqualIntA(a, ARCHIVE_OK, + archive_write_set_filter_option(a, NULL, "long", "27")); + assertEqualIntA(a, ARCHIVE_FAILED, + archive_write_set_filter_option(a, NULL, "long", "-1")); /* negative */ #endif assertEqualIntA(a, ARCHIVE_OK, archive_write_open_memory(a, buff, buffsize, &used2)); for (i = 0; i < 100; i++) { -- 2.47.2