|
|
@@ -1,898 +0,0 @@
|
|
|
-From 5fb9fdfb8757fc9afb6318a3dcf9dce0a97de352 Mon Sep 17 00:00:00 2001
|
|
|
-From: Phillip Lougher <[email protected]>
|
|
|
-Date: Wed, 19 Apr 2023 18:35:53 +0100
|
|
|
-Subject: [PATCH] xz_wrapper: make new OpenWrt extended options non-default
|
|
|
-
|
|
|
-The reason why these options are being made non-default are
|
|
|
-described here:
|
|
|
-
|
|
|
-https://github.com/plougher/squashfs-tools/pull/218#issuecomment-1515197256
|
|
|
-
|
|
|
-The new options can be enabled by editing the Makefile or by defining
|
|
|
-XZ_EXTENDED_OPTIONS on the Make command line, e.g.
|
|
|
-
|
|
|
-% CONFIG=1 XZ_SUPPORT=1 XZ_EXTENDED_OPTIONS=1 make
|
|
|
-
|
|
|
-Signed-off-by: Phillip Lougher <[email protected]>
|
|
|
----
|
|
|
- squashfs-tools/Makefile | 12 +
|
|
|
- squashfs-tools/xz_wrapper.c | 117 +----
|
|
|
- squashfs-tools/xz_wrapper_extended.c | 664 +++++++++++++++++++++++++++
|
|
|
- 3 files changed, 679 insertions(+), 114 deletions(-)
|
|
|
- create mode 100644 squashfs-tools/xz_wrapper_extended.c
|
|
|
-
|
|
|
---- a/squashfs-tools/Makefile
|
|
|
-+++ b/squashfs-tools/Makefile
|
|
|
-@@ -39,6 +39,10 @@ GZIP_SUPPORT = 1
|
|
|
- #
|
|
|
- #XZ_SUPPORT = 1
|
|
|
-
|
|
|
-+# Enable support for OpenWrt extended compression options by uncommenting
|
|
|
-+# next line. Do not do this unless you understand the implications.
|
|
|
-+#XZ_EXTENDED_OPTIONS = 1
|
|
|
-+
|
|
|
-
|
|
|
- ############ Building LZO support ##############
|
|
|
- #
|
|
|
-@@ -197,6 +201,7 @@ INSTALL_MANPAGES_DIR ?= $(INSTALL_PREFIX
|
|
|
- LZMA_XZ_SUPPORT ?= 0
|
|
|
- LZMA_SUPPORT ?= 0
|
|
|
- LZMA_DIR ?= ../../../../LZMA/lzma465
|
|
|
-+XZ_EXTENDED_OPTIONS ?= 0
|
|
|
- endif
|
|
|
-
|
|
|
-
|
|
|
-@@ -248,8 +253,13 @@ endif
|
|
|
-
|
|
|
- ifeq ($(XZ_SUPPORT),1)
|
|
|
- CFLAGS += -DXZ_SUPPORT
|
|
|
-+ifeq ($(XZ_EXTENDED_OPTIONS),1)
|
|
|
-+MKSQUASHFS_OBJS += xz_wrapper_extended.o
|
|
|
-+UNSQUASHFS_OBJS += xz_wrapper_extended.o
|
|
|
-+else
|
|
|
- MKSQUASHFS_OBJS += xz_wrapper.o
|
|
|
- UNSQUASHFS_OBJS += xz_wrapper.o
|
|
|
-+endif
|
|
|
- LIBS += -llzma
|
|
|
- COMPRESSORS += xz
|
|
|
- endif
|
|
|
-@@ -428,6 +438,8 @@ lz4_wrapper.o: lz4_wrapper.c squashfs_fs
|
|
|
-
|
|
|
- xz_wrapper.o: xz_wrapper.c squashfs_fs.h xz_wrapper.h compressor.h
|
|
|
-
|
|
|
-+xz_wrapper_extended.o: xz_wrapper_extended.c squashfs_fs.h xz_wrapper.h compressor.h
|
|
|
-+
|
|
|
- unsquashfs: $(UNSQUASHFS_OBJS)
|
|
|
- $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(UNSQUASHFS_OBJS) $(LIBS) -o $@
|
|
|
- ln -sf unsquashfs sqfscat
|
|
|
---- a/squashfs-tools/xz_wrapper.c
|
|
|
-+++ b/squashfs-tools/xz_wrapper.c
|
|
|
-@@ -44,10 +44,7 @@ static struct bcj bcj[] = {
|
|
|
- static int filter_count = 1;
|
|
|
- static int dictionary_size = 0;
|
|
|
- static float dictionary_percent = 0;
|
|
|
--static int preset = LZMA_PRESET_DEFAULT;
|
|
|
--static int lc = -1;
|
|
|
--static int lp = -1;
|
|
|
--static int pb = -1;
|
|
|
-+
|
|
|
-
|
|
|
- /*
|
|
|
- * This function is called by the options parsing code in mksquashfs.c
|
|
|
-@@ -56,11 +53,6 @@ static int pb = -1;
|
|
|
- * Two specific options are supported:
|
|
|
- * -Xbcj
|
|
|
- * -Xdict-size
|
|
|
-- * -Xpreset
|
|
|
-- * -Xe
|
|
|
-- * -Xlc
|
|
|
-- * -Xlp
|
|
|
-- * -Xpb
|
|
|
- *
|
|
|
- * This function returns:
|
|
|
- * >=0 (number of additional args parsed) on success
|
|
|
-@@ -149,85 +141,6 @@ static int xz_options(char *argv[], int
|
|
|
- }
|
|
|
-
|
|
|
- return 1;
|
|
|
-- } else if(strcmp(argv[0], "-Xpreset") == 0) {
|
|
|
-- char *b;
|
|
|
-- long val;
|
|
|
--
|
|
|
-- if(argc < 2) {
|
|
|
-- fprintf(stderr, "xz: -Xpreset missing preset-level "
|
|
|
-- "(valid value 0-9)\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- val = strtol(argv[1], &b, 10);
|
|
|
-- if (*b != '\0' || (int) val < 0 || (int) val & ~LZMA_PRESET_LEVEL_MASK) {
|
|
|
-- fprintf(stderr, "xz: -Xpreset can't be "
|
|
|
-- "negative or more than the max preset\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- preset &= ~LZMA_PRESET_LEVEL_MASK;
|
|
|
-- preset |= (int) val;
|
|
|
--
|
|
|
-- return 1;
|
|
|
-- } else if(strcmp(argv[0], "-Xe") == 0) {
|
|
|
-- preset |= LZMA_PRESET_EXTREME;
|
|
|
--
|
|
|
-- return 0;
|
|
|
-- } else if(strcmp(argv[0], "-Xlc") == 0) {
|
|
|
-- char *b;
|
|
|
-- long val;
|
|
|
--
|
|
|
-- if(argc < 2) {
|
|
|
-- fprintf(stderr, "xz: -Xlc missing value\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- val = strtol(argv[1], &b, 10);
|
|
|
-- if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
|
|
|
-- fprintf(stderr, "xz: -Xlc invalid value\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- lc = (int) val;
|
|
|
--
|
|
|
-- return 1;
|
|
|
-- } else if(strcmp(argv[0], "-Xlp") == 0) {
|
|
|
-- char *b;
|
|
|
-- long val;
|
|
|
--
|
|
|
-- if(argc < 2) {
|
|
|
-- fprintf(stderr, "xz: -Xlp missing value\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- val = strtol(argv[1], &b, 10);
|
|
|
-- if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
|
|
|
-- fprintf(stderr, "xz: -Xlp invalid value\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- lp = (int) val;
|
|
|
--
|
|
|
-- return 1;
|
|
|
-- } else if(strcmp(argv[0], "-Xpb") == 0) {
|
|
|
-- char *b;
|
|
|
-- long val;
|
|
|
--
|
|
|
-- if(argc < 2) {
|
|
|
-- fprintf(stderr, "xz: -Xpb missing value\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- val = strtol(argv[1], &b, 10);
|
|
|
-- if (*b != '\0' || (int) val < LZMA_PB_MIN || (int) val > LZMA_PB_MAX) {
|
|
|
-- fprintf(stderr, "xz: -Xpb invalid value\n");
|
|
|
-- goto failed;
|
|
|
-- }
|
|
|
--
|
|
|
-- pb = (int) val;
|
|
|
--
|
|
|
-- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- return -1;
|
|
|
-@@ -533,20 +446,11 @@ static int xz_compress(void *strm, void
|
|
|
- for(i = 0; i < stream->filters; i++) {
|
|
|
- struct filter *filter = &stream->filter[i];
|
|
|
-
|
|
|
-- if(lzma_lzma_preset(&stream->opt, preset))
|
|
|
-+ if(lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT))
|
|
|
- goto failed;
|
|
|
-
|
|
|
- stream->opt.dict_size = stream->dictionary_size;
|
|
|
-
|
|
|
-- if (lc >= 0)
|
|
|
-- stream->opt.lc = lc;
|
|
|
--
|
|
|
-- if (lp >= 0)
|
|
|
-- stream->opt.lp = lp;
|
|
|
--
|
|
|
-- if (pb >= 0)
|
|
|
-- stream->opt.pb = pb;
|
|
|
--
|
|
|
- filter->length = 0;
|
|
|
- res = lzma_stream_buffer_encode(filter->filter,
|
|
|
- LZMA_CHECK_CRC32, NULL, src, size, filter->buffer,
|
|
|
-@@ -617,28 +521,13 @@ static void xz_usage(FILE *stream)
|
|
|
- fprintf(stream, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
|
|
|
- fprintf(stream, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
|
|
|
- fprintf(stream, " 32K, 16K, 8K\n\t\tetc.\n");
|
|
|
-- fprintf(stream, "\t -Xpreset <preset-level>\n");
|
|
|
-- fprintf(stream, "\t\tUse <preset-value> as the custom preset to use");
|
|
|
-- fprintf(stream, " on compress.\n\t\t<preset-level> should be 0 .. 9");
|
|
|
-- fprintf(stream, " (default 6)\n");
|
|
|
-- fprintf(stream, "\t -Xe\n");
|
|
|
-- fprintf(stream, "\t\tEnable additional compression settings by passing");
|
|
|
-- fprintf(stream, " the EXTREME\n\t\tflag to the compression flags.\n");
|
|
|
-- fprintf(stream, "\t -Xlc <value>\n");
|
|
|
-- fprintf(stream, "\t -Xlp <value>\n");
|
|
|
-- fprintf(stream, "\t -Xpb <value>\n");
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- static int option_args(char *option)
|
|
|
- {
|
|
|
- if(strcmp(option, "-Xbcj") == 0 ||
|
|
|
-- strcmp(option, "-Xdict-size") == 0 ||
|
|
|
-- strcmp(option, "-Xpreset") == 0 ||
|
|
|
-- strcmp(option, "-Xe") == 0 ||
|
|
|
-- strcmp(option, "-Xlc") == 0 ||
|
|
|
-- strcmp(option, "-Xlp") == 0 ||
|
|
|
-- strcmp(option, "-Xpb") == 0)
|
|
|
-+ strcmp(option, "-Xdict-size") == 0)
|
|
|
- return 1;
|
|
|
-
|
|
|
- return 0;
|
|
|
---- /dev/null
|
|
|
-+++ b/squashfs-tools/xz_wrapper_extended.c
|
|
|
-@@ -0,0 +1,664 @@
|
|
|
-+/*
|
|
|
-+ * Copyright (c) 2010, 2011, 2012, 2013, 2021, 2022
|
|
|
-+ * Phillip Lougher <[email protected]>
|
|
|
-+ *
|
|
|
-+ * This program is free software; you can redistribute it and/or
|
|
|
-+ * modify it under the terms of the GNU General Public License
|
|
|
-+ * as published by the Free Software Foundation; either version 2,
|
|
|
-+ * or (at your option) any later version.
|
|
|
-+ *
|
|
|
-+ * This program is distributed in the hope that it will be useful,
|
|
|
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+ * GNU General Public License for more details.
|
|
|
-+ *
|
|
|
-+ * You should have received a copy of the GNU General Public License
|
|
|
-+ * along with this program; if not, write to the Free Software
|
|
|
-+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
-+ *
|
|
|
-+ * xz_wrapper_extended.c
|
|
|
-+ *
|
|
|
-+ * Support for XZ (LZMA2) compression using XZ Utils liblzma
|
|
|
-+ * http://tukaani.org/xz/
|
|
|
-+ *
|
|
|
-+ * This file supports OpenWrt extended XZ compression options.
|
|
|
-+ */
|
|
|
-+
|
|
|
-+#include <stdio.h>
|
|
|
-+#include <string.h>
|
|
|
-+#include <stdlib.h>
|
|
|
-+#include <lzma.h>
|
|
|
-+
|
|
|
-+#include "squashfs_fs.h"
|
|
|
-+#include "xz_wrapper.h"
|
|
|
-+#include "compressor.h"
|
|
|
-+
|
|
|
-+static struct bcj bcj[] = {
|
|
|
-+ { "x86", LZMA_FILTER_X86, 0 },
|
|
|
-+ { "powerpc", LZMA_FILTER_POWERPC, 0 },
|
|
|
-+ { "ia64", LZMA_FILTER_IA64, 0 },
|
|
|
-+ { "arm", LZMA_FILTER_ARM, 0 },
|
|
|
-+ { "armthumb", LZMA_FILTER_ARMTHUMB, 0 },
|
|
|
-+ { "sparc", LZMA_FILTER_SPARC, 0 },
|
|
|
-+ { NULL, LZMA_VLI_UNKNOWN, 0 }
|
|
|
-+};
|
|
|
-+
|
|
|
-+static int filter_count = 1;
|
|
|
-+static int dictionary_size = 0;
|
|
|
-+static float dictionary_percent = 0;
|
|
|
-+static int preset = LZMA_PRESET_DEFAULT;
|
|
|
-+static int lc = -1;
|
|
|
-+static int lp = -1;
|
|
|
-+static int pb = -1;
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * This function is called by the options parsing code in mksquashfs.c
|
|
|
-+ * to parse any -X compressor option.
|
|
|
-+ *
|
|
|
-+ * Two specific options are supported:
|
|
|
-+ * -Xbcj
|
|
|
-+ * -Xdict-size
|
|
|
-+ * -Xpreset
|
|
|
-+ * -Xe
|
|
|
-+ * -Xlc
|
|
|
-+ * -Xlp
|
|
|
-+ * -Xpb
|
|
|
-+ *
|
|
|
-+ * This function returns:
|
|
|
-+ * >=0 (number of additional args parsed) on success
|
|
|
-+ * -1 if the option was unrecognised, or
|
|
|
-+ * -2 if the option was recognised, but otherwise bad in
|
|
|
-+ * some way (e.g. invalid parameter)
|
|
|
-+ *
|
|
|
-+ * Note: this function sets internal compressor state, but does not
|
|
|
-+ * pass back the results of the parsing other than success/failure.
|
|
|
-+ * The xz_dump_options() function is called later to get the options in
|
|
|
-+ * a format suitable for writing to the filesystem.
|
|
|
-+ */
|
|
|
-+static int xz_options(char *argv[], int argc)
|
|
|
-+{
|
|
|
-+ int i;
|
|
|
-+ char *name;
|
|
|
-+
|
|
|
-+ if(strcmp(argv[0], "-Xbcj") == 0) {
|
|
|
-+ if(argc < 2) {
|
|
|
-+ fprintf(stderr, "xz: -Xbcj missing filter\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ name = argv[1];
|
|
|
-+ while(name[0] != '\0') {
|
|
|
-+ for(i = 0; bcj[i].name; i++) {
|
|
|
-+ int n = strlen(bcj[i].name);
|
|
|
-+ if((strncmp(name, bcj[i].name, n) == 0) &&
|
|
|
-+ (name[n] == '\0' ||
|
|
|
-+ name[n] == ',')) {
|
|
|
-+ if(bcj[i].selected == 0) {
|
|
|
-+ bcj[i].selected = 1;
|
|
|
-+ filter_count++;
|
|
|
-+ }
|
|
|
-+ name += name[n] == ',' ? n + 1 : n;
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ if(bcj[i].name == NULL) {
|
|
|
-+ fprintf(stderr, "xz: -Xbcj unrecognised "
|
|
|
-+ "filter\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ } else if(strcmp(argv[0], "-Xdict-size") == 0) {
|
|
|
-+ char *b;
|
|
|
-+ float size;
|
|
|
-+
|
|
|
-+ if(argc < 2) {
|
|
|
-+ fprintf(stderr, "xz: -Xdict-size missing dict-size\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ size = strtof(argv[1], &b);
|
|
|
-+ if(*b == '%') {
|
|
|
-+ if(size <= 0 || size > 100) {
|
|
|
-+ fprintf(stderr, "xz: -Xdict-size percentage "
|
|
|
-+ "should be 0 < dict-size <= 100\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ dictionary_percent = size;
|
|
|
-+ dictionary_size = 0;
|
|
|
-+ } else {
|
|
|
-+ if((float) ((int) size) != size) {
|
|
|
-+ fprintf(stderr, "xz: -Xdict-size can't be "
|
|
|
-+ "fractional unless a percentage of the"
|
|
|
-+ " block size\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ dictionary_percent = 0;
|
|
|
-+ dictionary_size = (int) size;
|
|
|
-+
|
|
|
-+ if(*b == 'k' || *b == 'K')
|
|
|
-+ dictionary_size *= 1024;
|
|
|
-+ else if(*b == 'm' || *b == 'M')
|
|
|
-+ dictionary_size *= 1024 * 1024;
|
|
|
-+ else if(*b != '\0') {
|
|
|
-+ fprintf(stderr, "xz: -Xdict-size invalid "
|
|
|
-+ "dict-size\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ } else if(strcmp(argv[0], "-Xpreset") == 0) {
|
|
|
-+ char *b;
|
|
|
-+ long val;
|
|
|
-+
|
|
|
-+ if(argc < 2) {
|
|
|
-+ fprintf(stderr, "xz: -Xpreset missing preset-level "
|
|
|
-+ "(valid value 0-9)\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ val = strtol(argv[1], &b, 10);
|
|
|
-+ if (*b != '\0' || (int) val < 0 || (int) val & ~LZMA_PRESET_LEVEL_MASK) {
|
|
|
-+ fprintf(stderr, "xz: -Xpreset can't be "
|
|
|
-+ "negative or more than the max preset\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ preset &= ~LZMA_PRESET_LEVEL_MASK;
|
|
|
-+ preset |= (int) val;
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ } else if(strcmp(argv[0], "-Xe") == 0) {
|
|
|
-+ preset |= LZMA_PRESET_EXTREME;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+ } else if(strcmp(argv[0], "-Xlc") == 0) {
|
|
|
-+ char *b;
|
|
|
-+ long val;
|
|
|
-+
|
|
|
-+ if(argc < 2) {
|
|
|
-+ fprintf(stderr, "xz: -Xlc missing value\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ val = strtol(argv[1], &b, 10);
|
|
|
-+ if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
|
|
|
-+ fprintf(stderr, "xz: -Xlc invalid value\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ lc = (int) val;
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ } else if(strcmp(argv[0], "-Xlp") == 0) {
|
|
|
-+ char *b;
|
|
|
-+ long val;
|
|
|
-+
|
|
|
-+ if(argc < 2) {
|
|
|
-+ fprintf(stderr, "xz: -Xlp missing value\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ val = strtol(argv[1], &b, 10);
|
|
|
-+ if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
|
|
|
-+ fprintf(stderr, "xz: -Xlp invalid value\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ lp = (int) val;
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ } else if(strcmp(argv[0], "-Xpb") == 0) {
|
|
|
-+ char *b;
|
|
|
-+ long val;
|
|
|
-+
|
|
|
-+ if(argc < 2) {
|
|
|
-+ fprintf(stderr, "xz: -Xpb missing value\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ val = strtol(argv[1], &b, 10);
|
|
|
-+ if (*b != '\0' || (int) val < LZMA_PB_MIN || (int) val > LZMA_PB_MAX) {
|
|
|
-+ fprintf(stderr, "xz: -Xpb invalid value\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pb = (int) val;
|
|
|
-+
|
|
|
-+ return 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return -1;
|
|
|
-+
|
|
|
-+failed:
|
|
|
-+ return -2;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * This function is called after all options have been parsed.
|
|
|
-+ * It is used to do post-processing on the compressor options using
|
|
|
-+ * values that were not expected to be known at option parse time.
|
|
|
-+ *
|
|
|
-+ * In this case block_size may not be known until after -Xdict-size has
|
|
|
-+ * been processed (in the case where -b is specified after -Xdict-size)
|
|
|
-+ *
|
|
|
-+ * This function returns 0 on successful post processing, or
|
|
|
-+ * -1 on error
|
|
|
-+ */
|
|
|
-+static int xz_options_post(int block_size)
|
|
|
-+{
|
|
|
-+ /*
|
|
|
-+ * if -Xdict-size has been specified use this to compute the datablock
|
|
|
-+ * dictionary size
|
|
|
-+ */
|
|
|
-+ if(dictionary_size || dictionary_percent) {
|
|
|
-+ int n;
|
|
|
-+
|
|
|
-+ if(dictionary_size) {
|
|
|
-+ if(dictionary_size > block_size) {
|
|
|
-+ fprintf(stderr, "xz: -Xdict-size is larger than"
|
|
|
-+ " block_size\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+ } else
|
|
|
-+ dictionary_size = block_size * dictionary_percent / 100;
|
|
|
-+
|
|
|
-+ if(dictionary_size < 8192) {
|
|
|
-+ fprintf(stderr, "xz: -Xdict-size should be 8192 bytes "
|
|
|
-+ "or larger\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * dictionary_size must be storable in xz header as either
|
|
|
-+ * 2^n or as 2^n+2^(n+1)
|
|
|
-+ */
|
|
|
-+ n = ffs(dictionary_size) - 1;
|
|
|
-+ if(dictionary_size != (1 << n) &&
|
|
|
-+ dictionary_size != ((1 << n) + (1 << (n + 1)))) {
|
|
|
-+ fprintf(stderr, "xz: -Xdict-size is an unsupported "
|
|
|
-+ "value, dict-size must be storable in xz "
|
|
|
-+ "header\n");
|
|
|
-+ fprintf(stderr, "as either 2^n or as 2^n+2^(n+1). "
|
|
|
-+ "Example dict-sizes are 75%%, 50%%, 37.5%%, "
|
|
|
-+ "25%%,\n");
|
|
|
-+ fprintf(stderr, "or 32K, 16K, 8K etc.\n");
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ } else
|
|
|
-+ /* No -Xdict-size specified, use defaults */
|
|
|
-+ dictionary_size = block_size;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+failed:
|
|
|
-+ return -1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * This function is called by mksquashfs to dump the parsed
|
|
|
-+ * compressor options in a format suitable for writing to the
|
|
|
-+ * compressor options field in the filesystem (stored immediately
|
|
|
-+ * after the superblock).
|
|
|
-+ *
|
|
|
-+ * This function returns a pointer to the compression options structure
|
|
|
-+ * to be stored (and the size), or NULL if there are no compression
|
|
|
-+ * options
|
|
|
-+ */
|
|
|
-+static void *xz_dump_options(int block_size, int *size)
|
|
|
-+{
|
|
|
-+ static struct comp_opts comp_opts;
|
|
|
-+ int flags = 0, i;
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * don't store compressor specific options in file system if the
|
|
|
-+ * default options are being used - no compressor options in the
|
|
|
-+ * file system means the default options are always assumed
|
|
|
-+ *
|
|
|
-+ * Defaults are:
|
|
|
-+ * metadata dictionary size: SQUASHFS_METADATA_SIZE
|
|
|
-+ * datablock dictionary size: block_size
|
|
|
-+ * 1 filter
|
|
|
-+ */
|
|
|
-+ if(dictionary_size == block_size && filter_count == 1)
|
|
|
-+ return NULL;
|
|
|
-+
|
|
|
-+ for(i = 0; bcj[i].name; i++)
|
|
|
-+ flags |= bcj[i].selected << i;
|
|
|
-+
|
|
|
-+ comp_opts.dictionary_size = dictionary_size;
|
|
|
-+ comp_opts.flags = flags;
|
|
|
-+
|
|
|
-+ SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
|
|
|
-+
|
|
|
-+ *size = sizeof(comp_opts);
|
|
|
-+ return &comp_opts;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * This function is a helper specifically for the append mode of
|
|
|
-+ * mksquashfs. Its purpose is to set the internal compressor state
|
|
|
-+ * to the stored compressor options in the passed compressor options
|
|
|
-+ * structure.
|
|
|
-+ *
|
|
|
-+ * In effect this function sets up the compressor options
|
|
|
-+ * to the same state they were when the filesystem was originally
|
|
|
-+ * generated, this is to ensure on appending, the compressor uses
|
|
|
-+ * the same compression options that were used to generate the
|
|
|
-+ * original filesystem.
|
|
|
-+ *
|
|
|
-+ * Note, even if there are no compressor options, this function is still
|
|
|
-+ * called with an empty compressor structure (size == 0), to explicitly
|
|
|
-+ * set the default options, this is to ensure any user supplied
|
|
|
-+ * -X options on the appending mksquashfs command line are over-ridden
|
|
|
-+ *
|
|
|
-+ * This function returns 0 on sucessful extraction of options, and
|
|
|
-+ * -1 on error
|
|
|
-+ */
|
|
|
-+static int xz_extract_options(int block_size, void *buffer, int size)
|
|
|
-+{
|
|
|
-+ struct comp_opts *comp_opts = buffer;
|
|
|
-+ int flags, i, n;
|
|
|
-+
|
|
|
-+ if(size == 0) {
|
|
|
-+ /* set defaults */
|
|
|
-+ dictionary_size = block_size;
|
|
|
-+ flags = 0;
|
|
|
-+ } else {
|
|
|
-+ /* check passed comp opts struct is of the correct length */
|
|
|
-+ if(size != sizeof(struct comp_opts))
|
|
|
-+ goto failed;
|
|
|
-+
|
|
|
-+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
|
|
-+
|
|
|
-+ dictionary_size = comp_opts->dictionary_size;
|
|
|
-+ flags = comp_opts->flags;
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * check that the dictionary size seems correct - the dictionary
|
|
|
-+ * size should 2^n or 2^n+2^(n+1)
|
|
|
-+ */
|
|
|
-+ n = ffs(dictionary_size) - 1;
|
|
|
-+ if(dictionary_size != (1 << n) &&
|
|
|
-+ dictionary_size != ((1 << n) + (1 << (n + 1))))
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ filter_count = 1;
|
|
|
-+ for(i = 0; bcj[i].name; i++) {
|
|
|
-+ if((flags >> i) & 1) {
|
|
|
-+ bcj[i].selected = 1;
|
|
|
-+ filter_count ++;
|
|
|
-+ } else
|
|
|
-+ bcj[i].selected = 0;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+failed:
|
|
|
-+ fprintf(stderr, "xz: error reading stored compressor options from "
|
|
|
-+ "filesystem!\n");
|
|
|
-+
|
|
|
-+ return -1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static void xz_display_options(void *buffer, int size)
|
|
|
-+{
|
|
|
-+ struct comp_opts *comp_opts = buffer;
|
|
|
-+ int dictionary_size, flags, printed;
|
|
|
-+ int i, n;
|
|
|
-+
|
|
|
-+ /* check passed comp opts struct is of the correct length */
|
|
|
-+ if(size != sizeof(struct comp_opts))
|
|
|
-+ goto failed;
|
|
|
-+
|
|
|
-+ SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
|
|
|
-+
|
|
|
-+ dictionary_size = comp_opts->dictionary_size;
|
|
|
-+ flags = comp_opts->flags;
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * check that the dictionary size seems correct - the dictionary
|
|
|
-+ * size should 2^n or 2^n+2^(n+1)
|
|
|
-+ */
|
|
|
-+ n = ffs(dictionary_size) - 1;
|
|
|
-+ if(dictionary_size != (1 << n) &&
|
|
|
-+ dictionary_size != ((1 << n) + (1 << (n + 1))))
|
|
|
-+ goto failed;
|
|
|
-+
|
|
|
-+ printf("\tDictionary size %d\n", dictionary_size);
|
|
|
-+
|
|
|
-+ printed = 0;
|
|
|
-+ for(i = 0; bcj[i].name; i++) {
|
|
|
-+ if((flags >> i) & 1) {
|
|
|
-+ if(printed)
|
|
|
-+ printf(", ");
|
|
|
-+ else
|
|
|
-+ printf("\tFilters selected: ");
|
|
|
-+ printf("%s", bcj[i].name);
|
|
|
-+ printed = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if(!printed)
|
|
|
-+ printf("\tNo filters specified\n");
|
|
|
-+ else
|
|
|
-+ printf("\n");
|
|
|
-+
|
|
|
-+ return;
|
|
|
-+
|
|
|
-+failed:
|
|
|
-+ fprintf(stderr, "xz: error reading stored compressor options from "
|
|
|
-+ "filesystem!\n");
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * This function is called by mksquashfs to initialise the
|
|
|
-+ * compressor, before compress() is called.
|
|
|
-+ *
|
|
|
-+ * This function returns 0 on success, and
|
|
|
-+ * -1 on error
|
|
|
-+ */
|
|
|
-+static int xz_init(void **strm, int block_size, int datablock)
|
|
|
-+{
|
|
|
-+ int i, j, filters = datablock ? filter_count : 1;
|
|
|
-+ struct filter *filter = malloc(filters * sizeof(struct filter));
|
|
|
-+ struct xz_stream *stream;
|
|
|
-+
|
|
|
-+ if(filter == NULL)
|
|
|
-+ goto failed;
|
|
|
-+
|
|
|
-+ stream = *strm = malloc(sizeof(struct xz_stream));
|
|
|
-+ if(stream == NULL)
|
|
|
-+ goto failed2;
|
|
|
-+
|
|
|
-+ stream->filter = filter;
|
|
|
-+ stream->filters = filters;
|
|
|
-+
|
|
|
-+ memset(filter, 0, filters * sizeof(struct filter));
|
|
|
-+
|
|
|
-+ stream->dictionary_size = datablock ? dictionary_size :
|
|
|
-+ SQUASHFS_METADATA_SIZE;
|
|
|
-+
|
|
|
-+ filter[0].filter[0].id = LZMA_FILTER_LZMA2;
|
|
|
-+ filter[0].filter[0].options = &stream->opt;
|
|
|
-+ filter[0].filter[1].id = LZMA_VLI_UNKNOWN;
|
|
|
-+
|
|
|
-+ for(i = 0, j = 1; datablock && bcj[i].name; i++) {
|
|
|
-+ if(bcj[i].selected) {
|
|
|
-+ filter[j].buffer = malloc(block_size);
|
|
|
-+ if(filter[j].buffer == NULL)
|
|
|
-+ goto failed3;
|
|
|
-+ filter[j].filter[0].id = bcj[i].id;
|
|
|
-+ filter[j].filter[1].id = LZMA_FILTER_LZMA2;
|
|
|
-+ filter[j].filter[1].options = &stream->opt;
|
|
|
-+ filter[j].filter[2].id = LZMA_VLI_UNKNOWN;
|
|
|
-+ j++;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+failed3:
|
|
|
-+ for(i = 1; i < filters; i++)
|
|
|
-+ free(filter[i].buffer);
|
|
|
-+ free(stream);
|
|
|
-+
|
|
|
-+failed2:
|
|
|
-+ free(filter);
|
|
|
-+
|
|
|
-+failed:
|
|
|
-+ return -1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static int xz_compress(void *strm, void *dest, void *src, int size,
|
|
|
-+ int block_size, int *error)
|
|
|
-+{
|
|
|
-+ int i;
|
|
|
-+ lzma_ret res = 0;
|
|
|
-+ struct xz_stream *stream = strm;
|
|
|
-+ struct filter *selected = NULL;
|
|
|
-+
|
|
|
-+ stream->filter[0].buffer = dest;
|
|
|
-+
|
|
|
-+ for(i = 0; i < stream->filters; i++) {
|
|
|
-+ struct filter *filter = &stream->filter[i];
|
|
|
-+
|
|
|
-+ if(lzma_lzma_preset(&stream->opt, preset))
|
|
|
-+ goto failed;
|
|
|
-+
|
|
|
-+ stream->opt.dict_size = stream->dictionary_size;
|
|
|
-+
|
|
|
-+ if (lc >= 0)
|
|
|
-+ stream->opt.lc = lc;
|
|
|
-+
|
|
|
-+ if (lp >= 0)
|
|
|
-+ stream->opt.lp = lp;
|
|
|
-+
|
|
|
-+ if (pb >= 0)
|
|
|
-+ stream->opt.pb = pb;
|
|
|
-+
|
|
|
-+ filter->length = 0;
|
|
|
-+ res = lzma_stream_buffer_encode(filter->filter,
|
|
|
-+ LZMA_CHECK_CRC32, NULL, src, size, filter->buffer,
|
|
|
-+ &filter->length, block_size);
|
|
|
-+
|
|
|
-+ if(res == LZMA_OK) {
|
|
|
-+ if(!selected || selected->length > filter->length)
|
|
|
-+ selected = filter;
|
|
|
-+ } else if(res != LZMA_BUF_ERROR)
|
|
|
-+ goto failed;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if(!selected)
|
|
|
-+ /*
|
|
|
-+ * Output buffer overflow. Return out of buffer space
|
|
|
-+ */
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ if(selected->buffer != dest)
|
|
|
-+ memcpy(dest, selected->buffer, selected->length);
|
|
|
-+
|
|
|
-+ return (int) selected->length;
|
|
|
-+
|
|
|
-+failed:
|
|
|
-+ /*
|
|
|
-+ * All other errors return failure, with the compressor
|
|
|
-+ * specific error code in *error
|
|
|
-+ */
|
|
|
-+ *error = res;
|
|
|
-+ return -1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static int xz_uncompress(void *dest, void *src, int size, int outsize,
|
|
|
-+ int *error)
|
|
|
-+{
|
|
|
-+ size_t src_pos = 0;
|
|
|
-+ size_t dest_pos = 0;
|
|
|
-+ uint64_t memlimit = MEMLIMIT;
|
|
|
-+
|
|
|
-+ lzma_ret res = lzma_stream_buffer_decode(&memlimit, 0, NULL,
|
|
|
-+ src, &src_pos, size, dest, &dest_pos, outsize);
|
|
|
-+
|
|
|
-+ if(res == LZMA_OK && size == (int) src_pos)
|
|
|
-+ return (int) dest_pos;
|
|
|
-+ else {
|
|
|
-+ *error = res;
|
|
|
-+ return -1;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static void xz_usage(FILE *stream)
|
|
|
-+{
|
|
|
-+ fprintf(stream, "\t -Xbcj filter1,filter2,...,filterN\n");
|
|
|
-+ fprintf(stream, "\t\tCompress using filter1,filter2,...,filterN in");
|
|
|
-+ fprintf(stream, " turn\n\t\t(in addition to no filter), and choose");
|
|
|
-+ fprintf(stream, " the best compression.\n");
|
|
|
-+ fprintf(stream, "\t\tAvailable filters: x86, arm, armthumb,");
|
|
|
-+ fprintf(stream, " powerpc, sparc, ia64\n");
|
|
|
-+ fprintf(stream, "\t -Xdict-size <dict-size>\n");
|
|
|
-+ fprintf(stream, "\t\tUse <dict-size> as the XZ dictionary size. The");
|
|
|
-+ fprintf(stream, " dictionary size\n\t\tcan be specified as a");
|
|
|
-+ fprintf(stream, " percentage of the block size, or as an\n\t\t");
|
|
|
-+ fprintf(stream, "absolute value. The dictionary size must be less");
|
|
|
-+ fprintf(stream, " than or equal\n\t\tto the block size and 8192 bytes");
|
|
|
-+ fprintf(stream, " or larger. It must also be\n\t\tstorable in the xz");
|
|
|
-+ fprintf(stream, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
|
|
|
-+ fprintf(stream, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
|
|
|
-+ fprintf(stream, " 32K, 16K, 8K\n\t\tetc.\n");
|
|
|
-+ fprintf(stream, "\t -Xpreset <preset-level>\n");
|
|
|
-+ fprintf(stream, "\t\tUse <preset-value> as the custom preset to use");
|
|
|
-+ fprintf(stream, " on compress.\n\t\t<preset-level> should be 0 .. 9");
|
|
|
-+ fprintf(stream, " (default 6)\n");
|
|
|
-+ fprintf(stream, "\t -Xe\n");
|
|
|
-+ fprintf(stream, "\t\tEnable additional compression settings by passing");
|
|
|
-+ fprintf(stream, " the EXTREME\n\t\tflag to the compression flags.\n");
|
|
|
-+ fprintf(stream, "\t -Xlc <value>\n");
|
|
|
-+ fprintf(stream, "\t -Xlp <value>\n");
|
|
|
-+ fprintf(stream, "\t -Xpb <value>\n");
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static int option_args(char *option)
|
|
|
-+{
|
|
|
-+ if(strcmp(option, "-Xbcj") == 0 ||
|
|
|
-+ strcmp(option, "-Xdict-size") == 0 ||
|
|
|
-+ strcmp(option, "-Xpreset") == 0 ||
|
|
|
-+ strcmp(option, "-Xe") == 0 ||
|
|
|
-+ strcmp(option, "-Xlc") == 0 ||
|
|
|
-+ strcmp(option, "-Xlp") == 0 ||
|
|
|
-+ strcmp(option, "-Xpb") == 0)
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+struct compressor xz_comp_ops = {
|
|
|
-+ .init = xz_init,
|
|
|
-+ .compress = xz_compress,
|
|
|
-+ .uncompress = xz_uncompress,
|
|
|
-+ .options = xz_options,
|
|
|
-+ .options_post = xz_options_post,
|
|
|
-+ .dump_options = xz_dump_options,
|
|
|
-+ .extract_options = xz_extract_options,
|
|
|
-+ .display_options = xz_display_options,
|
|
|
-+ .usage = xz_usage,
|
|
|
-+ .option_args = option_args,
|
|
|
-+ .id = XZ_COMPRESSION,
|
|
|
-+ .name = "xz",
|
|
|
-+ .supported = 1
|
|
|
-+};
|