1/* 2 * Copyright (c) 2005-2008 Rob Braun 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 * 3. Neither the name of Rob Braun nor the names of his contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29/* 30 * 03-Apr-2005 31 * DRI: Rob Braun <bbraun@synack.net> 32 */ 33/* 34 * Portions Copyright 2006, Apple Computer, Inc. 35 * Christopher Ryan <ryanc@apple.com> 36*/ 37 38#define _FILE_OFFSET_BITS 64 39 40#include "config.h" 41#include <stdlib.h> 42#include <stdio.h> 43#include <fcntl.h> 44#include <errno.h> 45#include <string.h> 46#include <limits.h> 47#include <unistd.h> 48#include <inttypes.h> 49#include <sys/types.h> 50#include <assert.h> 51 52#ifndef HAVE_ASPRINTF 53#include "asprintf.h" 54#endif 55#include "xar.h" 56#include "filetree.h" 57#include "archive.h" 58#include "io.h" 59#include "zxar.h" 60#include "bzxar.h" 61#include "lzmaxar.h" 62#include "hash.h" 63#include "script.h" 64#include "macho.h" 65#include "util.h" 66 67#if !defined(LLONG_MAX) && defined(LONG_LONG_MAX) 68#define LLONG_MAX LONG_LONG_MAX 69#endif 70 71#if !defined(LLONG_MIN) && defined(LONG_LONG_MIN) 72#define LLONG_MIN LONG_LONG_MIN 73#endif 74 75// IMPORTANT: Keep datamod count up to date in io.h! 76struct datamod xar_datamods[] = { 77 { xar_hash_fromheap_in, 78 xar_hash_fromheap_out, 79 xar_hash_fromheap_done, 80 xar_hash_toheap_in, 81 xar_hash_toheap_out, 82 xar_hash_toheap_done 83 }, 84 { (fromheap_in)NULL, 85 (fromheap_out)NULL, 86 (fromheap_done)NULL, 87 xar_script_in, 88 (toheap_out)NULL, 89 xar_script_done 90 }, 91 { (fromheap_in)NULL, 92 (fromheap_out)NULL, 93 (fromheap_done)NULL, 94 xar_macho_in, 95 (toheap_out)NULL, 96 xar_macho_done 97 }, 98 { xar_gzip_fromheap_in, 99 (fromheap_out)NULL, 100 xar_gzip_fromheap_done, 101 xar_gzip_toheap_in, 102 (toheap_out)NULL, 103 xar_gzip_toheap_done 104 }, 105 { xar_bzip_fromheap_in, 106 (fromheap_out)NULL, 107 xar_bzip_fromheap_done, 108 xar_bzip_toheap_in, 109 (toheap_out)NULL, 110 xar_bzip_toheap_done 111 }, 112 { xar_lzma_fromheap_in, 113 (fromheap_out)NULL, 114 xar_lzma_fromheap_done, 115 xar_lzma_toheap_in, 116 (toheap_out)NULL, 117 xar_lzma_toheap_done 118 } 119}; 120 121size_t xar_io_get_rsize(xar_t x) { 122 size_t bsize; 123 const char *opt = NULL; 124 125 opt = xar_opt_get(x, "rsize"); 126 if( !opt ) { 127 bsize = 4096; 128 } else { 129 bsize = strtol(opt, NULL, 0); 130 if( ((bsize == LONG_MAX) || (bsize == LONG_MIN)) && (errno == ERANGE) ) { 131 bsize = 4096; 132 } 133 } 134 135 return bsize; 136} 137 138off_t xar_io_get_heap_base_offset(xar_t x) { 139 return XAR(x)->toc_count + sizeof(xar_header_t); 140} 141 142size_t xar_io_get_toc_checksum_length_for_type(const char *type) { 143 if( !type ) { 144 return 0; 145 } else if( strcmp(type, XAR_OPT_VAL_NONE) == 0 ) { 146 return 0; 147 } else if( strcmp(type, XAR_OPT_VAL_SHA1) == 0 ) { 148 return 20; 149 } else if( strcmp(type, XAR_OPT_VAL_SHA256) == 0 ) { 150 return 32; 151 } else if( strcmp(type, XAR_OPT_VAL_SHA512) == 0 ) { 152 return 64; 153 } else if( strcmp(type, XAR_OPT_VAL_MD5) == 0 ) { 154 return 16; 155 } else { 156 return 0; 157 } 158} 159 160size_t xar_io_get_toc_checksum_length(xar_t x) { 161 switch(XAR(x)->header.cksum_alg) { 162 case XAR_CKSUM_NONE: 163 return 0; 164 case XAR_CKSUM_SHA1: 165 return 20; 166 case XAR_CKSUM_SHA256: 167 return 32; 168 case XAR_CKSUM_SHA512: 169 return 64; 170 case XAR_CKSUM_MD5: 171 return 16; 172 default: 173 fprintf(stderr, "Unknown hashing algorithm, skipping\n"); 174 return 0; 175 }; 176} 177 178off_t xar_io_get_file_offset(xar_t x, xar_file_t f, xar_prop_t p) { 179 xar_prop_t tmpp; 180 const char *opt = NULL; 181 tmpp = xar_prop_pget(p, "offset"); 182 if( tmpp ) { 183 opt = xar_prop_getvalue(tmpp); 184 return strtoll(opt, NULL, 0); 185 } else { 186 return -1; 187 } 188} 189 190int64_t xar_io_get_length(xar_prop_t p) { 191 const char *opt = NULL; 192 int64_t fsize = 0; 193 xar_prop_t tmpp; 194 195 tmpp = xar_prop_pget(p, "length"); 196 if( tmpp ) 197 opt = xar_prop_getvalue(tmpp); 198 if( !opt ) { 199 return 0; 200 } else { 201 fsize = strtoll(opt, NULL, 10); 202 if( ((fsize == LLONG_MAX) || (fsize == LLONG_MIN)) && (errno == ERANGE) ) { 203 return -1; 204 } 205 } 206 207 return fsize; 208} 209 210static void xar_io_seek(xar_t x, xar_file_t f, off_t seekoff) { 211 int r; 212 213 if( XAR(x)->fd >= 0 ) { 214 r = lseek(XAR(x)->fd, seekoff, SEEK_SET); 215 if( r == -1 ) { 216 if( errno == ESPIPE ) { 217 ssize_t rr; 218 char *buf; 219 unsigned int len; 220 221 len = seekoff - XAR(x)->toc_count; 222 len -= sizeof(xar_header_t); 223 if( XAR(x)->heap_offset > len ) { 224 xar_err_new(x); 225 xar_err_set_file(x, f); 226 xar_err_set_string(x, "Unable to seek"); 227 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 228 } else { 229 len -= XAR(x)->heap_offset; 230 buf = malloc(len); 231 assert(buf); 232 rr = xar_read_fd(XAR(x)->fd, buf, len); 233 if( rr < len ) { 234 xar_err_new(x); 235 xar_err_set_file(x, f); 236 xar_err_set_string(x, "Unable to seek"); 237 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 238 } 239 XAR(x)->heap_offset += rr; 240 free(buf); 241 } 242 } else { 243 xar_err_new(x); 244 xar_err_set_file(x, f); 245 xar_err_set_string(x, "Unable to seek"); 246 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 247 } 248 } 249 } 250} 251 252int32_t xar_attrcopy_to_heap(xar_t x, xar_file_t f, xar_prop_t p, read_callback rcb, void *context) { 253 int modulecount = (sizeof(xar_datamods)/sizeof(struct datamod)); 254 void *modulecontext[modulecount]; 255 int r, i; 256 size_t bsize, rsize; 257 int64_t readsize=0, writesize=0, inc = 0, this_write=0; 258 void *inbuf; 259 char *tmpstr = NULL; 260 const char *opt = NULL, *csum = NULL; 261 off_t orig_heap_offset = XAR(x)->heap_offset; 262 xar_file_t tmpf = NULL; 263 xar_prop_t tmpp = NULL; 264 265 memset(modulecontext, 0, sizeof(void*)*modulecount); 266 267 bsize = xar_io_get_rsize(x); 268 269 r = 1; 270 271 // (Apple) allocate once 272 inbuf = malloc(bsize); 273 if( !inbuf ) 274 return -1; 275 276 while(r != 0) { 277 278 r = rcb(x, f, inbuf, bsize, context); 279 if( r < 0 ) { 280 free(inbuf); 281 return -1; 282 } 283 284 readsize+=r; 285 inc += r; 286 rsize = r; 287 288 /* filter the data through the in modules */ 289 for( i = 0; i < modulecount; i++) { 290 if( xar_datamods[i].th_in ) { 291 xar_datamods[i].th_in(x, f, p, &inbuf, &rsize, &(modulecontext[i])); 292 } 293 } 294 295 /* filter the data through the out modules */ 296 for( i = 0; i < modulecount; i++) { 297 if( xar_datamods[i].th_out ) 298 xar_datamods[i].th_out(x, f, p, inbuf, rsize, &(modulecontext[i])); 299 } 300 301 size_t written = 0; 302 if( rsize != 0 ) { 303 while(written < rsize) { 304 this_write = xar_write_fd(XAR(x)->heap_fd, inbuf, rsize); 305 if( this_write < 0 ) { 306 xar_err_new(x); 307 xar_err_set_string(x, "write(2) error when writing to heap"); 308 xar_err_set_errno(x, errno); 309 xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_CREATION); 310 free(inbuf); 311 return -1; 312 } 313 written += this_write; 314 } 315 } 316 XAR(x)->heap_offset += written; 317 writesize += written; 318 } 319 320 free(inbuf); 321 322 323 /* If size is 0, don't bother having anything in the heap */ 324 if( readsize == 0 ) { 325 XAR(x)->heap_offset = orig_heap_offset; 326 lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); 327 for( i = 0; i < modulecount; i++) { 328 if( xar_datamods[i].th_done ) 329 xar_datamods[i].th_done(x, f, p, &(modulecontext[i])); 330 } 331 return 0; 332 } 333 /* finish up anything that still needs doing */ 334 for( i = 0; i < modulecount; i++) { 335 if( xar_datamods[i].th_done ) 336 xar_datamods[i].th_done(x, f, p, &(modulecontext[i])); 337 } 338 339 XAR(x)->heap_len += writesize; 340 tmpp = xar_prop_pget(p, "archived-checksum"); 341 if( tmpp ) 342 csum = xar_prop_getvalue(tmpp); 343 if( csum ) 344 tmpf = xmlHashLookup(XAR(x)->csum_hash, BAD_CAST(csum)); 345 if( tmpf ) { 346 const char *attr = xar_prop_getkey(p); 347 opt = xar_opt_get(x, XAR_OPT_LINKSAME); 348 if( opt && (strcmp(attr, "data") == 0) ) { 349 const char *id = xar_attr_pget(tmpf, NULL, "id"); 350 xar_prop_pset(f, NULL, "type", "hardlink"); 351 tmpp = xar_prop_pfirst(f); 352 if( tmpp ) 353 tmpp = xar_prop_find(tmpp, "type"); 354 if( tmpp ) 355 xar_attr_pset(f, tmpp, "link", id); 356 357 xar_prop_pset(tmpf, NULL, "type", "hardlink"); 358 tmpp = xar_prop_pfirst(tmpf); 359 if( tmpp ) 360 tmpp = xar_prop_find(tmpp, "type"); 361 if( tmpp ) 362 xar_attr_pset(tmpf, tmpp, "link", "original"); 363 364 tmpp = xar_prop_pfirst(f); 365 if( tmpp ) 366 tmpp = xar_prop_find(tmpp, "data"); 367 xar_prop_punset(f, tmpp); 368 369 XAR(x)->heap_offset = orig_heap_offset; 370 lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); 371 XAR(x)->heap_len -= writesize; 372 return 0; 373 } 374 opt = xar_opt_get(x, XAR_OPT_COALESCE); 375 if( opt ) { 376 long long tmpoff; 377 const char *offstr = NULL; 378 tmpp = xar_prop_pfirst(tmpf); 379 if( tmpp ) { 380 const char *key; 381 key = xar_prop_getkey(p); 382 tmpp = xar_prop_find(tmpp, key); 383 } 384 if( tmpp ) 385 tmpp = xar_prop_pget(tmpp, "offset"); 386 if( tmpp ) 387 offstr = xar_prop_getvalue(tmpp); 388 if( offstr ) { 389 tmpoff = strtoll(offstr, NULL, 10); 390 XAR(x)->heap_offset = orig_heap_offset; 391 lseek(XAR(x)->heap_fd, -writesize, SEEK_CUR); 392 orig_heap_offset = tmpoff; 393 XAR(x)->heap_len -= writesize; 394 } 395 396 } 397 } else if( csum ) { 398 xmlHashAddEntry(XAR(x)->csum_hash, BAD_CAST(csum), XAR_FILE(f)); 399 } else { 400 xar_err_new(x); 401 xar_err_set_file(x, f); 402 xar_err_set_string(x, "No archived-checksum"); 403 xar_err_callback(x, XAR_SEVERITY_WARNING, XAR_ERR_ARCHIVE_CREATION); 404 } 405 406 asprintf(&tmpstr, "%"PRIu64, readsize); 407 xar_prop_pset(f, p, "size", tmpstr); 408 free(tmpstr); 409 410 asprintf(&tmpstr, "%"PRIu64, (uint64_t)orig_heap_offset); 411 xar_prop_pset(f, p, "offset", tmpstr); 412 free(tmpstr); 413 414 tmpstr = (char *)xar_opt_get(x, XAR_OPT_COMPRESSION); 415 if( tmpstr && (strcmp(tmpstr, XAR_OPT_VAL_NONE) == 0) ) { 416 xar_prop_pset(f, p, "encoding", NULL); 417 tmpp = xar_prop_pget(p, "encoding"); 418 if( tmpp ) 419 xar_attr_pset(f, tmpp, "style", "application/octet-stream"); 420 } 421 422 asprintf(&tmpstr, "%"PRIu64, writesize); 423 xar_prop_pset(f, p, "length", tmpstr); 424 free(tmpstr); 425 426 return 0; 427} 428 429/* xar_copy_from_heap 430 * This is the arcmod extraction entry point for extracting the file's 431 * data from the heap file. 432 * It is assumed the heap_fd is already positioned appropriately. 433 */ 434int32_t xar_attrcopy_from_heap(xar_t x, xar_file_t f, xar_prop_t p, write_callback wcb, void *context) { 435 int modulecount = (sizeof(xar_datamods)/sizeof(struct datamod)); 436 void *modulecontext[modulecount]; 437 int r, i; 438 size_t bsize, def_bsize; 439 int64_t fsize, inc = 0, seekoff; 440 void *inbuf; 441 const char *opt; 442 xar_prop_t tmpp; 443 444 memset(modulecontext, 0, sizeof(void*)*modulecount); 445 446 def_bsize = xar_io_get_rsize(x); 447 448 seekoff = xar_io_get_file_offset(x, f, p); 449 if( seekoff == -1 ) { 450 wcb(x, f, NULL, 0, context); 451 return 0; 452 } else if( ((seekoff == LLONG_MAX) || (seekoff == LLONG_MIN)) && (errno == ERANGE) ) { 453 return -1; 454 } 455 seekoff += xar_io_get_heap_base_offset(x); 456 xar_io_seek(x, f, seekoff); 457 458 fsize = xar_io_get_length(p); 459 if( fsize == 0 ) 460 return 0; 461 if( fsize < 0 ) 462 return -1; 463 464 bsize = def_bsize; 465 inbuf = malloc(bsize); 466 if( !inbuf ) { 467 return -1; 468 } 469 470 while(1) { 471 /* Size has been reached */ 472 if( fsize == inc ) 473 break; 474 if( (fsize - inc) < bsize ) 475 bsize = fsize - inc; 476 r = read(XAR(x)->fd, inbuf, bsize); 477 if( r == 0 ) 478 break; 479 if( (r < 0) && (errno == EINTR) ) 480 continue; 481 if( r < 0 ) { 482 free(inbuf); 483 return -1; 484 } 485 486 XAR(x)->heap_offset += r; 487 inc += r; 488 bsize = r; 489 490 /* filter the data through the in modules */ 491 for( i = 0; i < modulecount; i++) { 492 if( xar_datamods[i].fh_in ) { 493 int32_t ret; 494 ret = xar_datamods[i].fh_in(x, f, p, &inbuf, &bsize, &(modulecontext[i])); 495 if( ret < 0 ) { 496 free(inbuf); // (Apple) don't leak inbuf 497 return -1; 498 } 499 } 500 } 501 502 /* Only due the write phase, if there is a write function to call */ 503 if(wcb){ 504 505 /* filter the data through the out modules */ 506 for( i = 0; i < modulecount; i++) { 507 if( xar_datamods[i].fh_out ) { 508 int32_t ret; 509 ret = xar_datamods[i].fh_out(x, f, p, inbuf, bsize, &(modulecontext[i])); 510 if( ret < 0 ) { 511 free(inbuf); // (Apple) don't leak inbuf 512 return -1; 513 } 514 } 515 } 516 517 wcb(x, f, inbuf, bsize, context); 518 } 519 520 bsize = def_bsize; 521 } 522 523 free(inbuf); 524 /* finish up anything that still needs doing */ 525 for( i = 0; i < modulecount; i++) { 526 if( xar_datamods[i].fh_done ) { 527 int32_t ret; 528 ret = xar_datamods[i].fh_done(x, f, p, &(modulecontext[i])); 529 if( ret < 0 ) 530 return ret; 531 } 532 } 533 return 0; 534} 535 536/* xar_attrcopy_from_heap_to_heap 537* This does a simple copy of the heap data from one head (read-only) to another heap (write only). 538* This does not set any properties or attributes of the file, so this should not be used alone. 539*/ 540int32_t xar_attrcopy_from_heap_to_heap(xar_t xsource, xar_file_t fsource, xar_prop_t p, xar_t xdest, xar_file_t fdest){ 541 int r, off; 542 size_t bsize; 543 int64_t fsize, inc = 0, seekoff, writesize=0; 544 off_t orig_heap_offset = XAR(xdest)->heap_offset; 545 void *inbuf; 546 const char *opt; 547 char *tmpstr = NULL; 548 xar_prop_t tmpp; 549 550 bsize = xar_io_get_rsize(xsource); 551 552 seekoff = xar_io_get_file_offset(xsource, fsource, p); 553 if( seekoff < 0 ) 554 return -1; 555 556 seekoff += XAR(xsource)->toc_count + sizeof(xar_header_t); 557 xar_io_seek(xsource, fsource, seekoff); 558 559 fsize = xar_io_get_length(p); 560 if( fsize == 0 ) 561 return 0; 562 if( fsize < 0 ) 563 return -1; 564 565 inbuf = malloc(bsize); 566 if( !inbuf ) { 567 return -1; 568 } 569 570 571 while(1) { 572 /* Size has been reached */ 573 if( fsize == inc ) 574 break; 575 if( (fsize - inc) < bsize ) 576 bsize = fsize - inc; 577 r = read(XAR(xsource)->fd, inbuf, bsize); 578 if( r == 0 ) 579 break; 580 if( (r < 0) && (errno == EINTR) ) 581 continue; 582 if( r < 0 ) { 583 free(inbuf); 584 return -1; 585 } 586 587 XAR(xsource)->heap_offset += r; 588 inc += r; 589 bsize = r; 590 591 off = 0; 592 593 do { 594 r = write(XAR(xdest)->heap_fd, ((char *)inbuf)+off, r-off ); 595 off += r; 596 writesize += r; 597 } while( off < r ); 598 XAR(xdest)->heap_offset += off; 599 XAR(xdest)->heap_len += off; 600 } 601 602 asprintf(&tmpstr, "%"PRIu64, (uint64_t)orig_heap_offset); 603 opt = xar_prop_getkey(p); 604 tmpp = xar_prop_pfirst(fdest); 605 if( tmpp ) 606 tmpp = xar_prop_find(tmpp, opt); 607 if( tmpp ) 608 xar_prop_pset(fdest, tmpp, "offset", tmpstr); 609 free(tmpstr); 610 611 612 free(inbuf); 613 614 /* It is the caller's responsibility to copy the attributes of the file, etc, this only copies the data in the heap */ 615 616 return 0; 617} 618 619static int32_t flush_stream(xar_stream *stream) { 620 xar_stream_state_t *state = (xar_stream_state_t *)(stream->state); 621 622 if( state->pending_buf && stream->avail_out ) { 623 size_t len = state->pending_buf_size; 624 625 if( stream->avail_out < len ) { 626 len = stream->avail_out; 627 } 628 629 memcpy(stream->next_out, state->pending_buf, len); 630 stream->next_out += len; 631 stream->avail_out -= len; 632 stream->total_out += len; 633 634 if( state->pending_buf_size == len ) { 635 state->pending_buf_size = 0; 636 637 free(state->pending_buf); 638 state->pending_buf = NULL; 639 } else if( state->pending_buf_size > len ) { 640 state->pending_buf_size -= len; 641 memcpy(state->pending_buf, state->pending_buf + len, state->pending_buf_size); 642 } 643 } 644 645 return XAR_STREAM_OK; 646} 647 648static int32_t write_to_stream(void *inbuf, size_t inlen, xar_stream *stream) { 649 xar_stream_state_t *state = (xar_stream_state_t *)stream->state; 650 size_t len = inlen; 651 652 if( stream->avail_out < len ) { 653 len = stream->avail_out; 654 } 655 656 memcpy(stream->next_out, inbuf, len); 657 stream->next_out += len; 658 stream->avail_out -= len; 659 stream->total_out += len; 660 661 if( inlen > len ) { 662 state->pending_buf_size = inlen - len; 663 state->pending_buf = malloc(state->pending_buf_size); 664 665 memcpy(state->pending_buf, ((char *)inbuf) + len, state->pending_buf_size); 666 } 667 668 return XAR_STREAM_OK; 669} 670 671int32_t xar_attrcopy_from_heap_to_stream_init(xar_t x, xar_file_t f, xar_prop_t p, xar_stream *stream) { 672 xar_stream_state_t *state; 673 off_t seekoff; 674 675 seekoff = xar_io_get_file_offset(x, f, p); 676 if( seekoff < 0 ) 677 return XAR_STREAM_ERR; 678 679 state = calloc(1, sizeof(xar_stream_state_t)); 680 if( !state ) { 681 return XAR_STREAM_ERR; 682 } 683 stream->state = (void*)state; 684 state->bsize = xar_io_get_rsize(x); 685 686 state->modulecount = (sizeof(xar_datamods)/sizeof(struct datamod)); 687 state->modulecontext = calloc(1, sizeof(void*)*state->modulecount); 688 if( !state->modulecontext ) { 689 free(state); 690 return XAR_STREAM_ERR; 691 } 692 693 seekoff += XAR(x)->toc_count + sizeof(xar_header_t); 694 xar_io_seek(x, f, seekoff); 695 696 stream->total_in = 0; 697 stream->total_out = 0; 698 699 state->fsize = xar_io_get_length(p); 700 701 if(state->fsize == 0) { 702 return XAR_STREAM_OK; 703 } else if(state->fsize == -1) { 704 free(state->modulecontext); 705 free(state); 706 return XAR_STREAM_ERR; 707 } 708 709 state->pending_buf = NULL; 710 state->pending_buf_size = 0; 711 state->x = x; 712 state->f = f; 713 state->p = p; 714 715 return XAR_STREAM_OK; 716} 717 718int32_t xar_attrcopy_from_heap_to_stream(xar_stream *stream) { 719 xar_stream_state_t *state = stream->state; 720 721 int r, i; 722 size_t bsize; 723 void *inbuf; 724 725 if( state->pending_buf_size ) { 726 return flush_stream(stream); 727 } 728 729 bsize = state->bsize; 730 inbuf = malloc(bsize); 731 if( !inbuf ) { 732 return XAR_STREAM_ERR; 733 } 734 735 /* Size has been reached */ 736 if( state->fsize == stream->total_in ) { 737 free(inbuf); 738 return XAR_STREAM_END; 739 } 740 if( (state->fsize - stream->total_in) < bsize ) 741 bsize = state->fsize - stream->total_in; 742 r = read(XAR(state->x)->fd, inbuf, bsize); 743 if( r == 0 ) { 744 free(inbuf); 745 return XAR_STREAM_END; 746 } 747 if( (r < 0) && (errno == EINTR) ) { 748 free(inbuf); 749 return XAR_STREAM_OK; 750 } 751 if( r < 0 ) { 752 free(inbuf); 753 return XAR_STREAM_ERR; 754 } 755 756 XAR(state->x)->heap_offset += r; 757 stream->total_in += r; 758 bsize = r; 759 760 /* filter the data through the in modules */ 761 for( i = 0; i < state->modulecount; i++) { 762 if( xar_datamods[i].fh_in ) { 763 int32_t ret; 764 ret = xar_datamods[i].fh_in(state->x, state->f, state->p, &inbuf, &bsize, &(state->modulecontext[i])); 765 if( ret < 0 ) 766 return XAR_STREAM_ERR; 767 } 768 } 769 770 /* filter the data through the out modules */ 771 for( i = 0; i < state->modulecount; i++) { 772 if( xar_datamods[i].fh_out ) { 773 int32_t ret; 774 ret = xar_datamods[i].fh_out(state->x, state->f, state->p, inbuf, bsize, &(state->modulecontext[i])); 775 if( ret < 0 ) 776 return XAR_STREAM_ERR; 777 } 778 } 779 780 write_to_stream(inbuf, bsize, stream); 781 782 free(inbuf); 783 784 return XAR_STREAM_OK; 785} 786 787int32_t xar_attrcopy_from_heap_to_stream_end(xar_stream *stream) { 788 xar_stream_state_t *state = (xar_stream_state_t *)stream->state; 789 int i; 790 791 /* finish up anything that still needs doing */ 792 for( i = 0; i < state->modulecount; i++) { 793 if( xar_datamods[i].fh_done ) { 794 int32_t ret; 795 ret = xar_datamods[i].fh_done(state->x, state->f, state->p, &(state->modulecontext[i])); 796 if( ret < 0 ) 797 return ret; 798 } 799 } 800 801 if( state->pending_buf ) { 802 free(state->pending_buf); 803 } 804 805 free(state->modulecontext); 806 free(state); 807 808 return XAR_STREAM_OK; 809} 810 811/* xar_heap_to_archive 812 * x: archive to operate on 813 * Returns 0 on success, -1 on error 814 * Summary: copies the heap into the archive. 815 */ 816int32_t xar_heap_to_archive(xar_t x) { 817 long bsize; 818 ssize_t r; 819 int off; 820 const char *opt; 821 char *b; 822 823 opt = xar_opt_get(x, "rsize"); 824 if( !opt ) { 825 bsize = 4096; 826 } else { 827 bsize = strtol(opt, NULL, 0); 828 if( ((bsize == LONG_MAX) || (bsize == LONG_MIN)) && (errno == ERANGE) ) { 829 bsize = 4096; 830 } 831 } 832 833 b = malloc(bsize); 834 if( !b ) return -1; 835 836 lseek(XAR(x)->heap_fd, 0, SEEK_SET); 837 while(1) { 838 r = read(XAR(x)->heap_fd, b, bsize); 839 if( r == 0 ) break; 840 if( (r < 0) && (errno == EINTR) ) continue; 841 if( r < 0 ) { 842 free(b); 843 return -1; 844 } 845 846 off = 0; 847 do { 848 r = write(XAR(x)->fd, b+off, bsize-off); 849 if( (r < 0) && (errno != EINTR) ) { 850 free(b); 851 return -1; 852 } 853 off += r; 854 } while( off < bsize ); 855 } 856 free(b); 857 return 0; 858} 859