2 * Copyright (c) 2004-2020 Apple, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
26 #include <sys/types.h>
35 #include <sys/errno.h>
38 #include <sys/xattr.h>
40 #include <sys/syscall.h>
41 #include <sys/param.h>
42 #include <sys/mount.h>
44 #include <libkern/OSByteOrder.h>
45 #include <membership.h>
48 #include <sys/clonefile.h>
49 #include <System/sys/content_protection.h>
51 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
52 # include <Kernel/sys/decmpfs.h>
55 #include <TargetConditionals.h>
57 #include <quarantine.h>
59 #define XATTR_QUARANTINE_NAME qtn_xattr_name
60 #else /* TARGET_OS_IPHONE */
61 #define qtn_file_t void *
62 #define QTN_SERIALIZED_DATA_MAX 0
63 static void * qtn_file_alloc(void) { return NULL
; }
64 static int qtn_file_init_with_fd(__unused
void *x
, __unused
int y
) { return -1; }
65 static int qtn_file_init_with_path(__unused
void *x
, __unused
const char *path
) { return -1; }
66 static int qtn_file_init_with_data(__unused
void *x
, __unused
const void *data
, __unused
size_t len
) { return -1; }
67 static void qtn_file_free(__unused
void *x
) { return; }
68 static int qtn_file_apply_to_fd(__unused
void *x
, __unused
int y
) { return 0; }
69 static char *qtn_error(__unused
int x
) { return NULL
; }
70 static int qtn_file_to_data(__unused
void *x
, __unused
char *y
, __unused
size_t *z
) { return -1; }
71 static void *qtn_file_clone(__unused
void *x
) { return NULL
; }
72 static uint32_t qtn_file_get_flags(__unused
void *x
) { return 0; }
73 static int qtn_file_set_flags(__unused
void *x
, __unused
uint32_t flags
) { return 0; }
74 #define XATTR_QUARANTINE_NAME "figgledidiggledy"
75 #define QTN_FLAG_DO_NOT_TRANSLOCATE 0
76 #endif /* TARGET_OS_IPHONE */
79 #include "copyfile_private.h"
80 #include "xattr_flags.h"
82 #define XATTR_ROOT_INSTALLED_NAME "com.apple.root.installed"
84 enum cfInternalFlags
{
85 cfDelayAce
= 1 << 0, /* set if ACE shouldn't be set until post-order traversal */
86 cfMakeFileInvisible
= 1 << 1, /* set if kFinderInvisibleMask is on src */
87 cfSawDecmpEA
= 1 << 2, /* set if we've seen a com.apple.decmpfs xattr */
88 cfSrcProtSupportValid
= 1 << 3, /* set if cfSrcSupportsCProtect is valid */
89 cfSrcSupportsCProtect
= 1 << 4, /* set if src supports MNT_CPROTECT */
90 cfDstProtSupportValid
= 1 << 5, /* set if cfDstSupportsCProtect is valid */
91 cfDstSupportsCProtect
= 1 << 6, /* set if dst supports MNT_CPROTECT */
94 #define COPYFILE_MNT_CPROTECT_MASK (cfSrcProtSupportValid | cfSrcSupportsCProtect | cfDstProtSupportValid | cfDstSupportsCProtect)
97 * The state structure keeps track of
98 * the source filename, the destination filename, their
99 * associated file-descriptors, the stat information for the
100 * source file, the security information for the source file,
101 * the flags passed in for the copy, a pointer to place statistics
102 * (not currently implemented), debug flags, and a pointer to callbacks
103 * (not currently implemented).
105 struct _copyfile_state
113 copyfile_flags_t flags
;
114 unsigned int internal_flags
;
117 copyfile_callback_t statuscb
;
119 qtn_file_t qinfo
; /* Quarantine information -- probably NULL */
120 filesec_t original_fsec
;
121 filesec_t permissive_fsec
;
125 xattr_operation_intent_t copyIntent
;
129 #define GET_PROT_CLASS(fd) fcntl((fd), F_GETPROTECTIONCLASS)
130 #define SET_PROT_CLASS(fd, prot_class) fcntl((fd), F_SETPROTECTIONCLASS, (prot_class))
134 #define _ACL_ENTRY_MAGIC 0xac1ac101
136 guid_t ae_applicable
;
143 struct acl_entry *__t = (struct acl_entry*)(ace); \
144 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
149 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
150 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
154 acl_compare_permset_np(acl_permset_t p1
, acl_permset_t p2
)
156 struct pm
{ u_int32_t ap_perms
; } *ps1
, *ps2
;
157 ps1
= (struct pm
*) p1
;
158 ps2
= (struct pm
*) p2
;
160 return ((ps1
->ap_perms
== ps2
->ap_perms
) ? 1 : 0);
165 doesdecmpfs(int fd
) {
166 #ifdef DECMPFS_XATTR_NAME
168 struct attrlist attrs
;
169 char volroot
[MAXPATHLEN
+ 1];
173 vol_capabilities_attr_t volAttrs
;
176 (void)fstatfs(fd
, &sfs
);
177 strlcpy(volroot
, sfs
.f_mntonname
, sizeof(volroot
));
179 memset(&attrs
, 0, sizeof(attrs
));
180 attrs
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
181 attrs
.volattr
= ATTR_VOL_CAPABILITIES
;
183 rv
= getattrlist(volroot
, &attrs
, &volattrs
, sizeof(volattrs
), 0);
186 (volattrs
.volAttrs
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
) &&
187 (volattrs
.volAttrs
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
)) {
195 does_copy_protection(int fd
)
199 if (fstatfs(fd
, &sfs
) == -1)
202 return ((sfs
.f_flags
& MNT_CPROTECT
) == MNT_CPROTECT
);
206 path_does_copy_protection(const char *path
)
210 if (statfs(path
, &sfs
) == -1) {
211 char parent_path
[MAXPATHLEN
];
216 // If the path doesn't exist,
217 // try to get its parent path and re-attempt the statfs().
218 if (dirname_r(path
, parent_path
) == NULL
)
221 if (statfs(parent_path
, &sfs
) == -1)
225 return ((sfs
.f_flags
& MNT_CPROTECT
) == MNT_CPROTECT
);
229 do_copy_protected_open(const char *path
, int flags
, int class, int dpflags
, int mode
)
231 // The passed-in protection class is meaningful, so use open_dprotected_np().
232 if (path_does_copy_protection(path
)) {
233 return open_dprotected_np(path
, flags
, class, dpflags
, mode
);
236 // Fall-back to regular open().
237 return open(path
, flags
, mode
);
241 sort_xattrname_list(void *start
, size_t length
)
248 /* If it's not a proper C string at the end, don't do anything */
249 if (((char*)start
)[length
] != 0)
252 * In order to sort the list of names, we need to
253 * make a list of pointers to strings. To do that,
254 * we need to run through the buffer, and find the
255 * beginnings of strings.
257 nel
= 10; // Most files don't have many EAs
258 ptrs
= (char**)calloc(nel
, sizeof(char*));
265 char *curPtr
= start
;
266 while (curPtr
< (char*)start
+ length
) {
267 printf("%s\n", curPtr
);
268 curPtr
+= strlen(curPtr
) + 1;
273 tmp
= ptrs
[indx
++] = (char*)start
;
275 while ((tmp
= memchr(tmp
, 0, ((char*)start
+ length
) - tmp
))) {
278 ptrs
= realloc(ptrs
, sizeof(char**) * nel
);
282 ptrs
[indx
++] = ++tmp
;
285 printf("Unsorted:\n");
286 for (nel
= 0; nel
< indx
-1; nel
++) {
287 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
290 qsort_b(ptrs
, indx
-1, sizeof(char*), ^(const void *left
, const void *right
) {
292 char *lstr
= *(char**)left
, *rstr
= *(char**)right
;
293 rv
= strcmp(lstr
, rstr
);
298 for (nel
= 0; nel
< indx
-1; nel
++) {
299 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
303 * Now that it's sorted, we need to make a copy, so we can
304 * move the strings around into the new order. Then we
305 * copy that on top of the old buffer, and we're done.
307 char *copy
= malloc(length
);
312 for (i
= 0; i
< indx
-1; i
++) {
313 size_t len
= strlen(ptrs
[i
]);
314 memcpy(curPtr
, ptrs
[i
], len
+1);
317 memcpy(start
, copy
, length
);
328 * Internally, the process is broken into a series of
331 static int copyfile_open (copyfile_state_t
);
332 static int copyfile_close (copyfile_state_t
);
333 static int copyfile_data (copyfile_state_t
);
334 static int copyfile_stat (copyfile_state_t
);
335 static int copyfile_security (copyfile_state_t
);
336 static int copyfile_xattr (copyfile_state_t
);
337 static int copyfile_pack (copyfile_state_t
);
338 static int copyfile_unpack (copyfile_state_t
);
340 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
341 static filesec_t
copyfile_fix_perms(copyfile_state_t
, filesec_t
*);
342 static int copyfile_preamble(copyfile_state_t
*s
, copyfile_flags_t flags
);
343 static int copyfile_internal(copyfile_state_t state
, copyfile_flags_t flags
);
344 static int copyfile_unset_posix_fsec(filesec_t
);
345 static int copyfile_quarantine(copyfile_state_t
);
347 #define COPYFILE_DEBUG (1<<31)
348 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
350 // These macros preserve the value of errno.
351 #ifndef _COPYFILE_TEST
352 # define copyfile_warn(str, ...) \
354 errno_t _errsv = errno; \
355 syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__); \
358 # define copyfile_debug(d, str, ...) \
360 if (s && (d <= s->debug)) {\
361 errno_t _errsv = errno; \
362 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
367 #define copyfile_warn(str, ...) \
369 errno_t _errsv = errno; \
370 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : ""); \
373 # define copyfile_debug(d, str, ...) \
375 if (s && (d <= s->debug)) {\
376 errno_t _errsv = errno; \
377 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
383 static int copyfile_quarantine(copyfile_state_t s
)
386 if (s
->qinfo
== NULL
)
389 s
->qinfo
= qtn_file_alloc();
390 if (s
->qinfo
== NULL
)
395 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
397 qtn_file_free(s
->qinfo
);
408 add_uberace(acl_t
*acl
)
411 acl_permset_t permset
;
414 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
418 * First, we create an entry, and give it the special name
419 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
420 * After that, we clear out all the permissions in it, and
421 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
422 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
423 * the functionality, and put this into the ACL.
425 if (acl_create_entry_np(acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
427 if (acl_get_permset(entry
, &permset
) == -1) {
428 copyfile_warn("acl_get_permset");
431 if (acl_clear_perms(permset
) == -1) {
432 copyfile_warn("acl_clear_permset");
435 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1) {
436 copyfile_warn("add ACL_WRITE_DATA");
439 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1) {
440 copyfile_warn("add ACL_WRITE_ATTRIBUTES");
443 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1) {
444 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES");
447 if (acl_add_perm(permset
, ACL_APPEND_DATA
) == -1) {
448 copyfile_warn("add ACL_APPEND_DATA");
451 if (acl_add_perm(permset
, ACL_WRITE_SECURITY
) == -1) {
452 copyfile_warn("add ACL_WRITE_SECURITY");
455 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1) {
456 copyfile_warn("set ACL_EXTENDED_ALLOW");
460 if(acl_set_permset(entry
, permset
) == -1) {
461 copyfile_warn("acl_set_permset");
464 if(acl_set_qualifier(entry
, qual
) == -1) {
465 copyfile_warn("acl_set_qualifier");
475 is_uberace(acl_entry_t ace
)
478 acl_permset_t perms
, tperms
;
485 // Who am I, and who is the ACE for?
486 mbr_uid_to_uuid(geteuid(), myuuid
);
487 qual
= (guid_t
*)acl_get_qualifier(ace
);
489 // Need to create a temporary acl, so I can get the uberace template.
495 if (acl_get_entry(tacl
, ACL_FIRST_ENTRY
, &tentry
) != 0) {
498 acl_get_permset(tentry
, &tperms
);
501 acl_get_tag_type(ace
, &tag
);
502 acl_get_permset(ace
, &perms
);
504 if (tag
== ACL_EXTENDED_ALLOW
&&
505 (memcmp(qual
, myuuid
, sizeof(myuuid
)) == 0) &&
506 acl_compare_permset_np(tperms
, perms
))
521 remove_uberace(int fd
, struct stat
*sbuf
)
523 filesec_t fsec
= NULL
;
528 fsec
= filesec_init();
533 if (fstatx_np(fd
, &sb
, fsec
) != 0) {
534 if (errno
== ENOTSUP
)
539 if (filesec_get_property(fsec
, FILESEC_ACL
, &acl
) != 0) {
543 if (acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
) == 0) {
544 if (is_uberace(entry
))
546 mode_t m
= sbuf
->st_mode
& ~S_IFMT
;
548 if (acl_delete_entry(acl
, entry
) != 0 ||
549 filesec_set_property(fsec
, FILESEC_ACL
, &acl
) != 0 ||
550 filesec_set_property(fsec
, FILESEC_MODE
, &m
) != 0 ||
551 fchmodx_np(fd
, fsec
) != 0)
564 fchmod(fd
, sbuf
->st_mode
& ~S_IFMT
);
569 reset_security(copyfile_state_t s
)
571 /* If we haven't reset the file security information
572 * (COPYFILE_SECURITY is not set in flags)
573 * restore back the permissions the file had originally
575 * One of the reasons this seems so complicated is that
576 * it is partially at odds with copyfile_security().
578 * Simplisticly, we are simply trying to make sure we
579 * only copy what was requested, and that we don't stomp
580 * on what wasn't requested.
583 #ifdef COPYFILE_RECURSIVE
584 if (s
->dst_fd
> -1) {
587 if (s
->src_fd
> -1 && (s
->flags
& COPYFILE_STAT
))
588 fstat(s
->src_fd
, &sbuf
);
590 fstat(s
->dst_fd
, &sbuf
);
592 if (!(s
->internal_flags
& cfDelayAce
))
593 remove_uberace(s
->dst_fd
, &sbuf
);
596 if (s
->permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
597 if (s
->flags
& COPYFILE_ACL
) {
598 /* Just need to reset the BSD information -- mode, owner, group */
599 (void)fchown(s
->dst_fd
, s
->dst_sb
.st_uid
, s
->dst_sb
.st_gid
);
600 (void)fchmod(s
->dst_fd
, s
->dst_sb
.st_mode
);
603 * flags is either COPYFILE_STAT, or neither; if it's
604 * neither, then we restore both ACL and POSIX permissions;
605 * if it's STAT, however, then we only want to restore the
606 * ACL (which may be empty). We do that by removing the
607 * POSIX information from the filesec object.
609 if (s
->flags
& COPYFILE_STAT
) {
610 copyfile_unset_posix_fsec(s
->original_fsec
);
612 if (fchmodx_np(s
->dst_fd
, s
->original_fsec
) < 0 && errno
!= ENOTSUP
)
613 copyfile_warn("restoring security information");
617 if (s
->permissive_fsec
) {
618 filesec_free(s
->permissive_fsec
);
619 s
->permissive_fsec
= NULL
;
622 if (s
->original_fsec
) {
623 filesec_free(s
->original_fsec
);
624 s
->original_fsec
= NULL
;
632 * copytree -- recursively copy a hierarchy.
634 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
635 * Care is taken to keep the ACLs set up correctly, in addition to the
636 * normal copying that is done. (When copying a hierarchy, we can't
637 * get rid of the "allow-all-writes" ACE on a directory until we're done
638 * copying the *contents* of the directory.)
640 * The other big difference from copyfile (for the moment) is that copytree()
641 * will use a call-back function to pass along information about what is
642 * about to be copied, and whether or not it succeeded.
644 * copytree() is called from copyfile() -- but copytree() itself then calls
645 * copyfile() to copy each individual object.
647 * If COPYFILE_CLONE is passed, copytree() will clone (instead of copy)
648 * regular files and symbolic links found in each directory.
649 * Directories will still be copied normally.
651 * XXX - no effort is made to handle overlapping hierarchies at the moment.
656 copytree(copyfile_state_t s
)
660 int (*sfunc
)(const char *, struct stat
*);
661 copyfile_callback_t status
= NULL
;
662 char srcisdir
= 0, dstisdir
= 0, dstexists
= 0;
665 const char *dstpathsep
= "";
667 char srcpath
[PATH_MAX
* 2 + 1], dstpath
[PATH_MAX
* 2 + 1];
673 const char *paths
[2] = { 0 };
674 unsigned int flags
= 0;
675 int fts_flags
= FTS_NOCHDIR
;
676 dev_t last_dev
= s
->sb
.st_dev
;
683 if (s
->flags
& (COPYFILE_MOVE
| COPYFILE_UNLINK
| COPYFILE_CHECK
| COPYFILE_PACK
| COPYFILE_UNPACK
| COPYFILE_CLONE_FORCE
)) {
689 flags
= s
->flags
& (COPYFILE_ALL
| COPYFILE_NOFOLLOW
| COPYFILE_VERBOSE
| COPYFILE_EXCL
| COPYFILE_CLONE
| COPYFILE_DATA_SPARSE
);
691 paths
[0] = src
= s
->src
;
694 if (src
== NULL
|| dst
== NULL
) {
700 sfunc
= (flags
& COPYFILE_NOFOLLOW_SRC
) ? lstat
: stat
;
701 if ((sfunc
)(src
, &sbuf
) == -1) {
705 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
709 sfunc
= (flags
& COPYFILE_NOFOLLOW_DST
) ? lstat
: stat
;
710 if ((sfunc
)(dst
, &sbuf
) == -1) {
711 if (errno
!= ENOENT
) {
717 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
723 // This doesn't handle filesystem crossing and case sensitivity
724 // So there's got to be a better way
726 if (realpath(src
, srcpath
) == NULL
) {
731 if (realpath(dst
, dstpath
) == NULL
&&
732 (errno
== ENOENT
&& realpath(dirname(dst
), dstpath
) == NULL
)) {
736 if (strstr(srcpath
, dstpath
) != NULL
) {
742 srcroot
= basename((char*)src
);
743 if (srcroot
== NULL
) {
749 * To work on as well:
750 * We have a few cases when copying a hierarchy:
751 * 1) src is a non-directory, dst is a directory;
752 * 2) src is a non-directory, dst is a non-directory;
753 * 3) src is a non-directory, dst does not exist;
754 * 4) src is a directory, dst is a directory;
755 * 5) src is a directory, dst is a non-directory;
756 * 6) src is a directory, dst does not exist
758 * (1) copies src to dst/basename(src).
759 * (2) fails if COPYFILE_EXCL is set, otherwise copies src to dst.
760 * (3) and (6) copy src to the name dst.
761 * (4) copies the contents of src to the contents of dst.
766 // copy /path/to/src to /path/to/dst/src
767 // Append "/" and (fts_path - strlen(basename(src))) to dst?
769 slash
= strrchr(src
, '/');
773 offset
= slash
- src
+ 1;
775 // copy /path/to/src to /path/to/dst
776 // append (fts_path + strlen(src)) to dst?
778 offset
= strlen(src
);
781 // COPYFILE_RECURSIVE is always done physically: see 11717978.
782 fts_flags
|= FTS_PHYSICAL
;
783 if (!(s
->flags
& (COPYFILE_NOFOLLOW_SRC
|COPYFILE_CLONE
))) {
784 // Follow 'src', even if it's a symlink, unless instructed not to
785 // or we're cloning, where we never follow symlinks.
786 fts_flags
|= FTS_COMFOLLOW
;
789 fts
= fts_open((char * const *)paths
, fts_flags
, NULL
);
791 status
= s
->statuscb
;
792 while ((ftsent
= fts_read(fts
)) != NULL
) {
794 char *dstfile
= NULL
;
796 copyfile_state_t tstate
= copyfile_state_alloc();
797 if (tstate
== NULL
) {
802 tstate
->statuscb
= s
->statuscb
;
803 tstate
->ctx
= s
->ctx
;
804 if (last_dev
== ftsent
->fts_dev
) {
805 tstate
->internal_flags
|= (s
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
807 last_dev
= ftsent
->fts_dev
;
809 asprintf(&dstfile
, "%s%s%s", dst
, dstpathsep
, ftsent
->fts_path
+ offset
);
810 if (dstfile
== NULL
) {
811 copyfile_state_free(tstate
);
816 switch (ftsent
->fts_info
) {
818 tstate
->internal_flags
|= cfDelayAce
;
819 cmd
= COPYFILE_RECURSE_DIR
;
825 cmd
= COPYFILE_RECURSE_FILE
;
828 cmd
= COPYFILE_RECURSE_DIR_CLEANUP
;
835 errno
= ftsent
->fts_errno
;
837 rv
= (*status
)(COPYFILE_RECURSE_ERROR
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
838 if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
842 if (rv
== COPYFILE_QUIT
) {
855 if (cmd
== COPYFILE_RECURSE_DIR
|| cmd
== COPYFILE_RECURSE_FILE
) {
857 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
858 if (rv
== COPYFILE_SKIP
) {
859 if (cmd
== COPYFILE_RECURSE_DIR
) {
860 rv
= fts_set(fts
, ftsent
, FTS_SKIP
);
862 rv
= (*status
)(0, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
863 if (rv
== COPYFILE_QUIT
)
869 if (rv
== COPYFILE_QUIT
) {
870 retval
= -1; errno
= 0;
874 // Since we don't support cloning directories this code depends on copyfile()
875 // falling back to a regular directory copy.
876 int tmp_flags
= (cmd
== COPYFILE_RECURSE_DIR
) ? (flags
& ~COPYFILE_STAT
) : flags
;
877 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, tmp_flags
);
880 rv
= (*status
)(cmd
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
881 if (rv
== COPYFILE_QUIT
) {
893 rv
= (*status
)(cmd
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
894 if (rv
== COPYFILE_QUIT
) {
895 retval
= -1; errno
= 0;
899 } else if (cmd
== COPYFILE_RECURSE_DIR_CLEANUP
) {
901 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
902 if (rv
== COPYFILE_QUIT
) {
903 retval
= -1; errno
= 0;
905 } else if (rv
== COPYFILE_SKIP
) {
910 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, (flags
& COPYFILE_NOFOLLOW
) | COPYFILE_STAT
);
913 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
914 if (rv
== COPYFILE_QUIT
) {
917 } else if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
918 if (rv
== COPYFILE_CONTINUE
)
929 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
930 if (rv
== COPYFILE_QUIT
) {
931 retval
= -1; errno
= 0;
941 s
->internal_flags
&= ~COPYFILE_MNT_CPROTECT_MASK
;
942 s
->internal_flags
|= (tstate
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
944 copyfile_state_free(tstate
);
954 copyfile_debug(1, "returning: %d errno %d\n", retval
, errno
);
959 * fcopyfile() is used to copy a source file descriptor to a destination file
960 * descriptor. This allows an application to figure out how it wants to open
961 * the files (doing various security checks, perhaps), and then just pass in
962 * the file descriptors.
964 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
967 copyfile_state_t s
= state
;
970 if (src_fd
< 0 || dst_fd
< 0)
976 if (copyfile_preamble(&s
, flags
) < 0)
979 copyfile_debug(2, "set src_fd <- %d", src_fd
);
980 if (s
->src_fd
== -2 && src_fd
> -1)
983 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
985 if (errno
== ENOTSUP
|| errno
== EPERM
)
986 fstat(s
->src_fd
, &s
->sb
);
989 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
995 /* prevent copying on unsupported types */
996 switch (s
->sb
.st_mode
& S_IFMT
)
1007 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
1008 if (s
->dst_fd
== -2 && dst_fd
> -1)
1011 (void)fstat(s
->dst_fd
, &dst_sb
);
1012 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
1014 (void)copyfile_quarantine(s
);
1016 ret
= copyfile_internal(s
, flags
);
1018 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
1020 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
1027 if (state
== NULL
) {
1029 copyfile_state_free(s
);
1040 * This routine implements the clonefileat functionality
1041 * for copyfile. There are 2 kinds of clone flags, namely
1042 * 1. COPYFILE_CLONE_FORCE which is a 'force' clone flag.
1043 * 2. COPYFILE_CLONE which is a 'best try' flag.
1044 * In both cases, we inherit the flags provided
1045 * to copyfile call and clone the file.
1046 * Both these flags are equivalent to
1047 * (COPYFILE_EXCL | COPYFILE_ACL | COPYFILE_STAT | COPYFILE_XATTR | COPYFILE_DATA)
1048 * With force clone flag set, we return failure if cloning fails,
1049 * however, in case of best try flag, we fallback to the copy method.
1052 static int copyfile_clone(copyfile_state_t state
)
1055 // Since we don't allow cloning of directories, we must also forbid
1056 // cloning the target of symlinks (since that may be a directory).
1057 int cloneFlags
= CLONE_NOFOLLOW
;
1060 if (lstat(state
->src
, &src_sb
) != 0)
1067 * Support only for files and symbolic links.
1068 * TODO:Remove this check when support for directories is added.
1070 if (S_ISREG(src_sb
.st_mode
) || S_ISLNK(src_sb
.st_mode
))
1073 * COPYFILE_UNLINK tells us to try removing the destination
1074 * before we create it. We don't care if the file doesn't
1075 * exist, so we ignore ENOENT.
1077 if (state
->flags
& COPYFILE_UNLINK
)
1079 if (remove(state
->dst
) < 0 && errno
!= ENOENT
)
1084 ret
= clonefileat(AT_FDCWD
, state
->src
, AT_FDCWD
, state
->dst
, cloneFlags
);
1087 * We could also report the size of the single
1088 * object that was cloned. However, that's a lot
1089 * more difficult when we eventually support
1090 * cloning directories. It seems reasonable to NOT
1091 * report any bytes being "copied" in this scenario,
1092 * and let the caller figure out how they want to
1095 state
->was_cloned
= true;
1098 * COPYFILE_MOVE tells us to attempt removing
1099 * the source file after the copy, and to
1100 * ignore any errors returned by remove(3).
1102 if (state
->flags
& COPYFILE_MOVE
) {
1103 (void)remove(state
->src
);
1116 * Check if two provided paths are identical,
1117 * and if we're able to determine that, return true.
1119 static bool copyfile_paths_identical(const char *src
, const char *dst
)
1121 struct attrlist attrs
;
1123 struct stat src_sb
, dst_sb
;
1124 char volroot
[MAXPATHLEN
+ 1];
1127 vol_capabilities_attr_t volAttrs
;
1129 char *real_src_path
= NULL
, *real_dst_path
= NULL
;
1131 // Common case: the destination does not exist.
1132 if ((stat(dst
, &dst_sb
) == -1) || (stat(src
, &src_sb
) == -1))
1135 // If both files exist, then we next try to check file IDs.
1136 // This requires that the underlying filesystem support persistent file IDs.
1137 if (statfs(src
, &sfs
) == -1)
1140 strlcpy(volroot
, sfs
.f_mntonname
, sizeof(volroot
));
1141 memset(&attrs
, 0, sizeof(attrs
));
1142 attrs
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
1143 attrs
.volattr
= ATTR_VOL_CAPABILITIES
;
1145 if (getattrlist(volroot
, &attrs
, &volattrs
, sizeof(volattrs
), 0) == -1)
1148 // If the underlying devices are not the same, then the files are not the same.
1149 if (src_sb
.st_dev
!= dst_sb
.st_dev
)
1152 if ((volattrs
.volAttrs
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PERSISTENTOBJECTIDS
) &&
1153 (volattrs
.volAttrs
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_PERSISTENTOBJECTIDS
)) {
1154 // The underlying source filesystem supports persistent file IDs,
1155 // so if our two files have the same file ID on the same device,
1156 // they are identical.
1157 return (src_sb
.st_ino
== dst_sb
.st_ino
);
1160 // Finally, if we don't support persistent file ID's,
1161 // we fall back to path comparisons.
1162 real_src_path
= realpath(src
, NULL
);
1163 if (real_src_path
== NULL
)
1166 real_dst_path
= realpath(dst
, NULL
);
1167 if (real_dst_path
== NULL
)
1170 if (strncasecmp(src
, dst
, MAXPATHLEN
) == 0)
1175 free(real_src_path
);
1178 free(real_dst_path
);
1184 * the original copyfile() routine; this copies a source file to a destination
1185 * file. Note that because we need to set the names in the state variable, this
1186 * is not just the same as opening the two files, and then calling fcopyfile().
1187 * Oh, if only life were that simple!
1189 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
1193 copyfile_state_t s
= state
;
1196 if (src
== NULL
&& dst
== NULL
)
1202 if (copyfile_preamble(&s
, flags
) < 0)
1208 * This macro is... well, it's not the worst thing you can do with cpp, not
1209 * by a long shot. Essentially, we are setting the filename (src or dst)
1210 * in the state structure; since the structure may not have been cleared out
1211 * before being used again, we do some of the cleanup here: if the given
1212 * filename (e.g., src) is set, and state->src is not equal to that, then
1213 * we need to check to see if the file descriptor had been opened, and if so,
1214 * close it. After that, we set state->src to be a copy of the given filename,
1215 * releasing the old copy if necessary.
1217 #define COPYFILE_SET_FNAME(NAME, S) \
1219 if (NAME != NULL) { \
1220 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
1221 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
1222 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
1223 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
1224 close(S->NAME##_fd); \
1225 S->NAME##_fd = -2; \
1232 if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \
1237 COPYFILE_SET_FNAME(src
, s
);
1238 COPYFILE_SET_FNAME(dst
, s
);
1240 if (!(s
->flags
& COPYFILE_CHECK
)) {
1241 // We have no work to do if `src` and `dst` point to the same place.
1242 if (copyfile_paths_identical(src
, dst
)) {
1243 // ...but return an error if requested to do so.
1244 if (s
->flags
& COPYFILE_EXCL
) {
1254 if (s
->flags
& COPYFILE_RECURSIVE
) {
1259 if (s
->flags
& (COPYFILE_CLONE_FORCE
| COPYFILE_CLONE
))
1261 ret
= copyfile_clone(s
);
1264 } else if (s
->flags
& COPYFILE_CLONE_FORCE
) {
1267 // cloning failed. Inherit clonefile flags required for
1268 // falling back to copyfile.
1269 s
->flags
|= (COPYFILE_ACL
| COPYFILE_EXCL
| COPYFILE_NOFOLLOW_SRC
|
1270 COPYFILE_STAT
| COPYFILE_XATTR
| COPYFILE_DATA
);
1272 s
->flags
&= ~COPYFILE_CLONE
;
1278 * Get a copy of the source file's security settings
1280 if (s
->original_fsec
) {
1281 filesec_free(s
->original_fsec
);
1282 s
->original_fsec
= NULL
;
1284 if ((s
->original_fsec
= filesec_init()) == NULL
)
1287 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
1288 ((dst_sb
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1289 if (s
->permissive_fsec
)
1290 free(s
->permissive_fsec
);
1291 s
->permissive_fsec
= NULL
;
1292 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
1295 * copyfile_fix_perms() will make a copy of the permission set,
1296 * and insert at the beginning an ACE that ensures we can write
1297 * to the file and set attributes.
1300 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
1303 * Set the permissions for the destination to our copy.
1304 * We should get ENOTSUP from any filesystem that simply
1305 * doesn't support it.
1307 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
1309 copyfile_warn("setting security information");
1310 filesec_free(s
->permissive_fsec
);
1311 s
->permissive_fsec
= NULL
;
1314 } else if (errno
== ENOENT
) {
1319 * If COPYFILE_CHECK is set in flags, then all we are going to do
1320 * is see what kinds of things WOULD have been copied (see
1321 * copyfile_check() below). We return that value.
1323 if (COPYFILE_CHECK
& flags
)
1325 ret
= copyfile_check(s
);
1327 } else if ((ret
= copyfile_open(s
)) < 0)
1330 (void)fcntl(s
->src_fd
, F_NOCACHE
, 1);
1331 (void)fcntl(s
->dst_fd
, F_NOCACHE
, 1);
1332 #ifdef F_SINGLE_WRITER
1333 (void)fcntl(s
->dst_fd
, F_SINGLE_WRITER
, 1);
1336 ret
= copyfile_internal(s
, flags
);
1340 #ifdef COPYFILE_RECURSIVE
1341 if (!(flags
& COPYFILE_STAT
)) {
1344 /* Just need to reset the BSD information -- mode, owner, group */
1345 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
1346 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
1353 if (s
->src
&& (flags
& COPYFILE_MOVE
))
1354 (void)remove(s
->src
);
1360 copyfile_debug(5, "returning %d errno %d\n", ret
, errno
);
1362 if (state
== NULL
) {
1364 copyfile_state_free(s
);
1379 * Shared prelude to the {f,}copyfile(). This initializes the
1380 * state variable, if necessary, and also checks for both debugging
1381 * and disabling environment variables.
1383 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
1389 if ((*state
= copyfile_state_alloc()) == NULL
)
1395 if (COPYFILE_DEBUG
& flags
)
1398 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
1401 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
1403 /* clamp s->debug to 1 if the environment variable is not parsable */
1404 if (s
->debug
== 0 && errno
!= 0)
1407 copyfile_debug(2, "debug value set to: %d", s
->debug
);
1411 /* Temporarily disabled */
1412 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
1414 copyfile_debug(1, "copyfile disabled");
1418 copyfile_debug(2, "setting flags: %d", s
->flags
);
1425 * The guts of {f,}copyfile().
1426 * This looks through the flags in a particular order, and calls the
1427 * associated functions.
1429 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
1433 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1435 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1441 * COPYFILE_PACK causes us to create an Apple Double version of the
1442 * source file, and puts it into the destination file. See
1443 * copyfile_pack() below for all the gory details.
1445 if (COPYFILE_PACK
& flags
)
1447 if ((ret
= copyfile_pack(s
)) < 0)
1449 if (s
->dst
) unlink(s
->dst
);
1456 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1457 * The goal there is to take an Apple Double file, and turn it
1458 * into a normal file (with data fork, resource fork, modes,
1459 * extended attributes, ACLs, etc.).
1461 if (COPYFILE_UNPACK
& flags
)
1463 if ((ret
= copyfile_unpack(s
)) < 0)
1471 * If we have quarantine info set, we attempt
1472 * to apply it to dst_fd. We don't care if
1473 * it fails, not yet anyway.
1481 * If COPYFILE_RUN_IN_PLACE is set, we need to add
1482 * QTN_FLAG_DO_NOT_TRANSLOCATE to the qinfo flags.
1484 * On iOS, qtn_file_get_flags & qtn_file_set_flags
1485 * don't modify anything, always return 0, per static
1486 * defines at top of this file, though we should never
1487 * get here in that case as qinfo will always be NULL.
1489 if (COPYFILE_RUN_IN_PLACE
& flags
)
1493 q_flags
= qtn_file_get_flags(s
->qinfo
);
1494 q_flags
|= QTN_FLAG_DO_NOT_TRANSLOCATE
;
1496 if (qtn_file_set_flags(s
->qinfo
, q_flags
) != 0) {
1497 s
->err
= errno
= EINVAL
;
1502 qr
= qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1507 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
1508 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1509 s
->xattr_name
= NULL
;
1510 if (rv
== COPYFILE_QUIT
) {
1511 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1515 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1522 * COPYFILE_XATTR tells us to copy the extended attributes;
1523 * this is seperate from the extended security (aka ACLs),
1524 * however. If we succeed in this, we continue to the next
1525 * stage; if we fail, we return with an error value. Note
1526 * that we fail if the errno is ENOTSUP, but we don't print
1527 * a warning in that case.
1529 if (COPYFILE_XATTR
& flags
)
1531 if ((ret
= copyfile_xattr(s
)) < 0)
1533 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1534 copyfile_warn("error processing extended attributes");
1540 * Similar to above, this tells us whether or not to copy
1541 * the non-meta data portion of the file. We attempt to
1542 * remove (via unlink) the destination file if we fail.
1544 if ((COPYFILE_DATA
|COPYFILE_DATA_SPARSE
) & flags
)
1546 if ((ret
= copyfile_data(s
)) < 0)
1548 copyfile_warn("error processing data");
1549 if (s
->dst
&& unlink(s
->dst
))
1550 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1556 * COPYFILE_SECURITY requests that we copy the security, both
1557 * extended and mundane (that is, ACLs and POSIX).
1559 if (COPYFILE_SECURITY
& flags
)
1561 if ((ret
= copyfile_security(s
)) < 0)
1563 copyfile_warn("error processing security information");
1568 if (COPYFILE_STAT
& flags
)
1570 if ((ret
= copyfile_stat(s
)) < 0)
1572 copyfile_warn("error processing POSIX information");
1586 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1588 copyfile_state_t
copyfile_state_alloc(void)
1590 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1597 filesec_free(s
->fsec
);
1600 s
->fsec
= filesec_init();
1608 * copyfile_state_free() returns the memory allocated to the state structure.
1609 * It also closes the file descriptors, if they've been opened.
1611 int copyfile_state_free(copyfile_state_t s
)
1616 filesec_free(s
->fsec
);
1618 if (s
->original_fsec
)
1619 filesec_free(s
->original_fsec
);
1621 if (s
->permissive_fsec
)
1622 filesec_free(s
->permissive_fsec
);
1625 qtn_file_free(s
->qinfo
);
1627 if (copyfile_close(s
) < 0)
1629 copyfile_warn("error closing files");
1633 free(s
->xattr_name
);
1644 * Should we worry if we can't close the source? NFS says we
1645 * should, but it's pretty late for us at this point.
1647 static int copyfile_close(copyfile_state_t s
)
1649 if (s
->src
&& s
->src_fd
>= 0)
1652 if (s
->dst
&& s
->dst_fd
>= 0) {
1653 if (close(s
->dst_fd
))
1661 * The purpose of this function is to set up a set of permissions
1662 * (ACL and traditional) that lets us write to the file. In the
1663 * case of ACLs, we do this by putting in a first entry that lets
1664 * us write data, attributes, and extended attributes. In the case
1665 * of traditional permissions, we set the S_IWUSR (user-write)
1668 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1670 filesec_t ret_fsec
= NULL
;
1674 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1677 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1679 #ifdef COPYFILE_RECURSIVE
1680 if (add_uberace(&acl
))
1684 acl_permset_t permset
;
1687 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1691 * First, we create an entry, and give it the special name
1692 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1693 * After that, we clear out all the permissions in it, and
1694 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1695 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1696 * the functionality, and put this into the ACL.
1698 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1700 if (acl_get_permset(entry
, &permset
) == -1)
1702 if (acl_clear_perms(permset
) == -1)
1704 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1706 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1708 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1710 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1713 if(acl_set_permset(entry
, permset
) == -1)
1715 if(acl_set_qualifier(entry
, qual
) == -1)
1719 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1724 * This is for the normal, mundane, POSIX permission model.
1725 * We make sure that we can write to the file.
1727 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1729 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1731 mode
|= S_IWUSR
|S_IRUSR
;
1732 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1746 filesec_free(ret_fsec
);
1753 * Used to clear out the BSD/POSIX security information from
1757 copyfile_unset_posix_fsec(filesec_t fsec
)
1759 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1760 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1761 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1766 * Used to remove acl information from a filesec_t
1767 * Unsetting the acl alone in Tiger was insufficient
1769 static int copyfile_unset_acl(copyfile_state_t s
)
1772 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1774 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1777 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1779 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1782 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1784 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1791 * copyfile_open() does what one expects: it opens up the files
1792 * given in the state structure, if they're not already open.
1793 * It also does some type validation, to ensure that we only
1794 * handle file types we know about.
1796 static int copyfile_open(copyfile_state_t s
)
1798 int oflags
= O_EXCL
| O_CREAT
;
1799 int islnk
= 0, isdir
= 0, isreg
= 0;
1800 int osrc
= 0, dsrc
= 0;
1801 int prot_class
= PROTECTION_CLASS_DEFAULT
;
1802 int set_cprot_explicit
= 0;
1805 if (s
->src
&& s
->src_fd
== -2)
1807 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1808 (s
->src
, &s
->sb
, s
->fsec
))
1810 copyfile_warn("stat on %s", s
->src
);
1814 /* prevent copying on unsupported types */
1815 switch (s
->sb
.st_mode
& S_IFMT
)
1819 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1820 s
->err
= ENOMEM
; /* too big for us to copy */
1832 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1838 * If we're packing, then we are actually
1839 * creating a file, no matter what the source
1842 if (s
->flags
& COPYFILE_PACK
) {
1844 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1845 * if the file is a symlink, and O_NOFOLLOW is specified,
1846 * open will return ELOOP, whether or not O_SYMLINK is set.
1847 * However, we know whether or not it was a symlink from
1848 * the stat above (although there is a potentiaal for a race
1849 * condition here, but it will err on the side of returning
1853 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1857 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1859 copyfile_warn("open on %s", s
->src
);
1862 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1864 (void)copyfile_quarantine(s
);
1867 if (s
->dst
&& s
->dst_fd
== -2)
1870 * Per <rdar://60074298>, only open files for writing if we expect
1871 * to modify the file's content. This avoids undesirable side effects
1872 * of O_WRONLY when we're only modifying metadata/attributes.
1874 * The calls needed by COPYFILE_METADATA (e.g. fchown(), fchmod(),
1875 * fchflags(), futimes(), fsetattrlist(), f{set,remove}xattr(), and
1876 * acl_set_fd()) are safe to use with O_RDONLY descriptors. They
1877 * operate on the underlying vnode_t, as path-based variants do.
1878 * These usually only need write permissions in st_mode or ACLs.
1880 const copyfile_flags_t writable_flags
= (COPYFILE_DATA
| COPYFILE_DATA_SPARSE
);
1881 if (COPYFILE_PACK
& s
->flags
) {
1882 oflags
|= O_WRONLY
; // always writes file content
1883 } else if (COPYFILE_UNPACK
& s
->flags
) {
1884 oflags
|= O_RDONLY
; // only updates metadata
1886 oflags
|= (writable_flags
& s
->flags
) ? O_WRONLY
: O_RDONLY
;
1890 * COPYFILE_UNLINK tells us to try removing the destination
1891 * before we create it. We don't care if the file doesn't
1892 * exist, so we ignore ENOENT.
1894 if (COPYFILE_UNLINK
& s
->flags
)
1896 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1898 copyfile_warn("%s: remove", s
->dst
);
1903 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1907 if (lstat(s
->dst
, &st
) != -1) {
1908 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1913 if (!(s
->internal_flags
& cfSrcProtSupportValid
))
1915 if ((error
= does_copy_protection(s
->src_fd
)) > 0)
1917 s
->internal_flags
|= cfSrcSupportsCProtect
;
1921 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->src
, errno
);
1924 s
->internal_flags
|= cfSrcProtSupportValid
;
1927 /* copy protection is only valid for regular files and directories. */
1928 if ((isreg
|| isdir
) && (s
->internal_flags
& cfSrcSupportsCProtect
))
1930 prot_class
= GET_PROT_CLASS(s
->src_fd
);
1933 copyfile_warn("GET_PROT_CLASS failed on (%s) with error <%d>", s
->src
, errno
);
1939 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1944 copyfile_warn("cannot allocate %zd bytes", sz
);
1947 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1948 copyfile_warn("cannot readlink %s", s
->src
);
1952 if (symlink(bp
, s
->dst
) == -1) {
1953 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1954 copyfile_warn("Cannot make symlink %s", s
->dst
);
1960 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1961 if (s
->dst_fd
== -1) {
1962 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1967 mode
= (s
->sb
.st_mode
& ~S_IFMT
) | S_IRWXU
;
1969 if (mkdir(s
->dst
, mode
) == -1) {
1970 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1971 copyfile_warn("Cannot make directory %s", s
->dst
);
1975 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1976 if (s
->dst_fd
== -1) {
1977 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1980 set_cprot_explicit
= 1;
1981 } else while((s
->dst_fd
= do_copy_protected_open(s
->dst
, oflags
| dsrc
, prot_class
,
1982 0, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1985 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1986 * was written -- allow one to set an extended attribute on a file descriptor
1987 * for a read-only file, even if the file descriptor is opened for writing.
1988 * This will only matter if the file does not already exist.
1993 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1994 if (s
->flags
& COPYFILE_EXCL
)
1996 oflags
= oflags
& ~O_CREAT
;
1997 /* if O_CREAT isn't set in open_dprotected_np, it won't set protection class.
1998 * Set the flag here so we know to do it later.
2000 set_cprot_explicit
= 1;
2001 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
2003 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
2008 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
2012 * If we're trying to write to a directory to which we don't
2013 * have access, the create above would have failed, but chmod
2014 * here would have given us ENOENT. But the real error is
2015 * still one of access, so we change the errno we're reporting.
2016 * This could cause confusion with a race condition.
2019 if (errno
== ENOENT
)
2024 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
2025 if (((s
->flags
& COPYFILE_EXCL
) ||
2026 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
2027 && !(s
->flags
& COPYFILE_UNPACK
))
2029 oflags
= (oflags
& ~(O_WRONLY
|O_CREAT
|O_TRUNC
)) | O_RDONLY
;
2032 copyfile_warn("open on %s", s
->dst
);
2035 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
2037 if (s
->internal_flags
& cfSrcSupportsCProtect
)
2039 if (!(s
->internal_flags
& cfDstProtSupportValid
))
2041 if ((error
= does_copy_protection(s
->dst_fd
)) > 0)
2043 s
->internal_flags
|= cfDstSupportsCProtect
;
2047 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->dst
, errno
);
2050 s
->internal_flags
|= cfDstProtSupportValid
;
2053 if ((isreg
|| isdir
)
2054 && set_cprot_explicit
2055 && (s
->internal_flags
& cfDstSupportsCProtect
))
2057 /* Protection class is set in open_dprotected_np for regular files that aren't truncated.
2058 * We set the protection class here for truncated files and directories.
2060 if (SET_PROT_CLASS(s
->dst_fd
, prot_class
) != 0)
2062 copyfile_warn("SET_PROT_CLASS failed on (%s) with error <%d>", s
->dst
, errno
);
2069 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
2071 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
2072 s
->src_fd
, s
->dst_fd
);
2081 * copyfile_check(), as described above, essentially tells you
2082 * what you'd have to copy, if you wanted it to copy the things
2083 * you asked it to copy.
2084 * In other words, if you pass in COPYFILE_ALL, and the file in
2085 * question had no extended attributes but did have an ACL, you'd
2086 * get back COPYFILE_ACL.
2088 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
2091 copyfile_flags_t ret
= 0;
2092 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
2102 if (COPYFILE_XATTR
& s
->flags
)
2103 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
2105 ret
|= COPYFILE_XATTR
;
2108 if (COPYFILE_ACL
& s
->flags
)
2110 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
2111 (s
->src
, &s
->sb
, s
->fsec
);
2113 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
2114 ret
|= COPYFILE_ACL
;
2117 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
2123 /* If the state has had quarantine info set already, we use that */
2124 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
2126 qinfo
= qtn_file_alloc();
2128 * For quarantine information, we need to see if the source file
2129 * has any. Since it may be a symlink, however, and we may, or
2130 * not be following, *and* there's no qtn* routine which can optionally
2131 * follow or not follow a symlink, we need to instead work around
2140 * If we care about not following symlinks, *and* the file exists
2141 * (which is to say, lstat doesn't return an error), *and* the file
2142 * is a symlink, then we open it up (with O_SYMLINK), and use
2143 * qtn_file_init_with_fd(); if none of that is true, however, then
2144 * we can simply use qtn_file_init_with_path().
2147 && lstat(s
->src
, &sbuf
) == 0
2148 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
2149 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
2151 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
2152 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
2157 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
2158 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
2161 qtn_file_free(qinfo
);
2169 * Attempt to copy the data section of a file sparsely.
2170 * Requires that the source and destination file systems support sparse files.
2171 * Also requires that the source file descriptor's offset is a multiple of the smaller of the
2172 * source and destination file systems' block size.
2173 * In practice, this means that we refuse to perform copies that are only partially sparse.
2174 * Returns 0 if the source sparse file was copied, -1 on an unrecoverable error that
2175 * callers should propagate, and ENOTSUP where this routine refuses to copy the source file.
2176 * In this final case, callers are free to attempt a full copy.
2178 static int copyfile_data_sparse(copyfile_state_t s
, size_t input_blk_size
, size_t output_blk_size
)
2180 int src_fd
= s
->src_fd
, dst_fd
= s
->dst_fd
, rc
= 0;
2181 off_t src_start
, dst_start
, src_size
= s
->sb
.st_size
;
2182 off_t first_hole_offset
, next_hole_offset
, current_src_offset
, next_src_offset
;
2184 size_t iosize
= MIN(input_blk_size
, output_blk_size
);
2185 copyfile_callback_t status
= s
->statuscb
;
2187 bool use_punchhole
= true;
2191 if (!(s
->flags
& COPYFILE_DATA_SPARSE
)) {
2192 // Don't attempt this unless the right flags are passed.
2194 } else if (src_size
< 0) {
2195 // The file size of our source is invalid; there's nothing to copy.
2198 } else if (src_size
== 0) {
2199 // This is a zero-length file: no work to do.
2203 // Since a major underlying filesystem requires that holes are block-aligned,
2204 // we only punch holes if we can guarantee that all holes from the source can
2205 // be holes in the destination, which requires that the source filesystem's block size
2206 // be an integral multiple of the destination filesystem's block size.
2207 if (input_blk_size
% output_blk_size
!= 0) {
2208 use_punchhole
= false;
2211 // Get the starting src/dest file descriptor offsets.
2212 src_start
= lseek(src_fd
, 0, SEEK_CUR
);
2213 dst_start
= lseek(dst_fd
, 0, SEEK_CUR
);
2214 if (src_start
< 0 || src_start
>= src_size
|| dst_start
< 0) {
2216 * Invalid starting source/destination offset:
2217 * Either < 0 which is plainly invalid (lseek may have failed),
2218 * or > EOF which means that the copy operation is undefined,
2219 * as by definition there is no data past EOF.
2224 copyfile_warn("Invalid file descriptor offset, cannot perform a sparse copy");
2226 } else if (src_start
!= (off_t
) roundup(src_start
, iosize
) ||
2227 dst_start
!= (off_t
) roundup(dst_start
, iosize
)) {
2228 // If the starting offset isn't a multiple of the iosize, we can't do an entire sparse copy.
2229 // Fall back to copyfile_data(), which will perform a full copy from the starting position.
2233 // Make sure that there is at least one hole in this [part of the] file.
2234 first_hole_offset
= lseek(src_fd
, src_start
, SEEK_HOLE
);
2235 if (first_hole_offset
== -1 || first_hole_offset
== src_size
) {
2237 * Either an error occurred, the src starting position is EOF, or there are no
2238 * holes in this [portion of the] source file. Regardless, we rewind the source file
2239 * and return ENOTSUP so copyfile_data() can attempt a full copy.
2241 if (lseek(src_fd
, src_start
, SEEK_SET
) == -1) {
2247 // We are ready to begin copying.
2248 // First, truncate the destination file to zero out any existing contents.
2249 // Then, truncate it again to its eventual size.
2250 if (ftruncate(dst_fd
, dst_start
) == -1) {
2251 copyfile_warn("Could not zero destination file before copy");
2253 } else if (ftruncate(dst_fd
, dst_start
+ src_size
- src_start
) == -1) {
2254 copyfile_warn("Could not set destination file size before copy");
2258 // Set the source's offset to the first data section.
2259 current_src_offset
= lseek(src_fd
, src_start
, SEEK_DATA
);
2260 if (current_src_offset
== -1) {
2261 if (errno
== ENXIO
) {
2262 // There are no more data sections in the file, so there's nothing to copy.
2263 goto set_total_copied
;
2268 // Now, current_src_offset points at the start of src's first data region.
2269 // Update dst_fd to point to the same offset (respecting its start).
2270 if (lseek(dst_fd
, dst_start
+ current_src_offset
- src_start
, SEEK_SET
) == -1) {
2271 copyfile_warn("failed to set dst to first data section");
2275 // Allocate a temporary buffer to copy data sections into.
2276 bp
= malloc(iosize
);
2278 copyfile_warn("No memory for copy buffer");
2283 * Performing a sparse copy:
2284 * While our source fd points to a data section (and is < EOF), read iosize bytes in.
2285 * Then, write those bytes to the dest fd, using the same iosize.
2286 * Finally, update our source and dest fds to point to the next data section.
2288 while ((nread
= read(src_fd
, bp
, iosize
)) > 0) {
2290 size_t left
= nread
;
2295 nwritten
= write(dst_fd
, ptr
, left
);
2299 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
2305 copyfile_warn("writing to output file failed");
2307 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2308 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
2311 } else if (rv
== COPYFILE_CONTINUE
) { // Retry the write
2316 // If we get here, we either have no callback or it didn't tell us to continue.
2321 ptr
= ((char*)ptr
) + nwritten
;
2325 s
->totalCopied
+= nwritten
;
2327 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
2328 if (rv
== COPYFILE_QUIT
) {
2334 current_src_offset
+= nread
;
2336 // Find the next area of src_fd to copy.
2337 // Since data sections can be any length, we need see if current_src_offset points
2339 // If we get ENXIO, we're done copying (the last part of the file was a data section).
2340 // If this is not a hole, we do not need to alter current_src_offset yet.
2341 // If this is a hole, then we need to look for the next data section.
2342 next_hole_offset
= lseek(src_fd
, current_src_offset
, SEEK_HOLE
);
2343 if (next_hole_offset
== -1) {
2344 if (errno
== ENXIO
) {
2345 break; // We're done copying data sections.
2347 copyfile_warn("unable to find next hole in file during copy");
2349 } else if (next_hole_offset
!= current_src_offset
) {
2350 // Keep copying this data section (we must rewind src_fd to current_src_offset).
2351 if (lseek(src_fd
, current_src_offset
, SEEK_SET
) == -1) {
2357 // If we get here, we need to find the next data section to copy.
2358 next_src_offset
= lseek(src_fd
, current_src_offset
, SEEK_DATA
);
2359 if (next_src_offset
== -1) {
2360 if (errno
== ENXIO
) {
2361 // There are no more data sections in this file, so we're done with the copy.
2365 copyfile_warn("unable to advance src to next data section");
2369 // Advance the dst_fd to match (taking into account where it started).
2370 if (lseek(dst_fd
, dst_start
+ (next_src_offset
- src_start
), SEEK_SET
) == -1) {
2371 copyfile_warn("unable to advance dst to next data section");
2375 current_src_offset
= next_src_offset
;
2378 copyfile_warn("error %d reading from %s", errno
, s
->src
? s
->src
: "(null src)");
2382 // Punch holes where possible if needed.
2383 if (use_punchhole
) {
2384 struct fpunchhole punchhole_args
;
2385 off_t hole_start
= first_hole_offset
, hole_end
;
2386 bool trailing_hole
= true;
2388 // First, reset the source and destination file descriptors.
2389 if (lseek(src_fd
, src_start
, SEEK_SET
) == -1 || lseek(dst_fd
, dst_start
, SEEK_SET
) == -1) {
2390 copyfile_warn("unable to reset file descriptors to punch holes");
2391 // We have still copied the data, so there's no need to return an error here.
2392 goto set_total_copied
;
2395 // Now, find holes in the source (first_hole_offset already points to a source hole),
2396 // determining their length by the presence of a data section.
2397 while ((hole_end
= lseek(src_fd
, hole_start
+ (off_t
) iosize
, SEEK_DATA
)) != -1) {
2398 memset(&punchhole_args
, 0, sizeof(punchhole_args
));
2400 // Fix up the offset and length for the destination file.
2401 punchhole_args
.fp_offset
= hole_start
- src_start
+ dst_start
;
2402 punchhole_args
.fp_length
= hole_end
- hole_start
;
2403 if (fcntl(dst_fd
, F_PUNCHHOLE
, &punchhole_args
) == -1) {
2404 copyfile_warn("unable to punch hole in destination file, offset %lld length %lld",
2405 hole_start
- src_start
+ dst_start
, hole_end
- hole_start
);
2406 goto set_total_copied
;
2409 // Now, find the start of the next hole.
2410 hole_start
= lseek(src_fd
, hole_end
, SEEK_HOLE
);
2411 if (hole_start
== -1 || hole_start
== src_size
) {
2412 // No more holes (or lseek failed), so break.
2413 trailing_hole
= false;
2418 if ((hole_end
== -1 || hole_start
== -1) && errno
!= ENXIO
) {
2419 // A call to lseek() failed. Hole punching is best effort, so exit.
2420 copyfile_warn("lseek during hole punching failed");
2421 goto set_total_copied
;
2424 // We will still have a trailing hole to punch if the last lseek(SEEK_HOLE) succeeded.
2425 if (trailing_hole
) {
2426 // Since we can only punch iosize-aligned holes, we must make sure the last hole
2427 // is iosize-aligned. Unfortunately, no good truncate macros are in scope here,
2428 // so we must round down the end of the trailing hole to an iosize boundary ourselves.
2429 hole_end
= (src_size
% iosize
== 0) ? src_size
: roundup(src_size
, iosize
) - iosize
;
2431 memset(&punchhole_args
, 0, sizeof(punchhole_args
));
2432 punchhole_args
.fp_offset
= hole_start
- src_start
+ dst_start
;
2433 punchhole_args
.fp_length
= hole_end
- hole_start
;
2434 if (fcntl(dst_fd
, F_PUNCHHOLE
, &punchhole_args
) == -1) {
2435 copyfile_warn("unable to punch trailing hole in destination file, offset %lld",
2436 hole_start
- src_start
+ dst_start
);
2437 goto set_total_copied
;
2443 // Since we don't know in advance how many bytes we're copying, we advance this number
2444 // as we copy, but to match copyfile_data() we set it here to the amount of bytes that would
2445 // have been transferred in a full copy.
2446 s
->totalCopied
= src_size
- src_start
;
2463 * Attempt to copy the data section of a file. Using blockisize
2464 * is not necessarily the fastest -- it might be desirable to
2465 * specify a blocksize, somehow. But it's a size that should be
2466 * guaranteed to work.
2468 static int copyfile_data(copyfile_state_t s
)
2474 size_t iBlocksize
= 0, iMinblocksize
= 0;
2475 size_t oBlocksize
= 0, oMinblocksize
= 0; // If 0, we don't support sparse copying.
2476 const size_t blocksize_limit
= 1 << 30; // 1 GiB
2478 copyfile_callback_t status
= s
->statuscb
;
2480 /* Unless it's a normal file, we don't copy. For now, anyway */
2481 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
2484 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
2485 if (s
->internal_flags
& cfSawDecmpEA
) {
2486 if (s
->sb
.st_flags
& UF_COMPRESSED
) {
2487 if ((s
->flags
& COPYFILE_STAT
) == 0) {
2488 if (fchflags(s
->dst_fd
, UF_COMPRESSED
) == 0) {
2496 // Calculate the input and output block sizes.
2497 // Our output block size can be no greater than our input block size.
2498 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
2499 iBlocksize
= s
->sb
.st_blksize
;
2501 iBlocksize
= sfs
.f_iosize
;
2502 iMinblocksize
= sfs
.f_bsize
;
2505 if (fstatfs(s
->dst_fd
, &sfs
) == -1) {
2506 oBlocksize
= iBlocksize
;
2508 oBlocksize
= (sfs
.f_iosize
== 0) ? iBlocksize
: MIN((size_t) sfs
.f_iosize
, iBlocksize
);
2509 oMinblocksize
= sfs
.f_bsize
;
2512 // 6453525 and 34848916 require us to limit our blocksize to resonable values.
2513 if ((size_t) s
->sb
.st_size
< iBlocksize
&& iMinblocksize
> 0) {
2514 copyfile_debug(3, "rounding up block size from fsize: %lld to multiple of %zu\n", s
->sb
.st_size
, iMinblocksize
);
2515 iBlocksize
= roundup((size_t) s
->sb
.st_size
, iMinblocksize
);
2516 oBlocksize
= MIN(oBlocksize
, iBlocksize
);
2519 if (iBlocksize
> blocksize_limit
) {
2520 iBlocksize
= blocksize_limit
;
2521 oBlocksize
= MIN(oBlocksize
, iBlocksize
);
2524 copyfile_debug(3, "input block size: %zu output block size: %zu\n", iBlocksize
, oBlocksize
);
2528 // If requested, attempt a sparse copy.
2529 if (s
->flags
& COPYFILE_DATA_SPARSE
) {
2530 // Check if the source & destination volumes both support sparse files.
2531 long min_hole_size
= MIN(fpathconf(s
->src_fd
, _PC_MIN_HOLE_SIZE
),
2532 fpathconf(s
->dst_fd
, _PC_MIN_HOLE_SIZE
));
2534 // If holes are supported on both the source and dest volumes, make sure our min_hole_size
2535 // is reasonable: if it's smaller than the source/dest block size,
2536 // our copy performance will suffer (and we may not create sparse files).
2537 if (iMinblocksize
> 0 && oMinblocksize
> 0 && (size_t) min_hole_size
>= iMinblocksize
2538 && (size_t) min_hole_size
>= oMinblocksize
) {
2540 ret
= copyfile_data_sparse(s
, iMinblocksize
, oMinblocksize
);
2542 // If we returned an error, exit gracefully.
2543 // If sparse copying is not supported, we try full copying if allowed by our caller.
2546 } else if (ret
!= ENOTSUP
) {
2552 // Make sure we're allowed to perform non-sparse copying.
2553 if (!(s
->flags
& COPYFILE_DATA
)) {
2560 if ((bp
= malloc(iBlocksize
)) == NULL
)
2565 /* If supported, do preallocation for Xsan / HFS / apfs volumes */
2566 #ifdef F_PREALLOCATE
2568 off_t dst_bytes_allocated
= 0;
2571 if (fstat(s
->dst_fd
, &dst_sb
) == 0) {
2572 // The destination may already have
2573 // preallocated space we can use.
2574 dst_bytes_allocated
= dst_sb
.st_blocks
* S_BLKSIZE
;
2577 if (dst_bytes_allocated
< s
->sb
.st_size
) {
2581 fst
.fst_posmode
= F_PEOFPOSMODE
;
2583 fst
.fst_length
= s
->sb
.st_size
- dst_bytes_allocated
;
2585 copyfile_debug(3, "preallocating %lld bytes on destination", fst
.fst_length
);
2586 /* Ignore errors; this is merely advisory. */
2587 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
2592 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
2595 size_t left
= nread
;
2600 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
2604 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
2611 copyfile_warn("writing to output file got error");
2613 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2614 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
2618 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
2627 ptr
= ((char*)ptr
) + nwritten
;
2631 s
->totalCopied
+= nwritten
;
2633 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
2634 if (rv
== COPYFILE_QUIT
) {
2635 ret
= -1; s
->err
= errno
= ECANCELED
;
2643 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
2648 if (ftruncate(s
->dst_fd
, s
->totalCopied
) < 0)
2664 * copyfile_security() will copy the ACL set, and the
2665 * POSIX set. Complexities come when dealing with
2666 * inheritied permissions, and when dealing with both
2667 * POSIX and ACL permissions.
2669 static int copyfile_security(copyfile_state_t s
)
2673 acl_t acl_src
= NULL
, acl_tmp
= NULL
, acl_dst
= NULL
;
2675 filesec_t tmp_fsec
= NULL
;
2676 filesec_t fsec_dst
= filesec_init();
2678 if (fsec_dst
== NULL
)
2682 if (COPYFILE_ACL
& s
->flags
)
2684 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
2686 if (errno
== ENOENT
)
2692 /* grab the destination acl
2693 cannot assume it's empty due to inheritance
2695 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
2698 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
2700 if (errno
== ENOENT
)
2706 if (acl_src
== NULL
&& acl_dst
== NULL
)
2709 acl_tmp
= acl_init(4);
2710 if (acl_tmp
== NULL
)
2714 acl_entry_t ace
= NULL
;
2715 acl_entry_t tmp
= NULL
;
2717 acl_get_entry(acl_src
,
2718 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2721 acl_flagset_t flags
= { 0 };
2722 acl_get_flagset_np(ace
, &flags
);
2723 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2725 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2728 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2731 copyfile_debug(2, "copied acl entry from %s to %s",
2732 s
->src
? s
->src
: "(null src)",
2733 s
->dst
? s
->dst
: "(null tmp)");
2739 acl_entry_t ace
= NULL
;
2740 acl_entry_t tmp
= NULL
;
2741 acl_flagset_t flags
= { 0 };
2742 for (copied
= 0;acl_get_entry(acl_dst
,
2743 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2746 acl_get_flagset_np(ace
, &flags
);
2747 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2749 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2752 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2755 copyfile_debug(2, "copied acl entry from %s to %s",
2756 s
->src
? s
->src
: "(null dst)",
2757 s
->dst
? s
->dst
: "(null tmp)");
2762 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_tmp
))
2764 copyfile_debug(3, "altered acl");
2769 * The following code is attempting to ensure that only the requested
2770 * security information gets copied over to the destination file.
2771 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2772 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2775 * If we have both flags, we copy everything; if we have ACL but not STAT,
2776 * we remove the POSIX information from the filesec object, and apply the
2777 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2778 * the extended version.
2780 tmp_fsec
= filesec_dup(s
->fsec
);
2781 if (tmp_fsec
== NULL
) {
2785 switch (COPYFILE_SECURITY
& s
->flags
) {
2787 copyfile_unset_posix_fsec(tmp_fsec
);
2789 case COPYFILE_ACL
| COPYFILE_STAT
:
2790 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
2793 * The call could have failed for a number of reasons, since
2794 * it does a number of things: it changes the mode of the file,
2795 * sets the owner and group, and applies an ACL (if one exists).
2796 * The typical failure is going to be trying to set the group of
2797 * the destination file to match the source file, when the process
2798 * doesn't have permission to put files in that group. We try to
2799 * work around this by breaking the steps out and doing them
2800 * discretely. We don't care if the fchown fails, but we do care
2801 * if the mode or ACL can't be set. For historical reasons, we
2802 * simply log those failures, however.
2804 * Big warning here: we may NOT have COPYFILE_STAT set, since
2805 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2808 #define NS(x) ((x) ? (x) : "(null string)")
2809 if ((s
->flags
& COPYFILE_STAT
) &&
2810 fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
2811 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
2813 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2814 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
2815 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
2816 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
2824 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
2827 filesec_free(tmp_fsec
);
2829 filesec_free(fsec_dst
);
2830 if (acl_src
) acl_free(acl_src
);
2831 if (acl_dst
) acl_free(acl_dst
);
2832 if (acl_tmp
) acl_free(acl_tmp
);
2843 * Attempt to set the destination file's stat information -- including
2844 * flags and time-related fields -- to the source's.
2845 * Note that we must set file flags *last*, as setting a flag like
2846 * UF_IMMUTABLE can prevent us from setting other attributes.
2848 static int copyfile_stat(copyfile_state_t s
)
2850 unsigned int added_flags
= 0, dst_flags
= 0;
2851 struct attrlist attrlist
;
2854 /* Order of these structs matters for setattrlist. */
2855 struct timespec mod_time
;
2856 struct timespec acc_time
;
2859 /* Try to set m/atimes using setattrlist(), for nanosecond precision. */
2860 memset(&attrlist
, 0, sizeof(attrlist
));
2861 attrlist
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
2862 attrlist
.commonattr
= ATTR_CMN_MODTIME
| ATTR_CMN_ACCTIME
;
2863 ma_times
.mod_time
= s
->sb
.st_mtimespec
;
2864 ma_times
.acc_time
= s
->sb
.st_atimespec
;
2865 (void)fsetattrlist(s
->dst_fd
, &attrlist
, &ma_times
, sizeof(ma_times
), 0);
2867 /* If this fails, we don't care */
2868 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2870 /* This may have already been done in copyfile_security() */
2871 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
2874 * NFS doesn't support chflags; ignore errors as a result, since
2875 * we don't return failure for this.
2877 if (s
->internal_flags
& cfMakeFileInvisible
)
2878 added_flags
|= UF_HIDDEN
;
2881 * We need to check if certain flags were set on the destination
2882 * by the kernel. If they were, don't drop them.
2884 if (fstat(s
->dst_fd
, &dst_sb
))
2886 added_flags
|= (dst_sb
.st_flags
& COPYFILE_PRESERVE_FLAGS
);
2889 * The caller requested that copyfile attempts to preserve UF_TRACKED
2890 * on the destination. This can be used to avoid dangling docIDs when
2891 * the copy races against a process that sets the flag on newly created
2892 * documents for instance.
2894 if (s
->flags
& COPYFILE_PRESERVE_DST_TRACKED
) {
2895 added_flags
|= (dst_sb
.st_flags
& UF_TRACKED
);
2898 /* Copy file flags, masking out any we don't want to preserve */
2899 dst_flags
= (s
->sb
.st_flags
& ~COPYFILE_OMIT_FLAGS
) | added_flags
;
2900 (void)fchflags(s
->dst_fd
, dst_flags
);
2905 #define MAX_GETXATTR_RETRIES 3
2906 #define MAX_XATTR_BUFFER_SIZE (32 * 1024 * 1024) // 32 MiB
2908 * Similar to copyfile_security() in some ways; this
2909 * routine copies the extended attributes from the source,
2910 * and sets them on the destination.
2911 * The procedure is pretty simple, even if it is verbose:
2912 * for each named attribute on the destination, get its name, and
2913 * remove it. We should have none after that.
2914 * For each named attribute on the source, get its name, get its
2915 * data, and set it on the destination.
2917 static int copyfile_xattr(copyfile_state_t s
)
2920 char *namebuf
= NULL
;
2924 ssize_t xa_bufsize
= 4096;
2925 ssize_t namebuf_size
= 0;
2929 int look_for_decmpea
= 0;
2930 int tries_left
= MAX_GETXATTR_RETRIES
;
2932 /* delete EAs on destination */
2934 if ((list_size
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2936 /* this is always true on the first call: no buffer yet (namebuf_size == 0) */
2937 if (list_size
> namebuf_size
) {
2938 if (list_size
> MAX_XATTR_BUFFER_SIZE
) {
2939 copyfile_warn("destination's xattr list size (%zu) exceeds the threshold (%d); trying to allocate", list_size
, MAX_XATTR_BUFFER_SIZE
);
2941 namebuf_size
= list_size
;
2942 void *tdptr
= namebuf
;
2945 (void *) realloc((void *) namebuf
, namebuf_size
)) == NULL
)
2953 list_size
= flistxattr(s
->dst_fd
, namebuf
, namebuf_size
, 0);
2955 if ((list_size
< 0) && (errno
== ERANGE
) && (tries_left
> 0)) {
2956 /* `namebuf` is too small - try again */
2959 } else if (list_size
> 0) {
2961 * With this, end points to the last byte of the allocated buffer
2962 * This *should* be NUL, from flistxattr, but if it's not, we can
2963 * set it anyway -- it'll result in a truncated name, which then
2964 * shouldn't match when we get them later.
2966 end
= namebuf
+ list_size
- 1;
2969 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
2970 /* If the quarantine information shows up as an EA, we skip over it */
2971 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
2974 fremovexattr(s
->dst_fd
, name
,0);
2978 else if (list_size
< 0)
2983 if (errno
== ENOTSUP
|| errno
== EPERM
) {
2994 tries_left
= MAX_GETXATTR_RETRIES
;
2996 #ifdef DECMPFS_XATTR_NAME
2997 if ((s
->flags
& COPYFILE_DATA
) &&
2998 (s
->sb
.st_flags
& UF_COMPRESSED
) &&
2999 doesdecmpfs(s
->src_fd
) &&
3000 doesdecmpfs(s
->dst_fd
)) {
3001 look_for_decmpea
= XATTR_SHOWCOMPRESSION
;
3005 /* get name list of EAs on source */
3007 if ((list_size
= flistxattr(s
->src_fd
, 0, 0, look_for_decmpea
)) <= 0)
3013 if (list_size
== 0) {
3015 } else if (errno
== ENOTSUP
|| errno
== EPERM
) {
3022 /* this is always true on the first call: no buffer yet (namebuf_size == 0) */
3023 if (list_size
> namebuf_size
) {
3024 if (list_size
> MAX_XATTR_BUFFER_SIZE
) {
3025 copyfile_warn("source's xattr list size (%zu) exceeds the threshold (%d); trying to allocate", list_size
, MAX_XATTR_BUFFER_SIZE
);
3027 namebuf_size
= list_size
;
3028 void *tdptr
= namebuf
;
3030 (void *) realloc((void *) namebuf
, namebuf_size
)) == NULL
)
3039 list_size
= flistxattr(s
->src_fd
, namebuf
, namebuf_size
, look_for_decmpea
);
3041 if ((list_size
< 0) && (errno
== ERANGE
) && (tries_left
> 0)) {
3042 /* `namebuf` is too small - try again */
3045 } else if (list_size
<= 0) {
3049 return (int)list_size
;
3053 * With this, end points to the last byte of the allocated buffer
3054 * This *should* be NUL, from flistxattr, but if it's not, we can
3055 * set it anyway -- it'll result in a truncated name, which then
3056 * shouldn't match when we get them later.
3058 end
= namebuf
+ list_size
- 1;
3062 if ((xa_dataptr
= (void *) malloc(xa_bufsize
)) == NULL
) {
3067 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
3069 if (s
->xattr_name
) {
3070 free(s
->xattr_name
);
3071 s
->xattr_name
= NULL
;
3074 /* If the quarantine information shows up as an EA, we skip over it */
3075 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
3078 tries_left
= MAX_GETXATTR_RETRIES
;
3080 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, look_for_decmpea
)) < 0)
3085 if (xa_size
> xa_bufsize
)
3087 if (xa_size
> MAX_XATTR_BUFFER_SIZE
) {
3088 copyfile_warn("xattr named %s has size (%zu), which exceeds the threshold (%d); trying to allocate", name
, list_size
, MAX_XATTR_BUFFER_SIZE
);
3090 void *tdptr
= xa_dataptr
;
3091 xa_bufsize
= xa_size
;
3093 (void *) realloc((void *) xa_dataptr
, xa_bufsize
)) == NULL
)
3101 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_bufsize
, 0, look_for_decmpea
)) < 0)
3103 if ((errno
== ERANGE
) && (tries_left
> 0)) {
3104 /* `xa_dataptr` is too small - try again */
3111 if (xa_size
!= asize
)
3114 #ifdef DECMPFS_XATTR_NAME
3115 if (strncmp(name
, DECMPFS_XATTR_NAME
, end
-name
) == 0)
3117 decmpfs_disk_header
*hdr
= xa_dataptr
;
3120 * If the EA has the decmpfs name, but is too
3121 * small, or doesn't have the right magic number,
3122 * or isn't the right type, we'll just skip it.
3123 * This means it won't end up in the destination
3124 * file, and data copy will happen normally.
3126 if ((size_t)xa_size
< sizeof(decmpfs_disk_header
)) {
3129 if (OSSwapLittleToHostInt32(hdr
->compression_magic
) != DECMPFS_MAGIC
) {
3133 * From AppleFSCompression documentation:
3134 * "It is incumbent on the aware copy engine to identify
3135 * the type of compression being used, and to perform an
3136 * unaware copy of any file it does not recognize."
3138 * Compression Types are defined in:
3139 * "AppleFSCompression/Common/compressorCommon.h"
3141 * Unfortunately, they don't provide a way to dynamically
3142 * determine what possible compression_type values exist,
3143 * so we have to update this every time a new compression_type
3144 * is added. Types 7->10 were added in 10.10, Types 11 & 12
3145 * were added in 10.11.
3147 * Ubiquity faulting file compression type 0x80000001 are
3148 * deprecated as of Yosemite, per rdar://17714998 don't copy the
3149 * decmpfs xattr on these files, zero byte files are safer
3150 * than a fault nobody knows how to handle.
3152 switch (OSSwapLittleToHostInt32(hdr
->compression_type
)) {
3153 case 3: /* zlib-compressed data in xattr */
3154 case 4: /* 64k chunked zlib-compressed data in resource fork */
3156 case 7: /* LZVN-compressed data in xattr */
3157 case 8: /* 64k chunked LZVN-compressed data in resource fork */
3159 case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */
3160 case 10: /* 64k chunked uncompressed data in resource fork */
3162 case 11: /* LZFSE-compressed data in xattr */
3163 case 12: /* 64k chunked LZFSE-compressed data in resource fork */
3165 /* valid compression type, we want to copy. */
3168 case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */
3169 copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.",
3170 s
->src
? s
->src
: "(null string)");
3173 case 6: /* unused */
3174 case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */
3176 copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s",
3177 OSSwapLittleToHostInt32(hdr
->compression_type
), name
, s
->src
? s
->src
: "(null string)");
3180 s
->internal_flags
|= cfSawDecmpEA
;
3184 // If we have a copy intention stated, and the EA is to be ignored, we ignore it
3186 && xattr_preserve_for_intent(name
, s
->copyIntent
) == 0)
3189 s
->xattr_name
= strdup(name
);
3193 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3194 if (rv
== COPYFILE_QUIT
) {
3197 } else if (rv
== COPYFILE_SKIP
) {
3201 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
) < 0)
3204 if (error
== EPERM
&& strcmp(name
, XATTR_ROOT_INSTALLED_NAME
) == 0) {
3205 //Silently ignore if we fail to set XATTR_ROOT_INSTALLED_NAME
3209 else if (s
->statuscb
)
3213 if (s
->xattr_name
== NULL
)
3214 s
->xattr_name
= strdup(name
);
3215 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3216 if (rv
== COPYFILE_QUIT
)
3227 copyfile_warn("could not set attributes %s on destination file descriptor", name
);
3233 if (s
->xattr_name
== NULL
)
3234 s
->xattr_name
= strdup(name
);
3236 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3237 if (rv
== COPYFILE_QUIT
) {
3246 free((void *) xa_dataptr
);
3247 if (s
->xattr_name
) {
3248 free(s
->xattr_name
);
3249 s
->xattr_name
= NULL
;
3255 * API interface into getting data from the opaque data type.
3257 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
3267 case COPYFILE_STATE_SRC_FD
:
3268 *(int*)ret
= s
->src_fd
;
3270 case COPYFILE_STATE_DST_FD
:
3271 *(int*)ret
= s
->dst_fd
;
3273 case COPYFILE_STATE_SRC_FILENAME
:
3274 *(char**)ret
= s
->src
;
3276 case COPYFILE_STATE_DST_FILENAME
:
3277 *(char**)ret
= s
->dst
;
3279 case COPYFILE_STATE_QUARANTINE
:
3280 *(qtn_file_t
*)ret
= s
->qinfo
;
3283 case COPYFILE_STATE_STATS
:
3284 ret
= s
->stats
.global
;
3286 case COPYFILE_STATE_PROGRESS_CB
:
3287 ret
= s
->callbacks
.progress
;
3290 #ifdef COPYFILE_STATE_STATUS_CB
3291 case COPYFILE_STATE_STATUS_CB
:
3292 *(copyfile_callback_t
*)ret
= s
->statuscb
;
3294 case COPYFILE_STATE_STATUS_CTX
:
3295 *(void**)ret
= s
->ctx
;
3297 case COPYFILE_STATE_COPIED
:
3298 *(off_t
*)ret
= s
->totalCopied
;
3301 #ifdef COPYFILE_STATE_XATTRNAME
3302 case COPYFILE_STATE_XATTRNAME
:
3303 *(char**)ret
= s
->xattr_name
;
3306 #ifdef COPYFILE_STATE_INTENT
3307 case COPYFILE_STATE_INTENT
:
3308 *(xattr_operation_intent_t
*)ret
= s
->copyIntent
;
3311 case COPYFILE_STATE_WAS_CLONED
:
3312 *(bool *)ret
= s
->was_cloned
;
3323 * Public API for setting state data (remember that the state is
3324 * an opaque data type).
3326 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
3328 #define copyfile_set_string(DST, SRC) \
3330 if (SRC != NULL) { \
3331 DST = strdup((char *)SRC); \
3333 if (DST != NULL) { \
3348 case COPYFILE_STATE_SRC_FD
:
3349 s
->src_fd
= *(int*)thing
;
3351 case COPYFILE_STATE_DST_FD
:
3352 s
->dst_fd
= *(int*)thing
;
3354 case COPYFILE_STATE_SRC_FILENAME
:
3355 copyfile_set_string(s
->src
, thing
);
3357 case COPYFILE_STATE_DST_FILENAME
:
3358 copyfile_set_string(s
->dst
, thing
);
3360 case COPYFILE_STATE_QUARANTINE
:
3363 qtn_file_free(s
->qinfo
);
3366 if (*(qtn_file_t
*)thing
)
3367 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
3370 case COPYFILE_STATE_STATS
:
3371 s
->stats
.global
= thing
;
3373 case COPYFILE_STATE_PROGRESS_CB
:
3374 s
->callbacks
.progress
= thing
;
3377 #ifdef COPYFILE_STATE_STATUS_CB
3378 case COPYFILE_STATE_STATUS_CB
:
3379 s
->statuscb
= (copyfile_callback_t
)thing
;
3381 case COPYFILE_STATE_STATUS_CTX
:
3382 s
->ctx
= (void*)thing
;
3385 #ifdef COPYFILE_STATE_INTENT
3386 case COPYFILE_STATE_INTENT
:
3387 s
->copyIntent
= *(xattr_operation_intent_t
*)thing
;
3395 #undef copyfile_set_string
3400 * Make this a standalone program for testing purposes by
3401 * defining _COPYFILE_TEST.
3403 #ifdef _COPYFILE_TEST
3404 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
3406 struct {char *s
; int v
;} opts
[] = {
3407 COPYFILE_OPTION(ACL
)
3408 COPYFILE_OPTION(STAT
)
3409 COPYFILE_OPTION(XATTR
)
3410 COPYFILE_OPTION(DATA
)
3411 COPYFILE_OPTION(SECURITY
)
3412 COPYFILE_OPTION(METADATA
)
3413 COPYFILE_OPTION(ALL
)
3414 COPYFILE_OPTION(NOFOLLOW_SRC
)
3415 COPYFILE_OPTION(NOFOLLOW_DST
)
3416 COPYFILE_OPTION(NOFOLLOW
)
3417 COPYFILE_OPTION(EXCL
)
3418 COPYFILE_OPTION(MOVE
)
3419 COPYFILE_OPTION(UNLINK
)
3420 COPYFILE_OPTION(PACK
)
3421 COPYFILE_OPTION(UNPACK
)
3422 COPYFILE_OPTION(CHECK
)
3423 COPYFILE_OPTION(CLONE
)
3424 COPYFILE_OPTION(CLONE_FORCE
)
3425 COPYFILE_OPTION(VERBOSE
)
3426 COPYFILE_OPTION(RECURSIVE
)
3427 COPYFILE_OPTION(DEBUG
)
3428 COPYFILE_OPTION(CLONE
)
3429 COPYFILE_OPTION(CLONE_FORCE
)
3430 COPYFILE_OPTION(DATA_SPARSE
)
3434 int main(int c
, char *v
[])
3438 copyfile_state_t state
= NULL
;
3441 errx(1, "insufficient arguments");
3445 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
3447 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
3449 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
3456 if (flags
& COPYFILE_DEBUG
) {
3457 state
= copyfile_state_alloc();
3458 state
->debug
= 10; // Turn on all debug statements
3460 ret
= copyfile(v
[1], v
[2], state
, flags
);
3462 (void)copyfile_state_free(state
);
3469 * Apple Double Create
3471 * Create an Apple Double "._" file from a file's extented attributes
3473 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
3476 #define XATTR_MAXATTRLEN (16*1024*1024)
3480 Typical "._" AppleDouble Header File layout:
3481 ------------------------------------------------------------
3486 .-- AD ENTRY[0] Finder Info Entry (must be first)
3487 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
3489 | ///////////// Fixed Size Data (32 bytes)
3493 | ATTR ENTRY[1] --+--.
3494 | ATTR ENTRY[2] --+--+--.
3496 | ATTR ENTRY[N] --+--+--+--.
3497 | ATTR DATA 0 <-' | | |
3498 | //////////// | | |
3499 | ATTR DATA 1 <----' | |
3501 | ATTR DATA 2 <-------' |
3504 | ATTR DATA N <----------'
3506 | Attribute Free Space
3508 '----> RESOURCE FORK
3509 ///////////// Variable Sized Data
3518 ------------------------------------------------------------
3520 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
3521 stored as part of the Finder Info. The length in the Finder
3522 Info AppleDouble entry includes the length of the extended
3523 attribute header, attribute entries, and attribute data.
3528 * On Disk Data Structures
3530 * Note: Motorola 68K alignment and big-endian.
3532 * See RFC 1740 for additional information about the AppleDouble file format.
3536 #define ADH_MAGIC 0x00051607
3537 #define ADH_VERSION 0x00020000
3538 #define ADH_MACOSX "Mac OS X "
3541 * AppleDouble Entry ID's
3543 #define AD_DATA 1 /* Data fork */
3544 #define AD_RESOURCE 2 /* Resource fork */
3545 #define AD_REALNAME 3 /* File's name on home file system */
3546 #define AD_COMMENT 4 /* Standard Mac comment */
3547 #define AD_ICONBW 5 /* Mac black & white icon */
3548 #define AD_ICONCOLOR 6 /* Mac color icon */
3549 #define AD_UNUSED 7 /* Not used */
3550 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
3551 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
3552 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
3553 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
3554 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
3555 #define AD_AFPNAME 13 /* Short name on AFP server */
3556 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
3557 #define AD_AFPDIRID 15 /* AFP directory ID */
3558 #define AD_ATTRIBUTES AD_FINDERINFO
3561 #define ATTR_FILE_PREFIX "._"
3562 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
3564 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
3566 /* Implementation Limits */
3567 #define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */
3568 #define ATTR_MAX_NAME_LEN 128
3569 #define ATTR_MAX_HDR_SIZE (65536+18)
3572 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
3573 * size supported (including the attribute entries). All of
3574 * the attribute entries must reside within this limit.
3578 #define FINDERINFOSIZE 32
3580 typedef struct apple_double_entry
3582 u_int32_t type
; /* entry type: see list, 0 invalid */
3583 u_int32_t offset
; /* entry data offset from the beginning of the file. */
3584 u_int32_t length
; /* entry data length in bytes. */
3585 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
3588 typedef struct apple_double_header
3590 u_int32_t magic
; /* == ADH_MAGIC */
3591 u_int32_t version
; /* format version: 2 = 0x00020000 */
3592 u_int32_t filler
[4];
3593 u_int16_t numEntries
; /* number of entries which follow */
3594 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
3595 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
3596 u_int8_t pad
[2]; /* get better alignment inside attr_header */
3597 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
3600 /* Entries are aligned on 4 byte boundaries */
3601 typedef struct attr_entry
3603 u_int32_t offset
; /* file offset to data */
3604 u_int32_t length
; /* size of attribute data */
3606 u_int8_t namelen
; /* length of name including NULL termination char */
3607 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
3608 } __attribute__((aligned(2), packed
)) attr_entry_t
;
3612 /* Header + entries must fit into 64K */
3613 typedef struct attr_header
3615 apple_double_header_t appledouble
;
3616 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
3617 u_int32_t debug_tag
; /* for debugging == file id of owning file */
3618 u_int32_t total_size
; /* total size of attribute header + entries + data */
3619 u_int32_t data_start
; /* file offset to attribute data area */
3620 u_int32_t data_length
; /* length of attribute data area */
3621 u_int32_t reserved
[3];
3623 u_int16_t num_attrs
;
3624 } __attribute__((aligned(2), packed
)) attr_header_t
;
3626 /* Empty Resource Fork Header */
3627 /* This comes by way of xnu's vfs_xattr.c */
3628 typedef struct rsrcfork_header
{
3629 u_int32_t fh_DataOffset
;
3630 u_int32_t fh_MapOffset
;
3631 u_int32_t fh_DataLength
;
3632 u_int32_t fh_MapLength
;
3633 u_int8_t systemData
[112];
3634 u_int8_t appData
[128];
3635 u_int32_t mh_DataOffset
;
3636 u_int32_t mh_MapOffset
;
3637 u_int32_t mh_DataLength
;
3638 u_int32_t mh_MapLength
;
3640 u_int16_t mh_RefNum
;
3642 u_int8_t mh_InMemoryAttr
;
3645 u_int16_t typeCount
;
3646 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
3647 #define RF_FIRST_RESOURCE 256
3648 #define RF_NULL_MAP_LENGTH 30
3649 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
3651 static const rsrcfork_header_t empty_rsrcfork_header
= {
3652 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
3653 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
3655 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
3656 { RF_EMPTY_TAG
, }, // systemData
3658 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
3659 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
3661 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
3665 0, // mh_InMemoryAttr
3666 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
3667 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
3668 OSSwapHostToBigInt16(-1), // typeCount
3671 #define SWAP16(x) OSSwapBigToHostInt16(x)
3672 #define SWAP32(x) OSSwapBigToHostInt32(x)
3673 #define SWAP64(x) OSSwapBigToHostInt64(x)
3675 #define ATTR_ALIGN 3L /* Use four-byte alignment */
3677 #define ATTR_ENTRY_LENGTH(namelen) \
3678 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
3680 #define ATTR_NEXT(ae) \
3681 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
3683 #define XATTR_SECURITY_NAME "com.apple.acl.text"
3686 * Endian swap Apple Double header
3689 swap_adhdr(apple_double_header_t
*adh
)
3691 #if BYTE_ORDER == LITTLE_ENDIAN
3695 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
3697 adh
->magic
= SWAP32 (adh
->magic
);
3698 adh
->version
= SWAP32 (adh
->version
);
3699 adh
->numEntries
= SWAP16 (adh
->numEntries
);
3701 for (i
= 0; i
< count
; i
++)
3703 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
3704 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
3705 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
3713 * Endian swap a single attr_entry_t
3716 swap_attrhdr_entry(attr_entry_t
*ae
)
3718 #if BYTE_ORDER == LITTLE_ENDIAN
3719 ae
->offset
= SWAP32 (ae
->offset
);
3720 ae
->length
= SWAP32 (ae
->length
);
3721 ae
->flags
= SWAP16 (ae
->flags
);
3728 * For a validated/endian swapped attr_header_t*
3729 * ah, endian swap all of the entries.
3732 swap_attrhdr_entries(attr_header_t
*ah
)
3734 #if BYTE_ORDER == LITTLE_ENDIAN
3737 attr_entry_t
*entry
;
3740 /* If we're in copyfile_pack, num_args is native endian,
3741 * if we're in _unpack, num_args is big endian. Use
3742 * the magic number to test for endianess.
3744 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
3746 entry
= (attr_entry_t
*)(&ah
[1]);
3747 for (i
= 0; i
< count
; i
++) {
3748 next
= ATTR_NEXT(entry
);
3749 swap_attrhdr_entry(entry
);
3758 * Endian swap extended attributes header
3761 swap_attrhdr(attr_header_t
*ah
)
3763 #if BYTE_ORDER == LITTLE_ENDIAN
3764 ah
->magic
= SWAP32 (ah
->magic
);
3765 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
3766 ah
->total_size
= SWAP32 (ah
->total_size
);
3767 ah
->data_start
= SWAP32 (ah
->data_start
);
3768 ah
->data_length
= SWAP32 (ah
->data_length
);
3769 ah
->flags
= SWAP16 (ah
->flags
);
3770 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
3776 static const u_int32_t emptyfinfo
[8] = {0};
3779 * Given an Apple Double file in src, turn it into a
3780 * normal file (possibly with multiple forks, EAs, and
3783 static int copyfile_unpack(copyfile_state_t s
)
3786 void * buffer
, * endptr
, * dataptr
= NULL
;
3787 apple_double_header_t
*adhdr
;
3791 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
3792 hdrsize
= (ssize_t
)s
->sb
.st_size
;
3794 hdrsize
= ATTR_MAX_HDR_SIZE
;
3796 buffer
= calloc(1, hdrsize
);
3797 if (buffer
== NULL
) {
3798 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize
);
3802 endptr
= (char*)buffer
+ hdrsize
;
3804 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
3808 copyfile_debug(1, "pread returned: %zd", bytes
);
3812 if (bytes
< hdrsize
)
3815 "pread couldn't read entire header: %d of %d",
3816 (int)bytes
, (int)s
->sb
.st_size
);
3820 adhdr
= (apple_double_header_t
*)buffer
;
3823 * Check for Apple Double file.
3825 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
3826 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
3827 SWAP32(adhdr
->version
) != ADH_VERSION
||
3828 SWAP16(adhdr
->numEntries
) != 2 ||
3829 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
3831 if (COPYFILE_VERBOSE
& s
->flags
)
3832 copyfile_warn("Not a valid Apple Double header");
3839 * Remove any extended attributes on the target.
3842 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
3844 char *namebuf
, *name
;
3846 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
3851 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
3854 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
3855 (void)fremovexattr(s
->dst_fd
, name
, 0);
3861 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
3866 * Extract the extended attributes.
3869 * This assumes that the data is already in memory (not
3870 * the case when there are lots of attributes or one of
3871 * the attributes is very large.
3873 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
3875 attr_header_t
*attrhdr
;
3876 attr_entry_t
*entry
;
3880 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
3881 copyfile_warn("bad attribute header: %zu < %zu", hdrsize
, sizeof(attr_header_t
));
3886 attrhdr
= (attr_header_t
*)buffer
;
3887 swap_attrhdr(attrhdr
);
3888 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
3890 if (COPYFILE_VERBOSE
& s
->flags
)
3891 copyfile_warn("bad attribute header");
3895 count
= attrhdr
->num_attrs
;
3896 entry
= (attr_entry_t
*)&attrhdr
[1];
3898 for (i
= 0; i
< count
; i
++)
3901 * First we do some simple sanity checking.
3902 * +) See if entry is within the buffer's range;
3904 * +) Check the attribute name length; if it's longer than the
3905 * maximum, we truncate it down. (We could error out as well;
3906 * I'm not sure which is the better way to go here.)
3908 * +) If, given the name length, it goes beyond the end of
3909 * the buffer, error out.
3911 * +) If the last byte isn't a NUL, make it a NUL. (Since we
3912 * truncated the name length above, we truncate the name here.)
3914 * +) If entry->offset is so large that it causes dataptr to
3915 * go beyond the end of the buffer -- or, worse, so large that
3916 * it wraps around! -- we error out.
3918 * +) If entry->length would cause the entry to go beyond the
3919 * end of the buffer (or, worse, wrap around to before it),
3920 * *or* if the length is larger than the hdrsize, we error out.
3921 * (An explanation of that: what we're checking for there is
3922 * the small range of values such that offset+length would cause
3923 * it to go beyond endptr, and then wrap around past buffer. We
3924 * care about this because we are passing entry->length down to
3925 * fgetxattr() below, and an erroneously large value could cause
3926 * problems there. By making sure that it's less than hdrsize,
3927 * which has already been sanity-checked above, we're safe.
3928 * That may mean that the check against < buffer is unnecessary.)
3930 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
3931 if (COPYFILE_VERBOSE
& s
->flags
)
3932 copyfile_warn("Incomplete or corrupt attribute entry");
3938 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
3939 if (COPYFILE_VERBOSE
& s
->flags
)
3940 copyfile_warn("Incomplete or corrupt attribute entry");
3947 * Endian swap the entry we're looking at. Previously
3948 * we did this swap as part of swap_attrhdr, but that
3949 * allowed a maliciously constructed file to overrun
3950 * our allocation. Instead do the swap after we've verified
3951 * the entry struct is within the buffer's range.
3953 swap_attrhdr_entry(entry
);
3955 if (entry
->namelen
< 2) {
3956 if (COPYFILE_VERBOSE
& s
->flags
)
3957 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
3963 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
3964 if (COPYFILE_VERBOSE
& s
->flags
)
3965 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
3971 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
3972 if (COPYFILE_VERBOSE
& s
->flags
)
3973 copyfile_warn("Incomplete or corrupt attribute entry");
3979 /* Because namelen includes the NUL, we check one byte back */
3980 if (entry
->name
[entry
->namelen
-1] != 0) {
3981 if (COPYFILE_VERBOSE
& s
->flags
)
3982 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3988 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3989 entry
->name
, entry
->length
, entry
->offset
);
3992 dataptr
= (char *)attrhdr
+ entry
->offset
;
3994 if (dataptr
> endptr
|| dataptr
< buffer
) {
3995 copyfile_debug(1, "Entry %d overflows: offset = %u", i
, entry
->offset
);
3997 s
->err
= EINVAL
; /* Invalid buffer */
4001 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
4002 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
4003 (entry
->length
> (size_t)hdrsize
)) {
4004 if (COPYFILE_VERBOSE
& s
->flags
)
4005 copyfile_warn("Incomplete or corrupt attribute entry");
4006 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
4007 i
, entry
->offset
, entry
->length
);
4009 s
->err
= EINVAL
; /* Invalid buffer */
4014 dataptr
= malloc(entry
->length
);
4015 if (dataptr
== NULL
) {
4016 copyfile_debug(1, "no memory for %u bytes\n", entry
->length
);
4021 if (pread(s
->src_fd
, dataptr
, entry
->length
, entry
->offset
) != (ssize_t
)entry
->length
) {
4022 copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry
->length
, entry
->offset
);
4029 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
4031 qtn_file_t tqinfo
= NULL
;
4033 if (s
->qinfo
== NULL
)
4035 tqinfo
= qtn_file_alloc();
4039 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
4041 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
4042 qtn_file_free(tqinfo
);
4054 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
4056 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
4059 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
4060 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4061 s
->xattr_name
= NULL
;
4062 if (rv
== COPYFILE_QUIT
) {
4063 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
4067 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
4072 if (tqinfo
&& !s
->qinfo
)
4074 qtn_file_free(tqinfo
);
4077 /* Look for ACL data */
4078 else if (strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
4083 char *tcp
= dataptr
;
4085 if (entry
->length
== 0) {
4086 /* Not sure how we got here, but we had one case
4087 * where it was 0. In a normal EA, we can have a 0-byte
4088 * payload. That means nothing in this case, so we'll
4089 * simply skip the EA.
4095 * acl_from_text() requires a NUL-terminated string. The ACL EA,
4096 * however, may not be NUL-terminated. So in that case, we need to
4097 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
4099 if (tcp
[entry
->length
- 1] != 0) {
4100 char *tmpstr
= malloc(entry
->length
+ 1);
4101 if (tmpstr
== NULL
) {
4105 // Can't use strlcpy here: tcp is not NUL-terminated!
4106 memcpy(tmpstr
, tcp
, entry
->length
);
4107 tmpstr
[entry
->length
] = 0;
4108 acl
= acl_from_text(tmpstr
);
4111 acl
= acl_from_text(tcp
);
4118 if ((fsec_tmp
= filesec_init()) == NULL
)
4120 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
4122 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
4125 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
4127 if (errno
== ENOTSUP
)
4129 if (retry
&& !copyfile_unset_acl(s
))
4135 copyfile_warn("setting security information");
4141 filesec_free(fsec_tmp
);
4148 /* And, finally, everything else */
4151 if (s
->copyIntent
||
4152 xattr_preserve_for_intent((char*)entry
->name
, s
->copyIntent
) == 1) {
4155 s
->xattr_name
= strdup((char*)entry
->name
);
4157 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4158 if (s
->xattr_name
) {
4159 free(s
->xattr_name
);
4160 s
->xattr_name
= NULL
;
4162 if (rv
== COPYFILE_QUIT
) {
4168 //Silently ignore failure to set XATTR_ROOT_INSTALLED_NAME
4169 int result
= fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0);
4170 int errorcode
= errno
;
4171 if (result
== -1 && !(errorcode
== EPERM
&&
4172 strcmp((char*)entry
->name
, XATTR_ROOT_INSTALLED_NAME
) == 0)) {
4174 if (COPYFILE_VERBOSE
& s
->flags
)
4175 copyfile_warn("error %d setting attribute %s", errorcode
, entry
->name
);
4179 s
->xattr_name
= strdup((char*)entry
->name
);
4180 rv
= (s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4181 if (s
->xattr_name
) {
4182 free(s
->xattr_name
);
4183 s
->xattr_name
= NULL
;
4185 if (rv
== COPYFILE_QUIT
) {
4193 } else if (s
->statuscb
) {
4196 s
->xattr_name
= strdup((char*)entry
->name
);
4197 s
->totalCopied
= entry
->length
;
4198 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4199 if (s
->xattr_name
) {
4200 free(s
->xattr_name
);
4201 s
->xattr_name
= NULL
;
4203 if (rv
== COPYFILE_QUIT
) {
4217 entry
= ATTR_NEXT(entry
);
4222 * Extract the Finder Info.
4224 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
4229 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
4233 enum { kFinderInvisibleMask
= 1 << 14 };
4235 newFinfo
= (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
;
4236 fFlags
= (uint16_t*)&newFinfo
[8];
4237 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
4240 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
4241 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4242 s
->xattr_name
= NULL
;
4243 if (rv
== COPYFILE_QUIT
) {
4247 } else if (rv
== COPYFILE_SKIP
) {
4251 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
4255 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
4256 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4257 s
->xattr_name
= NULL
;
4258 if (rv
== COPYFILE_QUIT
) {
4265 } else if (s
->statuscb
) {
4267 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
4268 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4269 s
->xattr_name
= NULL
;
4270 if (rv
== COPYFILE_QUIT
) {
4276 if (SWAP16(*fFlags
) & kFinderInvisibleMask
)
4277 s
->internal_flags
|= cfMakeFileInvisible
;
4282 * Extract the Resource Fork.
4284 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
4285 adhdr
->entries
[1].length
> 0)
4287 void * rsrcforkdata
= NULL
;
4291 struct attrlist attrlist
;
4293 /* Order of these structs matters for setattrlist. */
4294 struct timespec mod_time
;
4295 struct timespec acc_time
;
4298 length
= adhdr
->entries
[1].length
;
4299 offset
= adhdr
->entries
[1].offset
;
4300 rsrcforkdata
= malloc(length
);
4302 if (rsrcforkdata
== NULL
) {
4303 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
4309 if (fstat(s
->dst_fd
, &sb
) < 0)
4311 copyfile_debug(1, "couldn't stat destination file");
4316 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
4317 if (bytes
< (ssize_t
)length
)
4321 copyfile_debug(1, "couldn't read resource fork");
4326 "couldn't read resource fork (only read %d bytes of %d)",
4327 (int)bytes
, (int)length
);
4334 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
4335 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4336 s
->xattr_name
= NULL
;
4337 if (rv
== COPYFILE_QUIT
) {
4343 } else if (rv
== COPYFILE_SKIP
) {
4347 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
4351 * For filesystems that do not natively support named attributes,
4352 * the kernel creates an AppleDouble file that -- for compatabilty
4353 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
4354 * structure that says there are no resources. So, if fsetxattr has
4355 * failed, and the resource fork is that empty structure, *and* the
4356 * target file is a directory, then we do nothing with it.
4358 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
4359 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
4360 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
4361 copyfile_debug(2, "not setting empty resource fork on directory");
4367 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
4368 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4369 s
->xattr_name
= NULL
;
4370 if (rv
== COPYFILE_CONTINUE
) {
4375 copyfile_debug(1, "error %d setting resource fork attribute", error
);
4378 } else if (s
->statuscb
) {
4380 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
4381 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4382 s
->xattr_name
= NULL
;
4383 if (rv
== COPYFILE_QUIT
) {
4391 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
4392 XATTR_RESOURCEFORK_NAME
, (int)length
);
4394 if (!(s
->flags
& COPYFILE_STAT
))
4396 /* Try to set m/atimes using setattrlist(), for nanosecond precision. */
4397 memset(&attrlist
, 0, sizeof(attrlist
));
4398 attrlist
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
4399 attrlist
.commonattr
= ATTR_CMN_MODTIME
| ATTR_CMN_ACCTIME
;
4400 ma_times
.mod_time
= sb
.st_mtimespec
;
4401 ma_times
.acc_time
= sb
.st_atimespec
;
4402 if (fsetattrlist(s
->dst_fd
, &attrlist
, &ma_times
, sizeof(ma_times
), 0) != 0) {
4403 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
4411 if (COPYFILE_STAT
& s
->flags
)
4413 error
= copyfile_stat(s
);
4416 if (buffer
) free(buffer
);
4417 if (dataptr
) free(dataptr
);
4421 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
4424 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
4425 size_t qlen
= sizeof(qbuf
);
4427 if (s
->qinfo
== NULL
)
4433 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
4439 *buf
= malloc(qlen
);
4442 memcpy(*buf
, qbuf
, qlen
);
4449 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
4455 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
4457 if (errno
!= ENOENT
)
4460 if (COPYFILE_VERBOSE
& s
->flags
)
4461 copyfile_warn("getting acl");
4467 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
4470 * acl_to_text() doesn't include the NUL at the endo
4471 * in it's count (*len). It does, however, promise to
4472 * return a valid C string, so we need to up the count
4476 *buf
= malloc(*len
);
4478 memcpy(*buf
, acl_text
, *len
);
4483 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
4490 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
4493 char *databuf
= NULL
;
4498 * do COPYFILE_COPY_XATTR here; no need to
4499 * the work if we want to skip.
4506 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
4508 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4509 s
->xattr_name
= NULL
;
4510 if (rv
== COPYFILE_SKIP
) {
4514 if (rv
== COPYFILE_QUIT
) {
4520 /* Get the resource fork size */
4521 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
4523 if (COPYFILE_VERBOSE
& s
->flags
)
4524 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
4528 if (datasize
> INT_MAX
) {
4536 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
4539 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4540 s
->xattr_name
= NULL
;
4541 if (rv
== COPYFILE_QUIT
) {
4547 if ((databuf
= malloc(datasize
)) == NULL
)
4549 copyfile_warn("malloc");
4554 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
4556 if (COPYFILE_VERBOSE
& s
->flags
)
4557 copyfile_warn("couldn't read entire resource fork");
4562 /* Write the resource fork to disk. */
4563 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
4565 if (COPYFILE_VERBOSE
& s
->flags
)
4566 copyfile_warn("couldn't write resource fork");
4571 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4572 if (rv
== COPYFILE_QUIT
) {
4577 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
4578 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
4579 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
4582 if (ret
== -1 && s
->statuscb
)
4585 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4586 if (rv
== COPYFILE_CONTINUE
)
4589 if (s
->xattr_name
) {
4590 s
->xattr_name
= NULL
;
4597 * Do status callback here
4598 * If ret == -1, then error callback
4604 * The opposite of copyfile_unpack(), obviously.
4606 static int copyfile_pack(copyfile_state_t s
)
4608 char *attrnamebuf
= NULL
, *endnamebuf
;
4609 void *databuf
= NULL
;
4610 attr_header_t
*filehdr
, *endfilehdr
;
4611 attr_entry_t
*entry
;
4612 ssize_t listsize
= 0;
4618 int hasrsrcfork
= 0;
4620 int seenq
= 0; // Have we seen any quarantine info already?
4622 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_HDR_SIZE
);
4624 if (filehdr
== NULL
) {
4628 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_HDR_SIZE
);
4631 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
4632 if (attrnamebuf
== NULL
) {
4636 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
4640 * Fill in the Apple Double Header defaults.
4642 filehdr
->appledouble
.magic
= ADH_MAGIC
;
4643 filehdr
->appledouble
.version
= ADH_VERSION
;
4644 filehdr
->appledouble
.numEntries
= 2;
4645 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
4646 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)__builtin_offsetof(apple_double_header_t
, finfo
);
4647 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
4648 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
4649 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)__builtin_offsetof(apple_double_header_t
, pad
);
4650 filehdr
->appledouble
.entries
[1].length
= 0;
4651 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
4654 * Fill in the initial Attribute Header.
4656 filehdr
->magic
= ATTR_HDR_MAGIC
;
4657 filehdr
->debug_tag
= 0;
4658 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
4661 * Collect the attribute names.
4663 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
4666 * Test if there are acls to copy
4668 if (COPYFILE_ACL
& s
->flags
)
4670 acl_t temp_acl
= NULL
;
4671 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
4673 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
4676 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
4677 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
4678 endnamebuf
= attrnamebuf
+ offset
;
4684 if (COPYFILE_XATTR
& s
->flags
)
4686 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
4687 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
4689 copyfile_debug(2, "no extended attributes found (%d)", errno
);
4691 if (listsize
> left
)
4693 copyfile_debug(1, "extended attribute list too long");
4697 endnamebuf
= attrnamebuf
+ offset
+ (listsize
> 0 ? listsize
: 0);
4698 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
4704 sort_xattrname_list(attrnamebuf
, endnamebuf
- attrnamebuf
);
4706 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
4708 namelen
= strlen(nameptr
) + 1;
4709 /* Skip over FinderInfo or Resource Fork names */
4710 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
4711 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
4714 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
4718 /* The system should prevent this from happening, but... */
4719 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
4720 namelen
= XATTR_MAXNAMELEN
+ 1;
4722 if (s
->copyIntent
&&
4723 xattr_preserve_for_intent(nameptr
, s
->copyIntent
) == 0) {
4725 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
4726 memmove(nameptr
, nameptr
+ namelen
, amt
);
4727 endnamebuf
-= namelen
;
4728 /* Set namelen to 0 so continue doesn't miss names */
4735 char eaname
[namelen
];
4736 bcopy(nameptr
, eaname
, namelen
);
4737 eaname
[namelen
- 1] = 0; // Just to be sure!
4738 s
->xattr_name
= eaname
;
4739 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4740 s
->xattr_name
= NULL
;
4741 if (rv
== COPYFILE_QUIT
) {
4745 } else if (rv
== COPYFILE_SKIP
) {
4746 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
4747 memmove(nameptr
, nameptr
+ namelen
, amt
);
4748 endnamebuf
-= namelen
;
4749 /* Set namelen to 0 so continue doesn't miss names */
4754 entry
->namelen
= namelen
;
4756 if (nameptr
+ namelen
> endnamebuf
) {
4761 bcopy(nameptr
, &entry
->name
[0], namelen
);
4762 copyfile_debug(2, "copied name [%s]", entry
->name
);
4764 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
4765 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
4767 if ((void*)entry
>= (void*)endfilehdr
) {
4772 /* Update the attributes header. */
4773 filehdr
->num_attrs
++;
4774 filehdr
->data_start
+= (u_int32_t
)entrylen
;
4779 * If we have any quarantine data, we always pack it.
4780 * But if we've already got it in the EA list, don't put it in again.
4782 if (s
->qinfo
&& !seenq
)
4784 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
4785 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
4786 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
4791 * Collect the attribute data.
4793 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
4795 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
+ 1)
4797 namelen
= strlen(nameptr
);
4799 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
4800 copyfile_pack_acl(s
, &databuf
, &datasize
);
4801 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
4803 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
4805 /* Check for Finder Info. */
4806 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
4811 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
4812 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4813 s
->xattr_name
= NULL
;
4814 if (rv
== COPYFILE_QUIT
)
4816 s
->xattr_name
= NULL
;
4821 else if (rv
== COPYFILE_SKIP
)
4823 s
->xattr_name
= NULL
;
4827 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4828 s
->xattr_name
= NULL
;
4829 if (rv
== COPYFILE_QUIT
)
4836 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
4841 s
->xattr_name
= strdup(nameptr
);
4842 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4843 if (s
->xattr_name
) {
4844 free(s
->xattr_name
);
4845 s
->xattr_name
= NULL
;
4847 if (rv
== COPYFILE_QUIT
) {
4852 if (COPYFILE_VERBOSE
& s
->flags
)
4853 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4854 } else if (datasize
!= 32)
4856 if (COPYFILE_VERBOSE
& s
->flags
)
4857 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
4860 if (COPYFILE_VERBOSE
& s
->flags
)
4861 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
4862 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
4865 s
->xattr_name
= strdup(nameptr
);
4866 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4867 if (s
->xattr_name
) {
4868 free(s
->xattr_name
);
4869 s
->xattr_name
= NULL
;
4871 if (rv
== COPYFILE_QUIT
) {
4877 continue; /* finder info doesn't have an attribute entry */
4879 /* Check for Resource Fork. */
4880 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
4886 /* Just a normal attribute. */
4890 s
->xattr_name
= strdup(nameptr
);
4892 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4893 if (s
->xattr_name
) {
4894 free(s
->xattr_name
);
4895 s
->xattr_name
= NULL
;
4898 * Due to the nature of the packed file, we can't skip at this point.
4900 if (rv
== COPYFILE_QUIT
)
4907 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
4912 if (COPYFILE_VERBOSE
& s
->flags
)
4913 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4917 s
->xattr_name
= strdup(nameptr
);
4918 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4919 if (s
->xattr_name
) {
4920 free(s
->xattr_name
);
4921 s
->xattr_name
= NULL
;
4923 if (rv
== COPYFILE_QUIT
)
4932 if (datasize
> XATTR_MAXATTRLEN
)
4934 if (COPYFILE_VERBOSE
& s
->flags
)
4935 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
4938 databuf
= malloc(datasize
);
4939 if (databuf
== NULL
) {
4943 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
4946 s
->xattr_name
= strdup(nameptr
);
4947 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4948 if (s
->xattr_name
) {
4949 free(s
->xattr_name
);
4950 s
->xattr_name
= NULL
;
4952 if (rv
== COPYFILE_QUIT
) {
4960 entry
->length
= (u_int32_t
)datasize
;
4961 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
4963 filehdr
->data_length
+= (u_int32_t
)datasize
;
4967 * This assumes that the data is fits in memory (not
4968 * the case when there are lots of attributes or one of
4969 * the attributes is very large.
4971 if (entry
->offset
> ATTR_MAX_SIZE
||
4972 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
4975 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
4978 if (pwrite(s
->dst_fd
, databuf
, datasize
, entry
->offset
) != datasize
) {
4984 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
4986 /* bump to next entry */
4987 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
4988 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
4991 /* Now we know where the resource fork data starts. */
4992 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
4994 /* We also know the size of the "Finder Info entry. */
4995 filehdr
->appledouble
.entries
[0].length
=
4996 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
4998 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
5000 /* Copy Resource Fork. */
5001 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
5004 /* Write the header to disk. */
5005 datasize
= filehdr
->data_start
;
5007 swap_adhdr(&filehdr
->appledouble
);
5008 swap_attrhdr(filehdr
);
5009 swap_attrhdr_entries(filehdr
);
5011 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
5013 if (COPYFILE_VERBOSE
& s
->flags
)
5014 copyfile_warn("couldn't write file header");
5019 if (filehdr
) free(filehdr
);
5020 if (attrnamebuf
) free(attrnamebuf
);
5025 return copyfile_stat(s
);