From 929ca4c92ab7b341117994e083ac09ede2d0b70c Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 9 Jul 2024 01:08:56 -0500 Subject: [PATCH] libkmod: Move xz-related functions to separate file Move xz-related function to a separate file so it's easier to isolate the dependency on each decompression library. Declare struct kmod_file in a shared libkmod-internal-file.h that will be included only by sources implementing kmod_file decompression routines. Reviewed-by: Emil Velikov Link: https://github.com/kmod-project/kmod/pull/58 Signed-off-by: Lucas De Marchi --- Makefile.am | 5 ++ configure.ac | 1 + libkmod/libkmod-file-xz.c | 116 ++++++++++++++++++++++++++++++ libkmod/libkmod-file.c | 121 +------------------------------- libkmod/libkmod-internal-file.h | 27 +++++++ 5 files changed, 151 insertions(+), 119 deletions(-) create mode 100644 libkmod/libkmod-file-xz.c create mode 100644 libkmod/libkmod-internal-file.h diff --git a/Makefile.am b/Makefile.am index 3dc769f0..fbd205de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -63,6 +63,7 @@ lib_LTLIBRARIES = libkmod/libkmod.la libkmod_libkmod_la_SOURCES = \ libkmod/libkmod.h \ + libkmod/libkmod-internal-file.h \ libkmod/libkmod-internal.h \ libkmod/libkmod.c \ libkmod/libkmod-builtin.c \ @@ -75,6 +76,10 @@ libkmod_libkmod_la_SOURCES = \ libkmod/libkmod-elf.c \ libkmod/libkmod-signature.c +if ENABLE_XZ +libkmod_libkmod_la_SOURCES += libkmod/libkmod-file-xz.c +endif + EXTRA_DIST += libkmod/libkmod.sym EXTRA_DIST += libkmod/README \ libkmod/COPYING testsuite/COPYING tools/COPYING COPYING diff --git a/configure.ac b/configure.ac index 7ff699d9..5768e5e7 100644 --- a/configure.ac +++ b/configure.ac @@ -137,6 +137,7 @@ AS_IF([test "x$with_xz" != "xno"], [ AC_MSG_NOTICE([Xz support not requested]) ]) CC_FEATURE_APPEND([with_features], [with_xz], [XZ]) +AM_CONDITIONAL([ENABLE_XZ], [test "x$with_xz" != "xno"]) AC_ARG_WITH([zlib], AS_HELP_STRING([--with-zlib], [handle gzipped modules @<:@default=disabled@:>@]), diff --git a/libkmod/libkmod-file-xz.c b/libkmod/libkmod-file-xz.c new file mode 100644 index 00000000..7285c4b0 --- /dev/null +++ b/libkmod/libkmod-file-xz.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright © 2024 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "libkmod.h" +#include "libkmod-internal.h" +#include "libkmod-internal-file.h" + +static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret) +{ + switch (ret) { + case LZMA_MEM_ERROR: + ERR(file->ctx, "xz: %s\n", strerror(ENOMEM)); + break; + case LZMA_FORMAT_ERROR: + ERR(file->ctx, "xz: File format not recognized\n"); + break; + case LZMA_OPTIONS_ERROR: + ERR(file->ctx, "xz: Unsupported compression options\n"); + break; + case LZMA_DATA_ERROR: + ERR(file->ctx, "xz: File is corrupt\n"); + break; + case LZMA_BUF_ERROR: + ERR(file->ctx, "xz: Unexpected end of input\n"); + break; + default: + ERR(file->ctx, "xz: Internal error (bug)\n"); + break; + } +} + +static int xz_uncompress(lzma_stream *strm, struct kmod_file *file) +{ + uint8_t in_buf[BUFSIZ], out_buf[BUFSIZ]; + lzma_action action = LZMA_RUN; + lzma_ret ret; + void *p = NULL; + size_t total = 0; + + strm->avail_in = 0; + strm->next_out = out_buf; + strm->avail_out = sizeof(out_buf); + + while (true) { + if (strm->avail_in == 0) { + ssize_t rdret = read(file->fd, in_buf, sizeof(in_buf)); + if (rdret < 0) { + ret = -errno; + goto out; + } + strm->next_in = in_buf; + strm->avail_in = rdret; + if (rdret == 0) + action = LZMA_FINISH; + } + ret = lzma_code(strm, action); + if (strm->avail_out == 0 || ret != LZMA_OK) { + size_t write_size = BUFSIZ - strm->avail_out; + 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; + strm->next_out = out_buf; + strm->avail_out = BUFSIZ; + } + if (ret == LZMA_STREAM_END) + break; + if (ret != LZMA_OK) { + xz_uncompress_belch(file, ret); + ret = -EINVAL; + goto out; + } + } + file->memory = p; + file->size = total; + return 0; + out: + free(p); + return ret; +} + +int kmod_file_load_xz(struct kmod_file *file) +{ + lzma_stream strm = LZMA_STREAM_INIT; + lzma_ret lzret; + int ret; + + lzret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED); + if (lzret == LZMA_MEM_ERROR) { + ERR(file->ctx, "xz: %s\n", strerror(ENOMEM)); + return -ENOMEM; + } else if (lzret != LZMA_OK) { + ERR(file->ctx, "xz: Internal error (bug)\n"); + return -EINVAL; + } + ret = xz_uncompress(&strm, file); + lzma_end(&strm); + return ret; +} diff --git a/libkmod/libkmod-file.c b/libkmod/libkmod-file.c index 52490fbd..29e89ca2 100644 --- a/libkmod/libkmod-file.c +++ b/libkmod/libkmod-file.c @@ -29,9 +29,6 @@ #ifdef ENABLE_ZSTD #include #endif -#ifdef ENABLE_XZ -#include -#endif #ifdef ENABLE_ZLIB #include #endif @@ -40,16 +37,7 @@ #include "libkmod.h" #include "libkmod-internal.h" - -struct kmod_file { - int fd; - enum kmod_file_compression_type compression; - off_t size; - void *memory; - int (*load)(struct kmod_file *file); - const struct kmod_ctx *ctx; - struct kmod_elf *elf; -}; +#include "libkmod-internal-file.h" #ifdef ENABLE_ZSTD static int zstd_read_block(struct kmod_file *file, size_t block_size, @@ -186,111 +174,6 @@ static int load_zstd(struct kmod_file *file) #endif static const char magic_zstd[] = {0x28, 0xB5, 0x2F, 0xFD}; - -#ifdef ENABLE_XZ -static void xz_uncompress_belch(struct kmod_file *file, lzma_ret ret) -{ - switch (ret) { - case LZMA_MEM_ERROR: - ERR(file->ctx, "xz: %s\n", strerror(ENOMEM)); - break; - case LZMA_FORMAT_ERROR: - ERR(file->ctx, "xz: File format not recognized\n"); - break; - case LZMA_OPTIONS_ERROR: - ERR(file->ctx, "xz: Unsupported compression options\n"); - break; - case LZMA_DATA_ERROR: - ERR(file->ctx, "xz: File is corrupt\n"); - break; - case LZMA_BUF_ERROR: - ERR(file->ctx, "xz: Unexpected end of input\n"); - break; - default: - ERR(file->ctx, "xz: Internal error (bug)\n"); - break; - } -} - -static int xz_uncompress(lzma_stream *strm, struct kmod_file *file) -{ - uint8_t in_buf[BUFSIZ], out_buf[BUFSIZ]; - lzma_action action = LZMA_RUN; - lzma_ret ret; - void *p = NULL; - size_t total = 0; - - strm->avail_in = 0; - strm->next_out = out_buf; - strm->avail_out = sizeof(out_buf); - - while (true) { - if (strm->avail_in == 0) { - ssize_t rdret = read(file->fd, in_buf, sizeof(in_buf)); - if (rdret < 0) { - ret = -errno; - goto out; - } - strm->next_in = in_buf; - strm->avail_in = rdret; - if (rdret == 0) - action = LZMA_FINISH; - } - ret = lzma_code(strm, action); - if (strm->avail_out == 0 || ret != LZMA_OK) { - size_t write_size = BUFSIZ - strm->avail_out; - 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; - strm->next_out = out_buf; - strm->avail_out = BUFSIZ; - } - if (ret == LZMA_STREAM_END) - break; - if (ret != LZMA_OK) { - xz_uncompress_belch(file, ret); - ret = -EINVAL; - goto out; - } - } - file->memory = p; - file->size = total; - return 0; - out: - free(p); - return ret; -} - -static int load_xz(struct kmod_file *file) -{ - lzma_stream strm = LZMA_STREAM_INIT; - lzma_ret lzret; - int ret; - - lzret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_CONCATENATED); - if (lzret == LZMA_MEM_ERROR) { - ERR(file->ctx, "xz: %s\n", strerror(ENOMEM)); - return -ENOMEM; - } else if (lzret != LZMA_OK) { - ERR(file->ctx, "xz: Internal error (bug)\n"); - return -EINVAL; - } - ret = xz_uncompress(&strm, file); - lzma_end(&strm); - return ret; -} -#else -static int load_xz(struct kmod_file *file) -{ - return -ENOSYS; -} -#endif - static const char magic_xz[] = {0xfd, '7', 'z', 'X', 'Z', 0}; #ifdef ENABLE_ZLIB @@ -387,7 +270,7 @@ static const struct comp_type { int (*load)(struct kmod_file *file); } comp_types[] = { {sizeof(magic_zstd), KMOD_FILE_COMPRESSION_ZSTD, magic_zstd, load_zstd}, - {sizeof(magic_xz), KMOD_FILE_COMPRESSION_XZ, magic_xz, load_xz}, + {sizeof(magic_xz), KMOD_FILE_COMPRESSION_XZ, magic_xz, kmod_file_load_xz}, {sizeof(magic_zlib), KMOD_FILE_COMPRESSION_ZLIB, magic_zlib, load_zlib}, {0, KMOD_FILE_COMPRESSION_NONE, NULL, load_reg} }; diff --git a/libkmod/libkmod-internal-file.h b/libkmod/libkmod-internal-file.h new file mode 100644 index 00000000..1d74aed5 --- /dev/null +++ b/libkmod/libkmod-internal-file.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright © 2024 Intel Corporation + */ + +#include + +#include + +struct kmod_ctx; +struct kmod_elf; + +struct kmod_file { + int fd; + enum kmod_file_compression_type compression; + off_t size; + void *memory; + int (*load)(struct kmod_file *file); + const struct kmod_ctx *ctx; + struct kmod_elf *elf; +}; + +#ifdef ENABLE_XZ +int kmod_file_load_xz(struct kmod_file *file); +#else +static inline int kmod_file_load_xz(struct kmod_file *file) { return -ENOSYS; } +#endif -- 2.47.3