2 * Copyright (c) 2004-2010 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(void *x
, int y
) { return -1; }
65 static int qtn_file_init_with_path(void *x
, const char *path
) { return -1; }
66 static int qtn_file_init_with_data(void *x
, const void *data
, size_t len
) { return -1; }
67 static void qtn_file_free(void *x
) { return; }
68 static int qtn_file_apply_to_fd(void *x
, int y
) { return 0; }
69 static char *qtn_error(int x
) { return NULL
; }
70 static int qtn_file_to_data(void *x
, char *y
, size_t z
) { return -1; }
71 static void *qtn_file_clone(void *x
) { return NULL
; }
72 static uint32_t qtn_file_get_flags(void *x
) { return 0; }
73 static int qtn_file_set_flags(void *x
, 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 enum cfInternalFlags
{
83 cfDelayAce
= 1 << 0, /* set if ACE shouldn't be set until post-order traversal */
84 cfMakeFileInvisible
= 1 << 1, /* set if kFinderInvisibleMask is on src */
85 cfSawDecmpEA
= 1 << 2, /* set if we've seen a com.apple.decmpfs xattr */
86 cfSrcProtSupportValid
= 1 << 3, /* set if cfSrcSupportsCProtect is valid */
87 cfSrcSupportsCProtect
= 1 << 4, /* set if src supports MNT_CPROTECT */
88 cfDstProtSupportValid
= 1 << 5, /* set if cfDstSupportsCProtect is valid */
89 cfDstSupportsCProtect
= 1 << 6, /* set if dst supports MNT_CPROTECT */
92 #define COPYFILE_MNT_CPROTECT_MASK (cfSrcProtSupportValid | cfSrcSupportsCProtect | cfDstProtSupportValid | cfDstSupportsCProtect)
95 * The state structure keeps track of
96 * the source filename, the destination filename, their
97 * associated file-descriptors, the stat information for the
98 * source file, the security information for the source file,
99 * the flags passed in for the copy, a pointer to place statistics
100 * (not currently implemented), debug flags, and a pointer to callbacks
101 * (not currently implemented).
103 struct _copyfile_state
111 copyfile_flags_t flags
;
112 unsigned int internal_flags
;
115 copyfile_callback_t statuscb
;
117 qtn_file_t qinfo
; /* Quarantine information -- probably NULL */
118 filesec_t original_fsec
;
119 filesec_t permissive_fsec
;
123 xattr_operation_intent_t copyIntent
;
127 #define GET_PROT_CLASS(fd) fcntl((fd), F_GETPROTECTIONCLASS)
128 #define SET_PROT_CLASS(fd, prot_class) fcntl((fd), F_SETPROTECTIONCLASS, (prot_class))
132 #define _ACL_ENTRY_MAGIC 0xac1ac101
134 guid_t ae_applicable
;
141 struct acl_entry *__t = (struct acl_entry*)(ace); \
142 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
147 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
148 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
152 acl_compare_permset_np(acl_permset_t p1
, acl_permset_t p2
)
154 struct pm
{ u_int32_t ap_perms
; } *ps1
, *ps2
;
155 ps1
= (struct pm
*) p1
;
156 ps2
= (struct pm
*) p2
;
158 return ((ps1
->ap_perms
== ps2
->ap_perms
) ? 1 : 0);
163 doesdecmpfs(int fd
) {
164 #ifdef DECMPFS_XATTR_NAME
166 struct attrlist attrs
;
167 char volroot
[MAXPATHLEN
+ 1];
171 vol_capabilities_attr_t volAttrs
;
174 (void)fstatfs(fd
, &sfs
);
175 strlcpy(volroot
, sfs
.f_mntonname
, sizeof(volroot
));
177 memset(&attrs
, 0, sizeof(attrs
));
178 attrs
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
179 attrs
.volattr
= ATTR_VOL_CAPABILITIES
;
181 rv
= getattrlist(volroot
, &attrs
, &volattrs
, sizeof(volattrs
), 0);
184 (volattrs
.volAttrs
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
) &&
185 (volattrs
.volAttrs
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
)) {
193 does_copy_protection(int fd
)
197 if (fstatfs(fd
, &sfs
) == -1)
200 return ((sfs
.f_flags
& MNT_CPROTECT
) == MNT_CPROTECT
);
204 sort_xattrname_list(void *start
, size_t length
)
211 /* If it's not a proper C string at the end, don't do anything */
212 if (((char*)start
)[length
] != 0)
215 * In order to sort the list of names, we need to
216 * make a list of pointers to strings. To do that,
217 * we need to run through the buffer, and find the
218 * beginnings of strings.
220 nel
= 10; // Most files don't have many EAs
221 ptrs
= (char**)calloc(nel
, sizeof(char*));
228 char *curPtr
= start
;
229 while (curPtr
< (char*)start
+ length
) {
230 printf("%s\n", curPtr
);
231 curPtr
+= strlen(curPtr
) + 1;
236 tmp
= ptrs
[indx
++] = (char*)start
;
238 while (tmp
= memchr(tmp
, 0, ((char*)start
+ length
) - tmp
)) {
241 ptrs
= realloc(ptrs
, sizeof(char**) * nel
);
245 ptrs
[indx
++] = ++tmp
;
248 printf("Unsorted:\n");
249 for (nel
= 0; nel
< indx
-1; nel
++) {
250 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
253 qsort_b(ptrs
, indx
-1, sizeof(char*), ^(const void *left
, const void *right
) {
255 char *lstr
= *(char**)left
, *rstr
= *(char**)right
;
256 rv
= strcmp(lstr
, rstr
);
261 for (nel
= 0; nel
< indx
-1; nel
++) {
262 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
266 * Now that it's sorted, we need to make a copy, so we can
267 * move the strings around into the new order. Then we
268 * copy that on top of the old buffer, and we're done.
270 char *copy
= malloc(length
);
275 for (i
= 0; i
< indx
-1; i
++) {
276 size_t len
= strlen(ptrs
[i
]);
277 memcpy(curPtr
, ptrs
[i
], len
+1);
280 memcpy(start
, copy
, length
);
291 * Internally, the process is broken into a series of
294 static int copyfile_open (copyfile_state_t
);
295 static int copyfile_close (copyfile_state_t
);
296 static int copyfile_data (copyfile_state_t
);
297 static int copyfile_stat (copyfile_state_t
);
298 static int copyfile_security (copyfile_state_t
);
299 static int copyfile_xattr (copyfile_state_t
);
300 static int copyfile_pack (copyfile_state_t
);
301 static int copyfile_unpack (copyfile_state_t
);
303 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
304 static filesec_t
copyfile_fix_perms(copyfile_state_t
, filesec_t
*);
305 static int copyfile_preamble(copyfile_state_t
*s
, copyfile_flags_t flags
);
306 static int copyfile_internal(copyfile_state_t state
, copyfile_flags_t flags
);
307 static int copyfile_unset_posix_fsec(filesec_t
);
308 static int copyfile_quarantine(copyfile_state_t
);
310 #define COPYFILE_DEBUG (1<<31)
311 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
313 // These macros preserve the value of errno.
314 #ifndef _COPYFILE_TEST
315 # define copyfile_warn(str, ...) \
317 errno_t _errsv = errno; \
318 syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__); \
321 # define copyfile_debug(d, str, ...) \
323 if (s && (d <= s->debug)) {\
324 errno_t _errsv = errno; \
325 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
330 #define copyfile_warn(str, ...) \
332 errno_t _errsv = errno; \
333 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : ""); \
336 # define copyfile_debug(d, str, ...) \
338 if (s && (d <= s->debug)) {\
339 errno_t _errsv = errno; \
340 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
346 static int copyfile_quarantine(copyfile_state_t s
)
349 if (s
->qinfo
== NULL
)
352 s
->qinfo
= qtn_file_alloc();
353 if (s
->qinfo
== NULL
)
358 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
360 qtn_file_free(s
->qinfo
);
371 add_uberace(acl_t
*acl
)
374 acl_permset_t permset
;
377 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
381 * First, we create an entry, and give it the special name
382 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
383 * After that, we clear out all the permissions in it, and
384 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
385 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
386 * the functionality, and put this into the ACL.
388 if (acl_create_entry_np(acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
390 if (acl_get_permset(entry
, &permset
) == -1) {
391 copyfile_warn("acl_get_permset");
394 if (acl_clear_perms(permset
) == -1) {
395 copyfile_warn("acl_clear_permset");
398 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1) {
399 copyfile_warn("add ACL_WRITE_DATA");
402 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1) {
403 copyfile_warn("add ACL_WRITE_ATTRIBUTES");
406 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1) {
407 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES");
410 if (acl_add_perm(permset
, ACL_APPEND_DATA
) == -1) {
411 copyfile_warn("add ACL_APPEND_DATA");
414 if (acl_add_perm(permset
, ACL_WRITE_SECURITY
) == -1) {
415 copyfile_warn("add ACL_WRITE_SECURITY");
418 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1) {
419 copyfile_warn("set ACL_EXTENDED_ALLOW");
423 if(acl_set_permset(entry
, permset
) == -1) {
424 copyfile_warn("acl_set_permset");
427 if(acl_set_qualifier(entry
, qual
) == -1) {
428 copyfile_warn("acl_set_qualifier");
438 is_uberace(acl_entry_t ace
)
441 acl_permset_t perms
, tperms
;
448 // Who am I, and who is the ACE for?
449 mbr_uid_to_uuid(geteuid(), myuuid
);
450 qual
= (guid_t
*)acl_get_qualifier(ace
);
452 // Need to create a temporary acl, so I can get the uberace template.
458 if (acl_get_entry(tacl
, ACL_FIRST_ENTRY
, &tentry
) != 0) {
461 acl_get_permset(tentry
, &tperms
);
464 acl_get_tag_type(ace
, &tag
);
465 acl_get_permset(ace
, &perms
);
467 if (tag
== ACL_EXTENDED_ALLOW
&&
468 (memcmp(qual
, myuuid
, sizeof(myuuid
)) == 0) &&
469 acl_compare_permset_np(tperms
, perms
))
484 remove_uberace(int fd
, struct stat
*sbuf
)
486 filesec_t fsec
= NULL
;
491 fsec
= filesec_init();
496 if (fstatx_np(fd
, &sb
, fsec
) != 0) {
497 if (errno
== ENOTSUP
)
502 if (filesec_get_property(fsec
, FILESEC_ACL
, &acl
) != 0) {
506 if (acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
) == 0) {
507 if (is_uberace(entry
))
509 mode_t m
= sbuf
->st_mode
& ~S_IFMT
;
511 if (acl_delete_entry(acl
, entry
) != 0 ||
512 filesec_set_property(fsec
, FILESEC_ACL
, &acl
) != 0 ||
513 filesec_set_property(fsec
, FILESEC_MODE
, &m
) != 0 ||
514 fchmodx_np(fd
, fsec
) != 0)
527 fchmod(fd
, sbuf
->st_mode
& ~S_IFMT
);
532 reset_security(copyfile_state_t s
)
534 /* If we haven't reset the file security information
535 * (COPYFILE_SECURITY is not set in flags)
536 * restore back the permissions the file had originally
538 * One of the reasons this seems so complicated is that
539 * it is partially at odds with copyfile_security().
541 * Simplisticly, we are simply trying to make sure we
542 * only copy what was requested, and that we don't stomp
543 * on what wasn't requested.
546 #ifdef COPYFILE_RECURSIVE
547 if (s
->dst_fd
> -1) {
550 if (s
->src_fd
> -1 && (s
->flags
& COPYFILE_STAT
))
551 fstat(s
->src_fd
, &sbuf
);
553 fstat(s
->dst_fd
, &sbuf
);
555 if (!(s
->internal_flags
& cfDelayAce
))
556 remove_uberace(s
->dst_fd
, &sbuf
);
559 if (s
->permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
560 if (s
->flags
& COPYFILE_ACL
) {
561 /* Just need to reset the BSD information -- mode, owner, group */
562 (void)fchown(s
->dst_fd
, s
->dst_sb
.st_uid
, s
->dst_sb
.st_gid
);
563 (void)fchmod(s
->dst_fd
, s
->dst_sb
.st_mode
);
566 * flags is either COPYFILE_STAT, or neither; if it's
567 * neither, then we restore both ACL and POSIX permissions;
568 * if it's STAT, however, then we only want to restore the
569 * ACL (which may be empty). We do that by removing the
570 * POSIX information from the filesec object.
572 if (s
->flags
& COPYFILE_STAT
) {
573 copyfile_unset_posix_fsec(s
->original_fsec
);
575 if (fchmodx_np(s
->dst_fd
, s
->original_fsec
) < 0 && errno
!= ENOTSUP
)
576 copyfile_warn("restoring security information");
580 if (s
->permissive_fsec
) {
581 filesec_free(s
->permissive_fsec
);
582 s
->permissive_fsec
= NULL
;
585 if (s
->original_fsec
) {
586 filesec_free(s
->original_fsec
);
587 s
->original_fsec
= NULL
;
595 * copytree -- recursively copy a hierarchy.
597 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
598 * Care is taken to keep the ACLs set up correctly, in addition to the
599 * normal copying that is done. (When copying a hierarchy, we can't
600 * get rid of the "allow-all-writes" ACE on a directory until we're done
601 * copying the *contents* of the directory.)
603 * The other big difference from copyfile (for the moment) is that copytree()
604 * will use a call-back function to pass along information about what is
605 * about to be copied, and whether or not it succeeded.
607 * copytree() is called from copyfile() -- but copytree() itself then calls
608 * copyfile() to copy each individual object.
610 * If COPYFILE_CLONE is passed, copytree() will clone (instead of copy)
611 * regular files and symbolic links found in each directory.
612 * Directories will still be copied normally.
614 * XXX - no effort is made to handle overlapping hierarchies at the moment.
619 copytree(copyfile_state_t s
)
623 int (*sfunc
)(const char *, struct stat
*);
624 copyfile_callback_t status
= NULL
;
625 char srcisdir
= 0, dstisdir
= 0, dstexists
= 0;
628 const char *dstpathsep
= "";
630 char srcpath
[PATH_MAX
* 2 + 1], dstpath
[PATH_MAX
* 2 + 1];
636 const char *paths
[2] = { 0 };
637 unsigned int flags
= 0;
638 int fts_flags
= FTS_NOCHDIR
;
639 dev_t last_dev
= s
->sb
.st_dev
;
646 if (s
->flags
& (COPYFILE_MOVE
| COPYFILE_UNLINK
| COPYFILE_CHECK
| COPYFILE_PACK
| COPYFILE_UNPACK
)) {
652 flags
= s
->flags
& (COPYFILE_ALL
| COPYFILE_NOFOLLOW
| COPYFILE_VERBOSE
| COPYFILE_EXCL
| COPYFILE_CLONE
);
654 paths
[0] = src
= s
->src
;
657 if (src
== NULL
|| dst
== NULL
) {
663 sfunc
= (flags
& COPYFILE_NOFOLLOW_SRC
) ? lstat
: stat
;
664 if ((sfunc
)(src
, &sbuf
) == -1) {
668 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
672 sfunc
= (flags
& COPYFILE_NOFOLLOW_DST
) ? lstat
: stat
;
673 if ((sfunc
)(dst
, &sbuf
) == -1) {
674 if (errno
!= ENOENT
) {
680 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
686 // This doesn't handle filesystem crossing and case sensitivity
687 // So there's got to be a better way
689 if (realpath(src
, srcpath
) == NULL
) {
694 if (realpath(dst
, dstpath
) == NULL
&&
695 (errno
== ENOENT
&& realpath(dirname(dst
), dstpath
) == NULL
)) {
699 if (strstr(srcpath
, dstpath
) != NULL
) {
705 srcroot
= basename((char*)src
);
706 if (srcroot
== NULL
) {
712 * To work on as well:
713 * We have a few cases when copying a hierarchy:
714 * 1) src is a non-directory, dst is a directory;
715 * 2) src is a non-directory, dst is a non-directory;
716 * 3) src is a non-directory, dst does not exist;
717 * 4) src is a directory, dst is a directory;
718 * 5) src is a directory, dst is a non-directory;
719 * 6) src is a directory, dst does not exist
721 * (1) copies src to dst/basename(src).
722 * (2) fails if COPYFILE_EXCL is set, otherwise copies src to dst.
723 * (3) and (6) copy src to the name dst.
724 * (4) copies the contents of src to the contents of dst.
729 // copy /path/to/src to /path/to/dst/src
730 // Append "/" and (fts_path - strlen(basename(src))) to dst?
732 slash
= strrchr(src
, '/');
736 offset
= slash
- src
+ 1;
738 // copy /path/to/src to /path/to/dst
739 // append (fts_path + strlen(src)) to dst?
741 offset
= strlen(src
);
744 // COPYFILE_RECURSIVE is always done physically: see 11717978.
745 fts_flags
|= FTS_PHYSICAL
;
746 if (!(s
->flags
& (COPYFILE_NOFOLLOW_SRC
|COPYFILE_CLONE
))) {
747 // Follow 'src', even if it's a symlink, unless instructed not to
748 // or we're cloning, where we never follow symlinks.
749 fts_flags
|= FTS_COMFOLLOW
;
752 fts
= fts_open((char * const *)paths
, fts_flags
, NULL
);
754 status
= s
->statuscb
;
755 while ((ftsent
= fts_read(fts
)) != NULL
) {
757 char *dstfile
= NULL
;
759 copyfile_state_t tstate
= copyfile_state_alloc();
760 if (tstate
== NULL
) {
765 tstate
->statuscb
= s
->statuscb
;
766 tstate
->ctx
= s
->ctx
;
767 if (last_dev
== ftsent
->fts_dev
) {
768 tstate
->internal_flags
|= (s
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
770 last_dev
= ftsent
->fts_dev
;
772 asprintf(&dstfile
, "%s%s%s", dst
, dstpathsep
, ftsent
->fts_path
+ offset
);
773 if (dstfile
== NULL
) {
774 copyfile_state_free(tstate
);
779 switch (ftsent
->fts_info
) {
781 tstate
->internal_flags
|= cfDelayAce
;
782 cmd
= COPYFILE_RECURSE_DIR
;
788 cmd
= COPYFILE_RECURSE_FILE
;
791 cmd
= COPYFILE_RECURSE_DIR_CLEANUP
;
798 errno
= ftsent
->fts_errno
;
800 rv
= (*status
)(COPYFILE_RECURSE_ERROR
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
801 if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
805 if (rv
== COPYFILE_QUIT
) {
818 if (cmd
== COPYFILE_RECURSE_DIR
|| cmd
== COPYFILE_RECURSE_FILE
) {
820 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
821 if (rv
== COPYFILE_SKIP
) {
822 if (cmd
== COPYFILE_RECURSE_DIR
) {
823 rv
= fts_set(fts
, ftsent
, FTS_SKIP
);
825 rv
= (*status
)(0, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
826 if (rv
== COPYFILE_QUIT
)
832 if (rv
== COPYFILE_QUIT
) {
833 retval
= -1; errno
= 0;
837 // Since we don't support cloning directories this code depends on copyfile()
838 // falling back to a regular directory copy.
839 int tmp_flags
= (cmd
== COPYFILE_RECURSE_DIR
) ? (flags
& ~COPYFILE_STAT
) : flags
;
840 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, tmp_flags
);
843 rv
= (*status
)(cmd
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
844 if (rv
== COPYFILE_QUIT
) {
856 rv
= (*status
)(cmd
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
857 if (rv
== COPYFILE_QUIT
) {
858 retval
= -1; errno
= 0;
862 } else if (cmd
== COPYFILE_RECURSE_DIR_CLEANUP
) {
864 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
865 if (rv
== COPYFILE_QUIT
) {
866 retval
= -1; errno
= 0;
868 } else if (rv
== COPYFILE_SKIP
) {
873 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, (flags
& COPYFILE_NOFOLLOW
) | COPYFILE_STAT
);
876 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
877 if (rv
== COPYFILE_QUIT
) {
880 } else if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
881 if (rv
== COPYFILE_CONTINUE
)
892 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
893 if (rv
== COPYFILE_QUIT
) {
894 retval
= -1; errno
= 0;
904 s
->internal_flags
&= ~COPYFILE_MNT_CPROTECT_MASK
;
905 s
->internal_flags
|= (tstate
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
907 copyfile_state_free(tstate
);
917 copyfile_debug(1, "returning: %d errno %d\n", retval
, errno
);
922 * fcopyfile() is used to copy a source file descriptor to a destination file
923 * descriptor. This allows an application to figure out how it wants to open
924 * the files (doing various security checks, perhaps), and then just pass in
925 * the file descriptors.
927 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
930 copyfile_state_t s
= state
;
933 if (src_fd
< 0 || dst_fd
< 0)
939 if (copyfile_preamble(&s
, flags
) < 0)
942 copyfile_debug(2, "set src_fd <- %d", src_fd
);
943 if (s
->src_fd
== -2 && src_fd
> -1)
946 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
948 if (errno
== ENOTSUP
|| errno
== EPERM
)
949 fstat(s
->src_fd
, &s
->sb
);
952 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
958 /* prevent copying on unsupported types */
959 switch (s
->sb
.st_mode
& S_IFMT
)
970 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
971 if (s
->dst_fd
== -2 && dst_fd
> -1)
974 (void)fstat(s
->dst_fd
, &dst_sb
);
975 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
977 (void)copyfile_quarantine(s
);
979 ret
= copyfile_internal(s
, flags
);
981 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
983 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
992 copyfile_state_free(s
);
1003 * This routine implements the clonefileat functionality
1004 * for copyfile. There are 2 kinds of clone flags, namely
1005 * 1. COPYFILE_CLONE_FORCE which is a 'force' clone flag.
1006 * 2. COPYFILE_CLONE which is a 'best try' flag.
1007 * In both cases, we inherit the flags provided
1008 * to copyfile call and clone the file.
1009 * Both these flags are equivalent to
1010 * (COPYFILE_EXCL | COPYFILE_ACL | COPYFILE_STAT | COPYFILE_XATTR | COPYFILE_DATA)
1011 * With force clone flag set, we return failure if cloning fails,
1012 * however, in case of best try flag, we fallback to the copy method.
1015 static int copyfile_clone(copyfile_state_t state
)
1018 // Since we don't allow cloning of directories, we must also forbid
1019 // cloning the target of symlinks (since that may be a directory).
1020 int cloneFlags
= CLONE_NOFOLLOW
;
1023 if (lstat(state
->src
, &src_sb
) != 0)
1030 * Support only for files and symbolic links.
1031 * TODO:Remove this check when support for directories is added.
1033 if (S_ISREG(src_sb
.st_mode
) || S_ISLNK(src_sb
.st_mode
))
1036 * COPYFILE_UNLINK tells us to try removing the destination
1037 * before we create it. We don't care if the file doesn't
1038 * exist, so we ignore ENOENT.
1040 if (state
->flags
& COPYFILE_UNLINK
)
1042 if (remove(state
->dst
) < 0 && errno
!= ENOENT
)
1047 ret
= clonefileat(AT_FDCWD
, state
->src
, AT_FDCWD
, state
->dst
, cloneFlags
);
1050 * We could also report the size of the single
1051 * object that was cloned. However, that's a lot
1052 * more difficult when we eventually support
1053 * cloning directories. It seems reasonable to NOT
1054 * report any bytes being "copied" in this scenario,
1055 * and let the caller figure out how they want to
1058 state
->was_cloned
= true;
1061 * COPYFILE_MOVE tells us to attempt removing
1062 * the source file after the copy, and to
1063 * ignore any errors returned by remove(3).
1065 if (state
->flags
& COPYFILE_MOVE
) {
1066 (void)remove(state
->src
);
1079 * the original copyfile() routine; this copies a source file to a destination
1080 * file. Note that because we need to set the names in the state variable, this
1081 * is not just the same as opening the two files, and then calling fcopyfile().
1082 * Oh, if only life were that simple!
1084 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
1088 copyfile_state_t s
= state
;
1091 if (src
== NULL
&& dst
== NULL
)
1097 if (copyfile_preamble(&s
, flags
) < 0)
1103 * This macro is... well, it's not the worst thing you can do with cpp, not
1104 * by a long shot. Essentially, we are setting the filename (src or dst)
1105 * in the state structure; since the structure may not have been cleared out
1106 * before being used again, we do some of the cleanup here: if the given
1107 * filename (e.g., src) is set, and state->src is not equal to that, then
1108 * we need to check to see if the file descriptor had been opened, and if so,
1109 * close it. After that, we set state->src to be a copy of the given filename,
1110 * releasing the old copy if necessary.
1112 #define COPYFILE_SET_FNAME(NAME, S) \
1114 if (NAME != NULL) { \
1115 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
1116 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
1117 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
1118 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
1119 close(S->NAME##_fd); \
1120 S->NAME##_fd = -2; \
1127 if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \
1132 COPYFILE_SET_FNAME(src
, s
);
1133 COPYFILE_SET_FNAME(dst
, s
);
1135 if (s
->flags
& COPYFILE_RECURSIVE
) {
1140 if (s
->flags
& (COPYFILE_CLONE_FORCE
| COPYFILE_CLONE
))
1142 ret
= copyfile_clone(s
);
1145 } else if (s
->flags
& COPYFILE_CLONE_FORCE
) {
1148 // cloning failed. Inherit clonefile flags required for
1149 // falling back to copyfile.
1150 s
->flags
|= (COPYFILE_ACL
| COPYFILE_EXCL
| COPYFILE_NOFOLLOW_SRC
|
1151 COPYFILE_STAT
| COPYFILE_XATTR
| COPYFILE_DATA
);
1153 s
->flags
&= ~COPYFILE_CLONE
;
1159 * Get a copy of the source file's security settings
1161 if (s
->original_fsec
) {
1162 filesec_free(s
->original_fsec
);
1163 s
->original_fsec
= NULL
;
1165 if ((s
->original_fsec
= filesec_init()) == NULL
)
1168 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
1169 ((dst_sb
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1170 if (s
->permissive_fsec
)
1171 free(s
->permissive_fsec
);
1172 s
->permissive_fsec
= NULL
;
1173 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
1176 * copyfile_fix_perms() will make a copy of the permission set,
1177 * and insert at the beginning an ACE that ensures we can write
1178 * to the file and set attributes.
1181 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
1184 * Set the permissions for the destination to our copy.
1185 * We should get ENOTSUP from any filesystem that simply
1186 * doesn't support it.
1188 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
1190 copyfile_warn("setting security information");
1191 filesec_free(s
->permissive_fsec
);
1192 s
->permissive_fsec
= NULL
;
1195 } else if (errno
== ENOENT
) {
1200 * If COPYFILE_CHECK is set in flags, then all we are going to do
1201 * is see what kinds of things WOULD have been copied (see
1202 * copyfile_check() below). We return that value.
1204 if (COPYFILE_CHECK
& flags
)
1206 ret
= copyfile_check(s
);
1208 } else if ((ret
= copyfile_open(s
)) < 0)
1211 (void)fcntl(s
->src_fd
, F_NOCACHE
, 1);
1212 (void)fcntl(s
->dst_fd
, F_NOCACHE
, 1);
1213 #ifdef F_SINGLE_WRITER
1214 (void)fcntl(s
->dst_fd
, F_SINGLE_WRITER
, 1);
1217 ret
= copyfile_internal(s
, flags
);
1221 #ifdef COPYFILE_RECURSIVE
1222 if (!(flags
& COPYFILE_STAT
)) {
1225 /* Just need to reset the BSD information -- mode, owner, group */
1226 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
1227 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
1234 if (s
->src
&& (flags
& COPYFILE_MOVE
))
1235 (void)remove(s
->src
);
1241 copyfile_debug(5, "returning %d errno %d\n", ret
, errno
);
1243 if (state
== NULL
) {
1245 copyfile_state_free(s
);
1260 * Shared prelude to the {f,}copyfile(). This initializes the
1261 * state variable, if necessary, and also checks for both debugging
1262 * and disabling environment variables.
1264 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
1270 if ((*state
= copyfile_state_alloc()) == NULL
)
1276 if (COPYFILE_DEBUG
& flags
)
1279 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
1282 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
1284 /* clamp s->debug to 1 if the environment variable is not parsable */
1285 if (s
->debug
== 0 && errno
!= 0)
1288 copyfile_debug(2, "debug value set to: %d", s
->debug
);
1292 /* Temporarily disabled */
1293 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
1295 copyfile_debug(1, "copyfile disabled");
1299 copyfile_debug(2, "setting flags: %d", s
->flags
);
1306 * The guts of {f,}copyfile().
1307 * This looks through the flags in a particular order, and calls the
1308 * associated functions.
1310 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
1314 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1316 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1322 * COPYFILE_PACK causes us to create an Apple Double version of the
1323 * source file, and puts it into the destination file. See
1324 * copyfile_pack() below for all the gory details.
1326 if (COPYFILE_PACK
& flags
)
1328 if ((ret
= copyfile_pack(s
)) < 0)
1330 if (s
->dst
) unlink(s
->dst
);
1337 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1338 * The goal there is to take an Apple Double file, and turn it
1339 * into a normal file (with data fork, resource fork, modes,
1340 * extended attributes, ACLs, etc.).
1342 if (COPYFILE_UNPACK
& flags
)
1344 if ((ret
= copyfile_unpack(s
)) < 0)
1352 * If we have quarantine info set, we attempt
1353 * to apply it to dst_fd. We don't care if
1354 * it fails, not yet anyway.
1362 * If COPYFILE_RUN_IN_PLACE is set, we need to add
1363 * QTN_FLAG_DO_NOT_TRANSLOCATE to the qinfo flags.
1365 * On iOS, qtn_file_get_flags & qtn_file_set_flags
1366 * don't modify anything, always return 0, per static
1367 * defines at top of this file, though we should never
1368 * get here in that case as qinfo will always be NULL.
1370 if (COPYFILE_RUN_IN_PLACE
& flags
)
1374 q_flags
= qtn_file_get_flags(s
->qinfo
);
1375 q_flags
|= QTN_FLAG_DO_NOT_TRANSLOCATE
;
1377 if (qtn_file_set_flags(s
->qinfo
, q_flags
) != 0) {
1378 s
->err
= errno
= EINVAL
;
1383 qr
= qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1388 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
1389 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1390 s
->xattr_name
= NULL
;
1391 if (rv
== COPYFILE_QUIT
) {
1392 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1396 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1403 * COPYFILE_XATTR tells us to copy the extended attributes;
1404 * this is seperate from the extended security (aka ACLs),
1405 * however. If we succeed in this, we continue to the next
1406 * stage; if we fail, we return with an error value. Note
1407 * that we fail if the errno is ENOTSUP, but we don't print
1408 * a warning in that case.
1410 if (COPYFILE_XATTR
& flags
)
1412 if ((ret
= copyfile_xattr(s
)) < 0)
1414 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1415 copyfile_warn("error processing extended attributes");
1421 * Similar to above, this tells us whether or not to copy
1422 * the non-meta data portion of the file. We attempt to
1423 * remove (via unlink) the destination file if we fail.
1425 if (COPYFILE_DATA
& flags
)
1427 if ((ret
= copyfile_data(s
)) < 0)
1429 copyfile_warn("error processing data");
1430 if (s
->dst
&& unlink(s
->dst
))
1431 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1437 * COPYFILE_SECURITY requests that we copy the security, both
1438 * extended and mundane (that is, ACLs and POSIX).
1440 if (COPYFILE_SECURITY
& flags
)
1442 if ((ret
= copyfile_security(s
)) < 0)
1444 copyfile_warn("error processing security information");
1449 if (COPYFILE_STAT
& flags
)
1451 if ((ret
= copyfile_stat(s
)) < 0)
1453 copyfile_warn("error processing POSIX information");
1467 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1469 copyfile_state_t
copyfile_state_alloc(void)
1471 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1478 filesec_free(s
->fsec
);
1481 s
->fsec
= filesec_init();
1489 * copyfile_state_free() returns the memory allocated to the state structure.
1490 * It also closes the file descriptors, if they've been opened.
1492 int copyfile_state_free(copyfile_state_t s
)
1497 filesec_free(s
->fsec
);
1499 if (s
->original_fsec
)
1500 filesec_free(s
->original_fsec
);
1502 if (s
->permissive_fsec
)
1503 filesec_free(s
->permissive_fsec
);
1506 qtn_file_free(s
->qinfo
);
1508 if (copyfile_close(s
) < 0)
1510 copyfile_warn("error closing files");
1514 free(s
->xattr_name
);
1525 * Should we worry if we can't close the source? NFS says we
1526 * should, but it's pretty late for us at this point.
1528 static int copyfile_close(copyfile_state_t s
)
1530 if (s
->src
&& s
->src_fd
>= 0)
1533 if (s
->dst
&& s
->dst_fd
>= 0) {
1534 if (close(s
->dst_fd
))
1542 * The purpose of this function is to set up a set of permissions
1543 * (ACL and traditional) that lets us write to the file. In the
1544 * case of ACLs, we do this by putting in a first entry that lets
1545 * us write data, attributes, and extended attributes. In the case
1546 * of traditional permissions, we set the S_IWUSR (user-write)
1549 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1551 filesec_t ret_fsec
= NULL
;
1555 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1558 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1560 #ifdef COPYFILE_RECURSIVE
1561 if (add_uberace(&acl
))
1565 acl_permset_t permset
;
1568 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1572 * First, we create an entry, and give it the special name
1573 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1574 * After that, we clear out all the permissions in it, and
1575 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1576 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1577 * the functionality, and put this into the ACL.
1579 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1581 if (acl_get_permset(entry
, &permset
) == -1)
1583 if (acl_clear_perms(permset
) == -1)
1585 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1587 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1589 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1591 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1594 if(acl_set_permset(entry
, permset
) == -1)
1596 if(acl_set_qualifier(entry
, qual
) == -1)
1600 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1605 * This is for the normal, mundane, POSIX permission model.
1606 * We make sure that we can write to the file.
1608 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1610 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1612 mode
|= S_IWUSR
|S_IRUSR
;
1613 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1627 filesec_free(ret_fsec
);
1634 * Used to clear out the BSD/POSIX security information from
1638 copyfile_unset_posix_fsec(filesec_t fsec
)
1640 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1641 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1642 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1647 * Used to remove acl information from a filesec_t
1648 * Unsetting the acl alone in Tiger was insufficient
1650 static int copyfile_unset_acl(copyfile_state_t s
)
1653 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1655 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1658 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1660 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1663 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1665 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1672 * copyfile_open() does what one expects: it opens up the files
1673 * given in the state structure, if they're not already open.
1674 * It also does some type validation, to ensure that we only
1675 * handle file types we know about.
1677 static int copyfile_open(copyfile_state_t s
)
1679 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
1680 int islnk
= 0, isdir
= 0, isreg
= 0;
1681 int osrc
= 0, dsrc
= 0;
1682 int prot_class
= PROTECTION_CLASS_DEFAULT
;
1683 int set_cprot_explicit
= 0;
1686 if (s
->src
&& s
->src_fd
== -2)
1688 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1689 (s
->src
, &s
->sb
, s
->fsec
))
1691 copyfile_warn("stat on %s", s
->src
);
1695 /* prevent copying on unsupported types */
1696 switch (s
->sb
.st_mode
& S_IFMT
)
1700 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1701 s
->err
= ENOMEM
; /* too big for us to copy */
1713 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1719 * If we're packing, then we are actually
1720 * creating a file, no matter what the source
1723 if (s
->flags
& COPYFILE_PACK
) {
1725 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1726 * if the file is a symlink, and O_NOFOLLOW is specified,
1727 * open will return ELOOP, whether or not O_SYMLINK is set.
1728 * However, we know whether or not it was a symlink from
1729 * the stat above (although there is a potentiaal for a race
1730 * condition here, but it will err on the side of returning
1734 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1738 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1740 copyfile_warn("open on %s", s
->src
);
1743 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1745 (void)copyfile_quarantine(s
);
1748 if (s
->dst
&& s
->dst_fd
== -2)
1751 * COPYFILE_UNLINK tells us to try removing the destination
1752 * before we create it. We don't care if the file doesn't
1753 * exist, so we ignore ENOENT.
1755 if (COPYFILE_UNLINK
& s
->flags
)
1757 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1759 copyfile_warn("%s: remove", s
->dst
);
1764 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1768 if (lstat(s
->dst
, &st
) != -1) {
1769 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1774 if (!(s
->internal_flags
& cfSrcProtSupportValid
))
1776 if ((error
= does_copy_protection(s
->src_fd
)) > 0)
1778 s
->internal_flags
|= cfSrcSupportsCProtect
;
1782 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->src
, errno
);
1785 s
->internal_flags
|= cfSrcProtSupportValid
;
1788 /* copy protection is only valid for regular files and directories. */
1789 if ((isreg
|| isdir
) && (s
->internal_flags
& cfSrcSupportsCProtect
))
1791 prot_class
= GET_PROT_CLASS(s
->src_fd
);
1794 copyfile_warn("GET_PROT_CLASS failed on (%s) with error <%d>", s
->src
, errno
);
1800 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1805 copyfile_warn("cannot allocate %zd bytes", sz
);
1808 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1809 copyfile_warn("cannot readlink %s", s
->src
);
1813 if (symlink(bp
, s
->dst
) == -1) {
1814 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1815 copyfile_warn("Cannot make symlink %s", s
->dst
);
1821 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1822 if (s
->dst_fd
== -1) {
1823 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1828 mode
= (s
->sb
.st_mode
& ~S_IFMT
) | S_IRWXU
;
1830 if (mkdir(s
->dst
, mode
) == -1) {
1831 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1832 copyfile_warn("Cannot make directory %s", s
->dst
);
1836 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1837 if (s
->dst_fd
== -1) {
1838 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1841 set_cprot_explicit
= 1;
1842 } else while((s
->dst_fd
= open_dprotected_np(s
->dst
, oflags
| dsrc
, prot_class
, 0, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1845 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1846 * was written -- allow one to set an extended attribute on a file descriptor
1847 * for a read-only file, even if the file descriptor is opened for writing.
1848 * This will only matter if the file does not already exist.
1853 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1854 if (s
->flags
& COPYFILE_EXCL
)
1856 oflags
= oflags
& ~O_CREAT
;
1857 /* if O_CREAT isn't set in open_dprotected_np, it won't set protection class.
1858 * Set the flag here so we know to do it later.
1860 set_cprot_explicit
= 1;
1861 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
1863 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
1868 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
1872 * If we're trying to write to a directory to which we don't
1873 * have access, the create above would have failed, but chmod
1874 * here would have given us ENOENT. But the real error is
1875 * still one of access, so we change the errno we're reporting.
1876 * This could cause confusion with a race condition.
1879 if (errno
== ENOENT
)
1884 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
1885 if (((s
->flags
& COPYFILE_EXCL
) ||
1886 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
1887 && !(s
->flags
& COPYFILE_UNPACK
))
1889 oflags
= (oflags
& ~(O_WRONLY
|O_CREAT
|O_TRUNC
)) | O_RDONLY
;
1892 copyfile_warn("open on %s", s
->dst
);
1895 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
1897 if (s
->internal_flags
& cfSrcSupportsCProtect
)
1899 if (!(s
->internal_flags
& cfDstProtSupportValid
))
1901 if ((error
= does_copy_protection(s
->dst_fd
)) > 0)
1903 s
->internal_flags
|= cfDstSupportsCProtect
;
1907 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->dst
, errno
);
1910 s
->internal_flags
|= cfDstProtSupportValid
;
1913 if ((isreg
|| isdir
)
1914 && set_cprot_explicit
1915 && (s
->internal_flags
& cfDstSupportsCProtect
))
1917 /* Protection class is set in open_dprotected_np for regular files that aren't truncated.
1918 * We set the protection class here for truncated files and directories.
1920 if (SET_PROT_CLASS(s
->dst_fd
, prot_class
) != 0)
1922 copyfile_warn("SET_PROT_CLASS failed on (%s) with error <%d>", s
->dst
, errno
);
1929 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1931 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1932 s
->src_fd
, s
->dst_fd
);
1941 * copyfile_check(), as described above, essentially tells you
1942 * what you'd have to copy, if you wanted it to copy the things
1943 * you asked it to copy.
1944 * In other words, if you pass in COPYFILE_ALL, and the file in
1945 * question had no extended attributes but did have an ACL, you'd
1946 * get back COPYFILE_ACL.
1948 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
1951 copyfile_flags_t ret
= 0;
1952 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
1962 if (COPYFILE_XATTR
& s
->flags
)
1963 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
1965 ret
|= COPYFILE_XATTR
;
1968 if (COPYFILE_ACL
& s
->flags
)
1970 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1971 (s
->src
, &s
->sb
, s
->fsec
);
1973 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
1974 ret
|= COPYFILE_ACL
;
1977 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
1983 /* If the state has had quarantine info set already, we use that */
1984 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1986 qinfo
= qtn_file_alloc();
1988 * For quarantine information, we need to see if the source file
1989 * has any. Since it may be a symlink, however, and we may, or
1990 * not be following, *and* there's no qtn* routine which can optionally
1991 * follow or not follow a symlink, we need to instead work around
2000 * If we care about not following symlinks, *and* the file exists
2001 * (which is to say, lstat doesn't return an error), *and* the file
2002 * is a symlink, then we open it up (with O_SYMLINK), and use
2003 * qtn_file_init_with_fd(); if none of that is true, however, then
2004 * we can simply use qtn_file_init_with_path().
2007 && lstat(s
->src
, &sbuf
) == 0
2008 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
2009 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
2011 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
2012 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
2017 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
2018 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
2021 qtn_file_free(qinfo
);
2029 * Attempt to copy the data section of a file. Using blockisize
2030 * is not necessarily the fastest -- it might be desirable to
2031 * specify a blocksize, somehow. But it's a size that should be
2032 * guaranteed to work.
2034 static int copyfile_data(copyfile_state_t s
)
2040 size_t iBlocksize
= 0;
2041 size_t oBlocksize
= 0;
2042 const size_t onegig
= 1 << 30;
2044 copyfile_callback_t status
= s
->statuscb
;
2046 /* Unless it's a normal file, we don't copy. For now, anyway */
2047 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
2050 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
2051 if (s
->internal_flags
& cfSawDecmpEA
) {
2052 if (s
->sb
.st_flags
& UF_COMPRESSED
) {
2053 if ((s
->flags
& COPYFILE_STAT
) == 0) {
2054 if (fchflags(s
->dst_fd
, UF_COMPRESSED
) == 0) {
2062 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
2063 iBlocksize
= s
->sb
.st_blksize
;
2065 iBlocksize
= sfs
.f_iosize
;
2068 /* Work-around for 6453525, limit blocksize to 1G */
2069 if (iBlocksize
> onegig
) {
2070 iBlocksize
= onegig
;
2073 if ((bp
= malloc(iBlocksize
)) == NULL
)
2076 if (fstatfs(s
->dst_fd
, &sfs
) == -1 || sfs
.f_iosize
== 0) {
2077 oBlocksize
= iBlocksize
;
2079 oBlocksize
= sfs
.f_iosize
;
2080 if (oBlocksize
> onegig
)
2081 oBlocksize
= onegig
;
2087 /* If supported, do preallocation for Xsan / HFS volumes */
2088 #ifdef F_PREALLOCATE
2093 fst
.fst_posmode
= F_PEOFPOSMODE
;
2095 fst
.fst_length
= s
->sb
.st_size
;
2096 /* Ignore errors; this is merely advisory. */
2097 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
2101 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
2104 size_t left
= nread
;
2109 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
2113 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
2120 copyfile_warn("writing to output file got error");
2122 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2123 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
2127 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
2136 ptr
= ((char*)ptr
) + nwritten
;
2140 s
->totalCopied
+= nwritten
;
2142 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
2143 if (rv
== COPYFILE_QUIT
) {
2144 ret
= -1; s
->err
= errno
= ECANCELED
;
2152 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
2157 if (ftruncate(s
->dst_fd
, s
->totalCopied
) < 0)
2173 * copyfile_security() will copy the ACL set, and the
2174 * POSIX set. Complexities come when dealing with
2175 * inheritied permissions, and when dealing with both
2176 * POSIX and ACL permissions.
2178 static int copyfile_security(copyfile_state_t s
)
2182 acl_t acl_src
= NULL
, acl_tmp
= NULL
, acl_dst
= NULL
;
2184 filesec_t tmp_fsec
= NULL
;
2185 filesec_t fsec_dst
= filesec_init();
2187 if (fsec_dst
== NULL
)
2191 if (COPYFILE_ACL
& s
->flags
)
2193 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
2195 if (errno
== ENOENT
)
2201 /* grab the destination acl
2202 cannot assume it's empty due to inheritance
2204 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
2207 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
2209 if (errno
== ENOENT
)
2215 if (acl_src
== NULL
&& acl_dst
== NULL
)
2218 acl_tmp
= acl_init(4);
2219 if (acl_tmp
== NULL
)
2223 acl_entry_t ace
= NULL
;
2224 acl_entry_t tmp
= NULL
;
2226 acl_get_entry(acl_src
,
2227 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2230 acl_flagset_t flags
= { 0 };
2231 acl_get_flagset_np(ace
, &flags
);
2232 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2234 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2237 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2240 copyfile_debug(2, "copied acl entry from %s to %s",
2241 s
->src
? s
->src
: "(null src)",
2242 s
->dst
? s
->dst
: "(null tmp)");
2248 acl_entry_t ace
= NULL
;
2249 acl_entry_t tmp
= NULL
;
2250 acl_flagset_t flags
= { 0 };
2251 for (copied
= 0;acl_get_entry(acl_dst
,
2252 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2255 acl_get_flagset_np(ace
, &flags
);
2256 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2258 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2261 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2264 copyfile_debug(2, "copied acl entry from %s to %s",
2265 s
->src
? s
->src
: "(null dst)",
2266 s
->dst
? s
->dst
: "(null tmp)");
2271 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_tmp
))
2273 copyfile_debug(3, "altered acl");
2278 * The following code is attempting to ensure that only the requested
2279 * security information gets copied over to the destination file.
2280 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2281 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2284 * If we have both flags, we copy everything; if we have ACL but not STAT,
2285 * we remove the POSIX information from the filesec object, and apply the
2286 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2287 * the extended version.
2289 tmp_fsec
= filesec_dup(s
->fsec
);
2290 if (tmp_fsec
== NULL
) {
2294 switch (COPYFILE_SECURITY
& s
->flags
) {
2296 copyfile_unset_posix_fsec(tmp_fsec
);
2298 case COPYFILE_ACL
| COPYFILE_STAT
:
2299 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
2302 * The call could have failed for a number of reasons, since
2303 * it does a number of things: it changes the mode of the file,
2304 * sets the owner and group, and applies an ACL (if one exists).
2305 * The typical failure is going to be trying to set the group of
2306 * the destination file to match the source file, when the process
2307 * doesn't have permission to put files in that group. We try to
2308 * work around this by breaking the steps out and doing them
2309 * discretely. We don't care if the fchown fails, but we do care
2310 * if the mode or ACL can't be set. For historical reasons, we
2311 * simply log those failures, however.
2313 * Big warning here: we may NOT have COPYFILE_STAT set, since
2314 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2317 #define NS(x) ((x) ? (x) : "(null string)")
2318 if ((s
->flags
& COPYFILE_STAT
) &&
2319 fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
2320 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
2322 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2323 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
2324 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
2325 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
2333 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
2336 filesec_free(tmp_fsec
);
2338 filesec_free(fsec_dst
);
2339 if (acl_src
) acl_free(acl_src
);
2340 if (acl_dst
) acl_free(acl_dst
);
2341 if (acl_tmp
) acl_free(acl_tmp
);
2352 * Attempt to set the destination file's stat information -- including
2353 * flags and time-related fields -- to the source's.
2355 static int copyfile_stat(copyfile_state_t s
)
2357 unsigned int added_flags
= 0, dst_flags
= 0;
2358 struct attrlist attrlist
;
2361 /* Order of these structs matters for setattrlist. */
2362 struct timespec mod_time
;
2363 struct timespec acc_time
;
2367 * NFS doesn't support chflags; ignore errors as a result, since
2368 * we don't return failure for this.
2370 if (s
->internal_flags
& cfMakeFileInvisible
)
2371 added_flags
|= UF_HIDDEN
;
2374 * We need to check if SF_RESTRICTED was set on the destination
2375 * by the kernel. If it was, don't drop it.
2377 if (fstat(s
->dst_fd
, &dst_sb
))
2379 if (dst_sb
.st_flags
& SF_RESTRICTED
)
2380 added_flags
|= SF_RESTRICTED
;
2382 /* Copy file flags, masking out any we don't want to preserve */
2383 dst_flags
= (s
->sb
.st_flags
& ~COPYFILE_OMIT_FLAGS
) | added_flags
;
2384 (void)fchflags(s
->dst_fd
, dst_flags
);
2386 /* If this fails, we don't care */
2387 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2389 /* This may have already been done in copyfile_security() */
2390 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
2392 /* Try to set m/atimes using setattrlist(), for nanosecond precision. */
2393 memset(&attrlist
, 0, sizeof(attrlist
));
2394 attrlist
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
2395 attrlist
.commonattr
= ATTR_CMN_MODTIME
| ATTR_CMN_ACCTIME
;
2396 ma_times
.mod_time
= s
->sb
.st_mtimespec
;
2397 ma_times
.acc_time
= s
->sb
.st_atimespec
;
2398 (void)fsetattrlist(s
->dst_fd
, &attrlist
, &ma_times
, sizeof(ma_times
), 0);
2404 * Similar to copyfile_security() in some ways; this
2405 * routine copies the extended attributes from the source,
2406 * and sets them on the destination.
2407 * The procedure is pretty simple, even if it is verbose:
2408 * for each named attribute on the destination, get its name, and
2409 * remove it. We should have none after that.
2410 * For each named attribute on the source, get its name, get its
2411 * data, and set it on the destination.
2413 static int copyfile_xattr(copyfile_state_t s
)
2416 char *namebuf
, *end
;
2419 ssize_t bufsize
= 4096;
2423 int look_for_decmpea
= 0;
2425 /* delete EAs on destination */
2426 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2428 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2431 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
2435 * With this, end points to the last byte of the allocated buffer
2436 * This *should* be NUL, from flistxattr, but if it's not, we can
2437 * set it anyway -- it'll result in a truncated name, which then
2438 * shouldn't match when we get them later.
2440 end
= namebuf
+ nsize
- 1;
2443 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
2444 /* If the quarantine information shows up as an EA, we skip over it */
2445 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
2448 fremovexattr(s
->dst_fd
, name
,0);
2455 if (errno
== ENOTSUP
|| errno
== EPERM
)
2461 #ifdef DECMPFS_XATTR_NAME
2462 if ((s
->flags
& COPYFILE_DATA
) &&
2463 (s
->sb
.st_flags
& UF_COMPRESSED
) &&
2464 doesdecmpfs(s
->src_fd
) &&
2465 doesdecmpfs(s
->dst_fd
)) {
2466 look_for_decmpea
= XATTR_SHOWCOMPRESSION
;
2470 /* get name list of EAs on source */
2471 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, look_for_decmpea
)) < 0)
2473 if (errno
== ENOTSUP
|| errno
== EPERM
)
2481 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2484 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, look_for_decmpea
);
2492 * With this, end points to the last byte of the allocated buffer
2493 * This *should* be NUL, from flistxattr, but if it's not, we can
2494 * set it anyway -- it'll result in a truncated name, which then
2495 * shouldn't match when we get them later.
2497 end
= namebuf
+ nsize
- 1;
2501 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
2506 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
2508 if (s
->xattr_name
) {
2509 free(s
->xattr_name
);
2510 s
->xattr_name
= NULL
;
2513 /* If the quarantine information shows up as an EA, we skip over it */
2514 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
2517 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, look_for_decmpea
)) < 0)
2522 if (xa_size
> bufsize
)
2524 void *tdptr
= xa_dataptr
;
2527 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
2535 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
)) < 0)
2540 if (xa_size
!= asize
)
2543 #ifdef DECMPFS_XATTR_NAME
2544 if (strncmp(name
, DECMPFS_XATTR_NAME
, end
-name
) == 0)
2546 decmpfs_disk_header
*hdr
= xa_dataptr
;
2549 * If the EA has the decmpfs name, but is too
2550 * small, or doesn't have the right magic number,
2551 * or isn't the right type, we'll just skip it.
2552 * This means it won't end up in the destination
2553 * file, and data copy will happen normally.
2555 if ((size_t)xa_size
< sizeof(decmpfs_disk_header
)) {
2558 if (OSSwapLittleToHostInt32(hdr
->compression_magic
) != DECMPFS_MAGIC
) {
2562 * From AppleFSCompression documentation:
2563 * "It is incumbent on the aware copy engine to identify
2564 * the type of compression being used, and to perform an
2565 * unaware copy of any file it does not recognize."
2567 * Compression Types are defined in:
2568 * "AppleFSCompression/Common/compressorCommon.h"
2570 * Unfortunately, they don't provide a way to dynamically
2571 * determine what possible compression_type values exist,
2572 * so we have to update this every time a new compression_type
2573 * is added. Types 7->10 were added in 10.10, Types 11 & 12
2574 * were added in 10.11.
2576 * Ubiquity faulting file compression type 0x80000001 are
2577 * deprecated as of Yosemite, per rdar://17714998 don't copy the
2578 * decmpfs xattr on these files, zero byte files are safer
2579 * than a fault nobody knows how to handle.
2581 switch (OSSwapLittleToHostInt32(hdr
->compression_type
)) {
2582 case 3: /* zlib-compressed data in xattr */
2583 case 4: /* 64k chunked zlib-compressed data in resource fork */
2585 case 7: /* LZVN-compressed data in xattr */
2586 case 8: /* 64k chunked LZVN-compressed data in resource fork */
2588 case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */
2589 case 10: /* 64k chunked uncompressed data in resource fork */
2591 case 11: /* LZFSE-compressed data in xattr */
2592 case 12: /* 64k chunked LZFSE-compressed data in resource fork */
2594 /* valid compression type, we want to copy. */
2597 case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */
2598 copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.",
2599 s
->src
? s
->src
: "(null string)");
2602 case 6: /* unused */
2603 case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */
2605 copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s",
2606 OSSwapLittleToHostInt32(hdr
->compression_type
), name
, s
->src
? s
->src
: "(null string)");
2609 s
->internal_flags
|= cfSawDecmpEA
;
2613 // If we have a copy intention stated, and the EA is to be ignored, we ignore it
2615 && xattr_preserve_for_intent(name
, s
->copyIntent
) == 0)
2618 s
->xattr_name
= strdup(name
);
2622 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
2623 if (rv
== COPYFILE_QUIT
) {
2626 } else if (rv
== COPYFILE_SKIP
) {
2630 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
) < 0)
2635 if (s
->xattr_name
== NULL
)
2636 s
->xattr_name
= strdup(name
);
2637 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2638 if (rv
== COPYFILE_QUIT
)
2648 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name
, strerror(errno
));
2654 if (s
->xattr_name
== NULL
)
2655 s
->xattr_name
= strdup(name
);
2657 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
2658 if (rv
== COPYFILE_QUIT
) {
2667 free((void *) xa_dataptr
);
2668 if (s
->xattr_name
) {
2669 free(s
->xattr_name
);
2670 s
->xattr_name
= NULL
;
2676 * API interface into getting data from the opaque data type.
2678 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
2688 case COPYFILE_STATE_SRC_FD
:
2689 *(int*)ret
= s
->src_fd
;
2691 case COPYFILE_STATE_DST_FD
:
2692 *(int*)ret
= s
->dst_fd
;
2694 case COPYFILE_STATE_SRC_FILENAME
:
2695 *(char**)ret
= s
->src
;
2697 case COPYFILE_STATE_DST_FILENAME
:
2698 *(char**)ret
= s
->dst
;
2700 case COPYFILE_STATE_QUARANTINE
:
2701 *(qtn_file_t
*)ret
= s
->qinfo
;
2704 case COPYFILE_STATE_STATS
:
2705 ret
= s
->stats
.global
;
2707 case COPYFILE_STATE_PROGRESS_CB
:
2708 ret
= s
->callbacks
.progress
;
2711 #ifdef COPYFILE_STATE_STATUS_CB
2712 case COPYFILE_STATE_STATUS_CB
:
2713 *(copyfile_callback_t
*)ret
= s
->statuscb
;
2715 case COPYFILE_STATE_STATUS_CTX
:
2716 *(void**)ret
= s
->ctx
;
2718 case COPYFILE_STATE_COPIED
:
2719 *(off_t
*)ret
= s
->totalCopied
;
2722 #ifdef COPYFILE_STATE_XATTRNAME
2723 case COPYFILE_STATE_XATTRNAME
:
2724 *(char**)ret
= s
->xattr_name
;
2727 #ifdef COPYFILE_STATE_INTENT
2728 case COPYFILE_STATE_INTENT
:
2729 *(xattr_operation_intent_t
*)ret
= s
->copyIntent
;
2732 case COPYFILE_STATE_WAS_CLONED
:
2733 *(bool *)ret
= s
->was_cloned
;
2744 * Public API for setting state data (remember that the state is
2745 * an opaque data type).
2747 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
2749 #define copyfile_set_string(DST, SRC) \
2751 if (SRC != NULL) { \
2752 DST = strdup((char *)SRC); \
2754 if (DST != NULL) { \
2769 case COPYFILE_STATE_SRC_FD
:
2770 s
->src_fd
= *(int*)thing
;
2772 case COPYFILE_STATE_DST_FD
:
2773 s
->dst_fd
= *(int*)thing
;
2775 case COPYFILE_STATE_SRC_FILENAME
:
2776 copyfile_set_string(s
->src
, thing
);
2778 case COPYFILE_STATE_DST_FILENAME
:
2779 copyfile_set_string(s
->dst
, thing
);
2781 case COPYFILE_STATE_QUARANTINE
:
2784 qtn_file_free(s
->qinfo
);
2787 if (*(qtn_file_t
*)thing
)
2788 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
2791 case COPYFILE_STATE_STATS
:
2792 s
->stats
.global
= thing
;
2794 case COPYFILE_STATE_PROGRESS_CB
:
2795 s
->callbacks
.progress
= thing
;
2798 #ifdef COPYFILE_STATE_STATUS_CB
2799 case COPYFILE_STATE_STATUS_CB
:
2800 s
->statuscb
= (copyfile_callback_t
)thing
;
2802 case COPYFILE_STATE_STATUS_CTX
:
2803 s
->ctx
= (void*)thing
;
2806 #ifdef COPYFILE_STATE_INTENT
2807 case COPYFILE_STATE_INTENT
:
2808 s
->copyIntent
= *(xattr_operation_intent_t
*)thing
;
2816 #undef copyfile_set_string
2821 * Make this a standalone program for testing purposes by
2822 * defining _COPYFILE_TEST.
2824 #ifdef _COPYFILE_TEST
2825 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2827 struct {char *s
; int v
;} opts
[] = {
2828 COPYFILE_OPTION(ACL
)
2829 COPYFILE_OPTION(STAT
)
2830 COPYFILE_OPTION(XATTR
)
2831 COPYFILE_OPTION(DATA
)
2832 COPYFILE_OPTION(SECURITY
)
2833 COPYFILE_OPTION(METADATA
)
2834 COPYFILE_OPTION(ALL
)
2835 COPYFILE_OPTION(NOFOLLOW_SRC
)
2836 COPYFILE_OPTION(NOFOLLOW_DST
)
2837 COPYFILE_OPTION(NOFOLLOW
)
2838 COPYFILE_OPTION(EXCL
)
2839 COPYFILE_OPTION(MOVE
)
2840 COPYFILE_OPTION(UNLINK
)
2841 COPYFILE_OPTION(PACK
)
2842 COPYFILE_OPTION(UNPACK
)
2843 COPYFILE_OPTION(CHECK
)
2844 COPYFILE_OPTION(CLONE
)
2845 COPYFILE_OPTION(CLONE_FORCE
)
2846 COPYFILE_OPTION(VERBOSE
)
2847 COPYFILE_OPTION(RECURSIVE
)
2848 COPYFILE_OPTION(DEBUG
)
2852 int main(int c
, char *v
[])
2856 copyfile_state_t state
= NULL
;
2859 errx(1, "insufficient arguments");
2863 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
2865 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
2867 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
2874 if (flags
& COPYFILE_DEBUG
) {
2875 state
= copyfile_state_alloc();
2876 state
->debug
= 10; // Turn on all debug statements
2878 ret
= copyfile(v
[1], v
[2], state
, flags
);
2880 (void)copyfile_state_free(state
);
2887 * Apple Double Create
2889 * Create an Apple Double "._" file from a file's extented attributes
2891 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2895 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2897 #define XATTR_MAXATTRLEN (16*1024*1024)
2901 Typical "._" AppleDouble Header File layout:
2902 ------------------------------------------------------------
2907 .-- AD ENTRY[0] Finder Info Entry (must be first)
2908 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2910 | ///////////// Fixed Size Data (32 bytes)
2914 | ATTR ENTRY[1] --+--.
2915 | ATTR ENTRY[2] --+--+--.
2917 | ATTR ENTRY[N] --+--+--+--.
2918 | ATTR DATA 0 <-' | | |
2919 | //////////// | | |
2920 | ATTR DATA 1 <----' | |
2922 | ATTR DATA 2 <-------' |
2925 | ATTR DATA N <----------'
2927 | Attribute Free Space
2929 '----> RESOURCE FORK
2930 ///////////// Variable Sized Data
2939 ------------------------------------------------------------
2941 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2942 stored as part of the Finder Info. The length in the Finder
2943 Info AppleDouble entry includes the length of the extended
2944 attribute header, attribute entries, and attribute data.
2949 * On Disk Data Structures
2951 * Note: Motorola 68K alignment and big-endian.
2953 * See RFC 1740 for additional information about the AppleDouble file format.
2957 #define ADH_MAGIC 0x00051607
2958 #define ADH_VERSION 0x00020000
2959 #define ADH_MACOSX "Mac OS X "
2962 * AppleDouble Entry ID's
2964 #define AD_DATA 1 /* Data fork */
2965 #define AD_RESOURCE 2 /* Resource fork */
2966 #define AD_REALNAME 3 /* File's name on home file system */
2967 #define AD_COMMENT 4 /* Standard Mac comment */
2968 #define AD_ICONBW 5 /* Mac black & white icon */
2969 #define AD_ICONCOLOR 6 /* Mac color icon */
2970 #define AD_UNUSED 7 /* Not used */
2971 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2972 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2973 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2974 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2975 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2976 #define AD_AFPNAME 13 /* Short name on AFP server */
2977 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2978 #define AD_AFPDIRID 15 /* AFP directory ID */
2979 #define AD_ATTRIBUTES AD_FINDERINFO
2982 #define ATTR_FILE_PREFIX "._"
2983 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2985 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2987 /* Implementation Limits */
2988 #define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */
2989 #define ATTR_MAX_NAME_LEN 128
2990 #define ATTR_MAX_HDR_SIZE (65536+18)
2993 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2994 * size supported (including the attribute entries). All of
2995 * the attribute entries must reside within this limit.
2999 #define FINDERINFOSIZE 32
3001 typedef struct apple_double_entry
3003 u_int32_t type
; /* entry type: see list, 0 invalid */
3004 u_int32_t offset
; /* entry data offset from the beginning of the file. */
3005 u_int32_t length
; /* entry data length in bytes. */
3006 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
3009 typedef struct apple_double_header
3011 u_int32_t magic
; /* == ADH_MAGIC */
3012 u_int32_t version
; /* format version: 2 = 0x00020000 */
3013 u_int32_t filler
[4];
3014 u_int16_t numEntries
; /* number of entries which follow */
3015 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
3016 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
3017 u_int8_t pad
[2]; /* get better alignment inside attr_header */
3018 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
3021 /* Entries are aligned on 4 byte boundaries */
3022 typedef struct attr_entry
3024 u_int32_t offset
; /* file offset to data */
3025 u_int32_t length
; /* size of attribute data */
3027 u_int8_t namelen
; /* length of name including NULL termination char */
3028 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
3029 } __attribute__((aligned(2), packed
)) attr_entry_t
;
3033 /* Header + entries must fit into 64K */
3034 typedef struct attr_header
3036 apple_double_header_t appledouble
;
3037 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
3038 u_int32_t debug_tag
; /* for debugging == file id of owning file */
3039 u_int32_t total_size
; /* total size of attribute header + entries + data */
3040 u_int32_t data_start
; /* file offset to attribute data area */
3041 u_int32_t data_length
; /* length of attribute data area */
3042 u_int32_t reserved
[3];
3044 u_int16_t num_attrs
;
3045 } __attribute__((aligned(2), packed
)) attr_header_t
;
3047 /* Empty Resource Fork Header */
3048 /* This comes by way of xnu's vfs_xattr.c */
3049 typedef struct rsrcfork_header
{
3050 u_int32_t fh_DataOffset
;
3051 u_int32_t fh_MapOffset
;
3052 u_int32_t fh_DataLength
;
3053 u_int32_t fh_MapLength
;
3054 u_int8_t systemData
[112];
3055 u_int8_t appData
[128];
3056 u_int32_t mh_DataOffset
;
3057 u_int32_t mh_MapOffset
;
3058 u_int32_t mh_DataLength
;
3059 u_int32_t mh_MapLength
;
3061 u_int16_t mh_RefNum
;
3063 u_int8_t mh_InMemoryAttr
;
3066 u_int16_t typeCount
;
3067 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
3068 #define RF_FIRST_RESOURCE 256
3069 #define RF_NULL_MAP_LENGTH 30
3070 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
3072 static const rsrcfork_header_t empty_rsrcfork_header
= {
3073 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
3074 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
3076 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
3077 { RF_EMPTY_TAG
, }, // systemData
3079 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
3080 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
3082 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
3086 0, // mh_InMemoryAttr
3087 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
3088 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
3089 OSSwapHostToBigInt16(-1), // typeCount
3092 #define SWAP16(x) OSSwapBigToHostInt16(x)
3093 #define SWAP32(x) OSSwapBigToHostInt32(x)
3094 #define SWAP64(x) OSSwapBigToHostInt64(x)
3096 #define ATTR_ALIGN 3L /* Use four-byte alignment */
3098 #define ATTR_ENTRY_LENGTH(namelen) \
3099 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
3101 #define ATTR_NEXT(ae) \
3102 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
3104 #define XATTR_SECURITY_NAME "com.apple.acl.text"
3107 * Endian swap Apple Double header
3110 swap_adhdr(apple_double_header_t
*adh
)
3112 #if BYTE_ORDER == LITTLE_ENDIAN
3116 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
3118 adh
->magic
= SWAP32 (adh
->magic
);
3119 adh
->version
= SWAP32 (adh
->version
);
3120 adh
->numEntries
= SWAP16 (adh
->numEntries
);
3122 for (i
= 0; i
< count
; i
++)
3124 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
3125 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
3126 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
3134 * Endian swap a single attr_entry_t
3137 swap_attrhdr_entry(attr_entry_t
*ae
)
3139 #if BYTE_ORDER == LITTLE_ENDIAN
3140 ae
->offset
= SWAP32 (ae
->offset
);
3141 ae
->length
= SWAP32 (ae
->length
);
3142 ae
->flags
= SWAP16 (ae
->flags
);
3149 * For a validated/endian swapped attr_header_t*
3150 * ah, endian swap all of the entries.
3153 swap_attrhdr_entries(attr_header_t
*ah
)
3155 #if BYTE_ORDER == LITTLE_ENDIAN
3158 attr_entry_t
*entry
;
3161 /* If we're in copyfile_pack, num_args is native endian,
3162 * if we're in _unpack, num_args is big endian. Use
3163 * the magic number to test for endianess.
3165 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
3167 entry
= (attr_entry_t
*)(&ah
[1]);
3168 for (i
= 0; i
< count
; i
++) {
3169 next
= ATTR_NEXT(entry
);
3170 swap_attrhdr_entry(entry
);
3179 * Endian swap extended attributes header
3182 swap_attrhdr(attr_header_t
*ah
)
3184 #if BYTE_ORDER == LITTLE_ENDIAN
3185 ah
->magic
= SWAP32 (ah
->magic
);
3186 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
3187 ah
->total_size
= SWAP32 (ah
->total_size
);
3188 ah
->data_start
= SWAP32 (ah
->data_start
);
3189 ah
->data_length
= SWAP32 (ah
->data_length
);
3190 ah
->flags
= SWAP16 (ah
->flags
);
3191 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
3197 static const u_int32_t emptyfinfo
[8] = {0};
3200 * Given an Apple Double file in src, turn it into a
3201 * normal file (possibly with multiple forks, EAs, and
3204 static int copyfile_unpack(copyfile_state_t s
)
3207 void * buffer
, * endptr
, * dataptr
= NULL
;
3208 apple_double_header_t
*adhdr
;
3212 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
3213 hdrsize
= (ssize_t
)s
->sb
.st_size
;
3215 hdrsize
= ATTR_MAX_HDR_SIZE
;
3217 buffer
= calloc(1, hdrsize
);
3218 if (buffer
== NULL
) {
3219 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize
);
3223 endptr
= (char*)buffer
+ hdrsize
;
3225 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
3229 copyfile_debug(1, "pread returned: %zd", bytes
);
3233 if (bytes
< hdrsize
)
3236 "pread couldn't read entire header: %d of %d",
3237 (int)bytes
, (int)s
->sb
.st_size
);
3241 adhdr
= (apple_double_header_t
*)buffer
;
3244 * Check for Apple Double file.
3246 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
3247 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
3248 SWAP32(adhdr
->version
) != ADH_VERSION
||
3249 SWAP16(adhdr
->numEntries
) != 2 ||
3250 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
3252 if (COPYFILE_VERBOSE
& s
->flags
)
3253 copyfile_warn("Not a valid Apple Double header");
3260 * Remove any extended attributes on the target.
3263 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
3265 char *namebuf
, *name
;
3267 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
3272 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
3275 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
3276 (void)fremovexattr(s
->dst_fd
, name
, 0);
3282 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
3287 * Extract the extended attributes.
3290 * This assumes that the data is already in memory (not
3291 * the case when there are lots of attributes or one of
3292 * the attributes is very large.
3294 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
3296 attr_header_t
*attrhdr
;
3297 attr_entry_t
*entry
;
3301 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
3302 copyfile_warn("bad attribute header: %zu < %zu", hdrsize
, sizeof(attr_header_t
));
3307 attrhdr
= (attr_header_t
*)buffer
;
3308 swap_attrhdr(attrhdr
);
3309 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
3311 if (COPYFILE_VERBOSE
& s
->flags
)
3312 copyfile_warn("bad attribute header");
3316 count
= attrhdr
->num_attrs
;
3317 entry
= (attr_entry_t
*)&attrhdr
[1];
3319 for (i
= 0; i
< count
; i
++)
3322 * First we do some simple sanity checking.
3323 * +) See if entry is within the buffer's range;
3325 * +) Check the attribute name length; if it's longer than the
3326 * maximum, we truncate it down. (We could error out as well;
3327 * I'm not sure which is the better way to go here.)
3329 * +) If, given the name length, it goes beyond the end of
3330 * the buffer, error out.
3332 * +) If the last byte isn't a NUL, make it a NUL. (Since we
3333 * truncated the name length above, we truncate the name here.)
3335 * +) If entry->offset is so large that it causes dataptr to
3336 * go beyond the end of the buffer -- or, worse, so large that
3337 * it wraps around! -- we error out.
3339 * +) If entry->length would cause the entry to go beyond the
3340 * end of the buffer (or, worse, wrap around to before it),
3341 * *or* if the length is larger than the hdrsize, we error out.
3342 * (An explanation of that: what we're checking for there is
3343 * the small range of values such that offset+length would cause
3344 * it to go beyond endptr, and then wrap around past buffer. We
3345 * care about this because we are passing entry->length down to
3346 * fgetxattr() below, and an erroneously large value could cause
3347 * problems there. By making sure that it's less than hdrsize,
3348 * which has already been sanity-checked above, we're safe.
3349 * That may mean that the check against < buffer is unnecessary.)
3351 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
3352 if (COPYFILE_VERBOSE
& s
->flags
)
3353 copyfile_warn("Incomplete or corrupt attribute entry");
3359 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
3360 if (COPYFILE_VERBOSE
& s
->flags
)
3361 copyfile_warn("Incomplete or corrupt attribute entry");
3368 * Endian swap the entry we're looking at. Previously
3369 * we did this swap as part of swap_attrhdr, but that
3370 * allowed a maliciously constructed file to overrun
3371 * our allocation. Instead do the swap after we've verified
3372 * the entry struct is within the buffer's range.
3374 swap_attrhdr_entry(entry
);
3376 if (entry
->namelen
< 2) {
3377 if (COPYFILE_VERBOSE
& s
->flags
)
3378 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
3384 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
3385 if (COPYFILE_VERBOSE
& s
->flags
)
3386 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
3392 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
3393 if (COPYFILE_VERBOSE
& s
->flags
)
3394 copyfile_warn("Incomplete or corrupt attribute entry");
3400 /* Because namelen includes the NUL, we check one byte back */
3401 if (entry
->name
[entry
->namelen
-1] != 0) {
3402 if (COPYFILE_VERBOSE
& s
->flags
)
3403 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3409 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3410 entry
->name
, entry
->length
, entry
->offset
);
3413 dataptr
= (char *)attrhdr
+ entry
->offset
;
3415 if (dataptr
> endptr
|| dataptr
< buffer
) {
3416 copyfile_debug(1, "Entry %d overflows: offset = %u", i
, entry
->offset
);
3418 s
->err
= EINVAL
; /* Invalid buffer */
3422 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
3423 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
3424 (entry
->length
> (size_t)hdrsize
)) {
3425 if (COPYFILE_VERBOSE
& s
->flags
)
3426 copyfile_warn("Incomplete or corrupt attribute entry");
3427 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3428 i
, entry
->offset
, entry
->length
);
3430 s
->err
= EINVAL
; /* Invalid buffer */
3435 dataptr
= malloc(entry
->length
);
3436 if (dataptr
== NULL
) {
3437 copyfile_debug(1, "no memory for %u bytes\n", entry
->length
);
3442 if (pread(s
->src_fd
, dataptr
, entry
->length
, entry
->offset
) != (ssize_t
)entry
->length
) {
3443 copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry
->length
, entry
->offset
);
3450 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
3452 qtn_file_t tqinfo
= NULL
;
3454 if (s
->qinfo
== NULL
)
3456 tqinfo
= qtn_file_alloc();
3460 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
3462 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
3463 qtn_file_free(tqinfo
);
3475 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
3477 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
3480 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
3481 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3482 s
->xattr_name
= NULL
;
3483 if (rv
== COPYFILE_QUIT
) {
3484 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3488 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3493 if (tqinfo
&& !s
->qinfo
)
3495 qtn_file_free(tqinfo
);
3498 /* Look for ACL data */
3499 else if (strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
3504 char *tcp
= dataptr
;
3506 if (entry
->length
== 0) {
3507 /* Not sure how we got here, but we had one case
3508 * where it was 0. In a normal EA, we can have a 0-byte
3509 * payload. That means nothing in this case, so we'll
3510 * simply skip the EA.
3516 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3517 * however, may not be NUL-terminated. So in that case, we need to
3518 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3520 if (tcp
[entry
->length
- 1] != 0) {
3521 char *tmpstr
= malloc(entry
->length
+ 1);
3522 if (tmpstr
== NULL
) {
3526 // Can't use strlcpy here: tcp is not NUL-terminated!
3527 memcpy(tmpstr
, tcp
, entry
->length
);
3528 tmpstr
[entry
->length
] = 0;
3529 acl
= acl_from_text(tmpstr
);
3532 acl
= acl_from_text(tcp
);
3539 if ((fsec_tmp
= filesec_init()) == NULL
)
3541 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
3543 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
3546 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
3548 if (errno
== ENOTSUP
)
3550 if (retry
&& !copyfile_unset_acl(s
))
3556 copyfile_warn("setting security information");
3562 filesec_free(fsec_tmp
);
3569 /* And, finally, everything else */
3572 if (s
->copyIntent
||
3573 xattr_preserve_for_intent((char*)entry
->name
, s
->copyIntent
) == 1) {
3576 s
->xattr_name
= strdup((char*)entry
->name
);
3578 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3579 if (s
->xattr_name
) {
3580 free(s
->xattr_name
);
3581 s
->xattr_name
= NULL
;
3583 if (rv
== COPYFILE_QUIT
) {
3589 if (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0) == -1) {
3590 if (COPYFILE_VERBOSE
& s
->flags
)
3591 copyfile_warn("error %d setting attribute %s", errno
, entry
->name
);
3595 s
->xattr_name
= strdup((char*)entry
->name
);
3596 rv
= (s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3597 if (s
->xattr_name
) {
3598 free(s
->xattr_name
);
3599 s
->xattr_name
= NULL
;
3601 if (rv
== COPYFILE_QUIT
) {
3609 } else if (s
->statuscb
) {
3611 s
->xattr_name
= strdup((char*)entry
->name
);
3612 s
->totalCopied
= entry
->length
;
3613 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3614 if (s
->xattr_name
) {
3615 free(s
->xattr_name
);
3616 s
->xattr_name
= NULL
;
3618 if (rv
== COPYFILE_QUIT
) {
3630 entry
= ATTR_NEXT(entry
);
3635 * Extract the Finder Info.
3637 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
3642 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
3646 enum { kFinderInvisibleMask
= 1 << 14 };
3648 newFinfo
= (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
;
3649 fFlags
= (uint16_t*)&newFinfo
[8];
3650 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
3653 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3654 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3655 s
->xattr_name
= NULL
;
3656 if (rv
== COPYFILE_QUIT
) {
3660 } else if (rv
== COPYFILE_SKIP
) {
3664 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
3668 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3669 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3670 s
->xattr_name
= NULL
;
3671 if (rv
== COPYFILE_QUIT
) {
3678 } else if (s
->statuscb
) {
3680 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3681 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3682 s
->xattr_name
= NULL
;
3683 if (rv
== COPYFILE_QUIT
) {
3689 if (SWAP16(*fFlags
) & kFinderInvisibleMask
)
3690 s
->internal_flags
|= cfMakeFileInvisible
;
3695 * Extract the Resource Fork.
3697 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
3698 adhdr
->entries
[1].length
> 0)
3700 void * rsrcforkdata
= NULL
;
3704 struct attrlist attrlist
;
3706 /* Order of these structs matters for setattrlist. */
3707 struct timespec mod_time
;
3708 struct timespec acc_time
;
3711 length
= adhdr
->entries
[1].length
;
3712 offset
= adhdr
->entries
[1].offset
;
3713 rsrcforkdata
= malloc(length
);
3715 if (rsrcforkdata
== NULL
) {
3716 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3722 if (fstat(s
->dst_fd
, &sb
) < 0)
3724 copyfile_debug(1, "couldn't stat destination file");
3729 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
3730 if (bytes
< (ssize_t
)length
)
3734 copyfile_debug(1, "couldn't read resource fork");
3739 "couldn't read resource fork (only read %d bytes of %d)",
3740 (int)bytes
, (int)length
);
3747 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3748 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3749 s
->xattr_name
= NULL
;
3750 if (rv
== COPYFILE_QUIT
) {
3756 } else if (rv
== COPYFILE_SKIP
) {
3760 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
3764 * For filesystems that do not natively support named attributes,
3765 * the kernel creates an AppleDouble file that -- for compatabilty
3766 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3767 * structure that says there are no resources. So, if fsetxattr has
3768 * failed, and the resource fork is that empty structure, *and* the
3769 * target file is a directory, then we do nothing with it.
3771 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
3772 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
3773 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
3774 copyfile_debug(2, "not setting empty resource fork on directory");
3780 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3781 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3782 s
->xattr_name
= NULL
;
3783 if (rv
== COPYFILE_CONTINUE
) {
3788 copyfile_debug(1, "error %d setting resource fork attribute", error
);
3791 } else if (s
->statuscb
) {
3793 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3794 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3795 s
->xattr_name
= NULL
;
3796 if (rv
== COPYFILE_QUIT
) {
3804 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3805 XATTR_RESOURCEFORK_NAME
, (int)length
);
3807 if (!(s
->flags
& COPYFILE_STAT
))
3809 /* Try to set m/atimes using setattrlist(), for nanosecond precision. */
3810 memset(&attrlist
, 0, sizeof(attrlist
));
3811 attrlist
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
3812 attrlist
.commonattr
= ATTR_CMN_MODTIME
| ATTR_CMN_ACCTIME
;
3813 ma_times
.mod_time
= sb
.st_mtimespec
;
3814 ma_times
.acc_time
= sb
.st_atimespec
;
3815 if (fsetattrlist(s
->dst_fd
, &attrlist
, &ma_times
, sizeof(ma_times
), 0) != 0) {
3816 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
3824 if (COPYFILE_STAT
& s
->flags
)
3826 error
= copyfile_stat(s
);
3829 if (buffer
) free(buffer
);
3830 if (dataptr
) free(dataptr
);
3834 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3837 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
3838 size_t qlen
= sizeof(qbuf
);
3840 if (s
->qinfo
== NULL
)
3846 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
3852 *buf
= malloc(qlen
);
3855 memcpy(*buf
, qbuf
, qlen
);
3862 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3868 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
3870 if (errno
!= ENOENT
)
3873 if (COPYFILE_VERBOSE
& s
->flags
)
3874 copyfile_warn("getting acl");
3880 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
3883 * acl_to_text() doesn't include the NUL at the endo
3884 * in it's count (*len). It does, however, promise to
3885 * return a valid C string, so we need to up the count
3889 *buf
= malloc(*len
);
3891 memcpy(*buf
, acl_text
, *len
);
3896 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
3903 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
3906 char *databuf
= NULL
;
3911 * do COPYFILE_COPY_XATTR here; no need to
3912 * the work if we want to skip.
3919 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3921 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3922 s
->xattr_name
= NULL
;
3923 if (rv
== COPYFILE_SKIP
) {
3927 if (rv
== COPYFILE_QUIT
) {
3933 /* Get the resource fork size */
3934 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
3936 if (COPYFILE_VERBOSE
& s
->flags
)
3937 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
3941 if (datasize
> INT_MAX
) {
3949 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3952 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3953 s
->xattr_name
= NULL
;
3954 if (rv
== COPYFILE_QUIT
) {
3960 if ((databuf
= malloc(datasize
)) == NULL
)
3962 copyfile_warn("malloc");
3967 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
3969 if (COPYFILE_VERBOSE
& s
->flags
)
3970 copyfile_warn("couldn't read entire resource fork");
3975 /* Write the resource fork to disk. */
3976 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
3978 if (COPYFILE_VERBOSE
& s
->flags
)
3979 copyfile_warn("couldn't write resource fork");
3984 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3985 if (rv
== COPYFILE_QUIT
) {
3990 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3991 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
3992 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
3995 if (ret
== -1 && s
->statuscb
)
3998 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3999 if (rv
== COPYFILE_CONTINUE
)
4002 if (s
->xattr_name
) {
4003 s
->xattr_name
= NULL
;
4010 * Do status callback here
4011 * If ret == -1, then error callback
4017 * The opposite of copyfile_unpack(), obviously.
4019 static int copyfile_pack(copyfile_state_t s
)
4021 char *attrnamebuf
= NULL
, *endnamebuf
;
4022 void *databuf
= NULL
;
4023 attr_header_t
*filehdr
, *endfilehdr
;
4024 attr_entry_t
*entry
;
4025 ssize_t listsize
= 0;
4031 int hasrsrcfork
= 0;
4033 int seenq
= 0; // Have we seen any quarantine info already?
4035 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_HDR_SIZE
);
4037 if (filehdr
== NULL
) {
4041 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_HDR_SIZE
);
4044 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
4045 if (attrnamebuf
== NULL
) {
4049 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
4053 * Fill in the Apple Double Header defaults.
4055 filehdr
->appledouble
.magic
= ADH_MAGIC
;
4056 filehdr
->appledouble
.version
= ADH_VERSION
;
4057 filehdr
->appledouble
.numEntries
= 2;
4058 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
4059 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
4060 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
4061 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
4062 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
4063 filehdr
->appledouble
.entries
[1].length
= 0;
4064 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
4067 * Fill in the initial Attribute Header.
4069 filehdr
->magic
= ATTR_HDR_MAGIC
;
4070 filehdr
->debug_tag
= 0;
4071 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
4074 * Collect the attribute names.
4076 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
4079 * Test if there are acls to copy
4081 if (COPYFILE_ACL
& s
->flags
)
4083 acl_t temp_acl
= NULL
;
4084 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
4086 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
4089 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
4090 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
4091 endnamebuf
= attrnamebuf
+ offset
;
4097 if (COPYFILE_XATTR
& s
->flags
)
4099 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
4100 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
4102 copyfile_debug(2, "no extended attributes found (%d)", errno
);
4104 if (listsize
> left
)
4106 copyfile_debug(1, "extended attribute list too long");
4110 endnamebuf
= attrnamebuf
+ offset
+ (listsize
> 0 ? listsize
: 0);
4111 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
4117 sort_xattrname_list(attrnamebuf
, endnamebuf
- attrnamebuf
);
4119 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
4121 namelen
= strlen(nameptr
) + 1;
4122 /* Skip over FinderInfo or Resource Fork names */
4123 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
4124 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
4127 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
4131 /* The system should prevent this from happening, but... */
4132 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
4133 namelen
= XATTR_MAXNAMELEN
+ 1;
4135 if (s
->copyIntent
&&
4136 xattr_preserve_for_intent(nameptr
, s
->copyIntent
) == 0) {
4138 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
4139 memmove(nameptr
, nameptr
+ namelen
, amt
);
4140 endnamebuf
-= namelen
;
4141 /* Set namelen to 0 so continue doesn't miss names */
4148 char eaname
[namelen
];
4149 bcopy(nameptr
, eaname
, namelen
);
4150 eaname
[namelen
- 1] = 0; // Just to be sure!
4151 s
->xattr_name
= eaname
;
4152 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4153 s
->xattr_name
= NULL
;
4154 if (rv
== COPYFILE_QUIT
) {
4158 } else if (rv
== COPYFILE_SKIP
) {
4159 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
4160 memmove(nameptr
, nameptr
+ namelen
, amt
);
4161 endnamebuf
-= namelen
;
4162 /* Set namelen to 0 so continue doesn't miss names */
4167 entry
->namelen
= namelen
;
4169 if (nameptr
+ namelen
> endnamebuf
) {
4174 bcopy(nameptr
, &entry
->name
[0], namelen
);
4175 copyfile_debug(2, "copied name [%s]", entry
->name
);
4177 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
4178 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
4180 if ((void*)entry
>= (void*)endfilehdr
) {
4185 /* Update the attributes header. */
4186 filehdr
->num_attrs
++;
4187 filehdr
->data_start
+= (u_int32_t
)entrylen
;
4192 * If we have any quarantine data, we always pack it.
4193 * But if we've already got it in the EA list, don't put it in again.
4195 if (s
->qinfo
&& !seenq
)
4197 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
4198 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
4199 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
4204 * Collect the attribute data.
4206 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
4208 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
+ 1)
4210 namelen
= strlen(nameptr
);
4212 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
4213 copyfile_pack_acl(s
, &databuf
, &datasize
);
4214 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
4216 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
4218 /* Check for Finder Info. */
4219 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
4224 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
4225 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4226 s
->xattr_name
= NULL
;
4227 if (rv
== COPYFILE_QUIT
)
4229 s
->xattr_name
= NULL
;
4234 else if (rv
== COPYFILE_SKIP
)
4236 s
->xattr_name
= NULL
;
4240 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4241 s
->xattr_name
= NULL
;
4242 if (rv
== COPYFILE_QUIT
)
4249 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
4254 s
->xattr_name
= strdup(nameptr
);
4255 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4256 if (s
->xattr_name
) {
4257 free(s
->xattr_name
);
4258 s
->xattr_name
= NULL
;
4260 if (rv
== COPYFILE_QUIT
) {
4265 if (COPYFILE_VERBOSE
& s
->flags
)
4266 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4267 } else if (datasize
!= 32)
4269 if (COPYFILE_VERBOSE
& s
->flags
)
4270 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
4273 if (COPYFILE_VERBOSE
& s
->flags
)
4274 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
4275 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
4278 s
->xattr_name
= strdup(nameptr
);
4279 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4280 if (s
->xattr_name
) {
4281 free(s
->xattr_name
);
4282 s
->xattr_name
= NULL
;
4284 if (rv
== COPYFILE_QUIT
) {
4290 continue; /* finder info doesn't have an attribute entry */
4292 /* Check for Resource Fork. */
4293 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
4299 /* Just a normal attribute. */
4303 s
->xattr_name
= strdup(nameptr
);
4305 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4306 if (s
->xattr_name
) {
4307 free(s
->xattr_name
);
4308 s
->xattr_name
= NULL
;
4311 * Due to the nature of the packed file, we can't skip at this point.
4313 if (rv
== COPYFILE_QUIT
)
4320 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
4325 if (COPYFILE_VERBOSE
& s
->flags
)
4326 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4330 s
->xattr_name
= strdup(nameptr
);
4331 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4332 if (s
->xattr_name
) {
4333 free(s
->xattr_name
);
4334 s
->xattr_name
= NULL
;
4336 if (rv
== COPYFILE_QUIT
)
4345 if (datasize
> XATTR_MAXATTRLEN
)
4347 if (COPYFILE_VERBOSE
& s
->flags
)
4348 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
4351 databuf
= malloc(datasize
);
4352 if (databuf
== NULL
) {
4356 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
4359 s
->xattr_name
= strdup(nameptr
);
4360 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4361 if (s
->xattr_name
) {
4362 free(s
->xattr_name
);
4363 s
->xattr_name
= NULL
;
4365 if (rv
== COPYFILE_QUIT
) {
4373 entry
->length
= (u_int32_t
)datasize
;
4374 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
4376 filehdr
->data_length
+= (u_int32_t
)datasize
;
4380 * This assumes that the data is fits in memory (not
4381 * the case when there are lots of attributes or one of
4382 * the attributes is very large.
4384 if (entry
->offset
> ATTR_MAX_SIZE
||
4385 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
4388 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
4391 if (pwrite(s
->dst_fd
, databuf
, datasize
, entry
->offset
) != datasize
) {
4397 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
4399 /* bump to next entry */
4400 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
4401 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
4404 /* Now we know where the resource fork data starts. */
4405 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
4407 /* We also know the size of the "Finder Info entry. */
4408 filehdr
->appledouble
.entries
[0].length
=
4409 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
4411 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
4413 /* Copy Resource Fork. */
4414 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
4417 /* Write the header to disk. */
4418 datasize
= filehdr
->data_start
;
4420 swap_adhdr(&filehdr
->appledouble
);
4421 swap_attrhdr(filehdr
);
4422 swap_attrhdr_entries(filehdr
);
4424 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
4426 if (COPYFILE_VERBOSE
& s
->flags
)
4427 copyfile_warn("couldn't write file header");
4432 if (filehdr
) free(filehdr
);
4433 if (attrnamebuf
) free(attrnamebuf
);
4438 return copyfile_stat(s
);