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