summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README2
-rw-r--r--configure.ac17
-rw-r--r--lib/Makemodule.am7
-rw-r--r--lib/comp/compressor.c56
-rw-r--r--lib/comp/internal.h6
-rw-r--r--lib/comp/lz4.c106
-rw-r--r--mkfs/Makemodule.am4
-rw-r--r--unpack/Makemodule.am4
8 files changed, 201 insertions, 1 deletions
diff --git a/README b/README
index a953acf..c81fe46 100644
--- a/README
+++ b/README
@@ -83,5 +83,5 @@ At the moment, the following things are still missing:
- hard links
- NFS export tables
- compressor options
- - compressors other than XZ and GZIP (i.e. lz4, zstd, *maybe* lzma1?)
+ - zstd and *maybe* lzma1 compressors
- support for extracting SquashFS < 4.0
diff --git a/configure.ac b/configure.ac
index 422a113..b138c6f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,15 +71,27 @@ AC_ARG_WITH([lzo],
esac],
[AM_CONDITIONAL([WITH_LZO], [true])])
+AC_ARG_WITH([lz4],
+ [AS_HELP_STRING([--without-lz4],
+ [Build without lz4 compression support])],
+ [case "${withval}" in
+ yes) AM_CONDITIONAL([WITH_LZ4], [true]) ;;
+ no) AM_CONDITIONAL([WITH_LZ4], [false]) ;;
+ *) AC_MSG_ERROR([bad value ${withval} for --without-lz4]) ;;
+ esac],
+ [AM_CONDITIONAL([WITH_LZ4], [true])])
+
##### search for dependencies #####
need_zlib="no"
need_xz="no"
need_lzo="no"
+need_lz4="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"])
if test "x$need_zlib" = "xyes"; then
PKG_CHECK_MODULES(ZLIB, [zlib], [], [AC_MSG_ERROR([cannot find zlib])])
@@ -100,6 +112,11 @@ if test "x$need_lzo" = "xyes"; then
)
fi
+if test "x$need_lz4" = "xyes"; then
+ PKG_CHECK_MODULES(LZ4, [liblz4], [],
+ [AC_MSG_ERROR([cannot lz4 library])])
+fi
+
##### generate output #####
AC_CONFIG_HEADERS([config.h])
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index aacec34..17004bc 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -42,4 +42,11 @@ libcompress_a_CFLAGS += $(LZO_CFLAGS)
libcompress_a_CPPFLAGS += -DWITH_LZO
endif
+if WITH_LZ4
+libcompress_a_SOURCES += lib/comp/lz4.c
+
+libcompress_a_CFLAGS += $(LZ4_CFLAGS)
+libcompress_a_CPPFLAGS += -DWITH_LZ4
+endif
+
noinst_LIBRARIES += libfstree.a libcompress.a libutil.a libsquashfs.a
diff --git a/lib/comp/compressor.c b/lib/comp/compressor.c
index 42ebd8b..3b473a3 100644
--- a/lib/comp/compressor.c
+++ b/lib/comp/compressor.c
@@ -1,7 +1,9 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
#include <string.h>
+#include <stdio.h>
#include "internal.h"
+#include "util.h"
typedef compressor_t *(*compressor_fun_t)(bool compress, size_t block_size);
@@ -15,8 +17,62 @@ static compressor_fun_t compressors[SQFS_COMP_MAX + 1] = {
#ifdef WITH_LZO
[SQFS_COMP_LZO] = create_lzo_compressor,
#endif
+#ifdef WITH_LZ4
+ [SQFS_COMP_LZ4] = create_lz4_compressor,
+#endif
};
+int generic_write_options(int fd, const void *data, size_t size)
+{
+ uint8_t buffer[size + 2];
+ ssize_t ret;
+
+ *((uint16_t *)buffer) = htole16(0x8000 | size);
+ memcpy(buffer + 2, data, size);
+
+ ret = write_retry(fd, buffer, sizeof(buffer));
+
+ if (ret < 0) {
+ perror("writing compressor options");
+ return -1;
+ }
+
+ if ((size_t)ret < sizeof(buffer)) {
+ fputs("writing compressor options: truncated write\n", stderr);
+ return -1;
+ }
+
+ return ret;
+}
+
+int generic_read_options(int fd, void *data, size_t size)
+{
+ uint8_t buffer[size + 2];
+ ssize_t ret;
+
+ ret = read_retry(fd, buffer, sizeof(buffer));
+
+ if (ret < 0) {
+ perror("reading compressor options");
+ return -1;
+ }
+
+ if ((size_t)ret < sizeof(buffer)) {
+ fputs("reading compressor options: unexpected end of file\n",
+ stderr);
+ return -1;
+ }
+
+ if (le16toh(*((uint16_t *)buffer)) != (0x8000 | size)) {
+ fputs("reading compressor options: invalid meta data header\n",
+ stderr);
+ return -1;
+ }
+
+ memcpy(data, buffer + 2, size);
+ return 0;
+}
+
bool compressor_exists(E_SQFS_COMPRESSOR id)
{
if (id < SQFS_COMP_MIN || id > SQFS_COMP_MAX)
diff --git a/lib/comp/internal.h b/lib/comp/internal.h
index 3b24af0..863f82b 100644
--- a/lib/comp/internal.h
+++ b/lib/comp/internal.h
@@ -4,10 +4,16 @@
#include "compress.h"
+int generic_write_options(int fd, const void *data, size_t size);
+
+int generic_read_options(int fd, void *data, size_t size);
+
compressor_t *create_xz_compressor(bool compress, size_t block_size);
compressor_t *create_gzip_compressor(bool compress, size_t block_size);
compressor_t *create_lzo_compressor(bool compress, size_t block_size);
+compressor_t *create_lz4_compressor(bool compress, size_t block_size);
+
#endif /* INTERNAL_H */
diff --git a/lib/comp/lz4.c b/lib/comp/lz4.c
new file mode 100644
index 0000000..f9c753d
--- /dev/null
+++ b/lib/comp/lz4.c
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <lz4.h>
+#include <lz4hc.h>
+
+#include "internal.h"
+
+typedef struct {
+ compressor_t base;
+} lz4_compressor_t;
+
+typedef struct {
+ uint32_t version;
+ uint32_t flags;
+} lz4_options;
+
+#define LZ4LEGACY 1
+
+static int lz4_write_options(compressor_t *base, int fd)
+{
+ lz4_options opt = {
+ .version = htole32(LZ4LEGACY),
+ .flags = htole32(0),
+ };
+ (void)base;
+
+ return generic_write_options(fd, &opt, sizeof(opt));
+}
+
+static int lz4_read_options(compressor_t *base, int fd)
+{
+ lz4_options opt;
+ (void)base;
+
+ if (generic_read_options(fd, &opt, sizeof(opt)))
+ return -1;
+
+ opt.version = le32toh(opt.version);
+ opt.flags = le32toh(opt.flags);
+
+ if (opt.version != LZ4LEGACY) {
+ fprintf(stderr, "unsupported lz4 version '%d'\n", opt.version);
+ return -1;
+ }
+
+ return 0;
+}
+
+static ssize_t lz4_comp_block(compressor_t *base, const uint8_t *in,
+ size_t size, uint8_t *out, size_t outsize)
+{
+ int ret;
+ (void)base;
+
+ ret = LZ4_compress_default((void *)in, (void *)out, size, outsize);
+
+ if (ret < 0) {
+ fputs("internal error in lz4 compressor\n", stderr);
+ return -1;
+ }
+
+ return ret;
+}
+
+static ssize_t lz4_uncomp_block(compressor_t *base, const uint8_t *in,
+ size_t size, uint8_t *out, size_t outsize)
+{
+ int ret;
+ (void)base;
+
+ ret = LZ4_decompress_safe((void *)in, (void *)out, size, outsize);
+
+ if (ret < 0) {
+ fputs("internal error in lz4 decompressor\n", stderr);
+ return -1;
+ }
+
+ return ret;
+}
+
+static void lz4_destroy(compressor_t *base)
+{
+ free(base);
+}
+
+compressor_t *create_lz4_compressor(bool compress, size_t block_size)
+{
+ lz4_compressor_t *lz4 = calloc(1, sizeof(*lz4));
+ compressor_t *base = (compressor_t *)lz4;
+ (void)block_size;
+
+ if (lz4 == NULL) {
+ perror("creating lz4 compressor");
+ return NULL;
+ }
+
+ base->destroy = lz4_destroy;
+ base->do_block = compress ? lz4_comp_block : lz4_uncomp_block;
+ base->write_options = lz4_write_options;
+ base->read_options = lz4_read_options;
+ return base;
+}
diff --git a/mkfs/Makemodule.am b/mkfs/Makemodule.am
index 35e937c..dc105a0 100644
--- a/mkfs/Makemodule.am
+++ b/mkfs/Makemodule.am
@@ -14,4 +14,8 @@ if WITH_LZO
gensquashfs_LDADD += $(LZO_LIBS)
endif
+if WITH_LZ4
+gensquashfs_LDADD += $(LZ4_LIBS)
+endif
+
bin_PROGRAMS += gensquashfs
diff --git a/unpack/Makemodule.am b/unpack/Makemodule.am
index c3e61aa..c68a005 100644
--- a/unpack/Makemodule.am
+++ b/unpack/Makemodule.am
@@ -16,4 +16,8 @@ if WITH_LZO
rdsquashfs_LDADD += $(LZO_LIBS)
endif
+if WITH_LZ4
+rdsquashfs_LDADD += $(LZ4_LIBS)
+endif
+
bin_PROGRAMS += rdsquashfs