2 * Copyright (c) 2013, 2014
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 LZO compression http://www.oberhumer.com/opensource/lzo
27 #include <lzo/lzoconf.h>
28 #include <lzo/lzo1x.h>
30 #include "squashfs_fs.h"
31 #include "lzo_wrapper.h"
32 #include "compressor.h"
34 static struct lzo_algorithm lzo
[] = {
35 { "lzo1x_1", LZO1X_1_MEM_COMPRESS
, lzo1x_1_compress
},
36 { "lzo1x_1_11", LZO1X_1_11_MEM_COMPRESS
, lzo1x_1_11_compress
},
37 { "lzo1x_1_12", LZO1X_1_12_MEM_COMPRESS
, lzo1x_1_12_compress
},
38 { "lzo1x_1_15", LZO1X_1_15_MEM_COMPRESS
, lzo1x_1_15_compress
},
39 { "lzo1x_999", LZO1X_999_MEM_COMPRESS
, lzo1x_999_wrapper
},
43 /* default LZO compression algorithm and compression level */
44 static int algorithm
= SQUASHFS_LZO1X_999
;
45 static int compression_level
= SQUASHFS_LZO1X_999_COMP_DEFAULT
;
47 /* user specified compression level */
48 static int user_comp_level
= -1;
52 * This function is called by the options parsing code in mksquashfs.c
53 * to parse any -X compressor option.
55 * This function returns:
56 * >=0 (number of additional args parsed) on success
57 * -1 if the option was unrecognised, or
58 * -2 if the option was recognised, but otherwise bad in
59 * some way (e.g. invalid parameter)
61 * Note: this function sets internal compressor state, but does not
62 * pass back the results of the parsing other than success/failure.
63 * The lzo_dump_options() function is called later to get the options in
64 * a format suitable for writing to the filesystem.
66 static int lzo_options(char *argv
[], int argc
)
75 * This function is called after all options have been parsed.
76 * It is used to do post-processing on the compressor options using
77 * values that were not expected to be known at option parse time.
79 * In this case the LZO algorithm may not be known until after the
80 * compression level has been set (-Xalgorithm used after -Xcompression-level)
82 * This function returns 0 on successful post processing, or
85 static int lzo_options_post(int block_size
)
88 * Use of compression level only makes sense for
91 if(user_comp_level
!= -1) {
92 if(algorithm
!= SQUASHFS_LZO1X_999
) {
93 fprintf(stderr
, "lzo: -Xcompression-level not "
94 "supported by selected %s algorithm\n",
96 fprintf(stderr
, "lzo: -Xcompression-level is only "
97 "applicable for the lzo1x_999 algorithm\n");
100 compression_level
= user_comp_level
;
111 * This function is called by mksquashfs to dump the parsed
112 * compressor options in a format suitable for writing to the
113 * compressor options field in the filesystem (stored immediately
114 * after the superblock).
116 * This function returns a pointer to the compression options structure
117 * to be stored (and the size), or NULL if there are no compression
121 static void *lzo_dump_options(int block_size
, int *size
)
123 static struct lzo_comp_opts comp_opts
;
126 * If default compression options of SQUASHFS_LZO1X_999 and
127 * compression level of SQUASHFS_LZO1X_999_COMP_DEFAULT then
128 * don't store a compression options structure (this is compatible
129 * with the legacy implementation of LZO for Squashfs)
131 if(algorithm
== SQUASHFS_LZO1X_999
&&
132 compression_level
== SQUASHFS_LZO1X_999_COMP_DEFAULT
)
135 comp_opts
.algorithm
= algorithm
;
136 comp_opts
.compression_level
= algorithm
== SQUASHFS_LZO1X_999
?
137 compression_level
: 0;
139 SQUASHFS_INSWAP_COMP_OPTS(&comp_opts
);
141 *size
= sizeof(comp_opts
);
147 * This function is a helper specifically for the append mode of
148 * mksquashfs. Its purpose is to set the internal compressor state
149 * to the stored compressor options in the passed compressor options
152 * In effect this function sets up the compressor options
153 * to the same state they were when the filesystem was originally
154 * generated, this is to ensure on appending, the compressor uses
155 * the same compression options that were used to generate the
156 * original filesystem.
158 * Note, even if there are no compressor options, this function is still
159 * called with an empty compressor structure (size == 0), to explicitly
160 * set the default options, this is to ensure any user supplied
161 * -X options on the appending mksquashfs command line are over-ridden
163 * This function returns 0 on sucessful extraction of options, and
166 static int lzo_extract_options(int block_size
, void *buffer
, int size
)
168 struct lzo_comp_opts
*comp_opts
= buffer
;
171 /* Set default values */
172 algorithm
= SQUASHFS_LZO1X_999
;
173 compression_level
= SQUASHFS_LZO1X_999_COMP_DEFAULT
;
177 /* we expect a comp_opts structure of sufficient size to be present */
178 if(size
< sizeof(*comp_opts
))
181 SQUASHFS_INSWAP_COMP_OPTS(comp_opts
);
183 /* Check comp_opts structure for correctness */
184 switch(comp_opts
->algorithm
) {
185 case SQUASHFS_LZO1X_1
:
186 case SQUASHFS_LZO1X_1_11
:
187 case SQUASHFS_LZO1X_1_12
:
188 case SQUASHFS_LZO1X_1_15
:
189 if(comp_opts
->compression_level
!= 0) {
190 fprintf(stderr
, "lzo: bad compression level in "
191 "compression options structure\n");
195 case SQUASHFS_LZO1X_999
:
196 if(comp_opts
->compression_level
< 1 ||
197 comp_opts
->compression_level
> 9) {
198 fprintf(stderr
, "lzo: bad compression level in "
199 "compression options structure\n");
202 compression_level
= comp_opts
->compression_level
;
205 fprintf(stderr
, "lzo: bad algorithm in compression options "
210 algorithm
= comp_opts
->algorithm
;
215 fprintf(stderr
, "lzo: error reading stored compressor options from "
222 static void lzo_display_options(void *buffer
, int size
)
224 struct lzo_comp_opts
*comp_opts
= buffer
;
226 /* we expect a comp_opts structure of sufficient size to be present */
227 if(size
< sizeof(*comp_opts
))
230 SQUASHFS_INSWAP_COMP_OPTS(comp_opts
);
232 /* Check comp_opts structure for correctness */
233 switch(comp_opts
->algorithm
) {
234 case SQUASHFS_LZO1X_1
:
235 case SQUASHFS_LZO1X_1_11
:
236 case SQUASHFS_LZO1X_1_12
:
237 case SQUASHFS_LZO1X_1_15
:
238 printf("\talgorithm %s\n", lzo
[comp_opts
->algorithm
].name
);
240 case SQUASHFS_LZO1X_999
:
241 if(comp_opts
->compression_level
< 1 ||
242 comp_opts
->compression_level
> 9) {
243 fprintf(stderr
, "lzo: bad compression level in "
244 "compression options structure\n");
247 printf("\talgorithm %s\n", lzo
[comp_opts
->algorithm
].name
);
248 printf("\tcompression level %d\n",
249 comp_opts
->compression_level
);
252 fprintf(stderr
, "lzo: bad algorithm in compression options "
260 fprintf(stderr
, "lzo: error reading stored compressor options from "
266 * This function is called by mksquashfs to initialise the
267 * compressor, before compress() is called.
269 * This function returns 0 on success, and
272 static int squashfs_lzo_init(void **strm
, int block_size
, int datablock
)
274 struct lzo_stream
*stream
;
276 stream
= *strm
= malloc(sizeof(struct lzo_stream
));
280 stream
->workspace
= malloc(lzo
[algorithm
].size
);
281 if(stream
->workspace
== NULL
)
284 stream
->buffer
= malloc(LZO_MAX_EXPANSION(block_size
));
285 if(stream
->buffer
!= NULL
)
288 free(stream
->workspace
);
296 static int lzo_compress(void *strm
, void *dest
, void *src
, int size
,
297 int block_size
, int *error
)
304 static int lzo_uncompress(void *dest
, void *src
, int size
, int outsize
,
308 lzo_uint outlen
= outsize
;
310 res
= lzo1x_decompress_safe(src
, size
, dest
, &outlen
, NULL
);
311 if(res
!= LZO_E_OK
) {
320 static void lzo_usage()
324 fprintf(stderr
, "\t -Xalgorithm <algorithm>\n");
325 fprintf(stderr
, "\t\tWhere <algorithm> is one of:\n");
327 for(i
= 0; lzo
[i
].name
; i
++)
328 fprintf(stderr
, "\t\t\t%s%s\n", lzo
[i
].name
,
329 i
== SQUASHFS_LZO1X_999
? " (default)" : "");
331 fprintf(stderr
, "\t -Xcompression-level <compression-level>\n");
332 fprintf(stderr
, "\t\t<compression-level> should be 1 .. 9 (default "
333 "%d)\n", SQUASHFS_LZO1X_999_COMP_DEFAULT
);
334 fprintf(stderr
, "\t\tOnly applies to lzo1x_999 algorithm\n");
339 * Helper function for lzo1x_999 compression algorithm.
340 * All other lzo1x_xxx compressors do not take a compression level,
341 * so we need to wrap lzo1x_999 to pass the compression level which
342 * is applicable to it
344 int lzo1x_999_wrapper(const lzo_bytep src
, lzo_uint src_len
, lzo_bytep dst
,
345 lzo_uintp compsize
, lzo_voidp workspace
)
347 return lzo1x_999_compress_level(src
, src_len
, dst
, compsize
,
348 workspace
, NULL
, 0, 0, compression_level
);
352 struct compressor lzo_comp_ops
= {
353 .init
= squashfs_lzo_init
,
354 .compress
= lzo_compress
,
355 .uncompress
= lzo_uncompress
,
356 .options
= lzo_options
,
357 .options_post
= lzo_options_post
,
358 .dump_options
= lzo_dump_options
,
359 .extract_options
= lzo_extract_options
,
360 .display_options
= lzo_display_options
,
362 .id
= LZO_COMPRESSION
,