gzip_wrapper.c revision 420660993551ae45c9fdf13f689b4e5e97cc423e
1/* 2 * Copyright (c) 2009, 2010, 2013, 2014 3 * Phillip Lougher <phillip@squashfs.org.uk> 4 * 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. 9 * 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. 14 * 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. 18 * 19 * gzip_wrapper.c 20 * 21 * Support for ZLIB compression http://xxx 22 */ 23 24#include <stdio.h> 25#include <string.h> 26#include <stdlib.h> 27#include <zlib.h> 28 29#include "squashfs_fs.h" 30#include "gzip_wrapper.h" 31#include "compressor.h" 32 33/* default compression level */ 34static int compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL; 35 36/* default window size */ 37static int window_size = GZIP_DEFAULT_WINDOW_SIZE; 38 39/* 40 * This function is called by the options parsing code in mksquashfs.c 41 * to parse any -X compressor option. 42 * 43 * This function returns: 44 * >=0 (number of additional args parsed) on success 45 * -1 if the option was unrecognised, or 46 * -2 if the option was recognised, but otherwise bad in 47 * some way (e.g. invalid parameter) 48 * 49 * Note: this function sets internal compressor state, but does not 50 * pass back the results of the parsing other than success/failure. 51 * The gzip_dump_options() function is called later to get the options in 52 * a format suitable for writing to the filesystem. 53 */ 54static int gzip_options(char *argv[], int argc) 55{ 56 if(strcmp(argv[0], "-Xcompression-level") == 0) { 57 if(argc < 2) { 58 fprintf(stderr, "gzip: -Xcompression-level missing " 59 "compression level\n"); 60 fprintf(stderr, "gzip: -Xcompression-level it " 61 "should be 1 >= n <= 9\n"); 62 goto failed; 63 } 64 65 compression_level = atoi(argv[1]); 66 if(compression_level < 1 || compression_level > 9) { 67 fprintf(stderr, "gzip: -Xcompression-level invalid, it " 68 "should be 1 >= n <= 9\n"); 69 goto failed; 70 } 71 72 return 1; 73 } else if(strcmp(argv[0], "-Xwindow-size") == 0) { 74 if(argc < 2) { 75 fprintf(stderr, "gzip: -Xwindow-size missing window " 76 " size\n"); 77 fprintf(stderr, "gzip: -Xwindow-size <window-size>\n"); 78 goto failed; 79 } 80 81 window_size = atoi(argv[1]); 82 if(window_size < 8 || window_size > 15) { 83 fprintf(stderr, "gzip: -Xwindow-size invalid, it " 84 "should be 8 >= n <= 15\n"); 85 goto failed; 86 } 87 88 return 1; 89 } 90 91 return -1; 92 93failed: 94 return -2; 95} 96 97 98/* 99 * This function is called by mksquashfs to dump the parsed 100 * compressor options in a format suitable for writing to the 101 * compressor options field in the filesystem (stored immediately 102 * after the superblock). 103 * 104 * This function returns a pointer to the compression options structure 105 * to be stored (and the size), or NULL if there are no compression 106 * options 107 * 108 */ 109static void *gzip_dump_options(int block_size, int *size) 110{ 111 static struct gzip_comp_opts comp_opts; 112 113 /* 114 * If default compression options of: 115 * compression-level: 8 and 116 * window-size: 15 then 117 * don't store a compression options structure (this is compatible 118 * with the legacy implementation of GZIP for Squashfs) 119 */ 120 if(compression_level == GZIP_DEFAULT_COMPRESSION_LEVEL && 121 window_size == GZIP_DEFAULT_WINDOW_SIZE) 122 return NULL; 123 124 comp_opts.compression_level = compression_level; 125 comp_opts.window_size = window_size; 126 127 SQUASHFS_INSWAP_COMP_OPTS(&comp_opts); 128 129 *size = sizeof(comp_opts); 130 return &comp_opts; 131} 132 133 134/* 135 * This function is a helper specifically for the append mode of 136 * mksquashfs. Its purpose is to set the internal compressor state 137 * to the stored compressor options in the passed compressor options 138 * structure. 139 * 140 * In effect this function sets up the compressor options 141 * to the same state they were when the filesystem was originally 142 * generated, this is to ensure on appending, the compressor uses 143 * the same compression options that were used to generate the 144 * original filesystem. 145 * 146 * Note, even if there are no compressor options, this function is still 147 * called with an empty compressor structure (size == 0), to explicitly 148 * set the default options, this is to ensure any user supplied 149 * -X options on the appending mksquashfs command line are over-ridden 150 * 151 * This function returns 0 on sucessful extraction of options, and 152 * -1 on error 153 */ 154static int gzip_extract_options(int block_size, void *buffer, int size) 155{ 156 struct gzip_comp_opts *comp_opts = buffer; 157 158 if(size == 0) { 159 /* Set default values */ 160 compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL; 161 window_size = GZIP_DEFAULT_WINDOW_SIZE; 162 return 0; 163 } 164 165 /* we expect a comp_opts structure of sufficient size to be present */ 166 if(size < sizeof(*comp_opts)) 167 goto failed; 168 169 SQUASHFS_INSWAP_COMP_OPTS(comp_opts); 170 171 /* Check comp_opts structure for correctness */ 172 if(comp_opts->compression_level < 1 || 173 comp_opts->compression_level > 9) { 174 fprintf(stderr, "gzip: bad compression level in " 175 "compression options structure\n"); 176 goto failed; 177 } 178 compression_level = comp_opts->compression_level; 179 180 if(comp_opts->window_size < 8 || 181 comp_opts->window_size > 15) { 182 fprintf(stderr, "gzip: bad window size in " 183 "compression options structure\n"); 184 goto failed; 185 } 186 window_size = comp_opts->window_size; 187 return 0; 188 189failed: 190 fprintf(stderr, "gzip: error reading stored compressor options from " 191 "filesystem!\n"); 192 193 return -1; 194} 195 196 197void gzip_display_options(void *buffer, int size) 198{ 199 struct gzip_comp_opts *comp_opts = buffer; 200 201 /* we expect a comp_opts structure of sufficient size to be present */ 202 if(size < sizeof(*comp_opts)) 203 goto failed; 204 205 SQUASHFS_INSWAP_COMP_OPTS(comp_opts); 206 207 /* Check comp_opts structure for correctness */ 208 if(comp_opts->compression_level < 1 || 209 comp_opts->compression_level > 9) { 210 fprintf(stderr, "gzip: bad compression level in " 211 "compression options structure\n"); 212 goto failed; 213 } 214 printf("\tcompression-level %d\n", comp_opts->compression_level); 215 216 if(comp_opts->window_size < 8 || 217 comp_opts->window_size > 15) { 218 fprintf(stderr, "gzip: bad window size in " 219 "compression options structure\n"); 220 goto failed; 221 } 222 printf("\twindow-size %d\n", comp_opts->window_size); 223 224 return; 225 226failed: 227 fprintf(stderr, "gzip: error reading stored compressor options from " 228 "filesystem!\n"); 229} 230 231 232/* 233 * This function is called by mksquashfs to initialise the 234 * compressor, before compress() is called. 235 * 236 * This function returns 0 on success, and 237 * -1 on error 238 */ 239static int gzip_init(void **strm, int block_size, int flags) 240{ 241 int res; 242 z_stream *stream; 243 244 stream = *strm = malloc(sizeof(z_stream)); 245 if(stream == NULL) 246 goto failed; 247 248 stream->zalloc = Z_NULL; 249 stream->zfree = Z_NULL; 250 stream->opaque = 0; 251 252 res = deflateInit2(stream, compression_level, Z_DEFLATED, 253 window_size, 9, Z_DEFAULT_STRATEGY); 254 if(res != Z_OK) 255 goto failed2; 256 257 return 0; 258 259failed2: 260 free(stream); 261failed: 262 return -1; 263} 264 265 266static int gzip_compress(void *strm, void *d, void *s, int size, int block_size, 267 int *error) 268{ 269 int res; 270 z_stream *stream = strm; 271 272 res = deflateReset(stream); 273 if(res != Z_OK) 274 goto failed; 275 276 stream->next_in = s; 277 stream->avail_in = size; 278 stream->next_out = d; 279 stream->avail_out = block_size; 280 281 res = deflate(stream, Z_FINISH); 282 if(res == Z_STREAM_END) 283 /* 284 * Success, return the compressed size. 285 */ 286 return (int) stream->total_out; 287 if(res == Z_OK) 288 /* 289 * Output buffer overflow. Return out of buffer space 290 */ 291 return 0; 292failed: 293 /* 294 * All other errors return failure, with the compressor 295 * specific error code in *error 296 */ 297 *error = res; 298 return -1; 299} 300 301 302static int gzip_uncompress(void *d, void *s, int size, int outsize, int *error) 303{ 304 int res; 305 unsigned long bytes = outsize; 306 307 res = uncompress(d, &bytes, s, size); 308 309 if(res == Z_OK) 310 return (int) bytes; 311 else { 312 *error = res; 313 return -1; 314 } 315} 316 317 318void gzip_usage() 319{ 320 fprintf(stderr, "\t -Xcompression-level <compression-level>\n"); 321 fprintf(stderr, "\t\t<compression-level> should be 1 .. 9 (default " 322 "%d)\n", GZIP_DEFAULT_COMPRESSION_LEVEL); 323 fprintf(stderr, "\t -Xwindow-size <window-size>\n"); 324 fprintf(stderr, "\t\t<window-size> should be 8 .. 15 (default " 325 "%d)\n", GZIP_DEFAULT_WINDOW_SIZE); 326} 327 328 329struct compressor gzip_comp_ops = { 330 .init = gzip_init, 331 .compress = gzip_compress, 332 .uncompress = gzip_uncompress, 333 .options = gzip_options, 334 .dump_options = gzip_dump_options, 335 .extract_options = gzip_extract_options, 336 .display_options = gzip_display_options, 337 .usage = gzip_usage, 338 .id = ZLIB_COMPRESSION, 339 .name = "gzip", 340 .supported = 1 341}; 342