tools/squashfs4: backport OpenWrt extended options patch
[openwrt/staging/dedeckeh.git] / tools / squashfs4 / patches / 002-xz_wrapper-make-new-OpenWrt-extended-options-non-def.patch
1 From 5fb9fdfb8757fc9afb6318a3dcf9dce0a97de352 Mon Sep 17 00:00:00 2001
2 From: Phillip Lougher <phillip@squashfs.org.uk>
3 Date: Wed, 19 Apr 2023 18:35:53 +0100
4 Subject: [PATCH] xz_wrapper: make new OpenWrt extended options non-default
5
6 The reason why these options are being made non-default are
7 described here:
8
9 https://github.com/plougher/squashfs-tools/pull/218#issuecomment-1515197256
10
11 The new options can be enabled by editing the Makefile or by defining
12 XZ_EXTENDED_OPTIONS on the Make command line, e.g.
13
14 % CONFIG=1 XZ_SUPPORT=1 XZ_EXTENDED_OPTIONS=1 make
15
16 Signed-off-by: Phillip Lougher <phillip@squashfs.org.uk>
17 ---
18 squashfs-tools/Makefile | 12 +
19 squashfs-tools/xz_wrapper.c | 117 +----
20 squashfs-tools/xz_wrapper_extended.c | 664 +++++++++++++++++++++++++++
21 3 files changed, 679 insertions(+), 114 deletions(-)
22 create mode 100644 squashfs-tools/xz_wrapper_extended.c
23
24 --- a/squashfs-tools/Makefile
25 +++ b/squashfs-tools/Makefile
26 @@ -39,6 +39,10 @@ GZIP_SUPPORT = 1
27 #
28 #XZ_SUPPORT = 1
29
30 +# Enable support for OpenWrt extended compression options by uncommenting
31 +# next line. Do not do this unless you understand the implications.
32 +#XZ_EXTENDED_OPTIONS = 1
33 +
34
35 ############ Building LZO support ##############
36 #
37 @@ -197,6 +201,7 @@ INSTALL_MANPAGES_DIR ?= $(INSTALL_PREFIX
38 LZMA_XZ_SUPPORT ?= 0
39 LZMA_SUPPORT ?= 0
40 LZMA_DIR ?= ../../../../LZMA/lzma465
41 +XZ_EXTENDED_OPTIONS ?= 0
42 endif
43
44
45 @@ -248,8 +253,13 @@ endif
46
47 ifeq ($(XZ_SUPPORT),1)
48 CFLAGS += -DXZ_SUPPORT
49 +ifeq ($(XZ_EXTENDED_OPTIONS),1)
50 +MKSQUASHFS_OBJS += xz_wrapper_extended.o
51 +UNSQUASHFS_OBJS += xz_wrapper_extended.o
52 +else
53 MKSQUASHFS_OBJS += xz_wrapper.o
54 UNSQUASHFS_OBJS += xz_wrapper.o
55 +endif
56 LIBS += -llzma
57 COMPRESSORS += xz
58 endif
59 @@ -428,6 +438,8 @@ lz4_wrapper.o: lz4_wrapper.c squashfs_fs
60
61 xz_wrapper.o: xz_wrapper.c squashfs_fs.h xz_wrapper.h compressor.h
62
63 +xz_wrapper_extended.o: xz_wrapper_extended.c squashfs_fs.h xz_wrapper.h compressor.h
64 +
65 unsquashfs: $(UNSQUASHFS_OBJS)
66 $(CC) $(LDFLAGS) $(EXTRA_LDFLAGS) $(UNSQUASHFS_OBJS) $(LIBS) -o $@
67 ln -sf unsquashfs sqfscat
68 --- a/squashfs-tools/xz_wrapper.c
69 +++ b/squashfs-tools/xz_wrapper.c
70 @@ -44,10 +44,7 @@ static struct bcj bcj[] = {
71 static int filter_count = 1;
72 static int dictionary_size = 0;
73 static float dictionary_percent = 0;
74 -static int preset = LZMA_PRESET_DEFAULT;
75 -static int lc = -1;
76 -static int lp = -1;
77 -static int pb = -1;
78 +
79
80 /*
81 * This function is called by the options parsing code in mksquashfs.c
82 @@ -56,11 +53,6 @@ static int pb = -1;
83 * Two specific options are supported:
84 * -Xbcj
85 * -Xdict-size
86 - * -Xpreset
87 - * -Xe
88 - * -Xlc
89 - * -Xlp
90 - * -Xpb
91 *
92 * This function returns:
93 * >=0 (number of additional args parsed) on success
94 @@ -149,85 +141,6 @@ static int xz_options(char *argv[], int
95 }
96
97 return 1;
98 - } else if(strcmp(argv[0], "-Xpreset") == 0) {
99 - char *b;
100 - long val;
101 -
102 - if(argc < 2) {
103 - fprintf(stderr, "xz: -Xpreset missing preset-level "
104 - "(valid value 0-9)\n");
105 - goto failed;
106 - }
107 -
108 - val = strtol(argv[1], &b, 10);
109 - if (*b != '\0' || (int) val < 0 || (int) val & ~LZMA_PRESET_LEVEL_MASK) {
110 - fprintf(stderr, "xz: -Xpreset can't be "
111 - "negative or more than the max preset\n");
112 - goto failed;
113 - }
114 -
115 - preset &= ~LZMA_PRESET_LEVEL_MASK;
116 - preset |= (int) val;
117 -
118 - return 1;
119 - } else if(strcmp(argv[0], "-Xe") == 0) {
120 - preset |= LZMA_PRESET_EXTREME;
121 -
122 - return 0;
123 - } else if(strcmp(argv[0], "-Xlc") == 0) {
124 - char *b;
125 - long val;
126 -
127 - if(argc < 2) {
128 - fprintf(stderr, "xz: -Xlc missing value\n");
129 - goto failed;
130 - }
131 -
132 - val = strtol(argv[1], &b, 10);
133 - if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
134 - fprintf(stderr, "xz: -Xlc invalid value\n");
135 - goto failed;
136 - }
137 -
138 - lc = (int) val;
139 -
140 - return 1;
141 - } else if(strcmp(argv[0], "-Xlp") == 0) {
142 - char *b;
143 - long val;
144 -
145 - if(argc < 2) {
146 - fprintf(stderr, "xz: -Xlp missing value\n");
147 - goto failed;
148 - }
149 -
150 - val = strtol(argv[1], &b, 10);
151 - if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
152 - fprintf(stderr, "xz: -Xlp invalid value\n");
153 - goto failed;
154 - }
155 -
156 - lp = (int) val;
157 -
158 - return 1;
159 - } else if(strcmp(argv[0], "-Xpb") == 0) {
160 - char *b;
161 - long val;
162 -
163 - if(argc < 2) {
164 - fprintf(stderr, "xz: -Xpb missing value\n");
165 - goto failed;
166 - }
167 -
168 - val = strtol(argv[1], &b, 10);
169 - if (*b != '\0' || (int) val < LZMA_PB_MIN || (int) val > LZMA_PB_MAX) {
170 - fprintf(stderr, "xz: -Xpb invalid value\n");
171 - goto failed;
172 - }
173 -
174 - pb = (int) val;
175 -
176 - return 1;
177 }
178
179 return -1;
180 @@ -533,20 +446,11 @@ static int xz_compress(void *strm, void
181 for(i = 0; i < stream->filters; i++) {
182 struct filter *filter = &stream->filter[i];
183
184 - if(lzma_lzma_preset(&stream->opt, preset))
185 + if(lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT))
186 goto failed;
187
188 stream->opt.dict_size = stream->dictionary_size;
189
190 - if (lc >= 0)
191 - stream->opt.lc = lc;
192 -
193 - if (lp >= 0)
194 - stream->opt.lp = lp;
195 -
196 - if (pb >= 0)
197 - stream->opt.pb = pb;
198 -
199 filter->length = 0;
200 res = lzma_stream_buffer_encode(filter->filter,
201 LZMA_CHECK_CRC32, NULL, src, size, filter->buffer,
202 @@ -617,28 +521,13 @@ static void xz_usage(FILE *stream)
203 fprintf(stream, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
204 fprintf(stream, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
205 fprintf(stream, " 32K, 16K, 8K\n\t\tetc.\n");
206 - fprintf(stream, "\t -Xpreset <preset-level>\n");
207 - fprintf(stream, "\t\tUse <preset-value> as the custom preset to use");
208 - fprintf(stream, " on compress.\n\t\t<preset-level> should be 0 .. 9");
209 - fprintf(stream, " (default 6)\n");
210 - fprintf(stream, "\t -Xe\n");
211 - fprintf(stream, "\t\tEnable additional compression settings by passing");
212 - fprintf(stream, " the EXTREME\n\t\tflag to the compression flags.\n");
213 - fprintf(stream, "\t -Xlc <value>\n");
214 - fprintf(stream, "\t -Xlp <value>\n");
215 - fprintf(stream, "\t -Xpb <value>\n");
216 }
217
218
219 static int option_args(char *option)
220 {
221 if(strcmp(option, "-Xbcj") == 0 ||
222 - strcmp(option, "-Xdict-size") == 0 ||
223 - strcmp(option, "-Xpreset") == 0 ||
224 - strcmp(option, "-Xe") == 0 ||
225 - strcmp(option, "-Xlc") == 0 ||
226 - strcmp(option, "-Xlp") == 0 ||
227 - strcmp(option, "-Xpb") == 0)
228 + strcmp(option, "-Xdict-size") == 0)
229 return 1;
230
231 return 0;
232 --- /dev/null
233 +++ b/squashfs-tools/xz_wrapper_extended.c
234 @@ -0,0 +1,664 @@
235 +/*
236 + * Copyright (c) 2010, 2011, 2012, 2013, 2021, 2022
237 + * Phillip Lougher <phillip@squashfs.org.uk>
238 + *
239 + * This program is free software; you can redistribute it and/or
240 + * modify it under the terms of the GNU General Public License
241 + * as published by the Free Software Foundation; either version 2,
242 + * or (at your option) any later version.
243 + *
244 + * This program is distributed in the hope that it will be useful,
245 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
246 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
247 + * GNU General Public License for more details.
248 + *
249 + * You should have received a copy of the GNU General Public License
250 + * along with this program; if not, write to the Free Software
251 + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
252 + *
253 + * xz_wrapper_extended.c
254 + *
255 + * Support for XZ (LZMA2) compression using XZ Utils liblzma
256 + * http://tukaani.org/xz/
257 + *
258 + * This file supports OpenWrt extended XZ compression options.
259 + */
260 +
261 +#include <stdio.h>
262 +#include <string.h>
263 +#include <stdlib.h>
264 +#include <lzma.h>
265 +
266 +#include "squashfs_fs.h"
267 +#include "xz_wrapper.h"
268 +#include "compressor.h"
269 +
270 +static struct bcj bcj[] = {
271 + { "x86", LZMA_FILTER_X86, 0 },
272 + { "powerpc", LZMA_FILTER_POWERPC, 0 },
273 + { "ia64", LZMA_FILTER_IA64, 0 },
274 + { "arm", LZMA_FILTER_ARM, 0 },
275 + { "armthumb", LZMA_FILTER_ARMTHUMB, 0 },
276 + { "sparc", LZMA_FILTER_SPARC, 0 },
277 + { NULL, LZMA_VLI_UNKNOWN, 0 }
278 +};
279 +
280 +static int filter_count = 1;
281 +static int dictionary_size = 0;
282 +static float dictionary_percent = 0;
283 +static int preset = LZMA_PRESET_DEFAULT;
284 +static int lc = -1;
285 +static int lp = -1;
286 +static int pb = -1;
287 +
288 +/*
289 + * This function is called by the options parsing code in mksquashfs.c
290 + * to parse any -X compressor option.
291 + *
292 + * Two specific options are supported:
293 + * -Xbcj
294 + * -Xdict-size
295 + * -Xpreset
296 + * -Xe
297 + * -Xlc
298 + * -Xlp
299 + * -Xpb
300 + *
301 + * This function returns:
302 + * >=0 (number of additional args parsed) on success
303 + * -1 if the option was unrecognised, or
304 + * -2 if the option was recognised, but otherwise bad in
305 + * some way (e.g. invalid parameter)
306 + *
307 + * Note: this function sets internal compressor state, but does not
308 + * pass back the results of the parsing other than success/failure.
309 + * The xz_dump_options() function is called later to get the options in
310 + * a format suitable for writing to the filesystem.
311 + */
312 +static int xz_options(char *argv[], int argc)
313 +{
314 + int i;
315 + char *name;
316 +
317 + if(strcmp(argv[0], "-Xbcj") == 0) {
318 + if(argc < 2) {
319 + fprintf(stderr, "xz: -Xbcj missing filter\n");
320 + goto failed;
321 + }
322 +
323 + name = argv[1];
324 + while(name[0] != '\0') {
325 + for(i = 0; bcj[i].name; i++) {
326 + int n = strlen(bcj[i].name);
327 + if((strncmp(name, bcj[i].name, n) == 0) &&
328 + (name[n] == '\0' ||
329 + name[n] == ',')) {
330 + if(bcj[i].selected == 0) {
331 + bcj[i].selected = 1;
332 + filter_count++;
333 + }
334 + name += name[n] == ',' ? n + 1 : n;
335 + break;
336 + }
337 + }
338 + if(bcj[i].name == NULL) {
339 + fprintf(stderr, "xz: -Xbcj unrecognised "
340 + "filter\n");
341 + goto failed;
342 + }
343 + }
344 +
345 + return 1;
346 + } else if(strcmp(argv[0], "-Xdict-size") == 0) {
347 + char *b;
348 + float size;
349 +
350 + if(argc < 2) {
351 + fprintf(stderr, "xz: -Xdict-size missing dict-size\n");
352 + goto failed;
353 + }
354 +
355 + size = strtof(argv[1], &b);
356 + if(*b == '%') {
357 + if(size <= 0 || size > 100) {
358 + fprintf(stderr, "xz: -Xdict-size percentage "
359 + "should be 0 < dict-size <= 100\n");
360 + goto failed;
361 + }
362 +
363 + dictionary_percent = size;
364 + dictionary_size = 0;
365 + } else {
366 + if((float) ((int) size) != size) {
367 + fprintf(stderr, "xz: -Xdict-size can't be "
368 + "fractional unless a percentage of the"
369 + " block size\n");
370 + goto failed;
371 + }
372 +
373 + dictionary_percent = 0;
374 + dictionary_size = (int) size;
375 +
376 + if(*b == 'k' || *b == 'K')
377 + dictionary_size *= 1024;
378 + else if(*b == 'm' || *b == 'M')
379 + dictionary_size *= 1024 * 1024;
380 + else if(*b != '\0') {
381 + fprintf(stderr, "xz: -Xdict-size invalid "
382 + "dict-size\n");
383 + goto failed;
384 + }
385 + }
386 +
387 + return 1;
388 + } else if(strcmp(argv[0], "-Xpreset") == 0) {
389 + char *b;
390 + long val;
391 +
392 + if(argc < 2) {
393 + fprintf(stderr, "xz: -Xpreset missing preset-level "
394 + "(valid value 0-9)\n");
395 + goto failed;
396 + }
397 +
398 + val = strtol(argv[1], &b, 10);
399 + if (*b != '\0' || (int) val < 0 || (int) val & ~LZMA_PRESET_LEVEL_MASK) {
400 + fprintf(stderr, "xz: -Xpreset can't be "
401 + "negative or more than the max preset\n");
402 + goto failed;
403 + }
404 +
405 + preset &= ~LZMA_PRESET_LEVEL_MASK;
406 + preset |= (int) val;
407 +
408 + return 1;
409 + } else if(strcmp(argv[0], "-Xe") == 0) {
410 + preset |= LZMA_PRESET_EXTREME;
411 +
412 + return 0;
413 + } else if(strcmp(argv[0], "-Xlc") == 0) {
414 + char *b;
415 + long val;
416 +
417 + if(argc < 2) {
418 + fprintf(stderr, "xz: -Xlc missing value\n");
419 + goto failed;
420 + }
421 +
422 + val = strtol(argv[1], &b, 10);
423 + if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
424 + fprintf(stderr, "xz: -Xlc invalid value\n");
425 + goto failed;
426 + }
427 +
428 + lc = (int) val;
429 +
430 + return 1;
431 + } else if(strcmp(argv[0], "-Xlp") == 0) {
432 + char *b;
433 + long val;
434 +
435 + if(argc < 2) {
436 + fprintf(stderr, "xz: -Xlp missing value\n");
437 + goto failed;
438 + }
439 +
440 + val = strtol(argv[1], &b, 10);
441 + if (*b != '\0' || (int) val < LZMA_LCLP_MIN || (int) val > LZMA_LCLP_MAX) {
442 + fprintf(stderr, "xz: -Xlp invalid value\n");
443 + goto failed;
444 + }
445 +
446 + lp = (int) val;
447 +
448 + return 1;
449 + } else if(strcmp(argv[0], "-Xpb") == 0) {
450 + char *b;
451 + long val;
452 +
453 + if(argc < 2) {
454 + fprintf(stderr, "xz: -Xpb missing value\n");
455 + goto failed;
456 + }
457 +
458 + val = strtol(argv[1], &b, 10);
459 + if (*b != '\0' || (int) val < LZMA_PB_MIN || (int) val > LZMA_PB_MAX) {
460 + fprintf(stderr, "xz: -Xpb invalid value\n");
461 + goto failed;
462 + }
463 +
464 + pb = (int) val;
465 +
466 + return 1;
467 + }
468 +
469 + return -1;
470 +
471 +failed:
472 + return -2;
473 +}
474 +
475 +
476 +/*
477 + * This function is called after all options have been parsed.
478 + * It is used to do post-processing on the compressor options using
479 + * values that were not expected to be known at option parse time.
480 + *
481 + * In this case block_size may not be known until after -Xdict-size has
482 + * been processed (in the case where -b is specified after -Xdict-size)
483 + *
484 + * This function returns 0 on successful post processing, or
485 + * -1 on error
486 + */
487 +static int xz_options_post(int block_size)
488 +{
489 + /*
490 + * if -Xdict-size has been specified use this to compute the datablock
491 + * dictionary size
492 + */
493 + if(dictionary_size || dictionary_percent) {
494 + int n;
495 +
496 + if(dictionary_size) {
497 + if(dictionary_size > block_size) {
498 + fprintf(stderr, "xz: -Xdict-size is larger than"
499 + " block_size\n");
500 + goto failed;
501 + }
502 + } else
503 + dictionary_size = block_size * dictionary_percent / 100;
504 +
505 + if(dictionary_size < 8192) {
506 + fprintf(stderr, "xz: -Xdict-size should be 8192 bytes "
507 + "or larger\n");
508 + goto failed;
509 + }
510 +
511 + /*
512 + * dictionary_size must be storable in xz header as either
513 + * 2^n or as 2^n+2^(n+1)
514 + */
515 + n = ffs(dictionary_size) - 1;
516 + if(dictionary_size != (1 << n) &&
517 + dictionary_size != ((1 << n) + (1 << (n + 1)))) {
518 + fprintf(stderr, "xz: -Xdict-size is an unsupported "
519 + "value, dict-size must be storable in xz "
520 + "header\n");
521 + fprintf(stderr, "as either 2^n or as 2^n+2^(n+1). "
522 + "Example dict-sizes are 75%%, 50%%, 37.5%%, "
523 + "25%%,\n");
524 + fprintf(stderr, "or 32K, 16K, 8K etc.\n");
525 + goto failed;
526 + }
527 +
528 + } else
529 + /* No -Xdict-size specified, use defaults */
530 + dictionary_size = block_size;
531 +
532 + return 0;
533 +
534 +failed:
535 + return -1;
536 +}
537 +
538 +
539 +/*
540 + * This function is called by mksquashfs to dump the parsed
541 + * compressor options in a format suitable for writing to the
542 + * compressor options field in the filesystem (stored immediately
543 + * after the superblock).
544 + *
545 + * This function returns a pointer to the compression options structure
546 + * to be stored (and the size), or NULL if there are no compression
547 + * options
548 + */
549 +static void *xz_dump_options(int block_size, int *size)
550 +{
551 + static struct comp_opts comp_opts;
552 + int flags = 0, i;
553 +
554 + /*
555 + * don't store compressor specific options in file system if the
556 + * default options are being used - no compressor options in the
557 + * file system means the default options are always assumed
558 + *
559 + * Defaults are:
560 + * metadata dictionary size: SQUASHFS_METADATA_SIZE
561 + * datablock dictionary size: block_size
562 + * 1 filter
563 + */
564 + if(dictionary_size == block_size && filter_count == 1)
565 + return NULL;
566 +
567 + for(i = 0; bcj[i].name; i++)
568 + flags |= bcj[i].selected << i;
569 +
570 + comp_opts.dictionary_size = dictionary_size;
571 + comp_opts.flags = flags;
572 +
573 + SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
574 +
575 + *size = sizeof(comp_opts);
576 + return &comp_opts;
577 +}
578 +
579 +
580 +/*
581 + * This function is a helper specifically for the append mode of
582 + * mksquashfs. Its purpose is to set the internal compressor state
583 + * to the stored compressor options in the passed compressor options
584 + * structure.
585 + *
586 + * In effect this function sets up the compressor options
587 + * to the same state they were when the filesystem was originally
588 + * generated, this is to ensure on appending, the compressor uses
589 + * the same compression options that were used to generate the
590 + * original filesystem.
591 + *
592 + * Note, even if there are no compressor options, this function is still
593 + * called with an empty compressor structure (size == 0), to explicitly
594 + * set the default options, this is to ensure any user supplied
595 + * -X options on the appending mksquashfs command line are over-ridden
596 + *
597 + * This function returns 0 on sucessful extraction of options, and
598 + * -1 on error
599 + */
600 +static int xz_extract_options(int block_size, void *buffer, int size)
601 +{
602 + struct comp_opts *comp_opts = buffer;
603 + int flags, i, n;
604 +
605 + if(size == 0) {
606 + /* set defaults */
607 + dictionary_size = block_size;
608 + flags = 0;
609 + } else {
610 + /* check passed comp opts struct is of the correct length */
611 + if(size != sizeof(struct comp_opts))
612 + goto failed;
613 +
614 + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
615 +
616 + dictionary_size = comp_opts->dictionary_size;
617 + flags = comp_opts->flags;
618 +
619 + /*
620 + * check that the dictionary size seems correct - the dictionary
621 + * size should 2^n or 2^n+2^(n+1)
622 + */
623 + n = ffs(dictionary_size) - 1;
624 + if(dictionary_size != (1 << n) &&
625 + dictionary_size != ((1 << n) + (1 << (n + 1))))
626 + goto failed;
627 + }
628 +
629 + filter_count = 1;
630 + for(i = 0; bcj[i].name; i++) {
631 + if((flags >> i) & 1) {
632 + bcj[i].selected = 1;
633 + filter_count ++;
634 + } else
635 + bcj[i].selected = 0;
636 + }
637 +
638 + return 0;
639 +
640 +failed:
641 + fprintf(stderr, "xz: error reading stored compressor options from "
642 + "filesystem!\n");
643 +
644 + return -1;
645 +}
646 +
647 +
648 +static void xz_display_options(void *buffer, int size)
649 +{
650 + struct comp_opts *comp_opts = buffer;
651 + int dictionary_size, flags, printed;
652 + int i, n;
653 +
654 + /* check passed comp opts struct is of the correct length */
655 + if(size != sizeof(struct comp_opts))
656 + goto failed;
657 +
658 + SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
659 +
660 + dictionary_size = comp_opts->dictionary_size;
661 + flags = comp_opts->flags;
662 +
663 + /*
664 + * check that the dictionary size seems correct - the dictionary
665 + * size should 2^n or 2^n+2^(n+1)
666 + */
667 + n = ffs(dictionary_size) - 1;
668 + if(dictionary_size != (1 << n) &&
669 + dictionary_size != ((1 << n) + (1 << (n + 1))))
670 + goto failed;
671 +
672 + printf("\tDictionary size %d\n", dictionary_size);
673 +
674 + printed = 0;
675 + for(i = 0; bcj[i].name; i++) {
676 + if((flags >> i) & 1) {
677 + if(printed)
678 + printf(", ");
679 + else
680 + printf("\tFilters selected: ");
681 + printf("%s", bcj[i].name);
682 + printed = 1;
683 + }
684 + }
685 +
686 + if(!printed)
687 + printf("\tNo filters specified\n");
688 + else
689 + printf("\n");
690 +
691 + return;
692 +
693 +failed:
694 + fprintf(stderr, "xz: error reading stored compressor options from "
695 + "filesystem!\n");
696 +}
697 +
698 +
699 +/*
700 + * This function is called by mksquashfs to initialise the
701 + * compressor, before compress() is called.
702 + *
703 + * This function returns 0 on success, and
704 + * -1 on error
705 + */
706 +static int xz_init(void **strm, int block_size, int datablock)
707 +{
708 + int i, j, filters = datablock ? filter_count : 1;
709 + struct filter *filter = malloc(filters * sizeof(struct filter));
710 + struct xz_stream *stream;
711 +
712 + if(filter == NULL)
713 + goto failed;
714 +
715 + stream = *strm = malloc(sizeof(struct xz_stream));
716 + if(stream == NULL)
717 + goto failed2;
718 +
719 + stream->filter = filter;
720 + stream->filters = filters;
721 +
722 + memset(filter, 0, filters * sizeof(struct filter));
723 +
724 + stream->dictionary_size = datablock ? dictionary_size :
725 + SQUASHFS_METADATA_SIZE;
726 +
727 + filter[0].filter[0].id = LZMA_FILTER_LZMA2;
728 + filter[0].filter[0].options = &stream->opt;
729 + filter[0].filter[1].id = LZMA_VLI_UNKNOWN;
730 +
731 + for(i = 0, j = 1; datablock && bcj[i].name; i++) {
732 + if(bcj[i].selected) {
733 + filter[j].buffer = malloc(block_size);
734 + if(filter[j].buffer == NULL)
735 + goto failed3;
736 + filter[j].filter[0].id = bcj[i].id;
737 + filter[j].filter[1].id = LZMA_FILTER_LZMA2;
738 + filter[j].filter[1].options = &stream->opt;
739 + filter[j].filter[2].id = LZMA_VLI_UNKNOWN;
740 + j++;
741 + }
742 + }
743 +
744 + return 0;
745 +
746 +failed3:
747 + for(i = 1; i < filters; i++)
748 + free(filter[i].buffer);
749 + free(stream);
750 +
751 +failed2:
752 + free(filter);
753 +
754 +failed:
755 + return -1;
756 +}
757 +
758 +
759 +static int xz_compress(void *strm, void *dest, void *src, int size,
760 + int block_size, int *error)
761 +{
762 + int i;
763 + lzma_ret res = 0;
764 + struct xz_stream *stream = strm;
765 + struct filter *selected = NULL;
766 +
767 + stream->filter[0].buffer = dest;
768 +
769 + for(i = 0; i < stream->filters; i++) {
770 + struct filter *filter = &stream->filter[i];
771 +
772 + if(lzma_lzma_preset(&stream->opt, preset))
773 + goto failed;
774 +
775 + stream->opt.dict_size = stream->dictionary_size;
776 +
777 + if (lc >= 0)
778 + stream->opt.lc = lc;
779 +
780 + if (lp >= 0)
781 + stream->opt.lp = lp;
782 +
783 + if (pb >= 0)
784 + stream->opt.pb = pb;
785 +
786 + filter->length = 0;
787 + res = lzma_stream_buffer_encode(filter->filter,
788 + LZMA_CHECK_CRC32, NULL, src, size, filter->buffer,
789 + &filter->length, block_size);
790 +
791 + if(res == LZMA_OK) {
792 + if(!selected || selected->length > filter->length)
793 + selected = filter;
794 + } else if(res != LZMA_BUF_ERROR)
795 + goto failed;
796 + }
797 +
798 + if(!selected)
799 + /*
800 + * Output buffer overflow. Return out of buffer space
801 + */
802 + return 0;
803 +
804 + if(selected->buffer != dest)
805 + memcpy(dest, selected->buffer, selected->length);
806 +
807 + return (int) selected->length;
808 +
809 +failed:
810 + /*
811 + * All other errors return failure, with the compressor
812 + * specific error code in *error
813 + */
814 + *error = res;
815 + return -1;
816 +}
817 +
818 +
819 +static int xz_uncompress(void *dest, void *src, int size, int outsize,
820 + int *error)
821 +{
822 + size_t src_pos = 0;
823 + size_t dest_pos = 0;
824 + uint64_t memlimit = MEMLIMIT;
825 +
826 + lzma_ret res = lzma_stream_buffer_decode(&memlimit, 0, NULL,
827 + src, &src_pos, size, dest, &dest_pos, outsize);
828 +
829 + if(res == LZMA_OK && size == (int) src_pos)
830 + return (int) dest_pos;
831 + else {
832 + *error = res;
833 + return -1;
834 + }
835 +}
836 +
837 +
838 +static void xz_usage(FILE *stream)
839 +{
840 + fprintf(stream, "\t -Xbcj filter1,filter2,...,filterN\n");
841 + fprintf(stream, "\t\tCompress using filter1,filter2,...,filterN in");
842 + fprintf(stream, " turn\n\t\t(in addition to no filter), and choose");
843 + fprintf(stream, " the best compression.\n");
844 + fprintf(stream, "\t\tAvailable filters: x86, arm, armthumb,");
845 + fprintf(stream, " powerpc, sparc, ia64\n");
846 + fprintf(stream, "\t -Xdict-size <dict-size>\n");
847 + fprintf(stream, "\t\tUse <dict-size> as the XZ dictionary size. The");
848 + fprintf(stream, " dictionary size\n\t\tcan be specified as a");
849 + fprintf(stream, " percentage of the block size, or as an\n\t\t");
850 + fprintf(stream, "absolute value. The dictionary size must be less");
851 + fprintf(stream, " than or equal\n\t\tto the block size and 8192 bytes");
852 + fprintf(stream, " or larger. It must also be\n\t\tstorable in the xz");
853 + fprintf(stream, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
854 + fprintf(stream, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
855 + fprintf(stream, " 32K, 16K, 8K\n\t\tetc.\n");
856 + fprintf(stream, "\t -Xpreset <preset-level>\n");
857 + fprintf(stream, "\t\tUse <preset-value> as the custom preset to use");
858 + fprintf(stream, " on compress.\n\t\t<preset-level> should be 0 .. 9");
859 + fprintf(stream, " (default 6)\n");
860 + fprintf(stream, "\t -Xe\n");
861 + fprintf(stream, "\t\tEnable additional compression settings by passing");
862 + fprintf(stream, " the EXTREME\n\t\tflag to the compression flags.\n");
863 + fprintf(stream, "\t -Xlc <value>\n");
864 + fprintf(stream, "\t -Xlp <value>\n");
865 + fprintf(stream, "\t -Xpb <value>\n");
866 +}
867 +
868 +
869 +static int option_args(char *option)
870 +{
871 + if(strcmp(option, "-Xbcj") == 0 ||
872 + strcmp(option, "-Xdict-size") == 0 ||
873 + strcmp(option, "-Xpreset") == 0 ||
874 + strcmp(option, "-Xe") == 0 ||
875 + strcmp(option, "-Xlc") == 0 ||
876 + strcmp(option, "-Xlp") == 0 ||
877 + strcmp(option, "-Xpb") == 0)
878 + return 1;
879 +
880 + return 0;
881 +}
882 +
883 +
884 +struct compressor xz_comp_ops = {
885 + .init = xz_init,
886 + .compress = xz_compress,
887 + .uncompress = xz_uncompress,
888 + .options = xz_options,
889 + .options_post = xz_options_post,
890 + .dump_options = xz_dump_options,
891 + .extract_options = xz_extract_options,
892 + .display_options = xz_display_options,
893 + .usage = xz_usage,
894 + .option_args = option_args,
895 + .id = XZ_COMPRESSION,
896 + .name = "xz",
897 + .supported = 1
898 +};