diff --git a/Makefile.am b/Makefile.am index 47505c1..155456f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -89,7 +89,7 @@ libkmod_libkmod_la_DEPENDENCIES = \ ${top_srcdir}/libkmod/libkmod.sym libkmod_libkmod_la_LIBADD = \ shared/libshared.la \ - ${liblzma_LIBS} ${zlib_LIBS} ${libcrypto_LIBS} + ${libzstd_LIBS} ${liblzma_LIBS} ${zlib_LIBS} ${libcrypto_LIBS} noinst_LTLIBRARIES += libkmod/libkmod-internal.la libkmod_libkmod_internal_la_SOURCES = $(libkmod_libkmod_la_SOURCES) diff --git a/configure.ac b/configure.ac index e885d79..a286159 100644 --- a/configure.ac +++ b/configure.ac @@ -83,6 +83,17 @@ AC_ARG_WITH([rootlibdir], [], [with_rootlibdir=$libdir]) AC_SUBST([rootlibdir], [$with_rootlibdir]) +AC_ARG_WITH([zstd], + AS_HELP_STRING([--with-zstd], [handle Zstd-compressed modules @<:@default=disabled@:>@]), + [], [with_zstd=no]) +AS_IF([test "x$with_zstd" != "xno"], [ + PKG_CHECK_MODULES([libzstd], [libzstd >= 1.4.4]) + AC_DEFINE([ENABLE_ZSTD], [1], [Enable Zstd for modules.]) +], [ + AC_MSG_NOTICE([Zstd support not requested]) +]) +CC_FEATURE_APPEND([with_features], [with_zstd], [ZSTD]) + AC_ARG_WITH([xz], AS_HELP_STRING([--with-xz], [handle Xz-compressed modules @<:@default=disabled@:>@]), [], [with_xz=no]) @@ -307,7 +318,7 @@ AC_MSG_RESULT([ tools: ${enable_tools} python bindings: ${enable_python} logging: ${enable_logging} - compression: xz=${with_xz} zlib=${with_zlib} + compression: zstd=${with_zstd} xz=${with_xz} zlib=${with_zlib} debug: ${enable_debug} coverage: ${enable_coverage} doc: ${enable_gtk_doc} diff --git a/libkmod/libkmod-file.c b/libkmod/libkmod-file.c index 5eeba6a..2575b01 100644 --- a/libkmod/libkmod-file.c +++ b/libkmod/libkmod-file.c @@ -32,7 +32,9 @@ #ifdef ENABLE_ZLIB #include #endif - +#ifdef ENABLE_ZSTD +#include +#endif #include #include "libkmod.h" @@ -45,6 +47,9 @@ struct file_ops { }; struct kmod_file { +#ifdef ENABLE_ZSTD + bool zstd_used; +#endif #ifdef ENABLE_XZ bool xz_used; #endif @@ -60,6 +65,79 @@ struct kmod_file { struct kmod_elf *elf; }; +#ifdef ENABLE_ZSTD +static int zstd_uncompress(ZSTD_DStream *strm, struct kmod_file *file) { + uint8_t in_buf[BUFSIZ], out_buf[BUFSIZ]; + ZSTD_outBuffer output = { out_buf, sizeof(out_buf), 0 }; + ZSTD_inBuffer input = { in_buf, 0, 0 }; + void *p = NULL; + int ret = 0; + size_t total = 0; + + while(true) { + size_t sz; + if (input.pos == input.size) { + ssize_t rdret = read(file->fd, in_buf, sizeof(in_buf)); + if (rdret < 0) { + ret = -errno; + goto out; + } + input.size = rdret; + input.pos = 0; + } + if (input.size == 0) { + break; + } + sz = ZSTD_decompressStream(strm, &output, &input); + if (ZSTD_isError(sz)) { + ret = -1; + goto out; + } + if (output.pos == output.size || sz == 0) { + size_t write_size = output.pos; + char *tmp = realloc(p, total + write_size); + if (tmp == NULL) { + ret = -errno; + goto out; + } + memcpy(tmp + total, out_buf, write_size); + total += write_size; + p = tmp; + if (output.pos == output.size) { + output.pos = 0; + } + } + } + file->zstd_used = true; + file->memory = p; + file->size = total; + return 0; +out: + free(p); + return ret; +} + +static int load_zstd(struct kmod_file *file) +{ + ZSTD_DStream* strm = ZSTD_createDStream(); + int ret; + ZSTD_initDStream(strm); + + ret = zstd_uncompress(strm, file); + ZSTD_freeDStream(strm); + return ret; +} + +static void unload_zstd(struct kmod_file *file) +{ + if (!file->zstd_used) + return; + free(file->memory); +} + +static const char magic_zstd[] = {0x28, 0xb5, 0x2f, 0xfd}; +#endif + #ifdef ENABLE_XZ static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret) { @@ -238,6 +316,9 @@ static const struct comp_type { const char *magic_bytes; const struct file_ops ops; } comp_types[] = { +#ifdef ENABLE_ZSTD + {sizeof(magic_zstd), magic_zstd, {load_zstd, unload_zstd}}, +#endif #ifdef ENABLE_XZ {sizeof(magic_xz), magic_xz, {load_xz, unload_xz}}, #endif diff --git a/shared/util.c b/shared/util.c index fd2028d..b487b5f 100644 --- a/shared/util.c +++ b/shared/util.c @@ -45,6 +45,9 @@ static const struct kmod_ext { #endif #ifdef ENABLE_XZ {".ko.xz", sizeof(".ko.xz") - 1}, +#endif +#ifdef ENABLE_ZSTD + {".ko.zst", sizeof(".ko.zst") - 1}, #endif { } }; diff --git a/testsuite/test-util.c b/testsuite/test-util.c index 5e25e58..621446b 100644 --- a/testsuite/test-util.c +++ b/testsuite/test-util.c @@ -156,6 +156,9 @@ static int test_path_ends_with_kmod_ext(const struct test *t) #endif #ifdef ENABLE_XZ { "/bla.ko.xz", true }, +#endif +#ifdef ENABLE_ZSTD + { "/bla.ko.zst", true }, #endif { "/bla.ko.x", false }, { "/bla.ko.", false },