1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "archive_platform.h" 27 28 #ifdef HAVE_ERRNO_H 29 #include <errno.h> 30 #endif 31 #ifdef HAVE_STDLIB_H 32 #include <stdlib.h> 33 #endif 34 #ifdef HAVE_STRING_H 35 #include <string.h> 36 #endif 37 #include <time.h> 38 #ifdef HAVE_ZLIB_H 39 #include <zlib.h> 40 #endif 41 42 #include "archive.h" 43 #include "archive_private.h" 44 #include "archive_string.h" 45 #include "archive_write_private.h" 46 47 #if ARCHIVE_VERSION_NUMBER < 4000000 48 int 49 archive_write_set_compression_gzip(struct archive *a) 50 { 51 __archive_write_filters_free(a); 52 return (archive_write_add_filter_gzip(a)); 53 } 54 #endif 55 56 /* Don't compile this if we don't have zlib. */ 57 58 struct private_data { 59 int compression_level; 60 int timestamp; 61 char *original_filename; 62 #ifdef HAVE_ZLIB_H 63 z_stream stream; 64 int64_t total_in; 65 unsigned char *compressed; 66 size_t compressed_buffer_size; 67 unsigned long crc; 68 #else 69 struct archive_write_program_data *pdata; 70 #endif 71 }; 72 73 /* 74 * Yuck. zlib.h is not const-correct, so I need this one bit 75 * of ugly hackery to convert a const * pointer to a non-const pointer. 76 */ 77 #define SET_NEXT_IN(st,src) \ 78 (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src) 79 80 static int archive_compressor_gzip_options(struct archive_write_filter *, 81 const char *, const char *); 82 static int archive_compressor_gzip_open(struct archive_write_filter *); 83 static int archive_compressor_gzip_write(struct archive_write_filter *, 84 const void *, size_t); 85 static int archive_compressor_gzip_close(struct archive_write_filter *); 86 static int archive_compressor_gzip_free(struct archive_write_filter *); 87 #ifdef HAVE_ZLIB_H 88 static int drive_compressor(struct archive_write_filter *, 89 struct private_data *, int finishing); 90 #endif 91 92 93 /* 94 * Add a gzip compression filter to this write handle. 95 */ 96 int 97 archive_write_add_filter_gzip(struct archive *_a) 98 { 99 struct archive_write *a = (struct archive_write *)_a; 100 struct archive_write_filter *f = __archive_write_allocate_filter(_a); 101 struct private_data *data; 102 archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, 103 ARCHIVE_STATE_NEW, "archive_write_add_filter_gzip"); 104 105 data = calloc(1, sizeof(*data)); 106 if (data == NULL) { 107 archive_set_error(&a->archive, ENOMEM, "Out of memory"); 108 return (ARCHIVE_FATAL); 109 } 110 f->data = data; 111 f->open = &archive_compressor_gzip_open; 112 f->options = &archive_compressor_gzip_options; 113 f->close = &archive_compressor_gzip_close; 114 f->free = &archive_compressor_gzip_free; 115 f->code = ARCHIVE_FILTER_GZIP; 116 f->name = "gzip"; 117 118 data->original_filename = NULL; 119 #ifdef HAVE_ZLIB_H 120 data->compression_level = Z_DEFAULT_COMPRESSION; 121 return (ARCHIVE_OK); 122 #else 123 data->pdata = __archive_write_program_allocate("gzip"); 124 if (data->pdata == NULL) { 125 free(data); 126 archive_set_error(&a->archive, ENOMEM, "Out of memory"); 127 return (ARCHIVE_FATAL); 128 } 129 data->compression_level = 0; 130 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 131 "Using external gzip program"); 132 return (ARCHIVE_WARN); 133 #endif 134 } 135 136 static int 137 archive_compressor_gzip_free(struct archive_write_filter *f) 138 { 139 struct private_data *data = (struct private_data *)f->data; 140 141 #ifdef HAVE_ZLIB_H 142 free(data->compressed); 143 #else 144 __archive_write_program_free(data->pdata); 145 #endif 146 free((void*)data->original_filename); 147 free(data); 148 f->data = NULL; 149 return (ARCHIVE_OK); 150 } 151 152 /* 153 * Set write options. 154 */ 155 static int 156 archive_compressor_gzip_options(struct archive_write_filter *f, const char *key, 157 const char *value) 158 { 159 struct private_data *data = (struct private_data *)f->data; 160 161 if (strcmp(key, "compression-level") == 0) { 162 if (value == NULL || !(value[0] >= '0' && value[0] <= '9') || 163 value[1] != '\0') { 164 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 165 "compression-level invalid"); 166 return (ARCHIVE_FAILED); 167 } 168 data->compression_level = value[0] - '0'; 169 return (ARCHIVE_OK); 170 } 171 if (strcmp(key, "timestamp") == 0) { 172 data->timestamp = (value == NULL)?-1:1; 173 return (ARCHIVE_OK); 174 } 175 if (strcmp(key, "original-filename") == 0) { 176 free((void*)data->original_filename); 177 data->original_filename = NULL; 178 if (value) { 179 data->original_filename = strdup(value); 180 if (data->original_filename == NULL) 181 return (ARCHIVE_WARN); 182 } 183 return (ARCHIVE_OK); 184 } 185 186 /* Note: The "warn" return is just to inform the options 187 * supervisor that we didn't handle it. It will generate 188 * a suitable error if no one used this option. */ 189 return (ARCHIVE_WARN); 190 } 191 192 #ifdef HAVE_ZLIB_H 193 /* 194 * Setup callback. 195 */ 196 static int 197 archive_compressor_gzip_open(struct archive_write_filter *f) 198 { 199 struct private_data *data = (struct private_data *)f->data; 200 int ret = ARCHIVE_OK; 201 int init_success; 202 203 if (data->compressed == NULL) { 204 size_t bs = 65536, bpb; 205 if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 206 /* Buffer size should be a multiple number of 207 * the of bytes per block for performance. */ 208 bpb = archive_write_get_bytes_per_block(f->archive); 209 if (bpb > bs) 210 bs = bpb; 211 else if (bpb != 0) 212 bs -= bs % bpb; 213 } 214 data->compressed_buffer_size = bs; 215 data->compressed = malloc(data->compressed_buffer_size); 216 if (data->compressed == NULL) { 217 archive_set_error(f->archive, ENOMEM, 218 "Can't allocate data for compression buffer"); 219 return (ARCHIVE_FATAL); 220 } 221 } 222 223 data->crc = crc32(0L, NULL, 0); 224 data->stream.next_out = data->compressed; 225 data->stream.avail_out = (uInt)data->compressed_buffer_size; 226 227 /* Prime output buffer with a gzip header. */ 228 data->compressed[0] = 0x1f; /* GZip signature bytes */ 229 data->compressed[1] = 0x8b; 230 data->compressed[2] = 0x08; /* "Deflate" compression */ 231 data->compressed[3] = 0x00; /* Flags */ 232 if (data->timestamp >= 0) { 233 time_t t = time(NULL); 234 data->compressed[4] = (uint8_t)(t)&0xff; /* Timestamp */ 235 data->compressed[5] = (uint8_t)(t>>8)&0xff; 236 data->compressed[6] = (uint8_t)(t>>16)&0xff; 237 data->compressed[7] = (uint8_t)(t>>24)&0xff; 238 } else { 239 memset(&data->compressed[4], 0, 4); 240 } 241 if (data->compression_level == 9) { 242 data->compressed[8] = 2; 243 } else if(data->compression_level == 1) { 244 data->compressed[8] = 4; 245 } else { 246 data->compressed[8] = 0; 247 } 248 data->compressed[9] = 3; /* OS=Unix */ 249 data->stream.next_out += 10; 250 data->stream.avail_out -= 10; 251 252 if (data->original_filename != NULL) { 253 /* Limit "original filename" to 32k or the 254 * remaining space in the buffer, whichever is smaller. 255 */ 256 int ofn_length = strlen(data->original_filename); 257 int ofn_max_length = 32768; 258 int ofn_space_available = data->compressed 259 + data->compressed_buffer_size 260 - data->stream.next_out 261 - 1; 262 if (ofn_max_length > ofn_space_available) { 263 ofn_max_length = ofn_space_available; 264 } 265 if (ofn_length < ofn_max_length) { 266 data->compressed[3] |= 0x8; 267 strcpy((char*)data->compressed + 10, 268 data->original_filename); 269 data->stream.next_out += ofn_length + 1; 270 data->stream.avail_out -= ofn_length + 1; 271 } else { 272 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 273 "Gzip 'Original Filename' ignored because it is too long"); 274 ret = ARCHIVE_WARN; 275 } 276 } 277 278 f->write = archive_compressor_gzip_write; 279 280 /* Initialize compression library. */ 281 init_success = deflateInit2(&(data->stream), 282 data->compression_level, 283 Z_DEFLATED, 284 -15 /* < 0 to suppress zlib header */, 285 8, 286 Z_DEFAULT_STRATEGY); 287 288 if (init_success == Z_OK) { 289 f->data = data; 290 return (ret); 291 } 292 293 /* Library setup failed: clean up. */ 294 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, "Internal error " 295 "initializing compression library"); 296 297 /* Override the error message if we know what really went wrong. */ 298 switch (init_success) { 299 case Z_STREAM_ERROR: 300 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 301 "Internal error initializing " 302 "compression library: invalid setup parameter"); 303 break; 304 case Z_MEM_ERROR: 305 archive_set_error(f->archive, ENOMEM, 306 "Internal error initializing compression library"); 307 break; 308 case Z_VERSION_ERROR: 309 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 310 "Internal error initializing " 311 "compression library: invalid library version"); 312 break; 313 } 314 315 return (ARCHIVE_FATAL); 316 } 317 318 /* 319 * Write data to the compressed stream. 320 */ 321 static int 322 archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff, 323 size_t length) 324 { 325 struct private_data *data = (struct private_data *)f->data; 326 int ret; 327 328 /* Update statistics */ 329 data->crc = crc32(data->crc, (const Bytef *)buff, (uInt)length); 330 data->total_in += length; 331 332 /* Compress input data to output buffer */ 333 SET_NEXT_IN(data, buff); 334 data->stream.avail_in = (uInt)length; 335 if ((ret = drive_compressor(f, data, 0)) != ARCHIVE_OK) 336 return (ret); 337 338 return (ARCHIVE_OK); 339 } 340 341 /* 342 * Finish the compression... 343 */ 344 static int 345 archive_compressor_gzip_close(struct archive_write_filter *f) 346 { 347 unsigned char trailer[8]; 348 struct private_data *data = (struct private_data *)f->data; 349 int ret; 350 351 /* Finish compression cycle */ 352 ret = drive_compressor(f, data, 1); 353 if (ret == ARCHIVE_OK) { 354 /* Write the last compressed data. */ 355 ret = __archive_write_filter(f->next_filter, 356 data->compressed, 357 data->compressed_buffer_size - data->stream.avail_out); 358 } 359 if (ret == ARCHIVE_OK) { 360 /* Build and write out 8-byte trailer. */ 361 trailer[0] = (uint8_t)(data->crc)&0xff; 362 trailer[1] = (uint8_t)(data->crc >> 8)&0xff; 363 trailer[2] = (uint8_t)(data->crc >> 16)&0xff; 364 trailer[3] = (uint8_t)(data->crc >> 24)&0xff; 365 trailer[4] = (uint8_t)(data->total_in)&0xff; 366 trailer[5] = (uint8_t)(data->total_in >> 8)&0xff; 367 trailer[6] = (uint8_t)(data->total_in >> 16)&0xff; 368 trailer[7] = (uint8_t)(data->total_in >> 24)&0xff; 369 ret = __archive_write_filter(f->next_filter, trailer, 8); 370 } 371 372 switch (deflateEnd(&(data->stream))) { 373 case Z_OK: 374 break; 375 default: 376 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 377 "Failed to clean up compressor"); 378 ret = ARCHIVE_FATAL; 379 } 380 return ret; 381 } 382 383 /* 384 * Utility function to push input data through compressor, 385 * writing full output blocks as necessary. 386 * 387 * Note that this handles both the regular write case (finishing == 388 * false) and the end-of-archive case (finishing == true). 389 */ 390 static int 391 drive_compressor(struct archive_write_filter *f, 392 struct private_data *data, int finishing) 393 { 394 int ret; 395 396 for (;;) { 397 if (data->stream.avail_out == 0) { 398 ret = __archive_write_filter(f->next_filter, 399 data->compressed, 400 data->compressed_buffer_size); 401 if (ret != ARCHIVE_OK) 402 return (ARCHIVE_FATAL); 403 data->stream.next_out = data->compressed; 404 data->stream.avail_out = 405 (uInt)data->compressed_buffer_size; 406 } 407 408 /* If there's nothing to do, we're done. */ 409 if (!finishing && data->stream.avail_in == 0) 410 return (ARCHIVE_OK); 411 412 ret = deflate(&(data->stream), 413 finishing ? Z_FINISH : Z_NO_FLUSH ); 414 415 switch (ret) { 416 case Z_OK: 417 /* In non-finishing case, check if compressor 418 * consumed everything */ 419 if (!finishing && data->stream.avail_in == 0) 420 return (ARCHIVE_OK); 421 /* In finishing case, this return always means 422 * there's more work */ 423 break; 424 case Z_STREAM_END: 425 /* This return can only occur in finishing case. */ 426 return (ARCHIVE_OK); 427 default: 428 /* Any other return value indicates an error. */ 429 archive_set_error(f->archive, ARCHIVE_ERRNO_MISC, 430 "GZip compression failed:" 431 " deflate() call returned status %d", 432 ret); 433 return (ARCHIVE_FATAL); 434 } 435 } 436 } 437 438 #else /* HAVE_ZLIB_H */ 439 440 static int 441 archive_compressor_gzip_open(struct archive_write_filter *f) 442 { 443 struct private_data *data = (struct private_data *)f->data; 444 struct archive_string as; 445 int r; 446 447 archive_string_init(&as); 448 archive_strcpy(&as, "gzip"); 449 450 /* Specify compression level. */ 451 if (data->compression_level > 0) { 452 archive_strcat(&as, " -"); 453 archive_strappend_char(&as, '0' + data->compression_level); 454 } 455 if (data->timestamp < 0) 456 /* Do not save timestamp. */ 457 archive_strcat(&as, " -n"); 458 else if (data->timestamp > 0) 459 /* Save timestamp. */ 460 archive_strcat(&as, " -N"); 461 462 f->write = archive_compressor_gzip_write; 463 r = __archive_write_program_open(f, data->pdata, as.s); 464 archive_string_free(&as); 465 return (r); 466 } 467 468 static int 469 archive_compressor_gzip_write(struct archive_write_filter *f, const void *buff, 470 size_t length) 471 { 472 struct private_data *data = (struct private_data *)f->data; 473 474 return __archive_write_program_write(f, data->pdata, buff, length); 475 } 476 477 static int 478 archive_compressor_gzip_close(struct archive_write_filter *f) 479 { 480 struct private_data *data = (struct private_data *)f->data; 481 482 return __archive_write_program_close(f, data->pdata); 483 } 484 485 #endif /* HAVE_ZLIB_H */ 486