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 infomration 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 #ifndef _COPYFILE_TEST
314 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
315 # define copyfile_debug(d, str, ...) \
317 if (s && (d <= s->debug)) {\
318 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
322 #define copyfile_warn(str, ...) \
323 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
324 # define copyfile_debug(d, str, ...) \
326 if (s && (d <= s->debug)) {\
327 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
332 static int copyfile_quarantine(copyfile_state_t s
)
335 if (s
->qinfo
== NULL
)
338 s
->qinfo
= qtn_file_alloc();
339 if (s
->qinfo
== NULL
)
344 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
346 qtn_file_free(s
->qinfo
);
357 add_uberace(acl_t
*acl
)
360 acl_permset_t permset
;
363 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
367 * First, we create an entry, and give it the special name
368 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
369 * After that, we clear out all the permissions in it, and
370 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
371 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
372 * the functionality, and put this into the ACL.
374 if (acl_create_entry_np(acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
376 if (acl_get_permset(entry
, &permset
) == -1) {
377 copyfile_warn("acl_get_permset");
380 if (acl_clear_perms(permset
) == -1) {
381 copyfile_warn("acl_clear_permset");
384 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1) {
385 copyfile_warn("add ACL_WRITE_DATA");
388 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1) {
389 copyfile_warn("add ACL_WRITE_ATTRIBUTES");
392 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1) {
393 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES");
396 if (acl_add_perm(permset
, ACL_APPEND_DATA
) == -1) {
397 copyfile_warn("add ACL_APPEND_DATA");
400 if (acl_add_perm(permset
, ACL_WRITE_SECURITY
) == -1) {
401 copyfile_warn("add ACL_WRITE_SECURITY");
404 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1) {
405 copyfile_warn("set ACL_EXTENDED_ALLOW");
409 if(acl_set_permset(entry
, permset
) == -1) {
410 copyfile_warn("acl_set_permset");
413 if(acl_set_qualifier(entry
, qual
) == -1) {
414 copyfile_warn("acl_set_qualifier");
424 is_uberace(acl_entry_t ace
)
427 acl_permset_t perms
, tperms
;
434 // Who am I, and who is the ACE for?
435 mbr_uid_to_uuid(geteuid(), myuuid
);
436 qual
= (guid_t
*)acl_get_qualifier(ace
);
438 // Need to create a temporary acl, so I can get the uberace template.
444 if (acl_get_entry(tacl
, ACL_FIRST_ENTRY
, &tentry
) != 0) {
447 acl_get_permset(tentry
, &tperms
);
450 acl_get_tag_type(ace
, &tag
);
451 acl_get_permset(ace
, &perms
);
453 if (tag
== ACL_EXTENDED_ALLOW
&&
454 (memcmp(qual
, myuuid
, sizeof(myuuid
)) == 0) &&
455 acl_compare_permset_np(tperms
, perms
))
470 remove_uberace(int fd
, struct stat
*sbuf
)
472 filesec_t fsec
= NULL
;
477 fsec
= filesec_init();
482 if (fstatx_np(fd
, &sb
, fsec
) != 0) {
483 if (errno
== ENOTSUP
)
488 if (filesec_get_property(fsec
, FILESEC_ACL
, &acl
) != 0) {
492 if (acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
) == 0) {
493 if (is_uberace(entry
))
495 mode_t m
= sbuf
->st_mode
& ~S_IFMT
;
497 if (acl_delete_entry(acl
, entry
) != 0 ||
498 filesec_set_property(fsec
, FILESEC_ACL
, &acl
) != 0 ||
499 filesec_set_property(fsec
, FILESEC_MODE
, &m
) != 0 ||
500 fchmodx_np(fd
, fsec
) != 0)
513 fchmod(fd
, sbuf
->st_mode
& ~S_IFMT
);
518 reset_security(copyfile_state_t s
)
520 /* If we haven't reset the file security information
521 * (COPYFILE_SECURITY is not set in flags)
522 * restore back the permissions the file had originally
524 * One of the reasons this seems so complicated is that
525 * it is partially at odds with copyfile_security().
527 * Simplisticly, we are simply trying to make sure we
528 * only copy what was requested, and that we don't stomp
529 * on what wasn't requested.
532 #ifdef COPYFILE_RECURSIVE
533 if (s
->dst_fd
> -1) {
536 if (s
->src_fd
> -1 && (s
->flags
& COPYFILE_STAT
))
537 fstat(s
->src_fd
, &sbuf
);
539 fstat(s
->dst_fd
, &sbuf
);
541 if (!(s
->internal_flags
& cfDelayAce
))
542 remove_uberace(s
->dst_fd
, &sbuf
);
545 if (s
->permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
546 if (s
->flags
& COPYFILE_ACL
) {
547 /* Just need to reset the BSD information -- mode, owner, group */
548 (void)fchown(s
->dst_fd
, s
->dst_sb
.st_uid
, s
->dst_sb
.st_gid
);
549 (void)fchmod(s
->dst_fd
, s
->dst_sb
.st_mode
);
552 * flags is either COPYFILE_STAT, or neither; if it's
553 * neither, then we restore both ACL and POSIX permissions;
554 * if it's STAT, however, then we only want to restore the
555 * ACL (which may be empty). We do that by removing the
556 * POSIX information from the filesec object.
558 if (s
->flags
& COPYFILE_STAT
) {
559 copyfile_unset_posix_fsec(s
->original_fsec
);
561 if (fchmodx_np(s
->dst_fd
, s
->original_fsec
) < 0 && errno
!= ENOTSUP
)
562 copyfile_warn("restoring security information");
566 if (s
->permissive_fsec
) {
567 filesec_free(s
->permissive_fsec
);
568 s
->permissive_fsec
= NULL
;
571 if (s
->original_fsec
) {
572 filesec_free(s
->original_fsec
);
573 s
->original_fsec
= NULL
;
581 * copytree -- recursively copy a hierarchy.
583 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
584 * Care is taken to keep the ACLs set up correctly, in addition to the
585 * normal copying that is done. (When copying a hierarchy, we can't
586 * get rid of the "allow-all-writes" ACE on a directory until we're done
587 * copying the *contents* of the directory.)
589 * The other big difference from copyfile (for the moment) is that copytree()
590 * will use a call-back function to pass along information about what is
591 * about to be copied, and whether or not it succeeded.
593 * copytree() is called from copyfile() -- but copytree() itself then calls
594 * copyfile() to copy each individual object.
596 * XXX - no effort is made to handle overlapping hierarchies at the moment.
601 copytree(copyfile_state_t s
)
605 int (*sfunc
)(const char *, struct stat
*);
606 copyfile_callback_t status
= NULL
;
607 char srcisdir
= 0, dstisdir
= 0, dstexists
= 0;
610 const char *dstpathsep
= "";
612 char srcpath
[PATH_MAX
* 2 + 1], dstpath
[PATH_MAX
* 2 + 1];
618 const char *paths
[2] = { 0 };
619 unsigned int flags
= 0;
620 int fts_flags
= FTS_NOCHDIR
;
621 dev_t last_dev
= s
->sb
.st_dev
;
628 if (s
->flags
& (COPYFILE_MOVE
| COPYFILE_UNLINK
| COPYFILE_CHECK
| COPYFILE_PACK
| COPYFILE_UNPACK
)) {
634 flags
= s
->flags
& (COPYFILE_ALL
| COPYFILE_NOFOLLOW
| COPYFILE_VERBOSE
| COPYFILE_EXCL
);
636 paths
[0] = src
= s
->src
;
639 if (src
== NULL
|| dst
== NULL
) {
645 sfunc
= (flags
& COPYFILE_NOFOLLOW_SRC
) ? lstat
: stat
;
646 if ((sfunc
)(src
, &sbuf
) == -1) {
650 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
654 sfunc
= (flags
& COPYFILE_NOFOLLOW_DST
) ? lstat
: stat
;
655 if ((sfunc
)(dst
, &sbuf
) == -1) {
656 if (errno
!= ENOENT
) {
662 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
668 // This doesn't handle filesystem crossing and case sensitivity
669 // So there's got to be a better way
671 if (realpath(src
, srcpath
) == NULL
) {
676 if (realpath(dst
, dstpath
) == NULL
&&
677 (errno
== ENOENT
&& realpath(dirname(dst
), dstpath
) == NULL
)) {
681 if (strstr(srcpath
, dstpath
) != NULL
) {
687 srcroot
= basename((char*)src
);
688 if (srcroot
== NULL
) {
694 * To work on as well:
695 * We have a few cases when copying a hierarchy:
696 * 1) src is a non-directory, dst is a directory;
697 * 2) src is a non-directory, dst is a non-directory;
698 * 3) src is a non-directory, dst does not exist;
699 * 4) src is a directory, dst is a directory;
700 * 5) src is a directory, dst is a non-directory;
701 * 6) src is a directory, dst does not exist
703 * (1) copies src to dst/basename(src).
704 * (2) fails if COPYFILE_EXCL is set, otherwise copies src to dst.
705 * (3) and (6) copy src to the name dst.
706 * (4) copies the contents of src to the contents of dst.
711 // copy /path/to/src to /path/to/dst/src
712 // Append "/" and (fts_path - strlen(basename(src))) to dst?
714 slash
= strrchr(src
, '/');
718 offset
= slash
- src
+ 1;
720 // copy /path/to/src to /path/to/dst
721 // append (fts_path + strlen(src)) to dst?
723 offset
= strlen(src
);
726 if (s
->flags
| COPYFILE_NOFOLLOW_SRC
)
727 fts_flags
|= FTS_PHYSICAL
;
729 fts_flags
|= FTS_LOGICAL
;
731 fts
= fts_open((char * const *)paths
, fts_flags
, NULL
);
733 status
= s
->statuscb
;
734 while ((ftsent
= fts_read(fts
)) != NULL
) {
736 char *dstfile
= NULL
;
738 copyfile_state_t tstate
= copyfile_state_alloc();
739 if (tstate
== NULL
) {
744 tstate
->statuscb
= s
->statuscb
;
745 tstate
->ctx
= s
->ctx
;
746 if (last_dev
== ftsent
->fts_dev
) {
747 tstate
->internal_flags
|= (s
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
749 last_dev
= ftsent
->fts_dev
;
751 asprintf(&dstfile
, "%s%s%s", dst
, dstpathsep
, ftsent
->fts_path
+ offset
);
752 if (dstfile
== NULL
) {
753 copyfile_state_free(tstate
);
758 switch (ftsent
->fts_info
) {
760 tstate
->internal_flags
|= cfDelayAce
;
761 cmd
= COPYFILE_RECURSE_DIR
;
767 cmd
= COPYFILE_RECURSE_FILE
;
770 cmd
= COPYFILE_RECURSE_DIR_CLEANUP
;
777 errno
= ftsent
->fts_errno
;
779 rv
= (*status
)(COPYFILE_RECURSE_ERROR
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
780 if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
784 if (rv
== COPYFILE_QUIT
) {
797 if (cmd
== COPYFILE_RECURSE_DIR
|| cmd
== COPYFILE_RECURSE_FILE
) {
799 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
800 if (rv
== COPYFILE_SKIP
) {
801 if (cmd
== COPYFILE_RECURSE_DIR
) {
802 rv
= fts_set(fts
, ftsent
, FTS_SKIP
);
804 rv
= (*status
)(0, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
805 if (rv
== COPYFILE_QUIT
)
811 if (rv
== COPYFILE_QUIT
) {
812 retval
= -1; errno
= 0;
816 int tmp_flags
= (cmd
== COPYFILE_RECURSE_DIR
) ? (flags
& ~COPYFILE_STAT
) : flags
;
817 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, tmp_flags
);
820 rv
= (*status
)(cmd
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
821 if (rv
== COPYFILE_QUIT
) {
833 rv
= (*status
)(cmd
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
834 if (rv
== COPYFILE_QUIT
) {
835 retval
= -1; errno
= 0;
839 } else if (cmd
== COPYFILE_RECURSE_DIR_CLEANUP
) {
841 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
842 if (rv
== COPYFILE_QUIT
) {
843 retval
= -1; errno
= 0;
845 } else if (rv
== COPYFILE_SKIP
) {
850 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, (flags
& COPYFILE_NOFOLLOW
) | COPYFILE_STAT
);
853 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
854 if (rv
== COPYFILE_QUIT
) {
857 } else if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
858 if (rv
== COPYFILE_CONTINUE
)
869 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
870 if (rv
== COPYFILE_QUIT
) {
871 retval
= -1; errno
= 0;
881 s
->internal_flags
&= ~COPYFILE_MNT_CPROTECT_MASK
;
882 s
->internal_flags
|= (tstate
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
884 copyfile_state_free(tstate
);
898 * fcopyfile() is used to copy a source file descriptor to a destination file
899 * descriptor. This allows an application to figure out how it wants to open
900 * the files (doing various security checks, perhaps), and then just pass in
901 * the file descriptors.
903 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
906 copyfile_state_t s
= state
;
909 if (src_fd
< 0 || dst_fd
< 0)
915 if (copyfile_preamble(&s
, flags
) < 0)
918 copyfile_debug(2, "set src_fd <- %d", src_fd
);
919 if (s
->src_fd
== -2 && src_fd
> -1)
922 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
924 if (errno
== ENOTSUP
|| errno
== EPERM
)
925 fstat(s
->src_fd
, &s
->sb
);
928 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
934 /* prevent copying on unsupported types */
935 switch (s
->sb
.st_mode
& S_IFMT
)
946 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
947 if (s
->dst_fd
== -2 && dst_fd
> -1)
950 (void)fstat(s
->dst_fd
, &dst_sb
);
951 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
953 (void)copyfile_quarantine(s
);
955 ret
= copyfile_internal(s
, flags
);
957 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
959 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
968 copyfile_state_free(s
);
977 * This routine implements the clonefileat functionality
978 * for copyfile. There are 2 kinds of clone flags, namely
979 * 1. COPYFILE_CLONE_FORCE which is a 'force' clone flag.
980 * 2. COPYFILE_CLONE which is a 'best try' flag.
981 * In both cases, we inherit the flags provided
982 * to copyfile call and clone the file.
983 * Both these flags are equivalent to
984 * (COPYFILE_EXCL | COPYFILE_ACL | COPYFILE_STAT | COPYFILE_XATTR | COPYFILE_DATA)
985 * With force clone flag set, we return failure if cloning fails,
986 * however, in case of best try flag, we fallback to the copy method.
989 static int copyfile_clone(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
995 if (lstat(src
, &src_sb
) != 0)
1001 if (COPYFILE_NOFOLLOW
& flags
)
1003 cloneFlags
= CLONE_NOFOLLOW
;
1007 * Support only for files and symbolic links.
1008 * TODO:Remove this check when support for directories is added.
1010 if (S_ISREG(src_sb
.st_mode
) || S_ISLNK(src_sb
.st_mode
))
1013 * COPYFILE_UNLINK tells us to try removing the destination
1014 * before we create it. We don't care if the file doesn't
1015 * exist, so we ignore ENOENT.
1017 if (flags
& COPYFILE_UNLINK
)
1019 if (remove(dst
) < 0 && errno
!= ENOENT
)
1024 ret
= clonefileat(AT_FDCWD
, src
, AT_FDCWD
, dst
, cloneFlags
);
1027 * We could also report the size of the single
1028 * object that was cloned. However, that's a lot
1029 * more difficult when we eventually support
1030 * cloning directories. It seems reasonable to NOT
1031 * report any bytes being "copied" in this scenario,
1032 * and let the caller figure out how they want to
1036 state
->was_cloned
= true;
1048 * the original copyfile() routine; this copies a source file to a destination
1049 * file. Note that because we need to set the names in the state variable, this
1050 * is not just the same as opening the two files, and then calling fcopyfile().
1051 * Oh, if only life were that simple!
1053 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
1057 copyfile_state_t s
= state
;
1060 if (src
== NULL
&& dst
== NULL
)
1066 if (flags
& (COPYFILE_CLONE_FORCE
| COPYFILE_CLONE
))
1068 ret
= copyfile_clone(src
, dst
, state
, flags
);
1069 if ((ret
== 0) || (flags
& COPYFILE_CLONE_FORCE
))
1073 // cloning failed. Inherit clonefile flags required for
1074 // falling back to copyfile.
1075 flags
= flags
| (COPYFILE_EXCL
| COPYFILE_ACL
|
1076 COPYFILE_STAT
| COPYFILE_XATTR
| COPYFILE_DATA
);
1077 flags
= flags
& (~COPYFILE_CLONE
);
1080 if (copyfile_preamble(&s
, flags
) < 0)
1086 * This macro is... well, it's not the worst thing you can do with cpp, not
1087 * by a long shot. Essentially, we are setting the filename (src or dst)
1088 * in the state structure; since the structure may not have been cleared out
1089 * before being used again, we do some of the cleanup here: if the given
1090 * filename (e.g., src) is set, and state->src is not equal to that, then
1091 * we need to check to see if the file descriptor had been opened, and if so,
1092 * close it. After that, we set state->src to be a copy of the given filename,
1093 * releasing the old copy if necessary.
1095 #define COPYFILE_SET_FNAME(NAME, S) \
1097 if (NAME != NULL) { \
1098 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
1099 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
1100 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
1101 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
1102 close(S->NAME##_fd); \
1103 S->NAME##_fd = -2; \
1110 if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \
1115 COPYFILE_SET_FNAME(src
, s
);
1116 COPYFILE_SET_FNAME(dst
, s
);
1118 if (s
->flags
& COPYFILE_RECURSIVE
) {
1124 * Get a copy of the source file's security settings
1126 if (s
->original_fsec
) {
1127 filesec_free(s
->original_fsec
);
1128 s
->original_fsec
= NULL
;
1130 if ((s
->original_fsec
= filesec_init()) == NULL
)
1133 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
1134 ((dst_sb
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1135 if (s
->permissive_fsec
)
1136 free(s
->permissive_fsec
);
1137 s
->permissive_fsec
= NULL
;
1138 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
1141 * copyfile_fix_perms() will make a copy of the permission set,
1142 * and insert at the beginning an ACE that ensures we can write
1143 * to the file and set attributes.
1146 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
1149 * Set the permissions for the destination to our copy.
1150 * We should get ENOTSUP from any filesystem that simply
1151 * doesn't support it.
1153 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
1155 copyfile_warn("setting security information");
1156 filesec_free(s
->permissive_fsec
);
1157 s
->permissive_fsec
= NULL
;
1160 } else if (errno
== ENOENT
) {
1165 * If COPYFILE_CHECK is set in flags, then all we are going to do
1166 * is see what kinds of things WOULD have been copied (see
1167 * copyfile_check() below). We return that value.
1169 if (COPYFILE_CHECK
& flags
)
1171 ret
= copyfile_check(s
);
1173 } else if ((ret
= copyfile_open(s
)) < 0)
1176 (void)fcntl(s
->src_fd
, F_NOCACHE
, 1);
1177 (void)fcntl(s
->dst_fd
, F_NOCACHE
, 1);
1178 #ifdef F_SINGLE_WRITER
1179 (void)fcntl(s
->dst_fd
, F_SINGLE_WRITER
, 1);
1182 ret
= copyfile_internal(s
, flags
);
1186 #ifdef COPYFILE_RECURSIVE
1187 if (!(flags
& COPYFILE_STAT
)) {
1190 /* Just need to reset the BSD information -- mode, owner, group */
1191 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
1192 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
1199 if (s
->src
&& (flags
& COPYFILE_MOVE
))
1200 (void)remove(s
->src
);
1203 if (state
== NULL
) {
1205 copyfile_state_free(s
);
1221 * Shared prelude to the {f,}copyfile(). This initializes the
1222 * state variable, if necessary, and also checks for both debugging
1223 * and disabling environment variables.
1225 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
1231 if ((*state
= copyfile_state_alloc()) == NULL
)
1237 if (COPYFILE_DEBUG
& flags
)
1240 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
1243 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
1245 /* clamp s->debug to 1 if the environment variable is not parsable */
1246 if (s
->debug
== 0 && errno
!= 0)
1249 copyfile_debug(2, "debug value set to: %d", s
->debug
);
1253 /* Temporarily disabled */
1254 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
1256 copyfile_debug(1, "copyfile disabled");
1260 copyfile_debug(2, "setting flags: %d", s
->flags
);
1267 * The guts of {f,}copyfile().
1268 * This looks through the flags in a particular order, and calls the
1269 * associated functions.
1271 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
1275 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1277 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1283 * COPYFILE_PACK causes us to create an Apple Double version of the
1284 * source file, and puts it into the destination file. See
1285 * copyfile_pack() below for all the gory details.
1287 if (COPYFILE_PACK
& flags
)
1289 if ((ret
= copyfile_pack(s
)) < 0)
1291 if (s
->dst
) unlink(s
->dst
);
1298 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1299 * The goal there is to take an Apple Double file, and turn it
1300 * into a normal file (with data fork, resource fork, modes,
1301 * extended attributes, ACLs, etc.).
1303 if (COPYFILE_UNPACK
& flags
)
1305 if ((ret
= copyfile_unpack(s
)) < 0)
1313 * If we have quarantine info set, we attempt
1314 * to apply it to dst_fd. We don't care if
1315 * it fails, not yet anyway.
1323 * If COPYFILE_RUN_IN_PLACE is set, we need to add
1324 * QTN_FLAG_DO_NOT_TRANSLOCATE to the qinfo flags.
1326 * On iOS, qtn_file_get_flags & qtn_file_set_flags
1327 * don't modify anything, always return 0, per static
1328 * defines at top of this file, though we should never
1329 * get here in that case as qinfo will always be NULL.
1331 if (COPYFILE_RUN_IN_PLACE
& flags
)
1335 q_flags
= qtn_file_get_flags(s
->qinfo
);
1336 q_flags
|= QTN_FLAG_DO_NOT_TRANSLOCATE
;
1338 if (qtn_file_set_flags(s
->qinfo
, q_flags
) != 0) {
1339 s
->err
= errno
= EINVAL
;
1344 qr
= qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1349 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
1350 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1351 s
->xattr_name
= NULL
;
1352 if (rv
== COPYFILE_QUIT
) {
1353 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1357 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1364 * COPYFILE_XATTR tells us to copy the extended attributes;
1365 * this is seperate from the extended security (aka ACLs),
1366 * however. If we succeed in this, we continue to the next
1367 * stage; if we fail, we return with an error value. Note
1368 * that we fail if the errno is ENOTSUP, but we don't print
1369 * a warning in that case.
1371 if (COPYFILE_XATTR
& flags
)
1373 if ((ret
= copyfile_xattr(s
)) < 0)
1375 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1376 copyfile_warn("error processing extended attributes");
1382 * Simialr to above, this tells us whether or not to copy
1383 * the non-meta data portion of the file. We attempt to
1384 * remove (via unlink) the destination file if we fail.
1386 if (COPYFILE_DATA
& flags
)
1388 if ((ret
= copyfile_data(s
)) < 0)
1390 copyfile_warn("error processing data");
1391 if (s
->dst
&& unlink(s
->dst
))
1392 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1398 * COPYFILE_SECURITY requests that we copy the security, both
1399 * extended and mundane (that is, ACLs and POSIX).
1401 if (COPYFILE_SECURITY
& flags
)
1403 if ((ret
= copyfile_security(s
)) < 0)
1405 copyfile_warn("error processing security information");
1410 if (COPYFILE_STAT
& flags
)
1412 if ((ret
= copyfile_stat(s
)) < 0)
1414 copyfile_warn("error processing POSIX information");
1428 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1430 copyfile_state_t
copyfile_state_alloc(void)
1432 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1439 filesec_free(s
->fsec
);
1442 s
->fsec
= filesec_init();
1450 * copyfile_state_free() returns the memory allocated to the state structure.
1451 * It also closes the file descriptors, if they've been opened.
1453 int copyfile_state_free(copyfile_state_t s
)
1458 filesec_free(s
->fsec
);
1460 if (s
->original_fsec
)
1461 filesec_free(s
->original_fsec
);
1463 if (s
->permissive_fsec
)
1464 filesec_free(s
->permissive_fsec
);
1467 qtn_file_free(s
->qinfo
);
1469 if (copyfile_close(s
) < 0)
1471 copyfile_warn("error closing files");
1475 free(s
->xattr_name
);
1486 * Should we worry if we can't close the source? NFS says we
1487 * should, but it's pretty late for us at this point.
1489 static int copyfile_close(copyfile_state_t s
)
1491 if (s
->src
&& s
->src_fd
>= 0)
1494 if (s
->dst
&& s
->dst_fd
>= 0) {
1495 if (close(s
->dst_fd
))
1503 * The purpose of this function is to set up a set of permissions
1504 * (ACL and traditional) that lets us write to the file. In the
1505 * case of ACLs, we do this by putting in a first entry that lets
1506 * us write data, attributes, and extended attributes. In the case
1507 * of traditional permissions, we set the S_IWUSR (user-write)
1510 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1512 filesec_t ret_fsec
= NULL
;
1516 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1519 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1521 #ifdef COPYFILE_RECURSIVE
1522 if (add_uberace(&acl
))
1526 acl_permset_t permset
;
1529 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1533 * First, we create an entry, and give it the special name
1534 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1535 * After that, we clear out all the permissions in it, and
1536 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1537 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1538 * the functionality, and put this into the ACL.
1540 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1542 if (acl_get_permset(entry
, &permset
) == -1)
1544 if (acl_clear_perms(permset
) == -1)
1546 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1548 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1550 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1552 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1555 if(acl_set_permset(entry
, permset
) == -1)
1557 if(acl_set_qualifier(entry
, qual
) == -1)
1561 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1566 * This is for the normal, mundane, POSIX permission model.
1567 * We make sure that we can write to the file.
1569 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1571 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1573 mode
|= S_IWUSR
|S_IRUSR
;
1574 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1588 filesec_free(ret_fsec
);
1595 * Used to clear out the BSD/POSIX security information from
1599 copyfile_unset_posix_fsec(filesec_t fsec
)
1601 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1602 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1603 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1608 * Used to remove acl information from a filesec_t
1609 * Unsetting the acl alone in Tiger was insufficient
1611 static int copyfile_unset_acl(copyfile_state_t s
)
1614 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1616 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1619 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1621 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1624 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1626 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1633 * copyfile_open() does what one expects: it opens up the files
1634 * given in the state structure, if they're not already open.
1635 * It also does some type validation, to ensure that we only
1636 * handle file types we know about.
1638 static int copyfile_open(copyfile_state_t s
)
1640 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
1641 int islnk
= 0, isdir
= 0, isreg
= 0;
1642 int osrc
= 0, dsrc
= 0;
1643 int prot_class
= PROTECTION_CLASS_DEFAULT
;
1644 int set_cprot_explicit
= 0;
1647 if (s
->src
&& s
->src_fd
== -2)
1649 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1650 (s
->src
, &s
->sb
, s
->fsec
))
1652 copyfile_warn("stat on %s", s
->src
);
1656 /* prevent copying on unsupported types */
1657 switch (s
->sb
.st_mode
& S_IFMT
)
1661 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1662 s
->err
= ENOMEM
; /* too big for us to copy */
1674 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1680 * If we're packing, then we are actually
1681 * creating a file, no matter what the source
1684 if (s
->flags
& COPYFILE_PACK
) {
1686 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1687 * if the file is a symlink, and O_NOFOLLOW is specified,
1688 * open will return ELOOP, whether or not O_SYMLINK is set.
1689 * However, we know whether or not it was a symlink from
1690 * the stat above (although there is a potentiaal for a race
1691 * condition here, but it will err on the side of returning
1695 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1699 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1701 copyfile_warn("open on %s", s
->src
);
1704 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1706 (void)copyfile_quarantine(s
);
1709 if (s
->dst
&& s
->dst_fd
== -2)
1712 * COPYFILE_UNLINK tells us to try removing the destination
1713 * before we create it. We don't care if the file doesn't
1714 * exist, so we ignore ENOENT.
1716 if (COPYFILE_UNLINK
& s
->flags
)
1718 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1720 copyfile_warn("%s: remove", s
->dst
);
1725 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1729 if (lstat(s
->dst
, &st
) != -1) {
1730 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1735 if (!(s
->internal_flags
& cfSrcProtSupportValid
))
1737 if ((error
= does_copy_protection(s
->src_fd
)) > 0)
1739 s
->internal_flags
|= cfSrcSupportsCProtect
;
1743 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->src
, errno
);
1746 s
->internal_flags
|= cfSrcProtSupportValid
;
1749 /* copy protection is only valid for regular files and directories. */
1750 if ((isreg
|| isdir
) && (s
->internal_flags
& cfSrcSupportsCProtect
))
1752 prot_class
= GET_PROT_CLASS(s
->src_fd
);
1755 copyfile_warn("GET_PROT_CLASS failed on (%s) with error <%d>", s
->src
, errno
);
1761 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1766 copyfile_warn("cannot allocate %zd bytes", sz
);
1769 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1770 copyfile_warn("cannot readlink %s", s
->src
);
1774 if (symlink(bp
, s
->dst
) == -1) {
1775 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1776 copyfile_warn("Cannot make symlink %s", s
->dst
);
1782 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1783 if (s
->dst_fd
== -1) {
1784 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1789 mode
= (s
->sb
.st_mode
& ~S_IFMT
) | S_IRWXU
;
1791 if (mkdir(s
->dst
, mode
) == -1) {
1792 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1793 copyfile_warn("Cannot make directory %s", s
->dst
);
1797 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1798 if (s
->dst_fd
== -1) {
1799 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1802 set_cprot_explicit
= 1;
1803 } else while((s
->dst_fd
= open_dprotected_np(s
->dst
, oflags
| dsrc
, prot_class
, 0, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1806 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1807 * was written -- allow one to set an extended attribute on a file descriptor
1808 * for a read-only file, even if the file descriptor is opened for writing.
1809 * This will only matter if the file does not already exist.
1814 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1815 if (s
->flags
& COPYFILE_EXCL
)
1817 oflags
= oflags
& ~O_CREAT
;
1818 /* if O_CREAT isn't set in open_dprotected_np, it won't set protection class.
1819 * Set the flag here so we know to do it later.
1821 set_cprot_explicit
= 1;
1822 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
1824 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
1829 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
1833 * If we're trying to write to a directory to which we don't
1834 * have access, the create above would have failed, but chmod
1835 * here would have given us ENOENT. But the real error is
1836 * still one of access, so we change the errno we're reporting.
1837 * This could cause confusion with a race condition.
1840 if (errno
== ENOENT
)
1845 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
1846 if (((s
->flags
& COPYFILE_EXCL
) ||
1847 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
1848 && !(s
->flags
& COPYFILE_UNPACK
))
1850 oflags
= (oflags
& ~(O_WRONLY
|O_CREAT
|O_TRUNC
)) | O_RDONLY
;
1853 copyfile_warn("open on %s", s
->dst
);
1856 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
1858 if (s
->internal_flags
& cfSrcSupportsCProtect
)
1860 if (!(s
->internal_flags
& cfDstProtSupportValid
))
1862 if ((error
= does_copy_protection(s
->dst_fd
)) > 0)
1864 s
->internal_flags
|= cfDstSupportsCProtect
;
1868 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->dst
, errno
);
1871 s
->internal_flags
|= cfDstProtSupportValid
;
1874 if ((isreg
|| isdir
)
1875 && set_cprot_explicit
1876 && (s
->internal_flags
& cfDstSupportsCProtect
))
1878 /* Protection class is set in open_dprotected_np for regular files that aren't truncated.
1879 * We set the protection class here for truncated files and directories.
1881 if (SET_PROT_CLASS(s
->dst_fd
, prot_class
) != 0)
1883 copyfile_warn("SET_PROT_CLASS failed on (%s) with error <%d>", s
->dst
, errno
);
1890 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1892 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1893 s
->src_fd
, s
->dst_fd
);
1902 * copyfile_check(), as described above, essentially tells you
1903 * what you'd have to copy, if you wanted it to copy the things
1904 * you asked it to copy.
1905 * In other words, if you pass in COPYFILE_ALL, and the file in
1906 * question had no extended attributes but did have an ACL, you'd
1907 * get back COPYFILE_ACL.
1909 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
1912 copyfile_flags_t ret
= 0;
1913 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
1923 if (COPYFILE_XATTR
& s
->flags
)
1924 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
1926 ret
|= COPYFILE_XATTR
;
1929 if (COPYFILE_ACL
& s
->flags
)
1931 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1932 (s
->src
, &s
->sb
, s
->fsec
);
1934 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
1935 ret
|= COPYFILE_ACL
;
1938 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
1944 /* If the state has had quarantine info set already, we use that */
1945 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1947 qinfo
= qtn_file_alloc();
1949 * For quarantine information, we need to see if the source file
1950 * has any. Since it may be a symlink, however, and we may, or
1951 * not be following, *and* there's no qtn* routine which can optionally
1952 * follow or not follow a symlink, we need to instead work around
1961 * If we care about not following symlinks, *and* the file exists
1962 * (which is to say, lstat doesn't return an error), *and* the file
1963 * is a symlink, then we open it up (with O_SYMLINK), and use
1964 * qtn_file_init_with_fd(); if none of that is true, however, then
1965 * we can simply use qtn_file_init_with_path().
1968 && lstat(s
->src
, &sbuf
) == 0
1969 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1970 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
1972 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
1973 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1978 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
1979 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1982 qtn_file_free(qinfo
);
1990 * Attempt to copy the data section of a file. Using blockisize
1991 * is not necessarily the fastest -- it might be desirable to
1992 * specify a blocksize, somehow. But it's a size that should be
1993 * guaranteed to work.
1995 static int copyfile_data(copyfile_state_t s
)
2001 size_t iBlocksize
= 0;
2002 size_t oBlocksize
= 0;
2003 const size_t onegig
= 1 << 30;
2005 copyfile_callback_t status
= s
->statuscb
;
2007 /* Unless it's a normal file, we don't copy. For now, anyway */
2008 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
2011 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
2012 if (s
->internal_flags
& cfSawDecmpEA
) {
2013 if (s
->sb
.st_flags
& UF_COMPRESSED
) {
2014 if ((s
->flags
& COPYFILE_STAT
) == 0) {
2015 if (fchflags(s
->dst_fd
, UF_COMPRESSED
) == 0) {
2023 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
2024 iBlocksize
= s
->sb
.st_blksize
;
2026 iBlocksize
= sfs
.f_iosize
;
2029 /* Work-around for 6453525, limit blocksize to 1G */
2030 if (iBlocksize
> onegig
) {
2031 iBlocksize
= onegig
;
2034 if ((bp
= malloc(iBlocksize
)) == NULL
)
2037 if (fstatfs(s
->dst_fd
, &sfs
) == -1 || sfs
.f_iosize
== 0) {
2038 oBlocksize
= iBlocksize
;
2040 oBlocksize
= sfs
.f_iosize
;
2041 if (oBlocksize
> onegig
)
2042 oBlocksize
= onegig
;
2048 /* If supported, do preallocation for Xsan / HFS volumes */
2049 #ifdef F_PREALLOCATE
2054 fst
.fst_posmode
= F_PEOFPOSMODE
;
2056 fst
.fst_length
= s
->sb
.st_size
;
2057 /* Ignore errors; this is merely advisory. */
2058 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
2062 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
2065 size_t left
= nread
;
2070 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
2074 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
2081 copyfile_warn("writing to output file got error");
2083 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2084 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
2088 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
2097 ptr
= ((char*)ptr
) + nwritten
;
2101 s
->totalCopied
+= nwritten
;
2103 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
2104 if (rv
== COPYFILE_QUIT
) {
2105 ret
= -1; s
->err
= errno
= ECANCELED
;
2113 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
2118 if (ftruncate(s
->dst_fd
, s
->totalCopied
) < 0)
2134 * copyfile_security() will copy the ACL set, and the
2135 * POSIX set. Complexities come when dealing with
2136 * inheritied permissions, and when dealing with both
2137 * POSIX and ACL permissions.
2139 static int copyfile_security(copyfile_state_t s
)
2143 acl_t acl_src
= NULL
, acl_tmp
= NULL
, acl_dst
= NULL
;
2145 filesec_t tmp_fsec
= NULL
;
2146 filesec_t fsec_dst
= filesec_init();
2148 if (fsec_dst
== NULL
)
2152 if (COPYFILE_ACL
& s
->flags
)
2154 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
2156 if (errno
== ENOENT
)
2162 /* grab the destination acl
2163 cannot assume it's empty due to inheritance
2165 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
2168 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
2170 if (errno
== ENOENT
)
2176 if (acl_src
== NULL
&& acl_dst
== NULL
)
2179 acl_tmp
= acl_init(4);
2180 if (acl_tmp
== NULL
)
2184 acl_entry_t ace
= NULL
;
2185 acl_entry_t tmp
= NULL
;
2187 acl_get_entry(acl_src
,
2188 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2191 acl_flagset_t flags
= { 0 };
2192 acl_get_flagset_np(ace
, &flags
);
2193 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2195 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2198 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2201 copyfile_debug(2, "copied acl entry from %s to %s",
2202 s
->src
? s
->src
: "(null src)",
2203 s
->dst
? s
->dst
: "(null tmp)");
2209 acl_entry_t ace
= NULL
;
2210 acl_entry_t tmp
= NULL
;
2211 acl_flagset_t flags
= { 0 };
2212 for (copied
= 0;acl_get_entry(acl_dst
,
2213 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2216 acl_get_flagset_np(ace
, &flags
);
2217 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2219 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2222 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2225 copyfile_debug(2, "copied acl entry from %s to %s",
2226 s
->src
? s
->src
: "(null dst)",
2227 s
->dst
? s
->dst
: "(null tmp)");
2232 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_tmp
))
2234 copyfile_debug(3, "altered acl");
2239 * The following code is attempting to ensure that only the requested
2240 * security information gets copied over to the destination file.
2241 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2242 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2245 * If we have both flags, we copy everything; if we have ACL but not STAT,
2246 * we remove the POSIX information from the filesec object, and apply the
2247 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2248 * the extended version.
2250 tmp_fsec
= filesec_dup(s
->fsec
);
2251 if (tmp_fsec
== NULL
) {
2255 switch (COPYFILE_SECURITY
& s
->flags
) {
2257 copyfile_unset_posix_fsec(tmp_fsec
);
2259 case COPYFILE_ACL
| COPYFILE_STAT
:
2260 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
2263 * The call could have failed for a number of reasons, since
2264 * it does a number of things: it changes the mode of the file,
2265 * sets the owner and group, and applies an ACL (if one exists).
2266 * The typical failure is going to be trying to set the group of
2267 * the destination file to match the source file, when the process
2268 * doesn't have permission to put files in that group. We try to
2269 * work around this by breaking the steps out and doing them
2270 * discretely. We don't care if the fchown fails, but we do care
2271 * if the mode or ACL can't be set. For historical reasons, we
2272 * simply log those failures, however.
2274 * Big warning here: we may NOT have COPYFILE_STAT set, since
2275 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2278 #define NS(x) ((x) ? (x) : "(null string)")
2279 if ((s
->flags
& COPYFILE_STAT
) &&
2280 fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
2281 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
2283 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2284 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
2285 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
2286 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
2294 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
2297 filesec_free(tmp_fsec
);
2299 filesec_free(fsec_dst
);
2300 if (acl_src
) acl_free(acl_src
);
2301 if (acl_dst
) acl_free(acl_dst
);
2302 if (acl_tmp
) acl_free(acl_tmp
);
2313 * Attempt to set the destination file's stat information -- including
2314 * flags and time-related fields -- to the source's.
2316 static int copyfile_stat(copyfile_state_t s
)
2318 struct timeval tval
[2];
2319 unsigned int added_flags
= 0, dst_flags
= 0;
2323 * NFS doesn't support chflags; ignore errors as a result, since
2324 * we don't return failure for this.
2326 if (s
->internal_flags
& cfMakeFileInvisible
)
2327 added_flags
|= UF_HIDDEN
;
2330 * We need to check if SF_RESTRICTED was set on the destination
2331 * by the kernel. If it was, don't drop it.
2333 if (fstat(s
->dst_fd
, &dst_sb
))
2335 if (dst_sb
.st_flags
& SF_RESTRICTED
)
2336 added_flags
|= SF_RESTRICTED
;
2338 /* Copy file flags, masking out any we don't want to preserve */
2339 dst_flags
= (s
->sb
.st_flags
& ~COPYFILE_OMIT_FLAGS
) | added_flags
;
2340 (void)fchflags(s
->dst_fd
, dst_flags
);
2342 /* If this fails, we don't care */
2343 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2345 /* This may have already been done in copyfile_security() */
2346 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
2348 tval
[0].tv_sec
= s
->sb
.st_atime
;
2349 tval
[1].tv_sec
= s
->sb
.st_mtime
;
2350 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
2351 (void)futimes(s
->dst_fd
, tval
);
2357 * Similar to copyfile_security() in some ways; this
2358 * routine copies the extended attributes from the source,
2359 * and sets them on the destination.
2360 * The procedure is pretty simple, even if it is verbose:
2361 * for each named attribute on the destination, get its name, and
2362 * remove it. We should have none after that.
2363 * For each named attribute on the source, get its name, get its
2364 * data, and set it on the destination.
2366 static int copyfile_xattr(copyfile_state_t s
)
2369 char *namebuf
, *end
;
2372 ssize_t bufsize
= 4096;
2376 int look_for_decmpea
= 0;
2378 /* delete EAs on destination */
2379 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2381 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2384 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
2388 * With this, end points to the last byte of the allocated buffer
2389 * This *should* be NUL, from flistxattr, but if it's not, we can
2390 * set it anyway -- it'll result in a truncated name, which then
2391 * shouldn't match when we get them later.
2393 end
= namebuf
+ nsize
- 1;
2396 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
2397 /* If the quarantine information shows up as an EA, we skip over it */
2398 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
2401 fremovexattr(s
->dst_fd
, name
,0);
2408 if (errno
== ENOTSUP
|| errno
== EPERM
)
2414 #ifdef DECMPFS_XATTR_NAME
2415 if ((s
->flags
& COPYFILE_DATA
) &&
2416 (s
->sb
.st_flags
& UF_COMPRESSED
) &&
2417 doesdecmpfs(s
->src_fd
) &&
2418 doesdecmpfs(s
->dst_fd
)) {
2419 look_for_decmpea
= XATTR_SHOWCOMPRESSION
;
2423 /* get name list of EAs on source */
2424 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, look_for_decmpea
)) < 0)
2426 if (errno
== ENOTSUP
|| errno
== EPERM
)
2434 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2437 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, look_for_decmpea
);
2445 * With this, end points to the last byte of the allocated buffer
2446 * This *should* be NUL, from flistxattr, but if it's not, we can
2447 * set it anyway -- it'll result in a truncated name, which then
2448 * shouldn't match when we get them later.
2450 end
= namebuf
+ nsize
- 1;
2454 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
2459 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
2461 if (s
->xattr_name
) {
2462 free(s
->xattr_name
);
2463 s
->xattr_name
= NULL
;
2466 /* If the quarantine information shows up as an EA, we skip over it */
2467 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
2470 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, look_for_decmpea
)) < 0)
2475 if (xa_size
> bufsize
)
2477 void *tdptr
= xa_dataptr
;
2480 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
2488 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
)) < 0)
2493 if (xa_size
!= asize
)
2496 #ifdef DECMPFS_XATTR_NAME
2497 if (strncmp(name
, DECMPFS_XATTR_NAME
, end
-name
) == 0)
2499 decmpfs_disk_header
*hdr
= xa_dataptr
;
2502 * If the EA has the decmpfs name, but is too
2503 * small, or doesn't have the right magic number,
2504 * or isn't the right type, we'll just skip it.
2505 * This means it won't end up in the destination
2506 * file, and data copy will happen normally.
2508 if ((size_t)xa_size
< sizeof(decmpfs_disk_header
)) {
2511 if (OSSwapLittleToHostInt32(hdr
->compression_magic
) != DECMPFS_MAGIC
) {
2515 * From AppleFSCompression documentation:
2516 * "It is incumbent on the aware copy engine to identify
2517 * the type of compression being used, and to perform an
2518 * unaware copy of any file it does not recognize."
2520 * Compression Types are defined in:
2521 * "AppleFSCompression/Common/compressorCommon.h"
2523 * Unfortunately, they don't provide a way to dynamically
2524 * determine what possible compression_type values exist,
2525 * so we have to update this every time a new compression_type
2526 * is added. Types 7->10 were added in 10.10, Types 11 & 12
2527 * were added in 10.11.
2529 * Ubiquity faulting file compression type 0x80000001 are
2530 * deprecated as of Yosemite, per rdar://17714998 don't copy the
2531 * decmpfs xattr on these files, zero byte files are safer
2532 * than a fault nobody knows how to handle.
2534 switch (OSSwapLittleToHostInt32(hdr
->compression_type
)) {
2535 case 3: /* zlib-compressed data in xattr */
2536 case 4: /* 64k chunked zlib-compressed data in resource fork */
2538 case 7: /* LZVN-compressed data in xattr */
2539 case 8: /* 64k chunked LZVN-compressed data in resource fork */
2541 case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */
2542 case 10: /* 64k chunked uncompressed data in resource fork */
2544 case 11: /* LZFSE-compressed data in xattr */
2545 case 12: /* 64k chunked LZFSE-compressed data in resource fork */
2547 /* valid compression type, we want to copy. */
2550 case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */
2551 copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.",
2552 s
->src
? s
->src
: "(null string)");
2555 case 6: /* unused */
2556 case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */
2558 copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s",
2559 OSSwapLittleToHostInt32(hdr
->compression_type
), name
, s
->src
? s
->src
: "(null string)");
2562 s
->internal_flags
|= cfSawDecmpEA
;
2566 // If we have a copy intention stated, and the EA is to be ignored, we ignore it
2568 && xattr_preserve_for_intent(name
, s
->copyIntent
) == 0)
2571 s
->xattr_name
= strdup(name
);
2575 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
2576 if (rv
== COPYFILE_QUIT
) {
2579 } else if (rv
== COPYFILE_SKIP
) {
2583 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
) < 0)
2588 if (s
->xattr_name
== NULL
)
2589 s
->xattr_name
= strdup(name
);
2590 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2591 if (rv
== COPYFILE_QUIT
)
2601 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name
, strerror(errno
));
2607 if (s
->xattr_name
== NULL
)
2608 s
->xattr_name
= strdup(name
);
2610 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
2611 if (rv
== COPYFILE_QUIT
) {
2620 free((void *) xa_dataptr
);
2621 if (s
->xattr_name
) {
2622 free(s
->xattr_name
);
2623 s
->xattr_name
= NULL
;
2629 * API interface into getting data from the opaque data type.
2631 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
2641 case COPYFILE_STATE_SRC_FD
:
2642 *(int*)ret
= s
->src_fd
;
2644 case COPYFILE_STATE_DST_FD
:
2645 *(int*)ret
= s
->dst_fd
;
2647 case COPYFILE_STATE_SRC_FILENAME
:
2648 *(char**)ret
= s
->src
;
2650 case COPYFILE_STATE_DST_FILENAME
:
2651 *(char**)ret
= s
->dst
;
2653 case COPYFILE_STATE_QUARANTINE
:
2654 *(qtn_file_t
*)ret
= s
->qinfo
;
2657 case COPYFILE_STATE_STATS
:
2658 ret
= s
->stats
.global
;
2660 case COPYFILE_STATE_PROGRESS_CB
:
2661 ret
= s
->callbacks
.progress
;
2664 #ifdef COPYFILE_STATE_STATUS_CB
2665 case COPYFILE_STATE_STATUS_CB
:
2666 *(copyfile_callback_t
*)ret
= s
->statuscb
;
2668 case COPYFILE_STATE_STATUS_CTX
:
2669 *(void**)ret
= s
->ctx
;
2671 case COPYFILE_STATE_COPIED
:
2672 *(off_t
*)ret
= s
->totalCopied
;
2675 #ifdef COPYFILE_STATE_XATTRNAME
2676 case COPYFILE_STATE_XATTRNAME
:
2677 *(char**)ret
= s
->xattr_name
;
2680 #ifdef COPYFILE_STATE_INTENT
2681 case COPYFILE_STATE_INTENT
:
2682 *(xattr_operation_intent_t
*)ret
= s
->copyIntent
;
2685 case COPYFILE_STATE_WAS_CLONED
:
2686 *(bool *)ret
= s
->was_cloned
;
2697 * Public API for setting state data (remember that the state is
2698 * an opaque data type).
2700 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
2702 #define copyfile_set_string(DST, SRC) \
2704 if (SRC != NULL) { \
2705 DST = strdup((char *)SRC); \
2707 if (DST != NULL) { \
2722 case COPYFILE_STATE_SRC_FD
:
2723 s
->src_fd
= *(int*)thing
;
2725 case COPYFILE_STATE_DST_FD
:
2726 s
->dst_fd
= *(int*)thing
;
2728 case COPYFILE_STATE_SRC_FILENAME
:
2729 copyfile_set_string(s
->src
, thing
);
2731 case COPYFILE_STATE_DST_FILENAME
:
2732 copyfile_set_string(s
->dst
, thing
);
2734 case COPYFILE_STATE_QUARANTINE
:
2737 qtn_file_free(s
->qinfo
);
2740 if (*(qtn_file_t
*)thing
)
2741 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
2744 case COPYFILE_STATE_STATS
:
2745 s
->stats
.global
= thing
;
2747 case COPYFILE_STATE_PROGRESS_CB
:
2748 s
->callbacks
.progress
= thing
;
2751 #ifdef COPYFILE_STATE_STATUS_CB
2752 case COPYFILE_STATE_STATUS_CB
:
2753 s
->statuscb
= (copyfile_callback_t
)thing
;
2755 case COPYFILE_STATE_STATUS_CTX
:
2756 s
->ctx
= (void*)thing
;
2759 #ifdef COPYFILE_STATE_INTENT
2760 case COPYFILE_STATE_INTENT
:
2761 s
->copyIntent
= *(xattr_operation_intent_t
*)thing
;
2769 #undef copyfile_set_string
2774 * Make this a standalone program for testing purposes by
2775 * defining _COPYFILE_TEST.
2777 #ifdef _COPYFILE_TEST
2778 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2780 struct {char *s
; int v
;} opts
[] = {
2781 COPYFILE_OPTION(ACL
)
2782 COPYFILE_OPTION(STAT
)
2783 COPYFILE_OPTION(XATTR
)
2784 COPYFILE_OPTION(DATA
)
2785 COPYFILE_OPTION(SECURITY
)
2786 COPYFILE_OPTION(METADATA
)
2787 COPYFILE_OPTION(ALL
)
2788 COPYFILE_OPTION(NOFOLLOW_SRC
)
2789 COPYFILE_OPTION(NOFOLLOW_DST
)
2790 COPYFILE_OPTION(NOFOLLOW
)
2791 COPYFILE_OPTION(EXCL
)
2792 COPYFILE_OPTION(MOVE
)
2793 COPYFILE_OPTION(UNLINK
)
2794 COPYFILE_OPTION(PACK
)
2795 COPYFILE_OPTION(UNPACK
)
2796 COPYFILE_OPTION(CHECK
)
2797 COPYFILE_OPTION(VERBOSE
)
2798 COPYFILE_OPTION(DEBUG
)
2802 int main(int c
, char *v
[])
2808 errx(1, "insufficient arguments");
2812 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
2814 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
2816 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
2823 return copyfile(v
[1], v
[2], NULL
, flags
);
2827 * Apple Double Create
2829 * Create an Apple Double "._" file from a file's extented attributes
2831 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2835 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2837 #define XATTR_MAXATTRLEN (16*1024*1024)
2841 Typical "._" AppleDouble Header File layout:
2842 ------------------------------------------------------------
2847 .-- AD ENTRY[0] Finder Info Entry (must be first)
2848 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2850 | ///////////// Fixed Size Data (32 bytes)
2854 | ATTR ENTRY[1] --+--.
2855 | ATTR ENTRY[2] --+--+--.
2857 | ATTR ENTRY[N] --+--+--+--.
2858 | ATTR DATA 0 <-' | | |
2859 | //////////// | | |
2860 | ATTR DATA 1 <----' | |
2862 | ATTR DATA 2 <-------' |
2865 | ATTR DATA N <----------'
2867 | Attribute Free Space
2869 '----> RESOURCE FORK
2870 ///////////// Variable Sized Data
2879 ------------------------------------------------------------
2881 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2882 stored as part of the Finder Info. The length in the Finder
2883 Info AppleDouble entry includes the length of the extended
2884 attribute header, attribute entries, and attribute data.
2889 * On Disk Data Structures
2891 * Note: Motorola 68K alignment and big-endian.
2893 * See RFC 1740 for additional information about the AppleDouble file format.
2897 #define ADH_MAGIC 0x00051607
2898 #define ADH_VERSION 0x00020000
2899 #define ADH_MACOSX "Mac OS X "
2902 * AppleDouble Entry ID's
2904 #define AD_DATA 1 /* Data fork */
2905 #define AD_RESOURCE 2 /* Resource fork */
2906 #define AD_REALNAME 3 /* File's name on home file system */
2907 #define AD_COMMENT 4 /* Standard Mac comment */
2908 #define AD_ICONBW 5 /* Mac black & white icon */
2909 #define AD_ICONCOLOR 6 /* Mac color icon */
2910 #define AD_UNUSED 7 /* Not used */
2911 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2912 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2913 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2914 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2915 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2916 #define AD_AFPNAME 13 /* Short name on AFP server */
2917 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2918 #define AD_AFPDIRID 15 /* AFP directory ID */
2919 #define AD_ATTRIBUTES AD_FINDERINFO
2922 #define ATTR_FILE_PREFIX "._"
2923 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2925 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2927 /* Implementation Limits */
2928 #define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */
2929 #define ATTR_MAX_NAME_LEN 128
2930 #define ATTR_MAX_HDR_SIZE (65536+18)
2933 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2934 * size supported (including the attribute entries). All of
2935 * the attribute entries must reside within this limit.
2939 #define FINDERINFOSIZE 32
2941 typedef struct apple_double_entry
2943 u_int32_t type
; /* entry type: see list, 0 invalid */
2944 u_int32_t offset
; /* entry data offset from the beginning of the file. */
2945 u_int32_t length
; /* entry data length in bytes. */
2946 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
2949 typedef struct apple_double_header
2951 u_int32_t magic
; /* == ADH_MAGIC */
2952 u_int32_t version
; /* format version: 2 = 0x00020000 */
2953 u_int32_t filler
[4];
2954 u_int16_t numEntries
; /* number of entries which follow */
2955 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
2956 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
2957 u_int8_t pad
[2]; /* get better alignment inside attr_header */
2958 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
2961 /* Entries are aligned on 4 byte boundaries */
2962 typedef struct attr_entry
2964 u_int32_t offset
; /* file offset to data */
2965 u_int32_t length
; /* size of attribute data */
2967 u_int8_t namelen
; /* length of name including NULL termination char */
2968 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2969 } __attribute__((aligned(2), packed
)) attr_entry_t
;
2973 /* Header + entries must fit into 64K */
2974 typedef struct attr_header
2976 apple_double_header_t appledouble
;
2977 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
2978 u_int32_t debug_tag
; /* for debugging == file id of owning file */
2979 u_int32_t total_size
; /* total size of attribute header + entries + data */
2980 u_int32_t data_start
; /* file offset to attribute data area */
2981 u_int32_t data_length
; /* length of attribute data area */
2982 u_int32_t reserved
[3];
2984 u_int16_t num_attrs
;
2985 } __attribute__((aligned(2), packed
)) attr_header_t
;
2987 /* Empty Resource Fork Header */
2988 /* This comes by way of xnu's vfs_xattr.c */
2989 typedef struct rsrcfork_header
{
2990 u_int32_t fh_DataOffset
;
2991 u_int32_t fh_MapOffset
;
2992 u_int32_t fh_DataLength
;
2993 u_int32_t fh_MapLength
;
2994 u_int8_t systemData
[112];
2995 u_int8_t appData
[128];
2996 u_int32_t mh_DataOffset
;
2997 u_int32_t mh_MapOffset
;
2998 u_int32_t mh_DataLength
;
2999 u_int32_t mh_MapLength
;
3001 u_int16_t mh_RefNum
;
3003 u_int8_t mh_InMemoryAttr
;
3006 u_int16_t typeCount
;
3007 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
3008 #define RF_FIRST_RESOURCE 256
3009 #define RF_NULL_MAP_LENGTH 30
3010 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
3012 static const rsrcfork_header_t empty_rsrcfork_header
= {
3013 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
3014 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
3016 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
3017 { RF_EMPTY_TAG
, }, // systemData
3019 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
3020 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
3022 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
3026 0, // mh_InMemoryAttr
3027 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
3028 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
3029 OSSwapHostToBigInt16(-1), // typeCount
3032 #define SWAP16(x) OSSwapBigToHostInt16(x)
3033 #define SWAP32(x) OSSwapBigToHostInt32(x)
3034 #define SWAP64(x) OSSwapBigToHostInt64(x)
3036 #define ATTR_ALIGN 3L /* Use four-byte alignment */
3038 #define ATTR_ENTRY_LENGTH(namelen) \
3039 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
3041 #define ATTR_NEXT(ae) \
3042 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
3044 #define XATTR_SECURITY_NAME "com.apple.acl.text"
3047 * Endian swap Apple Double header
3050 swap_adhdr(apple_double_header_t
*adh
)
3052 #if BYTE_ORDER == LITTLE_ENDIAN
3056 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
3058 adh
->magic
= SWAP32 (adh
->magic
);
3059 adh
->version
= SWAP32 (adh
->version
);
3060 adh
->numEntries
= SWAP16 (adh
->numEntries
);
3062 for (i
= 0; i
< count
; i
++)
3064 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
3065 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
3066 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
3074 * Endian swap a single attr_entry_t
3077 swap_attrhdr_entry(attr_entry_t
*ae
)
3079 #if BYTE_ORDER == LITTLE_ENDIAN
3080 ae
->offset
= SWAP32 (ae
->offset
);
3081 ae
->length
= SWAP32 (ae
->length
);
3082 ae
->flags
= SWAP16 (ae
->flags
);
3089 * For a validated/endian swapped attr_header_t*
3090 * ah, endian swap all of the entries.
3093 swap_attrhdr_entries(attr_header_t
*ah
)
3095 #if BYTE_ORDER == LITTLE_ENDIAN
3098 attr_entry_t
*entry
;
3101 /* If we're in copyfile_pack, num_args is native endian,
3102 * if we're in _unpack, num_args is big endian. Use
3103 * the magic number to test for endianess.
3105 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
3107 entry
= (attr_entry_t
*)(&ah
[1]);
3108 for (i
= 0; i
< count
; i
++) {
3109 next
= ATTR_NEXT(entry
);
3110 swap_attrhdr_entry(entry
);
3119 * Endian swap extended attributes header
3122 swap_attrhdr(attr_header_t
*ah
)
3124 #if BYTE_ORDER == LITTLE_ENDIAN
3125 ah
->magic
= SWAP32 (ah
->magic
);
3126 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
3127 ah
->total_size
= SWAP32 (ah
->total_size
);
3128 ah
->data_start
= SWAP32 (ah
->data_start
);
3129 ah
->data_length
= SWAP32 (ah
->data_length
);
3130 ah
->flags
= SWAP16 (ah
->flags
);
3131 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
3137 static const u_int32_t emptyfinfo
[8] = {0};
3140 * Given an Apple Double file in src, turn it into a
3141 * normal file (possibly with multiple forks, EAs, and
3144 static int copyfile_unpack(copyfile_state_t s
)
3147 void * buffer
, * endptr
, * dataptr
= NULL
;
3148 apple_double_header_t
*adhdr
;
3152 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
3153 hdrsize
= (ssize_t
)s
->sb
.st_size
;
3155 hdrsize
= ATTR_MAX_HDR_SIZE
;
3157 buffer
= calloc(1, hdrsize
);
3158 if (buffer
== NULL
) {
3159 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize
);
3163 endptr
= (char*)buffer
+ hdrsize
;
3165 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
3169 copyfile_debug(1, "pread returned: %zd", bytes
);
3173 if (bytes
< hdrsize
)
3176 "pread couldn't read entire header: %d of %d",
3177 (int)bytes
, (int)s
->sb
.st_size
);
3181 adhdr
= (apple_double_header_t
*)buffer
;
3184 * Check for Apple Double file.
3186 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
3187 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
3188 SWAP32(adhdr
->version
) != ADH_VERSION
||
3189 SWAP16(adhdr
->numEntries
) != 2 ||
3190 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
3192 if (COPYFILE_VERBOSE
& s
->flags
)
3193 copyfile_warn("Not a valid Apple Double header");
3200 * Remove any extended attributes on the target.
3203 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
3205 char *namebuf
, *name
;
3207 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
3212 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
3215 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
3216 (void)fremovexattr(s
->dst_fd
, name
, 0);
3222 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
3227 * Extract the extended attributes.
3230 * This assumes that the data is already in memory (not
3231 * the case when there are lots of attributes or one of
3232 * the attributes is very large.
3234 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
3236 attr_header_t
*attrhdr
;
3237 attr_entry_t
*entry
;
3241 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
3242 copyfile_warn("bad attribute header: %zu < %zu", hdrsize
, sizeof(attr_header_t
));
3247 attrhdr
= (attr_header_t
*)buffer
;
3248 swap_attrhdr(attrhdr
);
3249 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
3251 if (COPYFILE_VERBOSE
& s
->flags
)
3252 copyfile_warn("bad attribute header");
3256 count
= attrhdr
->num_attrs
;
3257 entry
= (attr_entry_t
*)&attrhdr
[1];
3259 for (i
= 0; i
< count
; i
++)
3262 * First we do some simple sanity checking.
3263 * +) See if entry is within the buffer's range;
3265 * +) Check the attribute name length; if it's longer than the
3266 * maximum, we truncate it down. (We could error out as well;
3267 * I'm not sure which is the better way to go here.)
3269 * +) If, given the name length, it goes beyond the end of
3270 * the buffer, error out.
3272 * +) If the last byte isn't a NUL, make it a NUL. (Since we
3273 * truncated the name length above, we truncate the name here.)
3275 * +) If entry->offset is so large that it causes dataptr to
3276 * go beyond the end of the buffer -- or, worse, so large that
3277 * it wraps around! -- we error out.
3279 * +) If entry->length would cause the entry to go beyond the
3280 * end of the buffer (or, worse, wrap around to before it),
3281 * *or* if the length is larger than the hdrsize, we error out.
3282 * (An explanation of that: what we're checking for there is
3283 * the small range of values such that offset+length would cause
3284 * it to go beyond endptr, and then wrap around past buffer. We
3285 * care about this because we are passing entry->length down to
3286 * fgetxattr() below, and an erroneously large value could cause
3287 * problems there. By making sure that it's less than hdrsize,
3288 * which has already been sanity-checked above, we're safe.
3289 * That may mean that the check against < buffer is unnecessary.)
3291 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
3292 if (COPYFILE_VERBOSE
& s
->flags
)
3293 copyfile_warn("Incomplete or corrupt attribute entry");
3299 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
3300 if (COPYFILE_VERBOSE
& s
->flags
)
3301 copyfile_warn("Incomplete or corrupt attribute entry");
3308 * Endian swap the entry we're looking at. Previously
3309 * we did this swap as part of swap_attrhdr, but that
3310 * allowed a maliciously constructed file to overrun
3311 * our allocation. Instead do the swap after we've verified
3312 * the entry struct is within the buffer's range.
3314 swap_attrhdr_entry(entry
);
3316 if (entry
->namelen
< 2) {
3317 if (COPYFILE_VERBOSE
& s
->flags
)
3318 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
3324 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
3325 if (COPYFILE_VERBOSE
& s
->flags
)
3326 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
3332 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
3333 if (COPYFILE_VERBOSE
& s
->flags
)
3334 copyfile_warn("Incomplete or corrupt attribute entry");
3340 /* Because namelen includes the NUL, we check one byte back */
3341 if (entry
->name
[entry
->namelen
-1] != 0) {
3342 if (COPYFILE_VERBOSE
& s
->flags
)
3343 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3349 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3350 entry
->name
, entry
->length
, entry
->offset
);
3353 dataptr
= (char *)attrhdr
+ entry
->offset
;
3355 if (dataptr
> endptr
|| dataptr
< buffer
) {
3356 copyfile_debug(1, "Entry %d overflows: offset = %u", i
, entry
->offset
);
3358 s
->err
= EINVAL
; /* Invalid buffer */
3362 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
3363 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
3364 (entry
->length
> (size_t)hdrsize
)) {
3365 if (COPYFILE_VERBOSE
& s
->flags
)
3366 copyfile_warn("Incomplete or corrupt attribute entry");
3367 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3368 i
, entry
->offset
, entry
->length
);
3370 s
->err
= EINVAL
; /* Invalid buffer */
3375 dataptr
= malloc(entry
->length
);
3376 if (dataptr
== NULL
) {
3377 copyfile_debug(1, "no memory for %u bytes\n", entry
->length
);
3382 if (pread(s
->src_fd
, dataptr
, entry
->length
, entry
->offset
) != (ssize_t
)entry
->length
) {
3383 copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry
->length
, entry
->offset
);
3390 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
3392 qtn_file_t tqinfo
= NULL
;
3394 if (s
->qinfo
== NULL
)
3396 tqinfo
= qtn_file_alloc();
3400 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
3402 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
3403 qtn_file_free(tqinfo
);
3415 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
3417 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
3420 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
3421 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3422 s
->xattr_name
= NULL
;
3423 if (rv
== COPYFILE_QUIT
) {
3424 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3428 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3433 if (tqinfo
&& !s
->qinfo
)
3435 qtn_file_free(tqinfo
);
3438 /* Look for ACL data */
3439 else if (strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
3444 char *tcp
= dataptr
;
3446 if (entry
->length
== 0) {
3447 /* Not sure how we got here, but we had one case
3448 * where it was 0. In a normal EA, we can have a 0-byte
3449 * payload. That means nothing in this case, so we'll
3450 * simply skip the EA.
3456 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3457 * however, may not be NUL-terminated. So in that case, we need to
3458 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3460 if (tcp
[entry
->length
- 1] != 0) {
3461 char *tmpstr
= malloc(entry
->length
+ 1);
3462 if (tmpstr
== NULL
) {
3466 strlcpy(tmpstr
, tcp
, entry
->length
+ 1);
3467 acl
= acl_from_text(tmpstr
);
3470 acl
= acl_from_text(tcp
);
3477 if ((fsec_tmp
= filesec_init()) == NULL
)
3479 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
3481 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
3484 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
3486 if (errno
== ENOTSUP
)
3488 if (retry
&& !copyfile_unset_acl(s
))
3494 copyfile_warn("setting security information");
3500 filesec_free(fsec_tmp
);
3507 /* And, finally, everything else */
3510 if (s
->copyIntent
||
3511 xattr_preserve_for_intent((char*)entry
->name
, s
->copyIntent
) == 1) {
3514 s
->xattr_name
= strdup((char*)entry
->name
);
3516 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3517 if (s
->xattr_name
) {
3518 free(s
->xattr_name
);
3519 s
->xattr_name
= NULL
;
3521 if (rv
== COPYFILE_QUIT
) {
3527 if (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0) == -1) {
3528 if (COPYFILE_VERBOSE
& s
->flags
)
3529 copyfile_warn("error %d setting attribute %s", errno
, entry
->name
);
3533 s
->xattr_name
= strdup((char*)entry
->name
);
3534 rv
= (s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3535 if (s
->xattr_name
) {
3536 free(s
->xattr_name
);
3537 s
->xattr_name
= NULL
;
3539 if (rv
== COPYFILE_QUIT
) {
3547 } else if (s
->statuscb
) {
3549 s
->xattr_name
= strdup((char*)entry
->name
);
3550 s
->totalCopied
= entry
->length
;
3551 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3552 if (s
->xattr_name
) {
3553 free(s
->xattr_name
);
3554 s
->xattr_name
= NULL
;
3556 if (rv
== COPYFILE_QUIT
) {
3568 entry
= ATTR_NEXT(entry
);
3573 * Extract the Finder Info.
3575 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
3580 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
3584 enum { kFinderInvisibleMask
= 1 << 14 };
3586 newFinfo
= (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
;
3587 fFlags
= (uint16_t*)&newFinfo
[8];
3588 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
3591 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3592 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3593 s
->xattr_name
= NULL
;
3594 if (rv
== COPYFILE_QUIT
) {
3598 } else if (rv
== COPYFILE_SKIP
) {
3602 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
3606 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3607 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3608 s
->xattr_name
= NULL
;
3609 if (rv
== COPYFILE_QUIT
) {
3616 } else if (s
->statuscb
) {
3618 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3619 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3620 s
->xattr_name
= NULL
;
3621 if (rv
== COPYFILE_QUIT
) {
3627 if (SWAP16(*fFlags
) & kFinderInvisibleMask
)
3628 s
->internal_flags
|= cfMakeFileInvisible
;
3633 * Extract the Resource Fork.
3635 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
3636 adhdr
->entries
[1].length
> 0)
3638 void * rsrcforkdata
= NULL
;
3642 struct timeval tval
[2];
3644 length
= adhdr
->entries
[1].length
;
3645 offset
= adhdr
->entries
[1].offset
;
3646 rsrcforkdata
= malloc(length
);
3648 if (rsrcforkdata
== NULL
) {
3649 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3655 if (fstat(s
->dst_fd
, &sb
) < 0)
3657 copyfile_debug(1, "couldn't stat destination file");
3662 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
3663 if (bytes
< (ssize_t
)length
)
3667 copyfile_debug(1, "couldn't read resource fork");
3672 "couldn't read resource fork (only read %d bytes of %d)",
3673 (int)bytes
, (int)length
);
3680 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3681 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3682 s
->xattr_name
= NULL
;
3683 if (rv
== COPYFILE_QUIT
) {
3689 } else if (rv
== COPYFILE_SKIP
) {
3693 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
3697 * For filesystems that do not natively support named attributes,
3698 * the kernel creates an AppleDouble file that -- for compatabilty
3699 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3700 * structure that says there are no resources. So, if fsetxattr has
3701 * failed, and the resource fork is that empty structure, *and* the
3702 * target file is a directory, then we do nothing with it.
3704 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
3705 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
3706 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
3707 copyfile_debug(2, "not setting empty resource fork on directory");
3713 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3714 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3715 s
->xattr_name
= NULL
;
3716 if (rv
== COPYFILE_CONTINUE
) {
3721 copyfile_debug(1, "error %d setting resource fork attribute", error
);
3724 } else if (s
->statuscb
) {
3726 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3727 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3728 s
->xattr_name
= NULL
;
3729 if (rv
== COPYFILE_QUIT
) {
3737 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3738 XATTR_RESOURCEFORK_NAME
, (int)length
);
3740 if (!(s
->flags
& COPYFILE_STAT
))
3742 tval
[0].tv_sec
= sb
.st_atime
;
3743 tval
[1].tv_sec
= sb
.st_mtime
;
3744 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
3746 if (futimes(s
->dst_fd
, tval
))
3747 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
3754 if (COPYFILE_STAT
& s
->flags
)
3756 error
= copyfile_stat(s
);
3759 if (buffer
) free(buffer
);
3760 if (dataptr
) free(dataptr
);
3764 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3767 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
3768 size_t qlen
= sizeof(qbuf
);
3770 if (s
->qinfo
== NULL
)
3776 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
3782 *buf
= malloc(qlen
);
3785 memcpy(*buf
, qbuf
, qlen
);
3792 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3798 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
3800 if (errno
!= ENOENT
)
3803 if (COPYFILE_VERBOSE
& s
->flags
)
3804 copyfile_warn("getting acl");
3810 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
3813 * acl_to_text() doesn't include the NUL at the endo
3814 * in it's count (*len). It does, however, promise to
3815 * return a valid C string, so we need to up the count
3819 *buf
= malloc(*len
);
3821 memcpy(*buf
, acl_text
, *len
);
3826 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
3833 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
3836 char *databuf
= NULL
;
3841 * do COPYFILE_COPY_XATTR here; no need to
3842 * the work if we want to skip.
3849 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3851 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3852 s
->xattr_name
= NULL
;
3853 if (rv
== COPYFILE_SKIP
) {
3857 if (rv
== COPYFILE_QUIT
) {
3863 /* Get the resource fork size */
3864 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
3866 if (COPYFILE_VERBOSE
& s
->flags
)
3867 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
3871 if (datasize
> INT_MAX
) {
3879 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3882 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3883 s
->xattr_name
= NULL
;
3884 if (rv
== COPYFILE_QUIT
) {
3890 if ((databuf
= malloc(datasize
)) == NULL
)
3892 copyfile_warn("malloc");
3897 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
3899 if (COPYFILE_VERBOSE
& s
->flags
)
3900 copyfile_warn("couldn't read entire resource fork");
3905 /* Write the resource fork to disk. */
3906 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
3908 if (COPYFILE_VERBOSE
& s
->flags
)
3909 copyfile_warn("couldn't write resource fork");
3914 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3915 if (rv
== COPYFILE_QUIT
) {
3920 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3921 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
3922 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
3925 if (ret
== -1 && s
->statuscb
)
3928 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3929 if (rv
== COPYFILE_CONTINUE
)
3932 if (s
->xattr_name
) {
3933 s
->xattr_name
= NULL
;
3940 * Do status callback here
3941 * If ret == -1, then error callback
3947 * The opposite of copyfile_unpack(), obviously.
3949 static int copyfile_pack(copyfile_state_t s
)
3951 char *attrnamebuf
= NULL
, *endnamebuf
;
3952 void *databuf
= NULL
;
3953 attr_header_t
*filehdr
, *endfilehdr
;
3954 attr_entry_t
*entry
;
3955 ssize_t listsize
= 0;
3961 int hasrsrcfork
= 0;
3963 int seenq
= 0; // Have we seen any quarantine info already?
3965 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_HDR_SIZE
);
3967 if (filehdr
== NULL
) {
3971 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_HDR_SIZE
);
3974 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
3975 if (attrnamebuf
== NULL
) {
3979 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
3983 * Fill in the Apple Double Header defaults.
3985 filehdr
->appledouble
.magic
= ADH_MAGIC
;
3986 filehdr
->appledouble
.version
= ADH_VERSION
;
3987 filehdr
->appledouble
.numEntries
= 2;
3988 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
3989 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
3990 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
3991 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
3992 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
3993 filehdr
->appledouble
.entries
[1].length
= 0;
3994 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
3997 * Fill in the initial Attribute Header.
3999 filehdr
->magic
= ATTR_HDR_MAGIC
;
4000 filehdr
->debug_tag
= 0;
4001 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
4004 * Collect the attribute names.
4006 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
4009 * Test if there are acls to copy
4011 if (COPYFILE_ACL
& s
->flags
)
4013 acl_t temp_acl
= NULL
;
4014 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
4016 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
4019 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
4020 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
4021 endnamebuf
= attrnamebuf
+ offset
;
4027 if (COPYFILE_XATTR
& s
->flags
)
4029 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
4030 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
4032 copyfile_debug(2, "no extended attributes found (%d)", errno
);
4034 if (listsize
> left
)
4036 copyfile_debug(1, "extended attribute list too long");
4040 endnamebuf
= attrnamebuf
+ offset
+ (listsize
> 0 ? listsize
: 0);
4041 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
4047 sort_xattrname_list(attrnamebuf
, endnamebuf
- attrnamebuf
);
4049 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
4051 namelen
= strlen(nameptr
) + 1;
4052 /* Skip over FinderInfo or Resource Fork names */
4053 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
4054 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
4057 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
4061 /* The system should prevent this from happening, but... */
4062 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
4063 namelen
= XATTR_MAXNAMELEN
+ 1;
4065 if (s
->copyIntent
&&
4066 xattr_preserve_for_intent(nameptr
, s
->copyIntent
) == 0) {
4068 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
4069 memmove(nameptr
, nameptr
+ namelen
, amt
);
4070 endnamebuf
-= namelen
;
4071 /* Set namelen to 0 so continue doesn't miss names */
4078 char eaname
[namelen
];
4079 bcopy(nameptr
, eaname
, namelen
);
4080 eaname
[namelen
- 1] = 0; // Just to be sure!
4081 s
->xattr_name
= eaname
;
4082 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4083 s
->xattr_name
= NULL
;
4084 if (rv
== COPYFILE_QUIT
) {
4088 } else if (rv
== COPYFILE_SKIP
) {
4089 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
4090 memmove(nameptr
, nameptr
+ namelen
, amt
);
4091 endnamebuf
-= namelen
;
4092 /* Set namelen to 0 so continue doesn't miss names */
4097 entry
->namelen
= namelen
;
4099 if (nameptr
+ namelen
> endnamebuf
) {
4104 bcopy(nameptr
, &entry
->name
[0], namelen
);
4105 copyfile_debug(2, "copied name [%s]", entry
->name
);
4107 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
4108 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
4110 if ((void*)entry
>= (void*)endfilehdr
) {
4115 /* Update the attributes header. */
4116 filehdr
->num_attrs
++;
4117 filehdr
->data_start
+= (u_int32_t
)entrylen
;
4122 * If we have any quarantine data, we always pack it.
4123 * But if we've already got it in the EA list, don't put it in again.
4125 if (s
->qinfo
&& !seenq
)
4127 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
4128 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
4129 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
4134 * Collect the attribute data.
4136 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
4138 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
+ 1)
4140 namelen
= strlen(nameptr
);
4142 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
4143 copyfile_pack_acl(s
, &databuf
, &datasize
);
4144 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
4146 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
4148 /* Check for Finder Info. */
4149 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
4154 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
4155 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4156 s
->xattr_name
= NULL
;
4157 if (rv
== COPYFILE_QUIT
)
4159 s
->xattr_name
= NULL
;
4164 else if (rv
== COPYFILE_SKIP
)
4166 s
->xattr_name
= NULL
;
4170 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4171 s
->xattr_name
= NULL
;
4172 if (rv
== COPYFILE_QUIT
)
4179 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
4184 s
->xattr_name
= strdup(nameptr
);
4185 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4186 if (s
->xattr_name
) {
4187 free(s
->xattr_name
);
4188 s
->xattr_name
= NULL
;
4190 if (rv
== COPYFILE_QUIT
) {
4195 if (COPYFILE_VERBOSE
& s
->flags
)
4196 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4197 } else if (datasize
!= 32)
4199 if (COPYFILE_VERBOSE
& s
->flags
)
4200 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
4203 if (COPYFILE_VERBOSE
& s
->flags
)
4204 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
4205 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
4208 s
->xattr_name
= strdup(nameptr
);
4209 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4210 if (s
->xattr_name
) {
4211 free(s
->xattr_name
);
4212 s
->xattr_name
= NULL
;
4214 if (rv
== COPYFILE_QUIT
) {
4220 continue; /* finder info doesn't have an attribute entry */
4222 /* Check for Resource Fork. */
4223 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
4229 /* Just a normal attribute. */
4233 s
->xattr_name
= strdup(nameptr
);
4235 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4236 if (s
->xattr_name
) {
4237 free(s
->xattr_name
);
4238 s
->xattr_name
= NULL
;
4241 * Due to the nature of the packed file, we can't skip at this point.
4243 if (rv
== COPYFILE_QUIT
)
4250 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
4255 if (COPYFILE_VERBOSE
& s
->flags
)
4256 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4260 s
->xattr_name
= strdup(nameptr
);
4261 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4262 if (s
->xattr_name
) {
4263 free(s
->xattr_name
);
4264 s
->xattr_name
= NULL
;
4266 if (rv
== COPYFILE_QUIT
)
4275 if (datasize
> XATTR_MAXATTRLEN
)
4277 if (COPYFILE_VERBOSE
& s
->flags
)
4278 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
4281 databuf
= malloc(datasize
);
4282 if (databuf
== NULL
) {
4286 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
4289 s
->xattr_name
= strdup(nameptr
);
4290 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4291 if (s
->xattr_name
) {
4292 free(s
->xattr_name
);
4293 s
->xattr_name
= NULL
;
4295 if (rv
== COPYFILE_QUIT
) {
4303 entry
->length
= (u_int32_t
)datasize
;
4304 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
4306 filehdr
->data_length
+= (u_int32_t
)datasize
;
4310 * This assumes that the data is fits in memory (not
4311 * the case when there are lots of attributes or one of
4312 * the attributes is very large.
4314 if (entry
->offset
> ATTR_MAX_SIZE
||
4315 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
4318 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
4321 if (pwrite(s
->dst_fd
, databuf
, datasize
, entry
->offset
) != datasize
) {
4327 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
4329 /* bump to next entry */
4330 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
4331 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
4334 /* Now we know where the resource fork data starts. */
4335 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
4337 /* We also know the size of the "Finder Info entry. */
4338 filehdr
->appledouble
.entries
[0].length
=
4339 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
4341 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
4343 /* Copy Resource Fork. */
4344 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
4347 /* Write the header to disk. */
4348 datasize
= filehdr
->data_start
;
4350 swap_adhdr(&filehdr
->appledouble
);
4351 swap_attrhdr(filehdr
);
4352 swap_attrhdr_entries(filehdr
);
4354 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
4356 if (COPYFILE_VERBOSE
& s
->flags
)
4357 copyfile_warn("couldn't write file header");
4362 if (filehdr
) free(filehdr
);
4363 if (attrnamebuf
) free(attrnamebuf
);
4368 return copyfile_stat(s
);