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 <string.h> 44#include <unistd.h> 45#include <fcntl.h> 46#include <libgen.h> 47#include <errno.h> 48#include <limits.h> 49#include <sys/stat.h> 50#include <arpa/inet.h> /* for ntoh{l,s} */ 51#include <inttypes.h> /* for PRIu64 */ 52#include <time.h> 53#include <libxml/xmlwriter.h> 54#include <libxml/xmlreader.h> 55#include <libxml/xmlstring.h> 56#ifndef HAVE_ASPRINTF 57#include "asprintf.h" 58#endif 59#include "xar.h" 60#include "filetree.h" 61#include "archive.h" 62#include "signature.h" 63#include "arcmod.h" 64#include "io.h" 65#include "util.h" 66#include "subdoc.h" 67#include "darwinattr.h" 68 69#ifndef O_EXLOCK 70#define O_EXLOCK 0 71#endif 72#ifndef O_SHLOCK 73#define O_SHLOCK 0 74#endif 75 76#ifndef LONG_MAX 77#define LONG_MAX INT32_MAX 78#endif 79#ifndef LONG_MIN 80#define LONG_MIN INT32_MIN 81#endif 82 83#if LIBXML_VERSION < 20618 84#define xmlDictCleanup() /* function doesn't exist in older API */ 85#endif 86 87static int32_t xar_unserialize(xar_t x); 88void xar_serialize(xar_t x, const char *file); 89 90/* xar_new 91 * Returns: newly allocated xar_t structure 92 * Summary: just does basicallocation and initialization of 93 * xar_t structure. 94 */ 95static xar_t xar_new() { 96 xar_t ret; 97 ret = malloc(sizeof(struct __xar_t)); 98 if(!ret) return NULL; 99 memset(XAR(ret), 0, sizeof(struct __xar_t)); 100 XAR(ret)->readbuf_len = 4096; 101 XAR(ret)->readbuf = malloc(XAR(ret)->readbuf_len); 102 if(!XAR(ret)->readbuf) { 103 free((void *)ret); 104 return NULL; 105 } 106 XAR(ret)->offset = 0; 107 108 XAR(ret)->zs.zalloc = Z_NULL; 109 XAR(ret)->zs.zfree = Z_NULL; 110 XAR(ret)->zs.opaque = Z_NULL; 111 XAR(ret)->ino_hash = xmlHashCreate(0); 112 XAR(ret)->link_hash = xmlHashCreate(0); 113 XAR(ret)->csum_hash = xmlHashCreate(0); 114 XAR(ret)->subdocs = NULL; 115 116 XAR(ret)->attrcopy_to_heap = xar_attrcopy_to_heap; 117 XAR(ret)->attrcopy_from_heap = xar_attrcopy_from_heap; 118 XAR(ret)->heap_to_archive = xar_heap_to_archive; 119 120 return ret; 121} 122 123/* xar_parse_header 124 * x: archive to operate on. 125 * Returns: 0 on success, -1 on failure 126 * Summary: internal helper function to read in the xar header. 127 */ 128static int32_t xar_parse_header(xar_t x) { 129 ssize_t r; 130 int off = 0; 131 int sz2read = 0; 132 133 /* read just the magic, verify it, read the header length, 134 * then read in the size of the header according to the 135 * recorded header length, or the length of the structure 136 * we expect, whichever is smaller. Then seek forward 137 * if the recorded header length is greater than the 138 * expected header length. 139 */ 140 r = xar_read_fd(XAR(x)->fd, (char *)&XAR(x)->header.magic+off, sizeof(XAR(x)->header.magic)-off); 141 if ( r == -1 ) 142 return r; 143 144 /* Verify the header. If the header doesn't match, exit without 145 * attempting to read any more. 146 */ 147 XAR(x)->header.magic = ntohl(XAR(x)->header.magic); 148 149 if( XAR(x)->header.magic != XAR_HEADER_MAGIC ) { 150 return -1; 151 } 152 153 r = xar_read_fd(XAR(x)->fd, (char *)&XAR(x)->header.size+off, sizeof(XAR(x)->header.size)-off); 154 if ( r == -1 ) 155 return r; 156 157 XAR(x)->header.size = ntohs(XAR(x)->header.size); 158 159 if( XAR(x)->header.size > sizeof(xar_header_t) ) 160 sz2read = sizeof(xar_header_t); 161 else 162 sz2read = XAR(x)->header.size; 163 164 off = sizeof(XAR(x)->header.magic) + sizeof(XAR(x)->header.size); 165 r = xar_read_fd(XAR(x)->fd, ((char *)&XAR(x)->header)+off, sizeof(xar_header_t)-off); 166 if ( r == -1 ) 167 return r; 168 169 XAR(x)->header.version = ntohs(XAR(x)->header.version); 170 XAR(x)->header.toc_length_compressed = xar_ntoh64(XAR(x)->header.toc_length_compressed); 171 XAR(x)->header.toc_length_uncompressed = xar_ntoh64(XAR(x)->header.toc_length_uncompressed); 172 XAR(x)->header.cksum_alg = ntohl(XAR(x)->header.cksum_alg); 173 174 off = XAR(x)->header.size - sz2read; 175 if( off > 0 ) 176 r = lseek(XAR(x)->fd, (off_t)off, SEEK_CUR); 177 178 if ( (r == -1) && (errno != ESPIPE) ) 179 /* Some fatal error here perhaps? */ ; 180 181 return 0; 182} 183 184/* xar_open 185 * file: filename to open 186 * flags: flags on how to open the file. 0 for readonly, !0 for read/write 187 * Returns: allocated and initialized xar structure with an open 188 * file descriptor to the target xar file. If the xarchive is opened 189 * for writing, the file is created, and a heap file is opened. 190 */ 191xar_t xar_open(const char *file, int32_t flags) { 192 xar_t ret; 193 194 ret = xar_new(); 195 if( !ret ) return NULL; 196 if( !file ) 197 file = "-"; 198 XAR(ret)->filename = strdup(file); 199 if( flags ) { // writing 200 char *tmp1, *tmp2, *tmp3, *tmp4; 201 tmp1 = tmp2 = strdup(file); 202 tmp3 = dirname(tmp2); 203 XAR(ret)->dirname = strdup(tmp3); 204 /* Create the heap file in the directory which will contain 205 * the target archive. /tmp or elsewhere may fill up. 206 */ 207 asprintf(&tmp4, "%s/xar.heap.XXXXXX", tmp3); 208 free(tmp1); 209 if( strcmp(file, "-") == 0 ) 210 XAR(ret)->fd = 1; 211 else{ 212 XAR(ret)->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_EXLOCK, 0644); 213 if( (-1 == XAR(ret)->fd ) && (ENOTSUP == errno) ){ 214 XAR(ret)->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC , 0644); 215 } 216 } 217 XAR(ret)->heap_fd = mkstemp(tmp4); 218 if( XAR(ret)->heap_fd < 0 ) { 219 close(XAR(ret)->fd); 220 free(XAR(ret)); 221 return NULL; 222 } 223 224 unlink(tmp4); 225 free(tmp4); 226 227 deflateInit(&XAR(ret)->zs, Z_BEST_COMPRESSION); 228 229 if( XAR(ret)->fd < 0 ) { 230 xar_close(ret); 231 return NULL; 232 } 233 234 /* default to using sha1, if nothing else is 235 * specified. 236 */ 237 XAR(ret)->heap_offset += 20; 238 XAR(ret)->heap_len += 20; 239 240 xar_opt_set(ret, XAR_OPT_COMPRESSION, XAR_OPT_VAL_GZIP); 241 xar_opt_set(ret, XAR_OPT_FILECKSUM, XAR_OPT_VAL_SHA1); 242 xar_opt_set(ret, XAR_OPT_TOCCKSUM, XAR_OPT_VAL_SHA1); 243 } else { 244 if( strcmp(file, "-") == 0 ) 245 XAR(ret)->fd = 0; 246 else{ 247 XAR(ret)->fd = open(file, O_RDONLY | O_SHLOCK); 248 249 if( (-1 == XAR(ret)->fd ) && (ENOTSUP == errno) ){ 250 XAR(ret)->fd = open(file, O_RDONLY); 251 } 252 253 } 254 XAR(ret)->heap_fd = -1; 255 inflateInit(&XAR(ret)->zs); 256 if( XAR(ret)->fd < 0 ) { 257 xar_close(ret); 258 return NULL; 259 } 260 261 if( xar_parse_header(ret) != 0 ) { 262 xar_close(ret); 263 return NULL; 264 } 265 266 switch(XAR(ret)->header.cksum_alg) { 267 case XAR_CKSUM_NONE: 268 break; 269 case XAR_CKSUM_SHA1: 270 XAR(ret)->toc_hash_ctx = xar_hash_new("sha1", (void *)ret); 271 break; 272 case XAR_CKSUM_SHA256: 273 XAR(ret)->toc_hash_ctx = xar_hash_new("sha256", (void *)ret); 274 break; 275 case XAR_CKSUM_SHA512: 276 XAR(ret)->toc_hash_ctx = xar_hash_new("sha512", (void *)ret); 277 break; 278 case XAR_CKSUM_MD5: 279 XAR(ret)->toc_hash_ctx = xar_hash_new("md5", (void *)ret); 280 break; 281 default: 282 fprintf(stderr, "Unknown hashing algorithm, skipping\n"); 283 break; 284 }; 285 286 if( xar_unserialize(ret) != 0 ) { 287 xar_close(ret); 288 return NULL; 289 } 290 291 /* check for inconsistency between checksum style in header, 292 * and the one described in the TOC; otherwise, you can flip 293 * the header bit to XAR_CKSUM_NONE, and nothing will ever 294 * verify that the TOC matches the checksum stored in the 295 * heap, and the signature check will pass on a modified 296 * file! <rdar://problem/6134714> 297 */ 298 int cksum_match = 0; 299 const char* cksum_style = xar_attr_get(XAR_FILE(ret), "checksum", "style"); 300 switch(XAR(ret)->header.cksum_alg) { 301 case XAR_CKSUM_NONE: 302 cksum_match = (cksum_style == NULL || strcmp(cksum_style, XAR_OPT_VAL_NONE) == 0); 303 break; 304 case XAR_CKSUM_SHA1: 305 cksum_match = (cksum_style != NULL && strcmp(cksum_style, XAR_OPT_VAL_SHA1) == 0); 306 break; 307 case XAR_CKSUM_SHA256: 308 cksum_match = (cksum_style != NULL && strcmp(cksum_style, XAR_OPT_VAL_SHA256) == 0); 309 break; 310 case XAR_CKSUM_SHA512: 311 cksum_match = (cksum_style != NULL && strcmp(cksum_style, XAR_OPT_VAL_SHA512) == 0); 312 break; 313 case XAR_CKSUM_MD5: 314 cksum_match = (cksum_style != NULL && strcmp(cksum_style, XAR_OPT_VAL_MD5) == 0); 315 break; 316 default: 317 cksum_match = 0; 318 break; 319 } 320 if( !cksum_match ) { 321 fprintf(stderr, "Checksum style mismatch!\n"); 322 xar_close(ret); 323 return NULL; 324 } 325 326 /* also check for consistency between the checksum style and 327 * the existence (or not) of signatures: since the signature 328 * is signing the checksum, we must have a checksum to verify 329 * that the TOC has not been modified <rdar://problem/6134714> 330 */ 331 if( xar_signature_first(ret) != NULL && XAR(ret)->header.cksum_alg == XAR_CKSUM_NONE ) { 332 fprintf(stderr, "Checksum/signature mismatch!\n"); 333 xar_close(ret); 334 return NULL; 335 } 336 337 /* If we aren't checksumming the TOC, we're done */ 338 if( !XAR(ret)->toc_hash_ctx ) 339 return ret; 340 341 /* if TOC specifies a location for the checksum, make sure that 342 * we read the checksum from there: this is required for an archive 343 * with a signature, because the signature will be checked against 344 * the checksum at the specified location <rdar://problem/7041949> 345 */ 346 const char *value; 347 uint64_t offset = 0; 348 uint64_t length = 0; 349 if( xar_prop_get( XAR_FILE(ret) , "checksum/offset", &value) == 0 ) { 350 errno = 0; 351 offset = strtoull( value, (char **)NULL, 10); 352 if( errno != 0 ) { 353 xar_close(ret); 354 return NULL; 355 } 356 } else if( xar_signature_first(ret) != NULL ) { 357 // All archives that have a signature also specify the location 358 // of the checksum. If the location isn't specified, error out. 359 xar_close(ret); 360 return NULL; 361 } 362 363 XAR(ret)->heap_offset = xar_get_heap_offset(ret) + offset; 364 if( lseek(XAR(ret)->fd, XAR(ret)->heap_offset, SEEK_SET) == -1 ) { 365 xar_close(ret); 366 return NULL; 367 } 368 if( xar_prop_get( XAR_FILE(ret) , "checksum/size", &value) == 0 ) { 369 errno = 0; 370 length = strtoull( value, (char **)NULL, 10); 371 if( errno != 0 ) { 372 xar_close(ret); 373 return NULL; 374 } 375 } else if( xar_signature_first(ret) != NULL ) { 376 xar_close(ret); 377 return NULL; 378 } 379 380 size_t tlen = 0; 381 void *toccksum = xar_hash_finish(XAR(ret)->toc_hash_ctx, &tlen); 382 383 if( length != tlen ) { 384 free(toccksum); 385 xar_close(ret); 386 return NULL; 387 } 388 389 void *cval = calloc(1, tlen); 390 if( ! cval ) { 391 free(toccksum); 392 xar_close(ret); 393 return NULL; 394 } 395 396 xar_read_fd(XAR(ret)->fd, cval, tlen); 397 XAR(ret)->heap_offset += tlen; 398 if( memcmp(cval, toccksum, tlen) != 0 ) { 399 fprintf(stderr, "Checksums do not match!\n"); 400 free(toccksum); 401 free(cval); 402 xar_close(ret); 403 return NULL; 404 } 405 406 free(toccksum); 407 free(cval); 408 } 409 410 return ret; 411} 412 413/* xar_close 414 * x: the xar_t to close 415 * Summary: closes all open file descriptors, frees all 416 * file structures and options, deallocates the xar_t its self. 417 * Returns 0 for success, -1 for failure. 418 */ 419int xar_close(xar_t x) { 420 xar_attr_t a; 421 xar_file_t f; 422 int ret, retval = 0; 423 424 /* If we're creating an archive */ 425 if( XAR(x)->heap_fd != -1 ) { 426 char *tmpser; 427 void *rbuf, *wbuf = NULL; 428 int fd, r, off, wbytes, rbytes; 429 long rsize, wsize; 430 z_stream zs; 431 uint64_t ungztoc, gztoc; 432 int tocfd; 433 char timestr[128]; 434 struct tm tmptm; 435 time_t t; 436 437 tmpser = (char *)xar_opt_get(x, XAR_OPT_TOCCKSUM); 438 /* If no checksum type is specified, default to sha1 */ 439 if( !tmpser ) tmpser = XAR_OPT_VAL_SHA1; 440 441 if( (strcmp(tmpser, XAR_OPT_VAL_NONE) != 0) ) { 442 xar_prop_set(XAR_FILE(x), "checksum", NULL); 443 if( strcmp(tmpser, XAR_OPT_VAL_SHA1) == 0 ) { 444 XAR(x)->toc_hash_ctx = xar_hash_new("sha1", (void *)x); 445 XAR(x)->header.cksum_alg = htonl(XAR_CKSUM_SHA1); 446 xar_attr_set(XAR_FILE(x), "checksum", "style", XAR_OPT_VAL_SHA1); 447 xar_prop_set(XAR_FILE(x), "checksum/size", "20"); 448 } 449 if( strcmp(tmpser, XAR_OPT_VAL_SHA256) == 0 ) { 450 XAR(x)->toc_hash_ctx = xar_hash_new("sha256", (void *)x); 451 XAR(x)->header.cksum_alg = htonl(XAR_CKSUM_SHA256); 452 xar_attr_set(XAR_FILE(x), "checksum", "style", XAR_OPT_VAL_SHA256); 453 xar_prop_set(XAR_FILE(x), "checksum/size", "32"); 454 } 455 if( strcmp(tmpser, XAR_OPT_VAL_SHA512) == 0 ) { 456 XAR(x)->toc_hash_ctx = xar_hash_new("sha512", (void *)x); 457 XAR(x)->header.cksum_alg = htonl(XAR_CKSUM_SHA512); 458 xar_attr_set(XAR_FILE(x), "checksum", "style", XAR_OPT_VAL_SHA512); 459 xar_prop_set(XAR_FILE(x), "checksum/size", "64"); 460 } 461 if( strcmp(tmpser, XAR_OPT_VAL_MD5) == 0 ) { 462 XAR(x)->toc_hash_ctx = xar_hash_new("md5", (void *)x); 463 XAR(x)->header.cksum_alg = htonl(XAR_CKSUM_MD5); 464 xar_attr_set(XAR_FILE(x), "checksum", "style", XAR_OPT_VAL_MD5); 465 xar_prop_set(XAR_FILE(x), "checksum/size", "16"); 466 } 467 468 xar_prop_set(XAR_FILE(x), "checksum/offset", "0"); 469 } else { 470 XAR(x)->header.cksum_alg = XAR_CKSUM_NONE; 471 } 472 473 t = time(NULL); 474 gmtime_r(&t, &tmptm); 475 memset(timestr, 0, sizeof(timestr)); 476 strftime(timestr, sizeof(timestr), "%FT%T", &tmptm); 477 xar_prop_set(XAR_FILE(x), "creation-time", timestr); 478 479 /* serialize the toc to a tmp file */ 480 asprintf(&tmpser, "%s/xar.toc.XXXXXX", XAR(x)->dirname); 481 fd = mkstemp(tmpser); 482 xar_serialize(x, tmpser); 483 unlink(tmpser); 484 free(tmpser); 485 asprintf(&tmpser, "%s/xar.toc.XXXXXX", XAR(x)->dirname); 486 tocfd = mkstemp(tmpser); 487 unlink(tmpser); 488 free(tmpser); 489 490 491 /* read the toc from the tmp file, compress it, and write it 492 * out to the archive. 493 */ 494 rsize = wsize = 4096; 495 const char * opt = xar_opt_get(x, XAR_OPT_RSIZE); 496 if ( opt ) { 497 rsize = strtol(opt, NULL, 0); 498 if ( ((rsize == LONG_MAX) || (rsize == LONG_MIN)) && (errno == ERANGE) ) { 499 rsize = wsize; 500 } 501 } 502 503 rbuf = malloc(rsize); 504 if( !rbuf ) { 505 retval = -1; 506 close(fd); 507 close(tocfd); 508 goto CLOSE_BAIL; 509 } 510 zs.zalloc = Z_NULL; 511 zs.zfree = Z_NULL; 512 zs.opaque = Z_NULL; 513 deflateInit(&zs, Z_BEST_COMPRESSION); 514 515 ungztoc = gztoc = 0; 516 517 while(1) { 518 r = read(fd, rbuf, rsize); 519 if( (r < 0) && (errno == EINTR) ) 520 continue; 521 if( r == 0 ) 522 break; 523 524 ungztoc += r; 525 526 zs.avail_in = r; 527 zs.next_in = (void *)rbuf; 528 zs.next_out = NULL; 529 zs.avail_out = 0; 530 531 wsize = rsize/2; 532 533 off = 0; 534 while( zs.avail_in != 0 ) { 535 wsize *= 2; 536 wbuf = realloc(wbuf, wsize); 537 538 zs.next_out = ((unsigned char *)wbuf) + off; 539 zs.avail_out = wsize - off; 540 541 ret = deflate(&zs, Z_SYNC_FLUSH); 542 off = wsize - zs.avail_out; 543 } 544 545 wbytes = off; 546 off = 0; 547 do { 548 r = write(tocfd, ((char *)wbuf)+off, wbytes-off); 549 if( (r < 0) && (errno == EINTR) ) 550 continue; 551 if( r < 0 ) { 552 xar_err_new(x); 553 xar_err_set_string(x, "Error closing xar archive"); 554 retval = -1; 555 goto CLOSEEND; 556 } 557 if( XAR(x)->toc_hash_ctx ) 558 xar_hash_update(XAR(x)->toc_hash_ctx, ((char*)wbuf)+off, r); 559 off += r; 560 gztoc += r; 561 } while( off < wbytes ); 562 563 } 564 565 zs.next_in = NULL; 566 zs.avail_in = 0; 567 zs.next_out = wbuf; 568 zs.avail_out = wsize; 569 570 deflate(&zs, Z_FINISH); 571 r = write(tocfd, wbuf, wsize - zs.avail_out); 572 gztoc += r; 573 if( XAR(x)->toc_hash_ctx ) 574 xar_hash_update(XAR(x)->toc_hash_ctx, wbuf, r); 575 576 deflateEnd(&zs); 577 578 /* populate the header and write it out */ 579 XAR(x)->header.magic = htonl(XAR_HEADER_MAGIC); 580 XAR(x)->header.size = ntohs(sizeof(xar_header_t)); 581 XAR(x)->header.version = ntohs(1); 582 XAR(x)->header.toc_length_uncompressed = xar_ntoh64(ungztoc); 583 XAR(x)->header.toc_length_compressed = xar_ntoh64(gztoc); 584 585 write(XAR(x)->fd, &XAR(x)->header, sizeof(xar_header_t)); 586 587 /* Copy the temp compressed toc file into the file */ 588 lseek(tocfd, (off_t)0, SEEK_SET); 589 while(1) { 590 r = read(tocfd, rbuf, rsize); 591 if( (r < 0) && (errno == EINTR) ) 592 continue; 593 if( r == 0 ) 594 break; 595 596 wbytes = r; 597 off = 0; 598 do { 599 r = write(XAR(x)->fd, ((char *)rbuf)+off, wbytes-off); 600 if( (r < 0) && (errno == EINTR) ) 601 continue; 602 if( r < 0 ) { 603 xar_err_new(x); 604 xar_err_set_string(x, "Error closing xar archive"); 605 retval = -1; 606 goto CLOSEEND; 607 } 608 609 off += r; 610 } while( off < wbytes ); 611 } 612 613 if( XAR(x)->toc_hash_ctx ) { 614 size_t chklen = 0; 615 void *chkstr = xar_hash_finish(XAR(x)->toc_hash_ctx, &chklen); 616 write(XAR(x)->fd, chkstr, chklen); 617 618 /* If there are any signatures, get the signed data a sign it */ 619 if( XAR(x)->signatures ) { 620 xar_signature_t sig; 621 uint32_t signed_len = 0; 622 uint8_t *signed_data = NULL; 623 624 /* Loop through the signatures */ 625 for(sig = XAR(x)->signatures; sig; sig = XAR_SIGNATURE(sig)->next ){ 626 signed_len = XAR_SIGNATURE(sig)->len; 627 628 /* If callback returns something other then 0, bail */ 629 if( 0 != sig->signer_callback( sig, sig->callback_context, chkstr, chklen, &signed_data, &signed_len ) ){ 630 fprintf(stderr, "Error signing data.\n"); 631 free(chkstr); 632 retval = -1; 633 close(fd); 634 close(tocfd); 635 goto CLOSE_BAIL; 636 } 637 638 if( signed_len != XAR_SIGNATURE(sig)->len ){ 639 fprintf(stderr, "Signed data not the proper length. %i should be %i.\n",signed_len,XAR_SIGNATURE(sig)->len); 640 free(chkstr); 641 retval = -1; 642 close(fd); 643 close(tocfd); 644 goto CLOSE_BAIL; 645 } 646 647 /* Write the signed data to the heap */ 648 write(XAR(x)->fd, signed_data,XAR_SIGNATURE(sig)->len); 649 650 free(signed_data); 651 } 652 free(chkstr); 653 } 654 655 xar_signature_remove( XAR(x)->signatures ); 656 XAR(x)->signatures = NULL; 657 } 658 659 /* copy the heap from the temporary heap into the archive */ 660 if( 0 > XAR(x)->heap_to_archive(x) ) { 661 xar_err_new(x); 662 xar_err_set_string(x, "Error while copying heap contents into archive"); 663 xar_err_set_errno(x, errno); 664 xar_err_callback(x, XAR_SEVERITY_FATAL, XAR_ERR_ARCHIVE_CREATION); 665 retval = -1; 666 close(fd); 667 close(tocfd); 668 goto CLOSEEND; 669 } 670 671CLOSEEND: 672 close(fd); 673 close(tocfd); 674 free(rbuf); 675 free(wbuf); 676 deflateEnd(&XAR(x)->zs); 677 } else { 678 679 xar_signature_remove( XAR(x)->signatures ); 680 XAR(x)->signatures = NULL; 681 682 inflateEnd(&XAR(x)->zs); 683 } 684 685CLOSE_BAIL: 686 /* continue deallocating the archive and return */ 687 while(XAR(x)->subdocs) { 688 xar_subdoc_remove(XAR(x)->subdocs); 689 } 690 691 while(XAR(x)->attrs) { 692 a = XAR(x)->attrs; 693 XAR(x)->attrs = XAR_ATTR(a)->next; 694 xar_attr_free(a); 695 } 696 697 while(XAR(x)->props) { 698 xar_prop_t p; 699 p = XAR(x)->props; 700 XAR(x)->props = XAR_PROP(p)->next; 701 xar_prop_free(p); 702 } 703 704 while(XAR(x)->files) { 705 f = XAR(x)->files; 706 XAR(x)->files = XAR_FILE(f)->next; 707 xar_file_free(f); 708 } 709 710 xmlHashFree(XAR(x)->ino_hash, NULL); 711 xmlHashFree(XAR(x)->link_hash, NULL); 712 xmlHashFree(XAR(x)->csum_hash, NULL); 713 close(XAR(x)->fd); 714 if( XAR(x)->heap_fd >= 0 ) 715 close(XAR(x)->heap_fd); 716 free((char *)XAR(x)->filename); 717 free((char *)XAR(x)->dirname); 718 free(XAR(x)->readbuf); 719 free((void *)x); 720 721 return retval; 722} 723 724/* xar_opt_get 725 * x: archive to get the option from 726 * option: name of the option 727 * Returns: a pointer to the value of the option 728 * In the case of more than one option with the same name, this will 729 * return the first match. 730 */ 731const char *xar_opt_get(xar_t x, const char *option) { 732 xar_attr_t i; 733 for(i = XAR(x)->attrs; i && XAR_ATTR(i)->next; i = XAR_ATTR(i)->next) { 734 if(strcmp(XAR_ATTR(i)->key, option)==0) 735 return XAR_ATTR(i)->value; 736 } 737 if( i && (strcmp(XAR_ATTR(i)->key, option)==0) ) 738 return XAR_ATTR(i)->value; 739 return NULL; 740} 741 742/* xar_opt_set 743 * x: the archive to set the option of 744 * option: the name of the option to set the value of 745 * value: the value to set the option to 746 * Returns: 0 for sucess, -1 for failure 747 */ 748int32_t xar_opt_set(xar_t x, const char *option, const char *value) { 749 xar_attr_t currentAttr, a; 750 751 if( (strcmp(option, XAR_OPT_TOCCKSUM) == 0) ) { 752 XAR(x)->heap_offset = xar_io_get_toc_checksum_length_for_type(value); 753 } 754 755 /* This was an edit from xar-1.4 756 Looks like we would only allow one definition for a particular key in this list 757 But xar_opt_unset is implemented to remove many pairs for the same key 758 759 // if the attribute is already defined, find it and free its value, 760 // replace and return 761 for(currentAttr = XAR(x)->attrs; currentAttr ; currentAttr = XAR_ATTR(currentAttr)->next) { 762 if(strcmp(XAR_ATTR(currentAttr)->key, option)==0) { 763 free((char*)XAR_ATTR(currentAttr)->value); 764 XAR_ATTR(currentAttr)->value = strdup(value); 765 return 0; 766 } 767 } */ 768 769 // otherwise create a new attribute 770 a = xar_attr_new(); 771 XAR_ATTR(a)->key = strdup(option); 772 XAR_ATTR(a)->value = strdup(value); 773 // and prepend it to the attrs list for the archive 774 XAR_ATTR(a)->next = XAR(x)->attrs; 775 XAR(x)->attrs = a; 776 return 0; 777} 778 779/* xar_opt_unset 780 * x: the archive to set the option of 781 * option: the name of the option to delete 782 * This will delete ALL instances of the option name 783 */ 784int32_t xar_opt_unset(xar_t x, const char *option) { 785 xar_attr_t currentAttr, previousAttr = NULL; 786 for(currentAttr = XAR(x)->attrs; 787 currentAttr ; 788 previousAttr = currentAttr, currentAttr = XAR_ATTR(currentAttr)->next) { 789 if(strcmp(XAR_ATTR(currentAttr)->key, option)==0) { 790 791 // if this attribute match is the head of the attrs list 792 // promote the next list item to the head 793 if( previousAttr == NULL ) 794 XAR(previousAttr)->attrs = XAR_ATTR(currentAttr)->next; 795 796 // otherwise splice the list around this attr 797 else 798 XAR_ATTR(previousAttr)->next = XAR_ATTR(currentAttr)->next; 799 xar_attr_free(currentAttr); 800 801 // keep going to find other instances 802 currentAttr = previousAttr; 803 } 804 } 805 return 0; 806} 807 808/* xar_add_node 809 * x: archive the file should belong to 810 * f: parent node, possibly NULL 811 * name: name of the node to add 812 * realpath: real path to item, this is used if the item being archived is to be located at a different location in the tree 813 * then it is on the real filesystem. 814 * Returns: newly allocated and populated node 815 * Summary: helper function which adds a child of f and populates 816 * its properties. If f is NULL, the node will be added as a top 817 * level node of the archive, x. 818 */ 819static xar_file_t xar_add_node(xar_t x, xar_file_t f, const char *name, const char *prefix, const char *realpath, int srcpath) { 820 xar_file_t ret; 821 const char *path; 822 char *tmp; 823 char idstr[32]; 824 825 if( !f ) { 826 if( realpath ) 827 asprintf(&tmp, "%s", realpath); 828 else 829 asprintf(&tmp, "%s%s%s", XAR(x)->path_prefix, prefix, name); 830 831 if( lstat(tmp, &XAR(x)->sbcache) != 0 ) { 832 free(tmp); 833 return NULL; 834 } 835 836 ret = xar_file_new(NULL); 837 if( !ret ) 838 return NULL; 839 memset(idstr, 0, sizeof(idstr)); 840 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 841 xar_attr_set(ret, NULL, "id", idstr); 842 XAR_FILE(ret)->parent = NULL; 843 XAR_FILE(ret)->fspath = tmp; 844 if( XAR(x)->files == NULL ) 845 XAR(x)->files = ret; 846 else { 847 XAR_FILE(ret)->next = XAR(x)->files; 848 XAR(x)->files = ret; 849 } 850 } else { 851 path = XAR_FILE(f)->fspath; 852 if( strcmp(prefix, "../") == 0 ) { 853 int len1, len2; 854 len1 = strlen(path); 855 len2 = strlen(name); 856 if( (len1>=len2) && (strcmp(path+(len1-len2), name) == 0) ) { 857 return f; 858 } 859 860 } 861 862 if( realpath ){ 863 asprintf(&tmp, "%s", realpath); 864 }else 865 asprintf(&tmp, "%s/%s%s", path, prefix, name); 866 867 if( lstat(tmp, &XAR(x)->sbcache) != 0 ) { 868 free(tmp); 869 return NULL; 870 } 871 872 ret = xar_file_new(f); 873 if( !ret ) 874 return NULL; 875 memset(idstr, 0, sizeof(idstr)); 876 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 877 xar_attr_set(ret, NULL, "id", idstr); 878 XAR_FILE(ret)->fspath = tmp; 879 } 880 881 xar_prop_set(ret, "name", name); 882 883 if( xar_arcmod_archive(x, ret, XAR_FILE(ret)->fspath, NULL, 0) < 0 ) { 884 xar_file_t i = NULL; 885 if( f ) { 886 if( ret == XAR_FILE(f)->children ) 887 XAR_FILE(f)->children = XAR_FILE(ret)->next; 888 else 889 for( i = XAR_FILE(f)->children; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next ); 890 } else { 891 if( ret == XAR(x)->files ) 892 XAR(x)->files = XAR_FILE(ret)->next; 893 else 894 for( i = XAR(x)->files; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next ); 895 } 896 if( i ) 897 XAR_FILE(i)->next = XAR_FILE(ret)->next; 898 xar_file_free(ret); 899 return NULL; 900 } 901 902 return ret; 903} 904 905/* xar_add_pseudodir 906 * Summary: Adds a placeholder directory when archiving a file prior 907 * to archiving its path. 908 */ 909static xar_file_t xar_add_pseudodir(xar_t x, xar_file_t f, const char *name, const char *prefix, const char *realpath) 910{ 911 xar_file_t ret; 912 const char *path; 913 char *tmp; 914 char idstr[32]; 915 916 if( !f ) { 917 if( realpath ) 918 asprintf(&tmp, "%s", realpath); 919 else 920 asprintf(&tmp, "%s%s%s", XAR(x)->path_prefix, prefix, name); 921 922 if( lstat(tmp, &XAR(x)->sbcache) != 0 ) { 923 free(tmp); 924 return NULL; 925 } 926 927 ret = xar_file_new(NULL); 928 if( !ret ) 929 return NULL; 930 memset(idstr, 0, sizeof(idstr)); 931 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 932 xar_attr_set(ret, NULL, "id", idstr); 933 XAR_FILE(ret)->parent = NULL; 934 XAR_FILE(ret)->fspath = tmp; 935 if( XAR(x)->files == NULL ) 936 XAR(x)->files = ret; 937 else { 938 XAR_FILE(ret)->next = XAR(x)->files; 939 XAR(x)->files = ret; 940 } 941 } else { 942 path = XAR_FILE(f)->fspath; 943 if( strcmp(prefix, "../") == 0 ) { 944 int len1, len2; 945 len1 = strlen(path); 946 len2 = strlen(name); 947 if( (len1>=len2) && (strcmp(path+(len1-len2), name) == 0) ) { 948 return f; 949 } 950 951 } 952 953 if( realpath ){ 954 asprintf(&tmp, "%s", realpath); 955 }else 956 asprintf(&tmp, "%s/%s%s", path, prefix, name); 957 958 if( lstat(tmp, &XAR(x)->sbcache) != 0 ) { 959 free(tmp); 960 return NULL; 961 } 962 963 ret = xar_file_new(f); 964 if( !ret ) 965 return NULL; 966 memset(idstr, 0, sizeof(idstr)); 967 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 968 xar_attr_set(ret, NULL, "id", idstr); 969 XAR_FILE(ret)->fspath = tmp; 970 } 971 xar_prop_set(ret, "name", name); 972 xar_prop_set(ret, "type", "directory"); 973 974 return ret; 975} 976 977/* xar_add_r 978 * Summary: a recursive helper function for adding a node to the 979 * tree. This will search all children of node f, looking for 980 * the path component. If found, will recurse into it. If not, 981 * will add the path component to the tree, and recurse into it. 982 * If f is NULL, will start with x->files. 983 */ 984static xar_file_t xar_add_r(xar_t x, xar_file_t f, const char *path, const char *prefix) { 985 xar_file_t i = NULL, ret, ret2, start = NULL; 986 char *tmp1, *tmp2, *tmp3; 987 988 if( path && (path[0] == '\0') ) { 989 return f; 990 } 991 992 tmp1 = tmp2 = strdup(path); 993 tmp3 = strsep(&tmp2, "/"); 994 995 if( tmp3 && tmp2 && (tmp3[0] == '\0') ) { 996 ret2 = xar_add_r(x, f, tmp2, ""); 997 free(tmp1); 998 return ret2; 999 } 1000 1001 if( strcmp(tmp3, "..") == 0 ) { 1002 char *prefixstr; 1003 if( !XAR(x)->skipwarn ) { 1004 xar_err_new(x); 1005 xar_err_set_string(x, "Skipping .. in path"); 1006 xar_err_callback(x, XAR_SEVERITY_WARNING, XAR_ERR_ARCHIVE_CREATION); 1007 XAR(x)->skipwarn = 1; 1008 } 1009 asprintf(&prefixstr, "%s../", prefix); 1010 ret2 = xar_add_r(x, f, tmp2, prefixstr); 1011 free(prefixstr); 1012 free(tmp1); 1013 return ret2; 1014 } 1015 1016 if( strcmp(tmp3, ".") == 0 ) { 1017 if( tmp2 ) 1018 ret2 = xar_add_r(x, f, tmp2, prefix); 1019 else 1020 ret2 = NULL; 1021 free(tmp1); 1022 return ret2; 1023 } 1024 1025 if( !f ) { 1026 start = XAR(x)->files; 1027 } else { 1028 start = XAR_FILE(f)->children; 1029 } 1030 1031 /* Search all the siblings */ 1032 for( i = start; i; i = XAR_FILE(i)->next ) { 1033 const char *n; 1034 xar_prop_get(i, "name", &n); 1035 if( strcmp(n, tmp3) == 0 ) { 1036 if( !tmp2 ) { 1037 /* Node already exists, and it is i */ 1038 free(tmp1); 1039 return i; 1040 } 1041 ret2 = xar_add_r(x, i, tmp2, ""); 1042 free(tmp1); 1043 return ret2; 1044 } 1045 } 1046 1047 /* tmp3 was not found in children of start, so we add it */ 1048 if( tmp2 ) { 1049 //ret = xar_add_node(x, f, tmp3, prefix, NULL, 1); 1050 ret = xar_add_pseudodir(x, f, tmp3, prefix, NULL); 1051 } else { 1052 ret = xar_add_node(x, f, tmp3, prefix, NULL, 0); 1053 } 1054 1055 if( !ret ) { 1056 free(tmp1); 1057 return NULL; 1058 } 1059 1060 if( !tmp2 ) { 1061 /* We've added the final piece, done, don't recurse */ 1062 free(tmp1); 1063 return ret; 1064 } 1065 1066 /* still more to add, recurse */ 1067 ret2 = xar_add_r(x, ret, tmp2, ""); 1068 free(tmp1); 1069 return ret2; 1070} 1071 1072/* xar_add 1073 * x: archive to add the file to 1074 * path: path to file 1075 * Returns: allocated an populated xar_file_t representing the 1076 * specified file. 1077 * Summary: if a full path "foo/bar/blah" is specified, then any 1078 * directories not already existing in the archive will be added 1079 * automagically. The returned xar_file_t represents the file 1080 * specified, not the parent of the directory tree. 1081 * For instance, if "foo/bar/blah" is specified, the xar_file_t 1082 * representing "blah" will be returned. 1083 */ 1084xar_file_t xar_add(xar_t x, const char *path) { 1085#ifdef __APPLE__ 1086 xar_file_t ret; 1087 if( (ret = xar_underbar_check(x, NULL, path)) ) 1088 return ret; 1089#endif 1090 1091 if( path[0] == '/' ) { 1092 XAR(x)->path_prefix = "/"; 1093 path++; 1094 } else 1095 XAR(x)->path_prefix = ""; 1096 return xar_add_r(x, NULL, path, ""); 1097} 1098 1099/* xar_add_frombuffer 1100* x: archive to add the file to 1101* parent: parent node, possibly NULL 1102* name: name of file 1103* buffer: buffer for file contents 1104* length: length of buffer 1105* Returns: allocated an populated xar_file_t representing the 1106* specified file. 1107* Summary: Use this to add chunks of named data to a xar without 1108* using the filesystem. 1109*/ 1110 1111xar_file_t xar_add_frombuffer(xar_t x, xar_file_t parent, const char *name, char *buffer, size_t length) { 1112 xar_file_t ret; 1113 char idstr[32]; 1114 1115 if( !parent ) { 1116 ret = xar_file_new(NULL); 1117 if( !ret ) 1118 return NULL; 1119 memset(idstr, 0, sizeof(idstr)); 1120 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 1121 xar_attr_set(ret, NULL, "id", idstr); 1122 XAR_FILE(ret)->parent = NULL; 1123 if( XAR(x)->files == NULL ) 1124 XAR(x)->files = ret; 1125 else { 1126 XAR_FILE(ret)->next = XAR(x)->files; 1127 XAR(x)->files = ret; 1128 } 1129 } else { 1130 ret = xar_file_new(parent); 1131 if( !ret ) 1132 return NULL; 1133 memset(idstr, 0, sizeof(idstr)); 1134 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 1135 xar_attr_set(ret, NULL, "id", idstr); 1136 XAR_FILE(ret)->fspath = NULL; 1137 } 1138 1139 xar_prop_set(ret, "name", name); 1140 1141 //int32_t xar_arcmod_archive(xar_t x, xar_file_t f, const char *file, const char *buffer, size_t len) 1142 if( xar_arcmod_archive(x, ret, NULL , buffer , length) < 0 ) { 1143 xar_file_t i; 1144 if( parent ) { 1145 for( i = XAR_FILE(parent)->children; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next ); 1146 } else { 1147 for( i = XAR(x)->files; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next ); 1148 } 1149 if( i ) 1150 XAR_FILE(i)->next = XAR_FILE(ret)->next; 1151 xar_file_free(ret); 1152 return NULL; 1153 } 1154 1155 return ret; 1156} 1157 1158xar_file_t xar_add_folder(xar_t x, xar_file_t f, const char *name, struct stat *info) 1159{ 1160 xar_file_t ret; 1161 char idstr[32]; 1162 1163 if( info ) 1164 memcpy(&XAR(x)->sbcache,info,sizeof(struct stat)); 1165 1166 ret = xar_file_new(f); 1167 if( !ret ) 1168 return NULL; 1169 1170 memset(idstr, 0, sizeof(idstr)); 1171 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 1172 xar_attr_set(ret, NULL, "id", idstr); 1173 XAR_FILE(ret)->fspath = NULL; 1174 1175 if( !f ) { 1176 XAR_FILE(ret)->parent = NULL; 1177 1178 if( XAR(x)->files == NULL ) 1179 XAR(x)->files = ret; 1180 else { 1181 XAR_FILE(ret)->next = XAR(x)->files; 1182 XAR(x)->files = ret; 1183 } 1184 } 1185 1186 xar_prop_set(ret, "name", name); 1187 1188 if( xar_arcmod_archive(x, ret, XAR_FILE(ret)->fspath, NULL, 0) < 0 ) { 1189 xar_file_t i; 1190 if( f ) { 1191 for( i = XAR_FILE(f)->children; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next ); 1192 } else { 1193 for( i = XAR(x)->files; i && (XAR_FILE(i)->next != ret); i = XAR_FILE(i)->next ); 1194 } 1195 if( i ) 1196 XAR_FILE(i)->next = XAR_FILE(ret)->next; 1197 xar_file_free(ret); 1198 return NULL; 1199 } 1200 1201 return ret; 1202} 1203 1204xar_file_t xar_add_frompath(xar_t x, xar_file_t parent, const char *name, const char *realpath) 1205{ 1206 return xar_add_node(x, parent, name , "" , realpath, 1); 1207} 1208 1209xar_file_t xar_add_from_archive(xar_t x, xar_file_t parent, const char *name, xar_t sourcearchive, xar_file_t sourcefile) 1210{ 1211 xar_file_t ret; 1212 char idstr[32]; 1213 1214 ret = xar_file_replicate(sourcefile, parent); 1215 1216 if( !ret ) 1217 return NULL; 1218 1219 memset(idstr, 0, sizeof(idstr)); 1220 snprintf(idstr, sizeof(idstr)-1, "%"PRIu64, ++XAR(x)->last_fileid); 1221 xar_attr_set(ret, NULL, "id", idstr); 1222 XAR_FILE(ret)->fspath = NULL; 1223 1224 if( !parent ) { 1225 XAR_FILE(ret)->parent = NULL; 1226 1227 if( XAR(x)->files == NULL ) 1228 XAR(x)->files = ret; 1229 else { 1230 XAR_FILE(ret)->next = XAR(x)->files; 1231 XAR(x)->files = ret; 1232 } 1233 } 1234 1235 xar_prop_set(ret, "name", name); 1236 1237 /* iterate through all the properties, see if any of them have an offset */ 1238 xar_prop_t p = xar_prop_pfirst(ret); 1239 1240 do{ 1241 xar_prop_t tmpp; 1242 1243 tmpp = xar_prop_pget(p, "offset"); 1244 if(tmpp) { 1245 if( 0 != xar_attrcopy_from_heap_to_heap(sourcearchive, sourcefile, p, x, ret)){ 1246 xar_file_free(ret); 1247 ret = NULL; 1248 break; 1249 } 1250 } 1251 1252 }while( (p = xar_prop_pnext(p)) ); 1253 1254 return ret; 1255} 1256 1257/* xar_extract_tofile 1258* x: archive to extract from 1259* f: file associated with x 1260* Returns 0 on success, -1 on failure 1261* Summary: This actually does the file extraction. 1262* No traversal is performed, it is assumed all directory paths 1263* leading up to f already exist. 1264*/ 1265int32_t xar_extract_tofile(xar_t x, xar_file_t f, const char *path) { 1266 return xar_arcmod_extract(x, f, path,NULL, 0); 1267} 1268 1269 1270/* xar_extract_tobuffer 1271* x: archive to extract from 1272* buffer: buffer to extract to 1273* Returns 0 on success, -1 on failure. 1274* Summary: This is the entry point for extraction to a buffer. 1275* On success, a buffer is allocated with the contents of the file 1276* specified. The caller is responsible for freeing the returend buffer. 1277* Example: xar_extract_tobuffer(x, "foo/bar/blah",&buffer) 1278*/ 1279int32_t xar_extract_tobuffer(xar_t x, xar_file_t f, char **buffer) { 1280 size_t size; 1281 1282 return xar_extract_tobuffersz(x, f, buffer, &size); 1283} 1284 1285/* xar_extract_tobuffer 1286* x: archive to extract from 1287* buffer: buffer to extract to 1288* size: On return, this will contain the size of the memory pointed to by buffer 1289* Returns 0 on success, -1 on failure. 1290* Summary: This is the entry point for extraction to a buffer. 1291* On success, a buffer is allocated with the contents of the file 1292* specified. The caller is responsible for freeing the returend buffer. 1293* Example: xar_extract_tobuffer(x, "foo/bar/blah",&buffer) 1294*/ 1295int32_t xar_extract_tobuffersz(xar_t x, xar_file_t f, char **buffer, size_t *size) { 1296 const char *sizestring = NULL; 1297 int32_t ret; 1298 1299 if(0 != xar_prop_get(f,"data/size",&sizestring)){ 1300 if(0 != xar_prop_get(f, "type", &sizestring)) 1301 return -1; 1302 if(strcmp(sizestring, "file") == 0) { 1303 *size = 0; 1304 return 0; 1305 } 1306 return -1; 1307 } 1308 1309 *size = strtoull(sizestring, (char **)NULL, 10); 1310 *buffer = malloc(*size); 1311 1312 if(!(*buffer)){ 1313 return -1; 1314 } 1315 1316 ret = xar_arcmod_extract(x,f,NULL,*buffer,*size); 1317 if( ret ) { 1318 *size = 0; 1319 free(*buffer); 1320 *buffer = NULL; 1321 } 1322 1323 return ret; 1324} 1325 1326int32_t xar_extract_tostream_init(xar_t x, xar_file_t f, xar_stream *stream) { 1327 xar_prop_t tmpp; 1328 1329 if( !xar_check_prop(x, "data") ) 1330 return XAR_STREAM_OK; 1331 1332 tmpp = xar_prop_pfirst(f); 1333 if( tmpp ) 1334 tmpp = xar_prop_find(tmpp, "data"); 1335 if( !tmpp ) 1336 return XAR_STREAM_OK; 1337 1338 return xar_attrcopy_from_heap_to_stream_init(x, f, tmpp, stream); 1339} 1340 1341int32_t xar_extract_tostream(xar_stream *stream) { 1342 return xar_attrcopy_from_heap_to_stream(stream); 1343} 1344 1345int32_t xar_extract_tostream_end(xar_stream *stream) { 1346 return xar_attrcopy_from_heap_to_stream_end(stream); 1347} 1348 1349/* xar_extract 1350 * x: archive to extract from 1351 * path: path to file to extract 1352 * Returns 0 on success, -1 on failure. 1353 * Summary: This is the entry point for extraction. This will find 1354 * the file node described by path, extract any directories needed 1355 * to extract the node, and finally extract the file. 1356 * Example: xar_extract(x, "foo/bar/blah") 1357 * If foo does not exist, xar_extract will extract foo from the 1358 * archive, extract bar from the archive, and then extract blah. 1359 * Total extractions will be "foo", "foo/bar", and "foo/bar/blah". 1360 */ 1361int32_t xar_extract(xar_t x, xar_file_t f) { 1362 struct stat sb; 1363 char *tmp1, *dname; 1364 xar_file_t tmpf; 1365 1366 if( (strstr(XAR_FILE(f)->fspath, "/") != NULL) && (stat(XAR_FILE(f)->fspath, &sb)) && (XAR_FILE(f)->parent_extracted == 0) ) { 1367 tmp1 = strdup(XAR_FILE(f)->fspath); 1368 dname = dirname(tmp1); 1369 tmpf = xar_file_find(XAR(x)->files, dname); 1370 if( !tmpf ) { 1371 xar_err_set_string(x, "Unable to find file"); 1372 xar_err_callback(x, XAR_SEVERITY_NONFATAL, XAR_ERR_ARCHIVE_EXTRACTION); 1373 return -1; 1374 } 1375 free(tmp1); 1376 XAR_FILE(f)->parent_extracted++; 1377 xar_extract(x, tmpf); 1378 } 1379 1380 return xar_extract_tofile(x, f, XAR_FILE(f)->fspath); 1381} 1382 1383/* xar_verify 1384* x: archive to extract from 1385* f: file to verify 1386* Returns 0 on success, -1 on failure. 1387* Summary: This function allows for verification of 1388* an entry without extraction. If there is no checksum 1389* the verification will pass. 1390*/ 1391int32_t xar_verify(xar_t x, xar_file_t f) { 1392 return xar_arcmod_verify(x,f); 1393} 1394 1395/* toc_read_callback 1396 * context: context passed through from the reader 1397 * buffer: buffer to read into 1398 * len: size of buffer 1399 * Returns: number of bytes read or -1 in case of error 1400 * Summary: internal callback for xmlReaderForIO. 1401 */ 1402static int toc_read_callback(void *context, char *buffer, int len) { 1403 xar_t x = (xar_t)context; 1404 int ret, off = 0; 1405 1406 if ( ((!XAR(x)->offset) || (XAR(x)->offset == XAR(x)->readbuf_len)) && (XAR(x)->toc_count != XAR(x)->header.toc_length_compressed) ) { 1407 XAR(x)->offset = 0; 1408 if( (XAR(x)->readbuf_len - off) + XAR(x)->toc_count > XAR(x)->header.toc_length_compressed ) 1409 ret = xar_read_fd(XAR(x)->fd, XAR(x)->readbuf, XAR(x)->header.toc_length_compressed - XAR(x)->toc_count); 1410 else 1411 ret = read(XAR(x)->fd, XAR(x)->readbuf, XAR(x)->readbuf_len); 1412 if ( ret == -1 ) 1413 return ret; 1414 1415 if ( XAR(x)->toc_hash_ctx ) 1416 xar_hash_update(XAR(x)->toc_hash_ctx, XAR(x)->readbuf, ret); 1417 1418 XAR(x)->toc_count += ret; 1419 off += ret; 1420 } 1421 1422 if( off && (off < XAR(x)->readbuf_len) ) 1423 XAR(x)->readbuf_len = off; 1424 XAR(x)->zs.next_in = ((unsigned char *)XAR(x)->readbuf) + XAR(x)->offset; 1425 XAR(x)->zs.avail_in = XAR(x)->readbuf_len - XAR(x)->offset; 1426 XAR(x)->zs.next_out = (void *)buffer; 1427 XAR(x)->zs.avail_out = len; 1428 1429 ret = inflate(&XAR(x)->zs, Z_SYNC_FLUSH); 1430 if( ret < 0 ) 1431 return -1; 1432 1433 XAR(x)->offset = XAR(x)->readbuf_len - XAR(x)->zs.avail_in; 1434 1435 return len - XAR(x)->zs.avail_out; 1436} 1437 1438/* close_callback 1439 * context: this will be a xar_t 1440 * Returns: 0 or -1 in case of error 1441 * Summary: this is the callback for xmlTextReaderForIO to close the IO 1442 */ 1443static int close_callback(void *context) { 1444 return 0; 1445} 1446 1447/* xar_serialize 1448 * x: xar to serialize 1449 * file: file to serialize to 1450 * Summary: serializes the archive out to xml. 1451 */ 1452void xar_serialize(xar_t x, const char *file) { 1453 xmlTextWriterPtr writer; 1454 xar_subdoc_t i; 1455 1456 writer = xmlNewTextWriterFilename(file, 0); 1457 xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL); 1458 xmlTextWriterSetIndent(writer, 4); 1459 xmlTextWriterStartElement(writer, BAD_CAST("xar")); 1460 1461 for( i = XAR(x)->subdocs; i; i = xar_subdoc_next(i) ) 1462 xar_subdoc_serialize(i, writer, 1); 1463 1464 xmlTextWriterStartElement(writer, BAD_CAST("toc")); 1465 1466 if( XAR(x)->props ) 1467 xar_prop_serialize(XAR(x)->props, writer); 1468 1469 if( XAR(x)->signatures ) 1470 xar_signature_serialize(XAR(x)->signatures,writer); 1471 1472 if( XAR(x)->files ) 1473 xar_file_serialize(XAR(x)->files, writer); 1474 1475 xmlTextWriterEndDocument(writer); 1476 xmlFreeTextWriter(writer); 1477 return; 1478} 1479 1480/* xar_unserialize 1481 * x: xar archive to unserialize to. Must have been allocated with xar_open 1482 * file: the xml filename to unserialize from 1483 * Summary: Takes the TOC representation from file and creates the 1484 * corresponding in-memory representation. 1485 */ 1486static int32_t xar_unserialize(xar_t x) { 1487 xmlTextReaderPtr reader; 1488 xar_file_t f = NULL; 1489 const xmlChar *name, *prefix, *uri; 1490 int type, noattr, ret; 1491 1492 reader = xmlReaderForIO(toc_read_callback, close_callback, XAR(x), NULL, NULL, 0); 1493 if( !reader ) return -1; 1494 1495 while( (ret = xmlTextReaderRead(reader)) == 1 ) { 1496 type = xmlTextReaderNodeType(reader); 1497 noattr = xmlTextReaderAttributeCount(reader); 1498 name = xmlTextReaderConstLocalName(reader); 1499 if( type != XML_READER_TYPE_ELEMENT ) 1500 continue; 1501 if(strcmp((const char*)name, "xar") != 0) 1502 continue; 1503 while( (ret = xmlTextReaderRead(reader)) == 1 ) { 1504 type = xmlTextReaderNodeType(reader); 1505 noattr = xmlTextReaderAttributeCount(reader); 1506 name = xmlTextReaderConstLocalName(reader); 1507 if( type == XML_READER_TYPE_ELEMENT ) { 1508 if(strcmp((const char*)name, "toc") == 0) { 1509 while( (ret = xmlTextReaderRead(reader)) == 1 ) { 1510 type = xmlTextReaderNodeType(reader); 1511 noattr = xmlTextReaderAttributeCount(reader); 1512 name = xmlTextReaderConstLocalName(reader); 1513 if( type == XML_READER_TYPE_ELEMENT ) { 1514 if(strcmp((const char*)name, "file") == 0) { 1515 f = xar_file_unserialize(x, NULL, reader); 1516 XAR_FILE(f)->next = XAR(x)->files; 1517 XAR(x)->files = f; 1518 } else if( strcmp((const char*)name, "signature") == 0 1519#ifdef __APPLE__ 1520 || strcmp((const char*)name, "x-signature") == 0 1521#endif 1522 ){ 1523 xar_signature_t sig = NULL; 1524 sig = xar_signature_unserialize(x, reader ); 1525 1526 if( !sig ) { 1527 xmlFreeTextReader(reader); 1528 return -1; 1529 } 1530 1531 if( XAR(x)->signatures ) 1532 XAR_SIGNATURE(XAR(x)->signatures)->next = XAR_SIGNATURE(sig); 1533 else 1534 XAR(x)->signatures = sig; 1535 1536 } else { 1537 xar_prop_unserialize(XAR_FILE(x), NULL, reader); 1538 } 1539 } 1540 } 1541 if( ret == -1 ) { 1542 xmlFreeTextReader(reader); 1543 return -1; 1544 } 1545 } else { 1546 xar_subdoc_t s; 1547 int i; 1548 1549 prefix = xmlTextReaderPrefix(reader); 1550 uri = xmlTextReaderNamespaceUri(reader); 1551 1552 i = xmlTextReaderAttributeCount(reader); 1553 if( i > 0 ) { 1554 for(i = xmlTextReaderMoveToFirstAttribute(reader); i == 1; i = xmlTextReaderMoveToNextAttribute(reader)) { 1555 xar_attr_t a; 1556 const char *aname = (const char *)xmlTextReaderConstLocalName(reader); 1557 const char *avalue = (const char *)xmlTextReaderConstValue(reader); 1558 1559 if( aname && (strcmp("subdoc_name", aname) == 0) ) { 1560 name = (const unsigned char *)avalue; 1561 } else { 1562 a = xar_attr_new(); 1563 XAR_ATTR(a)->key = strdup(aname); 1564 XAR_ATTR(a)->value = strdup(avalue); 1565 XAR_ATTR(a)->next = XAR_SUBDOC(s)->attrs; 1566 XAR_SUBDOC(s)->attrs = XAR_ATTR(a); 1567 } 1568 } 1569 } 1570 1571 s = xar_subdoc_new(x, (const char *)name); 1572 if(s){ 1573 xar_subdoc_unserialize(s, reader); 1574 }else{ 1575 xmlFreeTextReader(reader); 1576 return -1; 1577 } 1578 } 1579 } 1580 if( (type == XML_READER_TYPE_END_ELEMENT) && (strcmp((const char *)name, "toc")==0) ) { 1581 break; 1582 } 1583 } 1584 if( ret == -1 ) { 1585 xmlFreeTextReader(reader); 1586 return -1; 1587 } 1588 } 1589 1590 if( ret == -1 ) { 1591 xmlFreeTextReader(reader); 1592 return -1; 1593 } 1594 1595 xmlFreeTextReader(reader); 1596 return 0; 1597} 1598