diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makemodule.am | 1 | ||||
-rw-r--r-- | lib/sqfs/comp/compressor.c | 100 | ||||
-rw-r--r-- | lib/sqfs/comp/gzip.c | 210 | ||||
-rw-r--r-- | lib/sqfs/comp/internal.h | 25 | ||||
-rw-r--r-- | lib/sqfs/comp/lz4.c | 42 | ||||
-rw-r--r-- | lib/sqfs/comp/lzo.c | 176 | ||||
-rw-r--r-- | lib/sqfs/comp/xz.c | 216 | ||||
-rw-r--r-- | lib/sqfs/comp/zstd.c | 64 | ||||
-rw-r--r-- | lib/sqfshelper/comp_opt.c | 380 | ||||
-rw-r--r-- | lib/sqfshelper/compress.c | 33 | ||||
-rw-r--r-- | lib/sqfshelper/sqfs_reader.c | 9 |
11 files changed, 648 insertions, 608 deletions
diff --git a/lib/Makemodule.am b/lib/Makemodule.am index bf2e965..3681344 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -29,6 +29,7 @@ libsqfshelper_a_SOURCES += lib/sqfshelper/write_inode.c libsqfshelper_a_SOURCES += lib/sqfshelper/write_export_table.c libsqfshelper_a_SOURCES += lib/sqfshelper/xattr_reader.c libsqfshelper_a_SOURCES += lib/sqfshelper/print_version.c +libsqfshelper_a_SOURCES += lib/sqfshelper/compress.c lib/sqfshelper/comp_opt.c libsqfshelper_a_SOURCES += include/data_reader.h lib/sqfshelper/data_reader.c libsqfshelper_a_SOURCES += include/data_writer.h lib/sqfshelper/data_writer.c libsqfshelper_a_SOURCES += include/xattr_reader.h lib/sqfshelper/write_xattr.c diff --git a/lib/sqfs/comp/compressor.c b/lib/sqfs/comp/compressor.c index e59d948..d436100 100644 --- a/lib/sqfs/comp/compressor.c +++ b/lib/sqfs/comp/compressor.c @@ -13,10 +13,7 @@ #include "internal.h" #include "util.h" -typedef compressor_t *(*compressor_fun_t)(bool compress, size_t block_size, - char *options); - -typedef void (*compressor_help_fun_t)(void); +typedef compressor_t *(*compressor_fun_t)(const compressor_config_t *cfg); static compressor_fun_t compressors[SQFS_COMP_MAX + 1] = { #ifdef WITH_GZIP @@ -36,24 +33,6 @@ static compressor_fun_t compressors[SQFS_COMP_MAX + 1] = { #endif }; -static const compressor_help_fun_t helpfuns[SQFS_COMP_MAX + 1] = { -#ifdef WITH_GZIP - [SQFS_COMP_GZIP] = compressor_gzip_print_help, -#endif -#ifdef WITH_XZ - [SQFS_COMP_XZ] = compressor_xz_print_help, -#endif -#ifdef WITH_LZO - [SQFS_COMP_LZO] = compressor_lzo_print_help, -#endif -#ifdef WITH_LZ4 - [SQFS_COMP_LZ4] = compressor_lz4_print_help, -#endif -#ifdef WITH_ZSTD - [SQFS_COMP_ZSTD] = compressor_zstd_print_help, -#endif -}; - static const char *names[] = { [SQFS_COMP_GZIP] = "gzip", [SQFS_COMP_LZMA] = "lzma", @@ -105,41 +84,15 @@ bool compressor_exists(E_SQFS_COMPRESSOR id) return (compressors[id] != NULL); } -compressor_t *compressor_create(E_SQFS_COMPRESSOR id, bool compress, - size_t block_size, char *options) +compressor_t *compressor_create(const compressor_config_t *cfg) { - if (id < SQFS_COMP_MIN || id > SQFS_COMP_MAX) + if (cfg == NULL || cfg->id < SQFS_COMP_MIN || cfg->id > SQFS_COMP_MAX) return NULL; - if (compressors[id] == NULL) + if (compressors[cfg->id] == NULL) return NULL; - return compressors[id](compress, block_size, options); -} - -void compressor_print_help(E_SQFS_COMPRESSOR id) -{ - if (id < SQFS_COMP_MIN || id > SQFS_COMP_MAX) - return; - - if (compressors[id] == NULL) - return; - - helpfuns[id](); -} - -void compressor_print_available(void) -{ - size_t i; - - fputs("Available compressors:\n", stdout); - - for (i = 0; i < sizeof(names) / sizeof(names[0]); ++i) { - if (compressor_exists(i)) - printf("\t%s\n", names[i]); - } - - printf("\nDefault compressor: %s\n", names[compressor_get_default()]); + return compressors[cfg->id](cfg); } const char *compressor_name_from_id(E_SQFS_COMPRESSOR id) @@ -164,20 +117,33 @@ int compressor_id_from_name(const char *name, E_SQFS_COMPRESSOR *out) return -1; } -E_SQFS_COMPRESSOR compressor_get_default(void) +int compressor_config_init(compressor_config_t *cfg, E_SQFS_COMPRESSOR id, + size_t block_size, uint16_t flags) { -#if defined(WITH_XZ) - return SQFS_COMP_XZ; -#elif defined(WITH_ZSTD) - return SQFS_COMP_ZSTD; -#elif defined(WITH_GZIP) - return SQFS_COMP_GZIP; -#elif defined(WITH_LZO) - return SQFS_COMP_LZO; -#elif defined(WITH_LZ4) - return SQFS_COMP_LZ4; -#else - fputs("No compressor implementation available!\n", stderr); - exit(EXIT_FAILURE); -#endif + memset(cfg, 0, sizeof(*cfg)); + + cfg->id = id; + cfg->flags = flags; + cfg->block_size = block_size; + + switch (id) { + case SQFS_COMP_GZIP: + cfg->opt.gzip.level = SQFS_GZIP_DEFAULT_LEVEL; + cfg->opt.gzip.window_size = SQFS_GZIP_DEFAULT_WINDOW; + break; + case SQFS_COMP_LZO: + cfg->opt.lzo.algorithm = SQFS_LZO_DEFAULT_ALG; + cfg->opt.lzo.level = SQFS_LZO_DEFAULT_LEVEL; + break; + case SQFS_COMP_ZSTD: + cfg->opt.zstd.level = SQFS_ZSTD_DEFAULT_LEVEL; + break; + case SQFS_COMP_XZ: + cfg->opt.xz.dict_size = block_size; + break; + default: + break; + } + + return 0; } diff --git a/lib/sqfs/comp/gzip.c b/lib/sqfs/comp/gzip.c index 1fdc051..bbe1e4f 100644 --- a/lib/sqfs/comp/gzip.c +++ b/lib/sqfs/comp/gzip.c @@ -15,32 +15,6 @@ #include "internal.h" -#define GZIP_DEFAULT_LEVEL 9 -#define GZIP_DEFAULT_WINDOW 15 -#define GZIP_NUM_STRATEGIES (sizeof(strategies) / sizeof(strategies[0])) - -typedef enum { - GZIP_STRATEGY_DEFAULT = 0x01, - GZIP_STRATEGY_FILTERED = 0x02, - GZIP_STRATEGY_HUFFMAN = 0x04, - GZIP_STARTEGY_RLE = 0x08, - GZIP_STRATEGY_FIXED = 0x10, - - GZIP_ALL_STRATEGIES = 0x1F, -} GZIP_STRATEGIES; - -static const struct { - const char *name; - int flag; - int zlib; -} strategies[] = { - { "default", GZIP_STRATEGY_DEFAULT, Z_DEFAULT_STRATEGY }, - { "filtered", GZIP_STRATEGY_FILTERED, Z_FILTERED }, - { "huffman", GZIP_STRATEGY_HUFFMAN, Z_HUFFMAN_ONLY }, - { "rle", GZIP_STARTEGY_RLE, Z_RLE }, - { "fixed", GZIP_STRATEGY_FIXED, Z_FIXED }, -}; - typedef struct { uint32_t level; uint16_t window; @@ -75,8 +49,8 @@ static int gzip_write_options(compressor_t *base, int fd) gzip_compressor_t *gzip = (gzip_compressor_t *)base; gzip_options_t opt; - if (gzip->opt.level == GZIP_DEFAULT_LEVEL && - gzip->opt.window == GZIP_DEFAULT_WINDOW && + if (gzip->opt.level == SQFS_GZIP_DEFAULT_LEVEL && + gzip->opt.window == SQFS_GZIP_DEFAULT_WINDOW && gzip->opt.strategies == 0) { return 0; } @@ -112,7 +86,7 @@ static int gzip_read_options(compressor_t *base, int fd) return -1; } - if (gzip->opt.strategies & ~GZIP_ALL_STRATEGIES) { + if (gzip->opt.strategies & ~SQFS_COMP_FLAG_GZIP_ALL) { fputs("Unknown gzip strategies selected.\n", stderr); return -1; } @@ -120,14 +94,32 @@ static int gzip_read_options(compressor_t *base, int fd) return 0; } +static int flag_to_zlib_strategy(int flag) +{ + switch (flag) { + case SQFS_COMP_FLAG_GZIP_DEFAULT: + return Z_DEFAULT_STRATEGY; + case SQFS_COMP_FLAG_GZIP_FILTERED: + return Z_FILTERED; + case SQFS_COMP_FLAG_GZIP_HUFFMAN: + return Z_HUFFMAN_ONLY; + case SQFS_COMP_FLAG_GZIP_RLE: + return Z_RLE; + case SQFS_COMP_FLAG_GZIP_FIXED: + return Z_FIXED; + } + + return 0; +} + static int find_strategy(gzip_compressor_t *gzip, const uint8_t *in, size_t size, uint8_t *out, size_t outsize) { - int ret, selected = Z_DEFAULT_STRATEGY; + int ret, strategy, selected = Z_DEFAULT_STRATEGY; size_t i, length, minlength = 0; - for (i = 0; i < GZIP_NUM_STRATEGIES; ++i) { - if (!(strategies[i].flag & gzip->opt.strategies)) + for (i = 0x01; i & SQFS_COMP_FLAG_GZIP_ALL; i <<= 1) { + if ((gzip->opt.strategies & i) == 0) continue; ret = deflateReset(&gzip->strm); @@ -137,13 +129,14 @@ static int find_strategy(gzip_compressor_t *gzip, const uint8_t *in, return -1; } + strategy = flag_to_zlib_strategy(i); + gzip->strm.next_in = (void *)in; gzip->strm.avail_in = size; gzip->strm.next_out = out; gzip->strm.avail_out = outsize; - ret = deflateParams(&gzip->strm, gzip->opt.level, - strategies[i].zlib); + ret = deflateParams(&gzip->strm, gzip->opt.level, strategy); if (ret != Z_OK) { fputs("setting deflate parameters failed\n", stderr); @@ -157,7 +150,7 @@ static int find_strategy(gzip_compressor_t *gzip, const uint8_t *in, if (minlength == 0 || length < minlength) { minlength = length; - selected = strategies[i].zlib; + selected = strategy; } } else if (ret != Z_OK && ret != Z_BUF_ERROR) { fputs("gzip block processing failed\n", stderr); @@ -229,85 +222,6 @@ static ssize_t gzip_do_block(compressor_t *base, const uint8_t *in, return 0; } -static int process_options(char *options, int *level, int *window, int *flags) -{ - enum { - OPT_WINDOW = 0, - OPT_LEVEL, - }; - char *const token[] = { - [OPT_WINDOW] = (char *)"window", - [OPT_LEVEL] = (char *)"level", - NULL - }; - char *subopts, *value; - size_t i; - int opt; - - subopts = options; - - while (*subopts != '\0') { - opt = getsubopt(&subopts, token, &value); - - switch (opt) { - case OPT_WINDOW: - if (value == NULL) - goto fail_value; - - for (i = 0; isdigit(value[i]); ++i) - ; - - if (i < 1 || i > 3 || value[i] != '\0') - goto fail_window; - - *window = atoi(value); - - if (*window < 8 || *window > 15) - goto fail_window; - break; - case OPT_LEVEL: - if (value == NULL) - goto fail_value; - - for (i = 0; isdigit(value[i]); ++i) - ; - - if (i < 1 || i > 3 || value[i] != '\0') - goto fail_level; - - *level = atoi(value); - - if (*level < 1 || *level > 9) - goto fail_level; - break; - default: - for (i = 0; i < GZIP_NUM_STRATEGIES; ++i) { - if (strcmp(value, strategies[i].name) == 0) { - *flags |= strategies[i].flag; - break; - } - } - if (i == GZIP_NUM_STRATEGIES) - goto fail_opt; - break; - } - } - - return 0; -fail_window: - fputs("Window size must be a number between 8 and 15.\n", stderr); - return -1; -fail_level: - fputs("Compression level must be a number between 1 and 9.\n", stderr); - return -1; -fail_opt: - fprintf(stderr, "Unknown option '%s'.\n", value); - return -1; -fail_value: - fprintf(stderr, "Missing value for '%s'.\n", token[opt]); - return -1; -} - static compressor_t *gzip_create_copy(compressor_t *cmp) { gzip_compressor_t *gzip = malloc(sizeof(*gzip)); @@ -338,19 +252,33 @@ static compressor_t *gzip_create_copy(compressor_t *cmp) return (compressor_t *)gzip; } -compressor_t *create_gzip_compressor(bool compress, size_t block_size, - char *options) +compressor_t *create_gzip_compressor(const compressor_config_t *cfg) { - int window = GZIP_DEFAULT_WINDOW; - int level = GZIP_DEFAULT_LEVEL; gzip_compressor_t *gzip; compressor_t *base; - int flags = 0; int ret; - if (options != NULL) { - if (process_options(options, &level, &window, &flags)) - return NULL; + if (cfg->flags & ~(SQFS_COMP_FLAG_GZIP_ALL | + SQFS_COMP_FLAG_GENERIC_ALL)) { + fputs("creating gzip compressor: unknown compressor flags\n", + stderr); + return NULL; + } + + if (cfg->opt.gzip.level < SQFS_GZIP_MIN_LEVEL || + cfg->opt.gzip.level > SQFS_GZIP_MAX_LEVEL) { + fprintf(stderr, "creating gzip compressor: compression level" + "must be between %d and %d inclusive\n", + SQFS_GZIP_MIN_LEVEL, SQFS_GZIP_MAX_LEVEL); + return NULL; + } + + if (cfg->opt.gzip.window_size < SQFS_GZIP_MIN_WINDOW || + cfg->opt.gzip.window_size > SQFS_GZIP_MAX_WINDOW) { + fprintf(stderr, "creating gzip compressor: window size" + "must be between %d and %d inclusive\n", + SQFS_GZIP_MIN_WINDOW, SQFS_GZIP_MAX_WINDOW); + return NULL; } gzip = calloc(1, sizeof(*gzip)); @@ -361,19 +289,20 @@ compressor_t *create_gzip_compressor(bool compress, size_t block_size, return NULL; } - gzip->opt.level = level; - gzip->opt.window = window; - gzip->opt.strategies = flags; - gzip->compress = compress; - gzip->block_size = block_size; + gzip->opt.level = cfg->opt.gzip.level; + gzip->opt.window = cfg->opt.gzip.window_size; + gzip->opt.strategies = cfg->flags & SQFS_COMP_FLAG_GZIP_ALL; + gzip->compress = (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) == 0; + gzip->block_size = cfg->block_size; base->do_block = gzip_do_block; base->destroy = gzip_destroy; base->write_options = gzip_write_options; base->read_options = gzip_read_options; base->create_copy = gzip_create_copy; - if (compress) { - ret = deflateInit2(&gzip->strm, level, Z_DEFLATED, window, 8, + if (gzip->compress) { + ret = deflateInit2(&gzip->strm, cfg->opt.gzip.level, + Z_DEFLATED, cfg->opt.gzip.window_size, 8, Z_DEFAULT_STRATEGY); } else { ret = inflateInit(&gzip->strm); @@ -387,26 +316,3 @@ compressor_t *create_gzip_compressor(bool compress, size_t block_size, return base; } - -void compressor_gzip_print_help(void) -{ - size_t i; - - printf( -"Available options for gzip compressor:\n" -"\n" -" level=<value> Compression level. Value from 1 to 9.\n" -" Defaults to %d.\n" -" window=<size> Deflate compression window size. Value from 8 to 15.\n" -" Defaults to %d.\n" -"\n" -"In additon to the options, one or more strategies can be specified.\n" -"If multiple stratgies are provided, the one yielding the best compression\n" -"ratio will be used.\n" -"\n" -"The following strategies are available:\n", - GZIP_DEFAULT_LEVEL, GZIP_DEFAULT_WINDOW); - - for (i = 0; i < GZIP_NUM_STRATEGIES; ++i) - printf("\t%s\n", strategies[i].name); -} diff --git a/lib/sqfs/comp/internal.h b/lib/sqfs/comp/internal.h index 19ef5cd..229772f 100644 --- a/lib/sqfs/comp/internal.h +++ b/lib/sqfs/comp/internal.h @@ -16,29 +16,14 @@ 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, - char *options); +compressor_t *create_xz_compressor(const compressor_config_t *cfg); -compressor_t *create_gzip_compressor(bool compress, size_t block_size, - char *options); +compressor_t *create_gzip_compressor(const compressor_config_t *cfg); -compressor_t *create_lzo_compressor(bool compress, size_t block_size, - char *options); +compressor_t *create_lzo_compressor(const compressor_config_t *cfg); -compressor_t *create_lz4_compressor(bool compress, size_t block_size, - char *options); +compressor_t *create_lz4_compressor(const compressor_config_t *cfg); -compressor_t *create_zstd_compressor(bool compress, size_t block_size, - char *options); - -void compressor_xz_print_help(void); - -void compressor_gzip_print_help(void); - -void compressor_lzo_print_help(void); - -void compressor_lz4_print_help(void); - -void compressor_zstd_print_help(void); +compressor_t *create_zstd_compressor(const compressor_config_t *cfg); #endif /* INTERNAL_H */ diff --git a/lib/sqfs/comp/lz4.c b/lib/sqfs/comp/lz4.c index abb6c5c..4a15198 100644 --- a/lib/sqfs/comp/lz4.c +++ b/lib/sqfs/comp/lz4.c @@ -27,14 +27,14 @@ typedef struct { } lz4_options; #define LZ4LEGACY 1 -#define LZ4_FLAG_HC 0x01 static int lz4_write_options(compressor_t *base, int fd) { lz4_compressor_t *lz4 = (lz4_compressor_t *)base; lz4_options opt = { .version = htole32(LZ4LEGACY), - .flags = htole32(lz4->high_compression ? LZ4_FLAG_HC : 0), + .flags = htole32(lz4->high_compression ? + SQFS_COMP_FLAG_LZ4_HC : 0), }; return generic_write_options(fd, &opt, sizeof(opt)); @@ -115,45 +115,31 @@ static void lz4_destroy(compressor_t *base) free(base); } -compressor_t *create_lz4_compressor(bool compress, size_t block_size, - char *options) +compressor_t *create_lz4_compressor(const compressor_config_t *cfg) { lz4_compressor_t *lz4 = calloc(1, sizeof(*lz4)); compressor_t *base = (compressor_t *)lz4; - (void)block_size; + if (cfg->flags & ~(SQFS_COMP_FLAG_LZ4_ALL | + SQFS_COMP_FLAG_GENERIC_ALL)) { + fputs("creating lz4 compressor: unknown compressor flags\n", + stderr); + } + + lz4 = calloc(1, sizeof(*lz4)); + base = (compressor_t *)lz4; if (lz4 == NULL) { perror("creating lz4 compressor"); return NULL; } - lz4->high_compression = false; - - if (options != NULL) { - if (strcmp(options, "hc") == 0) { - lz4->high_compression = true; - } else { - fputs("Unsupported extra options for lz4 " - "compressor.\n", stderr); - free(lz4); - return NULL; - } - } + lz4->high_compression = (cfg->flags & SQFS_COMP_FLAG_LZ4_HC) != 0; base->destroy = lz4_destroy; - base->do_block = compress ? lz4_comp_block : lz4_uncomp_block; + base->do_block = (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) ? + lz4_uncomp_block : lz4_comp_block; base->write_options = lz4_write_options; base->read_options = lz4_read_options; base->create_copy = lz4_create_copy; return base; } - -void compressor_lz4_print_help(void) -{ - fputs("Available options for lz4 compressor:\n" - "\n" - " hc If present, use slower but better compressing\n" - " variant of lz4.\n" - "\n", - stdout); -} diff --git a/lib/sqfs/comp/lzo.c b/lib/sqfs/comp/lzo.c index 09ef75c..3293af1 100644 --- a/lib/sqfs/comp/lzo.c +++ b/lib/sqfs/comp/lzo.c @@ -16,49 +16,32 @@ #include "internal.h" - -typedef enum { - LZO_ALGORITHM_LZO1X_1 = 0, - LZO_ALGORITHM_LZO1X_1_11 = 1, - LZO_ALGORITHM_LZO1X_1_12 = 2, - LZO_ALGORITHM_LZO1X_1_15 = 3, - LZO_ALGORITHM_LZO1X_999 = 4, -} LZO_ALGORITHM; - -#define LZO_DEFAULT_ALG LZO_ALGORITHM_LZO1X_999 -#define LZO_DEFAULT_LEVEL 8 #define LZO_NUM_ALGS (sizeof(lzo_algs) / sizeof(lzo_algs[0])) typedef int (*lzo_cb_t)(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp dst_len, lzo_voidp wrkmem); static const struct { - const char *name; lzo_cb_t compress; size_t bufsize; } lzo_algs[] = { - [LZO_ALGORITHM_LZO1X_1] = { - .name = "lzo1x_1", + [SQFS_LZO1X_1] = { .compress = lzo1x_1_compress, .bufsize = LZO1X_1_MEM_COMPRESS, }, - [LZO_ALGORITHM_LZO1X_1_11] = { - .name = "lzo1x_1_11", + [SQFS_LZO1X_1_11] = { .compress = lzo1x_1_11_compress, .bufsize = LZO1X_1_11_MEM_COMPRESS, }, - [LZO_ALGORITHM_LZO1X_1_12] = { - .name = "lzo1x_1_12", + [SQFS_LZO1X_1_12] = { .compress = lzo1x_1_12_compress, .bufsize = LZO1X_1_12_MEM_COMPRESS, }, - [LZO_ALGORITHM_LZO1X_1_15] = { - .name = "lzo1x_1_15", + [SQFS_LZO1X_1_15] = { .compress = lzo1x_1_15_compress, .bufsize = LZO1X_1_15_MEM_COMPRESS, }, - [LZO_ALGORITHM_LZO1X_999] = { - .name = "lzo1x_999", + [SQFS_LZO1X_999] = { .compress = lzo1x_999_compress, .bufsize = LZO1X_999_MEM_COMPRESS, }, @@ -82,14 +65,14 @@ static int lzo_write_options(compressor_t *base, int fd) lzo_compressor_t *lzo = (lzo_compressor_t *)base; lzo_options_t opt; - if (lzo->algorithm == LZO_DEFAULT_ALG && - lzo->level == LZO_DEFAULT_LEVEL) { + if (lzo->algorithm == SQFS_LZO_DEFAULT_ALG && + lzo->level == SQFS_LZO_DEFAULT_LEVEL) { return 0; } opt.algorithm = htole32(lzo->algorithm); - if (lzo->algorithm == LZO_ALGORITHM_LZO1X_999) { + if (lzo->algorithm == SQFS_LZO1X_999) { opt.level = htole32(lzo->level); } else { opt.level = 0; @@ -110,14 +93,14 @@ static int lzo_read_options(compressor_t *base, int fd) lzo->level = le32toh(opt.level); switch(lzo->algorithm) { - case LZO_ALGORITHM_LZO1X_1: - case LZO_ALGORITHM_LZO1X_1_11: - case LZO_ALGORITHM_LZO1X_1_12: - case LZO_ALGORITHM_LZO1X_1_15: + case SQFS_LZO1X_1: + case SQFS_LZO1X_1_11: + case SQFS_LZO1X_1_12: + case SQFS_LZO1X_1_15: if (lzo->level != 0) goto fail_level; break; - case LZO_ALGORITHM_LZO1X_999: + case SQFS_LZO1X_999: if (lzo->level < 1 || lzo->level > 9) goto fail_level; break; @@ -139,8 +122,8 @@ static ssize_t lzo_comp_block(compressor_t *base, const uint8_t *in, lzo_uint len = outsize; int ret; - if (lzo->algorithm == LZO_ALGORITHM_LZO1X_999 && - lzo->level != LZO_DEFAULT_LEVEL) { + if (lzo->algorithm == SQFS_LZO1X_999 && + lzo->level != SQFS_LZO_DEFAULT_LEVEL) { ret = lzo1x_999_compress_level(in, size, out, &len, lzo->buffer, NULL, 0, 0, lzo->level); @@ -198,91 +181,38 @@ static void lzo_destroy(compressor_t *base) free(base); } -static int process_options(char *options, int *algorithm, int *level) -{ - enum { - OPT_ALG = 0, - OPT_LEVEL, - }; - char *const token[] = { - [OPT_ALG] = (char *)"algorithm", - [OPT_LEVEL] = (char *)"level", - NULL - }; - char *subopts, *value; - size_t i; - int opt; - - subopts = options; - - while (*subopts != '\0') { - opt = getsubopt(&subopts, token, &value); - - switch (opt) { - case OPT_ALG: - if (value == NULL) - goto fail_value; - - for (i = 0; i < LZO_NUM_ALGS; ++i) { - if (strcmp(lzo_algs[i].name, value) == 0) { - *algorithm = i; - break; - } - } - - if (i == LZO_NUM_ALGS) { - fprintf(stderr, "Unknown lzo variant '%s'.\n", - value); - return -1; - } - break; - case OPT_LEVEL: - if (value == NULL) - goto fail_value; - - for (i = 0; isdigit(value[i]); ++i) - ; - - if (i < 1 || i > 3 || value[i] != '\0') - goto fail_level; - - *level = atoi(value); - - if (*level < 1 || *level > 9) - goto fail_level; - break; - default: - goto fail_opt; - } - } - - return 0; -fail_level: - fputs("Compression level must be a number between 1 and 9.\n", stderr); - return -1; -fail_opt: - fprintf(stderr, "Unknown option '%s'.\n", value); - return -1; -fail_value: - fprintf(stderr, "Missing value for '%s'.\n", token[opt]); - return -1; -} - -compressor_t *create_lzo_compressor(bool compress, size_t block_size, - char *options) +compressor_t *create_lzo_compressor(const compressor_config_t *cfg) { lzo_compressor_t *lzo; compressor_t *base; - int level, alg; - (void)block_size; - alg = LZO_DEFAULT_ALG; - level = LZO_DEFAULT_LEVEL; + if (cfg->flags & ~SQFS_COMP_FLAG_GENERIC_ALL) { + fputs("creating lzo compressor: unknown compressor flags\n", + stderr); + return NULL; + } - if (options != NULL && process_options(options, &alg, &level) != 0) + if (cfg->opt.lzo.algorithm > LZO_NUM_ALGS || + lzo_algs[cfg->opt.lzo.algorithm].compress == NULL) { + fputs("creating lzo compressor: unknown LZO variant\n", + stderr); return NULL; + } - lzo = alloc_flex(sizeof(*lzo), 1, lzo_algs[alg].bufsize); + if (cfg->opt.lzo.algorithm == SQFS_LZO1X_999) { + if (cfg->opt.lzo.level > SQFS_LZO_MAX_LEVEL) { + fputs("creating lzo compressor: compression level " + "must be between 0 and 9 inclusive\n", stderr); + return NULL; + } + } else if (cfg->opt.lzo.level != 0) { + fputs("creating lzo compressor: level argument " + "only supported by lzo1x 999\n", stderr); + return NULL; + } + + lzo = alloc_flex(sizeof(*lzo), 1, + lzo_algs[cfg->opt.lzo.algorithm].bufsize); base = (compressor_t *)lzo; if (lzo == NULL) { @@ -290,32 +220,14 @@ compressor_t *create_lzo_compressor(bool compress, size_t block_size, return NULL; } - lzo->algorithm = alg; - lzo->level = level; + lzo->algorithm = cfg->opt.lzo.algorithm; + lzo->level = cfg->opt.lzo.level; base->destroy = lzo_destroy; - base->do_block = compress ? lzo_comp_block : lzo_uncomp_block; + base->do_block = (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) ? + lzo_uncomp_block : lzo_comp_block; base->write_options = lzo_write_options; base->read_options = lzo_read_options; base->create_copy = lzo_create_copy; return base; } - -void compressor_lzo_print_help(void) -{ - size_t i; - - fputs("Available options for lzo compressor:\n" - "\n" - " algorithm=<name> Specify the variant of lzo to use.\n" - " Defaults to 'lzo1x_999'.\n" - " level=<value> For lzo1x_999, the compression level.\n" - " Value from 1 to 9. Defaults to 8.\n" - " Ignored if algorithm is not lzo1x_999.\n" - "\n" - "Available algorithms:\n", - stdout); - - for (i = 0; i < LZO_NUM_ALGS; ++i) - printf("\t%s\n", lzo_algs[i].name); -} diff --git a/lib/sqfs/comp/xz.c b/lib/sqfs/comp/xz.c index d38aab6..4f67b1c 100644 --- a/lib/sqfs/comp/xz.c +++ b/lib/sqfs/comp/xz.c @@ -15,17 +15,6 @@ #include "internal.h" -typedef enum { - XZ_FILTER_X86 = 0x01, - XZ_FILTER_POWERPC = 0x02, - XZ_FILTER_IA64 = 0x04, - XZ_FILTER_ARM = 0x08, - XZ_FILTER_ARMTHUMB = 0x10, - XZ_FILTER_SPARC = 0x20, - - XZ_FILTER_ALL = 0x3F, -} XZ_FILTER_FLAG; - typedef struct { compressor_t base; size_t block_size; @@ -38,20 +27,15 @@ typedef struct { uint32_t flags; } xz_options_t; -static const struct { - const char *name; - lzma_vli filter; - int flag; -} xz_filters[] = { - { "x86", LZMA_FILTER_X86, XZ_FILTER_X86 }, - { "powerpc", LZMA_FILTER_POWERPC, XZ_FILTER_POWERPC }, - { "ia64", LZMA_FILTER_IA64, XZ_FILTER_IA64 }, - { "arm", LZMA_FILTER_ARM, XZ_FILTER_ARM }, - { "armthumb", LZMA_FILTER_ARMTHUMB, XZ_FILTER_ARMTHUMB }, - { "sparc", LZMA_FILTER_SPARC, XZ_FILTER_SPARC }, -}; - -#define XZ_NUM_FILTERS (sizeof(xz_filters) / sizeof(xz_filters[0])) +static bool is_dict_size_valid(size_t size) +{ + size_t x = size & (size - 1); + + if (x == 0) + return true; + + return size == (x | (x >> 1)); +} static int xz_write_options(compressor_t *base, int fd) { @@ -71,7 +55,6 @@ static int xz_read_options(compressor_t *base, int fd) { xz_compressor_t *xz = (xz_compressor_t *)base; xz_options_t opt; - uint32_t mask; if (generic_read_options(fd, &opt, sizeof(opt))) return -1; @@ -79,14 +62,12 @@ static int xz_read_options(compressor_t *base, int fd) opt.dict_size = le32toh(opt.dict_size); opt.flags = le32toh(opt.flags); - mask = opt.dict_size & (opt.dict_size - 1); - - if (mask != 0 && ((mask & (mask - 1)) != 0)) { + if (!is_dict_size_valid(opt.dict_size)) { fputs("Invalid lzma dictionary size.\n", stderr); return -1; } - if (opt.flags & ~XZ_FILTER_ALL) { + if (opt.flags & ~SQFS_COMP_FLAG_XZ_ALL) { fputs("Unknown BCJ filter used.\n", stderr); return -1; } @@ -141,11 +122,31 @@ static ssize_t compress(xz_compressor_t *xz, lzma_vli filter, return 0; } +static lzma_vli flag_to_vli(int flag) +{ + switch (flag) { + case SQFS_COMP_FLAG_XZ_X86: + return LZMA_FILTER_X86; + case SQFS_COMP_FLAG_XZ_POWERPC: + return LZMA_FILTER_POWERPC; + case SQFS_COMP_FLAG_XZ_IA64: + return LZMA_FILTER_IA64; + case SQFS_COMP_FLAG_XZ_ARM: + return LZMA_FILTER_ARM; + case SQFS_COMP_FLAG_XZ_ARMTHUMB: + return LZMA_FILTER_ARMTHUMB; + case SQFS_COMP_FLAG_XZ_SPARC: + return LZMA_FILTER_SPARC; + } + + return LZMA_VLI_UNKNOWN; +} + static ssize_t xz_comp_block(compressor_t *base, const uint8_t *in, size_t size, uint8_t *out, size_t outsize) { xz_compressor_t *xz = (xz_compressor_t *)base; - lzma_vli selected = LZMA_VLI_UNKNOWN; + lzma_vli filter, selected = LZMA_VLI_UNKNOWN; size_t i, smallest; ssize_t ret; @@ -155,17 +156,19 @@ static ssize_t xz_comp_block(compressor_t *base, const uint8_t *in, smallest = ret; - for (i = 0; i < XZ_NUM_FILTERS; ++i) { - if (!(xz->flags & xz_filters[i].flag)) + for (i = 0; i & SQFS_COMP_FLAG_XZ_ALL; i <<= 1) { + if ((xz->flags & i) == 0) continue; - ret = compress(xz, xz_filters[i].filter, in, size, out, outsize); + filter = flag_to_vli(i); + + ret = compress(xz, filter, in, size, out, outsize); if (ret < 0) return -1; if (ret > 0 && (smallest == 0 || (size_t)ret < smallest)) { smallest = ret; - selected = xz_filters[i].filter; + selected = filter; } } @@ -213,108 +216,22 @@ static void xz_destroy(compressor_t *base) free(base); } -static int process_options(char *options, size_t blocksize, - int *flags, uint64_t *dictsize) -{ - enum { - OPT_DICT = 0, - }; - char *const token[] = { - [OPT_DICT] = (char *)"dictsize", - NULL - }; - char *subopts, *value; - uint64_t mask; - size_t i; - int opt; - - subopts = options; - - while (*subopts != '\0') { - opt = getsubopt(&subopts, token, &value); - - switch (opt) { - case OPT_DICT: - if (value == NULL) - goto fail_value; - - for (i = 0; isdigit(value[i]); ++i) - ; - - if (i < 1 || i > 9) - goto fail_dict; - - *dictsize = atol(value); - - switch (value[i]) { - case '\0': - break; - case 'm': - case 'M': - *dictsize <<= 20; - break; - case 'k': - case 'K': - *dictsize <<= 10; - break; - case '%': - *dictsize = ((*dictsize) * blocksize) / 100; - break; - default: - goto fail_dict; - } - - if (*dictsize > 0x0FFFFFFFFUL) - goto fail_dict_ov; - - mask = *dictsize & (*dictsize - 1); - - if (mask != 0 && ((mask & (mask - 1)) != 0)) - goto fail_dict_pot; - break; - default: - for (i = 0; i < XZ_NUM_FILTERS; ++i) { - if (strcmp(value, xz_filters[i].name) == 0) { - *flags |= xz_filters[i].flag; - break; - } - } - if (i == XZ_NUM_FILTERS) - goto fail_opt; - break; - } - } - - return 0; -fail_dict_pot: - fputs("dictionary size must be either 2^n or 2^n + 2^(n-1)\n", stderr); - return -1; -fail_dict_ov: - fputs("dictionary size too large.\n", stderr); - return -1; -fail_dict: - fputs("dictionary size must be a number with the optional " - "suffix 'm','k' or '%'.\n", stderr); - return -1; -fail_opt: - fprintf(stderr, "Unknown option '%s'.\n", value); - return -1; -fail_value: - fprintf(stderr, "Missing value for '%s'.\n", token[opt]); - return -1; -} - -compressor_t *create_xz_compressor(bool compress, size_t block_size, - char *options) +compressor_t *create_xz_compressor(const compressor_config_t *cfg) { - uint64_t dictsize = block_size; xz_compressor_t *xz; compressor_t *base; - int flags = 0; - if (options != NULL) { - if (process_options(options, block_size, &flags, &dictsize)) - return NULL; + if (cfg->flags & ~(SQFS_COMP_FLAG_GENERIC_ALL | + SQFS_COMP_FLAG_XZ_ALL)) { + fputs("creating xz compressor: unknown compressor flags\n", + stderr); + return NULL; + } + + if (!is_dict_size_valid(cfg->opt.xz.dict_size)) { + fputs("creating xz compressor: invalid dictionary size\n", + stderr); + return NULL; } xz = calloc(1, sizeof(*xz)); @@ -324,37 +241,14 @@ compressor_t *create_xz_compressor(bool compress, size_t block_size, return NULL; } - xz->flags = flags; - xz->dict_size = dictsize; - xz->block_size = block_size; + xz->flags = cfg->flags; + xz->dict_size = cfg->opt.xz.dict_size; + xz->block_size = cfg->block_size; base->destroy = xz_destroy; - base->do_block = compress ? xz_comp_block : xz_uncomp_block; + base->do_block = (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) ? + xz_uncomp_block : xz_comp_block; base->write_options = xz_write_options; base->read_options = xz_read_options; base->create_copy = xz_create_copy; return base; } - -void compressor_xz_print_help(void) -{ - size_t i; - - fputs( -"Available options for xz compressor:\n" -"\n" -" dictsize=<value> Dictionary size. Either a value in bytes or a\n" -" percentage of the block size. Defaults to 100%.\n" -" The suffix '%' indicates a percentage. 'K' and 'M'\n" -" can also be used for kibi and mebi bytes\n" -" respecitively.\n" -"\n" -"In additon to the options, one or more bcj filters can be specified.\n" -"If multiple filters are provided, the one yielding the best compression\n" -"ratio will be used.\n" -"\n" -"The following filters are available:\n", - stdout); - - for (i = 0; i < XZ_NUM_FILTERS; ++i) - printf("\t%s\n", xz_filters[i].name); -} diff --git a/lib/sqfs/comp/zstd.c b/lib/sqfs/comp/zstd.c index e206338..c805524 100644 --- a/lib/sqfs/comp/zstd.c +++ b/lib/sqfs/comp/zstd.c @@ -16,8 +16,6 @@ #include "internal.h" -#define ZSTD_DEFAULT_COMPRESSION_LEVEL 15 - typedef struct { compressor_t base; ZSTD_CCtx *zctx; @@ -34,7 +32,7 @@ static int zstd_write_options(compressor_t *base, int fd) zstd_options_t opt; (void)fd; - if (zstd->level == ZSTD_DEFAULT_COMPRESSION_LEVEL) + if (zstd->level == SQFS_ZSTD_DEFAULT_LEVEL) return 0; opt.level = htole32(zstd->level); @@ -119,38 +117,26 @@ static void zstd_destroy(compressor_t *base) free(zstd); } -compressor_t *create_zstd_compressor(bool compress, size_t block_size, - char *options) +compressor_t *create_zstd_compressor(const compressor_config_t *cfg) { - zstd_compressor_t *zstd = calloc(1, sizeof(*zstd)); - compressor_t *base = (compressor_t *)zstd; - size_t i; - (void)block_size; + zstd_compressor_t *zstd; + compressor_t *base; - if (zstd == NULL) { - perror("creating zstd compressor"); - return NULL; + if (cfg->flags & ~SQFS_COMP_FLAG_GENERIC_ALL) { + fputs("creating zstd compressor: unknown compressor flags\n", + stderr); } - zstd->level = ZSTD_DEFAULT_COMPRESSION_LEVEL; - - if (options != NULL) { - if (strncmp(options, "level=", 6) == 0) { - options += 6; - - for (i = 0; isdigit(options[i]); ++i) - ; - - if (i == 0 || options[i] != '\0' || i > 6) - goto fail_level; - - zstd->level = atoi(options); + if (cfg->opt.zstd.level < 1 || + cfg->opt.zstd.level > ZSTD_maxCLevel()) { + goto fail_level; + } - if (zstd->level < 1 || zstd->level > ZSTD_maxCLevel()) - goto fail_level; - } else { - goto fail_opt; - } + zstd = calloc(1, sizeof(*zstd)); + base = (compressor_t *)zstd; + if (zstd == NULL) { + perror("creating zstd compressor"); + return NULL; } zstd->zctx = ZSTD_createCCtx(); @@ -161,7 +147,8 @@ compressor_t *create_zstd_compressor(bool compress, size_t block_size, } base->destroy = zstd_destroy; - base->do_block = compress ? zstd_comp_block : zstd_uncomp_block; + base->do_block = cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS ? + zstd_uncomp_block : zstd_comp_block; base->write_options = zstd_write_options; base->read_options = zstd_read_options; base->create_copy = zstd_create_copy; @@ -169,20 +156,5 @@ compressor_t *create_zstd_compressor(bool compress, size_t block_size, fail_level: fprintf(stderr, "zstd compression level must be a number in the range " "1...%d\n", ZSTD_maxCLevel()); - free(zstd); return NULL; -fail_opt: - fputs("Unsupported extra options for zstd compressor\n", stderr); - free(zstd); - return NULL; -} - -void compressor_zstd_print_help(void) -{ - printf("Available options for zstd compressor:\n" - "\n" - " level=<value> Set compression level. Defaults to %d.\n" - " Maximum is %d.\n" - "\n", - ZSTD_DEFAULT_COMPRESSION_LEVEL, ZSTD_maxCLevel()); } diff --git a/lib/sqfshelper/comp_opt.c b/lib/sqfshelper/comp_opt.c new file mode 100644 index 0000000..1f3fabf --- /dev/null +++ b/lib/sqfshelper/comp_opt.c @@ -0,0 +1,380 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * comp_opt.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "config.h" + +#include "highlevel.h" + +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <ctype.h> + +typedef struct { + const char *name; + uint16_t flag; +} flag_t; + +static const flag_t gzip_flags[] = { + { "default", SQFS_COMP_FLAG_GZIP_DEFAULT }, + { "filtered", SQFS_COMP_FLAG_GZIP_FILTERED }, + { "huffman", SQFS_COMP_FLAG_GZIP_HUFFMAN }, + { "rle", SQFS_COMP_FLAG_GZIP_RLE }, + { "fixed", SQFS_COMP_FLAG_GZIP_FIXED }, +}; + +static const flag_t xz_flags[] = { + { "x86", SQFS_COMP_FLAG_XZ_X86 }, + { "powerpc", SQFS_COMP_FLAG_XZ_POWERPC }, + { "ia64", SQFS_COMP_FLAG_XZ_IA64 }, + { "arm", SQFS_COMP_FLAG_XZ_ARM }, + { "armthumb", SQFS_COMP_FLAG_XZ_ARMTHUMB }, + { "sparc", SQFS_COMP_FLAG_XZ_SPARC }, +}; + +static const flag_t lz4_flags[] = { + { "hc", SQFS_COMP_FLAG_LZ4_HC }, +}; + +static const char *lzo_algs[] = { + [SQFS_LZO1X_1] = "lzo1x_1", + [SQFS_LZO1X_1_11] = "lzo1x_1_11", + [SQFS_LZO1X_1_12] = "lzo1x_1_12", + [SQFS_LZO1X_1_15] = "lzo1x_1_15", + [SQFS_LZO1X_999] = "lzo1x_999", +}; + +static int set_flag(compressor_config_t *cfg, const char *name, + const flag_t *flags, size_t num_flags) +{ + size_t i; + + for (i = 0; i < num_flags; ++i) { + if (strcmp(flags[i].name, name) == 0) { + cfg->flags |= flags[i].flag; + return 0; + } + } + + return -1; +} + +static int find_lzo_alg(compressor_config_t *cfg, const char *name) +{ + size_t i; + + for (i = 0; i < sizeof(lzo_algs) / sizeof(lzo_algs[0]); ++i) { + if (strcmp(lzo_algs[i], name) == 0) { + cfg->opt.lzo.algorithm = i; + return 0; + } + } + + return -1; +} + +static int get_size_value(const char *value, uint32_t *out, uint32_t block_size) +{ + int i; + + for (i = 0; isdigit(value[i]) && i < 9; ++i) + ; + + if (i < 1 || i > 9) + return -1; + + *out = atol(value); + + switch (value[i]) { + case '\0': + break; + case 'm': + case 'M': + *out <<= 20; + break; + case 'k': + case 'K': + *out <<= 10; + break; + case '%': + *out = (*out * block_size) / 100; + break; + default: + return -1; + } + + return 0; +} + +enum { + OPT_WINDOW = 0, + OPT_LEVEL, + OPT_ALG, + OPT_DICT, +}; +static char *const token[] = { + [OPT_WINDOW] = (char *)"window", + [OPT_LEVEL] = (char *)"level", + [OPT_ALG] = (char *)"algorithm", + [OPT_DICT] = (char *)"dictsize", + NULL +}; + +int compressor_cfg_init_options(compressor_config_t *cfg, E_SQFS_COMPRESSOR id, + size_t block_size, char *options) +{ + size_t num_flags = 0, min_level = 0, max_level = 0, level; + const flag_t *flags = NULL; + char *subopts, *value; + int i, opt; + + if (compressor_config_init(cfg, id, block_size, 0)) + return -1; + + if (options == NULL) + return 0; + + switch (cfg->id) { + case SQFS_COMP_GZIP: + min_level = SQFS_GZIP_MIN_LEVEL; + max_level = SQFS_GZIP_MAX_LEVEL; + flags = gzip_flags; + num_flags = sizeof(gzip_flags) / sizeof(gzip_flags[0]); + break; + case SQFS_COMP_LZO: + min_level = SQFS_LZO_MIN_LEVEL; + max_level = SQFS_LZO_MAX_LEVEL; + break; + case SQFS_COMP_ZSTD: + min_level = SQFS_ZSTD_MIN_LEVEL; + max_level = SQFS_ZSTD_MAX_LEVEL; + break; + case SQFS_COMP_XZ: + flags = xz_flags; + num_flags = sizeof(xz_flags) / sizeof(xz_flags[0]); + break; + case SQFS_COMP_LZ4: + flags = lz4_flags; + num_flags = sizeof(lz4_flags) / sizeof(lz4_flags[0]); + break; + default: + break; + } + + subopts = options; + + while (*subopts != '\0') { + opt = getsubopt(&subopts, token, &value); + + switch (opt) { + case OPT_WINDOW: + if (cfg->id != SQFS_COMP_GZIP) + goto fail_opt; + + if (value == NULL) + goto fail_value; + + for (i = 0; isdigit(value[i]); ++i) + ; + + if (i < 1 || i > 3 || value[i] != '\0') + goto fail_window; + + cfg->opt.gzip.window_size = atoi(value); + + if (cfg->opt.gzip.window_size < SQFS_GZIP_MIN_WINDOW || + cfg->opt.gzip.window_size > SQFS_GZIP_MAX_WINDOW) + goto fail_window; + break; + case OPT_LEVEL: + if (value == NULL) + goto fail_value; + + for (i = 0; isdigit(value[i]) && i < 3; ++i) + ; + + if (i < 1 || i > 3 || value[i] != '\0') + goto fail_level; + + level = atoi(value); + + if (level < min_level || level > max_level) + goto fail_level; + + switch (cfg->id) { + case SQFS_COMP_GZIP: + cfg->opt.gzip.level = level; + break; + case SQFS_COMP_LZO: + cfg->opt.lzo.level = level; + break; + case SQFS_COMP_ZSTD: + cfg->opt.zstd.level = level; + break; + default: + goto fail_opt; + } + break; + case OPT_ALG: + if (cfg->id != SQFS_COMP_LZO) + goto fail_opt; + + if (value == NULL) + goto fail_value; + + if (find_lzo_alg(cfg, value)) + goto fail_lzo_alg; + break; + case OPT_DICT: + if (cfg->id != SQFS_COMP_XZ) + goto fail_opt; + + if (value == NULL) + goto fail_value; + + if (get_size_value(value, &cfg->opt.xz.dict_size, + cfg->block_size)) { + goto fail_dict; + } + break; + default: + if (set_flag(cfg, value, flags, num_flags)) + goto fail_opt; + break; + } + } + + return 0; +fail_lzo_alg: + fprintf(stderr, "Unknown lzo variant '%s'.\n", value); + return -1; +fail_window: + fputs("Window size must be a number between 8 and 15.\n", stderr); + return -1; +fail_level: + fprintf(stderr, + "Compression level must be a number between %zu and %zu.\n", + min_level, max_level); + return -1; +fail_opt: + fprintf(stderr, "Unknown compressor option '%s'.\n", value); + return -1; +fail_value: + fprintf(stderr, "Missing value for compressor option '%s'.\n", + token[opt]); + return -1; +fail_dict: + fputs("Dictionary size must be a number with the optional " + "suffix 'm','k' or '%'.\n", stderr); + return -1; +} + +typedef void (*compressor_help_fun_t)(void); + +static void gzip_print_help(void) +{ + size_t i; + + printf( +"Available options for gzip compressor:\n" +"\n" +" level=<value> Compression level. Value from 1 to 9.\n" +" Defaults to %d.\n" +" window=<size> Deflate compression window size. Value from 8 to 15.\n" +" Defaults to %d.\n" +"\n" +"In additon to the options, one or more strategies can be specified.\n" +"If multiple stratgies are provided, the one yielding the best compression\n" +"ratio will be used.\n" +"\n" +"The following strategies are available:\n", + SQFS_GZIP_DEFAULT_LEVEL, SQFS_GZIP_DEFAULT_WINDOW); + + for (i = 0; i < sizeof(gzip_flags) / sizeof(gzip_flags[0]); ++i) + printf("\t%s\n", gzip_flags[i].name); +} + +static void lz4_print_help(void) +{ + fputs("Available options for lz4 compressor:\n" + "\n" + " hc If present, use slower but better compressing\n" + " variant of lz4.\n" + "\n", + stdout); +} + +static void lzo_print_help(void) +{ + size_t i; + + fputs("Available options for lzo compressor:\n" + "\n" + " algorithm=<name> Specify the variant of lzo to use.\n" + " Defaults to 'lzo1x_999'.\n" + " level=<value> For lzo1x_999, the compression level.\n" + " Value from 1 to 9. Defaults to 8.\n" + " Ignored if algorithm is not lzo1x_999.\n" + "\n" + "Available algorithms:\n", + stdout); + + for (i = 0; i < sizeof(lzo_algs) / sizeof(lzo_algs[0]); ++i) + printf("\t%s\n", lzo_algs[i]); +} + +static void xz_print_help(void) +{ + size_t i; + + fputs( +"Available options for xz compressor:\n" +"\n" +" dictsize=<value> Dictionary size. Either a value in bytes or a\n" +" percentage of the block size. Defaults to 100%.\n" +" The suffix '%' indicates a percentage. 'K' and 'M'\n" +" can also be used for kibi and mebi bytes\n" +" respecitively.\n" +"\n" +"In additon to the options, one or more bcj filters can be specified.\n" +"If multiple filters are provided, the one yielding the best compression\n" +"ratio will be used.\n" +"\n" +"The following filters are available:\n", + stdout); + + for (i = 0; i < sizeof(xz_flags) / sizeof(xz_flags[0]); ++i) + printf("\t%s\n", xz_flags[i].name); +} + +static void zstd_print_help(void) +{ + printf("Available options for zstd compressor:\n" + "\n" + " level=<value> Set compression level. Defaults to %d.\n" + " Maximum is %d.\n" + "\n", + SQFS_ZSTD_DEFAULT_LEVEL, SQFS_ZSTD_MAX_LEVEL); +} + +static const compressor_help_fun_t helpfuns[SQFS_COMP_MAX + 1] = { + [SQFS_COMP_GZIP] = gzip_print_help, + [SQFS_COMP_XZ] = xz_print_help, + [SQFS_COMP_LZO] = lzo_print_help, + [SQFS_COMP_LZ4] = lz4_print_help, + [SQFS_COMP_ZSTD] = zstd_print_help, +}; + +void compressor_print_help(E_SQFS_COMPRESSOR id) +{ + if (id < SQFS_COMP_MIN || id > SQFS_COMP_MAX) + return; + + if (helpfuns[id] == NULL) + return; + + helpfuns[id](); +} diff --git a/lib/sqfshelper/compress.c b/lib/sqfshelper/compress.c new file mode 100644 index 0000000..3d53e9e --- /dev/null +++ b/lib/sqfshelper/compress.c @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * compress.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "highlevel.h" + +E_SQFS_COMPRESSOR compressor_get_default(void) +{ + if (compressor_exists(SQFS_COMP_XZ)) + return SQFS_COMP_XZ; + + if (compressor_exists(SQFS_COMP_ZSTD)) + return SQFS_COMP_ZSTD; + + return SQFS_COMP_GZIP; +} + +void compressor_print_available(void) +{ + int i; + + fputs("Available compressors:\n", stdout); + + for (i = SQFS_COMP_MIN; i <= SQFS_COMP_MAX; ++i) { + if (compressor_exists(i)) + printf("\t%s\n", compressor_name_from_id(i)); + } + + printf("\nDefault compressor: %s\n", + compressor_name_from_id(compressor_get_default())); +} diff --git a/lib/sqfshelper/sqfs_reader.c b/lib/sqfshelper/sqfs_reader.c index 197e08f..49e91f5 100644 --- a/lib/sqfshelper/sqfs_reader.c +++ b/lib/sqfshelper/sqfs_reader.c @@ -14,6 +14,8 @@ int sqfs_reader_open(sqfs_reader_t *rd, const char *filename, int rdtree_flags) { + compressor_config_t cfg; + memset(rd, 0, sizeof(*rd)); rd->sqfsfd = open(filename, O_RDONLY); @@ -30,8 +32,11 @@ int sqfs_reader_open(sqfs_reader_t *rd, const char *filename, int rdtree_flags) goto fail_fd; } - rd->cmp = compressor_create(rd->super.compression_id, false, - rd->super.block_size, NULL); + compressor_config_init(&cfg, rd->super.compression_id, + rd->super.block_size, + SQFS_COMP_FLAG_UNCOMPRESS); + + rd->cmp = compressor_create(&cfg); if (rd->cmp == NULL) goto fail_fd; |