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>
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 #define XATTR_QUARANTINE_NAME "figgledidiggledy"
73 #endif /* TARGET_OS_IPHONE */
76 #include "copyfile_private.h"
77 #include "xattr_flags.h"
79 enum cfInternalFlags
{
80 cfDelayAce
= 1 << 0, /* set if ACE shouldn't be set until post-order traversal */
81 cfMakeFileInvisible
= 1 << 1, /* set if kFinderInvisibleMask is on src */
82 cfSawDecmpEA
= 1 << 2, /* set if we've seen a com.apple.decmpfs xattr */
83 cfSrcProtSupportValid
= 1 << 3, /* set if cfSrcSupportsCProtect is valid */
84 cfSrcSupportsCProtect
= 1 << 4, /* set if src supports MNT_CPROTECT */
85 cfDstProtSupportValid
= 1 << 5, /* set if cfDstSupportsCProtect is valid */
86 cfDstSupportsCProtect
= 1 << 6, /* set if dst supports MNT_CPROTECT */
89 #define COPYFILE_MNT_CPROTECT_MASK (cfSrcProtSupportValid | cfSrcSupportsCProtect | cfDstProtSupportValid | cfDstSupportsCProtect)
92 * The state structure keeps track of
93 * the source filename, the destination filename, their
94 * associated file-descriptors, the stat infomration for the
95 * source file, the security information for the source file,
96 * the flags passed in for the copy, a pointer to place statistics
97 * (not currently implemented), debug flags, and a pointer to callbacks
98 * (not currently implemented).
100 struct _copyfile_state
108 copyfile_flags_t flags
;
109 unsigned int internal_flags
;
112 copyfile_callback_t statuscb
;
114 qtn_file_t qinfo
; /* Quarantine information -- probably NULL */
115 filesec_t original_fsec
;
116 filesec_t permissive_fsec
;
120 xattr_operation_intent_t copyIntent
;
123 #define GET_PROT_CLASS(fd) fcntl((fd), F_GETPROTECTIONCLASS)
124 #define SET_PROT_CLASS(fd, prot_class) fcntl((fd), F_SETPROTECTIONCLASS, (prot_class))
128 #define _ACL_ENTRY_MAGIC 0xac1ac101
130 guid_t ae_applicable
;
135 #define PACE(ace) do { \
136 struct acl_entry *__t = (struct acl_entry*)(ace); \
137 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
142 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
143 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
147 acl_compare_permset_np(acl_permset_t p1
, acl_permset_t p2
)
149 struct pm
{ u_int32_t ap_perms
; } *ps1
, *ps2
;
150 ps1
= (struct pm
*) p1
;
151 ps2
= (struct pm
*) p2
;
153 return ((ps1
->ap_perms
== ps2
->ap_perms
) ? 1 : 0);
158 doesdecmpfs(int fd
) {
159 #ifdef DECMPFS_XATTR_NAME
161 struct attrlist attrs
;
162 char volroot
[MAXPATHLEN
+ 1];
166 vol_capabilities_attr_t volAttrs
;
169 (void)fstatfs(fd
, &sfs
);
170 strlcpy(volroot
, sfs
.f_mntonname
, sizeof(volroot
));
172 memset(&attrs
, 0, sizeof(attrs
));
173 attrs
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
174 attrs
.volattr
= ATTR_VOL_CAPABILITIES
;
176 rv
= getattrlist(volroot
, &attrs
, &volattrs
, sizeof(volattrs
), 0);
179 (volattrs
.volAttrs
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
) &&
180 (volattrs
.volAttrs
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
)) {
188 does_copy_protection(int fd
)
192 if (fstatfs(fd
, &sfs
) == -1)
195 return ((sfs
.f_flags
& MNT_CPROTECT
) == MNT_CPROTECT
);
199 sort_xattrname_list(void *start
, size_t length
)
206 /* If it's not a proper C string at the end, don't do anything */
207 if (((char*)start
)[length
] != 0)
210 * In order to sort the list of names, we need to
211 * make a list of pointers to strings. To do that,
212 * we need to run through the buffer, and find the
213 * beginnings of strings.
215 nel
= 10; // Most files don't have many EAs
216 ptrs
= (char**)calloc(nel
, sizeof(char*));
223 char *curPtr
= start
;
224 while (curPtr
< (char*)start
+ length
) {
225 printf("%s\n", curPtr
);
226 curPtr
+= strlen(curPtr
) + 1;
231 tmp
= ptrs
[indx
++] = (char*)start
;
233 while (tmp
= memchr(tmp
, 0, ((char*)start
+ length
) - tmp
)) {
236 ptrs
= realloc(ptrs
, sizeof(char**) * nel
);
240 ptrs
[indx
++] = ++tmp
;
243 printf("Unsorted:\n");
244 for (nel
= 0; nel
< indx
-1; nel
++) {
245 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
248 qsort_b(ptrs
, indx
-1, sizeof(char*), ^(const void *left
, const void *right
) {
250 char *lstr
= *(char**)left
, *rstr
= *(char**)right
;
251 rv
= strcmp(lstr
, rstr
);
256 for (nel
= 0; nel
< indx
-1; nel
++) {
257 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
261 * Now that it's sorted, we need to make a copy, so we can
262 * move the strings around into the new order. Then we
263 * copy that on top of the old buffer, and we're done.
265 char *copy
= malloc(length
);
270 for (i
= 0; i
< indx
-1; i
++) {
271 size_t len
= strlen(ptrs
[i
]);
272 memcpy(curPtr
, ptrs
[i
], len
+1);
275 memcpy(start
, copy
, length
);
286 * Internally, the process is broken into a series of
289 static int copyfile_open (copyfile_state_t
);
290 static int copyfile_close (copyfile_state_t
);
291 static int copyfile_data (copyfile_state_t
);
292 static int copyfile_stat (copyfile_state_t
);
293 static int copyfile_security (copyfile_state_t
);
294 static int copyfile_xattr (copyfile_state_t
);
295 static int copyfile_pack (copyfile_state_t
);
296 static int copyfile_unpack (copyfile_state_t
);
298 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
299 static filesec_t
copyfile_fix_perms(copyfile_state_t
, filesec_t
*);
300 static int copyfile_preamble(copyfile_state_t
*s
, copyfile_flags_t flags
);
301 static int copyfile_internal(copyfile_state_t state
, copyfile_flags_t flags
);
302 static int copyfile_unset_posix_fsec(filesec_t
);
303 static int copyfile_quarantine(copyfile_state_t
);
305 #define COPYFILE_DEBUG (1<<31)
306 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
308 #ifndef _COPYFILE_TEST
309 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
310 # define copyfile_debug(d, str, ...) \
312 if (s && (d <= s->debug)) {\
313 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
317 #define copyfile_warn(str, ...) \
318 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
319 # define copyfile_debug(d, str, ...) \
321 if (s && (d <= s->debug)) {\
322 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
327 static int copyfile_quarantine(copyfile_state_t s
)
330 if (s
->qinfo
== NULL
)
333 s
->qinfo
= qtn_file_alloc();
334 if (s
->qinfo
== NULL
)
339 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
341 qtn_file_free(s
->qinfo
);
352 add_uberace(acl_t
*acl
)
355 acl_permset_t permset
;
358 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
362 * First, we create an entry, and give it the special name
363 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
364 * After that, we clear out all the permissions in it, and
365 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
366 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
367 * the functionality, and put this into the ACL.
369 if (acl_create_entry_np(acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
371 if (acl_get_permset(entry
, &permset
) == -1) {
372 copyfile_warn("acl_get_permset");
375 if (acl_clear_perms(permset
) == -1) {
376 copyfile_warn("acl_clear_permset");
379 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1) {
380 copyfile_warn("add ACL_WRITE_DATA");
383 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1) {
384 copyfile_warn("add ACL_WRITE_ATTRIBUTES");
387 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1) {
388 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES");
391 if (acl_add_perm(permset
, ACL_APPEND_DATA
) == -1) {
392 copyfile_warn("add ACL_APPEND_DATA");
395 if (acl_add_perm(permset
, ACL_WRITE_SECURITY
) == -1) {
396 copyfile_warn("add ACL_WRITE_SECURITY");
399 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1) {
400 copyfile_warn("set ACL_EXTENDED_ALLOW");
404 if(acl_set_permset(entry
, permset
) == -1) {
405 copyfile_warn("acl_set_permset");
408 if(acl_set_qualifier(entry
, qual
) == -1) {
409 copyfile_warn("acl_set_qualifier");
419 is_uberace(acl_entry_t ace
)
422 acl_permset_t perms
, tperms
;
429 // Who am I, and who is the ACE for?
430 mbr_uid_to_uuid(geteuid(), myuuid
);
431 qual
= (guid_t
*)acl_get_qualifier(ace
);
433 // Need to create a temporary acl, so I can get the uberace template.
439 if (acl_get_entry(tacl
, ACL_FIRST_ENTRY
, &tentry
) != 0) {
442 acl_get_permset(tentry
, &tperms
);
445 acl_get_tag_type(ace
, &tag
);
446 acl_get_permset(ace
, &perms
);
448 if (tag
== ACL_EXTENDED_ALLOW
&&
449 (memcmp(qual
, myuuid
, sizeof(myuuid
)) == 0) &&
450 acl_compare_permset_np(tperms
, perms
))
465 remove_uberace(int fd
, struct stat
*sbuf
)
467 filesec_t fsec
= NULL
;
472 fsec
= filesec_init();
477 if (fstatx_np(fd
, &sb
, fsec
) != 0) {
478 if (errno
== ENOTSUP
)
483 if (filesec_get_property(fsec
, FILESEC_ACL
, &acl
) != 0) {
487 if (acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
) == 0) {
488 if (is_uberace(entry
))
490 mode_t m
= sbuf
->st_mode
& ~S_IFMT
;
492 if (acl_delete_entry(acl
, entry
) != 0 ||
493 filesec_set_property(fsec
, FILESEC_ACL
, &acl
) != 0 ||
494 filesec_set_property(fsec
, FILESEC_MODE
, &m
) != 0 ||
495 fchmodx_np(fd
, fsec
) != 0)
508 fchmod(fd
, sbuf
->st_mode
& ~S_IFMT
);
513 reset_security(copyfile_state_t s
)
515 /* If we haven't reset the file security information
516 * (COPYFILE_SECURITY is not set in flags)
517 * restore back the permissions the file had originally
519 * One of the reasons this seems so complicated is that
520 * it is partially at odds with copyfile_security().
522 * Simplisticly, we are simply trying to make sure we
523 * only copy what was requested, and that we don't stomp
524 * on what wasn't requested.
527 #ifdef COPYFILE_RECURSIVE
528 if (s
->dst_fd
> -1) {
531 if (s
->src_fd
> -1 && (s
->flags
& COPYFILE_STAT
))
532 fstat(s
->src_fd
, &sbuf
);
534 fstat(s
->dst_fd
, &sbuf
);
536 if (!(s
->internal_flags
& cfDelayAce
))
537 remove_uberace(s
->dst_fd
, &sbuf
);
540 if (s
->permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
541 if (s
->flags
& COPYFILE_ACL
) {
542 /* Just need to reset the BSD information -- mode, owner, group */
543 (void)fchown(s
->dst_fd
, s
->dst_sb
.st_uid
, s
->dst_sb
.st_gid
);
544 (void)fchmod(s
->dst_fd
, s
->dst_sb
.st_mode
);
547 * flags is either COPYFILE_STAT, or neither; if it's
548 * neither, then we restore both ACL and POSIX permissions;
549 * if it's STAT, however, then we only want to restore the
550 * ACL (which may be empty). We do that by removing the
551 * POSIX information from the filesec object.
553 if (s
->flags
& COPYFILE_STAT
) {
554 copyfile_unset_posix_fsec(s
->original_fsec
);
556 if (fchmodx_np(s
->dst_fd
, s
->original_fsec
) < 0 && errno
!= ENOTSUP
)
557 copyfile_warn("restoring security information");
561 if (s
->permissive_fsec
) {
562 filesec_free(s
->permissive_fsec
);
563 s
->permissive_fsec
= NULL
;
566 if (s
->original_fsec
) {
567 filesec_free(s
->original_fsec
);
568 s
->original_fsec
= NULL
;
576 * copytree -- recursively copy a hierarchy.
578 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
579 * Care is taken to keep the ACLs set up correctly, in addition to the
580 * normal copying that is done. (When copying a hierarchy, we can't
581 * get rid of the "allow-all-writes" ACE on a directory until we're done
582 * copying the *contents* of the directory.)
584 * The other big difference from copyfile (for the moment) is that copytree()
585 * will use a call-back function to pass along information about what is
586 * about to be copied, and whether or not it succeeded.
588 * copytree() is called from copyfile() -- but copytree() itself then calls
589 * copyfile() to copy each individual object.
591 * XXX - no effort is made to handle overlapping hierarchies at the moment.
596 copytree(copyfile_state_t s
)
600 int (*sfunc
)(const char *, struct stat
*);
601 copyfile_callback_t status
= NULL
;
602 char srcisdir
= 0, dstisdir
= 0, dstexists
= 0;
605 const char *dstpathsep
= "";
607 char srcpath
[PATH_MAX
* 2 + 1], dstpath
[PATH_MAX
* 2 + 1];
613 const char *paths
[2] = { 0 };
614 unsigned int flags
= 0;
615 int fts_flags
= FTS_NOCHDIR
;
616 dev_t last_dev
= s
->sb
.st_dev
;
623 if (s
->flags
& (COPYFILE_MOVE
| COPYFILE_UNLINK
| COPYFILE_CHECK
| COPYFILE_PACK
| COPYFILE_UNPACK
)) {
629 flags
= s
->flags
& (COPYFILE_ALL
| COPYFILE_NOFOLLOW
| COPYFILE_VERBOSE
| COPYFILE_EXCL
);
631 paths
[0] = src
= s
->src
;
634 if (src
== NULL
|| dst
== NULL
) {
640 sfunc
= (flags
& COPYFILE_NOFOLLOW_SRC
) ? lstat
: stat
;
641 if ((sfunc
)(src
, &sbuf
) == -1) {
645 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
649 sfunc
= (flags
& COPYFILE_NOFOLLOW_DST
) ? lstat
: stat
;
650 if ((sfunc
)(dst
, &sbuf
) == -1) {
651 if (errno
!= ENOENT
) {
657 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
663 // This doesn't handle filesystem crossing and case sensitivity
664 // So there's got to be a better way
666 if (realpath(src
, srcpath
) == NULL
) {
671 if (realpath(dst
, dstpath
) == NULL
&&
672 (errno
== ENOENT
&& realpath(dirname(dst
), dstpath
) == NULL
)) {
676 if (strstr(srcpath
, dstpath
) != NULL
) {
682 srcroot
= basename((char*)src
);
683 if (srcroot
== NULL
) {
689 * To work on as well:
690 * We have a few cases when copying a hierarchy:
691 * 1) src is a non-directory, dst is a directory;
692 * 2) src is a non-directory, dst is a non-directory;
693 * 3) src is a non-directory, dst does not exist;
694 * 4) src is a directory, dst is a directory;
695 * 5) src is a directory, dst is a non-directory;
696 * 6) src is a directory, dst does not exist
698 * (1) copies src to dst/basename(src).
699 * (2) fails if COPYFILE_EXCL is set, otherwise copies src to dst.
700 * (3) and (6) copy src to the name dst.
701 * (4) copies the contents of src to the contents of dst.
706 // copy /path/to/src to /path/to/dst/src
707 // Append "/" and (fts_path - strlen(basename(src))) to dst?
709 slash
= strrchr(src
, '/');
713 offset
= slash
- src
+ 1;
715 // copy /path/to/src to /path/to/dst
716 // append (fts_path + strlen(src)) to dst?
718 offset
= strlen(src
);
721 if (s
->flags
| COPYFILE_NOFOLLOW_SRC
)
722 fts_flags
|= FTS_PHYSICAL
;
724 fts_flags
|= FTS_LOGICAL
;
726 fts
= fts_open((char * const *)paths
, fts_flags
, NULL
);
728 status
= s
->statuscb
;
729 while ((ftsent
= fts_read(fts
)) != NULL
) {
731 char *dstfile
= NULL
;
733 copyfile_state_t tstate
= copyfile_state_alloc();
734 if (tstate
== NULL
) {
739 tstate
->statuscb
= s
->statuscb
;
740 tstate
->ctx
= s
->ctx
;
741 if (last_dev
== ftsent
->fts_dev
) {
742 tstate
->internal_flags
|= (s
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
744 last_dev
= ftsent
->fts_dev
;
746 asprintf(&dstfile
, "%s%s%s", dst
, dstpathsep
, ftsent
->fts_path
+ offset
);
747 if (dstfile
== NULL
) {
748 copyfile_state_free(tstate
);
753 switch (ftsent
->fts_info
) {
755 tstate
->internal_flags
|= cfDelayAce
;
756 cmd
= COPYFILE_RECURSE_DIR
;
762 cmd
= COPYFILE_RECURSE_FILE
;
765 cmd
= COPYFILE_RECURSE_DIR_CLEANUP
;
772 errno
= ftsent
->fts_errno
;
774 rv
= (*status
)(COPYFILE_RECURSE_ERROR
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
775 if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
779 if (rv
== COPYFILE_QUIT
) {
792 if (cmd
== COPYFILE_RECURSE_DIR
|| cmd
== COPYFILE_RECURSE_FILE
) {
794 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
795 if (rv
== COPYFILE_SKIP
) {
796 if (cmd
== COPYFILE_RECURSE_DIR
) {
797 rv
= fts_set(fts
, ftsent
, FTS_SKIP
);
799 rv
= (*status
)(0, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
800 if (rv
== COPYFILE_QUIT
)
806 if (rv
== COPYFILE_QUIT
) {
807 retval
= -1; errno
= 0;
811 int tmp_flags
= (cmd
== COPYFILE_RECURSE_DIR
) ? (flags
& ~COPYFILE_STAT
) : flags
;
812 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, tmp_flags
);
815 rv
= (*status
)(cmd
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
816 if (rv
== COPYFILE_QUIT
) {
828 rv
= (*status
)(cmd
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
829 if (rv
== COPYFILE_QUIT
) {
830 retval
= -1; errno
= 0;
834 } else if (cmd
== COPYFILE_RECURSE_DIR_CLEANUP
) {
836 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
837 if (rv
== COPYFILE_QUIT
) {
838 retval
= -1; errno
= 0;
840 } else if (rv
== COPYFILE_SKIP
) {
845 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, (flags
& COPYFILE_NOFOLLOW
) | COPYFILE_STAT
);
848 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
849 if (rv
== COPYFILE_QUIT
) {
852 } else if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
853 if (rv
== COPYFILE_CONTINUE
)
864 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
865 if (rv
== COPYFILE_QUIT
) {
866 retval
= -1; errno
= 0;
876 s
->internal_flags
&= ~COPYFILE_MNT_CPROTECT_MASK
;
877 s
->internal_flags
|= (tstate
->internal_flags
& COPYFILE_MNT_CPROTECT_MASK
);
879 copyfile_state_free(tstate
);
893 * fcopyfile() is used to copy a source file descriptor to a destination file
894 * descriptor. This allows an application to figure out how it wants to open
895 * the files (doing various security checks, perhaps), and then just pass in
896 * the file descriptors.
898 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
901 copyfile_state_t s
= state
;
904 if (src_fd
< 0 || dst_fd
< 0)
910 if (copyfile_preamble(&s
, flags
) < 0)
913 copyfile_debug(2, "set src_fd <- %d", src_fd
);
914 if (s
->src_fd
== -2 && src_fd
> -1)
917 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
919 if (errno
== ENOTSUP
|| errno
== EPERM
)
920 fstat(s
->src_fd
, &s
->sb
);
923 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
929 /* prevent copying on unsupported types */
930 switch (s
->sb
.st_mode
& S_IFMT
)
941 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
942 if (s
->dst_fd
== -2 && dst_fd
> -1)
945 (void)fstat(s
->dst_fd
, &dst_sb
);
946 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
948 (void)copyfile_quarantine(s
);
950 ret
= copyfile_internal(s
, flags
);
952 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
954 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
963 copyfile_state_free(s
);
972 * the original copyfile() routine; this copies a source file to a destination
973 * file. Note that because we need to set the names in the state variable, this
974 * is not just the same as opening the two files, and then calling fcopyfile().
975 * Oh, if only life were that simple!
977 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
981 copyfile_state_t s
= state
;
984 if (src
== NULL
&& dst
== NULL
)
990 if (copyfile_preamble(&s
, flags
) < 0)
996 * This macro is... well, it's not the worst thing you can do with cpp, not
997 * by a long shot. Essentially, we are setting the filename (src or dst)
998 * in the state structure; since the structure may not have been cleared out
999 * before being used again, we do some of the cleanup here: if the given
1000 * filename (e.g., src) is set, and state->src is not equal to that, then
1001 * we need to check to see if the file descriptor had been opened, and if so,
1002 * close it. After that, we set state->src to be a copy of the given filename,
1003 * releasing the old copy if necessary.
1005 #define COPYFILE_SET_FNAME(NAME, S) \
1007 if (NAME != NULL) { \
1008 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
1009 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
1010 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
1011 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
1012 close(S->NAME##_fd); \
1013 S->NAME##_fd = -2; \
1020 if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \
1025 COPYFILE_SET_FNAME(src
, s
);
1026 COPYFILE_SET_FNAME(dst
, s
);
1028 if (s
->flags
& COPYFILE_RECURSIVE
) {
1034 * Get a copy of the source file's security settings
1036 if (s
->original_fsec
) {
1037 filesec_free(s
->original_fsec
);
1038 s
->original_fsec
= NULL
;
1040 if ((s
->original_fsec
= filesec_init()) == NULL
)
1043 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
1044 ((dst_sb
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1045 if (s
->permissive_fsec
)
1046 free(s
->permissive_fsec
);
1047 s
->permissive_fsec
= NULL
;
1048 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
1051 * copyfile_fix_perms() will make a copy of the permission set,
1052 * and insert at the beginning an ACE that ensures we can write
1053 * to the file and set attributes.
1056 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
1059 * Set the permissions for the destination to our copy.
1060 * We should get ENOTSUP from any filesystem that simply
1061 * doesn't support it.
1063 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
1065 copyfile_warn("setting security information");
1066 filesec_free(s
->permissive_fsec
);
1067 s
->permissive_fsec
= NULL
;
1070 } else if (errno
== ENOENT
) {
1075 * If COPYFILE_CHECK is set in flags, then all we are going to do
1076 * is see what kinds of things WOULD have been copied (see
1077 * copyfile_check() below). We return that value.
1079 if (COPYFILE_CHECK
& flags
)
1081 ret
= copyfile_check(s
);
1083 } else if ((ret
= copyfile_open(s
)) < 0)
1086 (void)fcntl(s
->src_fd
, F_NOCACHE
, 1);
1087 (void)fcntl(s
->dst_fd
, F_NOCACHE
, 1);
1088 #ifdef F_SINGLE_WRITER
1089 (void)fcntl(s
->dst_fd
, F_SINGLE_WRITER
, 1);
1092 ret
= copyfile_internal(s
, flags
);
1096 #ifdef COPYFILE_RECURSIVE
1097 if (!(flags
& COPYFILE_STAT
)) {
1100 /* Just need to reset the BSD information -- mode, owner, group */
1101 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
1102 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
1109 if (s
->src
&& (flags
& COPYFILE_MOVE
))
1110 (void)remove(s
->src
);
1113 if (state
== NULL
) {
1115 copyfile_state_free(s
);
1131 * Shared prelude to the {f,}copyfile(). This initializes the
1132 * state variable, if necessary, and also checks for both debugging
1133 * and disabling environment variables.
1135 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
1141 if ((*state
= copyfile_state_alloc()) == NULL
)
1147 if (COPYFILE_DEBUG
& flags
)
1150 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
1153 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
1155 /* clamp s->debug to 1 if the environment variable is not parsable */
1156 if (s
->debug
== 0 && errno
!= 0)
1159 copyfile_debug(2, "debug value set to: %d", s
->debug
);
1163 /* Temporarily disabled */
1164 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
1166 copyfile_debug(1, "copyfile disabled");
1170 copyfile_debug(2, "setting flags: %d", s
->flags
);
1177 * The guts of {f,}copyfile().
1178 * This looks through the flags in a particular order, and calls the
1179 * associated functions.
1181 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
1185 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1187 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1193 * COPYFILE_PACK causes us to create an Apple Double version of the
1194 * source file, and puts it into the destination file. See
1195 * copyfile_pack() below for all the gory details.
1197 if (COPYFILE_PACK
& flags
)
1199 if ((ret
= copyfile_pack(s
)) < 0)
1201 if (s
->dst
) unlink(s
->dst
);
1208 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1209 * The goal there is to take an Apple Double file, and turn it
1210 * into a normal file (with data fork, resource fork, modes,
1211 * extended attributes, ACLs, etc.).
1213 if (COPYFILE_UNPACK
& flags
)
1215 if ((ret
= copyfile_unpack(s
)) < 0)
1221 * If we have quarantine info set, we attempt
1222 * to apply it to dst_fd. We don't care if
1223 * it fails, not yet anyway.
1226 int qr
= qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1231 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
1232 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1233 s
->xattr_name
= NULL
;
1234 if (rv
== COPYFILE_QUIT
) {
1235 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1240 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1248 * COPYFILE_XATTR tells us to copy the extended attributes;
1249 * this is seperate from the extended security (aka ACLs),
1250 * however. If we succeed in this, we continue to the next
1251 * stage; if we fail, we return with an error value. Note
1252 * that we fail if the errno is ENOTSUP, but we don't print
1253 * a warning in that case.
1255 if (COPYFILE_XATTR
& flags
)
1257 if ((ret
= copyfile_xattr(s
)) < 0)
1259 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1260 copyfile_warn("error processing extended attributes");
1266 * Simialr to above, this tells us whether or not to copy
1267 * the non-meta data portion of the file. We attempt to
1268 * remove (via unlink) the destination file if we fail.
1270 if (COPYFILE_DATA
& flags
)
1272 if ((ret
= copyfile_data(s
)) < 0)
1274 copyfile_warn("error processing data");
1275 if (s
->dst
&& unlink(s
->dst
))
1276 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1282 * COPYFILE_SECURITY requests that we copy the security, both
1283 * extended and mundane (that is, ACLs and POSIX).
1285 if (COPYFILE_SECURITY
& flags
)
1287 if ((ret
= copyfile_security(s
)) < 0)
1289 copyfile_warn("error processing security information");
1294 if (COPYFILE_STAT
& flags
)
1296 if ((ret
= copyfile_stat(s
)) < 0)
1298 copyfile_warn("error processing POSIX information");
1312 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1314 copyfile_state_t
copyfile_state_alloc(void)
1316 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1323 filesec_free(s
->fsec
);
1326 s
->fsec
= filesec_init();
1334 * copyfile_state_free() returns the memory allocated to the state structure.
1335 * It also closes the file descriptors, if they've been opened.
1337 int copyfile_state_free(copyfile_state_t s
)
1342 filesec_free(s
->fsec
);
1344 if (s
->original_fsec
)
1345 filesec_free(s
->original_fsec
);
1347 if (s
->permissive_fsec
)
1348 filesec_free(s
->permissive_fsec
);
1351 qtn_file_free(s
->qinfo
);
1353 if (copyfile_close(s
) < 0)
1355 copyfile_warn("error closing files");
1359 free(s
->xattr_name
);
1370 * Should we worry if we can't close the source? NFS says we
1371 * should, but it's pretty late for us at this point.
1373 static int copyfile_close(copyfile_state_t s
)
1375 if (s
->src
&& s
->src_fd
>= 0)
1378 if (s
->dst
&& s
->dst_fd
>= 0) {
1379 if (close(s
->dst_fd
))
1387 * The purpose of this function is to set up a set of permissions
1388 * (ACL and traditional) that lets us write to the file. In the
1389 * case of ACLs, we do this by putting in a first entry that lets
1390 * us write data, attributes, and extended attributes. In the case
1391 * of traditional permissions, we set the S_IWUSR (user-write)
1394 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1396 filesec_t ret_fsec
= NULL
;
1400 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1403 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1405 #ifdef COPYFILE_RECURSIVE
1406 if (add_uberace(&acl
))
1410 acl_permset_t permset
;
1413 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1417 * First, we create an entry, and give it the special name
1418 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1419 * After that, we clear out all the permissions in it, and
1420 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1421 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1422 * the functionality, and put this into the ACL.
1424 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1426 if (acl_get_permset(entry
, &permset
) == -1)
1428 if (acl_clear_perms(permset
) == -1)
1430 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1432 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1434 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1436 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1439 if(acl_set_permset(entry
, permset
) == -1)
1441 if(acl_set_qualifier(entry
, qual
) == -1)
1445 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1450 * This is for the normal, mundane, POSIX permission model.
1451 * We make sure that we can write to the file.
1453 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1455 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1457 mode
|= S_IWUSR
|S_IRUSR
;
1458 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1472 filesec_free(ret_fsec
);
1479 * Used to clear out the BSD/POSIX security information from
1483 copyfile_unset_posix_fsec(filesec_t fsec
)
1485 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1486 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1487 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1492 * Used to remove acl information from a filesec_t
1493 * Unsetting the acl alone in Tiger was insufficient
1495 static int copyfile_unset_acl(copyfile_state_t s
)
1498 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1500 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1503 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1505 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1508 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1510 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1517 * copyfile_open() does what one expects: it opens up the files
1518 * given in the state structure, if they're not already open.
1519 * It also does some type validation, to ensure that we only
1520 * handle file types we know about.
1522 static int copyfile_open(copyfile_state_t s
)
1524 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
1525 int islnk
= 0, isdir
= 0, isreg
= 0;
1526 int osrc
= 0, dsrc
= 0;
1527 int prot_class
= PROTECTION_CLASS_DEFAULT
;
1528 int set_cprot_explicit
= 0;
1531 if (s
->src
&& s
->src_fd
== -2)
1533 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1534 (s
->src
, &s
->sb
, s
->fsec
))
1536 copyfile_warn("stat on %s", s
->src
);
1540 /* prevent copying on unsupported types */
1541 switch (s
->sb
.st_mode
& S_IFMT
)
1545 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1546 s
->err
= ENOMEM
; /* too big for us to copy */
1558 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1564 * If we're packing, then we are actually
1565 * creating a file, no matter what the source
1568 if (s
->flags
& COPYFILE_PACK
) {
1570 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1571 * if the file is a symlink, and O_NOFOLLOW is specified,
1572 * open will return ELOOP, whether or not O_SYMLINK is set.
1573 * However, we know whether or not it was a symlink from
1574 * the stat above (although there is a potentiaal for a race
1575 * condition here, but it will err on the side of returning
1579 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1583 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1585 copyfile_warn("open on %s", s
->src
);
1588 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1590 (void)copyfile_quarantine(s
);
1593 if (s
->dst
&& s
->dst_fd
== -2)
1596 * COPYFILE_UNLINK tells us to try removing the destination
1597 * before we create it. We don't care if the file doesn't
1598 * exist, so we ignore ENOENT.
1600 if (COPYFILE_UNLINK
& s
->flags
)
1602 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1604 copyfile_warn("%s: remove", s
->dst
);
1609 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1613 if (lstat(s
->dst
, &st
) != -1) {
1614 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1619 if (!(s
->internal_flags
& cfSrcProtSupportValid
))
1621 if ((error
= does_copy_protection(s
->src_fd
)) > 0)
1623 s
->internal_flags
|= cfSrcSupportsCProtect
;
1627 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->src
, errno
);
1630 s
->internal_flags
|= cfSrcProtSupportValid
;
1633 /* copy protection is only valid for regular files and directories. */
1634 if ((isreg
|| isdir
) && (s
->internal_flags
& cfSrcSupportsCProtect
))
1636 prot_class
= GET_PROT_CLASS(s
->src_fd
);
1639 copyfile_warn("GET_PROT_CLASS failed on (%s) with error <%d>", s
->src
, errno
);
1645 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1650 copyfile_warn("cannot allocate %zd bytes", sz
);
1653 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1654 copyfile_warn("cannot readlink %s", s
->src
);
1658 if (symlink(bp
, s
->dst
) == -1) {
1659 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1660 copyfile_warn("Cannot make symlink %s", s
->dst
);
1666 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1667 if (s
->dst_fd
== -1) {
1668 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1673 mode
= (s
->sb
.st_mode
& ~S_IFMT
) | S_IRWXU
;
1675 if (mkdir(s
->dst
, mode
) == -1) {
1676 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1677 copyfile_warn("Cannot make directory %s", s
->dst
);
1681 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1682 if (s
->dst_fd
== -1) {
1683 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1686 set_cprot_explicit
= 1;
1687 } else while((s
->dst_fd
= open_dprotected_np(s
->dst
, oflags
| dsrc
, prot_class
, 0, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1690 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1691 * was written -- allow one to set an extended attribute on a file descriptor
1692 * for a read-only file, even if the file descriptor is opened for writing.
1693 * This will only matter if the file does not already exist.
1698 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1699 if (s
->flags
& COPYFILE_EXCL
)
1701 oflags
= oflags
& ~O_CREAT
;
1702 /* if O_CREAT isn't set in open_dprotected_np, it won't set protection class.
1703 * Set the flag here so we know to do it later.
1705 set_cprot_explicit
= 1;
1706 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
1708 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
1713 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
1717 * If we're trying to write to a directory to which we don't
1718 * have access, the create above would have failed, but chmod
1719 * here would have given us ENOENT. But the real error is
1720 * still one of access, so we change the errno we're reporting.
1721 * This could cause confusion with a race condition.
1724 if (errno
== ENOENT
)
1729 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
1730 if (((s
->flags
& COPYFILE_EXCL
) ||
1731 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
1732 && !(s
->flags
& COPYFILE_UNPACK
))
1734 oflags
= (oflags
& ~(O_WRONLY
|O_CREAT
|O_TRUNC
)) | O_RDONLY
;
1737 copyfile_warn("open on %s", s
->dst
);
1740 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
1742 if (s
->internal_flags
& cfSrcSupportsCProtect
)
1744 if (!(s
->internal_flags
& cfDstProtSupportValid
))
1746 if ((error
= does_copy_protection(s
->dst_fd
)) > 0)
1748 s
->internal_flags
|= cfDstSupportsCProtect
;
1752 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s
->dst
, errno
);
1755 s
->internal_flags
|= cfDstProtSupportValid
;
1758 if ((isreg
|| isdir
)
1759 && set_cprot_explicit
1760 && (s
->internal_flags
& cfDstSupportsCProtect
))
1762 /* Protection class is set in open_dprotected_np for regular files that aren't truncated.
1763 * We set the protection class here for truncated files and directories.
1765 if (SET_PROT_CLASS(s
->dst_fd
, prot_class
) != 0)
1767 copyfile_warn("SET_PROT_CLASS failed on (%s) with error <%d>", s
->dst
, errno
);
1774 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1776 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1777 s
->src_fd
, s
->dst_fd
);
1786 * copyfile_check(), as described above, essentially tells you
1787 * what you'd have to copy, if you wanted it to copy the things
1788 * you asked it to copy.
1789 * In other words, if you pass in COPYFILE_ALL, and the file in
1790 * question had no extended attributes but did have an ACL, you'd
1791 * get back COPYFILE_ACL.
1793 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
1796 copyfile_flags_t ret
= 0;
1797 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
1807 if (COPYFILE_XATTR
& s
->flags
)
1808 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
1810 ret
|= COPYFILE_XATTR
;
1813 if (COPYFILE_ACL
& s
->flags
)
1815 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1816 (s
->src
, &s
->sb
, s
->fsec
);
1818 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
1819 ret
|= COPYFILE_ACL
;
1822 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
1828 /* If the state has had quarantine info set already, we use that */
1829 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1831 qinfo
= qtn_file_alloc();
1833 * For quarantine information, we need to see if the source file
1834 * has any. Since it may be a symlink, however, and we may, or
1835 * not be following, *and* there's no qtn* routine which can optionally
1836 * follow or not follow a symlink, we need to instead work around
1845 * If we care about not following symlinks, *and* the file exists
1846 * (which is to say, lstat doesn't return an error), *and* the file
1847 * is a symlink, then we open it up (with O_SYMLINK), and use
1848 * qtn_file_init_with_fd(); if none of that is true, however, then
1849 * we can simply use qtn_file_init_with_path().
1852 && lstat(s
->src
, &sbuf
) == 0
1853 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1854 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
1856 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
1857 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1862 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
1863 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1866 qtn_file_free(qinfo
);
1874 * Attempt to copy the data section of a file. Using blockisize
1875 * is not necessarily the fastest -- it might be desirable to
1876 * specify a blocksize, somehow. But it's a size that should be
1877 * guaranteed to work.
1879 static int copyfile_data(copyfile_state_t s
)
1885 size_t iBlocksize
= 0;
1886 size_t oBlocksize
= 0;
1887 const size_t onegig
= 1 << 30;
1889 copyfile_callback_t status
= s
->statuscb
;
1891 /* Unless it's a normal file, we don't copy. For now, anyway */
1892 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
1895 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
1896 if (s
->internal_flags
& cfSawDecmpEA
) {
1897 if (s
->sb
.st_flags
& UF_COMPRESSED
) {
1898 if ((s
->flags
& COPYFILE_STAT
) == 0) {
1899 if (fchflags(s
->dst_fd
, UF_COMPRESSED
) == 0) {
1907 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
1908 iBlocksize
= s
->sb
.st_blksize
;
1910 iBlocksize
= sfs
.f_iosize
;
1913 /* Work-around for 6453525, limit blocksize to 1G */
1914 if (iBlocksize
> onegig
) {
1915 iBlocksize
= onegig
;
1918 if ((bp
= malloc(iBlocksize
)) == NULL
)
1921 if (fstatfs(s
->dst_fd
, &sfs
) == -1 || sfs
.f_iosize
== 0) {
1922 oBlocksize
= iBlocksize
;
1924 oBlocksize
= sfs
.f_iosize
;
1925 if (oBlocksize
> onegig
)
1926 oBlocksize
= onegig
;
1932 /* If supported, do preallocation for Xsan / HFS volumes */
1933 #ifdef F_PREALLOCATE
1938 fst
.fst_posmode
= F_PEOFPOSMODE
;
1940 fst
.fst_length
= s
->sb
.st_size
;
1941 /* Ignore errors; this is merely advisory. */
1942 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
1946 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
1949 size_t left
= nread
;
1954 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
1958 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
1965 copyfile_warn("writing to output file got error");
1967 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1968 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
1972 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
1981 ptr
= ((char*)ptr
) + nwritten
;
1985 s
->totalCopied
+= nwritten
;
1987 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
1988 if (rv
== COPYFILE_QUIT
) {
1989 ret
= -1; s
->err
= errno
= ECANCELED
;
1997 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
2002 if (ftruncate(s
->dst_fd
, s
->totalCopied
) < 0)
2018 * copyfile_security() will copy the ACL set, and the
2019 * POSIX set. Complexities come when dealing with
2020 * inheritied permissions, and when dealing with both
2021 * POSIX and ACL permissions.
2023 static int copyfile_security(copyfile_state_t s
)
2027 acl_t acl_src
= NULL
, acl_tmp
= NULL
, acl_dst
= NULL
;
2029 filesec_t tmp_fsec
= NULL
;
2030 filesec_t fsec_dst
= filesec_init();
2032 if (fsec_dst
== NULL
)
2036 if (COPYFILE_ACL
& s
->flags
)
2038 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
2040 if (errno
== ENOENT
)
2046 /* grab the destination acl
2047 cannot assume it's empty due to inheritance
2049 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
2052 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
2054 if (errno
== ENOENT
)
2060 if (acl_src
== NULL
&& acl_dst
== NULL
)
2063 acl_tmp
= acl_init(4);
2064 if (acl_tmp
== NULL
)
2068 acl_entry_t ace
= NULL
;
2069 acl_entry_t tmp
= NULL
;
2071 acl_get_entry(acl_src
,
2072 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2075 acl_flagset_t flags
= { 0 };
2076 acl_get_flagset_np(ace
, &flags
);
2077 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2079 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2082 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2085 copyfile_debug(2, "copied acl entry from %s to %s",
2086 s
->src
? s
->src
: "(null src)",
2087 s
->dst
? s
->dst
: "(null tmp)");
2093 acl_entry_t ace
= NULL
;
2094 acl_entry_t tmp
= NULL
;
2095 acl_flagset_t flags
= { 0 };
2096 for (copied
= 0;acl_get_entry(acl_dst
,
2097 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2100 acl_get_flagset_np(ace
, &flags
);
2101 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2103 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2106 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2109 copyfile_debug(2, "copied acl entry from %s to %s",
2110 s
->src
? s
->src
: "(null dst)",
2111 s
->dst
? s
->dst
: "(null tmp)");
2116 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_tmp
))
2118 copyfile_debug(3, "altered acl");
2123 * The following code is attempting to ensure that only the requested
2124 * security information gets copied over to the destination file.
2125 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2126 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2129 * If we have both flags, we copy everything; if we have ACL but not STAT,
2130 * we remove the POSIX information from the filesec object, and apply the
2131 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2132 * the extended version.
2134 tmp_fsec
= filesec_dup(s
->fsec
);
2135 if (tmp_fsec
== NULL
) {
2139 switch (COPYFILE_SECURITY
& s
->flags
) {
2141 copyfile_unset_posix_fsec(tmp_fsec
);
2143 case COPYFILE_ACL
| COPYFILE_STAT
:
2144 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
2147 * The call could have failed for a number of reasons, since
2148 * it does a number of things: it changes the mode of the file,
2149 * sets the owner and group, and applies an ACL (if one exists).
2150 * The typical failure is going to be trying to set the group of
2151 * the destination file to match the source file, when the process
2152 * doesn't have permission to put files in that group. We try to
2153 * work around this by breaking the steps out and doing them
2154 * discretely. We don't care if the fchown fails, but we do care
2155 * if the mode or ACL can't be set. For historical reasons, we
2156 * simply log those failures, however.
2158 * Big warning here: we may NOT have COPYFILE_STAT set, since
2159 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2162 #define NS(x) ((x) ? (x) : "(null string)")
2163 if ((s
->flags
& COPYFILE_STAT
) &&
2164 fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
2165 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
2167 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2168 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
2169 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
2170 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
2178 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
2181 filesec_free(tmp_fsec
);
2183 filesec_free(fsec_dst
);
2184 if (acl_src
) acl_free(acl_src
);
2185 if (acl_dst
) acl_free(acl_dst
);
2186 if (acl_tmp
) acl_free(acl_tmp
);
2197 * Attempt to set the destination file's stat information -- including
2198 * flags and time-related fields -- to the source's.
2200 static int copyfile_stat(copyfile_state_t s
)
2202 struct timeval tval
[2];
2203 unsigned int added_flags
= 0, dst_flags
= 0;
2207 * NFS doesn't support chflags; ignore errors as a result, since
2208 * we don't return failure for this.
2210 if (s
->internal_flags
& cfMakeFileInvisible
)
2211 added_flags
|= UF_HIDDEN
;
2214 * We need to check if SF_RESTRICTED was set on the destination
2215 * by the kernel. If it was, don't drop it.
2217 if (fstat(s
->dst_fd
, &dst_sb
))
2219 if (dst_sb
.st_flags
& SF_RESTRICTED
)
2220 added_flags
|= SF_RESTRICTED
;
2222 /* Copy file flags, masking out any we don't want to preserve */
2223 dst_flags
= (s
->sb
.st_flags
& ~COPYFILE_OMIT_FLAGS
) | added_flags
;
2224 (void)fchflags(s
->dst_fd
, dst_flags
);
2226 /* If this fails, we don't care */
2227 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2229 /* This may have already been done in copyfile_security() */
2230 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
2232 tval
[0].tv_sec
= s
->sb
.st_atime
;
2233 tval
[1].tv_sec
= s
->sb
.st_mtime
;
2234 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
2235 (void)futimes(s
->dst_fd
, tval
);
2241 * Similar to copyfile_security() in some ways; this
2242 * routine copies the extended attributes from the source,
2243 * and sets them on the destination.
2244 * The procedure is pretty simple, even if it is verbose:
2245 * for each named attribute on the destination, get its name, and
2246 * remove it. We should have none after that.
2247 * For each named attribute on the source, get its name, get its
2248 * data, and set it on the destination.
2250 static int copyfile_xattr(copyfile_state_t s
)
2253 char *namebuf
, *end
;
2256 ssize_t bufsize
= 4096;
2260 int look_for_decmpea
= 0;
2262 /* delete EAs on destination */
2263 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2265 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2268 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
2272 * With this, end points to the last byte of the allocated buffer
2273 * This *should* be NUL, from flistxattr, but if it's not, we can
2274 * set it anyway -- it'll result in a truncated name, which then
2275 * shouldn't match when we get them later.
2277 end
= namebuf
+ nsize
- 1;
2280 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
2281 /* If the quarantine information shows up as an EA, we skip over it */
2282 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
2285 fremovexattr(s
->dst_fd
, name
,0);
2292 if (errno
== ENOTSUP
|| errno
== EPERM
)
2298 #ifdef DECMPFS_XATTR_NAME
2299 if ((s
->flags
& COPYFILE_DATA
) &&
2300 (s
->sb
.st_flags
& UF_COMPRESSED
) &&
2301 doesdecmpfs(s
->src_fd
) &&
2302 doesdecmpfs(s
->dst_fd
)) {
2303 look_for_decmpea
= XATTR_SHOWCOMPRESSION
;
2307 /* get name list of EAs on source */
2308 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, look_for_decmpea
)) < 0)
2310 if (errno
== ENOTSUP
|| errno
== EPERM
)
2318 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2321 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, look_for_decmpea
);
2329 * With this, end points to the last byte of the allocated buffer
2330 * This *should* be NUL, from flistxattr, but if it's not, we can
2331 * set it anyway -- it'll result in a truncated name, which then
2332 * shouldn't match when we get them later.
2334 end
= namebuf
+ nsize
- 1;
2338 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
2343 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
2345 if (s
->xattr_name
) {
2346 free(s
->xattr_name
);
2347 s
->xattr_name
= NULL
;
2350 /* If the quarantine information shows up as an EA, we skip over it */
2351 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
2354 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, look_for_decmpea
)) < 0)
2359 if (xa_size
> bufsize
)
2361 void *tdptr
= xa_dataptr
;
2364 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
2372 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
)) < 0)
2377 if (xa_size
!= asize
)
2380 #ifdef DECMPFS_XATTR_NAME
2381 if (strncmp(name
, DECMPFS_XATTR_NAME
, end
-name
) == 0)
2383 decmpfs_disk_header
*hdr
= xa_dataptr
;
2386 * If the EA has the decmpfs name, but is too
2387 * small, or doesn't have the right magic number,
2388 * or isn't the right type, we'll just skip it.
2389 * This means it won't end up in the destination
2390 * file, and data copy will happen normally.
2392 if ((size_t)xa_size
< sizeof(decmpfs_disk_header
)) {
2395 if (OSSwapLittleToHostInt32(hdr
->compression_magic
) != DECMPFS_MAGIC
) {
2399 * From AppleFSCompression documentation:
2400 * "It is incumbent on the aware copy engine to identify
2401 * the type of compression being used, and to perform an
2402 * unaware copy of any file it does not recognize."
2404 * Compression Types are defined in:
2405 * "AppleFSCompression/Common/compressorCommon.h"
2407 * Unfortunately, they don't provide a way to dynamically
2408 * determine what possible compression_type values exist,
2409 * so we have to update this every time a new compression_type
2410 * is added. Types 7->10 were added in 10.10, Types 11 & 12
2411 * were added in 10.11.
2413 * Ubiquity faulting file compression type 0x80000001 are
2414 * deprecated as of Yosemite, per rdar://17714998 don't copy the
2415 * decmpfs xattr on these files, zero byte files are safer
2416 * than a fault nobody knows how to handle.
2418 switch (OSSwapLittleToHostInt32(hdr
->compression_type
)) {
2419 case 3: /* zlib-compressed data in xattr */
2420 case 4: /* 64k chunked zlib-compressed data in resource fork */
2422 case 7: /* LZVN-compressed data in xattr */
2423 case 8: /* 64k chunked LZVN-compressed data in resource fork */
2425 case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */
2426 case 10: /* 64k chunked uncompressed data in resource fork */
2428 case 11: /* LZFSE-compressed data in xattr */
2429 case 12: /* 64k chunked LZFSE-compressed data in resource fork */
2431 /* valid compression type, we want to copy. */
2434 case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */
2435 copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.",
2436 s
->src
? s
->src
: "(null string)");
2439 case 6: /* unused */
2440 case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */
2442 copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s",
2443 OSSwapLittleToHostInt32(hdr
->compression_type
), name
, s
->src
? s
->src
: "(null string)");
2446 s
->internal_flags
|= cfSawDecmpEA
;
2450 // If we have a copy intention stated, and the EA is to be ignored, we ignore it
2452 && xattr_preserve_for_intent(name
, s
->copyIntent
) == 0)
2455 s
->xattr_name
= strdup(name
);
2459 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
2460 if (rv
== COPYFILE_QUIT
) {
2463 } else if (rv
== COPYFILE_SKIP
) {
2467 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
) < 0)
2472 if (s
->xattr_name
== NULL
)
2473 s
->xattr_name
= strdup(name
);
2474 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2475 if (rv
== COPYFILE_QUIT
)
2485 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name
, strerror(errno
));
2491 if (s
->xattr_name
== NULL
)
2492 s
->xattr_name
= strdup(name
);
2494 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
2495 if (rv
== COPYFILE_QUIT
) {
2504 free((void *) xa_dataptr
);
2505 if (s
->xattr_name
) {
2506 free(s
->xattr_name
);
2507 s
->xattr_name
= NULL
;
2513 * API interface into getting data from the opaque data type.
2515 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
2525 case COPYFILE_STATE_SRC_FD
:
2526 *(int*)ret
= s
->src_fd
;
2528 case COPYFILE_STATE_DST_FD
:
2529 *(int*)ret
= s
->dst_fd
;
2531 case COPYFILE_STATE_SRC_FILENAME
:
2532 *(char**)ret
= s
->src
;
2534 case COPYFILE_STATE_DST_FILENAME
:
2535 *(char**)ret
= s
->dst
;
2537 case COPYFILE_STATE_QUARANTINE
:
2538 *(qtn_file_t
*)ret
= s
->qinfo
;
2541 case COPYFILE_STATE_STATS
:
2542 ret
= s
->stats
.global
;
2544 case COPYFILE_STATE_PROGRESS_CB
:
2545 ret
= s
->callbacks
.progress
;
2548 #ifdef COPYFILE_STATE_STATUS_CB
2549 case COPYFILE_STATE_STATUS_CB
:
2550 *(copyfile_callback_t
*)ret
= s
->statuscb
;
2552 case COPYFILE_STATE_STATUS_CTX
:
2553 *(void**)ret
= s
->ctx
;
2555 case COPYFILE_STATE_COPIED
:
2556 *(off_t
*)ret
= s
->totalCopied
;
2559 #ifdef COPYFILE_STATE_XATTRNAME
2560 case COPYFILE_STATE_XATTRNAME
:
2561 *(char**)ret
= s
->xattr_name
;
2564 #ifdef COPYFILE_STATE_INTENT
2565 case COPYFILE_STATE_INTENT
:
2566 *(xattr_operation_intent_t
*)ret
= s
->copyIntent
;
2578 * Public API for setting state data (remember that the state is
2579 * an opaque data type).
2581 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
2583 #define copyfile_set_string(DST, SRC) \
2585 if (SRC != NULL) { \
2586 DST = strdup((char *)SRC); \
2588 if (DST != NULL) { \
2603 case COPYFILE_STATE_SRC_FD
:
2604 s
->src_fd
= *(int*)thing
;
2606 case COPYFILE_STATE_DST_FD
:
2607 s
->dst_fd
= *(int*)thing
;
2609 case COPYFILE_STATE_SRC_FILENAME
:
2610 copyfile_set_string(s
->src
, thing
);
2612 case COPYFILE_STATE_DST_FILENAME
:
2613 copyfile_set_string(s
->dst
, thing
);
2615 case COPYFILE_STATE_QUARANTINE
:
2618 qtn_file_free(s
->qinfo
);
2621 if (*(qtn_file_t
*)thing
)
2622 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
2625 case COPYFILE_STATE_STATS
:
2626 s
->stats
.global
= thing
;
2628 case COPYFILE_STATE_PROGRESS_CB
:
2629 s
->callbacks
.progress
= thing
;
2632 #ifdef COPYFILE_STATE_STATUS_CB
2633 case COPYFILE_STATE_STATUS_CB
:
2634 s
->statuscb
= (copyfile_callback_t
)thing
;
2636 case COPYFILE_STATE_STATUS_CTX
:
2637 s
->ctx
= (void*)thing
;
2640 #ifdef COPYFILE_STATE_INTENT
2641 case COPYFILE_STATE_INTENT
:
2642 s
->copyIntent
= *(xattr_operation_intent_t
*)thing
;
2650 #undef copyfile_set_string
2655 * Make this a standalone program for testing purposes by
2656 * defining _COPYFILE_TEST.
2658 #ifdef _COPYFILE_TEST
2659 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2661 struct {char *s
; int v
;} opts
[] = {
2662 COPYFILE_OPTION(ACL
)
2663 COPYFILE_OPTION(STAT
)
2664 COPYFILE_OPTION(XATTR
)
2665 COPYFILE_OPTION(DATA
)
2666 COPYFILE_OPTION(SECURITY
)
2667 COPYFILE_OPTION(METADATA
)
2668 COPYFILE_OPTION(ALL
)
2669 COPYFILE_OPTION(NOFOLLOW_SRC
)
2670 COPYFILE_OPTION(NOFOLLOW_DST
)
2671 COPYFILE_OPTION(NOFOLLOW
)
2672 COPYFILE_OPTION(EXCL
)
2673 COPYFILE_OPTION(MOVE
)
2674 COPYFILE_OPTION(UNLINK
)
2675 COPYFILE_OPTION(PACK
)
2676 COPYFILE_OPTION(UNPACK
)
2677 COPYFILE_OPTION(CHECK
)
2678 COPYFILE_OPTION(VERBOSE
)
2679 COPYFILE_OPTION(DEBUG
)
2683 int main(int c
, char *v
[])
2689 errx(1, "insufficient arguments");
2693 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
2695 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
2697 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
2704 return copyfile(v
[1], v
[2], NULL
, flags
);
2708 * Apple Double Create
2710 * Create an Apple Double "._" file from a file's extented attributes
2712 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2716 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2718 #define XATTR_MAXATTRLEN (16*1024*1024)
2722 Typical "._" AppleDouble Header File layout:
2723 ------------------------------------------------------------
2728 .-- AD ENTRY[0] Finder Info Entry (must be first)
2729 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2731 | ///////////// Fixed Size Data (32 bytes)
2735 | ATTR ENTRY[1] --+--.
2736 | ATTR ENTRY[2] --+--+--.
2738 | ATTR ENTRY[N] --+--+--+--.
2739 | ATTR DATA 0 <-' | | |
2740 | //////////// | | |
2741 | ATTR DATA 1 <----' | |
2743 | ATTR DATA 2 <-------' |
2746 | ATTR DATA N <----------'
2748 | Attribute Free Space
2750 '----> RESOURCE FORK
2751 ///////////// Variable Sized Data
2760 ------------------------------------------------------------
2762 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2763 stored as part of the Finder Info. The length in the Finder
2764 Info AppleDouble entry includes the length of the extended
2765 attribute header, attribute entries, and attribute data.
2770 * On Disk Data Structures
2772 * Note: Motorola 68K alignment and big-endian.
2774 * See RFC 1740 for additional information about the AppleDouble file format.
2778 #define ADH_MAGIC 0x00051607
2779 #define ADH_VERSION 0x00020000
2780 #define ADH_MACOSX "Mac OS X "
2783 * AppleDouble Entry ID's
2785 #define AD_DATA 1 /* Data fork */
2786 #define AD_RESOURCE 2 /* Resource fork */
2787 #define AD_REALNAME 3 /* File's name on home file system */
2788 #define AD_COMMENT 4 /* Standard Mac comment */
2789 #define AD_ICONBW 5 /* Mac black & white icon */
2790 #define AD_ICONCOLOR 6 /* Mac color icon */
2791 #define AD_UNUSED 7 /* Not used */
2792 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2793 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2794 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2795 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2796 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2797 #define AD_AFPNAME 13 /* Short name on AFP server */
2798 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2799 #define AD_AFPDIRID 15 /* AFP directory ID */
2800 #define AD_ATTRIBUTES AD_FINDERINFO
2803 #define ATTR_FILE_PREFIX "._"
2804 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2806 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2808 /* Implementation Limits */
2809 #define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */
2810 #define ATTR_MAX_NAME_LEN 128
2811 #define ATTR_MAX_HDR_SIZE (65536+18)
2814 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2815 * size supported (including the attribute entries). All of
2816 * the attribute entries must reside within this limit.
2820 #define FINDERINFOSIZE 32
2822 typedef struct apple_double_entry
2824 u_int32_t type
; /* entry type: see list, 0 invalid */
2825 u_int32_t offset
; /* entry data offset from the beginning of the file. */
2826 u_int32_t length
; /* entry data length in bytes. */
2827 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
2830 typedef struct apple_double_header
2832 u_int32_t magic
; /* == ADH_MAGIC */
2833 u_int32_t version
; /* format version: 2 = 0x00020000 */
2834 u_int32_t filler
[4];
2835 u_int16_t numEntries
; /* number of entries which follow */
2836 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
2837 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
2838 u_int8_t pad
[2]; /* get better alignment inside attr_header */
2839 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
2842 /* Entries are aligned on 4 byte boundaries */
2843 typedef struct attr_entry
2845 u_int32_t offset
; /* file offset to data */
2846 u_int32_t length
; /* size of attribute data */
2848 u_int8_t namelen
; /* length of name including NULL termination char */
2849 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2850 } __attribute__((aligned(2), packed
)) attr_entry_t
;
2854 /* Header + entries must fit into 64K */
2855 typedef struct attr_header
2857 apple_double_header_t appledouble
;
2858 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
2859 u_int32_t debug_tag
; /* for debugging == file id of owning file */
2860 u_int32_t total_size
; /* total size of attribute header + entries + data */
2861 u_int32_t data_start
; /* file offset to attribute data area */
2862 u_int32_t data_length
; /* length of attribute data area */
2863 u_int32_t reserved
[3];
2865 u_int16_t num_attrs
;
2866 } __attribute__((aligned(2), packed
)) attr_header_t
;
2868 /* Empty Resource Fork Header */
2869 /* This comes by way of xnu's vfs_xattr.c */
2870 typedef struct rsrcfork_header
{
2871 u_int32_t fh_DataOffset
;
2872 u_int32_t fh_MapOffset
;
2873 u_int32_t fh_DataLength
;
2874 u_int32_t fh_MapLength
;
2875 u_int8_t systemData
[112];
2876 u_int8_t appData
[128];
2877 u_int32_t mh_DataOffset
;
2878 u_int32_t mh_MapOffset
;
2879 u_int32_t mh_DataLength
;
2880 u_int32_t mh_MapLength
;
2882 u_int16_t mh_RefNum
;
2884 u_int8_t mh_InMemoryAttr
;
2887 u_int16_t typeCount
;
2888 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
2889 #define RF_FIRST_RESOURCE 256
2890 #define RF_NULL_MAP_LENGTH 30
2891 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2893 static const rsrcfork_header_t empty_rsrcfork_header
= {
2894 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
2895 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
2897 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
2898 { RF_EMPTY_TAG
, }, // systemData
2900 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
2901 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
2903 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
2907 0, // mh_InMemoryAttr
2908 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
2909 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
2910 OSSwapHostToBigInt16(-1), // typeCount
2913 #define SWAP16(x) OSSwapBigToHostInt16(x)
2914 #define SWAP32(x) OSSwapBigToHostInt32(x)
2915 #define SWAP64(x) OSSwapBigToHostInt64(x)
2917 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2919 #define ATTR_ENTRY_LENGTH(namelen) \
2920 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2922 #define ATTR_NEXT(ae) \
2923 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2925 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2928 * Endian swap Apple Double header
2931 swap_adhdr(apple_double_header_t
*adh
)
2933 #if BYTE_ORDER == LITTLE_ENDIAN
2937 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
2939 adh
->magic
= SWAP32 (adh
->magic
);
2940 adh
->version
= SWAP32 (adh
->version
);
2941 adh
->numEntries
= SWAP16 (adh
->numEntries
);
2943 for (i
= 0; i
< count
; i
++)
2945 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
2946 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
2947 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
2955 * Endian swap a single attr_entry_t
2958 swap_attrhdr_entry(attr_entry_t
*ae
)
2960 #if BYTE_ORDER == LITTLE_ENDIAN
2961 ae
->offset
= SWAP32 (ae
->offset
);
2962 ae
->length
= SWAP32 (ae
->length
);
2963 ae
->flags
= SWAP16 (ae
->flags
);
2970 * For a validated/endian swapped attr_header_t*
2971 * ah, endian swap all of the entries.
2974 swap_attrhdr_entries(attr_header_t
*ah
)
2976 #if BYTE_ORDER == LITTLE_ENDIAN
2979 attr_entry_t
*entry
;
2982 /* If we're in copyfile_pack, num_args is native endian,
2983 * if we're in _unpack, num_args is big endian. Use
2984 * the magic number to test for endianess.
2986 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
2988 entry
= (attr_entry_t
*)(&ah
[1]);
2989 for (i
= 0; i
< count
; i
++) {
2990 next
= ATTR_NEXT(entry
);
2991 swap_attrhdr_entry(entry
);
3000 * Endian swap extended attributes header
3003 swap_attrhdr(attr_header_t
*ah
)
3005 #if BYTE_ORDER == LITTLE_ENDIAN
3006 ah
->magic
= SWAP32 (ah
->magic
);
3007 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
3008 ah
->total_size
= SWAP32 (ah
->total_size
);
3009 ah
->data_start
= SWAP32 (ah
->data_start
);
3010 ah
->data_length
= SWAP32 (ah
->data_length
);
3011 ah
->flags
= SWAP16 (ah
->flags
);
3012 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
3018 static const u_int32_t emptyfinfo
[8] = {0};
3021 * Given an Apple Double file in src, turn it into a
3022 * normal file (possibly with multiple forks, EAs, and
3025 static int copyfile_unpack(copyfile_state_t s
)
3028 void * buffer
, * endptr
, * dataptr
= NULL
;
3029 apple_double_header_t
*adhdr
;
3033 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
3034 hdrsize
= (ssize_t
)s
->sb
.st_size
;
3036 hdrsize
= ATTR_MAX_HDR_SIZE
;
3038 buffer
= calloc(1, hdrsize
);
3039 if (buffer
== NULL
) {
3040 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize
);
3044 endptr
= (char*)buffer
+ hdrsize
;
3046 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
3050 copyfile_debug(1, "pread returned: %zd", bytes
);
3054 if (bytes
< hdrsize
)
3057 "pread couldn't read entire header: %d of %d",
3058 (int)bytes
, (int)s
->sb
.st_size
);
3062 adhdr
= (apple_double_header_t
*)buffer
;
3065 * Check for Apple Double file.
3067 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
3068 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
3069 SWAP32(adhdr
->version
) != ADH_VERSION
||
3070 SWAP16(adhdr
->numEntries
) != 2 ||
3071 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
3073 if (COPYFILE_VERBOSE
& s
->flags
)
3074 copyfile_warn("Not a valid Apple Double header");
3081 * Remove any extended attributes on the target.
3084 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
3086 char *namebuf
, *name
;
3088 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
3093 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
3096 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
3097 (void)fremovexattr(s
->dst_fd
, name
, 0);
3103 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
3108 * Extract the extended attributes.
3111 * This assumes that the data is already in memory (not
3112 * the case when there are lots of attributes or one of
3113 * the attributes is very large.
3115 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
3117 attr_header_t
*attrhdr
;
3118 attr_entry_t
*entry
;
3122 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
3123 copyfile_warn("bad attribute header: %zu < %zu", hdrsize
, sizeof(attr_header_t
));
3128 attrhdr
= (attr_header_t
*)buffer
;
3129 swap_attrhdr(attrhdr
);
3130 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
3132 if (COPYFILE_VERBOSE
& s
->flags
)
3133 copyfile_warn("bad attribute header");
3137 count
= attrhdr
->num_attrs
;
3138 entry
= (attr_entry_t
*)&attrhdr
[1];
3140 for (i
= 0; i
< count
; i
++)
3143 * First we do some simple sanity checking.
3144 * +) See if entry is within the buffer's range;
3146 * +) Check the attribute name length; if it's longer than the
3147 * maximum, we truncate it down. (We could error out as well;
3148 * I'm not sure which is the better way to go here.)
3150 * +) If, given the name length, it goes beyond the end of
3151 * the buffer, error out.
3153 * +) If the last byte isn't a NUL, make it a NUL. (Since we
3154 * truncated the name length above, we truncate the name here.)
3156 * +) If entry->offset is so large that it causes dataptr to
3157 * go beyond the end of the buffer -- or, worse, so large that
3158 * it wraps around! -- we error out.
3160 * +) If entry->length would cause the entry to go beyond the
3161 * end of the buffer (or, worse, wrap around to before it),
3162 * *or* if the length is larger than the hdrsize, we error out.
3163 * (An explanation of that: what we're checking for there is
3164 * the small range of values such that offset+length would cause
3165 * it to go beyond endptr, and then wrap around past buffer. We
3166 * care about this because we are passing entry->length down to
3167 * fgetxattr() below, and an erroneously large value could cause
3168 * problems there. By making sure that it's less than hdrsize,
3169 * which has already been sanity-checked above, we're safe.
3170 * That may mean that the check against < buffer is unnecessary.)
3172 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
3173 if (COPYFILE_VERBOSE
& s
->flags
)
3174 copyfile_warn("Incomplete or corrupt attribute entry");
3180 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
3181 if (COPYFILE_VERBOSE
& s
->flags
)
3182 copyfile_warn("Incomplete or corrupt attribute entry");
3189 * Endian swap the entry we're looking at. Previously
3190 * we did this swap as part of swap_attrhdr, but that
3191 * allowed a maliciously constructed file to overrun
3192 * our allocation. Instead do the swap after we've verified
3193 * the entry struct is within the buffer's range.
3195 swap_attrhdr_entry(entry
);
3197 if (entry
->namelen
< 2) {
3198 if (COPYFILE_VERBOSE
& s
->flags
)
3199 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
3205 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
3206 if (COPYFILE_VERBOSE
& s
->flags
)
3207 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
3213 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
3214 if (COPYFILE_VERBOSE
& s
->flags
)
3215 copyfile_warn("Incomplete or corrupt attribute entry");
3221 /* Because namelen includes the NUL, we check one byte back */
3222 if (entry
->name
[entry
->namelen
-1] != 0) {
3223 if (COPYFILE_VERBOSE
& s
->flags
)
3224 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3230 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3231 entry
->name
, entry
->length
, entry
->offset
);
3234 dataptr
= (char *)attrhdr
+ entry
->offset
;
3236 if (dataptr
> endptr
|| dataptr
< buffer
) {
3237 copyfile_debug(1, "Entry %d overflows: offset = %u", i
, entry
->offset
);
3239 s
->err
= EINVAL
; /* Invalid buffer */
3243 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
3244 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
3245 (entry
->length
> (size_t)hdrsize
)) {
3246 if (COPYFILE_VERBOSE
& s
->flags
)
3247 copyfile_warn("Incomplete or corrupt attribute entry");
3248 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3249 i
, entry
->offset
, entry
->length
);
3251 s
->err
= EINVAL
; /* Invalid buffer */
3256 dataptr
= malloc(entry
->length
);
3257 if (dataptr
== NULL
) {
3258 copyfile_debug(1, "no memory for %u bytes\n", entry
->length
);
3263 if (pread(s
->src_fd
, dataptr
, entry
->length
, entry
->offset
) != (ssize_t
)entry
->length
) {
3264 copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry
->length
, entry
->offset
);
3271 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
3273 qtn_file_t tqinfo
= NULL
;
3275 if (s
->qinfo
== NULL
)
3277 tqinfo
= qtn_file_alloc();
3281 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
3283 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
3284 qtn_file_free(tqinfo
);
3296 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
3298 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
3301 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
3302 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3303 s
->xattr_name
= NULL
;
3304 if (rv
== COPYFILE_QUIT
) {
3305 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3309 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3314 if (tqinfo
&& !s
->qinfo
)
3316 qtn_file_free(tqinfo
);
3319 /* Look for ACL data */
3320 else if (strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
3325 char *tcp
= dataptr
;
3327 if (entry
->length
== 0) {
3328 /* Not sure how we got here, but we had one case
3329 * where it was 0. In a normal EA, we can have a 0-byte
3330 * payload. That means nothing in this case, so we'll
3331 * simply skip the EA.
3337 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3338 * however, may not be NUL-terminated. So in that case, we need to
3339 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3341 if (tcp
[entry
->length
- 1] != 0) {
3342 char *tmpstr
= malloc(entry
->length
+ 1);
3343 if (tmpstr
== NULL
) {
3347 strlcpy(tmpstr
, tcp
, entry
->length
+ 1);
3348 acl
= acl_from_text(tmpstr
);
3351 acl
= acl_from_text(tcp
);
3358 if ((fsec_tmp
= filesec_init()) == NULL
)
3360 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
3362 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
3365 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
3367 if (errno
== ENOTSUP
)
3369 if (retry
&& !copyfile_unset_acl(s
))
3375 copyfile_warn("setting security information");
3381 filesec_free(fsec_tmp
);
3388 /* And, finally, everything else */
3391 if (s
->copyIntent
||
3392 xattr_preserve_for_intent((char*)entry
->name
, s
->copyIntent
) == 1) {
3395 s
->xattr_name
= strdup((char*)entry
->name
);
3397 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3398 if (s
->xattr_name
) {
3399 free(s
->xattr_name
);
3400 s
->xattr_name
= NULL
;
3402 if (rv
== COPYFILE_QUIT
) {
3408 if (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0) == -1) {
3409 if (COPYFILE_VERBOSE
& s
->flags
)
3410 copyfile_warn("error %d setting attribute %s", errno
, entry
->name
);
3414 s
->xattr_name
= strdup((char*)entry
->name
);
3415 rv
= (s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3416 if (s
->xattr_name
) {
3417 free(s
->xattr_name
);
3418 s
->xattr_name
= NULL
;
3420 if (rv
== COPYFILE_QUIT
) {
3428 } else if (s
->statuscb
) {
3430 s
->xattr_name
= strdup((char*)entry
->name
);
3431 s
->totalCopied
= entry
->length
;
3432 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3433 if (s
->xattr_name
) {
3434 free(s
->xattr_name
);
3435 s
->xattr_name
= NULL
;
3437 if (rv
== COPYFILE_QUIT
) {
3449 entry
= ATTR_NEXT(entry
);
3454 * Extract the Finder Info.
3456 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
3461 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
3465 enum { kFinderInvisibleMask
= 1 << 14 };
3467 newFinfo
= (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
;
3468 fFlags
= (uint16_t*)&newFinfo
[8];
3469 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
3472 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3473 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3474 s
->xattr_name
= NULL
;
3475 if (rv
== COPYFILE_QUIT
) {
3479 } else if (rv
== COPYFILE_SKIP
) {
3483 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
3487 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3488 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3489 s
->xattr_name
= NULL
;
3490 if (rv
== COPYFILE_QUIT
) {
3497 } else if (s
->statuscb
) {
3499 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3500 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3501 s
->xattr_name
= NULL
;
3502 if (rv
== COPYFILE_QUIT
) {
3508 if (SWAP16(*fFlags
) & kFinderInvisibleMask
)
3509 s
->internal_flags
|= cfMakeFileInvisible
;
3514 * Extract the Resource Fork.
3516 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
3517 adhdr
->entries
[1].length
> 0)
3519 void * rsrcforkdata
= NULL
;
3523 struct timeval tval
[2];
3525 length
= adhdr
->entries
[1].length
;
3526 offset
= adhdr
->entries
[1].offset
;
3527 rsrcforkdata
= malloc(length
);
3529 if (rsrcforkdata
== NULL
) {
3530 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3536 if (fstat(s
->dst_fd
, &sb
) < 0)
3538 copyfile_debug(1, "couldn't stat destination file");
3543 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
3544 if (bytes
< (ssize_t
)length
)
3548 copyfile_debug(1, "couldn't read resource fork");
3553 "couldn't read resource fork (only read %d bytes of %d)",
3554 (int)bytes
, (int)length
);
3561 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3562 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3563 s
->xattr_name
= NULL
;
3564 if (rv
== COPYFILE_QUIT
) {
3570 } else if (rv
== COPYFILE_SKIP
) {
3574 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
3578 * For filesystems that do not natively support named attributes,
3579 * the kernel creates an AppleDouble file that -- for compatabilty
3580 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3581 * structure that says there are no resources. So, if fsetxattr has
3582 * failed, and the resource fork is that empty structure, *and* the
3583 * target file is a directory, then we do nothing with it.
3585 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
3586 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
3587 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
3588 copyfile_debug(2, "not setting empty resource fork on directory");
3594 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3595 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3596 s
->xattr_name
= NULL
;
3597 if (rv
== COPYFILE_CONTINUE
) {
3602 copyfile_debug(1, "error %d setting resource fork attribute", error
);
3605 } else if (s
->statuscb
) {
3607 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3608 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3609 s
->xattr_name
= NULL
;
3610 if (rv
== COPYFILE_QUIT
) {
3618 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3619 XATTR_RESOURCEFORK_NAME
, (int)length
);
3621 if (!(s
->flags
& COPYFILE_STAT
))
3623 tval
[0].tv_sec
= sb
.st_atime
;
3624 tval
[1].tv_sec
= sb
.st_mtime
;
3625 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
3627 if (futimes(s
->dst_fd
, tval
))
3628 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
3635 if (COPYFILE_STAT
& s
->flags
)
3637 error
= copyfile_stat(s
);
3640 if (buffer
) free(buffer
);
3641 if (dataptr
) free(dataptr
);
3645 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3648 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
3649 size_t qlen
= sizeof(qbuf
);
3651 if (s
->qinfo
== NULL
)
3657 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
3663 *buf
= malloc(qlen
);
3666 memcpy(*buf
, qbuf
, qlen
);
3673 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3679 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
3681 if (errno
!= ENOENT
)
3684 if (COPYFILE_VERBOSE
& s
->flags
)
3685 copyfile_warn("getting acl");
3691 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
3694 * acl_to_text() doesn't include the NUL at the endo
3695 * in it's count (*len). It does, however, promise to
3696 * return a valid C string, so we need to up the count
3700 *buf
= malloc(*len
);
3702 memcpy(*buf
, acl_text
, *len
);
3707 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
3714 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
3717 char *databuf
= NULL
;
3722 * do COPYFILE_COPY_XATTR here; no need to
3723 * the work if we want to skip.
3730 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3732 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3733 s
->xattr_name
= NULL
;
3734 if (rv
== COPYFILE_SKIP
) {
3738 if (rv
== COPYFILE_QUIT
) {
3744 /* Get the resource fork size */
3745 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
3747 if (COPYFILE_VERBOSE
& s
->flags
)
3748 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
3752 if (datasize
> INT_MAX
) {
3760 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3763 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3764 s
->xattr_name
= NULL
;
3765 if (rv
== COPYFILE_QUIT
) {
3771 if ((databuf
= malloc(datasize
)) == NULL
)
3773 copyfile_warn("malloc");
3778 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
3780 if (COPYFILE_VERBOSE
& s
->flags
)
3781 copyfile_warn("couldn't read entire resource fork");
3786 /* Write the resource fork to disk. */
3787 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
3789 if (COPYFILE_VERBOSE
& s
->flags
)
3790 copyfile_warn("couldn't write resource fork");
3795 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3796 if (rv
== COPYFILE_QUIT
) {
3801 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3802 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
3803 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
3806 if (ret
== -1 && s
->statuscb
)
3809 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3810 if (rv
== COPYFILE_CONTINUE
)
3813 if (s
->xattr_name
) {
3814 s
->xattr_name
= NULL
;
3821 * Do status callback here
3822 * If ret == -1, then error callback
3828 * The opposite of copyfile_unpack(), obviously.
3830 static int copyfile_pack(copyfile_state_t s
)
3832 char *attrnamebuf
= NULL
, *endnamebuf
;
3833 void *databuf
= NULL
;
3834 attr_header_t
*filehdr
, *endfilehdr
;
3835 attr_entry_t
*entry
;
3836 ssize_t listsize
= 0;
3842 int hasrsrcfork
= 0;
3844 int seenq
= 0; // Have we seen any quarantine info already?
3846 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_HDR_SIZE
);
3848 if (filehdr
== NULL
) {
3852 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_HDR_SIZE
);
3855 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
3856 if (attrnamebuf
== NULL
) {
3860 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
3864 * Fill in the Apple Double Header defaults.
3866 filehdr
->appledouble
.magic
= ADH_MAGIC
;
3867 filehdr
->appledouble
.version
= ADH_VERSION
;
3868 filehdr
->appledouble
.numEntries
= 2;
3869 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
3870 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
3871 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
3872 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
3873 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
3874 filehdr
->appledouble
.entries
[1].length
= 0;
3875 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
3878 * Fill in the initial Attribute Header.
3880 filehdr
->magic
= ATTR_HDR_MAGIC
;
3881 filehdr
->debug_tag
= 0;
3882 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
3885 * Collect the attribute names.
3887 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3890 * Test if there are acls to copy
3892 if (COPYFILE_ACL
& s
->flags
)
3894 acl_t temp_acl
= NULL
;
3895 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
3897 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
3900 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
3901 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
3902 endnamebuf
= attrnamebuf
+ offset
;
3908 if (COPYFILE_XATTR
& s
->flags
)
3910 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3911 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
3913 copyfile_debug(2, "no extended attributes found (%d)", errno
);
3915 if (listsize
> left
)
3917 copyfile_debug(1, "extended attribute list too long");
3921 endnamebuf
= attrnamebuf
+ offset
+ (listsize
> 0 ? listsize
: 0);
3922 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
3928 sort_xattrname_list(attrnamebuf
, endnamebuf
- attrnamebuf
);
3930 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
3932 namelen
= strlen(nameptr
) + 1;
3933 /* Skip over FinderInfo or Resource Fork names */
3934 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
3935 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
3938 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
3942 /* The system should prevent this from happening, but... */
3943 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
3944 namelen
= XATTR_MAXNAMELEN
+ 1;
3946 if (s
->copyIntent
&&
3947 xattr_preserve_for_intent(nameptr
, s
->copyIntent
) == 0) {
3949 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
3950 memmove(nameptr
, nameptr
+ namelen
, amt
);
3951 endnamebuf
-= namelen
;
3952 /* Set namelen to 0 so continue doesn't miss names */
3959 char eaname
[namelen
];
3960 bcopy(nameptr
, eaname
, namelen
);
3961 eaname
[namelen
- 1] = 0; // Just to be sure!
3962 s
->xattr_name
= eaname
;
3963 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3964 s
->xattr_name
= NULL
;
3965 if (rv
== COPYFILE_QUIT
) {
3969 } else if (rv
== COPYFILE_SKIP
) {
3970 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
3971 memmove(nameptr
, nameptr
+ namelen
, amt
);
3972 endnamebuf
-= namelen
;
3973 /* Set namelen to 0 so continue doesn't miss names */
3978 entry
->namelen
= namelen
;
3980 if (nameptr
+ namelen
> endnamebuf
) {
3985 bcopy(nameptr
, &entry
->name
[0], namelen
);
3986 copyfile_debug(2, "copied name [%s]", entry
->name
);
3988 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
3989 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
3991 if ((void*)entry
>= (void*)endfilehdr
) {
3996 /* Update the attributes header. */
3997 filehdr
->num_attrs
++;
3998 filehdr
->data_start
+= (u_int32_t
)entrylen
;
4003 * If we have any quarantine data, we always pack it.
4004 * But if we've already got it in the EA list, don't put it in again.
4006 if (s
->qinfo
&& !seenq
)
4008 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
4009 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
4010 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
4015 * Collect the attribute data.
4017 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
4019 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
+ 1)
4021 namelen
= strlen(nameptr
);
4023 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
4024 copyfile_pack_acl(s
, &databuf
, &datasize
);
4025 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
4027 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
4029 /* Check for Finder Info. */
4030 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
4035 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
4036 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
4037 s
->xattr_name
= NULL
;
4038 if (rv
== COPYFILE_QUIT
)
4040 s
->xattr_name
= NULL
;
4045 else if (rv
== COPYFILE_SKIP
)
4047 s
->xattr_name
= NULL
;
4051 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4052 s
->xattr_name
= NULL
;
4053 if (rv
== COPYFILE_QUIT
)
4060 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
4065 s
->xattr_name
= strdup(nameptr
);
4066 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4067 if (s
->xattr_name
) {
4068 free(s
->xattr_name
);
4069 s
->xattr_name
= NULL
;
4071 if (rv
== COPYFILE_QUIT
) {
4076 if (COPYFILE_VERBOSE
& s
->flags
)
4077 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4078 } else if (datasize
!= 32)
4080 if (COPYFILE_VERBOSE
& s
->flags
)
4081 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
4084 if (COPYFILE_VERBOSE
& s
->flags
)
4085 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
4086 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
4089 s
->xattr_name
= strdup(nameptr
);
4090 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4091 if (s
->xattr_name
) {
4092 free(s
->xattr_name
);
4093 s
->xattr_name
= NULL
;
4095 if (rv
== COPYFILE_QUIT
) {
4101 continue; /* finder info doesn't have an attribute entry */
4103 /* Check for Resource Fork. */
4104 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
4110 /* Just a normal attribute. */
4114 s
->xattr_name
= strdup(nameptr
);
4116 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
4117 if (s
->xattr_name
) {
4118 free(s
->xattr_name
);
4119 s
->xattr_name
= NULL
;
4122 * Due to the nature of the packed file, we can't skip at this point.
4124 if (rv
== COPYFILE_QUIT
)
4131 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
4136 if (COPYFILE_VERBOSE
& s
->flags
)
4137 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
4141 s
->xattr_name
= strdup(nameptr
);
4142 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
4143 if (s
->xattr_name
) {
4144 free(s
->xattr_name
);
4145 s
->xattr_name
= NULL
;
4147 if (rv
== COPYFILE_QUIT
)
4156 if (datasize
> XATTR_MAXATTRLEN
)
4158 if (COPYFILE_VERBOSE
& s
->flags
)
4159 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
4162 databuf
= malloc(datasize
);
4163 if (databuf
== NULL
) {
4167 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
4170 s
->xattr_name
= strdup(nameptr
);
4171 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
4172 if (s
->xattr_name
) {
4173 free(s
->xattr_name
);
4174 s
->xattr_name
= NULL
;
4176 if (rv
== COPYFILE_QUIT
) {
4184 entry
->length
= (u_int32_t
)datasize
;
4185 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
4187 filehdr
->data_length
+= (u_int32_t
)datasize
;
4191 * This assumes that the data is fits in memory (not
4192 * the case when there are lots of attributes or one of
4193 * the attributes is very large.
4195 if (entry
->offset
> ATTR_MAX_SIZE
||
4196 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
4199 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
4202 if (pwrite(s
->dst_fd
, databuf
, datasize
, entry
->offset
) != datasize
) {
4208 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
4210 /* bump to next entry */
4211 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
4212 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
4215 /* Now we know where the resource fork data starts. */
4216 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
4218 /* We also know the size of the "Finder Info entry. */
4219 filehdr
->appledouble
.entries
[0].length
=
4220 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
4222 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
4224 /* Copy Resource Fork. */
4225 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
4228 /* Write the header to disk. */
4229 datasize
= filehdr
->data_start
;
4231 swap_adhdr(&filehdr
->appledouble
);
4232 swap_attrhdr(filehdr
);
4233 swap_attrhdr_entries(filehdr
);
4235 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
4237 if (COPYFILE_VERBOSE
& s
->flags
)
4238 copyfile_warn("couldn't write file header");
4243 if (filehdr
) free(filehdr
);
4244 if (attrnamebuf
) free(attrnamebuf
);
4249 return copyfile_stat(s
);