]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add --long write option for zstd (#1962)
authortomaThomas <thomas.moeller@mailbox.org>
Wed, 6 Sep 2023 13:24:58 +0000 (15:24 +0200)
committerGitHub <noreply@github.com>
Wed, 6 Sep 2023 13:24:58 +0000 (06:24 -0700)
Fixes #1795

libarchive/archive_write_add_filter_zstd.c
libarchive/archive_write_set_options.3
libarchive/test/test_write_filter_zstd.c

index 584cfb668f05b0135e7bf196f042b65a4f781f42..c78e840d89d35fab0ea4f6d4733c69614e5b87c8 100644 (file)
@@ -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);
index 86079bfbf2973cd5a1bc9296b850001910f58508..f4b5081e298e1cf7accd34c4fecf483138f2d5a9 100644 (file)
@@ -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.
index aa77b49860c0c9c84195060cc1d5503c579c16c6..3cdbd812a99ba482fa63e984dffd9d4960bf2dd1 100644 (file)
@@ -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++) {