This is an automated email from the git hooks/post-receive script. guillem pushed a commit to branch main in repository dpkg.
View the commit online: https://git.dpkg.org/cgit/dpkg/dpkg.git/commit/?id=2c2f7066bd8c3209762762fa6905fa567b08ca5a commit 2c2f7066bd8c3209762762fa6905fa567b08ca5a (HEAD -> main) Author: Guillem Jover <[email protected]> AuthorDate: Mon Jan 9 02:32:42 2023 +0100 libdpkg: Add zstd support for .deb archives This adds support for .deb ZStandard compression and decompression. The main reason for this addition is due to Ubuntu having forked the .deb ecosystem when they added support for this unilaterally, so now there are many .deb in the wild using this compression format, which cannot be handled by the upstream dpkg-deb tool. Although at least now the ZStandard format is widely used on many projects, has been specified within the IETF as RFC8878, so backwards compatibility and format stability are no longer a concern, and it has good trade offs between size and speed. This has been implemented from scratch, based on the initial prototype code used during the early request evaluation. Using the new advanced API, with support for multi-threading, and using an I/O loop resembling the one used with liblzma, as the plan is to eventually switch all compressors to use a single I/O loop implementation. Closes: #892664 --- README | 1 + configure.ac | 2 + debian/control | 6 + debian/rules | 1 + lib/dpkg/Makefile.am | 1 + lib/dpkg/compress.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++++- lib/dpkg/compress.h | 1 + lib/dpkg/libdpkg.pc.in | 2 +- m4/dpkg-libs.m4 | 7 + man/deb.pod | 2 + man/dpkg-deb.pod | 12 +- src/Makefile.am | 1 + src/at/deb-format.at | 38 ++++++ src/deb/extract.c | 1 + src/deb/main.c | 3 +- 15 files changed, 411 insertions(+), 9 deletions(-) diff --git a/README b/README index eca08c25a..e791ef5a6 100644 --- a/README +++ b/README @@ -86,6 +86,7 @@ To enable optional functionality or programs, this software might be needed: libmd (used by libdpkg, required if libc is missing digest functions) libz (from zlib, used instead of gzip command-line tool) liblzma (from xz utils, used instead of xz command-line tool) + libzstd (from libzstd, used instead of zstd command-line tool) libbz2 (from bzip2, used instead of bzip2 command-line tool) libselinux curses compatible library (needed on --enable-dselect) diff --git a/configure.ac b/configure.ac index 0c15c8b90..9a2412920 100644 --- a/configure.ac +++ b/configure.ac @@ -97,6 +97,7 @@ DPKG_LIB_MD DPKG_LIB_Z DPKG_LIB_BZ2 DPKG_LIB_LZMA +DPKG_LIB_ZSTD DPKG_LIB_SELINUX AS_IF([test "x$build_dselect" = "xyes"], [ DPKG_LIB_CURSES @@ -287,6 +288,7 @@ Configuration: libmd . . . . . . . . . . . . : $have_libmd libz . . . . . . . . . . . . : $have_libz_impl liblzma . . . . . . . . . . . : $have_liblzma + libzstd . . . . . . . . . . . : $have_libzstd libbz2 . . . . . . . . . . . : $have_libbz2 libcurses . . . . . . . . . . : ${have_libcurses:-no} CONFIG diff --git a/debian/control b/debian/control index 57d418a3f..f7f5e1068 100644 --- a/debian/control +++ b/debian/control @@ -21,12 +21,16 @@ Build-Depends: libbz2-dev, # Version needed for multi-threaded decompressor support. liblzma-dev (>= 5.4.0), +# Version needed for the new streaming API. + libzstd-dev (>= 1.4.0), libselinux1-dev [linux-any], libncurses-dev (>= 6.1+20180210), # Needed for the functional test. bzip2 <!nocheck>, # Version needed for multi-threaded decompressor support. xz-utils (>= 5.4.0) <!nocheck>, +# Needed for the functional test. + zstd <!nocheck>, # Needed for the author release process. git <pkg.dpkg.author-release>, ca-certificates <pkg.dpkg.author-release>, @@ -86,6 +90,8 @@ Depends: zlib1g-dev, # Version needed for multi-threaded decompressor support. liblzma-dev (>= 5.4.0), +# Version needed for the new streaming API. + libzstd-dev (>= 1.4.0), libbz2-dev, Description: Debian package management static library This package provides the header files and static library necessary to diff --git a/debian/rules b/debian/rules index a37fd4de4..eec726690 100755 --- a/debian/rules +++ b/debian/rules @@ -52,6 +52,7 @@ override_dh_auto_configure: --with-devlibdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH) \ --with-libz \ --with-liblzma \ + --with-libzstd \ --with-libbz2 \ # EOL diff --git a/lib/dpkg/Makefile.am b/lib/dpkg/Makefile.am index 892a11278..97a8dbfa6 100644 --- a/lib/dpkg/Makefile.am +++ b/lib/dpkg/Makefile.am @@ -45,6 +45,7 @@ libdpkg_la_LIBADD += \ $(LIBINTL) \ $(Z_LIBS) \ $(LZMA_LIBS) \ + $(ZSTD_LIBS) \ $(BZ2_LIBS) \ # EOL endif diff --git a/lib/dpkg/compress.c b/lib/dpkg/compress.c index 760f93b34..e56f6c1a4 100644 --- a/lib/dpkg/compress.c +++ b/lib/dpkg/compress.c @@ -4,7 +4,7 @@ * * Copyright © 2000 Wichert Akkerman <[email protected]> * Copyright © 2004 Scott James Remnant <[email protected]> - * Copyright © 2006-2015 Guillem Jover <[email protected]> + * Copyright © 2006-2023 Guillem Jover <[email protected]> * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +35,13 @@ #ifdef WITH_LIBLZMA #include <lzma.h> #endif +#ifdef WITH_LIBZSTD +#include <zstd.h> +#define DPKG_ZSTD_MAX_LEVEL ZSTD_maxCLevel() +#else +#define DPKG_ZSTD_MAX_LEVEL 22 +#define ZSTD_CLEVEL_DEFAULT 3 +#endif #ifdef WITH_LIBBZ2 #include <bzlib.h> #endif @@ -50,6 +57,7 @@ #include <dpkg/compress.h> #if USE_LIBZ_IMPL == USE_LIBZ_IMPL_NONE || \ !defined(WITH_LIBLZMA) || \ + !defined(WITH_LIBZSTD) || \ !defined(WITH_LIBBZ2) #include <dpkg/subproc.h> @@ -100,7 +108,7 @@ command_decompress_init(struct command *cmd, const char *name, const char *desc) } #endif -#if defined(WITH_LIBLZMA) +#if defined(WITH_LIBLZMA) || defined(WITH_LIBZSTD) enum dpkg_stream_filter { DPKG_STREAM_COMPRESS = 1, DPKG_STREAM_DECOMPRESS = 2, @@ -961,6 +969,330 @@ static const struct compressor compressor_lzma = { .decompress = decompress_lzma, }; +/* + * ZStandard compressor. + */ + +#define ZSTD "zstd" + +#ifdef WITH_LIBZSTD +struct io_zstd_stream { + enum dpkg_stream_filter filter; + enum dpkg_stream_action action; + enum dpkg_stream_status status; + + union { + ZSTD_CCtx *c; + ZSTD_DCtx *d; + } ctx; + + const uint8_t *next_in; + size_t avail_in; + uint8_t *next_out; + size_t avail_out; +}; + +struct io_zstd { + const char *desc; + + struct compress_params *params; + + void (*init)(struct io_zstd *io, struct io_zstd_stream *s); + void (*code)(struct io_zstd *io, struct io_zstd_stream *s); + void (*done)(struct io_zstd *io, struct io_zstd_stream *s); +}; + +static void DPKG_ATTR_NORET +filter_zstd_error(struct io_zstd *io, size_t ret) +{ + ohshit(_("%s: zstd error: %s"), io->desc, ZSTD_getErrorName(ret)); +} + +static uint32_t +filter_zstd_get_cputhreads(struct compress_params *params) +{ + ZSTD_bounds workers; + long threads_max = 1; + + /* The shared library has not been built with multi-threading. */ + workers = ZSTD_cParam_getBounds(ZSTD_c_nbWorkers); + if (workers.upperBound == 0) + return 1; + +#ifdef _SC_NPROCESSORS_ONLN + threads_max = sysconf(_SC_NPROCESSORS_ONLN); + if (threads_max < 0) + return 1; +#endif + + if (params->threads_max >= 0) + return clamp(params->threads_max, 1, threads_max); + + return threads_max; +} + +static size_t +filter_zstd_get_buf_in_size(struct io_zstd_stream *s) +{ + if (s->filter == DPKG_STREAM_DECOMPRESS) + return ZSTD_DStreamInSize(); + else + return ZSTD_CStreamInSize(); +} + +static size_t +filter_zstd_get_buf_out_size(struct io_zstd_stream *s) +{ + if (s->filter == DPKG_STREAM_DECOMPRESS) + return ZSTD_DStreamOutSize(); + else + return ZSTD_CStreamOutSize(); +} + +static void +filter_unzstd_init(struct io_zstd *io, struct io_zstd_stream *s) +{ + s->filter = DPKG_STREAM_DECOMPRESS; + s->action = DPKG_STREAM_RUN; + s->status = DPKG_STREAM_OK; + + s->ctx.d = ZSTD_createDCtx(); + if (s->ctx.d == NULL) + ohshit(_("%s: cannot create zstd decompression context"), + io->desc); +} + +static void +filter_unzstd_code(struct io_zstd *io, struct io_zstd_stream *s) +{ + ZSTD_inBuffer buf_in = { s->next_in, s->avail_in, 0 }; + ZSTD_outBuffer buf_out = { s->next_out, s->avail_out, 0 }; + size_t ret; + + ret = ZSTD_decompressStream(s->ctx.d, &buf_out, &buf_in); + if (ZSTD_isError(ret)) + filter_zstd_error(io, ret); + + s->next_in += buf_in.pos; + s->avail_in -= buf_in.pos; + s->next_out += buf_out.pos; + s->avail_out -= buf_out.pos; + + if (ret == 0) + s->status = DPKG_STREAM_END; +} + +static void +filter_unzstd_done(struct io_zstd *io, struct io_zstd_stream *s) +{ + ZSTD_freeDCtx(s->ctx.d); +} + +static void +filter_zstd_init(struct io_zstd *io, struct io_zstd_stream *s) +{ + int clevel = io->params->level; + uint32_t nthreads; + size_t ret; + + s->filter = DPKG_STREAM_COMPRESS; + s->action = DPKG_STREAM_RUN; + s->status = DPKG_STREAM_OK; + + s->ctx.c = ZSTD_createCCtx(); + if (s->ctx.c == NULL) + ohshit(_("%s: cannot create zstd compression context"), + io->desc); + + ret = ZSTD_CCtx_setParameter(s->ctx.c, ZSTD_c_compressionLevel, clevel); + if (ZSTD_isError(ret)) + filter_zstd_error(io, ret); + ret = ZSTD_CCtx_setParameter(s->ctx.c, ZSTD_c_checksumFlag, 1); + if (ZSTD_isError(ret)) + filter_zstd_error(io, ret); + + nthreads = filter_zstd_get_cputhreads(io->params); + if (nthreads > 1) + ZSTD_CCtx_setParameter(s->ctx.c, ZSTD_c_nbWorkers, nthreads); +} + +static void +filter_zstd_code(struct io_zstd *io, struct io_zstd_stream *s) +{ + ZSTD_inBuffer buf_in = { s->next_in, s->avail_in, 0 }; + ZSTD_outBuffer buf_out = { s->next_out, s->avail_out, 0 }; + ZSTD_EndDirective action; + size_t ret; + + if (s->action == DPKG_STREAM_FINISH) + action = ZSTD_e_end; + else + action = ZSTD_e_continue; + + ret = ZSTD_compressStream2(s->ctx.c, &buf_out, &buf_in, action); + if (ZSTD_isError(ret)) + filter_zstd_error(io, ret); + + s->next_in += buf_in.pos; + s->avail_in -= buf_in.pos; + s->next_out += buf_out.pos; + s->avail_out -= buf_out.pos; + + if (s->action == DPKG_STREAM_FINISH && ret == 0) + s->status = DPKG_STREAM_END; +} + +static void +filter_zstd_done(struct io_zstd *io, struct io_zstd_stream *s) +{ + ZSTD_freeCCtx(s->ctx.c); +} + +static void +filter_zstd(struct io_zstd *io, int fd_in, int fd_out) +{ + ssize_t buf_in_size; + ssize_t buf_out_size; + uint8_t *buf_in; + uint8_t *buf_out; + struct io_zstd_stream s = { + .action = DPKG_STREAM_INIT, + }; + + io->init(io, &s); + + buf_in_size = filter_zstd_get_buf_in_size(&s); + buf_in = m_malloc(buf_in_size); + buf_out_size = filter_zstd_get_buf_out_size(&s); + buf_out = m_malloc(buf_out_size); + + s.next_out = buf_out; + s.avail_out = buf_out_size; + + do { + ssize_t len; + + if (s.avail_in == 0 && s.action != DPKG_STREAM_FINISH) { + len = fd_read(fd_in, buf_in, buf_in_size); + if (len < 0) + ohshite(_("%s: zstd read error"), io->desc); + if (len < buf_in_size) + s.action = DPKG_STREAM_FINISH; + s.next_in = buf_in; + s.avail_in = len; + } + + io->code(io, &s); + + if (s.avail_out == 0 || s.status == DPKG_STREAM_END) { + len = fd_write(fd_out, buf_out, s.next_out - buf_out); + if (len < 0) + ohshite(_("%s: zstd write error"), io->desc); + s.next_out = buf_out; + s.avail_out = buf_out_size; + } + } while (s.status != DPKG_STREAM_END); + + io->done(io, &s); + + free(buf_in); + free(buf_out); + + if (close(fd_out)) + ohshite(_("%s: zstd close error"), io->desc); +} + +static void +decompress_zstd(struct compress_params *params, int fd_in, int fd_out, + const char *desc) +{ + struct io_zstd io; + + io.init = filter_unzstd_init; + io.code = filter_unzstd_code; + io.done = filter_unzstd_done; + io.desc = desc; + io.params = params; + + filter_zstd(&io, fd_in, fd_out); +} + +static void +compress_zstd(struct compress_params *params, int fd_in, int fd_out, + const char *desc) +{ + struct io_zstd io; + + io.init = filter_zstd_init; + io.code = filter_zstd_code; + io.done = filter_zstd_done; + io.desc = desc; + io.params = params; + + filter_zstd(&io, fd_in, fd_out); +} +#else +static const char *env_zstd[] = { + "ZSTD_CLEVEL", + "ZSTD_NBTHREADS", + NULL, +}; + +static void +decompress_zstd(struct compress_params *params, int fd_in, int fd_out, + const char *desc) +{ + struct command cmd; + char *threads_opt = NULL; + + command_decompress_init(&cmd, ZSTD, desc); + command_add_arg(&cmd, "-q"); + + if (params->threads_max > 0) { + threads_opt = str_fmt("-T%d", params->threads_max); + command_add_arg(&cmd, threads_opt); + } + + fd_fd_filter(&cmd, fd_in, fd_out, env_zstd); + + command_destroy(&cmd); + free(threads_opt); +} + +static void +compress_zstd(struct compress_params *params, int fd_in, int fd_out, + const char *desc) +{ + struct command cmd; + char *threads_opt = NULL; + + command_compress_init(&cmd, ZSTD, desc, params->level); + command_add_arg(&cmd, "-q"); + + if (params->level > 19) + command_add_arg(&cmd, "--ultra"); + + if (params->threads_max > 0) { + threads_opt = str_fmt("-T%d", params->threads_max); + command_add_arg(&cmd, threads_opt); + } + + fd_fd_filter(&cmd, fd_in, fd_out, env_zstd); + + command_destroy(&cmd); + free(threads_opt); +} +#endif + +static const struct compressor compressor_zstd = { + .name = "zstd", + .extension = ".zst", + .default_level = ZSTD_CLEVEL_DEFAULT, + .fixup_params = fixup_none_params, + .compress = compress_zstd, + .decompress = decompress_zstd, +}; + /* * Generic compressor filter. */ @@ -969,6 +1301,7 @@ static const struct compressor *compressor_array[] = { [COMPRESSOR_TYPE_NONE] = &compressor_none, [COMPRESSOR_TYPE_GZIP] = &compressor_gzip, [COMPRESSOR_TYPE_XZ] = &compressor_xz, + [COMPRESSOR_TYPE_ZSTD] = &compressor_zstd, [COMPRESSOR_TYPE_BZIP2] = &compressor_bzip2, [COMPRESSOR_TYPE_LZMA] = &compressor_lzma, }; @@ -1053,7 +1386,10 @@ compressor_check_params(struct compress_params *params, struct dpkg_error *err) { compressor_fixup_params(params); - if (params->level > 9) { + if ((params->type == COMPRESSOR_TYPE_ZSTD && + params->level > DPKG_ZSTD_MAX_LEVEL) || + (params->type != COMPRESSOR_TYPE_ZSTD && + params->level > 9)) { dpkg_put_error(err, _("invalid compression level %d"), params->level); return false; diff --git a/lib/dpkg/compress.h b/lib/dpkg/compress.h index f9b66ba0e..7458e174b 100644 --- a/lib/dpkg/compress.h +++ b/lib/dpkg/compress.h @@ -40,6 +40,7 @@ enum compressor_type { COMPRESSOR_TYPE_NONE, COMPRESSOR_TYPE_GZIP, COMPRESSOR_TYPE_XZ, + COMPRESSOR_TYPE_ZSTD, COMPRESSOR_TYPE_BZIP2, COMPRESSOR_TYPE_LZMA, }; diff --git a/lib/dpkg/libdpkg.pc.in b/lib/dpkg/libdpkg.pc.in index 4bf1b72be..1a9159498 100644 --- a/lib/dpkg/libdpkg.pc.in +++ b/lib/dpkg/libdpkg.pc.in @@ -7,5 +7,5 @@ Name: libdpkg Description: Debian package management system library Version: @VERSION@ Libs: -L${libdir} -ldpkg -Libs.private: @MD_LIBS@ @Z_LIBS@ @LZMA_LIBS@ @BZ2_LIBS@ +Libs.private: @MD_LIBS@ @Z_LIBS@ @LZMA_LIBS@ @ZSTD_LIBS@ @BZ2_LIBS@ Cflags: -I${includedir} diff --git a/m4/dpkg-libs.m4 b/m4/dpkg-libs.m4 index 2badcd74d..556446a54 100644 --- a/m4/dpkg-libs.m4 +++ b/m4/dpkg-libs.m4 @@ -108,6 +108,13 @@ AC_DEFUN([DPKG_LIB_LZMA], [ ]) ])# DPKG_LIB_LZMA +# DPKG_LIB_ZSTD +# ------------ +# Check for zstd library. +AC_DEFUN([DPKG_LIB_ZSTD], [ + DPKG_WITH_COMPRESS_LIB([zstd], [zstd.h], [ZSTD_compressStream2]) +])# DPKG_LIB_ZSTD + # DPKG_LIB_BZ2 # ------------ # Check for bz2 library. diff --git a/man/deb.pod b/man/deb.pod index 6e3964507..812b2bcfb 100644 --- a/man/deb.pod +++ b/man/deb.pod @@ -84,6 +84,7 @@ It is a tar archive containing the package control information, either not compressed (supported since dpkg 1.17.6), or compressed with gzip (with B<.gz> extension) or xz (with B<.xz> extension, supported since 1.17.6), +zstd (with B<.zst> extension, supported since dpkg 1.21.18), as a series of plain files, of which the file B<control> is mandatory and contains the core control information, the @@ -106,6 +107,7 @@ It contains the filesystem as a tar archive, either not compressed (supported since dpkg 1.10.24), or compressed with gzip (with B<.gz> extension), xz (with B<.xz> extension, supported since dpkg 1.15.6), +zstd (with B<.zst> extension, supported since dpkg 1.21.18), bzip2 (with B<.bz2> extension, supported since dpkg 1.10.24) or lzma (with B<.lzma> extension, supported since dpkg 1.13.25). diff --git a/man/dpkg-deb.pod b/man/dpkg-deb.pod index 42ac708c3..50076c1f0 100644 --- a/man/dpkg-deb.pod +++ b/man/dpkg-deb.pod @@ -254,8 +254,11 @@ The default for this field is “${Package}\t${Version}\n”. =item B<-z>I<compress-level> Specify which compression level to use on the compressor backend, when -building a package (default is 9 for gzip, 6 for xz). -The accepted values are 0-9 with: 0 being mapped to compressor none for gzip. +building a package (default is 9 for gzip, 6 for xz, 3 for zstd). +The accepted values are compressor specific. +For gzip, from 0-9 with 0 being mapped to compressor none. +For xz from 0-9. +For zstd from 0-22, with levels from 20 to 22 enabling its ultra mode. Before dpkg 1.16.2 level 0 was equivalent to compressor none for all compressors. @@ -270,6 +273,7 @@ gzip (since dpkg 1.17.0) and B<extreme> for xz. Specify which compression type to use when building a package. Allowed values are B<gzip>, B<xz> (since dpkg 1.15.6), +B<zstd> (since dpkg 1.21.18) and B<none> (default is B<xz>). =item B<--[no-]uniform-compression> @@ -278,8 +282,8 @@ Specify that the same compression parameters should be used for all archive members (i.e. B<control.tar> and B<data.tar>; since dpkg 1.17.6). Otherwise only the B<data.tar> member will use those parameters. The only supported -compression types allowed to be uniformly used are B<none>, B<gzip> -and B<xz>. +compression types allowed to be uniformly used are B<none>, B<gzip>, +B<xz> and B<zstd>. The B<--no-uniform-compression> option disables uniform compression (since dpkg 1.19.0). Uniform compression is the default (since dpkg 1.19.0). diff --git a/src/Makefile.am b/src/Makefile.am index 95cc94353..435816558 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -100,6 +100,7 @@ dpkg_deb_LDADD = \ $(LDADD) \ $(Z_LIBS) \ $(LZMA_LIBS) \ + $(ZSTD_LIBS) \ $(BZ2_LIBS) \ # EOL diff --git a/src/at/deb-format.at b/src/at/deb-format.at index b706b1228..b06beeda1 100644 --- a/src/at/deb-format.at +++ b/src/at/deb-format.at @@ -169,6 +169,7 @@ AT_KEYWORDS([dpkg-deb deb]) AT_SKIP_IF([! command -v xz >/dev/null]) AT_SKIP_IF([! command -v gzip >/dev/null]) +AT_SKIP_IF([! command -v zstd >/dev/null]) AT_SKIP_IF([! command -v bzip2 >/dev/null]) AT_SKIP_IF([! command -v lzma >/dev/null]) @@ -198,6 +199,8 @@ gzip -c control.tar >control.tar.gz gzip -c data.tar >data.tar.gz xz -c control.tar >control.tar.xz xz -c data.tar >data.tar.xz +zstd -c control.tar >control.tar.zst +zstd -c data.tar >data.tar.zst bzip2 -c data.tar >data.tar.bz2 lzma -c data.tar >data.tar.lzma touch _ignore @@ -441,6 +444,19 @@ drwxr-xr-x root/root 0 1970-01-01 00:00 ./ -rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ ]) +AT_CHECK([ +# Test control.tar.zst member +ar rc pkg-control-zst.deb debian-binary control.tar.zst data.tar.zst +ar t pkg-control-zst.deb +dpkg-deb -c pkg-control-zst.deb +], [], [debian-binary +control.tar.zst +data.tar.zst +drwxr-xr-x root/root 0 1970-01-01 00:00 ./ +-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old +-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ +]) + AT_CHECK([ # Test data.tar member ar rc pkg-data-none.deb debian-binary control.tar.gz data.tar @@ -480,6 +496,19 @@ drwxr-xr-x root/root 0 1970-01-01 00:00 ./ -rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ ]) +AT_CHECK([ +# Test data.tar.zst member +ar rc pkg-data-zst.deb debian-binary control.tar.gz data.tar.zst +ar t pkg-data-zst.deb +dpkg-deb -c pkg-data-zst.deb +], [], [debian-binary +control.tar.gz +data.tar.zst +drwxr-xr-x root/root 0 1970-01-01 00:00 ./ +-rw-r--r-- root/root 641345 1970-01-01 00:00 ./ChangeLog.old +-rw-r--r-- root/root 5 1970-01-01 00:00 ./file-templ +]) + AT_CHECK([ # Test data.tar.bz2 member ar rc pkg-data-bz2.deb debian-binary control.tar.gz data.tar.bz2 @@ -558,4 +587,13 @@ cmp ctrl-xz.tar control.tar cmp fsys-xz.tar data.tar ]) +AT_CHECK([ +# Test building and extracting zstd compressed archive +dpkg-deb --uniform-compression --root-owner-group -Zzstd -b pkg-templ pkg-comp-zstd.deb >/dev/null +dpkg-deb --ctrl-tarfile pkg-comp-zstd.deb >ctrl-zstd.tar +dpkg-deb --fsys-tarfile pkg-comp-zstd.deb >fsys-zstd.tar +cmp ctrl-zstd.tar control.tar +cmp fsys-zstd.tar data.tar +]) + AT_CLEANUP diff --git a/src/deb/extract.c b/src/deb/extract.c index 6466fa6f2..73612a454 100644 --- a/src/deb/extract.c +++ b/src/deb/extract.c @@ -185,6 +185,7 @@ extracthalf(const char *debar, const char *dir, decompress_params.type = compressor_find_by_extension(extension); if (decompress_params.type != COMPRESSOR_TYPE_NONE && decompress_params.type != COMPRESSOR_TYPE_GZIP && + decompress_params.type != COMPRESSOR_TYPE_ZSTD && decompress_params.type != COMPRESSOR_TYPE_XZ) ohshit(_("archive '%s' uses unknown compression for member '%.*s', " "giving up"), diff --git a/src/deb/main.c b/src/deb/main.c index 416eba30f..4a1673835 100644 --- a/src/deb/main.c +++ b/src/deb/main.c @@ -109,7 +109,7 @@ usage(const char *const *argv) " --[no-]uniform-compression Use the compression params on all members.\n" " -z# Set the compression level when building.\n" " -Z<type> Set the compression type used when building.\n" -" Allowed types: gzip, xz, none.\n" +" Allowed types: gzip, xz, zstd, none.\n" " -S<strategy> Set the compression strategy when building.\n" " Allowed values: none; extreme (xz);\n" " filtered, huffman, rle, fixed (gzip).\n" @@ -297,6 +297,7 @@ int main(int argc, const char *const *argv) { if (opt_uniform_compression && (compress_params.type != COMPRESSOR_TYPE_NONE && compress_params.type != COMPRESSOR_TYPE_GZIP && + compress_params.type != COMPRESSOR_TYPE_ZSTD && compress_params.type != COMPRESSOR_TYPE_XZ)) badusage(_("unsupported compression type '%s' with uniform compression"), compressor_get_name(compress_params.type)); -- Dpkg.Org's dpkg

