1/* 2 * Copyright (c) 2004-2010 Apple, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <err.h> 25#include <errno.h> 26#include <sys/types.h> 27#include <sys/acl.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <stdint.h> 32#include <syslog.h> 33#include <unistd.h> 34#include <fcntl.h> 35#include <sys/errno.h> 36#include <sys/stat.h> 37#include <sys/time.h> 38#include <sys/xattr.h> 39#include <sys/attr.h> 40#include <sys/syscall.h> 41#include <sys/param.h> 42#include <sys/mount.h> 43#include <sys/acl.h> 44#include <libkern/OSByteOrder.h> 45#include <membership.h> 46#include <fts.h> 47#include <libgen.h> 48 49#ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION 50# include <Kernel/sys/decmpfs.h> 51#endif 52 53#include <TargetConditionals.h> 54#if !TARGET_OS_IPHONE 55#include <quarantine.h> 56 57#define XATTR_QUARANTINE_NAME qtn_xattr_name 58#else /* TARGET_OS_IPHONE */ 59#define qtn_file_t void * 60#define QTN_SERIALIZED_DATA_MAX 0 61static void * qtn_file_alloc(void) { return NULL; } 62static int qtn_file_init_with_fd(void *x, int y) { return -1; } 63static int qtn_file_init_with_path(void *x, const char *path) { return -1; } 64static int qtn_file_init_with_data(void *x, const void *data, size_t len) { return -1; } 65static void qtn_file_free(void *x) { return; } 66static int qtn_file_apply_to_fd(void *x, int y) { return 0; } 67static char *qtn_error(int x) { return NULL; } 68static int qtn_file_to_data(void *x, char *y, size_t z) { return -1; } 69static void *qtn_file_clone(void *x) { return NULL; } 70#define XATTR_QUARANTINE_NAME "figgledidiggledy" 71#endif /* TARGET_OS_IPHONE */ 72 73#include "copyfile.h" 74#include "copyfile_private.h" 75#include "xattr_flags.h" 76 77enum cfInternalFlags { 78 cfDelayAce = 1 << 0, 79 cfMakeFileInvisible = 1 << 1, 80 cfSawDecmpEA = 1 << 2, 81}; 82 83/* 84 * The state structure keeps track of 85 * the source filename, the destination filename, their 86 * associated file-descriptors, the stat infomration for the 87 * source file, the security information for the source file, 88 * the flags passed in for the copy, a pointer to place statistics 89 * (not currently implemented), debug flags, and a pointer to callbacks 90 * (not currently implemented). 91 */ 92struct _copyfile_state 93{ 94 char *src; 95 char *dst; 96 int src_fd; 97 int dst_fd; 98 struct stat sb; 99 filesec_t fsec; 100 copyfile_flags_t flags; 101 unsigned int internal_flags; 102 void *stats; 103 uint32_t debug; 104 copyfile_callback_t statuscb; 105 void *ctx; 106 qtn_file_t qinfo; /* Quarantine information -- probably NULL */ 107 filesec_t original_fsec; 108 filesec_t permissive_fsec; 109 off_t totalCopied; 110 int err; 111 char *xattr_name; 112 xattr_operation_intent_t copyIntent; 113}; 114 115struct acl_entry { 116 u_int32_t ae_magic; 117#define _ACL_ENTRY_MAGIC 0xac1ac101 118 u_int32_t ae_tag; 119 guid_t ae_applicable; 120 u_int32_t ae_flags; 121 u_int32_t ae_perms; 122}; 123 124#define PACE(ace) do { \ 125 struct acl_entry *__t = (struct acl_entry*)(ace); \ 126 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \ 127 } while (0) 128 129#define PACL(ace) \ 130 do { \ 131 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \ 132 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \ 133 } while (0) 134 135static int 136acl_compare_permset_np(acl_permset_t p1, acl_permset_t p2) 137{ 138 struct pm { u_int32_t ap_perms; } *ps1, *ps2; 139 ps1 = (struct pm*) p1; 140 ps2 = (struct pm*) p2; 141 142 return ((ps1->ap_perms == ps2->ap_perms) ? 1 : 0); 143} 144 145 146static int 147doesdecmpfs(int fd) { 148#ifdef DECMPFS_XATTR_NAME 149 int rv; 150 struct attrlist attrs; 151 char volroot[MAXPATHLEN + 1]; 152 struct statfs sfs; 153 struct { 154 uint32_t length; 155 vol_capabilities_attr_t volAttrs; 156 } volattrs; 157 158 (void)fstatfs(fd, &sfs); 159 strlcpy(volroot, sfs.f_mntonname, sizeof(volroot)); 160 161 memset(&attrs, 0, sizeof(attrs)); 162 attrs.bitmapcount = ATTR_BIT_MAP_COUNT; 163 attrs.volattr = ATTR_VOL_CAPABILITIES; 164 165 rv = getattrlist(volroot, &attrs, &volattrs, sizeof(volattrs), 0); 166 167 if (rv != -1 && 168 (volattrs.volAttrs.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION) && 169 (volattrs.volAttrs.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION)) { 170 return 1; 171 } 172#endif 173 return 0; 174} 175 176 177static void 178sort_xattrname_list(void *start, size_t length) 179{ 180 char **ptrs = NULL; 181 int nel; 182 char *tmp; 183 int indx = 0; 184 185 /* If it's not a proper C string at the end, don't do anything */ 186 if (((char*)start)[length] != 0) 187 return; 188 /* 189 * In order to sort the list of names, we need to 190 * make a list of pointers to strings. To do that, 191 * we need to run through the buffer, and find the 192 * beginnings of strings. 193 */ 194 nel = 10; // Most files don't have many EAs 195 ptrs = (char**)calloc(nel, sizeof(char*)); 196 197 if (ptrs == NULL) 198 goto done; 199 200#ifdef DEBUG 201{ 202 char *curPtr = start; 203 while (curPtr < (char*)start + length) { 204 printf("%s\n", curPtr); 205 curPtr += strlen(curPtr) + 1; 206 } 207} 208#endif 209 210 tmp = ptrs[indx++] = (char*)start; 211 212 while (tmp = memchr(tmp, 0, ((char*)start + length) - tmp)) { 213 if (indx == nel) { 214 nel += 10; 215 ptrs = realloc(ptrs, sizeof(char**) * nel); 216 if (ptrs == NULL) 217 goto done; 218 } 219 ptrs[indx++] = ++tmp; 220 } 221#ifdef DEBUG 222 printf("Unsorted:\n"); 223 for (nel = 0; nel < indx-1; nel++) { 224 printf("\tEA %d = `%s'\n", nel, ptrs[nel]); 225 } 226#endif 227 qsort_b(ptrs, indx-1, sizeof(char*), ^(const void *left, const void *right) { 228 int rv; 229 char *lstr = *(char**)left, *rstr = *(char**)right; 230 rv = strcmp(lstr, rstr); 231 return rv; 232 }); 233#ifdef DEBUG 234 printf("Sorted:\n"); 235 for (nel = 0; nel < indx-1; nel++) { 236 printf("\tEA %d = `%s'\n", nel, ptrs[nel]); 237 } 238#endif 239 /* 240 * Now that it's sorted, we need to make a copy, so we can 241 * move the strings around into the new order. Then we 242 * copy that on top of the old buffer, and we're done. 243 */ 244 char *copy = malloc(length); 245 if (copy) { 246 int i; 247 char *curPtr = copy; 248 249 for (i = 0; i < indx-1; i++) { 250 size_t len = strlen(ptrs[i]); 251 memcpy(curPtr, ptrs[i], len+1); 252 curPtr += len+1; 253 } 254 memcpy(start, copy, length); 255 free(copy); 256 } 257 258done: 259 if (ptrs) 260 free(ptrs); 261 return; 262} 263 264/* 265 * Internally, the process is broken into a series of 266 * private functions. 267 */ 268static int copyfile_open (copyfile_state_t); 269static int copyfile_close (copyfile_state_t); 270static int copyfile_data (copyfile_state_t); 271static int copyfile_stat (copyfile_state_t); 272static int copyfile_security (copyfile_state_t); 273static int copyfile_xattr (copyfile_state_t); 274static int copyfile_pack (copyfile_state_t); 275static int copyfile_unpack (copyfile_state_t); 276 277static copyfile_flags_t copyfile_check (copyfile_state_t); 278static filesec_t copyfile_fix_perms(copyfile_state_t, filesec_t *); 279static int copyfile_preamble(copyfile_state_t *s, copyfile_flags_t flags); 280static int copyfile_internal(copyfile_state_t state, copyfile_flags_t flags); 281static int copyfile_unset_posix_fsec(filesec_t); 282static int copyfile_quarantine(copyfile_state_t); 283 284#define COPYFILE_DEBUG (1<<31) 285#define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG" 286 287#ifndef _COPYFILE_TEST 288# define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__) 289# define copyfile_debug(d, str, ...) \ 290 do { \ 291 if (s && (d <= s->debug)) {\ 292 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \ 293 } \ 294 } while (0) 295#else 296#define copyfile_warn(str, ...) \ 297 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "") 298# define copyfile_debug(d, str, ...) \ 299 do { \ 300 if (s && (d <= s->debug)) {\ 301 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \ 302 } \ 303 } while(0) 304#endif 305 306static int copyfile_quarantine(copyfile_state_t s) 307{ 308 int rv = 0; 309 if (s->qinfo == NULL) 310 { 311 int error; 312 s->qinfo = qtn_file_alloc(); 313 if (s->qinfo == NULL) 314 { 315 rv = -1; 316 goto done; 317 } 318 if ((error = qtn_file_init_with_fd(s->qinfo, s->src_fd)) != 0) 319 { 320 qtn_file_free(s->qinfo); 321 s->qinfo = NULL; 322 rv = -1; 323 goto done; 324 } 325 } 326done: 327 return rv; 328} 329 330static int 331add_uberace(acl_t *acl) 332{ 333 acl_entry_t entry; 334 acl_permset_t permset; 335 uuid_t qual; 336 337 if (mbr_uid_to_uuid(getuid(), qual) != 0) 338 goto error_exit; 339 340 /* 341 * First, we create an entry, and give it the special name 342 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first. 343 * After that, we clear out all the permissions in it, and 344 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and 345 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows 346 * the functionality, and put this into the ACL. 347 */ 348 if (acl_create_entry_np(acl, &entry, ACL_FIRST_ENTRY) == -1) 349 goto error_exit; 350 if (acl_get_permset(entry, &permset) == -1) { 351 copyfile_warn("acl_get_permset"); 352 goto error_exit; 353 } 354 if (acl_clear_perms(permset) == -1) { 355 copyfile_warn("acl_clear_permset"); 356 goto error_exit; 357 } 358 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1) { 359 copyfile_warn("add ACL_WRITE_DATA"); 360 goto error_exit; 361 } 362 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1) { 363 copyfile_warn("add ACL_WRITE_ATTRIBUTES"); 364 goto error_exit; 365 } 366 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1) { 367 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES"); 368 goto error_exit; 369 } 370 if (acl_add_perm(permset, ACL_APPEND_DATA) == -1) { 371 copyfile_warn("add ACL_APPEND_DATA"); 372 goto error_exit; 373 } 374 if (acl_add_perm(permset, ACL_WRITE_SECURITY) == -1) { 375 copyfile_warn("add ACL_WRITE_SECURITY"); 376 goto error_exit; 377 } 378 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1) { 379 copyfile_warn("set ACL_EXTENDED_ALLOW"); 380 goto error_exit; 381 } 382 383 if(acl_set_permset(entry, permset) == -1) { 384 copyfile_warn("acl_set_permset"); 385 goto error_exit; 386 } 387 if(acl_set_qualifier(entry, qual) == -1) { 388 copyfile_warn("acl_set_qualifier"); 389 goto error_exit; 390 } 391 392 return 0; 393error_exit: 394 return -1; 395} 396 397static int 398is_uberace(acl_entry_t ace) 399{ 400 int retval = 0; 401 acl_permset_t perms, tperms; 402 acl_t tacl; 403 acl_entry_t tentry; 404 acl_tag_t tag; 405 guid_t *qual = NULL; 406 uuid_t myuuid; 407 408 // Who am I, and who is the ACE for? 409 mbr_uid_to_uuid(geteuid(), myuuid); 410 qual = (guid_t*)acl_get_qualifier(ace); 411 412 // Need to create a temporary acl, so I can get the uberace template. 413 tacl = acl_init(1); 414 if (tacl == NULL) { 415 goto done; 416 } 417 add_uberace(&tacl); 418 if (acl_get_entry(tacl, ACL_FIRST_ENTRY, &tentry) != 0) { 419 goto done; 420 } 421 acl_get_permset(tentry, &tperms); 422 423 // Now I need to get 424 acl_get_tag_type(ace, &tag); 425 acl_get_permset(ace, &perms); 426 427 if (tag == ACL_EXTENDED_ALLOW && 428 (memcmp(qual, myuuid, sizeof(myuuid)) == 0) && 429 acl_compare_permset_np(tperms, perms)) 430 retval = 1; 431 432done: 433 434 if (qual) 435 acl_free(qual); 436 437 if (tacl) 438 acl_free(tacl); 439 440 return retval; 441} 442 443static void 444remove_uberace(int fd, struct stat *sbuf) 445{ 446 filesec_t fsec = NULL; 447 acl_t acl = NULL; 448 acl_entry_t entry; 449 struct stat sb; 450 451 fsec = filesec_init(); 452 if (fsec == NULL) { 453 goto noacl; 454 } 455 456 if (fstatx_np(fd, &sb, fsec) != 0) { 457 if (errno == ENOTSUP) 458 goto noacl; 459 goto done; 460 } 461 462 if (filesec_get_property(fsec, FILESEC_ACL, &acl) != 0) { 463 goto done; 464 } 465 466 if (acl_get_entry(acl, ACL_FIRST_ENTRY, &entry) == 0) { 467 if (is_uberace(entry)) 468 { 469 mode_t m = sbuf->st_mode & ~S_IFMT; 470 471 if (acl_delete_entry(acl, entry) != 0 || 472 filesec_set_property(fsec, FILESEC_ACL, &acl) != 0 || 473 filesec_set_property(fsec, FILESEC_MODE, &m) != 0 || 474 fchmodx_np(fd, fsec) != 0) 475 goto noacl; 476 } 477 } 478 479done: 480 if (acl) 481 acl_free(acl); 482 if (fsec) 483 filesec_free(fsec); 484 return; 485 486noacl: 487 fchmod(fd, sbuf->st_mode & ~S_IFMT); 488 goto done; 489} 490 491static void 492reset_security(copyfile_state_t s) 493{ 494 /* If we haven't reset the file security information 495 * (COPYFILE_SECURITY is not set in flags) 496 * restore back the permissions the file had originally 497 * 498 * One of the reasons this seems so complicated is that 499 * it is partially at odds with copyfile_security(). 500 * 501 * Simplisticly, we are simply trying to make sure we 502 * only copy what was requested, and that we don't stomp 503 * on what wasn't requested. 504 */ 505 506#ifdef COPYFILE_RECURSIVE 507 if (s->dst_fd > -1) { 508 struct stat sbuf; 509 510 if (s->src_fd > -1 && (s->flags & COPYFILE_STAT)) 511 fstat(s->src_fd, &sbuf); 512 else 513 fstat(s->dst_fd, &sbuf); 514 515 if (!(s->internal_flags & cfDelayAce)) 516 remove_uberace(s->dst_fd, &sbuf); 517 } 518#else 519 if (s->permissive_fsec && (s->flags & COPYFILE_SECURITY) != COPYFILE_SECURITY) { 520 if (s->flags & COPYFILE_ACL) { 521 /* Just need to reset the BSD information -- mode, owner, group */ 522 (void)fchown(s->dst_fd, s->dst_sb.st_uid, s->dst_sb.st_gid); 523 (void)fchmod(s->dst_fd, s->dst_sb.st_mode); 524 } else { 525 /* 526 * flags is either COPYFILE_STAT, or neither; if it's 527 * neither, then we restore both ACL and POSIX permissions; 528 * if it's STAT, however, then we only want to restore the 529 * ACL (which may be empty). We do that by removing the 530 * POSIX information from the filesec object. 531 */ 532 if (s->flags & COPYFILE_STAT) { 533 copyfile_unset_posix_fsec(s->original_fsec); 534 } 535 if (fchmodx_np(s->dst_fd, s->original_fsec) < 0 && errno != ENOTSUP) 536 copyfile_warn("restoring security information"); 537 } 538 } 539 540 if (s->permissive_fsec) { 541 filesec_free(s->permissive_fsec); 542 s->permissive_fsec = NULL; 543 } 544 545 if (s->original_fsec) { 546 filesec_free(s->original_fsec); 547 s->original_fsec = NULL; 548 } 549#endif 550 551 return; 552} 553 554/* 555 * copytree -- recursively copy a hierarchy. 556 * 557 * Unlike normal copyfile(), copytree() can copy an entire hierarchy. 558 * Care is taken to keep the ACLs set up correctly, in addition to the 559 * normal copying that is done. (When copying a hierarchy, we can't 560 * get rid of the "allow-all-writes" ACE on a directory until we're done 561 * copying the *contents* of the directory.) 562 * 563 * The other big difference from copyfile (for the moment) is that copytree() 564 * will use a call-back function to pass along information about what is 565 * about to be copied, and whether or not it succeeded. 566 * 567 * copytree() is called from copyfile() -- but copytree() itself then calls 568 * copyfile() to copy each individual object. 569 * 570 * XXX - no effort is made to handle overlapping hierarchies at the moment. 571 * 572 */ 573 574static int 575copytree(copyfile_state_t s) 576{ 577 char *slash; 578 int retval = 0; 579 int (*sfunc)(const char *, struct stat *); 580 copyfile_callback_t status = NULL; 581 char srcisdir = 0, dstisdir = 0, dstexists = 0; 582 struct stat sbuf; 583 char *src, *dst; 584 const char *dstpathsep = ""; 585#ifdef NOTYET 586 char srcpath[PATH_MAX * 2 + 1], dstpath[PATH_MAX * 2 + 1]; 587#endif 588 char *srcroot; 589 FTS *fts = NULL; 590 FTSENT *ftsent; 591 ssize_t offset = 0; 592 const char *paths[2] = { 0 }; 593 unsigned int flags = 0; 594 int fts_flags = FTS_NOCHDIR; 595 596 if (s == NULL) { 597 errno = EINVAL; 598 retval = -1; 599 goto done; 600 } 601 if (s->flags & (COPYFILE_MOVE | COPYFILE_UNLINK | COPYFILE_CHECK | COPYFILE_PACK | COPYFILE_UNPACK)) { 602 errno = EINVAL; 603 retval = -1; 604 goto done; 605 } 606 607 flags = s->flags & (COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_VERBOSE); 608 609 paths[0] = src = s->src; 610 dst = s->dst; 611 612 if (src == NULL || dst == NULL) { 613 errno = EINVAL; 614 retval = -1; 615 goto done; 616 } 617 618 sfunc = (flags & COPYFILE_NOFOLLOW_SRC) ? lstat : stat; 619 if ((sfunc)(src, &sbuf) == -1) { 620 retval = -1; 621 goto done; 622 } 623 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { 624 srcisdir = 1; 625 } 626 627 sfunc = (flags & COPYFILE_NOFOLLOW_DST) ? lstat : stat; 628 if ((sfunc)(dst, &sbuf) == -1) { 629 if (errno != ENOENT) { 630 retval = -1; 631 goto done; 632 } 633 } else { 634 dstexists = 1; 635 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) { 636 dstisdir = 1; 637 } 638 } 639 640#ifdef NOTYET 641 // This doesn't handle filesystem crossing and case sensitivity 642 // So there's got to be a better way 643 644 if (realpath(src, srcpath) == NULL) { 645 retval = -1; 646 goto done; 647 } 648 649 if (realpath(dst, dstpath) == NULL && 650 (errno == ENOENT && realpath(dirname(dst), dstpath) == NULL)) { 651 retval = -1; 652 goto done; 653 } 654 if (strstr(srcpath, dstpath) != NULL) { 655 errno = EINVAL; 656 retval = -1; 657 goto done; 658 } 659#endif 660 srcroot = basename((char*)src); 661 if (srcroot == NULL) { 662 retval = -1; 663 goto done; 664 } 665 666 /* 667 * To work on as well: 668 * We have a few cases when copying a hierarchy: 669 * 1) src is a non-directory, dst is a directory; 670 * 2) src is a non-directory, dst is a non-directory; 671 * 3) src is a non-directory, dst does not exist; 672 * 4) src is a directory, dst is a directory; 673 * 5) src is a directory, dst is a non-directory; 674 * 6) src is a directory, dst does not exist 675 * 676 * (1) copies src to dst/basename(src). 677 * (2) fails if COPYFILE_EXCLUSIVE is set, otherwise copies src to dst. 678 * (3) and (6) copy src to the name dst. 679 * (4) copies the contents of src to the contents of dst. 680 * (5) is an error. 681 */ 682 683 if (dstisdir) { 684 // copy /path/to/src to /path/to/dst/src 685 // Append "/" and (fts_path - strlen(basename(src))) to dst? 686 dstpathsep = "/"; 687 slash = strrchr(src, '/'); 688 if (slash == NULL) 689 offset = 0; 690 else 691 offset = slash - src + 1; 692 } else { 693 // copy /path/to/src to /path/to/dst 694 // append (fts_path + strlen(src)) to dst? 695 dstpathsep = ""; 696 offset = strlen(src); 697 } 698 699 if (s->flags | COPYFILE_NOFOLLOW_SRC) 700 fts_flags |= FTS_PHYSICAL; 701 else 702 fts_flags |= FTS_LOGICAL; 703 704 fts = fts_open((char * const *)paths, fts_flags, NULL); 705 706 status = s->statuscb; 707 while ((ftsent = fts_read(fts)) != NULL) { 708 int rv = 0; 709 char *dstfile = NULL; 710 int cmd = 0; 711 copyfile_state_t tstate = copyfile_state_alloc(); 712 if (tstate == NULL) { 713 errno = ENOMEM; 714 retval = -1; 715 break; 716 } 717 tstate->statuscb = s->statuscb; 718 tstate->ctx = s->ctx; 719 asprintf(&dstfile, "%s%s%s", dst, dstpathsep, ftsent->fts_path + offset); 720 if (dstfile == NULL) { 721 copyfile_state_free(tstate); 722 errno = ENOMEM; 723 retval = -1; 724 break; 725 } 726 switch (ftsent->fts_info) { 727 case FTS_D: 728 tstate->internal_flags |= cfDelayAce; 729 cmd = COPYFILE_RECURSE_DIR; 730 break; 731 case FTS_SL: 732 case FTS_SLNONE: 733 case FTS_DEFAULT: 734 case FTS_F: 735 cmd = COPYFILE_RECURSE_FILE; 736 break; 737 case FTS_DP: 738 cmd = COPYFILE_RECURSE_DIR_CLEANUP; 739 break; 740 case FTS_DNR: 741 case FTS_ERR: 742 case FTS_NS: 743 case FTS_NSOK: 744 default: 745 errno = ftsent->fts_errno; 746 if (status) { 747 rv = (*status)(COPYFILE_RECURSE_ERROR, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 748 if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) { 749 errno = 0; 750 goto skipit; 751 } 752 if (rv == COPYFILE_QUIT) { 753 retval = -1; 754 goto stopit; 755 } 756 } else { 757 retval = -1; 758 goto stopit; 759 } 760 case FTS_DOT: 761 goto skipit; 762 763 } 764 765 if (cmd == COPYFILE_RECURSE_DIR || cmd == COPYFILE_RECURSE_FILE) { 766 if (status) { 767 rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx); 768 if (rv == COPYFILE_SKIP) { 769 if (cmd == COPYFILE_RECURSE_DIR) { 770 rv = fts_set(fts, ftsent, FTS_SKIP); 771 if (rv == -1) { 772 rv = (*status)(0, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 773 if (rv == COPYFILE_QUIT) 774 retval = -1; 775 } 776 } 777 goto skipit; 778 } 779 if (rv == COPYFILE_QUIT) { 780 retval = -1; errno = 0; 781 goto stopit; 782 } 783 } 784 int tmp_flags = (cmd == COPYFILE_RECURSE_DIR) ? (flags & ~COPYFILE_STAT) : flags; 785 rv = copyfile(ftsent->fts_path, dstfile, tstate, tmp_flags); 786 if (rv < 0) { 787 if (status) { 788 rv = (*status)(cmd, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 789 if (rv == COPYFILE_QUIT) { 790 retval = -1; 791 goto stopit; 792 } else 793 rv = 0; 794 goto skipit; 795 } else { 796 retval = -1; 797 goto stopit; 798 } 799 } 800 if (status) { 801 rv = (*status)(cmd, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx); 802 if (rv == COPYFILE_QUIT) { 803 retval = -1; errno = 0; 804 goto stopit; 805 } 806 } 807 } else if (cmd == COPYFILE_RECURSE_DIR_CLEANUP) { 808 if (status) { 809 rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx); 810 if (rv == COPYFILE_QUIT) { 811 retval = -1; errno = 0; 812 goto stopit; 813 } else if (rv == COPYFILE_SKIP) { 814 rv = 0; 815 goto skipit; 816 } 817 } 818 rv = copyfile(ftsent->fts_path, dstfile, tstate, (flags & COPYFILE_NOFOLLOW) | COPYFILE_STAT); 819 if (rv < 0) { 820 if (status) { 821 rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx); 822 if (rv == COPYFILE_QUIT) { 823 retval = -1; 824 goto stopit; 825 } else if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) { 826 if (rv == COPYFILE_CONTINUE) 827 errno = 0; 828 retval = 0; 829 goto skipit; 830 } 831 } else { 832 retval = -1; 833 goto stopit; 834 } 835 } else { 836 if (status) { 837 rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx); 838 if (rv == COPYFILE_QUIT) { 839 retval = -1; errno = 0; 840 goto stopit; 841 } 842 } 843 } 844 845 rv = 0; 846 } 847skipit: 848stopit: 849 copyfile_state_free(tstate); 850 free(dstfile); 851 if (retval == -1) 852 break; 853 } 854 855done: 856 if (fts) 857 fts_close(fts); 858 859 return retval; 860} 861 862/* 863 * fcopyfile() is used to copy a source file descriptor to a destination file 864 * descriptor. This allows an application to figure out how it wants to open 865 * the files (doing various security checks, perhaps), and then just pass in 866 * the file descriptors. 867 */ 868int fcopyfile(int src_fd, int dst_fd, copyfile_state_t state, copyfile_flags_t flags) 869{ 870 int ret = 0; 871 copyfile_state_t s = state; 872 struct stat dst_sb; 873 874 if (src_fd < 0 || dst_fd < 0) 875 { 876 errno = EINVAL; 877 return -1; 878 } 879 880 if (copyfile_preamble(&s, flags) < 0) 881 return -1; 882 883 copyfile_debug(2, "set src_fd <- %d", src_fd); 884 if (s->src_fd == -2 && src_fd > -1) 885 { 886 s->src_fd = src_fd; 887 if (fstatx_np(s->src_fd, &s->sb, s->fsec) != 0) 888 { 889 if (errno == ENOTSUP || errno == EPERM) 890 fstat(s->src_fd, &s->sb); 891 else 892 { 893 copyfile_warn("fstatx_np on src fd %d", s->src_fd); 894 return -1; 895 } 896 } 897 } 898 899 /* prevent copying on unsupported types */ 900 switch (s->sb.st_mode & S_IFMT) 901 { 902 case S_IFLNK: 903 case S_IFDIR: 904 case S_IFREG: 905 break; 906 default: 907 errno = ENOTSUP; 908 return -1; 909 } 910 911 copyfile_debug(2, "set dst_fd <- %d", dst_fd); 912 if (s->dst_fd == -2 && dst_fd > -1) 913 s->dst_fd = dst_fd; 914 915 (void)fstat(s->dst_fd, &dst_sb); 916 (void)fchmod(s->dst_fd, (dst_sb.st_mode & ~S_IFMT) | (S_IRUSR | S_IWUSR)); 917 918 (void)copyfile_quarantine(s); 919 920 ret = copyfile_internal(s, flags); 921 922 if (ret >= 0 && !(s->flags & COPYFILE_STAT)) 923 { 924 (void)fchmod(s->dst_fd, dst_sb.st_mode & ~S_IFMT); 925 } 926 927 if (s->err) { 928 errno = s->err; 929 s->err = 0; 930 } 931 if (state == NULL) { 932 int t = errno; 933 copyfile_state_free(s); 934 errno = t; 935 } 936 937 return ret; 938 939} 940 941/* 942 * the original copyfile() routine; this copies a source file to a destination 943 * file. Note that because we need to set the names in the state variable, this 944 * is not just the same as opening the two files, and then calling fcopyfile(). 945 * Oh, if only life were that simple! 946 */ 947int copyfile(const char *src, const char *dst, copyfile_state_t state, copyfile_flags_t flags) 948{ 949 int ret = 0; 950 int createdst = 0; 951 copyfile_state_t s = state; 952 struct stat dst_sb; 953 954 if (src == NULL && dst == NULL) 955 { 956 errno = EINVAL; 957 return -1; 958 } 959 960 if (copyfile_preamble(&s, flags) < 0) 961 { 962 return -1; 963 } 964 965/* 966 * This macro is... well, it's not the worst thing you can do with cpp, not 967 * by a long shot. Essentially, we are setting the filename (src or dst) 968 * in the state structure; since the structure may not have been cleared out 969 * before being used again, we do some of the cleanup here: if the given 970 * filename (e.g., src) is set, and state->src is not equal to that, then 971 * we need to check to see if the file descriptor had been opened, and if so, 972 * close it. After that, we set state->src to be a copy of the given filename, 973 * releasing the old copy if necessary. 974 */ 975#define COPYFILE_SET_FNAME(NAME, S) \ 976 do { \ 977 if (NAME != NULL) { \ 978 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \ 979 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\ 980 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \ 981 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \ 982 close(S->NAME##_fd); \ 983 S->NAME##_fd = -2; \ 984 } \ 985 } \ 986 if (S->NAME) { \ 987 free(S->NAME); \ 988 S->NAME = NULL; \ 989 } \ 990 if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \ 991 return -1; \ 992 } \ 993 } while (0) 994 995 COPYFILE_SET_FNAME(src, s); 996 COPYFILE_SET_FNAME(dst, s); 997 998 if (s->flags & COPYFILE_RECURSIVE) { 999 ret = copytree(s); 1000 goto exit; 1001 } 1002 1003 /* 1004 * Get a copy of the source file's security settings 1005 */ 1006 if (s->original_fsec) { 1007 filesec_free(s->original_fsec); 1008 s->original_fsec = NULL; 1009 } 1010 if ((s->original_fsec = filesec_init()) == NULL) 1011 goto error_exit; 1012 1013 if ((s->flags & COPYFILE_NOFOLLOW_DST) && lstat(s->dst, &dst_sb) == 0 && 1014 ((dst_sb.st_mode & S_IFMT) == S_IFLNK)) { 1015 if (s->permissive_fsec) 1016 free(s->permissive_fsec); 1017 s->permissive_fsec = NULL; 1018 } else if(statx_np(s->dst, &dst_sb, s->original_fsec) == 0) 1019 { 1020 /* 1021 * copyfile_fix_perms() will make a copy of the permission set, 1022 * and insert at the beginning an ACE that ensures we can write 1023 * to the file and set attributes. 1024 */ 1025 1026 if((s->permissive_fsec = copyfile_fix_perms(s, &s->original_fsec)) != NULL) 1027 { 1028 /* 1029 * Set the permissions for the destination to our copy. 1030 * We should get ENOTSUP from any filesystem that simply 1031 * doesn't support it. 1032 */ 1033 if (chmodx_np(s->dst, s->permissive_fsec) < 0 && errno != ENOTSUP) 1034 { 1035 copyfile_warn("setting security information"); 1036 filesec_free(s->permissive_fsec); 1037 s->permissive_fsec = NULL; 1038 } 1039 } 1040 } else if (errno == ENOENT) { 1041 createdst = 1; 1042 } 1043 1044 /* 1045 * If COPYFILE_CHECK is set in flags, then all we are going to do 1046 * is see what kinds of things WOULD have been copied (see 1047 * copyfile_check() below). We return that value. 1048 */ 1049 if (COPYFILE_CHECK & flags) 1050 { 1051 ret = copyfile_check(s); 1052 goto exit; 1053 } else if ((ret = copyfile_open(s)) < 0) 1054 goto error_exit; 1055 1056 (void)fcntl(s->src_fd, F_NOCACHE, 1); 1057 (void)fcntl(s->dst_fd, F_NOCACHE, 1); 1058#ifdef F_SINGLE_WRITER 1059 (void)fcntl(s->dst_fd, F_SINGLE_WRITER, 1); 1060#endif 1061 1062 ret = copyfile_internal(s, flags); 1063 if (ret == -1) 1064 goto error_exit; 1065 1066#ifdef COPYFILE_RECURSIVE 1067 if (!(flags & COPYFILE_STAT)) { 1068 if (!createdst) 1069 { 1070 /* Just need to reset the BSD information -- mode, owner, group */ 1071 (void)fchown(s->dst_fd, dst_sb.st_uid, dst_sb.st_gid); 1072 (void)fchmod(s->dst_fd, dst_sb.st_mode); 1073 } 1074 } 1075#endif 1076 1077 reset_security(s); 1078 1079 if (s->src && (flags & COPYFILE_MOVE)) 1080 (void)remove(s->src); 1081 1082exit: 1083 if (state == NULL) { 1084 int t = errno; 1085 copyfile_state_free(s); 1086 errno = t; 1087 } 1088 1089 return ret; 1090 1091error_exit: 1092 ret = -1; 1093 if (s->err) { 1094 errno = s->err; 1095 s->err = 0; 1096 } 1097 goto exit; 1098} 1099 1100/* 1101 * Shared prelude to the {f,}copyfile(). This initializes the 1102 * state variable, if necessary, and also checks for both debugging 1103 * and disabling environment variables. 1104 */ 1105static int copyfile_preamble(copyfile_state_t *state, copyfile_flags_t flags) 1106{ 1107 copyfile_state_t s; 1108 1109 if (*state == NULL) 1110 { 1111 if ((*state = copyfile_state_alloc()) == NULL) 1112 return -1; 1113 } 1114 1115 s = *state; 1116 1117 if (COPYFILE_DEBUG & flags) 1118 { 1119 char *e; 1120 if ((e = getenv(COPYFILE_DEBUG_VAR))) 1121 { 1122 errno = 0; 1123 s->debug = (uint32_t)strtol(e, NULL, 0); 1124 1125 /* clamp s->debug to 1 if the environment variable is not parsable */ 1126 if (s->debug == 0 && errno != 0) 1127 s->debug = 1; 1128 } 1129 copyfile_debug(2, "debug value set to: %d", s->debug); 1130 } 1131 1132#if 0 1133 /* Temporarily disabled */ 1134 if (getenv(COPYFILE_DISABLE_VAR) != NULL) 1135 { 1136 copyfile_debug(1, "copyfile disabled"); 1137 return 2; 1138 } 1139#endif 1140 copyfile_debug(2, "setting flags: %d", s->flags); 1141 s->flags = flags; 1142 1143 return 0; 1144} 1145 1146/* 1147 * The guts of {f,}copyfile(). 1148 * This looks through the flags in a particular order, and calls the 1149 * associated functions. 1150 */ 1151static int copyfile_internal(copyfile_state_t s, copyfile_flags_t flags) 1152{ 1153 int ret = 0; 1154 1155 if (s->dst_fd < 0 || s->src_fd < 0) 1156 { 1157 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s->src_fd, s->dst_fd); 1158 s->err = EINVAL; 1159 return -1; 1160 } 1161 1162 /* 1163 * COPYFILE_PACK causes us to create an Apple Double version of the 1164 * source file, and puts it into the destination file. See 1165 * copyfile_pack() below for all the gory details. 1166 */ 1167 if (COPYFILE_PACK & flags) 1168 { 1169 if ((ret = copyfile_pack(s)) < 0) 1170 { 1171 if (s->dst) unlink(s->dst); 1172 goto exit; 1173 } 1174 goto exit; 1175 } 1176 1177 /* 1178 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously. 1179 * The goal there is to take an Apple Double file, and turn it 1180 * into a normal file (with data fork, resource fork, modes, 1181 * extended attributes, ACLs, etc.). 1182 */ 1183 if (COPYFILE_UNPACK & flags) 1184 { 1185 if ((ret = copyfile_unpack(s)) < 0) 1186 goto error_exit; 1187 goto exit; 1188 } 1189 1190 /* 1191 * If we have quarantine info set, we attempt 1192 * to apply it to dst_fd. We don't care if 1193 * it fails, not yet anyway. 1194 */ 1195 if (s->qinfo) { 1196 int qr = qtn_file_apply_to_fd(s->qinfo, s->dst_fd); 1197 if (qr != 0) { 1198 if (s->statuscb) { 1199 int rv; 1200 1201 s->xattr_name = (char*)XATTR_QUARANTINE_NAME; 1202 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 1203 s->xattr_name = NULL; 1204 if (rv == COPYFILE_QUIT) { 1205 s->err = errno = (qr < 0 ? ENOTSUP : qr); 1206 ret = -1; 1207 goto exit; 1208 } 1209 } else { 1210 s->err = errno = (qr < 0 ? ENOTSUP : qr); 1211 ret = -1; 1212 goto exit; 1213 } 1214 } 1215 } 1216 1217 /* 1218 * COPYFILE_XATTR tells us to copy the extended attributes; 1219 * this is seperate from the extended security (aka ACLs), 1220 * however. If we succeed in this, we continue to the next 1221 * stage; if we fail, we return with an error value. Note 1222 * that we fail if the errno is ENOTSUP, but we don't print 1223 * a warning in that case. 1224 */ 1225 if (COPYFILE_XATTR & flags) 1226 { 1227 if ((ret = copyfile_xattr(s)) < 0) 1228 { 1229 if (errno != ENOTSUP && errno != EPERM) 1230 copyfile_warn("error processing extended attributes"); 1231 goto exit; 1232 } 1233 } 1234 1235 /* 1236 * Simialr to above, this tells us whether or not to copy 1237 * the non-meta data portion of the file. We attempt to 1238 * remove (via unlink) the destination file if we fail. 1239 */ 1240 if (COPYFILE_DATA & flags) 1241 { 1242 if ((ret = copyfile_data(s)) < 0) 1243 { 1244 copyfile_warn("error processing data"); 1245 if (s->dst && unlink(s->dst)) 1246 copyfile_warn("%s: remove", s->src ? s->src : "(null src)"); 1247 goto exit; 1248 } 1249 } 1250 1251 /* 1252 * COPYFILE_SECURITY requests that we copy the security, both 1253 * extended and mundane (that is, ACLs and POSIX). 1254 */ 1255 if (COPYFILE_SECURITY & flags) 1256 { 1257 if ((ret = copyfile_security(s)) < 0) 1258 { 1259 copyfile_warn("error processing security information"); 1260 goto exit; 1261 } 1262 } 1263 1264 if (COPYFILE_STAT & flags) 1265 { 1266 if ((ret = copyfile_stat(s)) < 0) 1267 { 1268 copyfile_warn("error processing POSIX information"); 1269 goto exit; 1270 } 1271 } 1272 1273exit: 1274 return ret; 1275 1276error_exit: 1277 ret = -1; 1278 goto exit; 1279} 1280 1281/* 1282 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable. 1283 */ 1284copyfile_state_t copyfile_state_alloc(void) 1285{ 1286 copyfile_state_t s = (copyfile_state_t) calloc(1, sizeof(struct _copyfile_state)); 1287 1288 if (s != NULL) 1289 { 1290 s->src_fd = -2; 1291 s->dst_fd = -2; 1292 if (s->fsec) { 1293 filesec_free(s->fsec); 1294 s->fsec = NULL; 1295 } 1296 s->fsec = filesec_init(); 1297 } else 1298 errno = ENOMEM; 1299 1300 return s; 1301} 1302 1303/* 1304 * copyfile_state_free() returns the memory allocated to the state structure. 1305 * It also closes the file descriptors, if they've been opened. 1306 */ 1307int copyfile_state_free(copyfile_state_t s) 1308{ 1309 if (s != NULL) 1310 { 1311 if (s->fsec) 1312 filesec_free(s->fsec); 1313 1314 if (s->original_fsec) 1315 filesec_free(s->original_fsec); 1316 1317 if (s->permissive_fsec) 1318 filesec_free(s->permissive_fsec); 1319 1320 if (s->qinfo) 1321 qtn_file_free(s->qinfo); 1322 1323 if (copyfile_close(s) < 0) 1324 { 1325 copyfile_warn("error closing files"); 1326 return -1; 1327 } 1328 if (s->xattr_name) 1329 free(s->xattr_name); 1330 if (s->dst) 1331 free(s->dst); 1332 if (s->src) 1333 free(s->src); 1334 free(s); 1335 } 1336 return 0; 1337} 1338 1339/* 1340 * Should we worry if we can't close the source? NFS says we 1341 * should, but it's pretty late for us at this point. 1342 */ 1343static int copyfile_close(copyfile_state_t s) 1344{ 1345 if (s->src && s->src_fd >= 0) 1346 close(s->src_fd); 1347 1348 if (s->dst && s->dst_fd >= 0) { 1349 if (close(s->dst_fd)) 1350 return -1; 1351 } 1352 1353 return 0; 1354} 1355 1356/* 1357 * The purpose of this function is to set up a set of permissions 1358 * (ACL and traditional) that lets us write to the file. In the 1359 * case of ACLs, we do this by putting in a first entry that lets 1360 * us write data, attributes, and extended attributes. In the case 1361 * of traditional permissions, we set the S_IWUSR (user-write) 1362 * bit. 1363 */ 1364static filesec_t copyfile_fix_perms(copyfile_state_t s __unused, filesec_t *fsec) 1365{ 1366 filesec_t ret_fsec = NULL; 1367 mode_t mode; 1368 acl_t acl = NULL; 1369 1370 if ((ret_fsec = filesec_dup(*fsec)) == NULL) 1371 goto error_exit; 1372 1373 if (filesec_get_property(ret_fsec, FILESEC_ACL, &acl) == 0) 1374 { 1375#ifdef COPYFILE_RECURSIVE 1376 if (add_uberace(&acl)) 1377 goto error_exit; 1378#else 1379 acl_entry_t entry; 1380 acl_permset_t permset; 1381 uuid_t qual; 1382 1383 if (mbr_uid_to_uuid(getuid(), qual) != 0) 1384 goto error_exit; 1385 1386 /* 1387 * First, we create an entry, and give it the special name 1388 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first. 1389 * After that, we clear out all the permissions in it, and 1390 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and 1391 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows 1392 * the functionality, and put this into the ACL. 1393 */ 1394 if (acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY) == -1) 1395 goto error_exit; 1396 if (acl_get_permset(entry, &permset) == -1) 1397 goto error_exit; 1398 if (acl_clear_perms(permset) == -1) 1399 goto error_exit; 1400 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1) 1401 goto error_exit; 1402 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1) 1403 goto error_exit; 1404 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1) 1405 goto error_exit; 1406 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1) 1407 goto error_exit; 1408 1409 if(acl_set_permset(entry, permset) == -1) 1410 goto error_exit; 1411 if(acl_set_qualifier(entry, qual) == -1) 1412 goto error_exit; 1413#endif 1414 1415 if (filesec_set_property(ret_fsec, FILESEC_ACL, &acl) != 0) 1416 goto error_exit; 1417 } 1418 1419 /* 1420 * This is for the normal, mundane, POSIX permission model. 1421 * We make sure that we can write to the file. 1422 */ 1423 if (filesec_get_property(ret_fsec, FILESEC_MODE, &mode) == 0) 1424 { 1425 if ((mode & (S_IWUSR | S_IRUSR)) != (S_IWUSR | S_IRUSR)) 1426 { 1427 mode |= S_IWUSR|S_IRUSR; 1428 if (filesec_set_property(ret_fsec, FILESEC_MODE, &mode) != 0) 1429 goto error_exit; 1430 } 1431 } 1432 1433exit: 1434 if (acl) 1435 acl_free(acl); 1436 1437 return ret_fsec; 1438 1439error_exit: 1440 if (ret_fsec) 1441 { 1442 filesec_free(ret_fsec); 1443 ret_fsec = NULL; 1444 } 1445 goto exit; 1446} 1447 1448/* 1449 * Used to clear out the BSD/POSIX security information from 1450 * a filesec 1451 */ 1452static int 1453copyfile_unset_posix_fsec(filesec_t fsec) 1454{ 1455 (void)filesec_set_property(fsec, FILESEC_OWNER, _FILESEC_UNSET_PROPERTY); 1456 (void)filesec_set_property(fsec, FILESEC_GROUP, _FILESEC_UNSET_PROPERTY); 1457 (void)filesec_set_property(fsec, FILESEC_MODE, _FILESEC_UNSET_PROPERTY); 1458 return 0; 1459} 1460 1461/* 1462 * Used to remove acl information from a filesec_t 1463 * Unsetting the acl alone in Tiger was insufficient 1464 */ 1465static int copyfile_unset_acl(copyfile_state_t s) 1466{ 1467 int ret = 0; 1468 if (filesec_set_property(s->fsec, FILESEC_ACL, NULL) == -1) 1469 { 1470 copyfile_debug(5, "unsetting acl attribute on %s", s->dst ? s->dst : "(null dst)"); 1471 ++ret; 1472 } 1473 if (filesec_set_property(s->fsec, FILESEC_UUID, NULL) == -1) 1474 { 1475 copyfile_debug(5, "unsetting uuid attribute on %s", s->dst ? s->dst : "(null dst)"); 1476 ++ret; 1477 } 1478 if (filesec_set_property(s->fsec, FILESEC_GRPUUID, NULL) == -1) 1479 { 1480 copyfile_debug(5, "unsetting group uuid attribute on %s", s->dst ? s->dst : "(null dst)"); 1481 ++ret; 1482 } 1483 return ret; 1484} 1485 1486/* 1487 * copyfile_open() does what one expects: it opens up the files 1488 * given in the state structure, if they're not already open. 1489 * It also does some type validation, to ensure that we only 1490 * handle file types we know about. 1491 */ 1492static int copyfile_open(copyfile_state_t s) 1493{ 1494 int oflags = O_EXCL | O_CREAT | O_WRONLY; 1495 int islnk = 0, isdir = 0; 1496 int osrc = 0, dsrc = 0; 1497 1498 if (s->src && s->src_fd == -2) 1499 { 1500 if ((COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np) 1501 (s->src, &s->sb, s->fsec)) 1502 { 1503 copyfile_warn("stat on %s", s->src); 1504 return -1; 1505 } 1506 1507 /* prevent copying on unsupported types */ 1508 switch (s->sb.st_mode & S_IFMT) 1509 { 1510 case S_IFLNK: 1511 islnk = 1; 1512 if ((size_t)s->sb.st_size > SIZE_T_MAX) { 1513 s->err = ENOMEM; /* too big for us to copy */ 1514 return -1; 1515 } 1516 osrc = O_SYMLINK; 1517 break; 1518 case S_IFDIR: 1519 isdir = 1; 1520 break; 1521 case S_IFREG: 1522 break; 1523 default: 1524 if (!(strcmp(s->src, "/dev/null") == 0 && (s->flags & COPYFILE_METADATA))) { 1525 s->err = ENOTSUP; 1526 return -1; 1527 } 1528 } 1529 /* 1530 * If we're packing, then we are actually 1531 * creating a file, no matter what the source 1532 * was. 1533 */ 1534 if (s->flags & COPYFILE_PACK) { 1535 /* 1536 * O_SYMLINK and O_NOFOLLOW are not compatible options: 1537 * if the file is a symlink, and O_NOFOLLOW is specified, 1538 * open will return ELOOP, whether or not O_SYMLINK is set. 1539 * However, we know whether or not it was a symlink from 1540 * the stat above (although there is a potentiaal for a race 1541 * condition here, but it will err on the side of returning 1542 * ELOOP from open). 1543 */ 1544 if (!islnk) 1545 osrc = (s->flags & COPYFILE_NOFOLLOW_SRC) ? O_NOFOLLOW : 0; 1546 isdir = islnk = 0; 1547 } 1548 1549 if ((s->src_fd = open(s->src, O_RDONLY | osrc , 0)) < 0) 1550 { 1551 copyfile_warn("open on %s", s->src); 1552 return -1; 1553 } else 1554 copyfile_debug(2, "open successful on source (%s)", s->src); 1555 1556 (void)copyfile_quarantine(s); 1557 } 1558 1559 if (s->dst && s->dst_fd == -2) 1560 { 1561 /* 1562 * COPYFILE_UNLINK tells us to try removing the destination 1563 * before we create it. We don't care if the file doesn't 1564 * exist, so we ignore ENOENT. 1565 */ 1566 if (COPYFILE_UNLINK & s->flags) 1567 { 1568 if (remove(s->dst) < 0 && errno != ENOENT) 1569 { 1570 copyfile_warn("%s: remove", s->dst); 1571 return -1; 1572 } 1573 } 1574 1575 if (s->flags & COPYFILE_NOFOLLOW_DST) { 1576 struct stat st; 1577 1578 dsrc = O_NOFOLLOW; 1579 if (lstat(s->dst, &st) != -1) { 1580 if ((st.st_mode & S_IFMT) == S_IFLNK) 1581 dsrc = O_SYMLINK; 1582 } 1583 } 1584 1585 if (islnk) { 1586 size_t sz = (size_t)s->sb.st_size + 1; 1587 char *bp; 1588 1589 bp = calloc(1, sz); 1590 if (bp == NULL) { 1591 copyfile_warn("cannot allocate %zd bytes", sz); 1592 return -1; 1593 } 1594 if (readlink(s->src, bp, sz-1) == -1) { 1595 copyfile_warn("cannot readlink %s", s->src); 1596 free(bp); 1597 return -1; 1598 } 1599 if (symlink(bp, s->dst) == -1) { 1600 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) { 1601 copyfile_warn("Cannot make symlink %s", s->dst); 1602 free(bp); 1603 return -1; 1604 } 1605 } 1606 free(bp); 1607 s->dst_fd = open(s->dst, O_RDONLY | O_SYMLINK); 1608 if (s->dst_fd == -1) { 1609 copyfile_warn("Cannot open symlink %s for reading", s->dst); 1610 return -1; 1611 } 1612 } else if (isdir) { 1613 mode_t mode; 1614 mode = (s->sb.st_mode & ~S_IFMT) | S_IRWXU; 1615 1616 if (mkdir(s->dst, mode) == -1) { 1617 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) { 1618 copyfile_warn("Cannot make directory %s", s->dst); 1619 return -1; 1620 } 1621 } 1622 s->dst_fd = open(s->dst, O_RDONLY | dsrc); 1623 if (s->dst_fd == -1) { 1624 copyfile_warn("Cannot open directory %s for reading", s->dst); 1625 return -1; 1626 } 1627 } else while((s->dst_fd = open(s->dst, oflags | dsrc, s->sb.st_mode | S_IWUSR)) < 0) 1628 { 1629 /* 1630 * We set S_IWUSR because fsetxattr does not -- at the time this comment 1631 * was written -- allow one to set an extended attribute on a file descriptor 1632 * for a read-only file, even if the file descriptor is opened for writing. 1633 * This will only matter if the file does not already exist. 1634 */ 1635 switch(errno) 1636 { 1637 case EEXIST: 1638 copyfile_debug(3, "open failed, retrying (%s)", s->dst); 1639 if (s->flags & COPYFILE_EXCL) 1640 break; 1641 oflags = oflags & ~O_CREAT; 1642 if (s->flags & (COPYFILE_PACK | COPYFILE_DATA)) 1643 { 1644 copyfile_debug(4, "truncating existing file (%s)", s->dst); 1645 oflags |= O_TRUNC; 1646 } 1647 continue; 1648 case EACCES: 1649 if(chmod(s->dst, (s->sb.st_mode | S_IWUSR) & ~S_IFMT) == 0) 1650 continue; 1651 else { 1652 /* 1653 * If we're trying to write to a directory to which we don't 1654 * have access, the create above would have failed, but chmod 1655 * here would have given us ENOENT. But the real error is 1656 * still one of access, so we change the errno we're reporting. 1657 * This could cause confusion with a race condition. 1658 */ 1659 1660 if (errno == ENOENT) 1661 errno = EACCES; 1662 break; 1663 } 1664 case EISDIR: 1665 copyfile_debug(3, "open failed because it is a directory (%s)", s->dst); 1666 if (((s->flags & COPYFILE_EXCL) || 1667 (!isdir && (s->flags & COPYFILE_DATA))) 1668 && !(s->flags & COPYFILE_UNPACK)) 1669 break; 1670 oflags = (oflags & ~(O_WRONLY|O_CREAT|O_TRUNC)) | O_RDONLY; 1671 continue; 1672 } 1673 copyfile_warn("open on %s", s->dst); 1674 return -1; 1675 } 1676 copyfile_debug(2, "open successful on destination (%s)", s->dst); 1677 } 1678 1679 if (s->dst_fd < 0 || s->src_fd < 0) 1680 { 1681 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", 1682 s->src_fd, s->dst_fd); 1683 s->err = EINVAL; 1684 return -1; 1685 } 1686 return 0; 1687} 1688 1689 1690/* 1691 * copyfile_check(), as described above, essentially tells you 1692 * what you'd have to copy, if you wanted it to copy the things 1693 * you asked it to copy. 1694 * In other words, if you pass in COPYFILE_ALL, and the file in 1695 * question had no extended attributes but did have an ACL, you'd 1696 * get back COPYFILE_ACL. 1697 */ 1698static copyfile_flags_t copyfile_check(copyfile_state_t s) 1699{ 1700 acl_t acl = NULL; 1701 copyfile_flags_t ret = 0; 1702 int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC); 1703 qtn_file_t qinfo; 1704 1705 if (!s->src) 1706 { 1707 s->err = EINVAL; 1708 return -1; 1709 } 1710 1711 /* check EAs */ 1712 if (COPYFILE_XATTR & s->flags) 1713 if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0) 1714 { 1715 ret |= COPYFILE_XATTR; 1716 } 1717 1718 if (COPYFILE_ACL & s->flags) 1719 { 1720 (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np) 1721 (s->src, &s->sb, s->fsec); 1722 1723 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0) 1724 ret |= COPYFILE_ACL; 1725 } 1726 1727 copyfile_debug(2, "check result: %d (%s)", ret, s->src); 1728 1729 if (acl) 1730 acl_free(acl); 1731 1732 if (s->qinfo) { 1733 /* If the state has had quarantine info set already, we use that */ 1734 ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL); 1735 } else { 1736 qinfo = qtn_file_alloc(); 1737 /* 1738 * For quarantine information, we need to see if the source file 1739 * has any. Since it may be a symlink, however, and we may, or 1740 * not be following, *and* there's no qtn* routine which can optionally 1741 * follow or not follow a symlink, we need to instead work around 1742 * this limitation. 1743 */ 1744 if (qinfo) { 1745 int fd; 1746 int qret = 0; 1747 struct stat sbuf; 1748 1749 /* 1750 * If we care about not following symlinks, *and* the file exists 1751 * (which is to say, lstat doesn't return an error), *and* the file 1752 * is a symlink, then we open it up (with O_SYMLINK), and use 1753 * qtn_file_init_with_fd(); if none of that is true, however, then 1754 * we can simply use qtn_file_init_with_path(). 1755 */ 1756 if (nofollow 1757 && lstat(s->src, &sbuf) == 0 1758 && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) { 1759 fd = open(s->src, O_RDONLY | O_SYMLINK); 1760 if (fd != -1) { 1761 if (!qtn_file_init_with_fd(qinfo, fd)) { 1762 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL); 1763 } 1764 close(fd); 1765 } 1766 } else { 1767 if (!qtn_file_init_with_path(qinfo, s->src)) { 1768 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL); 1769 } 1770 } 1771 qtn_file_free(qinfo); 1772 ret |= qret; 1773 } 1774 } 1775 return ret; 1776} 1777 1778/* 1779 * Attempt to copy the data section of a file. Using blockisize 1780 * is not necessarily the fastest -- it might be desirable to 1781 * specify a blocksize, somehow. But it's a size that should be 1782 * guaranteed to work. 1783 */ 1784static int copyfile_data(copyfile_state_t s) 1785{ 1786 size_t blen; 1787 char *bp = 0; 1788 ssize_t nread; 1789 int ret = 0; 1790 size_t iBlocksize = 0; 1791 size_t oBlocksize = 0; 1792 const size_t onegig = 1 << 30; 1793 struct statfs sfs; 1794 copyfile_callback_t status = s->statuscb; 1795 1796 /* Unless it's a normal file, we don't copy. For now, anyway */ 1797 if ((s->sb.st_mode & S_IFMT) != S_IFREG) 1798 return 0; 1799 1800#ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION 1801 if (s->internal_flags & cfSawDecmpEA) { 1802 if (s->sb.st_flags & UF_COMPRESSED) { 1803 if ((s->flags & COPYFILE_STAT) == 0) { 1804 if (fchflags(s->dst_fd, UF_COMPRESSED) == 0) { 1805 goto exit; 1806 } 1807 } 1808 } 1809 } 1810#endif 1811 1812 if (fstatfs(s->src_fd, &sfs) == -1) { 1813 iBlocksize = s->sb.st_blksize; 1814 } else { 1815 iBlocksize = sfs.f_iosize; 1816 } 1817 1818 /* Work-around for 6453525, limit blocksize to 1G */ 1819 if (iBlocksize > onegig) { 1820 iBlocksize = onegig; 1821 } 1822 1823 if ((bp = malloc(iBlocksize)) == NULL) 1824 return -1; 1825 1826 if (fstatfs(s->dst_fd, &sfs) == -1 || sfs.f_iosize == 0) { 1827 oBlocksize = iBlocksize; 1828 } else { 1829 oBlocksize = sfs.f_iosize; 1830 if (oBlocksize > onegig) 1831 oBlocksize = onegig; 1832 } 1833 1834 blen = iBlocksize; 1835 1836 s->totalCopied = 0; 1837/* If supported, do preallocation for Xsan / HFS volumes */ 1838#ifdef F_PREALLOCATE 1839 { 1840 fstore_t fst; 1841 1842 fst.fst_flags = 0; 1843 fst.fst_posmode = F_PEOFPOSMODE; 1844 fst.fst_offset = 0; 1845 fst.fst_length = s->sb.st_size; 1846 /* Ignore errors; this is merely advisory. */ 1847 (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst); 1848 } 1849#endif 1850 1851 while ((nread = read(s->src_fd, bp, blen)) > 0) 1852 { 1853 ssize_t nwritten; 1854 size_t left = nread; 1855 void *ptr = bp; 1856 int loop = 0; 1857 1858 while (left > 0) { 1859 nwritten = write(s->dst_fd, ptr, MIN(left, oBlocksize)); 1860 switch (nwritten) { 1861 case 0: 1862 if (++loop > 5) { 1863 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop); 1864 ret = -1; 1865 s->err = EAGAIN; 1866 goto exit; 1867 } 1868 break; 1869 case -1: 1870 copyfile_warn("writing to output file got error"); 1871 if (status) { 1872 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 1873 if (rv == COPYFILE_SKIP) { // Skip the data copy 1874 ret = 0; 1875 goto exit; 1876 } 1877 if (rv == COPYFILE_CONTINUE) { // Retry the write 1878 errno = 0; 1879 continue; 1880 } 1881 } 1882 ret = -1; 1883 goto exit; 1884 default: 1885 left -= nwritten; 1886 ptr = ((char*)ptr) + nwritten; 1887 loop = 0; 1888 break; 1889 } 1890 s->totalCopied += nwritten; 1891 if (status) { 1892 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 1893 if (rv == COPYFILE_QUIT) { 1894 ret = -1; s->err = errno = ECANCELED; 1895 goto exit; 1896 } 1897 } 1898 } 1899 } 1900 if (nread < 0) 1901 { 1902 copyfile_warn("reading from %s", s->src ? s->src : "(null src)"); 1903 ret = -1; 1904 goto exit; 1905 } 1906 1907 if (ftruncate(s->dst_fd, s->totalCopied) < 0) 1908 { 1909 ret = -1; 1910 goto exit; 1911 } 1912 1913exit: 1914 if (ret == -1) 1915 { 1916 s->err = errno; 1917 } 1918 free(bp); 1919 return ret; 1920} 1921 1922/* 1923 * copyfile_security() will copy the ACL set, and the 1924 * POSIX set. Complexities come when dealing with 1925 * inheritied permissions, and when dealing with both 1926 * POSIX and ACL permissions. 1927 */ 1928static int copyfile_security(copyfile_state_t s) 1929{ 1930 int copied = 0; 1931 struct stat sb; 1932 acl_t acl_src = NULL, acl_tmp = NULL, acl_dst = NULL; 1933 int ret = 0; 1934 filesec_t tmp_fsec = NULL; 1935 filesec_t fsec_dst = filesec_init(); 1936 1937 if (fsec_dst == NULL) 1938 return -1; 1939 1940 1941 if (COPYFILE_ACL & s->flags) 1942 { 1943 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src)) 1944 { 1945 if (errno == ENOENT) 1946 acl_src = NULL; 1947 else 1948 goto error_exit; 1949 } 1950 1951/* grab the destination acl 1952 cannot assume it's empty due to inheritance 1953*/ 1954 if(fstatx_np(s->dst_fd, &sb, fsec_dst)) 1955 goto error_exit; 1956 1957 if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst)) 1958 { 1959 if (errno == ENOENT) 1960 acl_dst = NULL; 1961 else 1962 goto error_exit; 1963 } 1964 1965 if (acl_src == NULL && acl_dst == NULL) 1966 goto no_acl; 1967 1968 acl_tmp = acl_init(4); 1969 if (acl_tmp == NULL) 1970 goto error_exit; 1971 1972 if (acl_src) { 1973 acl_entry_t ace = NULL; 1974 acl_entry_t tmp = NULL; 1975 for (copied = 0; 1976 acl_get_entry(acl_src, 1977 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, 1978 &ace) == 0;) 1979 { 1980 acl_flagset_t flags = { 0 }; 1981 acl_get_flagset_np(ace, &flags); 1982 if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED)) 1983 { 1984 if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1) 1985 goto error_exit; 1986 1987 if ((ret = acl_copy_entry(tmp, ace)) == -1) 1988 goto error_exit; 1989 1990 copyfile_debug(2, "copied acl entry from %s to %s", 1991 s->src ? s->src : "(null src)", 1992 s->dst ? s->dst : "(null tmp)"); 1993 copied++; 1994 } 1995 } 1996 } 1997 if (acl_dst) { 1998 acl_entry_t ace = NULL; 1999 acl_entry_t tmp = NULL; 2000 acl_flagset_t flags = { 0 }; 2001 for (copied = 0;acl_get_entry(acl_dst, 2002 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, 2003 &ace) == 0;) 2004 { 2005 acl_get_flagset_np(ace, &flags); 2006 if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED)) 2007 { 2008 if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1) 2009 goto error_exit; 2010 2011 if ((ret = acl_copy_entry(tmp, ace)) == -1) 2012 goto error_exit; 2013 2014 copyfile_debug(2, "copied acl entry from %s to %s", 2015 s->src ? s->src : "(null dst)", 2016 s->dst ? s->dst : "(null tmp)"); 2017 copied++; 2018 } 2019 } 2020 } 2021 if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_tmp)) 2022 { 2023 copyfile_debug(3, "altered acl"); 2024 } 2025 } 2026no_acl: 2027 /* 2028 * The following code is attempting to ensure that only the requested 2029 * security information gets copied over to the destination file. 2030 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT, 2031 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in 2032 * this function). 2033 * 2034 * If we have both flags, we copy everything; if we have ACL but not STAT, 2035 * we remove the POSIX information from the filesec object, and apply the 2036 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore 2037 * the extended version. 2038 */ 2039 tmp_fsec = filesec_dup(s->fsec); 2040 if (tmp_fsec == NULL) { 2041 goto error_exit; 2042 } 2043 2044 switch (COPYFILE_SECURITY & s->flags) { 2045 case COPYFILE_ACL: 2046 copyfile_unset_posix_fsec(tmp_fsec); 2047 /* FALLTHROUGH */ 2048 case COPYFILE_ACL | COPYFILE_STAT: 2049 if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) { 2050 acl_t acl = NULL; 2051 /* 2052 * The call could have failed for a number of reasons, since 2053 * it does a number of things: it changes the mode of the file, 2054 * sets the owner and group, and applies an ACL (if one exists). 2055 * The typical failure is going to be trying to set the group of 2056 * the destination file to match the source file, when the process 2057 * doesn't have permission to put files in that group. We try to 2058 * work around this by breaking the steps out and doing them 2059 * discretely. We don't care if the fchown fails, but we do care 2060 * if the mode or ACL can't be set. For historical reasons, we 2061 * simply log those failures, however. 2062 * 2063 * Big warning here: we may NOT have COPYFILE_STAT set, since 2064 * we fell-through from COPYFILE_ACL. So check for the fchmod. 2065 */ 2066 2067#define NS(x) ((x) ? (x) : "(null string)") 2068 if ((s->flags & COPYFILE_STAT) && 2069 fchmod(s->dst_fd, s->sb.st_mode) == -1) { 2070 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s->dst), NS(s->src)); 2071 } 2072 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid); 2073 if (filesec_get_property(tmp_fsec, FILESEC_ACL, &acl) == 0) { 2074 if (acl_set_fd(s->dst_fd, acl) == -1) { 2075 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s->dst), NS(s->src)); 2076 } 2077 acl_free(acl); 2078 } 2079 } 2080#undef NS 2081 break; 2082 case COPYFILE_STAT: 2083 (void)fchmod(s->dst_fd, s->sb.st_mode); 2084 break; 2085 } 2086 filesec_free(tmp_fsec); 2087exit: 2088 filesec_free(fsec_dst); 2089 if (acl_src) acl_free(acl_src); 2090 if (acl_dst) acl_free(acl_dst); 2091 if (acl_tmp) acl_free(acl_tmp); 2092 2093 return ret; 2094 2095error_exit: 2096 ret = -1; 2097goto exit; 2098 2099} 2100 2101/* 2102 * Attempt to set the destination file's stat information -- including 2103 * flags and time-related fields -- to the source's. 2104 */ 2105static int copyfile_stat(copyfile_state_t s) 2106{ 2107 struct timeval tval[2]; 2108 unsigned int added_flags = 0, dst_flags = 0; 2109 struct stat dst_sb; 2110 2111 /* 2112 * NFS doesn't support chflags; ignore errors as a result, since 2113 * we don't return failure for this. 2114 */ 2115 if (s->internal_flags & cfMakeFileInvisible) 2116 added_flags |= UF_HIDDEN; 2117 2118 /* 2119 * We need to check if SF_RESTRICTED was set on the destination 2120 * by the kernel. If it was, don't drop it. 2121 */ 2122 if (fstat(s->dst_fd, &dst_sb)) 2123 return -1; 2124 if (dst_sb.st_flags & SF_RESTRICTED) 2125 added_flags |= SF_RESTRICTED; 2126 2127 /* Copy file flags, masking out any we don't want to preserve */ 2128 dst_flags = (s->sb.st_flags & ~COPYFILE_OMIT_FLAGS) | added_flags; 2129 (void)fchflags(s->dst_fd, dst_flags); 2130 2131 /* If this fails, we don't care */ 2132 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid); 2133 2134 /* This may have already been done in copyfile_security() */ 2135 (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT); 2136 2137 tval[0].tv_sec = s->sb.st_atime; 2138 tval[1].tv_sec = s->sb.st_mtime; 2139 tval[0].tv_usec = tval[1].tv_usec = 0; 2140 (void)futimes(s->dst_fd, tval); 2141 2142 return 0; 2143} 2144 2145/* 2146 * Similar to copyfile_security() in some ways; this 2147 * routine copies the extended attributes from the source, 2148 * and sets them on the destination. 2149 * The procedure is pretty simple, even if it is verbose: 2150 * for each named attribute on the destination, get its name, and 2151 * remove it. We should have none after that. 2152 * For each named attribute on the source, get its name, get its 2153 * data, and set it on the destination. 2154 */ 2155static int copyfile_xattr(copyfile_state_t s) 2156{ 2157 char *name; 2158 char *namebuf, *end; 2159 ssize_t xa_size; 2160 void *xa_dataptr; 2161 ssize_t bufsize = 4096; 2162 ssize_t asize; 2163 ssize_t nsize; 2164 int ret = 0; 2165 int look_for_decmpea = 0; 2166 2167 /* delete EAs on destination */ 2168 if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0) 2169 { 2170 if ((namebuf = (char *) malloc(nsize)) == NULL) 2171 return -1; 2172 else 2173 nsize = flistxattr(s->dst_fd, namebuf, nsize, 0); 2174 2175 if (nsize > 0) { 2176 /* 2177 * With this, end points to the last byte of the allocated buffer 2178 * This *should* be NUL, from flistxattr, but if it's not, we can 2179 * set it anyway -- it'll result in a truncated name, which then 2180 * shouldn't match when we get them later. 2181 */ 2182 end = namebuf + nsize - 1; 2183 if (*end != 0) 2184 *end = 0; 2185 for (name = namebuf; name <= end; name += strlen(name) + 1) { 2186 /* If the quarantine information shows up as an EA, we skip over it */ 2187 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) { 2188 continue; 2189 } 2190 fremovexattr(s->dst_fd, name,0); 2191 } 2192 } 2193 free(namebuf); 2194 } else 2195 if (nsize < 0) 2196 { 2197 if (errno == ENOTSUP || errno == EPERM) 2198 return 0; 2199 else 2200 return -1; 2201 } 2202 2203#ifdef DECMPFS_XATTR_NAME 2204 if ((s->flags & COPYFILE_DATA) && 2205 (s->sb.st_flags & UF_COMPRESSED) && 2206 doesdecmpfs(s->src_fd) && 2207 doesdecmpfs(s->dst_fd)) { 2208 look_for_decmpea = XATTR_SHOWCOMPRESSION; 2209 } 2210#endif 2211 2212 /* get name list of EAs on source */ 2213 if ((nsize = flistxattr(s->src_fd, 0, 0, look_for_decmpea)) < 0) 2214 { 2215 if (errno == ENOTSUP || errno == EPERM) 2216 return 0; 2217 else 2218 return -1; 2219 } else 2220 if (nsize == 0) 2221 return 0; 2222 2223 if ((namebuf = (char *) malloc(nsize)) == NULL) 2224 return -1; 2225 else 2226 nsize = flistxattr(s->src_fd, namebuf, nsize, look_for_decmpea); 2227 2228 if (nsize <= 0) { 2229 free(namebuf); 2230 return (int)nsize; 2231 } 2232 2233 /* 2234 * With this, end points to the last byte of the allocated buffer 2235 * This *should* be NUL, from flistxattr, but if it's not, we can 2236 * set it anyway -- it'll result in a truncated name, which then 2237 * shouldn't match when we get them later. 2238 */ 2239 end = namebuf + nsize - 1; 2240 if (*end != 0) 2241 *end = 0; 2242 2243 if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) { 2244 free(namebuf); 2245 return -1; 2246 } 2247 2248 for (name = namebuf; name <= end; name += strlen(name) + 1) 2249 { 2250 if (s->xattr_name) { 2251 free(s->xattr_name); 2252 s->xattr_name = NULL; 2253 } 2254 2255 /* If the quarantine information shows up as an EA, we skip over it */ 2256 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) 2257 continue; 2258 2259 if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, look_for_decmpea)) < 0) 2260 { 2261 continue; 2262 } 2263 2264 if (xa_size > bufsize) 2265 { 2266 void *tdptr = xa_dataptr; 2267 bufsize = xa_size; 2268 if ((xa_dataptr = 2269 (void *) realloc((void *) xa_dataptr, bufsize)) == NULL) 2270 { 2271 free(tdptr); 2272 ret = -1; 2273 continue; 2274 } 2275 } 2276 2277 if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea)) < 0) 2278 { 2279 continue; 2280 } 2281 2282 if (xa_size != asize) 2283 xa_size = asize; 2284 2285#ifdef DECMPFS_XATTR_NAME 2286 if (strncmp(name, DECMPFS_XATTR_NAME, end-name) == 0) 2287 { 2288 decmpfs_disk_header *hdr = xa_dataptr; 2289 2290 /* 2291 * If the EA has the decmpfs name, but is too 2292 * small, or doesn't have the right magic number, 2293 * or isn't the right type, we'll just skip it. 2294 * This means it won't end up in the destination 2295 * file, and data copy will happen normally. 2296 */ 2297 if ((size_t)xa_size < sizeof(decmpfs_disk_header)) { 2298 continue; 2299 } 2300 if (OSSwapLittleToHostInt32(hdr->compression_magic) != DECMPFS_MAGIC) { 2301 continue; 2302 } 2303 /* 2304 * From AppleFSCompression documentation: 2305 * "It is incumbent on the aware copy engine to identify 2306 * the type of compression being used, and to perform an 2307 * unaware copy of any file it does not recognize." 2308 * 2309 * Compression Types are defined in: 2310 * "AppleFSCompression/Common/compressorCommon.h" 2311 * 2312 * Unfortunately, they don't provide a way to dynamically 2313 * determine what possible compression_type values exist, 2314 * so we have to update this every time a new compression_type 2315 * is added (Types 7->10 were added in Yosemite) 2316 * 2317 * Ubiquity faulting file compression type 0x80000001 are 2318 * deprecated as of Yosemite, per rdar://17714998 don't copy the 2319 * decmpfs xattr on these files, zero byte files are safer 2320 * than a fault nobody knows how to handle. 2321 */ 2322 switch (OSSwapLittleToHostInt32(hdr->compression_type)) { 2323 case 3: /* zlib-compressed data in xattr */ 2324 case 4: /* 64k chunked zlib-compressed data in resource fork */ 2325 2326 case 7: /* LZVN-compressed data in xattr */ 2327 case 8: /* 64k chunked LZVN-compressed data in resource fork */ 2328 2329 case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */ 2330 case 10: /* 64k chunked uncompressed data in resource fork */ 2331 2332 /* valid compression type, we want to copy. */ 2333 break; 2334 2335 case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */ 2336 copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.", 2337 s->src ? s->src : "(null string)"); 2338 continue; 2339 2340 case 6: /* unused */ 2341 case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */ 2342 default: 2343 copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s", 2344 OSSwapLittleToHostInt32(hdr->compression_type), name, s->src ? s->src : "(null string)"); 2345 continue; 2346 } 2347 s->internal_flags |= cfSawDecmpEA; 2348 } 2349#endif 2350 2351 // If we have a copy intention stated, and the EA is to be ignored, we ignore it 2352 if (s->copyIntent 2353 && xattr_preserve_for_intent(name, s->copyIntent) == 0) 2354 continue; 2355 2356 s->xattr_name = strdup(name); 2357 2358 if (s->statuscb) { 2359 int rv; 2360 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 2361 if (rv == COPYFILE_QUIT) { 2362 s->err = ECANCELED; 2363 goto out; 2364 } else if (rv == COPYFILE_SKIP) { 2365 continue; 2366 } 2367 } 2368 if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea) < 0) 2369 { 2370 if (s->statuscb) 2371 { 2372 int rv; 2373 if (s->xattr_name == NULL) 2374 s->xattr_name = strdup(name); 2375 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 2376 if (rv == COPYFILE_QUIT) 2377 { 2378 s->err = ECANCELED; 2379 ret = -1; 2380 goto out; 2381 } 2382 } 2383 else 2384 { 2385 ret = -1; 2386 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name, strerror(errno)); 2387 continue; 2388 } 2389 } 2390 if (s->statuscb) { 2391 int rv; 2392 if (s->xattr_name == NULL) 2393 s->xattr_name = strdup(name); 2394 2395 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 2396 if (rv == COPYFILE_QUIT) { 2397 s->err = ECANCELED; 2398 goto out; 2399 } 2400 } 2401 } 2402out: 2403 if (namebuf) 2404 free(namebuf); 2405 free((void *) xa_dataptr); 2406 if (s->xattr_name) { 2407 free(s->xattr_name); 2408 s->xattr_name = NULL; 2409 } 2410 return ret; 2411} 2412 2413/* 2414 * API interface into getting data from the opaque data type. 2415 */ 2416int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret) 2417{ 2418 if (ret == NULL) 2419 { 2420 errno = EFAULT; 2421 return -1; 2422 } 2423 2424 switch(flag) 2425 { 2426 case COPYFILE_STATE_SRC_FD: 2427 *(int*)ret = s->src_fd; 2428 break; 2429 case COPYFILE_STATE_DST_FD: 2430 *(int*)ret = s->dst_fd; 2431 break; 2432 case COPYFILE_STATE_SRC_FILENAME: 2433 *(char**)ret = s->src; 2434 break; 2435 case COPYFILE_STATE_DST_FILENAME: 2436 *(char**)ret = s->dst; 2437 break; 2438 case COPYFILE_STATE_QUARANTINE: 2439 *(qtn_file_t*)ret = s->qinfo; 2440 break; 2441#if 0 2442 case COPYFILE_STATE_STATS: 2443 ret = s->stats.global; 2444 break; 2445 case COPYFILE_STATE_PROGRESS_CB: 2446 ret = s->callbacks.progress; 2447 break; 2448#endif 2449#ifdef COPYFILE_STATE_STATUS_CB 2450 case COPYFILE_STATE_STATUS_CB: 2451 *(copyfile_callback_t*)ret = s->statuscb; 2452 break; 2453 case COPYFILE_STATE_STATUS_CTX: 2454 *(void**)ret = s->ctx; 2455 break; 2456 case COPYFILE_STATE_COPIED: 2457 *(off_t*)ret = s->totalCopied; 2458 break; 2459#endif 2460#ifdef COPYFILE_STATE_XATTRNAME 2461 case COPYFILE_STATE_XATTRNAME: 2462 *(char**)ret = s->xattr_name; 2463 break; 2464#endif 2465#ifdef COPYFILE_STATE_INTENT 2466 case COPYFILE_STATE_INTENT: 2467 *(xattr_operation_intent_t*)ret = s->copyIntent; 2468 break; 2469#endif 2470 default: 2471 errno = EINVAL; 2472 ret = NULL; 2473 return -1; 2474 } 2475 return 0; 2476} 2477 2478/* 2479 * Public API for setting state data (remember that the state is 2480 * an opaque data type). 2481 */ 2482int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing) 2483{ 2484#define copyfile_set_string(DST, SRC) \ 2485 do { \ 2486 if (SRC != NULL) { \ 2487 DST = strdup((char *)SRC); \ 2488 } else { \ 2489 if (DST != NULL) { \ 2490 free(DST); \ 2491 } \ 2492 DST = NULL; \ 2493 } \ 2494 } while (0) 2495 2496 if (thing == NULL) 2497 { 2498 errno = EFAULT; 2499 return -1; 2500 } 2501 2502 switch(flag) 2503 { 2504 case COPYFILE_STATE_SRC_FD: 2505 s->src_fd = *(int*)thing; 2506 break; 2507 case COPYFILE_STATE_DST_FD: 2508 s->dst_fd = *(int*)thing; 2509 break; 2510 case COPYFILE_STATE_SRC_FILENAME: 2511 copyfile_set_string(s->src, thing); 2512 break; 2513 case COPYFILE_STATE_DST_FILENAME: 2514 copyfile_set_string(s->dst, thing); 2515 break; 2516 case COPYFILE_STATE_QUARANTINE: 2517 if (s->qinfo) 2518 { 2519 qtn_file_free(s->qinfo); 2520 s->qinfo = NULL; 2521 } 2522 if (*(qtn_file_t*)thing) 2523 s->qinfo = qtn_file_clone(*(qtn_file_t*)thing); 2524 break; 2525#if 0 2526 case COPYFILE_STATE_STATS: 2527 s->stats.global = thing; 2528 break; 2529 case COPYFILE_STATE_PROGRESS_CB: 2530 s->callbacks.progress = thing; 2531 break; 2532#endif 2533#ifdef COPYFILE_STATE_STATUS_CB 2534 case COPYFILE_STATE_STATUS_CB: 2535 s->statuscb = (copyfile_callback_t)thing; 2536 break; 2537 case COPYFILE_STATE_STATUS_CTX: 2538 s->ctx = (void*)thing; 2539 break; 2540#endif 2541#ifdef COPYFILE_STATE_INTENT 2542 case COPYFILE_STATE_INTENT: 2543 s->copyIntent = *(xattr_operation_intent_t*)thing; 2544 break; 2545#endif 2546 default: 2547 errno = EINVAL; 2548 return -1; 2549 } 2550 return 0; 2551#undef copyfile_set_string 2552} 2553 2554 2555/* 2556 * Make this a standalone program for testing purposes by 2557 * defining _COPYFILE_TEST. 2558 */ 2559#ifdef _COPYFILE_TEST 2560#define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x }, 2561 2562struct {char *s; int v;} opts[] = { 2563 COPYFILE_OPTION(ACL) 2564 COPYFILE_OPTION(STAT) 2565 COPYFILE_OPTION(XATTR) 2566 COPYFILE_OPTION(DATA) 2567 COPYFILE_OPTION(SECURITY) 2568 COPYFILE_OPTION(METADATA) 2569 COPYFILE_OPTION(ALL) 2570 COPYFILE_OPTION(NOFOLLOW_SRC) 2571 COPYFILE_OPTION(NOFOLLOW_DST) 2572 COPYFILE_OPTION(NOFOLLOW) 2573 COPYFILE_OPTION(EXCL) 2574 COPYFILE_OPTION(MOVE) 2575 COPYFILE_OPTION(UNLINK) 2576 COPYFILE_OPTION(PACK) 2577 COPYFILE_OPTION(UNPACK) 2578 COPYFILE_OPTION(CHECK) 2579 COPYFILE_OPTION(VERBOSE) 2580 COPYFILE_OPTION(DEBUG) 2581 {NULL, 0} 2582}; 2583 2584int main(int c, char *v[]) 2585{ 2586 int i; 2587 int flags = 0; 2588 2589 if (c < 3) 2590 errx(1, "insufficient arguments"); 2591 2592 while(c-- > 3) 2593 { 2594 for (i = 0; opts[i].s != NULL; ++i) 2595 { 2596 if (strcasecmp(opts[i].s, v[c]) == 0) 2597 { 2598 printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v); 2599 flags |= opts[i].v; 2600 break; 2601 } 2602 } 2603 } 2604 2605 return copyfile(v[1], v[2], NULL, flags); 2606} 2607#endif 2608/* 2609 * Apple Double Create 2610 * 2611 * Create an Apple Double "._" file from a file's extented attributes 2612 * 2613 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. 2614 */ 2615 2616 2617#define offsetof(type, member) ((size_t)(&((type *)0)->member)) 2618 2619#define XATTR_MAXATTRLEN (16*1024*1024) 2620 2621 2622/* 2623 Typical "._" AppleDouble Header File layout: 2624 ------------------------------------------------------------ 2625 MAGIC 0x00051607 2626 VERSION 0x00020000 2627 FILLER 0 2628 COUNT 2 2629 .-- AD ENTRY[0] Finder Info Entry (must be first) 2630 .--+-- AD ENTRY[1] Resource Fork Entry (must be last) 2631 | '-> FINDER INFO 2632 | ///////////// Fixed Size Data (32 bytes) 2633 | EXT ATTR HDR 2634 | ///////////// 2635 | ATTR ENTRY[0] --. 2636 | ATTR ENTRY[1] --+--. 2637 | ATTR ENTRY[2] --+--+--. 2638 | ... | | | 2639 | ATTR ENTRY[N] --+--+--+--. 2640 | ATTR DATA 0 <-' | | | 2641 | //////////// | | | 2642 | ATTR DATA 1 <----' | | 2643 | ///////////// | | 2644 | ATTR DATA 2 <-------' | 2645 | ///////////// | 2646 | ... | 2647 | ATTR DATA N <----------' 2648 | ///////////// 2649 | Attribute Free Space 2650 | 2651 '----> RESOURCE FORK 2652 ///////////// Variable Sized Data 2653 ///////////// 2654 ///////////// 2655 ///////////// 2656 ///////////// 2657 ///////////// 2658 ... 2659 ///////////// 2660 2661 ------------------------------------------------------------ 2662 2663 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are 2664 stored as part of the Finder Info. The length in the Finder 2665 Info AppleDouble entry includes the length of the extended 2666 attribute header, attribute entries, and attribute data. 2667*/ 2668 2669 2670/* 2671 * On Disk Data Structures 2672 * 2673 * Note: Motorola 68K alignment and big-endian. 2674 * 2675 * See RFC 1740 for additional information about the AppleDouble file format. 2676 * 2677 */ 2678 2679#define ADH_MAGIC 0x00051607 2680#define ADH_VERSION 0x00020000 2681#define ADH_MACOSX "Mac OS X " 2682 2683/* 2684 * AppleDouble Entry ID's 2685 */ 2686#define AD_DATA 1 /* Data fork */ 2687#define AD_RESOURCE 2 /* Resource fork */ 2688#define AD_REALNAME 3 /* File's name on home file system */ 2689#define AD_COMMENT 4 /* Standard Mac comment */ 2690#define AD_ICONBW 5 /* Mac black & white icon */ 2691#define AD_ICONCOLOR 6 /* Mac color icon */ 2692#define AD_UNUSED 7 /* Not used */ 2693#define AD_FILEDATES 8 /* File dates; create, modify, etc */ 2694#define AD_FINDERINFO 9 /* Mac Finder info & extended info */ 2695#define AD_MACINFO 10 /* Mac file info, attributes, etc */ 2696#define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */ 2697#define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */ 2698#define AD_AFPNAME 13 /* Short name on AFP server */ 2699#define AD_AFPINFO 14 /* AFP file info, attrib., etc */ 2700#define AD_AFPDIRID 15 /* AFP directory ID */ 2701#define AD_ATTRIBUTES AD_FINDERINFO 2702 2703 2704#define ATTR_FILE_PREFIX "._" 2705#define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */ 2706 2707#define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */ 2708 2709/* Implementation Limits */ 2710#define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */ 2711#define ATTR_MAX_NAME_LEN 128 2712#define ATTR_MAX_HDR_SIZE (65536+18) 2713 2714/* 2715 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header 2716 * size supported (including the attribute entries). All of 2717 * the attribute entries must reside within this limit. 2718 */ 2719 2720 2721#define FINDERINFOSIZE 32 2722 2723typedef struct apple_double_entry 2724{ 2725 u_int32_t type; /* entry type: see list, 0 invalid */ 2726 u_int32_t offset; /* entry data offset from the beginning of the file. */ 2727 u_int32_t length; /* entry data length in bytes. */ 2728} __attribute__((aligned(2), packed)) apple_double_entry_t; 2729 2730 2731typedef struct apple_double_header 2732{ 2733 u_int32_t magic; /* == ADH_MAGIC */ 2734 u_int32_t version; /* format version: 2 = 0x00020000 */ 2735 u_int32_t filler[4]; 2736 u_int16_t numEntries; /* number of entries which follow */ 2737 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */ 2738 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */ 2739 u_int8_t pad[2]; /* get better alignment inside attr_header */ 2740} __attribute__((aligned(2), packed)) apple_double_header_t; 2741 2742 2743/* Entries are aligned on 4 byte boundaries */ 2744typedef struct attr_entry 2745{ 2746 u_int32_t offset; /* file offset to data */ 2747 u_int32_t length; /* size of attribute data */ 2748 u_int16_t flags; 2749 u_int8_t namelen; /* length of name including NULL termination char */ 2750 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */ 2751} __attribute__((aligned(2), packed)) attr_entry_t; 2752 2753 2754 2755/* Header + entries must fit into 64K */ 2756typedef struct attr_header 2757{ 2758 apple_double_header_t appledouble; 2759 u_int32_t magic; /* == ATTR_HDR_MAGIC */ 2760 u_int32_t debug_tag; /* for debugging == file id of owning file */ 2761 u_int32_t total_size; /* total size of attribute header + entries + data */ 2762 u_int32_t data_start; /* file offset to attribute data area */ 2763 u_int32_t data_length; /* length of attribute data area */ 2764 u_int32_t reserved[3]; 2765 u_int16_t flags; 2766 u_int16_t num_attrs; 2767} __attribute__((aligned(2), packed)) attr_header_t; 2768 2769/* Empty Resource Fork Header */ 2770/* This comes by way of xnu's vfs_xattr.c */ 2771typedef struct rsrcfork_header { 2772 u_int32_t fh_DataOffset; 2773 u_int32_t fh_MapOffset; 2774 u_int32_t fh_DataLength; 2775 u_int32_t fh_MapLength; 2776 u_int8_t systemData[112]; 2777 u_int8_t appData[128]; 2778 u_int32_t mh_DataOffset; 2779 u_int32_t mh_MapOffset; 2780 u_int32_t mh_DataLength; 2781 u_int32_t mh_MapLength; 2782 u_int32_t mh_Next; 2783 u_int16_t mh_RefNum; 2784 u_int8_t mh_Attr; 2785 u_int8_t mh_InMemoryAttr; 2786 u_int16_t mh_Types; 2787 u_int16_t mh_Names; 2788 u_int16_t typeCount; 2789} __attribute__((aligned(2), packed)) rsrcfork_header_t; 2790#define RF_FIRST_RESOURCE 256 2791#define RF_NULL_MAP_LENGTH 30 2792#define RF_EMPTY_TAG "This resource fork intentionally left blank " 2793 2794static const rsrcfork_header_t empty_rsrcfork_header = { 2795 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_DataOffset 2796 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_MapOffset 2797 0, // fh_DataLength 2798 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // fh_MapLength 2799 { RF_EMPTY_TAG, }, // systemData 2800 { 0 }, // appData 2801 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_DataOffset 2802 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_MapOffset 2803 0, // mh_DataLength 2804 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // mh_MapLength 2805 0, // mh_Next 2806 0, // mh_RefNum 2807 0, // mh_Attr 2808 0, // mh_InMemoryAttr 2809 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2), // mh_Types 2810 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH), // mh_Names 2811 OSSwapHostToBigInt16(-1), // typeCount 2812}; 2813 2814#define SWAP16(x) OSSwapBigToHostInt16(x) 2815#define SWAP32(x) OSSwapBigToHostInt32(x) 2816#define SWAP64(x) OSSwapBigToHostInt64(x) 2817 2818#define ATTR_ALIGN 3L /* Use four-byte alignment */ 2819 2820#define ATTR_ENTRY_LENGTH(namelen) \ 2821 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN)) 2822 2823#define ATTR_NEXT(ae) \ 2824 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen)) 2825 2826#define XATTR_SECURITY_NAME "com.apple.acl.text" 2827 2828/* 2829 * Endian swap Apple Double header 2830 */ 2831static void 2832swap_adhdr(apple_double_header_t *adh) 2833{ 2834#if BYTE_ORDER == LITTLE_ENDIAN 2835 int count; 2836 int i; 2837 2838 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries); 2839 2840 adh->magic = SWAP32 (adh->magic); 2841 adh->version = SWAP32 (adh->version); 2842 adh->numEntries = SWAP16 (adh->numEntries); 2843 2844 for (i = 0; i < count; i++) 2845 { 2846 adh->entries[i].type = SWAP32 (adh->entries[i].type); 2847 adh->entries[i].offset = SWAP32 (adh->entries[i].offset); 2848 adh->entries[i].length = SWAP32 (adh->entries[i].length); 2849 } 2850#else 2851 (void)adh; 2852#endif 2853} 2854 2855/* 2856 * Endian swap a single attr_entry_t 2857 */ 2858static void 2859swap_attrhdr_entry(attr_entry_t *ae) 2860{ 2861#if BYTE_ORDER == LITTLE_ENDIAN 2862 ae->offset = SWAP32 (ae->offset); 2863 ae->length = SWAP32 (ae->length); 2864 ae->flags = SWAP16 (ae->flags); 2865#else 2866 (void)ae; 2867#endif 2868} 2869 2870/* 2871 * For a validated/endian swapped attr_header_t* 2872 * ah, endian swap all of the entries. 2873 */ 2874static void 2875swap_attrhdr_entries(attr_header_t *ah) 2876{ 2877#if BYTE_ORDER == LITTLE_ENDIAN 2878 int i; 2879 int count; 2880 attr_entry_t *entry; 2881 attr_entry_t *next; 2882 2883 /* If we're in copyfile_pack, num_args is native endian, 2884 * if we're in _unpack, num_args is big endian. Use 2885 * the magic number to test for endianess. 2886 */ 2887 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs); 2888 2889 entry = (attr_entry_t *)(&ah[1]); 2890 for (i = 0; i < count; i++) { 2891 next = ATTR_NEXT(entry); 2892 swap_attrhdr_entry(entry); 2893 entry = next; 2894 } 2895#else 2896 (void)ah; 2897#endif 2898} 2899 2900/* 2901 * Endian swap extended attributes header 2902 */ 2903static void 2904swap_attrhdr(attr_header_t *ah) 2905{ 2906#if BYTE_ORDER == LITTLE_ENDIAN 2907 ah->magic = SWAP32 (ah->magic); 2908 ah->debug_tag = SWAP32 (ah->debug_tag); 2909 ah->total_size = SWAP32 (ah->total_size); 2910 ah->data_start = SWAP32 (ah->data_start); 2911 ah->data_length = SWAP32 (ah->data_length); 2912 ah->flags = SWAP16 (ah->flags); 2913 ah->num_attrs = SWAP16 (ah->num_attrs); 2914#else 2915 (void)ah; 2916#endif 2917} 2918 2919static const u_int32_t emptyfinfo[8] = {0}; 2920 2921/* 2922 * Given an Apple Double file in src, turn it into a 2923 * normal file (possibly with multiple forks, EAs, and 2924 * ACLs) in dst. 2925 */ 2926static int copyfile_unpack(copyfile_state_t s) 2927{ 2928 ssize_t bytes; 2929 void * buffer, * endptr, * dataptr = NULL; 2930 apple_double_header_t *adhdr; 2931 ssize_t hdrsize; 2932 int error = 0; 2933 2934 if (s->sb.st_size < ATTR_MAX_HDR_SIZE) 2935 hdrsize = (ssize_t)s->sb.st_size; 2936 else 2937 hdrsize = ATTR_MAX_HDR_SIZE; 2938 2939 buffer = calloc(1, hdrsize); 2940 if (buffer == NULL) { 2941 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize); 2942 error = -1; 2943 goto exit; 2944 } else 2945 endptr = (char*)buffer + hdrsize; 2946 2947 bytes = pread(s->src_fd, buffer, hdrsize, 0); 2948 2949 if (bytes < 0) 2950 { 2951 copyfile_debug(1, "pread returned: %zd", bytes); 2952 error = -1; 2953 goto exit; 2954 } 2955 if (bytes < hdrsize) 2956 { 2957 copyfile_debug(1, 2958 "pread couldn't read entire header: %d of %d", 2959 (int)bytes, (int)s->sb.st_size); 2960 error = -1; 2961 goto exit; 2962 } 2963 adhdr = (apple_double_header_t *)buffer; 2964 2965 /* 2966 * Check for Apple Double file. 2967 */ 2968 if ((size_t)bytes < sizeof(apple_double_header_t) - 2 || 2969 SWAP32(adhdr->magic) != ADH_MAGIC || 2970 SWAP32(adhdr->version) != ADH_VERSION || 2971 SWAP16(adhdr->numEntries) != 2 || 2972 SWAP32(adhdr->entries[0].type) != AD_FINDERINFO) 2973 { 2974 if (COPYFILE_VERBOSE & s->flags) 2975 copyfile_warn("Not a valid Apple Double header"); 2976 error = -1; 2977 goto exit; 2978 } 2979 swap_adhdr(adhdr); 2980 2981 /* 2982 * Remove any extended attributes on the target. 2983 */ 2984 2985 if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0) 2986 { 2987 char *namebuf, *name; 2988 2989 if ((namebuf = (char*) malloc(bytes)) == NULL) 2990 { 2991 s->err = ENOMEM; 2992 goto exit; 2993 } 2994 bytes = flistxattr(s->dst_fd, namebuf, bytes, 0); 2995 2996 if (bytes > 0) 2997 for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1) 2998 (void)fremovexattr(s->dst_fd, name, 0); 2999 3000 free(namebuf); 3001 } 3002 else if (bytes < 0) 3003 { 3004 if (errno != ENOTSUP && errno != EPERM) 3005 goto exit; 3006 } 3007 3008 /* 3009 * Extract the extended attributes. 3010 * 3011 * >>> WARNING <<< 3012 * This assumes that the data is already in memory (not 3013 * the case when there are lots of attributes or one of 3014 * the attributes is very large. 3015 */ 3016 if (adhdr->entries[0].length > FINDERINFOSIZE) 3017 { 3018 attr_header_t *attrhdr; 3019 attr_entry_t *entry; 3020 int count; 3021 int i; 3022 3023 if ((size_t)hdrsize < sizeof(attr_header_t)) { 3024 copyfile_warn("bad attribute header: %zu < %zu", hdrsize, sizeof(attr_header_t)); 3025 error = -1; 3026 goto exit; 3027 } 3028 3029 attrhdr = (attr_header_t *)buffer; 3030 swap_attrhdr(attrhdr); 3031 if (attrhdr->magic != ATTR_HDR_MAGIC) 3032 { 3033 if (COPYFILE_VERBOSE & s->flags) 3034 copyfile_warn("bad attribute header"); 3035 error = -1; 3036 goto exit; 3037 } 3038 count = attrhdr->num_attrs; 3039 entry = (attr_entry_t *)&attrhdr[1]; 3040 3041 for (i = 0; i < count; i++) 3042 { 3043 /* 3044 * First we do some simple sanity checking. 3045 * +) See if entry is within the buffer's range; 3046 * 3047 * +) Check the attribute name length; if it's longer than the 3048 * maximum, we truncate it down. (We could error out as well; 3049 * I'm not sure which is the better way to go here.) 3050 * 3051 * +) If, given the name length, it goes beyond the end of 3052 * the buffer, error out. 3053 * 3054 * +) If the last byte isn't a NUL, make it a NUL. (Since we 3055 * truncated the name length above, we truncate the name here.) 3056 * 3057 * +) If entry->offset is so large that it causes dataptr to 3058 * go beyond the end of the buffer -- or, worse, so large that 3059 * it wraps around! -- we error out. 3060 * 3061 * +) If entry->length would cause the entry to go beyond the 3062 * end of the buffer (or, worse, wrap around to before it), 3063 * *or* if the length is larger than the hdrsize, we error out. 3064 * (An explanation of that: what we're checking for there is 3065 * the small range of values such that offset+length would cause 3066 * it to go beyond endptr, and then wrap around past buffer. We 3067 * care about this because we are passing entry->length down to 3068 * fgetxattr() below, and an erroneously large value could cause 3069 * problems there. By making sure that it's less than hdrsize, 3070 * which has already been sanity-checked above, we're safe. 3071 * That may mean that the check against < buffer is unnecessary.) 3072 */ 3073 if ((void*)entry >= endptr || (void*)entry < buffer) { 3074 if (COPYFILE_VERBOSE & s->flags) 3075 copyfile_warn("Incomplete or corrupt attribute entry"); 3076 error = -1; 3077 s->err = EINVAL; 3078 goto exit; 3079 } 3080 3081 if (((char*)entry + sizeof(*entry)) > (char*)endptr) { 3082 if (COPYFILE_VERBOSE & s->flags) 3083 copyfile_warn("Incomplete or corrupt attribute entry"); 3084 error = -1; 3085 s->err = EINVAL; 3086 goto exit; 3087 } 3088 3089 /* 3090 * Endian swap the entry we're looking at. Previously 3091 * we did this swap as part of swap_attrhdr, but that 3092 * allowed a maliciously constructed file to overrun 3093 * our allocation. Instead do the swap after we've verified 3094 * the entry struct is within the buffer's range. 3095 */ 3096 swap_attrhdr_entry(entry); 3097 3098 if (entry->namelen < 2) { 3099 if (COPYFILE_VERBOSE & s->flags) 3100 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen); 3101 error = -1; 3102 s->err = EINVAL; 3103 goto exit; 3104 } 3105 3106 if (entry->namelen > XATTR_MAXNAMELEN + 1) { 3107 if (COPYFILE_VERBOSE & s->flags) 3108 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen); 3109 error = -1; 3110 s->err = EINVAL; 3111 goto exit; 3112 } 3113 3114 if ((void*)(entry->name + entry->namelen) > endptr) { 3115 if (COPYFILE_VERBOSE & s->flags) 3116 copyfile_warn("Incomplete or corrupt attribute entry"); 3117 error = -1; 3118 s->err = EINVAL; 3119 goto exit; 3120 } 3121 3122 /* Because namelen includes the NUL, we check one byte back */ 3123 if (entry->name[entry->namelen-1] != 0) { 3124 if (COPYFILE_VERBOSE & s->flags) 3125 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)"); 3126 error = -1; 3127 s->err = EINVAL; 3128 goto exit; 3129 } 3130 3131 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u", 3132 entry->name, entry->length, entry->offset); 3133 3134#if 0 3135 dataptr = (char *)attrhdr + entry->offset; 3136 3137 if (dataptr > endptr || dataptr < buffer) { 3138 copyfile_debug(1, "Entry %d overflows: offset = %u", i, entry->offset); 3139 error = -1; 3140 s->err = EINVAL; /* Invalid buffer */ 3141 goto exit; 3142 } 3143 3144 if (((char*)dataptr + entry->length) > (char*)endptr || 3145 (((char*)dataptr + entry->length) < (char*)buffer) || 3146 (entry->length > (size_t)hdrsize)) { 3147 if (COPYFILE_VERBOSE & s->flags) 3148 copyfile_warn("Incomplete or corrupt attribute entry"); 3149 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u", 3150 i, entry->offset, entry->length); 3151 error = -1; 3152 s->err = EINVAL; /* Invalid buffer */ 3153 goto exit; 3154 } 3155 3156#else 3157 dataptr = malloc(entry->length); 3158 if (dataptr == NULL) { 3159 copyfile_debug(1, "no memory for %u bytes\n", entry->length); 3160 error = -1; 3161 s->err = ENOMEM; 3162 goto exit; 3163 } 3164 if (pread(s->src_fd, dataptr, entry->length, entry->offset) != (ssize_t)entry->length) { 3165 copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry->length, entry->offset); 3166 error = -1; 3167 s->err = EINVAL; 3168 goto exit; 3169 } 3170#endif 3171 3172 if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0) 3173 { 3174 qtn_file_t tqinfo = NULL; 3175 3176 if (s->qinfo == NULL) 3177 { 3178 tqinfo = qtn_file_alloc(); 3179 if (tqinfo) 3180 { 3181 int x; 3182 if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0) 3183 { 3184 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x)); 3185 qtn_file_free(tqinfo); 3186 tqinfo = NULL; 3187 } 3188 } 3189 } 3190 else 3191 { 3192 tqinfo = s->qinfo; 3193 } 3194 if (tqinfo) 3195 { 3196 int x; 3197 x = qtn_file_apply_to_fd(tqinfo, s->dst_fd); 3198 if (x != 0) { 3199 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x)); 3200 if (s->statuscb) { 3201 int rv; 3202 s->xattr_name = (char*)XATTR_QUARANTINE_NAME; 3203 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3204 s->xattr_name = NULL; 3205 if (rv == COPYFILE_QUIT) { 3206 error = s->err = x < 0 ? ENOTSUP : errno; 3207 goto exit; 3208 } 3209 } else { 3210 error = s->err = x < 0 ? ENOTSUP : errno; 3211 goto exit; 3212 } 3213 } 3214 } 3215 if (tqinfo && !s->qinfo) 3216 { 3217 qtn_file_free(tqinfo); 3218 } 3219 } 3220 /* Look for ACL data */ 3221 else if (strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0) 3222 { 3223 acl_t acl; 3224 struct stat sb; 3225 int retry = 1; 3226 char *tcp = dataptr; 3227 3228 if (entry->length == 0) { 3229 /* Not sure how we got here, but we had one case 3230 * where it was 0. In a normal EA, we can have a 0-byte 3231 * payload. That means nothing in this case, so we'll 3232 * simply skip the EA. 3233 */ 3234 error = 0; 3235 goto acl_done; 3236 } 3237 /* 3238 * acl_from_text() requires a NUL-terminated string. The ACL EA, 3239 * however, may not be NUL-terminated. So in that case, we need to 3240 * copy it to a +1 sized buffer, to ensure it's got a terminated string. 3241 */ 3242 if (tcp[entry->length - 1] != 0) { 3243 char *tmpstr = malloc(entry->length + 1); 3244 if (tmpstr == NULL) { 3245 error = -1; 3246 goto exit; 3247 } 3248 strlcpy(tmpstr, tcp, entry->length + 1); 3249 acl = acl_from_text(tmpstr); 3250 free(tmpstr); 3251 } else { 3252 acl = acl_from_text(tcp); 3253 } 3254 3255 if (acl != NULL) 3256 { 3257 filesec_t fsec_tmp; 3258 3259 if ((fsec_tmp = filesec_init()) == NULL) 3260 error = -1; 3261 else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0) 3262 error = -1; 3263 else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0) 3264 error = -1; 3265 else { 3266 while (fchmodx_np(s->dst_fd, fsec_tmp) < 0) 3267 { 3268 if (errno == ENOTSUP) 3269 { 3270 if (retry && !copyfile_unset_acl(s)) 3271 { 3272 retry = 0; 3273 continue; 3274 } 3275 } 3276 copyfile_warn("setting security information"); 3277 error = -1; 3278 break; 3279 } 3280 } 3281 acl_free(acl); 3282 filesec_free(fsec_tmp); 3283 3284acl_done: 3285 if (error == -1) 3286 goto exit; 3287 } 3288 } 3289 /* And, finally, everything else */ 3290 else 3291 { 3292 if (s->copyIntent || 3293 xattr_preserve_for_intent((char*)entry->name, s->copyIntent) == 1) { 3294 if (s->statuscb) { 3295 int rv; 3296 s->xattr_name = strdup((char*)entry->name); 3297 s->totalCopied = 0; 3298 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3299 if (s->xattr_name) { 3300 free(s->xattr_name); 3301 s->xattr_name = NULL; 3302 } 3303 if (rv == COPYFILE_QUIT) { 3304 s->err = ECANCELED; 3305 error = -1; 3306 goto exit; 3307 } 3308 } 3309 if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) { 3310 if (COPYFILE_VERBOSE & s->flags) 3311 copyfile_warn("error %d setting attribute %s", errno, entry->name); 3312 if (s->statuscb) { 3313 int rv; 3314 3315 s->xattr_name = strdup((char*)entry->name); 3316 rv = (s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3317 if (s->xattr_name) { 3318 free(s->xattr_name); 3319 s->xattr_name = NULL; 3320 } 3321 if (rv == COPYFILE_QUIT) { 3322 error = -1; 3323 goto exit; 3324 } 3325 } else { 3326 error = -1; 3327 goto exit; 3328 } 3329 } else if (s->statuscb) { 3330 int rv; 3331 s->xattr_name = strdup((char*)entry->name); 3332 s->totalCopied = entry->length; 3333 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3334 if (s->xattr_name) { 3335 free(s->xattr_name); 3336 s->xattr_name = NULL; 3337 } 3338 if (rv == COPYFILE_QUIT) { 3339 error = -1; 3340 s->err = ECANCELED; 3341 goto exit; 3342 } 3343 } 3344 } 3345 } 3346 if (dataptr) { 3347 free(dataptr); 3348 dataptr = NULL; 3349 } 3350 entry = ATTR_NEXT(entry); 3351 } 3352 } 3353 3354 /* 3355 * Extract the Finder Info. 3356 */ 3357 if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) { 3358 error = -1; 3359 goto exit; 3360 } 3361 3362 if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0) 3363 { 3364 uint16_t *fFlags; 3365 uint8_t *newFinfo; 3366 enum { kFinderInvisibleMask = 1 << 14 }; 3367 3368 newFinfo = (u_int8_t*)buffer + adhdr->entries[0].offset; 3369 fFlags = (uint16_t*)&newFinfo[8]; 3370 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME); 3371 if (s->statuscb) { 3372 int rv; 3373 s->xattr_name = (char*)XATTR_FINDERINFO_NAME; 3374 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3375 s->xattr_name = NULL; 3376 if (rv == COPYFILE_QUIT) { 3377 error = -1; 3378 s->err = ECANCELED; 3379 goto exit; 3380 } else if (rv == COPYFILE_SKIP) { 3381 goto skip_fi; 3382 } 3383 } 3384 error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0); 3385 if (error) { 3386 if (s->statuscb) { 3387 int rv; 3388 s->xattr_name = (char *)XATTR_FINDERINFO_NAME; 3389 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3390 s->xattr_name = NULL; 3391 if (rv == COPYFILE_QUIT) { 3392 error = -1; 3393 s->err = ECANCELED; 3394 goto exit; 3395 } 3396 } 3397 goto exit; 3398 } else if (s->statuscb) { 3399 int rv; 3400 s->xattr_name = (char *)XATTR_FINDERINFO_NAME; 3401 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3402 s->xattr_name = NULL; 3403 if (rv == COPYFILE_QUIT) { 3404 error = -1; 3405 s->err = ECANCELED; 3406 goto exit; 3407 } 3408 } 3409 if (SWAP16(*fFlags) & kFinderInvisibleMask) 3410 s->internal_flags |= cfMakeFileInvisible; 3411 } 3412skip_fi: 3413 3414 /* 3415 * Extract the Resource Fork. 3416 */ 3417 if (adhdr->entries[1].type == AD_RESOURCE && 3418 adhdr->entries[1].length > 0) 3419 { 3420 void * rsrcforkdata = NULL; 3421 size_t length; 3422 off_t offset; 3423 struct stat sb; 3424 struct timeval tval[2]; 3425 3426 length = adhdr->entries[1].length; 3427 offset = adhdr->entries[1].offset; 3428 rsrcforkdata = malloc(length); 3429 3430 if (rsrcforkdata == NULL) { 3431 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata", 3432 length); 3433 error = -1; 3434 goto bad; 3435 } 3436 3437 if (fstat(s->dst_fd, &sb) < 0) 3438 { 3439 copyfile_debug(1, "couldn't stat destination file"); 3440 error = -1; 3441 goto bad; 3442 } 3443 3444 bytes = pread(s->src_fd, rsrcforkdata, length, offset); 3445 if (bytes < (ssize_t)length) 3446 { 3447 if (bytes == -1) 3448 { 3449 copyfile_debug(1, "couldn't read resource fork"); 3450 } 3451 else 3452 { 3453 copyfile_debug(1, 3454 "couldn't read resource fork (only read %d bytes of %d)", 3455 (int)bytes, (int)length); 3456 } 3457 error = -1; 3458 goto bad; 3459 } 3460 if (s->statuscb) { 3461 int rv; 3462 s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME; 3463 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3464 s->xattr_name = NULL; 3465 if (rv == COPYFILE_QUIT) { 3466 error = -1; 3467 s->err = ECANCELED; 3468 if (rsrcforkdata) 3469 free(rsrcforkdata); 3470 goto exit; 3471 } else if (rv == COPYFILE_SKIP) { 3472 goto bad; 3473 } 3474 } 3475 error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0); 3476 if (error) 3477 { 3478 /* 3479 * For filesystems that do not natively support named attributes, 3480 * the kernel creates an AppleDouble file that -- for compatabilty 3481 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t 3482 * structure that says there are no resources. So, if fsetxattr has 3483 * failed, and the resource fork is that empty structure, *and* the 3484 * target file is a directory, then we do nothing with it. 3485 */ 3486 if ((bytes == sizeof(rsrcfork_header_t)) && 3487 ((sb.st_mode & S_IFMT) == S_IFDIR) && 3488 (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) { 3489 copyfile_debug(2, "not setting empty resource fork on directory"); 3490 error = errno = 0; 3491 goto bad; 3492 } 3493 if (s->statuscb) { 3494 int rv; 3495 s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME; 3496 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3497 s->xattr_name = NULL; 3498 if (rv == COPYFILE_CONTINUE) { 3499 error = errno = 0; 3500 goto bad; 3501 } 3502 } 3503 copyfile_debug(1, "error %d setting resource fork attribute", error); 3504 error = -1; 3505 goto bad; 3506 } else if (s->statuscb) { 3507 int rv; 3508 s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME; 3509 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3510 s->xattr_name = NULL; 3511 if (rv == COPYFILE_QUIT) { 3512 error = -1; 3513 s->err = ECANCELED; 3514 if (rsrcforkdata) 3515 free(rsrcforkdata); 3516 goto exit; 3517 } 3518 } 3519 copyfile_debug(3, "extracting \"%s\" (%d bytes)", 3520 XATTR_RESOURCEFORK_NAME, (int)length); 3521 3522 if (!(s->flags & COPYFILE_STAT)) 3523 { 3524 tval[0].tv_sec = sb.st_atime; 3525 tval[1].tv_sec = sb.st_mtime; 3526 tval[0].tv_usec = tval[1].tv_usec = 0; 3527 3528 if (futimes(s->dst_fd, tval)) 3529 copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)"); 3530 } 3531bad: 3532 if (rsrcforkdata) 3533 free(rsrcforkdata); 3534 } 3535 3536 if (COPYFILE_STAT & s->flags) 3537 { 3538 error = copyfile_stat(s); 3539 } 3540exit: 3541 if (buffer) free(buffer); 3542 if (dataptr) free(dataptr); 3543 return error; 3544} 3545 3546static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len) 3547{ 3548 int ret = 0; 3549 char qbuf[QTN_SERIALIZED_DATA_MAX]; 3550 size_t qlen = sizeof(qbuf); 3551 3552 if (s->qinfo == NULL) 3553 { 3554 ret = -1; 3555 goto done; 3556 } 3557 3558 if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0) 3559 { 3560 ret = -1; 3561 goto done; 3562 } 3563 3564 *buf = malloc(qlen); 3565 if (*buf) 3566 { 3567 memcpy(*buf, qbuf, qlen); 3568 *len = qlen; 3569 } 3570done: 3571 return ret; 3572} 3573 3574static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len) 3575{ 3576 int ret = 0; 3577 acl_t acl = NULL; 3578 char *acl_text; 3579 3580 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0) 3581 { 3582 if (errno != ENOENT) 3583 { 3584 ret = -1; 3585 if (COPYFILE_VERBOSE & s->flags) 3586 copyfile_warn("getting acl"); 3587 } 3588 *len = 0; 3589 goto exit; 3590 } 3591 3592 if ((acl_text = acl_to_text(acl, len)) != NULL) 3593 { 3594 /* 3595 * acl_to_text() doesn't include the NUL at the endo 3596 * in it's count (*len). It does, however, promise to 3597 * return a valid C string, so we need to up the count 3598 * by 1. 3599 */ 3600 *len = *len + 1; 3601 *buf = malloc(*len); 3602 if (*buf) 3603 memcpy(*buf, acl_text, *len); 3604 else 3605 *len = 0; 3606 acl_free(acl_text); 3607 } 3608 copyfile_debug(2, "copied acl (%ld) %p", *len, *buf); 3609exit: 3610 if (acl) 3611 acl_free(acl); 3612 return ret; 3613} 3614 3615static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr) 3616{ 3617 ssize_t datasize; 3618 char *databuf = NULL; 3619 int ret = 0; 3620 3621/* 3622 * XXX 3623 * do COPYFILE_COPY_XATTR here; no need to 3624 * the work if we want to skip. 3625 */ 3626 3627 if (s->statuscb) 3628 { 3629 int rv; 3630 3631 s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME; 3632 3633 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3634 s->xattr_name = NULL; 3635 if (rv == COPYFILE_SKIP) { 3636 ret = 0; 3637 goto done; 3638 } 3639 if (rv == COPYFILE_QUIT) { 3640 ret = -1; 3641 s->err = ECANCELED; 3642 goto done; 3643 } 3644 } 3645 /* Get the resource fork size */ 3646 if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0) 3647 { 3648 if (COPYFILE_VERBOSE & s->flags) 3649 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno); 3650 return -1; 3651 } 3652 3653 if (datasize > INT_MAX) { 3654 s->err = EINVAL; 3655 ret = -1; 3656 goto done; 3657 } 3658 3659 if (s->statuscb) { 3660 int rv; 3661 s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME; 3662 3663 s->totalCopied = 0; 3664 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 3665 s->xattr_name = NULL; 3666 if (rv == COPYFILE_QUIT) { 3667 s->err = ECANCELED; 3668 ret = -1; 3669 goto done; 3670 } 3671 } 3672 if ((databuf = malloc(datasize)) == NULL) 3673 { 3674 copyfile_warn("malloc"); 3675 ret = -1; 3676 goto done; 3677 } 3678 3679 if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize) 3680 { 3681 if (COPYFILE_VERBOSE & s->flags) 3682 copyfile_warn("couldn't read entire resource fork"); 3683 ret = -1; 3684 goto done; 3685 } 3686 3687 /* Write the resource fork to disk. */ 3688 if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize) 3689 { 3690 if (COPYFILE_VERBOSE & s->flags) 3691 copyfile_warn("couldn't write resource fork"); 3692 } 3693 if (s->statuscb) 3694 { 3695 int rv; 3696 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3697 if (rv == COPYFILE_QUIT) { 3698 ret = -1; 3699 goto done; 3700 } 3701 } 3702 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x", 3703 datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset); 3704 filehdr->appledouble.entries[1].length = (u_int32_t)datasize; 3705 3706done: 3707 if (ret == -1 && s->statuscb) 3708 { 3709 int rv; 3710 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3711 if (rv == COPYFILE_CONTINUE) 3712 ret = 0; 3713 } 3714 if (s->xattr_name) { 3715 s->xattr_name = NULL; 3716 } 3717 if (databuf) 3718 free(databuf); 3719 3720/* 3721 * XXX 3722 * Do status callback here 3723 * If ret == -1, then error callback 3724 */ 3725 return ret; 3726} 3727 3728/* 3729 * The opposite of copyfile_unpack(), obviously. 3730 */ 3731static int copyfile_pack(copyfile_state_t s) 3732{ 3733 char *attrnamebuf = NULL, *endnamebuf; 3734 void *databuf = NULL; 3735 attr_header_t *filehdr, *endfilehdr; 3736 attr_entry_t *entry; 3737 ssize_t listsize = 0; 3738 char *nameptr; 3739 size_t namelen; 3740 size_t entrylen; 3741 ssize_t datasize; 3742 size_t offset = 0; 3743 int hasrsrcfork = 0; 3744 int error = 0; 3745 int seenq = 0; // Have we seen any quarantine info already? 3746 3747 filehdr = (attr_header_t *) calloc(1, ATTR_MAX_HDR_SIZE); 3748 3749 if (filehdr == NULL) { 3750 error = -1; 3751 goto exit; 3752 } else { 3753 endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_HDR_SIZE); 3754 } 3755 3756 attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE); 3757 if (attrnamebuf == NULL) { 3758 error = -1; 3759 goto exit; 3760 } else { 3761 endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE; 3762 } 3763 3764 /* 3765 * Fill in the Apple Double Header defaults. 3766 */ 3767 filehdr->appledouble.magic = ADH_MAGIC; 3768 filehdr->appledouble.version = ADH_VERSION; 3769 filehdr->appledouble.numEntries = 2; 3770 filehdr->appledouble.entries[0].type = AD_FINDERINFO; 3771 filehdr->appledouble.entries[0].offset = (u_int32_t)offsetof(apple_double_header_t, finfo); 3772 filehdr->appledouble.entries[0].length = FINDERINFOSIZE; 3773 filehdr->appledouble.entries[1].type = AD_RESOURCE; 3774 filehdr->appledouble.entries[1].offset = (u_int32_t)offsetof(apple_double_header_t, pad); 3775 filehdr->appledouble.entries[1].length = 0; 3776 bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler)); 3777 3778 /* 3779 * Fill in the initial Attribute Header. 3780 */ 3781 filehdr->magic = ATTR_HDR_MAGIC; 3782 filehdr->debug_tag = 0; 3783 filehdr->data_start = (u_int32_t)sizeof(attr_header_t); 3784 3785 /* 3786 * Collect the attribute names. 3787 */ 3788 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t)); 3789 3790 /* 3791 * Test if there are acls to copy 3792 */ 3793 if (COPYFILE_ACL & s->flags) 3794 { 3795 acl_t temp_acl = NULL; 3796 if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0) 3797 { 3798 copyfile_debug(2, "no acl entries found (errno = %d)", errno); 3799 } else 3800 { 3801 offset = strlen(XATTR_SECURITY_NAME) + 1; 3802 strcpy(attrnamebuf, XATTR_SECURITY_NAME); 3803 endnamebuf = attrnamebuf + offset; 3804 } 3805 if (temp_acl) 3806 acl_free(temp_acl); 3807 } 3808 3809 if (COPYFILE_XATTR & s->flags) 3810 { 3811 ssize_t left = ATTR_MAX_HDR_SIZE - offset; 3812 if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0) 3813 { 3814 copyfile_debug(2, "no extended attributes found (%d)", errno); 3815 } 3816 if (listsize > left) 3817 { 3818 copyfile_debug(1, "extended attribute list too long"); 3819 listsize = left; 3820 } 3821 3822 endnamebuf = attrnamebuf + offset + (listsize > 0 ? listsize : 0); 3823 if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) { 3824 error = -1; 3825 goto exit; 3826 } 3827 3828 if (listsize > 0) 3829 sort_xattrname_list(attrnamebuf, endnamebuf - attrnamebuf); 3830 3831 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen) 3832 { 3833 namelen = strlen(nameptr) + 1; 3834 /* Skip over FinderInfo or Resource Fork names */ 3835 if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 || 3836 strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) { 3837 continue; 3838 } 3839 if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) { 3840 seenq = 1; 3841 } 3842 3843 /* The system should prevent this from happening, but... */ 3844 if (namelen > XATTR_MAXNAMELEN + 1) { 3845 namelen = XATTR_MAXNAMELEN + 1; 3846 } 3847 if (s->copyIntent && 3848 xattr_preserve_for_intent(nameptr, s->copyIntent) == 0) { 3849 // Skip it 3850 size_t amt = endnamebuf - (nameptr + namelen); 3851 memmove(nameptr, nameptr + namelen, amt); 3852 endnamebuf -= namelen; 3853 /* Set namelen to 0 so continue doesn't miss names */ 3854 namelen = 0; 3855 continue; 3856 } 3857 3858 if (s->statuscb) { 3859 int rv; 3860 char eaname[namelen]; 3861 bcopy(nameptr, eaname, namelen); 3862 eaname[namelen - 1] = 0; // Just to be sure! 3863 s->xattr_name = eaname; 3864 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3865 s->xattr_name = NULL; 3866 if (rv == COPYFILE_QUIT) { 3867 error = -1; 3868 s->err = ECANCELED; 3869 goto exit; 3870 } else if (rv == COPYFILE_SKIP) { 3871 size_t amt = endnamebuf - (nameptr + namelen); 3872 memmove(nameptr, nameptr + namelen, amt); 3873 endnamebuf -= namelen; 3874 /* Set namelen to 0 so continue doesn't miss names */ 3875 namelen = 0; 3876 continue; 3877 } 3878 } 3879 entry->namelen = namelen; 3880 entry->flags = 0; 3881 if (nameptr + namelen > endnamebuf) { 3882 error = -1; 3883 goto exit; 3884 } 3885 3886 bcopy(nameptr, &entry->name[0], namelen); 3887 copyfile_debug(2, "copied name [%s]", entry->name); 3888 3889 entrylen = ATTR_ENTRY_LENGTH(namelen); 3890 entry = (attr_entry_t *)(((char *)entry) + entrylen); 3891 3892 if ((void*)entry >= (void*)endfilehdr) { 3893 error = -1; 3894 goto exit; 3895 } 3896 3897 /* Update the attributes header. */ 3898 filehdr->num_attrs++; 3899 filehdr->data_start += (u_int32_t)entrylen; 3900 } 3901 } 3902 3903 /* 3904 * If we have any quarantine data, we always pack it. 3905 * But if we've already got it in the EA list, don't put it in again. 3906 */ 3907 if (s->qinfo && !seenq) 3908 { 3909 ssize_t left = ATTR_MAX_HDR_SIZE - offset; 3910 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */ 3911 offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1; 3912 } 3913 3914 seenq = 0; 3915 /* 3916 * Collect the attribute data. 3917 */ 3918 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t)); 3919 3920 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen + 1) 3921 { 3922 namelen = strlen(nameptr); 3923 3924 if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0) 3925 copyfile_pack_acl(s, &databuf, &datasize); 3926 else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) 3927 { 3928 copyfile_pack_quarantine(s, &databuf, &datasize); 3929 } 3930 /* Check for Finder Info. */ 3931 else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0) 3932 { 3933 if (s->statuscb) 3934 { 3935 int rv; 3936 s->xattr_name = (char*)XATTR_FINDERINFO_NAME; 3937 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx); 3938 s->xattr_name = NULL; 3939 if (rv == COPYFILE_QUIT) 3940 { 3941 s->xattr_name = NULL; 3942 s->err = ECANCELED; 3943 error = -1; 3944 goto exit; 3945 } 3946 else if (rv == COPYFILE_SKIP) 3947 { 3948 s->xattr_name = NULL; 3949 continue; 3950 } 3951 s->totalCopied = 0; 3952 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 3953 s->xattr_name = NULL; 3954 if (rv == COPYFILE_QUIT) 3955 { 3956 s->err = ECANCELED; 3957 error = -1; 3958 goto exit; 3959 } 3960 } 3961 datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0); 3962 if (datasize < 0) 3963 { 3964 if (s->statuscb) { 3965 int rv; 3966 s->xattr_name = strdup(nameptr); 3967 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 3968 if (s->xattr_name) { 3969 free(s->xattr_name); 3970 s->xattr_name = NULL; 3971 } 3972 if (rv == COPYFILE_QUIT) { 3973 error = -1; 3974 goto exit; 3975 } 3976 } 3977 if (COPYFILE_VERBOSE & s->flags) 3978 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno); 3979 } else if (datasize != 32) 3980 { 3981 if (COPYFILE_VERBOSE & s->flags) 3982 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr); 3983 } else 3984 { 3985 if (COPYFILE_VERBOSE & s->flags) 3986 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x", 3987 XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset); 3988 if (s->statuscb) { 3989 int rv; 3990 s->xattr_name = strdup(nameptr); 3991 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 3992 if (s->xattr_name) { 3993 free(s->xattr_name); 3994 s->xattr_name = NULL; 3995 } 3996 if (rv == COPYFILE_QUIT) { 3997 error = -1; 3998 goto exit; 3999 } 4000 } 4001 } 4002 continue; /* finder info doesn't have an attribute entry */ 4003 } 4004 /* Check for Resource Fork. */ 4005 else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) 4006 { 4007 hasrsrcfork = 1; 4008 continue; 4009 } else 4010 { 4011 /* Just a normal attribute. */ 4012 if (s->statuscb) 4013 { 4014 int rv; 4015 s->xattr_name = strdup(nameptr); 4016 s->totalCopied = 0; 4017 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx); 4018 if (s->xattr_name) { 4019 free(s->xattr_name); 4020 s->xattr_name = NULL; 4021 } 4022 /* 4023 * Due to the nature of the packed file, we can't skip at this point. 4024 */ 4025 if (rv == COPYFILE_QUIT) 4026 { 4027 s->err = ECANCELED; 4028 error = -1; 4029 goto exit; 4030 } 4031 } 4032 datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0); 4033 if (datasize == 0) 4034 goto next; 4035 if (datasize < 0) 4036 { 4037 if (COPYFILE_VERBOSE & s->flags) 4038 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno); 4039 if (s->statuscb) 4040 { 4041 int rv; 4042 s->xattr_name = strdup(nameptr); 4043 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx); 4044 if (s->xattr_name) { 4045 free(s->xattr_name); 4046 s->xattr_name = NULL; 4047 } 4048 if (rv == COPYFILE_QUIT) 4049 { 4050 s->err = ECANCELED; 4051 error = -1; 4052 goto exit; 4053 } 4054 } 4055 goto next; 4056 } 4057 if (datasize > XATTR_MAXATTRLEN) 4058 { 4059 if (COPYFILE_VERBOSE & s->flags) 4060 copyfile_warn("skipping attr \"%s\" (too big)", nameptr); 4061 goto next; 4062 } 4063 databuf = malloc(datasize); 4064 if (databuf == NULL) { 4065 error = -1; 4066 continue; 4067 } 4068 datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0); 4069 if (s->statuscb) { 4070 int rv; 4071 s->xattr_name = strdup(nameptr); 4072 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx); 4073 if (s->xattr_name) { 4074 free(s->xattr_name); 4075 s->xattr_name = NULL; 4076 } 4077 if (rv == COPYFILE_QUIT) { 4078 s->err = ECANCELED; 4079 error = -1; 4080 goto exit; 4081 } 4082 } 4083 } 4084 4085 entry->length = (u_int32_t)datasize; 4086 entry->offset = filehdr->data_start + filehdr->data_length; 4087 4088 filehdr->data_length += (u_int32_t)datasize; 4089#if 0 4090 /* 4091 * >>> WARNING <<< 4092 * This assumes that the data is fits in memory (not 4093 * the case when there are lots of attributes or one of 4094 * the attributes is very large. 4095 */ 4096 if (entry->offset > ATTR_MAX_SIZE || 4097 (entry->offset + datasize > ATTR_MAX_SIZE)) { 4098 error = 1; 4099 } else { 4100 bcopy(databuf, (char*)filehdr + entry->offset, datasize); 4101 } 4102#else 4103 if (pwrite(s->dst_fd, databuf, datasize, entry->offset) != datasize) { 4104 error = 1; 4105 } 4106#endif 4107 free(databuf); 4108 4109 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset); 4110next: 4111 /* bump to next entry */ 4112 entrylen = ATTR_ENTRY_LENGTH(entry->namelen); 4113 entry = (attr_entry_t *)((char *)entry + entrylen); 4114 } 4115 4116 /* Now we know where the resource fork data starts. */ 4117 filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length); 4118 4119 /* We also know the size of the "Finder Info entry. */ 4120 filehdr->appledouble.entries[0].length = 4121 filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset; 4122 4123 filehdr->total_size = filehdr->appledouble.entries[1].offset; 4124 4125 /* Copy Resource Fork. */ 4126 if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr))) 4127 goto exit; 4128 4129 /* Write the header to disk. */ 4130 datasize = filehdr->data_start; 4131 4132 swap_adhdr(&filehdr->appledouble); 4133 swap_attrhdr(filehdr); 4134 swap_attrhdr_entries(filehdr); 4135 4136 if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize) 4137 { 4138 if (COPYFILE_VERBOSE & s->flags) 4139 copyfile_warn("couldn't write file header"); 4140 error = -1; 4141 goto exit; 4142 } 4143exit: 4144 if (filehdr) free(filehdr); 4145 if (attrnamebuf) free(attrnamebuf); 4146 4147 if (error) 4148 return error; 4149 else 4150 return copyfile_stat(s); 4151} 4152