From bc2bdb3c4f5cb969635f320beaa9e7bcf42450b2 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 19 May 2019 21:46:34 +0200 Subject: Add ZSTD compressor implementation Signed-off-by: David Oberhollenzer --- README | 1 - configure.ac | 17 +++++++++ lib/Makemodule.am | 7 ++++ lib/comp/compressor.c | 3 ++ lib/comp/internal.h | 2 ++ lib/comp/zstd.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ mkfs/Makemodule.am | 4 +++ unpack/Makemodule.am | 4 +++ 8 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 lib/comp/zstd.c diff --git a/README b/README index 4e0a1be..af7dd08 100644 --- a/README +++ b/README @@ -92,5 +92,4 @@ At the moment, the following things are still missing: - hard links - NFS export tables - compressor options - - zstd and *maybe* lzma1 compressors - support for extracting SquashFS < 4.0 diff --git a/configure.ac b/configure.ac index 5b98b7b..243b9ae 100644 --- a/configure.ac +++ b/configure.ac @@ -81,6 +81,16 @@ AC_ARG_WITH([lz4], esac], [AM_CONDITIONAL([WITH_LZ4], [true])]) +AC_ARG_WITH([zstd], + [AS_HELP_STRING([--without-zstd], + [Build without zstd compression support])], + [case "${withval}" in + yes) AM_CONDITIONAL([WITH_ZSTD], [true]) ;; + no) AM_CONDITIONAL([WITH_ZSTD], [false]) ;; + *) AC_MSG_ERROR([bad value ${withval} for --without-zstd]) ;; + esac], + [AM_CONDITIONAL([WITH_ZSTD], [true])]) + AC_ARG_WITH([selinux], [AS_HELP_STRING([--without-selinux], [Build without SELinux label file support])], @@ -97,12 +107,14 @@ need_zlib="no" need_xz="no" need_lzo="no" need_lz4="no" +need_zstd="no" need_selinux="no" AM_COND_IF([WITH_GZIP], [need_zlib="yes"]) AM_COND_IF([WITH_XZ], [need_xz="yes"]) AM_COND_IF([WITH_LZO], [need_lzo="yes"]) AM_COND_IF([WITH_LZ4], [need_lz4="yes"]) +AM_COND_IF([WITH_ZSTD], [need_zstd="yes"]) AM_COND_IF([WITH_SELINUX], [need_selinux="yes"]) if test "x$need_zlib" = "xyes"; then @@ -129,6 +141,11 @@ if test "x$need_lz4" = "xyes"; then [AC_MSG_ERROR([cannot lz4 library])]) fi +if test "x$need_zstd" = "xyes"; then + PKG_CHECK_MODULES(ZSTD, [libzstd], [], + [AC_MSG_ERROR([cannot zstd library])]) +fi + if test "x$need_selinux" = "xyes"; then PKG_CHECK_MODULES(LIBSELINUX, [libselinux], [], [AC_MSG_ERROR([cannot find libselinux])]) diff --git a/lib/Makemodule.am b/lib/Makemodule.am index 737b474..ee02d44 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -52,6 +52,13 @@ libcompress_a_CFLAGS += $(LZ4_CFLAGS) libcompress_a_CPPFLAGS += -DWITH_LZ4 endif +if WITH_ZSTD +libcompress_a_SOURCES += lib/comp/zstd.c + +libcompress_a_CFLAGS += $(ZSTD_CFLAGS) +libcompress_a_CPPFLAGS += -DWITH_ZSTD +endif + if WITH_SELINUX libfstree_a_SOURCES += lib/fstree/selinux.c diff --git a/lib/comp/compressor.c b/lib/comp/compressor.c index 3b473a3..369cbea 100644 --- a/lib/comp/compressor.c +++ b/lib/comp/compressor.c @@ -20,6 +20,9 @@ static compressor_fun_t compressors[SQFS_COMP_MAX + 1] = { #ifdef WITH_LZ4 [SQFS_COMP_LZ4] = create_lz4_compressor, #endif +#ifdef WITH_ZSTD + [SQFS_COMP_ZSTD] = create_zstd_compressor, +#endif }; int generic_write_options(int fd, const void *data, size_t size) diff --git a/lib/comp/internal.h b/lib/comp/internal.h index 863f82b..8f880f4 100644 --- a/lib/comp/internal.h +++ b/lib/comp/internal.h @@ -16,4 +16,6 @@ compressor_t *create_lzo_compressor(bool compress, size_t block_size); compressor_t *create_lz4_compressor(bool compress, size_t block_size); +compressor_t *create_zstd_compressor(bool compress, size_t block_size); + #endif /* INTERNAL_H */ diff --git a/lib/comp/zstd.c b/lib/comp/zstd.c new file mode 100644 index 0000000..6c90505 --- /dev/null +++ b/lib/comp/zstd.c @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +#include +#include +#include +#include + +#include + +#include "internal.h" + +#define ZSTD_DEFAULT_COMPRESSION_LEVEL 15 + +typedef struct { + compressor_t base; + ZSTD_CCtx *zctx; +} zstd_compressor_t; + +static int zstd_write_options(compressor_t *base, int fd) +{ + (void)base; (void)fd; + return 0; +} + +static int zstd_read_options(compressor_t *base, int fd) +{ + (void)base; (void)fd; + fputs("zstd extra options are not yet implemented\n", stderr); + return -1; +} + +static ssize_t zstd_comp_block(compressor_t *base, const uint8_t *in, + size_t size, uint8_t *out, size_t outsize) +{ + zstd_compressor_t *zstd = (zstd_compressor_t *)base; + size_t ret; + + ret = ZSTD_compressCCtx(zstd->zctx, out, outsize, in, size, + ZSTD_DEFAULT_COMPRESSION_LEVEL); + + if (ZSTD_isError(ret)) { + fputs("internal error in ZSTD compressor\n", stderr); + return -1; + } + + return ret < size ? ret : 0; +} + +static ssize_t zstd_uncomp_block(compressor_t *base, const uint8_t *in, + size_t size, uint8_t *out, size_t outsize) +{ + size_t ret; + (void)base; + + ret = ZSTD_decompress(out, outsize, in, size); + + if (ZSTD_isError(ret)) { + fputs("error uncompressing ZSTD compressed data", stderr); + return -1; + } + + return ret; +} + +static void zstd_destroy(compressor_t *base) +{ + zstd_compressor_t *zstd = (zstd_compressor_t *)base; + + ZSTD_freeCCtx(zstd->zctx); + free(zstd); +} + +compressor_t *create_zstd_compressor(bool compress, size_t block_size) +{ + zstd_compressor_t *zstd = calloc(1, sizeof(*zstd)); + compressor_t *base = (compressor_t *)zstd; + (void)block_size; + + if (zstd == NULL) { + perror("creating zstd compressor"); + return NULL; + } + + zstd->zctx = ZSTD_createCCtx(); + if (zstd->zctx == NULL) { + fputs("error creating zstd compression context\n", stderr); + free(zstd); + return NULL; + } + + base->destroy = zstd_destroy; + base->do_block = compress ? zstd_comp_block : zstd_uncomp_block; + base->write_options = zstd_write_options; + base->read_options = zstd_read_options; + return base; +} diff --git a/mkfs/Makemodule.am b/mkfs/Makemodule.am index 1dedc33..31340d1 100644 --- a/mkfs/Makemodule.am +++ b/mkfs/Makemodule.am @@ -19,6 +19,10 @@ if WITH_LZ4 gensquashfs_LDADD += $(LZ4_LIBS) endif +if WITH_ZSTD +gensquashfs_LDADD += $(ZSTD_LIBS) +endif + if WITH_SELINUX gensquashfs_CPPFLAGS += -DWITH_SELINUX gensquashfs_LDADD += $(LIBSELINUX_LIBS) diff --git a/unpack/Makemodule.am b/unpack/Makemodule.am index c68a005..6829681 100644 --- a/unpack/Makemodule.am +++ b/unpack/Makemodule.am @@ -20,4 +20,8 @@ if WITH_LZ4 rdsquashfs_LDADD += $(LZ4_LIBS) endif +if WITH_LZ4 +rdsquashfs_LDADD += $(ZSTD_LIBS) +endif + bin_PROGRAMS += rdsquashfs -- cgit v1.2.3