1/* 2 * Copyright (c) 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 its 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 * 24-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#include "config.h" 39#include <stdio.h> 40#include <unistd.h> 41#include <string.h> 42#include <libgen.h> 43#include <fcntl.h> 44#include <sys/stat.h> 45#include <arpa/inet.h> 46#include "xar.h" 47#include "arcmod.h" 48#include "b64.h" 49#include <errno.h> 50#include <string.h> 51#include "util.h" 52#include "linuxattr.h" 53#include "io.h" 54#include "appledouble.h" 55#include "stat.h" 56#include "archive.h" 57 58#if defined(HAVE_SYS_XATTR_H) 59#include <sys/xattr.h> 60#endif 61 62struct _darwinattr_context{ 63 int fd; 64 char *finfo; 65 char *buf; 66 int len; 67 int off; 68}; 69 70#define DARWINATTR_CONTEXT(x) ((struct _darwinattr_context *)(x)) 71#if defined(__APPLE__) 72#ifdef HAVE_GETATTRLIST 73#include <sys/attr.h> 74#include <sys/vnode.h> 75struct fi { 76 uint32_t length; 77 fsobj_type_t objtype; 78 char finderinfo[32]; 79}; 80 81/* finfo_read 82 * This is for archiving the finderinfo via the getattrlist method. 83 * This function is used from the nonea_archive() function. 84 */ 85static int32_t finfo_read(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { 86 if( len < 32 ) 87 return -1; 88 89 if( DARWINATTR_CONTEXT(context)->finfo == NULL ) 90 return 0; 91 92 memcpy(buf, DARWINATTR_CONTEXT(context)->finfo, 32); 93 DARWINATTR_CONTEXT(context)->finfo = NULL; 94 return 32; 95} 96 97/* finfo_write 98 * This is for extracting the finderinfo via the setattrlist method. 99 * This function is used from the nonea_extract() function. 100 */ 101static int32_t finfo_write(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { 102 struct attrlist attrs; 103 struct fi finfo; 104 105 if( len < 32 ) 106 return -1; 107 if( DARWINATTR_CONTEXT(context)->finfo == NULL ) 108 return 0; 109 110 memset(&attrs, 0, sizeof(attrs)); 111 attrs.bitmapcount = ATTR_BIT_MAP_COUNT; 112 attrs.commonattr = ATTR_CMN_OBJTYPE | ATTR_CMN_FNDRINFO; 113 114 getattrlist(DARWINATTR_CONTEXT(context)->finfo, &attrs, &finfo, sizeof(finfo), 0); 115 116 attrs.commonattr = ATTR_CMN_FNDRINFO; 117 if( setattrlist(DARWINATTR_CONTEXT(context)->finfo, &attrs, buf, 32, 0) != 0 ) 118 return -1; 119 120 DARWINATTR_CONTEXT(context)->finfo = NULL; 121 return 32; 122} 123#endif /* HAVE_GETATTRLIST */ 124 125/* xar_rsrc_read 126 * This is the read callback function for archiving the resource fork via 127 * the ..namedfork method. This callback is used from nonea_archive() 128 */ 129static int32_t xar_rsrc_read(xar_t x, xar_file_t f, void *inbuf, size_t bsize, void *context) { 130 int32_t r; 131 132 while(1) { 133 r = read(DARWINATTR_CONTEXT(context)->fd, inbuf, bsize); 134 if( (r < 0) && (errno == EINTR) ) 135 continue; 136 return r; 137 } 138} 139#endif /* __APPLE__ */ 140 141/* xar_rsrc_write 142 * This is the write callback function for writing the resource fork 143 * back to the file via ..namedfork method. This is the callback used 144 * in nonea_extract() and underbar_extract(). 145 */ 146static int32_t xar_rsrc_write(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { 147 int32_t r; 148 size_t off = 0; 149 do { 150 r = write(DARWINATTR_CONTEXT(context)->fd, ((char *)buf)+off, len-off); 151 if( (r < 0) && (errno != EINTR) ) 152 return r; 153 off += r; 154 } while( off < len ); 155 return off; 156} 157 158#ifdef __APPLE__ 159#if defined(HAVE_GETXATTR) 160 161static int32_t xar_ea_read(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { 162 if( DARWINATTR_CONTEXT(context)->buf == NULL ) 163 return 0; 164 165 if( ((DARWINATTR_CONTEXT(context)->len)-(DARWINATTR_CONTEXT(context)->off)) <= len ) { 166 int siz = (DARWINATTR_CONTEXT(context)->len)-(DARWINATTR_CONTEXT(context)->off); 167 memcpy(buf, DARWINATTR_CONTEXT(context)->buf+DARWINATTR_CONTEXT(context)->off, siz); 168 free(DARWINATTR_CONTEXT(context)->buf); 169 DARWINATTR_CONTEXT(context)->buf = NULL; 170 DARWINATTR_CONTEXT(context)->off = 0; 171 DARWINATTR_CONTEXT(context)->len = 0; 172 return siz; 173 } 174 175 memcpy(buf, DARWINATTR_CONTEXT(context)->buf+DARWINATTR_CONTEXT(context)->off, len); 176 DARWINATTR_CONTEXT(context)->off += len; 177 178 if( DARWINATTR_CONTEXT(context)->off == DARWINATTR_CONTEXT(context)->len ) { 179 free(DARWINATTR_CONTEXT(context)->buf); 180 DARWINATTR_CONTEXT(context)->buf = NULL; 181 DARWINATTR_CONTEXT(context)->off = 0; 182 DARWINATTR_CONTEXT(context)->len = 0; 183 } 184 185 return len; 186} 187 188static int32_t xar_ea_write(xar_t x, xar_file_t f, void *buf, size_t len, void *context) { 189 if( DARWINATTR_CONTEXT(context)->buf == NULL ) 190 return 0; 191 192 if( DARWINATTR_CONTEXT(context)->off == DARWINATTR_CONTEXT(context)->len ) 193 return 0; 194 195 if( ((DARWINATTR_CONTEXT(context)->len)-(DARWINATTR_CONTEXT(context)->off)) <= len ) { 196 int siz = (DARWINATTR_CONTEXT(context)->len)-(DARWINATTR_CONTEXT(context)->off); 197 memcpy((DARWINATTR_CONTEXT(context)->buf)+(DARWINATTR_CONTEXT(context)->off), buf, siz); 198 return siz; 199 } 200 201 memcpy((DARWINATTR_CONTEXT(context)->buf)+(DARWINATTR_CONTEXT(context)->off), buf, len); 202 DARWINATTR_CONTEXT(context)->off += len; 203 204 return len; 205} 206 207static int32_t ea_archive(xar_t x, xar_file_t f, const char* file, void *context) { 208 char *buf, *i; 209 int ret, bufsz, attrsz; 210 int32_t retval = 0; 211 212 if( file == NULL ) 213 return 0; 214 215 ret = listxattr(file, NULL, 0, XATTR_NOFOLLOW); 216 if( ret < 0 ) 217 return -1; 218 if( ret == 0 ) 219 return 0; 220 bufsz = ret; 221 222TRYAGAIN: 223 buf = malloc(bufsz); 224 if( !buf ) 225 goto TRYAGAIN; 226 ret = listxattr(file, buf, bufsz, XATTR_NOFOLLOW); 227 if( ret < 0 ) { 228 switch(errno) { 229 case ERANGE: bufsz = bufsz*2; free(buf); goto TRYAGAIN; 230 case ENOTSUP: retval = 0; goto BAIL; 231 default: retval = -1; goto BAIL; 232 }; 233 } 234 if( ret == 0 ) { 235 retval = 0; 236 goto BAIL; 237 } 238 239 attrsz = ret; 240 for( i = buf; (i-buf) < attrsz; i += strlen(i)+1 ) { 241 xar_ea_t e; 242 243 ret = getxattr(file, i, NULL, 0, 0, XATTR_NOFOLLOW); 244 if( ret < 0 ) 245 continue; 246 DARWINATTR_CONTEXT(context)->len = ret; 247 DARWINATTR_CONTEXT(context)->buf = malloc(DARWINATTR_CONTEXT(context)->len); 248 if( !DARWINATTR_CONTEXT(context)->buf ) 249 goto BAIL; 250 251 ret = getxattr(file, i, DARWINATTR_CONTEXT(context)->buf, DARWINATTR_CONTEXT(context)->len, 0, XATTR_NOFOLLOW); 252 if( ret < 0 ) { 253 free(DARWINATTR_CONTEXT(context)->buf); 254 DARWINATTR_CONTEXT(context)->buf = NULL; 255 DARWINATTR_CONTEXT(context)->len = 0; 256 continue; 257 } 258 259 e = xar_ea_new(f, i); 260 XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), xar_ea_read, context); 261 } 262BAIL: 263 free(buf); 264 return retval; 265} 266 267static int32_t ea_extract(xar_t x, xar_file_t f, const char* file, void *context) { 268 xar_prop_t p; 269 270 for(p = xar_prop_pfirst(f); p; p = xar_prop_pnext(p)) { 271 const char *opt; 272 const char *name = NULL; 273 int len; 274 xar_prop_t tmpp; 275 276 name = xar_prop_getkey(p); 277 if( strncmp(name, XAR_EA_FORK, strlen(XAR_EA_FORK)) ) 278 continue; 279 if( strlen(name) != strlen(XAR_EA_FORK) ) 280 continue; 281 282 opt = NULL; 283 tmpp = xar_prop_pget(p, "size"); 284 if( tmpp ) 285 opt = xar_prop_getvalue(tmpp); 286 if( !opt ) 287 continue; 288 289 len = strtol(opt, NULL, 10); 290 DARWINATTR_CONTEXT(context)->buf = malloc(len); 291 if( !DARWINATTR_CONTEXT(context)->buf ) 292 return -1; 293 DARWINATTR_CONTEXT(context)->len = len; 294 295 XAR(x)->attrcopy_from_heap(x, f, p, xar_ea_write, context); 296 297 name = NULL; 298 tmpp = xar_prop_pget(p, "name"); 299 if( tmpp ) 300 name = xar_prop_getvalue(tmpp); 301 if( !name ) 302 continue; 303 304 setxattr(file, name, DARWINATTR_CONTEXT(context)->buf, DARWINATTR_CONTEXT(context)->len, 0, XATTR_NOFOLLOW); 305 free(DARWINATTR_CONTEXT(context)->buf); 306 DARWINATTR_CONTEXT(context)->buf = NULL; 307 DARWINATTR_CONTEXT(context)->len = 0; 308 DARWINATTR_CONTEXT(context)->off = 0; 309 } 310 311 return 0; 312} 313#endif /* HAVE_GETXATTR */ 314 315/* nonea_archive 316 * Archive the finderinfo and resource fork through getattrlist and 317 * ..namedfork methods rather than via EAs. This is mainly for 10.3 318 * and earlier support 319 */ 320static int32_t nonea_archive(xar_t x, xar_file_t f, const char* file, void *context) { 321 char rsrcname[4096]; 322 struct stat sb; 323 xar_ea_t e; 324#ifdef HAVE_GETATTRLIST 325 struct attrlist attrs; 326 struct fi finfo; 327 int ret; 328 char z[32]; 329 330 memset(&attrs, 0, sizeof(attrs)); 331 attrs.bitmapcount = ATTR_BIT_MAP_COUNT; 332 attrs.commonattr = ATTR_CMN_OBJTYPE | ATTR_CMN_FNDRINFO; 333 334 ret = getattrlist(file, &attrs, &finfo, sizeof(finfo), 0); 335 if( ret != 0 ) 336 return -1; 337 338 memset(z, 0, sizeof(z)); 339 if( memcmp(finfo.finderinfo, z, sizeof(finfo.finderinfo)) != 0 ) { 340 e = xar_ea_new(f, "com.apple.FinderInfo"); 341 DARWINATTR_CONTEXT(context)->finfo = finfo.finderinfo; 342 XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), finfo_read, context); 343 } 344 345 346#endif /* HAVE_GETATTRLIST */ 347 348 349 memset(rsrcname, 0, sizeof(rsrcname)); 350 snprintf(rsrcname, sizeof(rsrcname)-1, "%s/..namedfork/rsrc", file); 351 if( lstat(rsrcname, &sb) != 0 ) 352 return 0; 353 354 if( sb.st_size == 0 ) 355 return 0; 356 357 DARWINATTR_CONTEXT(context)->fd = open(rsrcname, O_RDONLY, 0); 358 if( DARWINATTR_CONTEXT(context)->fd < 0 ) 359 return -1; 360 361 e = xar_ea_new(f, "com.apple.ResourceFork"); 362 XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), xar_rsrc_read, context); 363 close(DARWINATTR_CONTEXT(context)->fd); 364 return 0; 365} 366 367/* nonea_extract 368 * Extract the finderinfo and resource fork through setattrlist and 369 * ..namedfork methods rather than via EAs. This is mainly for 10.3 370 * and earlier support 371 */ 372static int32_t nonea_extract(xar_t x, xar_file_t f, const char* file, void *context) { 373 char rsrcname[4096]; 374 xar_prop_t p; 375#ifdef HAVE_SETATTRLIST 376 struct attrlist attrs; 377 struct fi finfo; 378 int ret; 379 380 memset(&attrs, 0, sizeof(attrs)); 381 attrs.bitmapcount = ATTR_BIT_MAP_COUNT; 382 attrs.commonattr = ATTR_CMN_OBJTYPE | ATTR_CMN_FNDRINFO; 383 384 ret = getattrlist(file, &attrs, &finfo, sizeof(finfo), 0); 385 if( ret != 0 ) 386 return -1; 387 388 DARWINATTR_CONTEXT(context)->finfo = (char *)file; 389 390 p = xar_ea_find(f, "com.apple.ResourceFork"); 391 if( p ) 392 XAR(x)->attrcopy_from_heap(x, f, p, finfo_write, context); 393#endif /* HAVE_SETATTRLIST */ 394 395 memset(rsrcname, 0, sizeof(rsrcname)); 396 snprintf(rsrcname, sizeof(rsrcname)-1, "%s/..namedfork/rsrc", file); 397 DARWINATTR_CONTEXT(context)->fd = open(rsrcname, O_RDWR|O_TRUNC); 398 if( DARWINATTR_CONTEXT(context)->fd < 0 ) 399 return 0; 400 401 p = xar_ea_find(f, "com.apple.ResourceFork"); 402 if( p ) 403 XAR(x)->attrcopy_from_heap(x, f, p, xar_rsrc_write, context); 404 close(DARWINATTR_CONTEXT(context)->fd); 405 return 0; 406} 407#endif /* __APPLE__ */ 408 409/* xar_underbar_check 410 * Check to see if the file we're archiving is a ._ file. If so, 411 * stop the archival process. 412 */ 413xar_file_t xar_underbar_check(xar_t x, xar_file_t f, const char* file, void *context) { 414 char *bname, *tmp; 415 416 tmp = strdup(file); 417 bname = basename(tmp); 418 419 if(bname && (bname[0] == '.') && (bname[1] == '_')) { 420 char *nonunderbar, *nupath, *tmp2, *dname; 421 struct stat sb; 422 423 nonunderbar = bname+2; 424 tmp2 = strdup(file); 425 dname = dirname(tmp2); 426 asprintf(&nupath, "%s/%s", dname, nonunderbar); 427 free(tmp2); 428 429 /* if there is no file that the ._ corresponds to, archive 430 * it like a normal file. 431 */ 432 if( stat(nupath, &sb) ) { 433 free(tmp); 434 free(nupath); 435 return NULL; 436 } 437 438 asprintf(&tmp2, "%s/..namedfork/rsrc", nupath); 439 440 /* If there is a file that the ._ file corresponds to, and 441 * there is no resource fork, assume the ._ file contains 442 * the file's resource fork, and skip it (to be picked up 443 * when the file is archived. 444 */ 445 if( stat(tmp2, &sb) ) { 446 xar_file_t tmpf; 447 tmpf = xar_file_find(XAR(x)->files, nupath); 448 if( !tmpf ) { 449 tmpf = xar_add(x, nupath); 450 } 451 free(nupath); 452 free(tmp2); 453 free(tmp); 454 return tmpf; 455 } 456 457 /* otherwise, we have a corresponding file and it supports 458 * resource forks, so we assume this is a detached ._ file 459 * and archive it as a real file. 460 */ 461 free(nupath); 462 free(tmp2); 463 free(tmp); 464 return NULL; 465 } 466 467 free(tmp); 468 return NULL; 469} 470 471#ifdef __APPLE__ 472/* This only really makes sense on OSX */ 473static int32_t underbar_archive(xar_t x, xar_file_t f, const char* file, void *context) { 474 struct stat sb; 475 char underbarname[4096], z[32]; 476 char *dname, *bname, *tmp, *tmp2; 477 struct AppleSingleHeader ash; 478 struct AppleSingleEntry ase; 479 int num_entries = 0, i, r; 480 off_t off; 481 482 if( !file ) 483 return 0; 484 485 tmp = strdup(file); 486 tmp2 = strdup(file); 487 dname = dirname(tmp2); 488 bname = basename(tmp); 489 490 memset(underbarname, 0, sizeof(underbarname)); 491 snprintf(underbarname, sizeof(underbarname)-1, "%s/._%s", dname, bname); 492 free(tmp); 493 free(tmp2); 494 495 if( stat(underbarname, &sb) != 0 ) 496 return 0; 497 498 DARWINATTR_CONTEXT(context)->fd = open(underbarname, O_RDONLY); 499 if( DARWINATTR_CONTEXT(context)->fd < 0 ) 500 return -1; 501 502 memset(&ash, 0, sizeof(ash)); 503 memset(&ase, 0, sizeof(ase)); 504 r = read(DARWINATTR_CONTEXT(context)->fd, &ash, XAR_ASH_SIZE); 505 if( r < XAR_ASH_SIZE ) { 506 close(DARWINATTR_CONTEXT(context)->fd); 507 return -1; 508 } 509 510 if( ntohl(ash.magic) != APPLEDOUBLE_MAGIC ) { 511 close(DARWINATTR_CONTEXT(context)->fd); 512 return -1; 513 } 514 if( ntohl(ash.version) != APPLEDOUBLE_VERSION ) { 515 close(DARWINATTR_CONTEXT(context)->fd); 516 return -1; 517 } 518 519 off = XAR_ASH_SIZE; 520 num_entries = ntohs(ash.entries); 521 522 for(i = 0; i < num_entries; i++) { 523 off_t entoff; 524 r = read(DARWINATTR_CONTEXT(context)->fd, &ase, sizeof(ase)); 525 if( r < sizeof(ase) ) { 526 close(DARWINATTR_CONTEXT(context)->fd); 527 return -1; 528 } 529 off+=r; 530 531 if( ntohl(ase.entry_id) == AS_ID_FINDER ) { 532 xar_ea_t e; 533 entoff = (off_t)ntohl(ase.offset); 534 if( lseek(DARWINATTR_CONTEXT(context)->fd, entoff, SEEK_SET) == -1 ) { 535 close(DARWINATTR_CONTEXT(context)->fd); 536 return -1; 537 } 538 r = read(DARWINATTR_CONTEXT(context)->fd, z, sizeof(z)); 539 if( r < sizeof(z) ) { 540 close(DARWINATTR_CONTEXT(context)->fd); 541 return -1; 542 } 543 544 DARWINATTR_CONTEXT(context)->finfo = z; 545 e = xar_ea_new(f, "com.apple.FinderInfo"); 546 XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), finfo_read, context); 547 if( lseek(DARWINATTR_CONTEXT(context)->fd, (off_t)off, SEEK_SET) == -1 ) { 548 close(DARWINATTR_CONTEXT(context)->fd); 549 return -1; 550 } 551 } 552 if( ntohl(ase.entry_id) == AS_ID_RESOURCE ) { 553 xar_ea_t e; 554 entoff = (off_t)ntohl(ase.offset); 555 if( lseek(DARWINATTR_CONTEXT(context)->fd, entoff, SEEK_SET) == -1 ) { 556 close(DARWINATTR_CONTEXT(context)->fd); 557 return -1; 558 } 559 560 e = xar_ea_new(f, "com.apple.ResourceFork"); 561 XAR(x)->attrcopy_to_heap(x, f, xar_ea_root(e), xar_rsrc_read, context); 562 563 if( lseek(DARWINATTR_CONTEXT(context)->fd, (off_t)off, SEEK_SET) == -1 ) { 564 close(DARWINATTR_CONTEXT(context)->fd); 565 return -1; 566 } 567 } 568 } 569 570 close(DARWINATTR_CONTEXT(context)->fd); 571 DARWINATTR_CONTEXT(context)->fd = 0; 572 return 0; 573} 574#endif 575 576/* underbar_extract 577 * Extract finderinfo and resource fork information to an appledouble 578 * ._ file. 579 */ 580static int32_t underbar_extract(xar_t x, xar_file_t f, const char* file, void *context) { 581 char underbarname[4096]; 582 char *dname, *bname, *tmp, *tmp2; 583 const char *rsrclenstr; 584 struct AppleSingleHeader ash; 585 struct AppleSingleEntry ase; 586 int num_entries = 0, rsrclen = 0, have_rsrc = 0, have_fi = 0; 587 xar_prop_t p; 588 xar_prop_t rfprop = NULL, fiprop = NULL; 589 590 fiprop = xar_ea_find(f, "com.apple.FinderInfo"); 591 if( fiprop ) { 592 have_fi = 1; 593 num_entries++; 594 } 595 596 rfprop = xar_ea_find(f, "com.apple.ResourceFork"); 597 if( rfprop ) { 598 have_rsrc = 1; 599 num_entries++; 600 } 601 602 if( num_entries == 0 ) 603 return 0; 604 605 tmp = strdup(file); 606 tmp2 = strdup(file); 607 dname = dirname(tmp2); 608 bname = basename(tmp); 609 610 memset(underbarname, 0, sizeof(underbarname)); 611 snprintf(underbarname, sizeof(underbarname)-1, "%s/._%s", dname, bname); 612 free(tmp); 613 free(tmp2); 614 615 DARWINATTR_CONTEXT(context)->fd = open(underbarname, O_RDWR | O_CREAT | O_TRUNC, 0); 616 if( DARWINATTR_CONTEXT(context)->fd < 0 ) 617 return -1; 618 619 rsrclenstr = NULL; 620 if( rfprop ) { 621 p = xar_prop_pget(rfprop, "size"); 622 if( p ) 623 rsrclenstr = xar_prop_getvalue(p); 624 if( rsrclenstr ) 625 rsrclen = strtol(rsrclenstr, NULL, 10); 626 } 627 628 memset(&ash, 0, sizeof(ash)); 629 memset(&ase, 0, sizeof(ase)); 630 ash.magic = htonl(APPLEDOUBLE_MAGIC); 631 ash.version = htonl(APPLEDOUBLE_VERSION); 632 ash.entries = htons(num_entries); 633 634 write(DARWINATTR_CONTEXT(context)->fd, &ash, XAR_ASH_SIZE); 635 636 ase.offset = htonl(XAR_ASH_SIZE + ntohs(ash.entries)*12); 637 if( have_fi ) { 638 ase.entry_id = htonl(AS_ID_FINDER); 639 ase.length = htonl(32); 640 write(DARWINATTR_CONTEXT(context)->fd, &ase, 12); 641 } 642 643 if( have_rsrc ) { 644 ase.entry_id = htonl(AS_ID_RESOURCE); 645 ase.offset = htonl(ntohl(ase.offset) + ntohl(ase.length)); 646 ase.length = htonl(rsrclen); 647 write(DARWINATTR_CONTEXT(context)->fd, &ase, 12); 648 } 649 650 if( have_fi ) 651 XAR(x)->attrcopy_from_heap(x, f, fiprop, xar_rsrc_write, context); 652 if( have_rsrc ) 653 XAR(x)->attrcopy_from_heap(x, f, rfprop, xar_rsrc_write, context); 654 close(DARWINATTR_CONTEXT(context)->fd); 655 656 DARWINATTR_CONTEXT(context)->fd = 0; 657 658 xar_set_perm(x, f, underbarname, NULL, 0 ); 659 660 return 0; 661} 662 663#if defined(__APPLE__) 664static int32_t stragglers_archive(xar_t x, xar_file_t f, const char* file, void *context) { 665#ifdef HAVE_GETATTRLIST 666 struct fits { 667 uint32_t length; 668 struct timespec ts; 669 }; 670 struct fits fts; 671 struct attrlist attrs; 672 int ret; 673 674 if( !xar_check_prop(x, "FinderCreateTime") ) 675 return 0; 676 677 memset(&attrs, 0, sizeof(attrs)); 678 attrs.bitmapcount = ATTR_BIT_MAP_COUNT; 679 attrs.commonattr = ATTR_CMN_CRTIME; 680 ret = getattrlist(file, &attrs, &fts, sizeof(fts), 0); 681 if( ret == 0 ) { 682 xar_prop_t tmpp; 683 684 tmpp = xar_prop_new(f, NULL); 685 if( tmpp ) { 686 char tmpc[128]; 687 struct tm tm; 688 xar_prop_setkey(tmpp, "FinderCreateTime"); 689 xar_prop_setvalue(tmpp, NULL); 690 memset(tmpc, 0, sizeof(tmpc)); 691 gmtime_r(&fts.ts.tv_sec, &tm); 692 strftime(tmpc, sizeof(tmpc), "%FT%T", &tm); 693 xar_prop_pset(f, tmpp, "time", tmpc); 694 memset(tmpc, 0, sizeof(tmpc)); 695 sprintf(tmpc, "%ld", fts.ts.tv_nsec); 696 xar_prop_pset(f, tmpp, "nanoseconds", tmpc); 697 } 698 } 699#endif 700 return 0; 701} 702 703static int32_t stragglers_extract(xar_t x, xar_file_t f, const char* file, void *context) { 704#ifdef HAVE_GETATTRLIST 705 const char *tmpc = NULL; 706 struct tm tm; 707 struct timespec ts; 708 struct attrlist attrs; 709 710 xar_prop_get(f, "FinderCreateTime/time", &tmpc); 711 if( tmpc ) { 712 strptime(tmpc, "%FT%T", &tm); 713 ts.tv_sec = timegm(&tm); 714 xar_prop_get(f, "FinderCreateTime/nanoseconds", &tmpc); 715 ts.tv_nsec = strtol(tmpc, NULL, 10); 716 memset(&attrs, 0, sizeof(attrs)); 717 attrs.bitmapcount = ATTR_BIT_MAP_COUNT; 718 attrs.commonattr = ATTR_CMN_CRTIME; 719 setattrlist(file, &attrs, &ts, sizeof(ts), 0); 720 } 721 722#endif 723 return 0; 724} 725#endif /* __APPLE__ */ 726 727int32_t xar_darwinattr_archive(xar_t x, xar_file_t f, const char* file, const char *buffer, size_t len) 728{ 729 struct _darwinattr_context context; 730 731 memset(&context,0,sizeof(struct _darwinattr_context)); 732 733#if defined(__APPLE__) 734 if( len ) 735 return 0; 736 stragglers_archive(x, f, file, (void *)&context); 737 738 /* From here on out, props are only EA's */ 739 if( !xar_check_prop(x, "ea") ) 740 return 0; 741 742#if defined(HAVE_GETXATTR) 743 if( ea_archive(x, f, file, (void *)&context) == 0 ) 744 return 0; 745#endif 746 if( nonea_archive(x, f, file, (void *)&context) == 0 ) 747 return 0; 748 return underbar_archive(x, f, file, (void *)&context); 749#endif /* __APPLE__ */ 750 return 0; 751} 752 753int32_t xar_darwinattr_extract(xar_t x, xar_file_t f, const char* file, char *buffer, size_t len) 754{ 755 struct _darwinattr_context context; 756 757 memset(&context,0,sizeof(struct _darwinattr_context)); 758 759#if defined(__APPLE__) 760 if( len ) 761 return 0; 762 stragglers_extract(x, f, file, (void *)&context); 763 764#if defined(HAVE_GETXATTR) 765 if( ea_extract(x, f, file, (void *)&context) == 0 ) 766 return 0; 767#endif 768 if( nonea_extract(x, f, file, (void *)&context) == 0 ) 769 return 0; 770#endif /* __APPLE__ */ 771 return underbar_extract(x, f, file, (void *)&context); 772} 773