]>
glassweightruler.freedombox.rocks Git - Ventoy.git/blob - SQUASHFS/squashfs-tools-4.4/squashfs-tools/xz_wrapper.c
2 * Copyright (c) 2010, 2011, 2012, 2013
3 * Phillip Lougher <phillip@squashfs.org.uk>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2,
8 * or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Support for XZ (LZMA2) compression using XZ Utils liblzma
22 * http://tukaani.org/xz/
30 #include "squashfs_fs.h"
31 #include "xz_wrapper.h"
32 #include "compressor.h"
34 static struct bcj bcj
[] = {
35 { "x86", LZMA_FILTER_X86
, 0 },
36 { "powerpc", LZMA_FILTER_POWERPC
, 0 },
37 { "ia64", LZMA_FILTER_IA64
, 0 },
38 { "arm", LZMA_FILTER_ARM
, 0 },
39 { "armthumb", LZMA_FILTER_ARMTHUMB
, 0 },
40 { "sparc", LZMA_FILTER_SPARC
, 0 },
41 { NULL
, LZMA_VLI_UNKNOWN
, 0 }
44 static int filter_count
= 1;
45 static int dictionary_size
= 0;
46 static float dictionary_percent
= 0;
50 * This function is called by the options parsing code in mksquashfs.c
51 * to parse any -X compressor option.
53 * Two specific options are supported:
57 * This function returns:
58 * >=0 (number of additional args parsed) on success
59 * -1 if the option was unrecognised, or
60 * -2 if the option was recognised, but otherwise bad in
61 * some way (e.g. invalid parameter)
63 * Note: this function sets internal compressor state, but does not
64 * pass back the results of the parsing other than success/failure.
65 * The xz_dump_options() function is called later to get the options in
66 * a format suitable for writing to the filesystem.
68 static int xz_options(char *argv
[], int argc
)
73 if(strcmp(argv
[0], "-Xbcj") == 0) {
75 fprintf(stderr
, "xz: -Xbcj missing filter\n");
80 while(name
[0] != '\0') {
81 for(i
= 0; bcj
[i
].name
; i
++) {
82 int n
= strlen(bcj
[i
].name
);
83 if((strncmp(name
, bcj
[i
].name
, n
) == 0) &&
86 if(bcj
[i
].selected
== 0) {
90 name
+= name
[n
] == ',' ? n
+ 1 : n
;
94 if(bcj
[i
].name
== NULL
) {
95 fprintf(stderr
, "xz: -Xbcj unrecognised "
102 } else if(strcmp(argv
[0], "-Xdict-size") == 0) {
107 fprintf(stderr
, "xz: -Xdict-size missing dict-size\n");
111 size
= strtof(argv
[1], &b
);
113 if(size
<= 0 || size
> 100) {
114 fprintf(stderr
, "xz: -Xdict-size percentage "
115 "should be 0 < dict-size <= 100\n");
119 dictionary_percent
= size
;
122 if((float) ((int) size
) != size
) {
123 fprintf(stderr
, "xz: -Xdict-size can't be "
124 "fractional unless a percentage of the"
129 dictionary_percent
= 0;
130 dictionary_size
= (int) size
;
132 if(*b
== 'k' || *b
== 'K')
133 dictionary_size
*= 1024;
134 else if(*b
== 'm' || *b
== 'M')
135 dictionary_size
*= 1024 * 1024;
136 else if(*b
!= '\0') {
137 fprintf(stderr
, "xz: -Xdict-size invalid "
154 * This function is called after all options have been parsed.
155 * It is used to do post-processing on the compressor options using
156 * values that were not expected to be known at option parse time.
158 * In this case block_size may not be known until after -Xdict-size has
159 * been processed (in the case where -b is specified after -Xdict-size)
161 * This function returns 0 on successful post processing, or
164 static int xz_options_post(int block_size
)
167 * if -Xdict-size has been specified use this to compute the datablock
170 if(dictionary_size
|| dictionary_percent
) {
173 if(dictionary_size
) {
174 if(dictionary_size
> block_size
) {
175 fprintf(stderr
, "xz: -Xdict-size is larger than"
180 dictionary_size
= block_size
* dictionary_percent
/ 100;
182 if(dictionary_size
< 8192) {
183 fprintf(stderr
, "xz: -Xdict-size should be 8192 bytes "
189 * dictionary_size must be storable in xz header as either
190 * 2^n or as 2^n+2^(n+1)
192 n
= ffs(dictionary_size
) - 1;
193 if(dictionary_size
!= (1 << n
) &&
194 dictionary_size
!= ((1 << n
) + (1 << (n
+ 1)))) {
195 fprintf(stderr
, "xz: -Xdict-size is an unsupported "
196 "value, dict-size must be storable in xz "
198 fprintf(stderr
, "as either 2^n or as 2^n+2^(n+1). "
199 "Example dict-sizes are 75%%, 50%%, 37.5%%, "
201 fprintf(stderr
, "or 32K, 16K, 8K etc.\n");
206 /* No -Xdict-size specified, use defaults */
207 dictionary_size
= block_size
;
217 * This function is called by mksquashfs to dump the parsed
218 * compressor options in a format suitable for writing to the
219 * compressor options field in the filesystem (stored immediately
220 * after the superblock).
222 * This function returns a pointer to the compression options structure
223 * to be stored (and the size), or NULL if there are no compression
226 static void *xz_dump_options(int block_size
, int *size
)
228 static struct comp_opts comp_opts
;
232 * don't store compressor specific options in file system if the
233 * default options are being used - no compressor options in the
234 * file system means the default options are always assumed
237 * metadata dictionary size: SQUASHFS_METADATA_SIZE
238 * datablock dictionary size: block_size
241 if(dictionary_size
== block_size
&& filter_count
== 1)
244 for(i
= 0; bcj
[i
].name
; i
++)
245 flags
|= bcj
[i
].selected
<< i
;
247 comp_opts
.dictionary_size
= dictionary_size
;
248 comp_opts
.flags
= flags
;
250 SQUASHFS_INSWAP_COMP_OPTS(&comp_opts
);
252 *size
= sizeof(comp_opts
);
258 * This function is a helper specifically for the append mode of
259 * mksquashfs. Its purpose is to set the internal compressor state
260 * to the stored compressor options in the passed compressor options
263 * In effect this function sets up the compressor options
264 * to the same state they were when the filesystem was originally
265 * generated, this is to ensure on appending, the compressor uses
266 * the same compression options that were used to generate the
267 * original filesystem.
269 * Note, even if there are no compressor options, this function is still
270 * called with an empty compressor structure (size == 0), to explicitly
271 * set the default options, this is to ensure any user supplied
272 * -X options on the appending mksquashfs command line are over-ridden
274 * This function returns 0 on sucessful extraction of options, and
277 static int xz_extract_options(int block_size
, void *buffer
, int size
)
279 struct comp_opts
*comp_opts
= buffer
;
284 dictionary_size
= block_size
;
287 /* check passed comp opts struct is of the correct length */
288 if(size
!= sizeof(struct comp_opts
))
291 SQUASHFS_INSWAP_COMP_OPTS(comp_opts
);
293 dictionary_size
= comp_opts
->dictionary_size
;
294 flags
= comp_opts
->flags
;
297 * check that the dictionary size seems correct - the dictionary
298 * size should 2^n or 2^n+2^(n+1)
300 n
= ffs(dictionary_size
) - 1;
301 if(dictionary_size
!= (1 << n
) &&
302 dictionary_size
!= ((1 << n
) + (1 << (n
+ 1))))
307 for(i
= 0; bcj
[i
].name
; i
++) {
308 if((flags
>> i
) & 1) {
318 fprintf(stderr
, "xz: error reading stored compressor options from "
325 static void xz_display_options(void *buffer
, int size
)
327 struct comp_opts
*comp_opts
= buffer
;
328 int dictionary_size
, flags
, printed
;
331 /* check passed comp opts struct is of the correct length */
332 if(size
!= sizeof(struct comp_opts
))
335 SQUASHFS_INSWAP_COMP_OPTS(comp_opts
);
337 dictionary_size
= comp_opts
->dictionary_size
;
338 flags
= comp_opts
->flags
;
341 * check that the dictionary size seems correct - the dictionary
342 * size should 2^n or 2^n+2^(n+1)
344 n
= ffs(dictionary_size
) - 1;
345 if(dictionary_size
!= (1 << n
) &&
346 dictionary_size
!= ((1 << n
) + (1 << (n
+ 1))))
349 printf("\tDictionary size %d\n", dictionary_size
);
352 for(i
= 0; bcj
[i
].name
; i
++) {
353 if((flags
>> i
) & 1) {
357 printf("\tFilters selected: ");
358 printf("%s", bcj
[i
].name
);
364 printf("\tNo filters specified\n");
371 fprintf(stderr
, "xz: error reading stored compressor options from "
377 * This function is called by mksquashfs to initialise the
378 * compressor, before compress() is called.
380 * This function returns 0 on success, and
383 static int xz_init(void **strm
, int block_size
, int datablock
)
385 int i
, j
, filters
= datablock
? filter_count
: 1;
386 struct filter
*filter
= malloc(filters
* sizeof(struct filter
));
387 struct xz_stream
*stream
;
392 stream
= *strm
= malloc(sizeof(struct xz_stream
));
396 stream
->filter
= filter
;
397 stream
->filters
= filters
;
399 memset(filter
, 0, filters
* sizeof(struct filter
));
401 stream
->dictionary_size
= datablock
? dictionary_size
:
402 SQUASHFS_METADATA_SIZE
;
404 filter
[0].filter
[0].id
= LZMA_FILTER_LZMA2
;
405 filter
[0].filter
[0].options
= &stream
->opt
;
406 filter
[0].filter
[1].id
= LZMA_VLI_UNKNOWN
;
408 for(i
= 0, j
= 1; datablock
&& bcj
[i
].name
; i
++) {
409 if(bcj
[i
].selected
) {
410 filter
[j
].buffer
= malloc(block_size
);
411 if(filter
[j
].buffer
== NULL
)
413 filter
[j
].filter
[0].id
= bcj
[i
].id
;
414 filter
[j
].filter
[1].id
= LZMA_FILTER_LZMA2
;
415 filter
[j
].filter
[1].options
= &stream
->opt
;
416 filter
[j
].filter
[2].id
= LZMA_VLI_UNKNOWN
;
424 for(i
= 1; i
< filters
; i
++)
425 free(filter
[i
].buffer
);
436 static int xz_compress(void *strm
, void *dest
, void *src
, int size
,
437 int block_size
, int *error
)
441 struct xz_stream
*stream
= strm
;
442 struct filter
*selected
= NULL
;
444 stream
->filter
[0].buffer
= dest
;
446 for(i
= 0; i
< stream
->filters
; i
++) {
447 struct filter
*filter
= &stream
->filter
[i
];
449 if(lzma_lzma_preset(&stream
->opt
, LZMA_PRESET_DEFAULT
))
452 stream
->opt
.dict_size
= stream
->dictionary_size
;
455 res
= lzma_stream_buffer_encode(filter
->filter
,
456 LZMA_CHECK_CRC32
, NULL
, src
, size
, filter
->buffer
,
457 &filter
->length
, block_size
);
460 if(!selected
|| selected
->length
> filter
->length
)
462 } else if(res
!= LZMA_BUF_ERROR
)
468 * Output buffer overflow. Return out of buffer space
472 if(selected
->buffer
!= dest
)
473 memcpy(dest
, selected
->buffer
, selected
->length
);
475 return (int) selected
->length
;
479 * All other errors return failure, with the compressor
480 * specific error code in *error
487 static int xz_uncompress(void *dest
, void *src
, int size
, int outsize
,
492 uint64_t memlimit
= MEMLIMIT
;
494 lzma_ret res
= lzma_stream_buffer_decode(&memlimit
, 0, NULL
,
495 src
, &src_pos
, size
, dest
, &dest_pos
, outsize
);
497 if(res
== LZMA_OK
&& size
== (int) src_pos
)
498 return (int) dest_pos
;
506 static void xz_usage()
508 fprintf(stderr
, "\t -Xbcj filter1,filter2,...,filterN\n");
509 fprintf(stderr
, "\t\tCompress using filter1,filter2,...,filterN in");
510 fprintf(stderr
, " turn\n\t\t(in addition to no filter), and choose");
511 fprintf(stderr
, " the best compression.\n");
512 fprintf(stderr
, "\t\tAvailable filters: x86, arm, armthumb,");
513 fprintf(stderr
, " powerpc, sparc, ia64\n");
514 fprintf(stderr
, "\t -Xdict-size <dict-size>\n");
515 fprintf(stderr
, "\t\tUse <dict-size> as the XZ dictionary size. The");
516 fprintf(stderr
, " dictionary size\n\t\tcan be specified as a");
517 fprintf(stderr
, " percentage of the block size, or as an\n\t\t");
518 fprintf(stderr
, "absolute value. The dictionary size must be less");
519 fprintf(stderr
, " than or equal\n\t\tto the block size and 8192 bytes");
520 fprintf(stderr
, " or larger. It must also be\n\t\tstorable in the xz");
521 fprintf(stderr
, " header as either 2^n or as 2^n+2^(n+1).\n\t\t");
522 fprintf(stderr
, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or");
523 fprintf(stderr
, " 32K, 16K, 8K\n\t\tetc.\n");
527 struct compressor xz_comp_ops
= {
529 .compress
= xz_compress
,
530 .uncompress
= xz_uncompress
,
531 .options
= xz_options
,
532 .options_post
= xz_options_post
,
533 .dump_options
= xz_dump_options
,
534 .extract_options
= xz_extract_options
,
535 .display_options
= xz_display_options
,
537 .id
= XZ_COMPRESSION
,