1*79398b25SAndroid Build Coastguard Worker /*
2*79398b25SAndroid Build Coastguard Worker * Copyright (c) 2013
3*79398b25SAndroid Build Coastguard Worker * Phillip Lougher <[email protected]>
4*79398b25SAndroid Build Coastguard Worker *
5*79398b25SAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or
6*79398b25SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
7*79398b25SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version 2,
8*79398b25SAndroid Build Coastguard Worker * or (at your option) any later version.
9*79398b25SAndroid Build Coastguard Worker *
10*79398b25SAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
11*79398b25SAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*79398b25SAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*79398b25SAndroid Build Coastguard Worker * GNU General Public License for more details.
14*79398b25SAndroid Build Coastguard Worker *
15*79398b25SAndroid Build Coastguard Worker * You should have received a copy of the GNU General Public License
16*79398b25SAndroid Build Coastguard Worker * along with this program; if not, write to the Free Software
17*79398b25SAndroid Build Coastguard Worker * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18*79398b25SAndroid Build Coastguard Worker *
19*79398b25SAndroid Build Coastguard Worker * lz4_wrapper.c
20*79398b25SAndroid Build Coastguard Worker *
21*79398b25SAndroid Build Coastguard Worker * Support for LZ4 compression http://fastcompression.blogspot.com/p/lz4.html
22*79398b25SAndroid Build Coastguard Worker */
23*79398b25SAndroid Build Coastguard Worker
24*79398b25SAndroid Build Coastguard Worker #include <stdio.h>
25*79398b25SAndroid Build Coastguard Worker #include <string.h>
26*79398b25SAndroid Build Coastguard Worker #include <stdlib.h>
27*79398b25SAndroid Build Coastguard Worker #include <lz4.h>
28*79398b25SAndroid Build Coastguard Worker #include <lz4hc.h>
29*79398b25SAndroid Build Coastguard Worker
30*79398b25SAndroid Build Coastguard Worker #include "squashfs_fs.h"
31*79398b25SAndroid Build Coastguard Worker #include "lz4_wrapper.h"
32*79398b25SAndroid Build Coastguard Worker #include "compressor.h"
33*79398b25SAndroid Build Coastguard Worker
34*79398b25SAndroid Build Coastguard Worker static int hc = 0;
35*79398b25SAndroid Build Coastguard Worker
36*79398b25SAndroid Build Coastguard Worker /*
37*79398b25SAndroid Build Coastguard Worker * This function is called by the options parsing code in mksquashfs.c
38*79398b25SAndroid Build Coastguard Worker * to parse any -X compressor option.
39*79398b25SAndroid Build Coastguard Worker *
40*79398b25SAndroid Build Coastguard Worker * This function returns:
41*79398b25SAndroid Build Coastguard Worker * >=0 (number of additional args parsed) on success
42*79398b25SAndroid Build Coastguard Worker * -1 if the option was unrecognised, or
43*79398b25SAndroid Build Coastguard Worker * -2 if the option was recognised, but otherwise bad in
44*79398b25SAndroid Build Coastguard Worker * some way (e.g. invalid parameter)
45*79398b25SAndroid Build Coastguard Worker *
46*79398b25SAndroid Build Coastguard Worker * Note: this function sets internal compressor state, but does not
47*79398b25SAndroid Build Coastguard Worker * pass back the results of the parsing other than success/failure.
48*79398b25SAndroid Build Coastguard Worker * The lz4_dump_options() function is called later to get the options in
49*79398b25SAndroid Build Coastguard Worker * a format suitable for writing to the filesystem.
50*79398b25SAndroid Build Coastguard Worker */
lz4_options(char * argv[],int argc)51*79398b25SAndroid Build Coastguard Worker static int lz4_options(char *argv[], int argc)
52*79398b25SAndroid Build Coastguard Worker {
53*79398b25SAndroid Build Coastguard Worker if(strcmp(argv[0], "-Xhc") == 0) {
54*79398b25SAndroid Build Coastguard Worker hc = 1;
55*79398b25SAndroid Build Coastguard Worker return 0;
56*79398b25SAndroid Build Coastguard Worker }
57*79398b25SAndroid Build Coastguard Worker
58*79398b25SAndroid Build Coastguard Worker return -1;
59*79398b25SAndroid Build Coastguard Worker }
60*79398b25SAndroid Build Coastguard Worker
61*79398b25SAndroid Build Coastguard Worker
62*79398b25SAndroid Build Coastguard Worker /*
63*79398b25SAndroid Build Coastguard Worker * This function is called by mksquashfs to dump the parsed
64*79398b25SAndroid Build Coastguard Worker * compressor options in a format suitable for writing to the
65*79398b25SAndroid Build Coastguard Worker * compressor options field in the filesystem (stored immediately
66*79398b25SAndroid Build Coastguard Worker * after the superblock).
67*79398b25SAndroid Build Coastguard Worker *
68*79398b25SAndroid Build Coastguard Worker * This function returns a pointer to the compression options structure
69*79398b25SAndroid Build Coastguard Worker * to be stored (and the size), or NULL if there are no compression
70*79398b25SAndroid Build Coastguard Worker * options
71*79398b25SAndroid Build Coastguard Worker *
72*79398b25SAndroid Build Coastguard Worker * Currently LZ4 always returns a comp_opts structure, with
73*79398b25SAndroid Build Coastguard Worker * the version indicating LZ4_LEGACY stream fomat. This is to
74*79398b25SAndroid Build Coastguard Worker * easily accomodate changes in the kernel code to different
75*79398b25SAndroid Build Coastguard Worker * stream formats
76*79398b25SAndroid Build Coastguard Worker */
lz4_dump_options(int block_size,int * size)77*79398b25SAndroid Build Coastguard Worker static void *lz4_dump_options(int block_size, int *size)
78*79398b25SAndroid Build Coastguard Worker {
79*79398b25SAndroid Build Coastguard Worker static struct lz4_comp_opts comp_opts;
80*79398b25SAndroid Build Coastguard Worker
81*79398b25SAndroid Build Coastguard Worker comp_opts.version = LZ4_LEGACY;
82*79398b25SAndroid Build Coastguard Worker comp_opts.flags = hc ? LZ4_HC : 0;
83*79398b25SAndroid Build Coastguard Worker SQUASHFS_INSWAP_COMP_OPTS(&comp_opts);
84*79398b25SAndroid Build Coastguard Worker
85*79398b25SAndroid Build Coastguard Worker *size = sizeof(comp_opts);
86*79398b25SAndroid Build Coastguard Worker return &comp_opts;
87*79398b25SAndroid Build Coastguard Worker }
88*79398b25SAndroid Build Coastguard Worker
89*79398b25SAndroid Build Coastguard Worker
90*79398b25SAndroid Build Coastguard Worker /*
91*79398b25SAndroid Build Coastguard Worker * This function is a helper specifically for the append mode of
92*79398b25SAndroid Build Coastguard Worker * mksquashfs. Its purpose is to set the internal compressor state
93*79398b25SAndroid Build Coastguard Worker * to the stored compressor options in the passed compressor options
94*79398b25SAndroid Build Coastguard Worker * structure.
95*79398b25SAndroid Build Coastguard Worker *
96*79398b25SAndroid Build Coastguard Worker * In effect this function sets up the compressor options
97*79398b25SAndroid Build Coastguard Worker * to the same state they were when the filesystem was originally
98*79398b25SAndroid Build Coastguard Worker * generated, this is to ensure on appending, the compressor uses
99*79398b25SAndroid Build Coastguard Worker * the same compression options that were used to generate the
100*79398b25SAndroid Build Coastguard Worker * original filesystem.
101*79398b25SAndroid Build Coastguard Worker *
102*79398b25SAndroid Build Coastguard Worker * Note, even if there are no compressor options, this function is still
103*79398b25SAndroid Build Coastguard Worker * called with an empty compressor structure (size == 0), to explicitly
104*79398b25SAndroid Build Coastguard Worker * set the default options, this is to ensure any user supplied
105*79398b25SAndroid Build Coastguard Worker * -X options on the appending mksquashfs command line are over-ridden
106*79398b25SAndroid Build Coastguard Worker *
107*79398b25SAndroid Build Coastguard Worker * This function returns 0 on sucessful extraction of options, and
108*79398b25SAndroid Build Coastguard Worker * -1 on error
109*79398b25SAndroid Build Coastguard Worker */
lz4_extract_options(int block_size,void * buffer,int size)110*79398b25SAndroid Build Coastguard Worker static int lz4_extract_options(int block_size, void *buffer, int size)
111*79398b25SAndroid Build Coastguard Worker {
112*79398b25SAndroid Build Coastguard Worker struct lz4_comp_opts *comp_opts = buffer;
113*79398b25SAndroid Build Coastguard Worker
114*79398b25SAndroid Build Coastguard Worker /* we expect a comp_opts structure to be present */
115*79398b25SAndroid Build Coastguard Worker if(size < sizeof(*comp_opts))
116*79398b25SAndroid Build Coastguard Worker goto failed;
117*79398b25SAndroid Build Coastguard Worker
118*79398b25SAndroid Build Coastguard Worker SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
119*79398b25SAndroid Build Coastguard Worker
120*79398b25SAndroid Build Coastguard Worker /* we expect the stream format to be LZ4_LEGACY */
121*79398b25SAndroid Build Coastguard Worker if(comp_opts->version != LZ4_LEGACY) {
122*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: unknown LZ4 version\n");
123*79398b25SAndroid Build Coastguard Worker goto failed;
124*79398b25SAndroid Build Coastguard Worker }
125*79398b25SAndroid Build Coastguard Worker
126*79398b25SAndroid Build Coastguard Worker /*
127*79398b25SAndroid Build Coastguard Worker * Check compression flags, currently only LZ4_HC ("high compression")
128*79398b25SAndroid Build Coastguard Worker * can be set.
129*79398b25SAndroid Build Coastguard Worker */
130*79398b25SAndroid Build Coastguard Worker if(comp_opts->flags == LZ4_HC)
131*79398b25SAndroid Build Coastguard Worker hc = 1;
132*79398b25SAndroid Build Coastguard Worker else if(comp_opts->flags != 0) {
133*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: unknown LZ4 flags\n");
134*79398b25SAndroid Build Coastguard Worker goto failed;
135*79398b25SAndroid Build Coastguard Worker }
136*79398b25SAndroid Build Coastguard Worker
137*79398b25SAndroid Build Coastguard Worker return 0;
138*79398b25SAndroid Build Coastguard Worker
139*79398b25SAndroid Build Coastguard Worker failed:
140*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: error reading stored compressor options from "
141*79398b25SAndroid Build Coastguard Worker "filesystem!\n");
142*79398b25SAndroid Build Coastguard Worker
143*79398b25SAndroid Build Coastguard Worker return -1;
144*79398b25SAndroid Build Coastguard Worker }
145*79398b25SAndroid Build Coastguard Worker
146*79398b25SAndroid Build Coastguard Worker
147*79398b25SAndroid Build Coastguard Worker /*
148*79398b25SAndroid Build Coastguard Worker * This function is a helper specifically for unsquashfs.
149*79398b25SAndroid Build Coastguard Worker * Its purpose is to check that the compression options are
150*79398b25SAndroid Build Coastguard Worker * understood by this version of LZ4.
151*79398b25SAndroid Build Coastguard Worker *
152*79398b25SAndroid Build Coastguard Worker * This is important for LZ4 because the format understood by the
153*79398b25SAndroid Build Coastguard Worker * Linux kernel may change from the already obsolete legacy format
154*79398b25SAndroid Build Coastguard Worker * currently supported.
155*79398b25SAndroid Build Coastguard Worker *
156*79398b25SAndroid Build Coastguard Worker * If this does happen, then this version of LZ4 will not be able to decode
157*79398b25SAndroid Build Coastguard Worker * the newer format. So we need to check for this.
158*79398b25SAndroid Build Coastguard Worker *
159*79398b25SAndroid Build Coastguard Worker * This function returns 0 on sucessful checking of options, and
160*79398b25SAndroid Build Coastguard Worker * -1 on error
161*79398b25SAndroid Build Coastguard Worker */
lz4_check_options(int block_size,void * buffer,int size)162*79398b25SAndroid Build Coastguard Worker static int lz4_check_options(int block_size, void *buffer, int size)
163*79398b25SAndroid Build Coastguard Worker {
164*79398b25SAndroid Build Coastguard Worker struct lz4_comp_opts *comp_opts = buffer;
165*79398b25SAndroid Build Coastguard Worker
166*79398b25SAndroid Build Coastguard Worker /* we expect a comp_opts structure to be present */
167*79398b25SAndroid Build Coastguard Worker if(size < sizeof(*comp_opts))
168*79398b25SAndroid Build Coastguard Worker goto failed;
169*79398b25SAndroid Build Coastguard Worker
170*79398b25SAndroid Build Coastguard Worker SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
171*79398b25SAndroid Build Coastguard Worker
172*79398b25SAndroid Build Coastguard Worker /* we expect the stream format to be LZ4_LEGACY */
173*79398b25SAndroid Build Coastguard Worker if(comp_opts->version != LZ4_LEGACY) {
174*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: unknown LZ4 version\n");
175*79398b25SAndroid Build Coastguard Worker goto failed;
176*79398b25SAndroid Build Coastguard Worker }
177*79398b25SAndroid Build Coastguard Worker
178*79398b25SAndroid Build Coastguard Worker return 0;
179*79398b25SAndroid Build Coastguard Worker
180*79398b25SAndroid Build Coastguard Worker failed:
181*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: error reading stored compressor options from "
182*79398b25SAndroid Build Coastguard Worker "filesystem!\n");
183*79398b25SAndroid Build Coastguard Worker return -1;
184*79398b25SAndroid Build Coastguard Worker }
185*79398b25SAndroid Build Coastguard Worker
186*79398b25SAndroid Build Coastguard Worker
lz4_display_options(void * buffer,int size)187*79398b25SAndroid Build Coastguard Worker void lz4_display_options(void *buffer, int size)
188*79398b25SAndroid Build Coastguard Worker {
189*79398b25SAndroid Build Coastguard Worker struct lz4_comp_opts *comp_opts = buffer;
190*79398b25SAndroid Build Coastguard Worker
191*79398b25SAndroid Build Coastguard Worker /* check passed comp opts struct is of the correct length */
192*79398b25SAndroid Build Coastguard Worker if(size < sizeof(*comp_opts))
193*79398b25SAndroid Build Coastguard Worker goto failed;
194*79398b25SAndroid Build Coastguard Worker
195*79398b25SAndroid Build Coastguard Worker SQUASHFS_INSWAP_COMP_OPTS(comp_opts);
196*79398b25SAndroid Build Coastguard Worker
197*79398b25SAndroid Build Coastguard Worker /* we expect the stream format to be LZ4_LEGACY */
198*79398b25SAndroid Build Coastguard Worker if(comp_opts->version != LZ4_LEGACY) {
199*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: unknown LZ4 version\n");
200*79398b25SAndroid Build Coastguard Worker goto failed;
201*79398b25SAndroid Build Coastguard Worker }
202*79398b25SAndroid Build Coastguard Worker
203*79398b25SAndroid Build Coastguard Worker /*
204*79398b25SAndroid Build Coastguard Worker * Check compression flags, currently only LZ4_HC ("high compression")
205*79398b25SAndroid Build Coastguard Worker * can be set.
206*79398b25SAndroid Build Coastguard Worker */
207*79398b25SAndroid Build Coastguard Worker if(comp_opts->flags & ~LZ4_FLAGS_MASK) {
208*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: unknown LZ4 flags\n");
209*79398b25SAndroid Build Coastguard Worker goto failed;
210*79398b25SAndroid Build Coastguard Worker }
211*79398b25SAndroid Build Coastguard Worker
212*79398b25SAndroid Build Coastguard Worker if(comp_opts->flags & LZ4_HC)
213*79398b25SAndroid Build Coastguard Worker printf("\tHigh Compression option specified (-Xhc)\n");
214*79398b25SAndroid Build Coastguard Worker
215*79398b25SAndroid Build Coastguard Worker return;
216*79398b25SAndroid Build Coastguard Worker
217*79398b25SAndroid Build Coastguard Worker failed:
218*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "lz4: error reading stored compressor options from "
219*79398b25SAndroid Build Coastguard Worker "filesystem!\n");
220*79398b25SAndroid Build Coastguard Worker }
221*79398b25SAndroid Build Coastguard Worker
222*79398b25SAndroid Build Coastguard Worker
lz4_compress(void * strm,void * dest,void * src,int size,int block_size,int * error)223*79398b25SAndroid Build Coastguard Worker static int lz4_compress(void *strm, void *dest, void *src, int size,
224*79398b25SAndroid Build Coastguard Worker int block_size, int *error)
225*79398b25SAndroid Build Coastguard Worker {
226*79398b25SAndroid Build Coastguard Worker int res;
227*79398b25SAndroid Build Coastguard Worker
228*79398b25SAndroid Build Coastguard Worker if(hc)
229*79398b25SAndroid Build Coastguard Worker res = LZ4_compress_HC(src, dest, size, block_size,
230*79398b25SAndroid Build Coastguard Worker LZ4HC_CLEVEL_DEFAULT);
231*79398b25SAndroid Build Coastguard Worker else
232*79398b25SAndroid Build Coastguard Worker res = LZ4_compress_default(src, dest, size, block_size);
233*79398b25SAndroid Build Coastguard Worker
234*79398b25SAndroid Build Coastguard Worker if(res == 0) {
235*79398b25SAndroid Build Coastguard Worker /*
236*79398b25SAndroid Build Coastguard Worker * Output buffer overflow. Return out of buffer space
237*79398b25SAndroid Build Coastguard Worker */
238*79398b25SAndroid Build Coastguard Worker return 0;
239*79398b25SAndroid Build Coastguard Worker } else if(res < 0) {
240*79398b25SAndroid Build Coastguard Worker /*
241*79398b25SAndroid Build Coastguard Worker * All other errors return failure, with the compressor
242*79398b25SAndroid Build Coastguard Worker * specific error code in *error
243*79398b25SAndroid Build Coastguard Worker */
244*79398b25SAndroid Build Coastguard Worker *error = res;
245*79398b25SAndroid Build Coastguard Worker return -1;
246*79398b25SAndroid Build Coastguard Worker }
247*79398b25SAndroid Build Coastguard Worker
248*79398b25SAndroid Build Coastguard Worker return res;
249*79398b25SAndroid Build Coastguard Worker }
250*79398b25SAndroid Build Coastguard Worker
251*79398b25SAndroid Build Coastguard Worker
lz4_uncompress(void * dest,void * src,int size,int outsize,int * error)252*79398b25SAndroid Build Coastguard Worker static int lz4_uncompress(void *dest, void *src, int size, int outsize,
253*79398b25SAndroid Build Coastguard Worker int *error)
254*79398b25SAndroid Build Coastguard Worker {
255*79398b25SAndroid Build Coastguard Worker int res = LZ4_decompress_safe(src, dest, size, outsize);
256*79398b25SAndroid Build Coastguard Worker if(res < 0) {
257*79398b25SAndroid Build Coastguard Worker *error = res;
258*79398b25SAndroid Build Coastguard Worker return -1;
259*79398b25SAndroid Build Coastguard Worker }
260*79398b25SAndroid Build Coastguard Worker
261*79398b25SAndroid Build Coastguard Worker return res;
262*79398b25SAndroid Build Coastguard Worker }
263*79398b25SAndroid Build Coastguard Worker
264*79398b25SAndroid Build Coastguard Worker
lz4_usage()265*79398b25SAndroid Build Coastguard Worker void lz4_usage()
266*79398b25SAndroid Build Coastguard Worker {
267*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "\t -Xhc\n");
268*79398b25SAndroid Build Coastguard Worker fprintf(stderr, "\t\tCompress using LZ4 High Compression\n");
269*79398b25SAndroid Build Coastguard Worker }
270*79398b25SAndroid Build Coastguard Worker
271*79398b25SAndroid Build Coastguard Worker
272*79398b25SAndroid Build Coastguard Worker struct compressor lz4_comp_ops = {
273*79398b25SAndroid Build Coastguard Worker .compress = lz4_compress,
274*79398b25SAndroid Build Coastguard Worker .uncompress = lz4_uncompress,
275*79398b25SAndroid Build Coastguard Worker .options = lz4_options,
276*79398b25SAndroid Build Coastguard Worker .dump_options = lz4_dump_options,
277*79398b25SAndroid Build Coastguard Worker .extract_options = lz4_extract_options,
278*79398b25SAndroid Build Coastguard Worker .check_options = lz4_check_options,
279*79398b25SAndroid Build Coastguard Worker .display_options = lz4_display_options,
280*79398b25SAndroid Build Coastguard Worker .usage = lz4_usage,
281*79398b25SAndroid Build Coastguard Worker .id = LZ4_COMPRESSION,
282*79398b25SAndroid Build Coastguard Worker .name = "lz4",
283*79398b25SAndroid Build Coastguard Worker .supported = 1
284*79398b25SAndroid Build Coastguard Worker };
285