-e 's,@exec_prefix\@,$(exec_prefix),g' \
-e 's,@libdir\@,$(libdir),g' \
-e 's,@includedir\@,$(includedir),g' \
+ -e 's,@liblzma_CFLAGS\@,${liblzma_CFLAGS},g' \
+ -e 's,@liblzma_LIBS\@,${liblzma_LIBS},g' \
-e 's,@zlib_CFLAGS\@,${zlib_CFLAGS},g' \
-e 's,@zlib_LIBS\@,${zlib_LIBS},g' \
< $< > $@ || rm $@
-version-info $(LIBKMOD_CURRENT):$(LIBKMOD_REVISION):$(LIBKMOD_AGE) \
-Wl,--version-script=$(top_srcdir)/libkmod/libkmod.sym
libkmod_libkmod_la_DEPENDENCIES = ${top_srcdir}/libkmod/libkmod.sym
-libkmod_libkmod_la_LIBADD = ${zlib_LIBS}
+libkmod_libkmod_la_LIBADD = ${liblzma_LIBS} ${zlib_LIBS}
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libkmod/libkmod.pc
AC_DEFINE(ENABLE_LOGGING, [1], [System logging.])
])
+AC_ARG_WITH([xz],
+ AS_HELP_STRING([--with-xz], [handle Xz-compressed modules @<:@default=disabled@:>@]),
+ [], [with_xz=no])
+AS_IF([test "x$with_xz" != "xno"], [
+ PKG_CHECK_MODULES([liblzma], [liblzma >= 4.99])
+ AC_DEFINE([ENABLE_XZ], [1], [Enable Xz for modules.])
+], [
+ AC_MSG_NOTICE([Xz support not requested])
+])
+
AC_ARG_WITH([zlib],
AS_HELP_STRING([--with-zlib], [handle gzipped modules @<:@default=disabled@:>@]),
[], [with_zlib=no])
tools: ${enable_tools}
logging: ${enable_logging}
- zlib: ${with_zlib}
+ compression: xz=${with_xz} zlib=${with_zlib}
debug: ${enable_debug}
])
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "libkmod.h"
#include "libkmod-private.h"
+#ifdef ENABLE_XZ
+#include <lzma.h>
+#endif
#ifdef ENABLE_ZLIB
#include <zlib.h>
#endif
struct kmod_file {
+#ifdef ENABLE_XZ
+ bool xz_used;
+#endif
#ifdef ENABLE_ZLIB
gzFile gzf;
#endif
void *memory;
};
+#ifdef ENABLE_XZ
+static bool xz_detect(struct kmod_file *file)
+{
+ ssize_t ret;
+ char buf[6];
+
+ ret = read(file->fd, buf, sizeof(buf));
+ if (ret < 0 || lseek(file->fd, 0, SEEK_SET))
+ return -errno;
+ return ret == sizeof(buf) &&
+ memcmp(buf, "\xFD""7zXZ\x00", sizeof(buf)) == 0;
+}
+
+static void xz_uncompress_belch(lzma_ret ret)
+{
+ switch (ret) {
+ case LZMA_MEM_ERROR:
+ fprintf(stderr, "xz: %s\n", strerror(ENOMEM));
+ break;
+ case LZMA_FORMAT_ERROR:
+ fprintf(stderr, "xz: File format not recognized\n");
+ break;
+ case LZMA_OPTIONS_ERROR:
+ fprintf(stderr, "xz: Unsupported compression options\n");
+ break;
+ case LZMA_DATA_ERROR:
+ fprintf(stderr, "xz: File is corrupt\n");
+ break;
+ case LZMA_BUF_ERROR:
+ fprintf(stderr, "xz: Unexpected end of input\n");
+ break;
+ default:
+ fprintf(stderr, "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(ret);
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ file->memory = p;
+ file->size = total;
+ return 0;
+ out:
+ free(p);
+ close(file->fd);
+ return ret;
+}
+
+static int xz_file_open(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) {
+ fprintf(stderr, "xz: %s\n", strerror(ENOMEM));
+ close(file->fd);
+ return -ENOMEM;
+ } else if (lzret != LZMA_OK) {
+ fprintf(stderr, "xz: Internal error (bug)\n");
+ close(file->fd);
+ return -EINVAL;
+ }
+ ret = xz_uncompress(&strm, file);
+ lzma_end(&strm);
+ return ret;
+}
+#endif
+
#ifdef ENABLE_ZLIB
#define READ_STEP (4 * 1024 * 1024)
goto error;
}
+#ifdef ENABLE_XZ
+ if (xz_detect(file))
+ err = xz_file_open(file);
+ else
+#endif
#ifdef ENABLE_ZLIB
if (check_zlib(file))
err = zlib_file_open(file);
void kmod_file_unref(struct kmod_file *file)
{
+#ifdef ENABLE_XZ
+ if (file->xz_used) {
+ free(file->memory);
+ close(file->fd);
+ } else
+#endif
#ifdef ENABLE_ZLIB
if (file->gzf != NULL) {
free(file->memory);