1 /*- 2 * Copyright (c) 2014 Michihiro NAKAJIMA 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 __FBSDID("$FreeBSD$"); 29 30 #ifdef HAVE_ERRNO_H 31 #include <errno.h> 32 #endif 33 #include <stdio.h> 34 #ifdef HAVE_STDLIB_H 35 #include <stdlib.h> 36 #endif 37 #ifdef HAVE_STRING_H 38 #include <string.h> 39 #endif 40 #ifdef HAVE_LZ4_H 41 #include <lz4.h> 42 #endif 43 #ifdef HAVE_LZ4HC_H 44 #include <lz4hc.h> 45 #endif 46 47 #include "archive.h" 48 #include "archive_endian.h" 49 #include "archive_private.h" 50 #include "archive_write_private.h" 51 #include "archive_xxhash.h" 52 53 #define LZ4_MAGICNUMBER 0x184d2204 54 55 struct private_data { 56 int compression_level; 57 unsigned header_written:1; 58 unsigned version_number:1; 59 unsigned block_independence:1; 60 unsigned block_checksum:1; 61 unsigned stream_size:1; 62 unsigned stream_checksum:1; 63 unsigned preset_dictionary:1; 64 unsigned block_maximum_size:3; 65 #if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2 66 int64_t total_in; 67 char *out; 68 char *out_buffer; 69 size_t out_buffer_size; 70 size_t out_block_size; 71 char *in; 72 char *in_buffer_allocated; 73 char *in_buffer; 74 size_t in_buffer_size; 75 size_t block_size; 76 77 void *xxh32_state; 78 void *lz4_stream; 79 #else 80 struct archive_write_program_data *pdata; 81 #endif 82 }; 83 84 static int archive_filter_lz4_close(struct archive_write_filter *); 85 static int archive_filter_lz4_free(struct archive_write_filter *); 86 static int archive_filter_lz4_open(struct archive_write_filter *); 87 static int archive_filter_lz4_options(struct archive_write_filter *, 88 const char *, const char *); 89 static int archive_filter_lz4_write(struct archive_write_filter *, 90 const void *, size_t); 91 92 /* 93 * Add a lz4 compression filter to this write handle. 94 */ 95 int 96 archive_write_add_filter_lz4(struct archive *_a) 97 { 98 struct archive_write *a = (struct archive_write *)_a; 99 struct archive_write_filter *f = __archive_write_allocate_filter(_a); 100 struct private_data *data; 101 102 archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, 103 ARCHIVE_STATE_NEW, "archive_write_add_filter_lz4"); 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 111 /* 112 * Setup default settings. 113 */ 114 data->compression_level = 1; 115 data->version_number = 0x01; 116 data->block_independence = 1; 117 data->block_checksum = 0; 118 data->stream_size = 0; 119 data->stream_checksum = 1; 120 data->preset_dictionary = 0; 121 data->block_maximum_size = 7; 122 123 /* 124 * Setup a filter setting. 125 */ 126 f->data = data; 127 f->options = &archive_filter_lz4_options; 128 f->close = &archive_filter_lz4_close; 129 f->free = &archive_filter_lz4_free; 130 f->open = &archive_filter_lz4_open; 131 f->code = ARCHIVE_FILTER_LZ4; 132 f->name = "lz4"; 133 #if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2 134 return (ARCHIVE_OK); 135 #else 136 /* 137 * We don't have lz4 library, and execute external lz4 program 138 * instead. 139 */ 140 data->pdata = __archive_write_program_allocate("lz4"); 141 if (data->pdata == NULL) { 142 free(data); 143 archive_set_error(&a->archive, ENOMEM, "Out of memory"); 144 return (ARCHIVE_FATAL); 145 } 146 data->compression_level = 0; 147 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, 148 "Using external lz4 program"); 149 return (ARCHIVE_WARN); 150 #endif 151 } 152 153 /* 154 * Set write options. 155 */ 156 static int 157 archive_filter_lz4_options(struct archive_write_filter *f, 158 const char *key, const char *value) 159 { 160 struct private_data *data = (struct private_data *)f->data; 161 162 if (strcmp(key, "compression-level") == 0) { 163 int val; 164 if (value == NULL || !((val = value[0] - '0') >= 1 && val <= 9) || 165 value[1] != '\0') 166 return (ARCHIVE_WARN); 167 168 #ifndef HAVE_LZ4HC_H 169 if(val >= 3) 170 { 171 archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER, 172 "High compression not included in this build"); 173 return (ARCHIVE_FATAL); 174 } 175 #endif 176 data->compression_level = val; 177 return (ARCHIVE_OK); 178 } 179 if (strcmp(key, "stream-checksum") == 0) { 180 data->stream_checksum = value != NULL; 181 return (ARCHIVE_OK); 182 } 183 if (strcmp(key, "block-checksum") == 0) { 184 data->block_checksum = value != NULL; 185 return (ARCHIVE_OK); 186 } 187 if (strcmp(key, "block-size") == 0) { 188 if (value == NULL || !(value[0] >= '4' && value[0] <= '7') || 189 value[1] != '\0') 190 return (ARCHIVE_WARN); 191 data->block_maximum_size = value[0] - '0'; 192 return (ARCHIVE_OK); 193 } 194 if (strcmp(key, "block-dependence") == 0) { 195 data->block_independence = value == NULL; 196 return (ARCHIVE_OK); 197 } 198 199 /* Note: The "warn" return is just to inform the options 200 * supervisor that we didn't handle it. It will generate 201 * a suitable error if no one used this option. */ 202 return (ARCHIVE_WARN); 203 } 204 205 #if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2 206 /* Don't compile this if we don't have liblz4. */ 207 208 static int drive_compressor(struct archive_write_filter *, const char *, 209 size_t); 210 static int drive_compressor_independence(struct archive_write_filter *, 211 const char *, size_t); 212 static int drive_compressor_dependence(struct archive_write_filter *, 213 const char *, size_t); 214 static int lz4_write_stream_descriptor(struct archive_write_filter *); 215 static ssize_t lz4_write_one_block(struct archive_write_filter *, const char *, 216 size_t); 217 218 219 /* 220 * Setup callback. 221 */ 222 static int 223 archive_filter_lz4_open(struct archive_write_filter *f) 224 { 225 struct private_data *data = (struct private_data *)f->data; 226 size_t required_size; 227 static size_t const bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024, 228 4 * 1024 * 1024 }; 229 size_t pre_block_size; 230 231 if (data->block_maximum_size < 4) 232 data->block_size = bkmap[0]; 233 else 234 data->block_size = bkmap[data->block_maximum_size - 4]; 235 236 required_size = 4 + 15 + 4 + data->block_size + 4 + 4; 237 if (data->out_buffer_size < required_size) { 238 size_t bs = required_size, bpb; 239 free(data->out_buffer); 240 if (f->archive->magic == ARCHIVE_WRITE_MAGIC) { 241 /* Buffer size should be a multiple number of 242 * the of bytes per block for performance. */ 243 bpb = archive_write_get_bytes_per_block(f->archive); 244 if (bpb > bs) 245 bs = bpb; 246 else if (bpb != 0) { 247 bs += bpb; 248 bs -= bs % bpb; 249 } 250 } 251 data->out_block_size = bs; 252 bs += required_size; 253 data->out_buffer = malloc(bs); 254 data->out = data->out_buffer; 255 data->out_buffer_size = bs; 256 } 257 258 pre_block_size = (data->block_independence)? 0: 64 * 1024; 259 if (data->in_buffer_size < data->block_size + pre_block_size) { 260 free(data->in_buffer_allocated); 261 data->in_buffer_size = data->block_size; 262 data->in_buffer_allocated = 263 malloc(data->in_buffer_size + pre_block_size); 264 data->in_buffer = data->in_buffer_allocated + pre_block_size; 265 if (!data->block_independence && data->compression_level >= 3) 266 data->in_buffer = data->in_buffer_allocated; 267 data->in = data->in_buffer; 268 data->in_buffer_size = data->block_size; 269 } 270 271 if (data->out_buffer == NULL || data->in_buffer_allocated == NULL) { 272 archive_set_error(f->archive, ENOMEM, 273 "Can't allocate data for compression buffer"); 274 return (ARCHIVE_FATAL); 275 } 276 277 f->write = archive_filter_lz4_write; 278 279 return (ARCHIVE_OK); 280 } 281 282 /* 283 * Write data to the out stream. 284 * 285 * Returns ARCHIVE_OK if all data written, error otherwise. 286 */ 287 static int 288 archive_filter_lz4_write(struct archive_write_filter *f, 289 const void *buff, size_t length) 290 { 291 struct private_data *data = (struct private_data *)f->data; 292 int ret = ARCHIVE_OK; 293 const char *p; 294 size_t remaining; 295 ssize_t size; 296 297 /* If we haven't written a stream descriptor, we have to do it first. */ 298 if (!data->header_written) { 299 ret = lz4_write_stream_descriptor(f); 300 if (ret != ARCHIVE_OK) 301 return (ret); 302 data->header_written = 1; 303 } 304 305 /* Update statistics */ 306 data->total_in += length; 307 308 p = (const char *)buff; 309 remaining = length; 310 while (remaining) { 311 size_t l; 312 /* Compress input data to output buffer */ 313 size = lz4_write_one_block(f, p, remaining); 314 if (size < ARCHIVE_OK) 315 return (ARCHIVE_FATAL); 316 l = data->out - data->out_buffer; 317 if (l >= data->out_block_size) { 318 ret = __archive_write_filter(f->next_filter, 319 data->out_buffer, data->out_block_size); 320 l -= data->out_block_size; 321 memcpy(data->out_buffer, 322 data->out_buffer + data->out_block_size, l); 323 data->out = data->out_buffer + l; 324 if (ret < ARCHIVE_WARN) 325 break; 326 } 327 p += size; 328 remaining -= size; 329 } 330 331 return (ret); 332 } 333 334 /* 335 * Finish the compression. 336 */ 337 static int 338 archive_filter_lz4_close(struct archive_write_filter *f) 339 { 340 struct private_data *data = (struct private_data *)f->data; 341 int ret; 342 343 /* Finish compression cycle. */ 344 ret = (int)lz4_write_one_block(f, NULL, 0); 345 if (ret >= 0) { 346 /* 347 * Write the last block and the end of the stream data. 348 */ 349 350 /* Write End Of Stream. */ 351 memset(data->out, 0, 4); data->out += 4; 352 /* Write Stream checksum if needed. */ 353 if (data->stream_checksum) { 354 unsigned int checksum; 355 checksum = __archive_xxhash.XXH32_digest( 356 data->xxh32_state); 357 data->xxh32_state = NULL; 358 archive_le32enc(data->out, checksum); 359 data->out += 4; 360 } 361 ret = __archive_write_filter(f->next_filter, 362 data->out_buffer, data->out - data->out_buffer); 363 } 364 return ret; 365 } 366 367 static int 368 archive_filter_lz4_free(struct archive_write_filter *f) 369 { 370 struct private_data *data = (struct private_data *)f->data; 371 372 if (data->lz4_stream != NULL) { 373 #ifdef HAVE_LZ4HC_H 374 if (data->compression_level >= 3) 375 #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 376 LZ4_freeStreamHC(data->lz4_stream); 377 #else 378 LZ4_freeHC(data->lz4_stream); 379 #endif 380 else 381 #endif 382 #if LZ4_VERSION_MINOR >= 3 383 LZ4_freeStream(data->lz4_stream); 384 #else 385 LZ4_free(data->lz4_stream); 386 #endif 387 } 388 free(data->out_buffer); 389 free(data->in_buffer_allocated); 390 free(data->xxh32_state); 391 free(data); 392 f->data = NULL; 393 return (ARCHIVE_OK); 394 } 395 396 static int 397 lz4_write_stream_descriptor(struct archive_write_filter *f) 398 { 399 struct private_data *data = (struct private_data *)f->data; 400 uint8_t *sd; 401 402 sd = (uint8_t *)data->out; 403 /* Write Magic Number. */ 404 archive_le32enc(&sd[0], LZ4_MAGICNUMBER); 405 /* FLG */ 406 sd[4] = (data->version_number << 6) 407 | (data->block_independence << 5) 408 | (data->block_checksum << 4) 409 | (data->stream_size << 3) 410 | (data->stream_checksum << 2) 411 | (data->preset_dictionary << 0); 412 /* BD */ 413 sd[5] = (data->block_maximum_size << 4); 414 sd[6] = (__archive_xxhash.XXH32(&sd[4], 2, 0) >> 8) & 0xff; 415 data->out += 7; 416 if (data->stream_checksum) 417 data->xxh32_state = __archive_xxhash.XXH32_init(0); 418 else 419 data->xxh32_state = NULL; 420 return (ARCHIVE_OK); 421 } 422 423 static ssize_t 424 lz4_write_one_block(struct archive_write_filter *f, const char *p, 425 size_t length) 426 { 427 struct private_data *data = (struct private_data *)f->data; 428 ssize_t r; 429 430 if (p == NULL) { 431 /* Compress remaining uncompressed data. */ 432 if (data->in_buffer == data->in) 433 return 0; 434 else { 435 size_t l = data->in - data->in_buffer; 436 r = drive_compressor(f, data->in_buffer, l); 437 if (r == ARCHIVE_OK) 438 r = (ssize_t)l; 439 } 440 } else if ((data->block_independence || data->compression_level < 3) && 441 data->in_buffer == data->in && length >= data->block_size) { 442 r = drive_compressor(f, p, data->block_size); 443 if (r == ARCHIVE_OK) 444 r = (ssize_t)data->block_size; 445 } else { 446 size_t remaining_size = data->in_buffer_size - 447 (data->in - data->in_buffer); 448 size_t l = (remaining_size > length)? length: remaining_size; 449 memcpy(data->in, p, l); 450 data->in += l; 451 if (l == remaining_size) { 452 r = drive_compressor(f, data->in_buffer, 453 data->block_size); 454 if (r == ARCHIVE_OK) 455 r = (ssize_t)l; 456 data->in = data->in_buffer; 457 } else 458 r = (ssize_t)l; 459 } 460 461 return (r); 462 } 463 464 465 /* 466 * Utility function to push input data through compressor, writing 467 * full output blocks as necessary. 468 * 469 * Note that this handles both the regular write case (finishing == 470 * false) and the end-of-archive case (finishing == true). 471 */ 472 static int 473 drive_compressor(struct archive_write_filter *f, const char *p, size_t length) 474 { 475 struct private_data *data = (struct private_data *)f->data; 476 477 if (data->stream_checksum) 478 __archive_xxhash.XXH32_update(data->xxh32_state, 479 p, (int)length); 480 if (data->block_independence) 481 return drive_compressor_independence(f, p, length); 482 else 483 return drive_compressor_dependence(f, p, length); 484 } 485 486 static int 487 drive_compressor_independence(struct archive_write_filter *f, const char *p, 488 size_t length) 489 { 490 struct private_data *data = (struct private_data *)f->data; 491 unsigned int outsize; 492 493 #ifdef HAVE_LZ4HC_H 494 if (data->compression_level >= 3) 495 #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 496 outsize = LZ4_compress_HC(p, data->out + 4, 497 (int)length, (int)data->block_size, 498 data->compression_level); 499 #else 500 outsize = LZ4_compressHC2_limitedOutput(p, data->out + 4, 501 (int)length, (int)data->block_size, 502 data->compression_level); 503 #endif 504 else 505 #endif 506 #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 507 outsize = LZ4_compress_default(p, data->out + 4, 508 (int)length, (int)data->block_size); 509 #else 510 outsize = LZ4_compress_limitedOutput(p, data->out + 4, 511 (int)length, (int)data->block_size); 512 #endif 513 514 if (outsize) { 515 /* The buffer is compressed. */ 516 archive_le32enc(data->out, outsize); 517 data->out += 4; 518 } else { 519 /* The buffer is not compressed. The compressed size was 520 * bigger than its uncompressed size. */ 521 archive_le32enc(data->out, length | 0x80000000); 522 data->out += 4; 523 memcpy(data->out, p, length); 524 outsize = length; 525 } 526 data->out += outsize; 527 if (data->block_checksum) { 528 unsigned int checksum = 529 __archive_xxhash.XXH32(data->out - outsize, outsize, 0); 530 archive_le32enc(data->out, checksum); 531 data->out += 4; 532 } 533 return (ARCHIVE_OK); 534 } 535 536 static int 537 drive_compressor_dependence(struct archive_write_filter *f, const char *p, 538 size_t length) 539 { 540 struct private_data *data = (struct private_data *)f->data; 541 int outsize; 542 543 #define DICT_SIZE (64 * 1024) 544 #ifdef HAVE_LZ4HC_H 545 if (data->compression_level >= 3) { 546 if (data->lz4_stream == NULL) { 547 #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 548 data->lz4_stream = LZ4_createStreamHC(); 549 LZ4_resetStreamHC(data->lz4_stream, data->compression_level); 550 #else 551 data->lz4_stream = 552 LZ4_createHC(data->in_buffer_allocated); 553 #endif 554 if (data->lz4_stream == NULL) { 555 archive_set_error(f->archive, ENOMEM, 556 "Can't allocate data for compression" 557 " buffer"); 558 return (ARCHIVE_FATAL); 559 } 560 } 561 else 562 LZ4_loadDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE); 563 564 #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 565 outsize = LZ4_compress_HC_continue( 566 data->lz4_stream, p, data->out + 4, (int)length, 567 (int)data->block_size); 568 #else 569 outsize = LZ4_compressHC2_limitedOutput_continue( 570 data->lz4_stream, p, data->out + 4, (int)length, 571 (int)data->block_size, data->compression_level); 572 #endif 573 } else 574 #endif 575 { 576 if (data->lz4_stream == NULL) { 577 data->lz4_stream = LZ4_createStream(); 578 if (data->lz4_stream == NULL) { 579 archive_set_error(f->archive, ENOMEM, 580 "Can't allocate data for compression" 581 " buffer"); 582 return (ARCHIVE_FATAL); 583 } 584 } 585 else 586 LZ4_loadDict(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE); 587 588 #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 589 outsize = LZ4_compress_fast_continue( 590 data->lz4_stream, p, data->out + 4, (int)length, 591 (int)data->block_size, 1); 592 #else 593 outsize = LZ4_compress_limitedOutput_continue( 594 data->lz4_stream, p, data->out + 4, (int)length, 595 (int)data->block_size); 596 #endif 597 } 598 599 if (outsize) { 600 /* The buffer is compressed. */ 601 archive_le32enc(data->out, outsize); 602 data->out += 4; 603 } else { 604 /* The buffer is not compressed. The compressed size was 605 * bigger than its uncompressed size. */ 606 archive_le32enc(data->out, length | 0x80000000); 607 data->out += 4; 608 memcpy(data->out, p, length); 609 outsize = length; 610 } 611 data->out += outsize; 612 if (data->block_checksum) { 613 unsigned int checksum = 614 __archive_xxhash.XXH32(data->out - outsize, outsize, 0); 615 archive_le32enc(data->out, checksum); 616 data->out += 4; 617 } 618 619 if (length == data->block_size) { 620 #ifdef HAVE_LZ4HC_H 621 if (data->compression_level >= 3) { 622 #if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7 623 LZ4_saveDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE); 624 #else 625 LZ4_slideInputBufferHC(data->lz4_stream); 626 #endif 627 data->in_buffer = data->in_buffer_allocated + DICT_SIZE; 628 } 629 else 630 #endif 631 LZ4_saveDict(data->lz4_stream, 632 data->in_buffer_allocated, DICT_SIZE); 633 #undef DICT_SIZE 634 } 635 return (ARCHIVE_OK); 636 } 637 638 #else /* HAVE_LIBLZ4 */ 639 640 static int 641 archive_filter_lz4_open(struct archive_write_filter *f) 642 { 643 struct private_data *data = (struct private_data *)f->data; 644 struct archive_string as; 645 int r; 646 647 archive_string_init(&as); 648 archive_strcpy(&as, "lz4 -z -q -q"); 649 650 /* Specify a compression level. */ 651 if (data->compression_level > 0) { 652 archive_strcat(&as, " -"); 653 archive_strappend_char(&as, '0' + data->compression_level); 654 } 655 /* Specify a block size. */ 656 archive_strcat(&as, " -B"); 657 archive_strappend_char(&as, '0' + data->block_maximum_size); 658 659 if (data->block_checksum) 660 archive_strcat(&as, " -BX"); 661 if (data->stream_checksum == 0) 662 archive_strcat(&as, " --no-frame-crc"); 663 if (data->block_independence == 0) 664 archive_strcat(&as, " -BD"); 665 666 f->write = archive_filter_lz4_write; 667 668 r = __archive_write_program_open(f, data->pdata, as.s); 669 archive_string_free(&as); 670 return (r); 671 } 672 673 static int 674 archive_filter_lz4_write(struct archive_write_filter *f, const void *buff, 675 size_t length) 676 { 677 struct private_data *data = (struct private_data *)f->data; 678 679 return __archive_write_program_write(f, data->pdata, buff, length); 680 } 681 682 static int 683 archive_filter_lz4_close(struct archive_write_filter *f) 684 { 685 struct private_data *data = (struct private_data *)f->data; 686 687 return __archive_write_program_close(f, data->pdata); 688 } 689 690 static int 691 archive_filter_lz4_free(struct archive_write_filter *f) 692 { 693 struct private_data *data = (struct private_data *)f->data; 694 695 __archive_write_program_free(data->pdata); 696 free(data); 697 return (ARCHIVE_OK); 698 } 699 700 #endif /* HAVE_LIBLZ4 */ 701