You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
4.6 KiB
188 lines
4.6 KiB
4 years ago
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 8eadb99..a471c55 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -90,7 +90,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 4a65d6b..30aaa1d 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 <zlib.h>
|
||
|
#endif
|
||
|
-
|
||
|
+#ifdef ENABLE_ZSTD
|
||
|
+#include <zstd.h>
|
||
|
+#endif
|
||
|
#include <shared/util.h>
|
||
|
|
||
|
#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 },
|