aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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
4 files changed, 175 insertions, 0 deletions
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;
+}