diff options
Diffstat (limited to 'lib/comp')
-rw-r--r-- | lib/comp/compressor.c | 56 | ||||
-rw-r--r-- | lib/comp/internal.h | 6 | ||||
-rw-r--r-- | lib/comp/lz4.c | 106 |
3 files changed, 168 insertions, 0 deletions
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; +} |