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 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
50 # include <Kernel/sys/decmpfs.h>
53 #include <TargetConditionals.h>
55 #include <quarantine.h>
57 #define XATTR_QUARANTINE_NAME qtn_xattr_name
58 #else /* TARGET_OS_IPHONE */
59 #define qtn_file_t void *
60 #define QTN_SERIALIZED_DATA_MAX 0
61 static void * qtn_file_alloc(void) { return NULL
; }
62 static int qtn_file_init_with_fd(void *x
, int y
) { return -1; }
63 static int qtn_file_init_with_path(void *x
, const char *path
) { return -1; }
64 static int qtn_file_init_with_data(void *x
, const void *data
, size_t len
) { return -1; }
65 static void qtn_file_free(void *x
) { return; }
66 static int qtn_file_apply_to_fd(void *x
, int y
) { return 0; }
67 static char *qtn_error(int x
) { return NULL
; }
68 static int qtn_file_to_data(void *x
, char *y
, size_t z
) { return -1; }
69 static void *qtn_file_clone(void *x
) { return NULL
; }
70 #define XATTR_QUARANTINE_NAME "figgledidiggledy"
71 #endif /* TARGET_OS_IPHONE */
74 #include "copyfile_private.h"
75 #include "xattr_properties.h"
77 enum cfInternalFlags
{
79 cfMakeFileInvisible
= 1 << 1,
80 cfSawDecmpEA
= 1 << 2,
84 * The state structure keeps track of
85 * the source filename, the destination filename, their
86 * associated file-descriptors, the stat infomration for the
87 * source file, the security information for the source file,
88 * the flags passed in for the copy, a pointer to place statistics
89 * (not currently implemented), debug flags, and a pointer to callbacks
90 * (not currently implemented).
92 struct _copyfile_state
100 copyfile_flags_t flags
;
101 unsigned int internal_flags
;
104 copyfile_callback_t statuscb
;
106 qtn_file_t qinfo
; /* Quarantine information -- probably NULL */
107 filesec_t original_fsec
;
108 filesec_t permissive_fsec
;
112 CopyOperationIntent_t copyIntent
;
117 #define _ACL_ENTRY_MAGIC 0xac1ac101
119 guid_t ae_applicable
;
124 #define PACE(ace) do { \
125 struct acl_entry *__t = (struct acl_entry*)(ace); \
126 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
131 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
132 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
136 acl_compare_permset_np(acl_permset_t p1
, acl_permset_t p2
)
138 struct pm
{ u_int32_t ap_perms
; } *ps1
, *ps2
;
139 ps1
= (struct pm
*) p1
;
140 ps2
= (struct pm
*) p2
;
142 return ((ps1
->ap_perms
== ps2
->ap_perms
) ? 1 : 0);
147 doesdecmpfs(int fd
) {
148 #ifdef DECMPFS_XATTR_NAME
150 struct attrlist attrs
;
151 char volroot
[MAXPATHLEN
+ 1];
155 vol_capabilities_attr_t volAttrs
;
158 (void)fstatfs(fd
, &sfs
);
159 strlcpy(volroot
, sfs
.f_mntonname
, sizeof(volroot
));
161 memset(&attrs
, 0, sizeof(attrs
));
162 attrs
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
163 attrs
.volattr
= ATTR_VOL_CAPABILITIES
;
165 rv
= getattrlist(volroot
, &attrs
, &volattrs
, sizeof(volattrs
), 0);
168 (volattrs
.volAttrs
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
) &&
169 (volattrs
.volAttrs
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
)) {
178 sort_xattrname_list(void *start
, size_t length
)
185 /* If it's not a proper C string at the end, don't do anything */
186 if (((char*)start
)[length
] != 0)
189 * In order to sort the list of names, we need to
190 * make a list of pointers to strings. To do that,
191 * we need to run through the buffer, and find the
192 * beginnings of strings.
194 nel
= 10; // Most files don't have many EAs
195 ptrs
= (char**)calloc(nel
, sizeof(char*));
202 char *curPtr
= start
;
203 while (curPtr
< (char*)start
+ length
) {
204 printf("%s\n", curPtr
);
205 curPtr
+= strlen(curPtr
) + 1;
210 tmp
= ptrs
[indx
++] = (char*)start
;
212 while (tmp
= memchr(tmp
, 0, ((char*)start
+ length
) - tmp
)) {
215 ptrs
= realloc(ptrs
, sizeof(char**) * nel
);
219 ptrs
[indx
++] = ++tmp
;
222 printf("Unsorted:\n");
223 for (nel
= 0; nel
< indx
-1; nel
++) {
224 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
227 qsort_b(ptrs
, indx
-1, sizeof(char*), ^(const void *left
, const void *right
) {
229 char *lstr
= *(char**)left
, *rstr
= *(char**)right
;
230 rv
= strcmp(lstr
, rstr
);
235 for (nel
= 0; nel
< indx
-1; nel
++) {
236 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
240 * Now that it's sorted, we need to make a copy, so we can
241 * move the strings around into the new order. Then we
242 * copy that on top of the old buffer, and we're done.
244 char *copy
= malloc(length
);
249 for (i
= 0; i
< indx
-1; i
++) {
250 size_t len
= strlen(ptrs
[i
]);
251 memcpy(curPtr
, ptrs
[i
], len
+1);
254 memcpy(start
, copy
, length
);
265 * Internally, the process is broken into a series of
268 static int copyfile_open (copyfile_state_t
);
269 static int copyfile_close (copyfile_state_t
);
270 static int copyfile_data (copyfile_state_t
);
271 static int copyfile_stat (copyfile_state_t
);
272 static int copyfile_security (copyfile_state_t
);
273 static int copyfile_xattr (copyfile_state_t
);
274 static int copyfile_pack (copyfile_state_t
);
275 static int copyfile_unpack (copyfile_state_t
);
277 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
278 static filesec_t
copyfile_fix_perms(copyfile_state_t
, filesec_t
*);
279 static int copyfile_preamble(copyfile_state_t
*s
, copyfile_flags_t flags
);
280 static int copyfile_internal(copyfile_state_t state
, copyfile_flags_t flags
);
281 static int copyfile_unset_posix_fsec(filesec_t
);
282 static int copyfile_quarantine(copyfile_state_t
);
284 #define COPYFILE_DEBUG (1<<31)
285 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
287 #ifndef _COPYFILE_TEST
288 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
289 # define copyfile_debug(d, str, ...) \
291 if (s && (d <= s->debug)) {\
292 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
296 #define copyfile_warn(str, ...) \
297 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
298 # define copyfile_debug(d, str, ...) \
300 if (s && (d <= s->debug)) {\
301 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
306 static int copyfile_quarantine(copyfile_state_t s
)
309 if (s
->qinfo
== NULL
)
312 s
->qinfo
= qtn_file_alloc();
313 if (s
->qinfo
== NULL
)
318 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
320 qtn_file_free(s
->qinfo
);
331 add_uberace(acl_t
*acl
)
334 acl_permset_t permset
;
337 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
341 * First, we create an entry, and give it the special name
342 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
343 * After that, we clear out all the permissions in it, and
344 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
345 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
346 * the functionality, and put this into the ACL.
348 if (acl_create_entry_np(acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
350 if (acl_get_permset(entry
, &permset
) == -1) {
351 copyfile_warn("acl_get_permset");
354 if (acl_clear_perms(permset
) == -1) {
355 copyfile_warn("acl_clear_permset");
358 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1) {
359 copyfile_warn("add ACL_WRITE_DATA");
362 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1) {
363 copyfile_warn("add ACL_WRITE_ATTRIBUTES");
366 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1) {
367 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES");
370 if (acl_add_perm(permset
, ACL_APPEND_DATA
) == -1) {
371 copyfile_warn("add ACL_APPEND_DATA");
374 if (acl_add_perm(permset
, ACL_WRITE_SECURITY
) == -1) {
375 copyfile_warn("add ACL_WRITE_SECURITY");
378 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1) {
379 copyfile_warn("set ACL_EXTENDED_ALLOW");
383 if(acl_set_permset(entry
, permset
) == -1) {
384 copyfile_warn("acl_set_permset");
387 if(acl_set_qualifier(entry
, qual
) == -1) {
388 copyfile_warn("acl_set_qualifier");
398 is_uberace(acl_entry_t ace
)
401 acl_permset_t perms
, tperms
;
408 // Who am I, and who is the ACE for?
409 mbr_uid_to_uuid(geteuid(), myuuid
);
410 qual
= (guid_t
*)acl_get_qualifier(ace
);
412 // Need to create a temporary acl, so I can get the uberace template.
418 if (acl_get_entry(tacl
, ACL_FIRST_ENTRY
, &tentry
) != 0) {
421 acl_get_permset(tentry
, &tperms
);
424 acl_get_tag_type(ace
, &tag
);
425 acl_get_permset(ace
, &perms
);
427 if (tag
== ACL_EXTENDED_ALLOW
&&
428 (memcmp(qual
, myuuid
, sizeof(myuuid
)) == 0) &&
429 acl_compare_permset_np(tperms
, perms
))
444 remove_uberace(int fd
, struct stat
*sbuf
)
446 filesec_t fsec
= NULL
;
451 fsec
= filesec_init();
456 if (fstatx_np(fd
, &sb
, fsec
) != 0) {
457 if (errno
== ENOTSUP
)
462 if (filesec_get_property(fsec
, FILESEC_ACL
, &acl
) != 0) {
466 if (acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
) == 0) {
467 if (is_uberace(entry
))
469 mode_t m
= sbuf
->st_mode
& ~S_IFMT
;
471 if (acl_delete_entry(acl
, entry
) != 0 ||
472 filesec_set_property(fsec
, FILESEC_ACL
, &acl
) != 0 ||
473 filesec_set_property(fsec
, FILESEC_MODE
, &m
) != 0 ||
474 fchmodx_np(fd
, fsec
) != 0)
487 fchmod(fd
, sbuf
->st_mode
& ~S_IFMT
);
492 reset_security(copyfile_state_t s
)
494 /* If we haven't reset the file security information
495 * (COPYFILE_SECURITY is not set in flags)
496 * restore back the permissions the file had originally
498 * One of the reasons this seems so complicated is that
499 * it is partially at odds with copyfile_security().
501 * Simplisticly, we are simply trying to make sure we
502 * only copy what was requested, and that we don't stomp
503 * on what wasn't requested.
506 #ifdef COPYFILE_RECURSIVE
507 if (s
->dst_fd
> -1) {
510 if (s
->src_fd
> -1 && (s
->flags
& COPYFILE_STAT
))
511 fstat(s
->src_fd
, &sbuf
);
513 fstat(s
->dst_fd
, &sbuf
);
515 if (!(s
->internal_flags
& cfDelayAce
))
516 remove_uberace(s
->dst_fd
, &sbuf
);
519 if (s
->permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
520 if (s
->flags
& COPYFILE_ACL
) {
521 /* Just need to reset the BSD information -- mode, owner, group */
522 (void)fchown(s
->dst_fd
, s
->dst_sb
.st_uid
, s
->dst_sb
.st_gid
);
523 (void)fchmod(s
->dst_fd
, s
->dst_sb
.st_mode
);
526 * flags is either COPYFILE_STAT, or neither; if it's
527 * neither, then we restore both ACL and POSIX permissions;
528 * if it's STAT, however, then we only want to restore the
529 * ACL (which may be empty). We do that by removing the
530 * POSIX information from the filesec object.
532 if (s
->flags
& COPYFILE_STAT
) {
533 copyfile_unset_posix_fsec(s
->original_fsec
);
535 if (fchmodx_np(s
->dst_fd
, s
->original_fsec
) < 0 && errno
!= ENOTSUP
)
536 copyfile_warn("restoring security information");
540 if (s
->permissive_fsec
) {
541 filesec_free(s
->permissive_fsec
);
542 s
->permissive_fsec
= NULL
;
545 if (s
->original_fsec
) {
546 filesec_free(s
->original_fsec
);
547 s
->original_fsec
= NULL
;
555 * copytree -- recursively copy a hierarchy.
557 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
558 * Care is taken to keep the ACLs set up correctly, in addition to the
559 * normal copying that is done. (When copying a hierarchy, we can't
560 * get rid of the "allow-all-writes" ACE on a directory until we're done
561 * copying the *contents* of the directory.)
563 * The other big difference from copyfile (for the moment) is that copytree()
564 * will use a call-back function to pass along information about what is
565 * about to be copied, and whether or not it succeeded.
567 * copytree() is called from copyfile() -- but copytree() itself then calls
568 * copyfile() to copy each individual object.
570 * XXX - no effort is made to handle overlapping hierarchies at the moment.
575 copytree(copyfile_state_t s
)
579 int (*sfunc
)(const char *, struct stat
*);
580 copyfile_callback_t status
= NULL
;
581 char srcisdir
= 0, dstisdir
= 0, dstexists
= 0;
584 const char *dstpathsep
= "";
586 char srcpath
[PATH_MAX
* 2 + 1], dstpath
[PATH_MAX
* 2 + 1];
592 const char *paths
[2] = { 0 };
593 unsigned int flags
= 0;
594 int fts_flags
= FTS_NOCHDIR
;
601 if (s
->flags
& (COPYFILE_MOVE
| COPYFILE_UNLINK
| COPYFILE_CHECK
| COPYFILE_PACK
| COPYFILE_UNPACK
)) {
607 flags
= s
->flags
& (COPYFILE_ALL
| COPYFILE_NOFOLLOW
| COPYFILE_VERBOSE
);
609 paths
[0] = src
= s
->src
;
612 if (src
== NULL
|| dst
== NULL
) {
618 sfunc
= (flags
& COPYFILE_NOFOLLOW_SRC
) ? lstat
: stat
;
619 if ((sfunc
)(src
, &sbuf
) == -1) {
623 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
627 sfunc
= (flags
& COPYFILE_NOFOLLOW_DST
) ? lstat
: stat
;
628 if ((sfunc
)(dst
, &sbuf
) == -1) {
629 if (errno
!= ENOENT
) {
635 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
641 // This doesn't handle filesystem crossing and case sensitivity
642 // So there's got to be a better way
644 if (realpath(src
, srcpath
) == NULL
) {
649 if (realpath(dst
, dstpath
) == NULL
&&
650 (errno
== ENOENT
&& realpath(dirname(dst
), dstpath
) == NULL
)) {
654 if (strstr(srcpath
, dstpath
) != NULL
) {
660 srcroot
= basename((char*)src
);
661 if (srcroot
== NULL
) {
667 * To work on as well:
668 * We have a few cases when copying a hierarchy:
669 * 1) src is a non-directory, dst is a directory;
670 * 2) src is a non-directory, dst is a non-directory;
671 * 3) src is a non-directory, dst does not exist;
672 * 4) src is a directory, dst is a directory;
673 * 5) src is a directory, dst is a non-directory;
674 * 6) src is a directory, dst does not exist
676 * (1) copies src to dst/basename(src).
677 * (2) fails if COPYFILE_EXCLUSIVE is set, otherwise copies src to dst.
678 * (3) and (6) copy src to the name dst.
679 * (4) copies the contents of src to the contents of dst.
684 // copy /path/to/src to /path/to/dst/src
685 // Append "/" and (fts_path - strlen(basename(src))) to dst?
687 slash
= strrchr(src
, '/');
691 offset
= slash
- src
+ 1;
693 // copy /path/to/src to /path/to/dst
694 // append (fts_path + strlen(src)) to dst?
696 offset
= strlen(src
);
699 if (s
->flags
| COPYFILE_NOFOLLOW_SRC
)
700 fts_flags
|= FTS_PHYSICAL
;
702 fts_flags
|= FTS_LOGICAL
;
704 fts
= fts_open((char * const *)paths
, fts_flags
, NULL
);
706 status
= s
->statuscb
;
707 while ((ftsent
= fts_read(fts
)) != NULL
) {
709 char *dstfile
= NULL
;
711 copyfile_state_t tstate
= copyfile_state_alloc();
712 if (tstate
== NULL
) {
717 tstate
->statuscb
= s
->statuscb
;
718 tstate
->ctx
= s
->ctx
;
719 asprintf(&dstfile
, "%s%s%s", dst
, dstpathsep
, ftsent
->fts_path
+ offset
);
720 if (dstfile
== NULL
) {
721 copyfile_state_free(tstate
);
726 switch (ftsent
->fts_info
) {
728 tstate
->internal_flags
|= cfDelayAce
;
729 cmd
= COPYFILE_RECURSE_DIR
;
735 cmd
= COPYFILE_RECURSE_FILE
;
738 cmd
= COPYFILE_RECURSE_DIR_CLEANUP
;
745 errno
= ftsent
->fts_errno
;
747 rv
= (*status
)(COPYFILE_RECURSE_ERROR
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
748 if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
752 if (rv
== COPYFILE_QUIT
) {
765 if (cmd
== COPYFILE_RECURSE_DIR
|| cmd
== COPYFILE_RECURSE_FILE
) {
767 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
768 if (rv
== COPYFILE_SKIP
) {
769 if (cmd
== COPYFILE_RECURSE_DIR
) {
770 rv
= fts_set(fts
, ftsent
, FTS_SKIP
);
772 rv
= (*status
)(0, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
773 if (rv
== COPYFILE_QUIT
)
779 if (rv
== COPYFILE_QUIT
) {
780 retval
= -1; errno
= 0;
784 int tmp_flags
= (cmd
== COPYFILE_RECURSE_DIR
) ? (flags
& ~COPYFILE_STAT
) : flags
;
785 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, tmp_flags
);
788 rv
= (*status
)(cmd
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
789 if (rv
== COPYFILE_QUIT
) {
801 rv
= (*status
)(cmd
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
802 if (rv
== COPYFILE_QUIT
) {
803 retval
= -1; errno
= 0;
807 } else if (cmd
== COPYFILE_RECURSE_DIR_CLEANUP
) {
809 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
810 if (rv
== COPYFILE_QUIT
) {
811 retval
= -1; errno
= 0;
813 } else if (rv
== COPYFILE_SKIP
) {
818 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, (flags
& COPYFILE_NOFOLLOW
) | COPYFILE_STAT
);
821 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
822 if (rv
== COPYFILE_QUIT
) {
825 } else if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
826 if (rv
== COPYFILE_CONTINUE
)
837 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
838 if (rv
== COPYFILE_QUIT
) {
839 retval
= -1; errno
= 0;
849 copyfile_state_free(tstate
);
863 * fcopyfile() is used to copy a source file descriptor to a destination file
864 * descriptor. This allows an application to figure out how it wants to open
865 * the files (doing various security checks, perhaps), and then just pass in
866 * the file descriptors.
868 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
871 copyfile_state_t s
= state
;
874 if (src_fd
< 0 || dst_fd
< 0)
880 if (copyfile_preamble(&s
, flags
) < 0)
883 copyfile_debug(2, "set src_fd <- %d", src_fd
);
884 if (s
->src_fd
== -2 && src_fd
> -1)
887 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
889 if (errno
== ENOTSUP
|| errno
== EPERM
)
890 fstat(s
->src_fd
, &s
->sb
);
893 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
899 /* prevent copying on unsupported types */
900 switch (s
->sb
.st_mode
& S_IFMT
)
911 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
912 if (s
->dst_fd
== -2 && dst_fd
> -1)
915 (void)fstat(s
->dst_fd
, &dst_sb
);
916 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
918 (void)copyfile_quarantine(s
);
920 ret
= copyfile_internal(s
, flags
);
922 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
924 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
933 copyfile_state_free(s
);
942 * the original copyfile() routine; this copies a source file to a destination
943 * file. Note that because we need to set the names in the state variable, this
944 * is not just the same as opening the two files, and then calling fcopyfile().
945 * Oh, if only life were that simple!
947 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
951 copyfile_state_t s
= state
;
954 if (src
== NULL
&& dst
== NULL
)
960 if (copyfile_preamble(&s
, flags
) < 0)
966 * This macro is... well, it's not the worst thing you can do with cpp, not
967 * by a long shot. Essentially, we are setting the filename (src or dst)
968 * in the state structure; since the structure may not have been cleared out
969 * before being used again, we do some of the cleanup here: if the given
970 * filename (e.g., src) is set, and state->src is not equal to that, then
971 * we need to check to see if the file descriptor had been opened, and if so,
972 * close it. After that, we set state->src to be a copy of the given filename,
973 * releasing the old copy if necessary.
975 #define COPYFILE_SET_FNAME(NAME, S) \
977 if (NAME != NULL) { \
978 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
979 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
980 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
981 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
982 close(S->NAME##_fd); \
990 if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \
995 COPYFILE_SET_FNAME(src
, s
);
996 COPYFILE_SET_FNAME(dst
, s
);
998 if (s
->flags
& COPYFILE_RECURSIVE
) {
1004 * Get a copy of the source file's security settings
1006 if (s
->original_fsec
) {
1007 filesec_free(s
->original_fsec
);
1008 s
->original_fsec
= NULL
;
1010 if ((s
->original_fsec
= filesec_init()) == NULL
)
1013 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
1014 ((dst_sb
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1015 if (s
->permissive_fsec
)
1016 free(s
->permissive_fsec
);
1017 s
->permissive_fsec
= NULL
;
1018 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
1021 * copyfile_fix_perms() will make a copy of the permission set,
1022 * and insert at the beginning an ACE that ensures we can write
1023 * to the file and set attributes.
1026 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
1029 * Set the permissions for the destination to our copy.
1030 * We should get ENOTSUP from any filesystem that simply
1031 * doesn't support it.
1033 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
1035 copyfile_warn("setting security information");
1036 filesec_free(s
->permissive_fsec
);
1037 s
->permissive_fsec
= NULL
;
1040 } else if (errno
== ENOENT
) {
1045 * If COPYFILE_CHECK is set in flags, then all we are going to do
1046 * is see what kinds of things WOULD have been copied (see
1047 * copyfile_check() below). We return that value.
1049 if (COPYFILE_CHECK
& flags
)
1051 ret
= copyfile_check(s
);
1053 } else if ((ret
= copyfile_open(s
)) < 0)
1056 (void)fcntl(s
->src_fd
, F_NOCACHE
, 1);
1057 (void)fcntl(s
->dst_fd
, F_NOCACHE
, 1);
1058 #ifdef F_SINGLE_WRITER
1059 (void)fcntl(s
->dst_fd
, F_SINGLE_WRITER
, 1);
1062 ret
= copyfile_internal(s
, flags
);
1066 #ifdef COPYFILE_RECURSIVE
1067 if (!(flags
& COPYFILE_STAT
)) {
1070 /* Just need to reset the BSD information -- mode, owner, group */
1071 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
1072 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
1079 if (s
->src
&& (flags
& COPYFILE_MOVE
))
1080 (void)remove(s
->src
);
1083 if (state
== NULL
) {
1085 copyfile_state_free(s
);
1101 * Shared prelude to the {f,}copyfile(). This initializes the
1102 * state variable, if necessary, and also checks for both debugging
1103 * and disabling environment variables.
1105 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
1111 if ((*state
= copyfile_state_alloc()) == NULL
)
1117 if (COPYFILE_DEBUG
& flags
)
1120 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
1123 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
1125 /* clamp s->debug to 1 if the environment variable is not parsable */
1126 if (s
->debug
== 0 && errno
!= 0)
1129 copyfile_debug(2, "debug value set to: %d", s
->debug
);
1133 /* Temporarily disabled */
1134 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
1136 copyfile_debug(1, "copyfile disabled");
1140 copyfile_debug(2, "setting flags: %d", s
->flags
);
1147 * The guts of {f,}copyfile().
1148 * This looks through the flags in a particular order, and calls the
1149 * associated functions.
1151 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
1155 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1157 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1163 * COPYFILE_PACK causes us to create an Apple Double version of the
1164 * source file, and puts it into the destination file. See
1165 * copyfile_pack() below for all the gory details.
1167 if (COPYFILE_PACK
& flags
)
1169 if ((ret
= copyfile_pack(s
)) < 0)
1171 if (s
->dst
) unlink(s
->dst
);
1178 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1179 * The goal there is to take an Apple Double file, and turn it
1180 * into a normal file (with data fork, resource fork, modes,
1181 * extended attributes, ACLs, etc.).
1183 if (COPYFILE_UNPACK
& flags
)
1185 if ((ret
= copyfile_unpack(s
)) < 0)
1191 * If we have quarantine info set, we attempt
1192 * to apply it to dst_fd. We don't care if
1193 * it fails, not yet anyway.
1196 int qr
= qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1201 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
1202 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1203 s
->xattr_name
= NULL
;
1204 if (rv
== COPYFILE_QUIT
) {
1205 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1210 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1218 * COPYFILE_XATTR tells us to copy the extended attributes;
1219 * this is seperate from the extended security (aka ACLs),
1220 * however. If we succeed in this, we continue to the next
1221 * stage; if we fail, we return with an error value. Note
1222 * that we fail if the errno is ENOTSUP, but we don't print
1223 * a warning in that case.
1225 if (COPYFILE_XATTR
& flags
)
1227 if ((ret
= copyfile_xattr(s
)) < 0)
1229 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1230 copyfile_warn("error processing extended attributes");
1236 * Simialr to above, this tells us whether or not to copy
1237 * the non-meta data portion of the file. We attempt to
1238 * remove (via unlink) the destination file if we fail.
1240 if (COPYFILE_DATA
& flags
)
1242 if ((ret
= copyfile_data(s
)) < 0)
1244 copyfile_warn("error processing data");
1245 if (s
->dst
&& unlink(s
->dst
))
1246 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1252 * COPYFILE_SECURITY requests that we copy the security, both
1253 * extended and mundane (that is, ACLs and POSIX).
1255 if (COPYFILE_SECURITY
& flags
)
1257 if ((ret
= copyfile_security(s
)) < 0)
1259 copyfile_warn("error processing security information");
1264 if (COPYFILE_STAT
& flags
)
1266 if ((ret
= copyfile_stat(s
)) < 0)
1268 copyfile_warn("error processing POSIX information");
1282 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1284 copyfile_state_t
copyfile_state_alloc(void)
1286 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1293 filesec_free(s
->fsec
);
1296 s
->fsec
= filesec_init();
1304 * copyfile_state_free() returns the memory allocated to the state structure.
1305 * It also closes the file descriptors, if they've been opened.
1307 int copyfile_state_free(copyfile_state_t s
)
1312 filesec_free(s
->fsec
);
1314 if (s
->original_fsec
)
1315 filesec_free(s
->original_fsec
);
1317 if (s
->permissive_fsec
)
1318 filesec_free(s
->permissive_fsec
);
1321 qtn_file_free(s
->qinfo
);
1323 if (copyfile_close(s
) < 0)
1325 copyfile_warn("error closing files");
1329 free(s
->xattr_name
);
1340 * Should we worry if we can't close the source? NFS says we
1341 * should, but it's pretty late for us at this point.
1343 static int copyfile_close(copyfile_state_t s
)
1345 if (s
->src
&& s
->src_fd
>= 0)
1348 if (s
->dst
&& s
->dst_fd
>= 0) {
1349 if (close(s
->dst_fd
))
1357 * The purpose of this function is to set up a set of permissions
1358 * (ACL and traditional) that lets us write to the file. In the
1359 * case of ACLs, we do this by putting in a first entry that lets
1360 * us write data, attributes, and extended attributes. In the case
1361 * of traditional permissions, we set the S_IWUSR (user-write)
1364 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1366 filesec_t ret_fsec
= NULL
;
1370 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1373 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1375 #ifdef COPYFILE_RECURSIVE
1376 if (add_uberace(&acl
))
1380 acl_permset_t permset
;
1383 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1387 * First, we create an entry, and give it the special name
1388 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1389 * After that, we clear out all the permissions in it, and
1390 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1391 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1392 * the functionality, and put this into the ACL.
1394 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1396 if (acl_get_permset(entry
, &permset
) == -1)
1398 if (acl_clear_perms(permset
) == -1)
1400 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1402 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1404 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1406 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1409 if(acl_set_permset(entry
, permset
) == -1)
1411 if(acl_set_qualifier(entry
, qual
) == -1)
1415 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1420 * This is for the normal, mundane, POSIX permission model.
1421 * We make sure that we can write to the file.
1423 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1425 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1427 mode
|= S_IWUSR
|S_IRUSR
;
1428 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1442 filesec_free(ret_fsec
);
1449 * Used to clear out the BSD/POSIX security information from
1453 copyfile_unset_posix_fsec(filesec_t fsec
)
1455 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1456 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1457 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1462 * Used to remove acl information from a filesec_t
1463 * Unsetting the acl alone in Tiger was insufficient
1465 static int copyfile_unset_acl(copyfile_state_t s
)
1468 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1470 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1473 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1475 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1478 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1480 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1487 * copyfile_open() does what one expects: it opens up the files
1488 * given in the state structure, if they're not already open.
1489 * It also does some type validation, to ensure that we only
1490 * handle file types we know about.
1492 static int copyfile_open(copyfile_state_t s
)
1494 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
1495 int islnk
= 0, isdir
= 0;
1496 int osrc
= 0, dsrc
= 0;
1498 if (s
->src
&& s
->src_fd
== -2)
1500 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1501 (s
->src
, &s
->sb
, s
->fsec
))
1503 copyfile_warn("stat on %s", s
->src
);
1507 /* prevent copying on unsupported types */
1508 switch (s
->sb
.st_mode
& S_IFMT
)
1512 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1513 s
->err
= ENOMEM
; /* too big for us to copy */
1524 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1530 * If we're packing, then we are actually
1531 * creating a file, no matter what the source
1534 if (s
->flags
& COPYFILE_PACK
) {
1536 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1537 * if the file is a symlink, and O_NOFOLLOW is specified,
1538 * open will return ELOOP, whether or not O_SYMLINK is set.
1539 * However, we know whether or not it was a symlink from
1540 * the stat above (although there is a potentiaal for a race
1541 * condition here, but it will err on the side of returning
1545 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1549 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1551 copyfile_warn("open on %s", s
->src
);
1554 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1556 (void)copyfile_quarantine(s
);
1559 if (s
->dst
&& s
->dst_fd
== -2)
1562 * COPYFILE_UNLINK tells us to try removing the destination
1563 * before we create it. We don't care if the file doesn't
1564 * exist, so we ignore ENOENT.
1566 if (COPYFILE_UNLINK
& s
->flags
)
1568 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1570 copyfile_warn("%s: remove", s
->dst
);
1575 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1579 if (lstat(s
->dst
, &st
) != -1) {
1580 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1586 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1591 copyfile_warn("cannot allocate %zd bytes", sz
);
1594 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1595 copyfile_warn("cannot readlink %s", s
->src
);
1599 if (symlink(bp
, s
->dst
) == -1) {
1600 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1601 copyfile_warn("Cannot make symlink %s", s
->dst
);
1607 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1608 if (s
->dst_fd
== -1) {
1609 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1614 mode
= (s
->sb
.st_mode
& ~S_IFMT
) | S_IRWXU
;
1616 if (mkdir(s
->dst
, mode
) == -1) {
1617 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1618 copyfile_warn("Cannot make directory %s", s
->dst
);
1622 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1623 if (s
->dst_fd
== -1) {
1624 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1627 } else while((s
->dst_fd
= open(s
->dst
, oflags
| dsrc
, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1630 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1631 * was written -- allow one to set an extended attribute on a file descriptor
1632 * for a read-only file, even if the file descriptor is opened for writing.
1633 * This will only matter if the file does not already exist.
1638 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1639 if (s
->flags
& COPYFILE_EXCL
)
1641 oflags
= oflags
& ~O_CREAT
;
1642 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
1644 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
1649 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
1653 * If we're trying to write to a directory to which we don't
1654 * have access, the create above would have failed, but chmod
1655 * here would have given us ENOENT. But the real error is
1656 * still one of access, so we change the errno we're reporting.
1657 * This could cause confusion with a race condition.
1660 if (errno
== ENOENT
)
1665 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
1666 if (((s
->flags
& COPYFILE_EXCL
) ||
1667 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
1668 && !(s
->flags
& COPYFILE_UNPACK
))
1670 oflags
= (oflags
& ~(O_WRONLY
|O_CREAT
|O_TRUNC
)) | O_RDONLY
;
1673 copyfile_warn("open on %s", s
->dst
);
1676 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
1679 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1681 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1682 s
->src_fd
, s
->dst_fd
);
1691 * copyfile_check(), as described above, essentially tells you
1692 * what you'd have to copy, if you wanted it to copy the things
1693 * you asked it to copy.
1694 * In other words, if you pass in COPYFILE_ALL, and the file in
1695 * question had no extended attributes but did have an ACL, you'd
1696 * get back COPYFILE_ACL.
1698 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
1701 copyfile_flags_t ret
= 0;
1702 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
1712 if (COPYFILE_XATTR
& s
->flags
)
1713 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
1715 ret
|= COPYFILE_XATTR
;
1718 if (COPYFILE_ACL
& s
->flags
)
1720 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1721 (s
->src
, &s
->sb
, s
->fsec
);
1723 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
1724 ret
|= COPYFILE_ACL
;
1727 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
1733 /* If the state has had quarantine info set already, we use that */
1734 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1736 qinfo
= qtn_file_alloc();
1738 * For quarantine information, we need to see if the source file
1739 * has any. Since it may be a symlink, however, and we may, or
1740 * not be following, *and* there's no qtn* routine which can optionally
1741 * follow or not follow a symlink, we need to instead work around
1750 * If we care about not following symlinks, *and* the file exists
1751 * (which is to say, lstat doesn't return an error), *and* the file
1752 * is a symlink, then we open it up (with O_SYMLINK), and use
1753 * qtn_file_init_with_fd(); if none of that is true, however, then
1754 * we can simply use qtn_file_init_with_path().
1757 && lstat(s
->src
, &sbuf
) == 0
1758 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1759 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
1761 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
1762 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1767 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
1768 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1771 qtn_file_free(qinfo
);
1779 * Attempt to copy the data section of a file. Using blockisize
1780 * is not necessarily the fastest -- it might be desirable to
1781 * specify a blocksize, somehow. But it's a size that should be
1782 * guaranteed to work.
1784 static int copyfile_data(copyfile_state_t s
)
1790 size_t iBlocksize
= 0;
1791 size_t oBlocksize
= 0;
1792 const size_t onegig
= 1 << 30;
1794 copyfile_callback_t status
= s
->statuscb
;
1796 /* Unless it's a normal file, we don't copy. For now, anyway */
1797 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
1800 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
1801 if (s
->internal_flags
& cfSawDecmpEA
) {
1802 if (s
->sb
.st_flags
& UF_COMPRESSED
) {
1803 if ((s
->flags
& COPYFILE_STAT
) == 0) {
1804 if (fchflags(s
->dst_fd
, UF_COMPRESSED
) == 0) {
1812 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
1813 iBlocksize
= s
->sb
.st_blksize
;
1815 iBlocksize
= sfs
.f_iosize
;
1818 /* Work-around for 6453525, limit blocksize to 1G */
1819 if (iBlocksize
> onegig
) {
1820 iBlocksize
= onegig
;
1823 if ((bp
= malloc(iBlocksize
)) == NULL
)
1826 if (fstatfs(s
->dst_fd
, &sfs
) == -1 || sfs
.f_iosize
== 0) {
1827 oBlocksize
= iBlocksize
;
1829 oBlocksize
= sfs
.f_iosize
;
1830 if (oBlocksize
> onegig
)
1831 oBlocksize
= onegig
;
1837 /* If supported, do preallocation for Xsan / HFS volumes */
1838 #ifdef F_PREALLOCATE
1843 fst
.fst_posmode
= F_PEOFPOSMODE
;
1845 fst
.fst_length
= s
->sb
.st_size
;
1846 /* Ignore errors; this is merely advisory. */
1847 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
1851 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
1854 size_t left
= nread
;
1859 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
1863 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
1870 copyfile_warn("writing to output file got error");
1872 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1873 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
1877 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
1886 ptr
= ((char*)ptr
) + nwritten
;
1890 s
->totalCopied
+= nwritten
;
1892 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
1893 if (rv
== COPYFILE_QUIT
) {
1894 ret
= -1; s
->err
= errno
= ECANCELED
;
1902 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
1907 if (ftruncate(s
->dst_fd
, s
->totalCopied
) < 0)
1923 * copyfile_security() will copy the ACL set, and the
1924 * POSIX set. Complexities come when dealing with
1925 * inheritied permissions, and when dealing with both
1926 * POSIX and ACL permissions.
1928 static int copyfile_security(copyfile_state_t s
)
1932 acl_t acl_src
= NULL
, acl_tmp
= NULL
, acl_dst
= NULL
;
1934 filesec_t tmp_fsec
= NULL
;
1935 filesec_t fsec_dst
= filesec_init();
1937 if (fsec_dst
== NULL
)
1941 if (COPYFILE_ACL
& s
->flags
)
1943 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
1945 if (errno
== ENOENT
)
1951 /* grab the destination acl
1952 cannot assume it's empty due to inheritance
1954 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
1957 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
1959 if (errno
== ENOENT
)
1965 if (acl_src
== NULL
&& acl_dst
== NULL
)
1968 acl_tmp
= acl_init(4);
1969 if (acl_tmp
== NULL
)
1973 acl_entry_t ace
= NULL
;
1974 acl_entry_t tmp
= NULL
;
1976 acl_get_entry(acl_src
,
1977 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1980 acl_flagset_t flags
= { 0 };
1981 acl_get_flagset_np(ace
, &flags
);
1982 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
1984 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
1987 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
1990 copyfile_debug(2, "copied acl entry from %s to %s",
1991 s
->src
? s
->src
: "(null src)",
1992 s
->dst
? s
->dst
: "(null tmp)");
1998 acl_entry_t ace
= NULL
;
1999 acl_entry_t tmp
= NULL
;
2000 acl_flagset_t flags
= { 0 };
2001 for (copied
= 0;acl_get_entry(acl_dst
,
2002 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
2005 acl_get_flagset_np(ace
, &flags
);
2006 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2008 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2011 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2014 copyfile_debug(2, "copied acl entry from %s to %s",
2015 s
->src
? s
->src
: "(null dst)",
2016 s
->dst
? s
->dst
: "(null tmp)");
2021 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_tmp
))
2023 copyfile_debug(3, "altered acl");
2028 * The following code is attempting to ensure that only the requested
2029 * security information gets copied over to the destination file.
2030 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2031 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2034 * If we have both flags, we copy everything; if we have ACL but not STAT,
2035 * we remove the POSIX information from the filesec object, and apply the
2036 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2037 * the extended version.
2039 tmp_fsec
= filesec_dup(s
->fsec
);
2040 if (tmp_fsec
== NULL
) {
2044 switch (COPYFILE_SECURITY
& s
->flags
) {
2046 copyfile_unset_posix_fsec(tmp_fsec
);
2048 case COPYFILE_ACL
| COPYFILE_STAT
:
2049 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
2052 * The call could have failed for a number of reasons, since
2053 * it does a number of things: it changes the mode of the file,
2054 * sets the owner and group, and applies an ACL (if one exists).
2055 * The typical failure is going to be trying to set the group of
2056 * the destination file to match the source file, when the process
2057 * doesn't have permission to put files in that group. We try to
2058 * work around this by breaking the steps out and doing them
2059 * discretely. We don't care if the fchown fails, but we do care
2060 * if the mode or ACL can't be set. For historical reasons, we
2061 * simply log those failures, however.
2063 * Big warning here: we may NOT have COPYFILE_STAT set, since
2064 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2067 #define NS(x) ((x) ? (x) : "(null string)")
2068 if ((s
->flags
& COPYFILE_STAT
) &&
2069 fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
2070 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
2072 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2073 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
2074 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
2075 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
2083 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
2086 filesec_free(tmp_fsec
);
2088 filesec_free(fsec_dst
);
2089 if (acl_src
) acl_free(acl_src
);
2090 if (acl_dst
) acl_free(acl_dst
);
2091 if (acl_tmp
) acl_free(acl_tmp
);
2102 * Attempt to set the destination file's stat information -- including
2103 * flags and time-related fields -- to the source's.
2105 static int copyfile_stat(copyfile_state_t s
)
2107 struct timeval tval
[2];
2108 unsigned int added_flags
= 0;
2111 * NFS doesn't support chflags; ignore errors as a result, since
2112 * we don't return failure for this.
2114 if (s
->internal_flags
& cfMakeFileInvisible
)
2115 added_flags
|= UF_HIDDEN
;
2117 (void)fchflags(s
->dst_fd
, (u_int
)s
->sb
.st_flags
| added_flags
);
2119 /* If this fails, we don't care */
2120 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2122 /* This may have already been done in copyfile_security() */
2123 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
2125 tval
[0].tv_sec
= s
->sb
.st_atime
;
2126 tval
[1].tv_sec
= s
->sb
.st_mtime
;
2127 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
2128 (void)futimes(s
->dst_fd
, tval
);
2134 * Similar to copyfile_security() in some ways; this
2135 * routine copies the extended attributes from the source,
2136 * and sets them on the destination.
2137 * The procedure is pretty simple, even if it is verbose:
2138 * for each named attribute on the destination, get its name, and
2139 * remove it. We should have none after that.
2140 * For each named attribute on the source, get its name, get its
2141 * data, and set it on the destination.
2143 static int copyfile_xattr(copyfile_state_t s
)
2146 char *namebuf
, *end
;
2149 ssize_t bufsize
= 4096;
2153 int look_for_decmpea
= 0;
2155 /* delete EAs on destination */
2156 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2158 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2161 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
2165 * With this, end points to the last byte of the allocated buffer
2166 * This *should* be NUL, from flistxattr, but if it's not, we can
2167 * set it anyway -- it'll result in a truncated name, which then
2168 * shouldn't match when we get them later.
2170 end
= namebuf
+ nsize
- 1;
2173 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
2174 /* If the quarantine information shows up as an EA, we skip over it */
2175 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
2178 fremovexattr(s
->dst_fd
, name
,0);
2185 if (errno
== ENOTSUP
|| errno
== EPERM
)
2191 #ifdef DECMPFS_XATTR_NAME
2192 if ((s
->flags
& COPYFILE_DATA
) &&
2193 (s
->sb
.st_flags
& UF_COMPRESSED
) &&
2194 doesdecmpfs(s
->src_fd
) &&
2195 doesdecmpfs(s
->dst_fd
)) {
2196 look_for_decmpea
= XATTR_SHOWCOMPRESSION
;
2200 /* get name list of EAs on source */
2201 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, look_for_decmpea
)) < 0)
2203 if (errno
== ENOTSUP
|| errno
== EPERM
)
2211 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2214 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, look_for_decmpea
);
2222 * With this, end points to the last byte of the allocated buffer
2223 * This *should* be NUL, from flistxattr, but if it's not, we can
2224 * set it anyway -- it'll result in a truncated name, which then
2225 * shouldn't match when we get them later.
2227 end
= namebuf
+ nsize
- 1;
2231 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
2236 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
2238 if (s
->xattr_name
) {
2239 free(s
->xattr_name
);
2240 s
->xattr_name
= NULL
;
2243 /* If the quarantine information shows up as an EA, we skip over it */
2244 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
2247 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, look_for_decmpea
)) < 0)
2252 if (xa_size
> bufsize
)
2254 void *tdptr
= xa_dataptr
;
2257 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
2265 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
)) < 0)
2270 if (xa_size
!= asize
)
2273 #ifdef DECMPFS_XATTR_NAME
2274 if (strncmp(name
, DECMPFS_XATTR_NAME
, end
-name
) == 0)
2276 decmpfs_disk_header
*hdr
= xa_dataptr
;
2279 * If the EA has the decmpfs name, but is too
2280 * small, or doesn't have the right magic number,
2281 * or isn't the right type, we'll just skip it.
2282 * This means it won't end up in the destination
2283 * file, and data copy will happen normally.
2285 if ((size_t)xa_size
< sizeof(decmpfs_disk_header
)) {
2288 if (OSSwapLittleToHostInt32(hdr
->compression_magic
) != DECMPFS_MAGIC
) {
2291 if (OSSwapLittleToHostInt32(hdr
->compression_type
) != 3 &&
2292 OSSwapLittleToHostInt32(hdr
->compression_type
) != 4) {
2295 s
->internal_flags
|= cfSawDecmpEA
;
2299 // If we have a copy intention stated, and the EA is to be ignored, we ignore it
2301 && _PreserveEA(name
, s
->copyIntent
) == 0)
2304 s
->xattr_name
= strdup(name
);
2308 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
2309 if (rv
== COPYFILE_QUIT
) {
2312 } else if (rv
== COPYFILE_SKIP
) {
2316 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
) < 0)
2321 if (s
->xattr_name
== NULL
)
2322 s
->xattr_name
= strdup(name
);
2323 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2324 if (rv
== COPYFILE_QUIT
)
2334 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name
, strerror(errno
));
2340 if (s
->xattr_name
== NULL
)
2341 s
->xattr_name
= strdup(name
);
2343 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
2344 if (rv
== COPYFILE_QUIT
) {
2353 free((void *) xa_dataptr
);
2354 if (s
->xattr_name
) {
2355 free(s
->xattr_name
);
2356 s
->xattr_name
= NULL
;
2362 * API interface into getting data from the opaque data type.
2364 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
2374 case COPYFILE_STATE_SRC_FD
:
2375 *(int*)ret
= s
->src_fd
;
2377 case COPYFILE_STATE_DST_FD
:
2378 *(int*)ret
= s
->dst_fd
;
2380 case COPYFILE_STATE_SRC_FILENAME
:
2381 *(char**)ret
= s
->src
;
2383 case COPYFILE_STATE_DST_FILENAME
:
2384 *(char**)ret
= s
->dst
;
2386 case COPYFILE_STATE_QUARANTINE
:
2387 *(qtn_file_t
*)ret
= s
->qinfo
;
2390 case COPYFILE_STATE_STATS
:
2391 ret
= s
->stats
.global
;
2393 case COPYFILE_STATE_PROGRESS_CB
:
2394 ret
= s
->callbacks
.progress
;
2397 #ifdef COPYFILE_STATE_STATUS_CB
2398 case COPYFILE_STATE_STATUS_CB
:
2399 *(copyfile_callback_t
*)ret
= s
->statuscb
;
2401 case COPYFILE_STATE_STATUS_CTX
:
2402 *(void**)ret
= s
->ctx
;
2404 case COPYFILE_STATE_COPIED
:
2405 *(off_t
*)ret
= s
->totalCopied
;
2408 #ifdef COPYFILE_STATE_XATTRNAME
2409 case COPYFILE_STATE_XATTRNAME
:
2410 *(char**)ret
= s
->xattr_name
;
2413 #ifdef COPYFILE_STATE_INTENT
2414 case COPYFILE_STATE_INTENT
:
2415 *(CopyOperationIntent_t
*)ret
= s
->copyIntent
;
2427 * Public API for setting state data (remember that the state is
2428 * an opaque data type).
2430 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
2432 #define copyfile_set_string(DST, SRC) \
2434 if (SRC != NULL) { \
2435 DST = strdup((char *)SRC); \
2437 if (DST != NULL) { \
2452 case COPYFILE_STATE_SRC_FD
:
2453 s
->src_fd
= *(int*)thing
;
2455 case COPYFILE_STATE_DST_FD
:
2456 s
->dst_fd
= *(int*)thing
;
2458 case COPYFILE_STATE_SRC_FILENAME
:
2459 copyfile_set_string(s
->src
, thing
);
2461 case COPYFILE_STATE_DST_FILENAME
:
2462 copyfile_set_string(s
->dst
, thing
);
2464 case COPYFILE_STATE_QUARANTINE
:
2467 qtn_file_free(s
->qinfo
);
2470 if (*(qtn_file_t
*)thing
)
2471 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
2474 case COPYFILE_STATE_STATS
:
2475 s
->stats
.global
= thing
;
2477 case COPYFILE_STATE_PROGRESS_CB
:
2478 s
->callbacks
.progress
= thing
;
2481 #ifdef COPYFILE_STATE_STATUS_CB
2482 case COPYFILE_STATE_STATUS_CB
:
2483 s
->statuscb
= (copyfile_callback_t
)thing
;
2485 case COPYFILE_STATE_STATUS_CTX
:
2486 s
->ctx
= (void*)thing
;
2489 #ifdef COPYFILE_STATE_INTENT
2490 case COPYFILE_STATE_INTENT
:
2491 s
->copyIntent
= *(CopyOperationIntent_t
*)thing
;
2499 #undef copyfile_set_string
2504 * Make this a standalone program for testing purposes by
2505 * defining _COPYFILE_TEST.
2507 #ifdef _COPYFILE_TEST
2508 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2510 struct {char *s
; int v
;} opts
[] = {
2511 COPYFILE_OPTION(ACL
)
2512 COPYFILE_OPTION(STAT
)
2513 COPYFILE_OPTION(XATTR
)
2514 COPYFILE_OPTION(DATA
)
2515 COPYFILE_OPTION(SECURITY
)
2516 COPYFILE_OPTION(METADATA
)
2517 COPYFILE_OPTION(ALL
)
2518 COPYFILE_OPTION(NOFOLLOW_SRC
)
2519 COPYFILE_OPTION(NOFOLLOW_DST
)
2520 COPYFILE_OPTION(NOFOLLOW
)
2521 COPYFILE_OPTION(EXCL
)
2522 COPYFILE_OPTION(MOVE
)
2523 COPYFILE_OPTION(UNLINK
)
2524 COPYFILE_OPTION(PACK
)
2525 COPYFILE_OPTION(UNPACK
)
2526 COPYFILE_OPTION(CHECK
)
2527 COPYFILE_OPTION(VERBOSE
)
2528 COPYFILE_OPTION(DEBUG
)
2532 int main(int c
, char *v
[])
2538 errx(1, "insufficient arguments");
2542 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
2544 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
2546 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
2553 return copyfile(v
[1], v
[2], NULL
, flags
);
2557 * Apple Double Create
2559 * Create an Apple Double "._" file from a file's extented attributes
2561 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2565 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2567 #define XATTR_MAXATTRLEN (16*1024*1024)
2571 Typical "._" AppleDouble Header File layout:
2572 ------------------------------------------------------------
2577 .-- AD ENTRY[0] Finder Info Entry (must be first)
2578 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2580 | ///////////// Fixed Size Data (32 bytes)
2584 | ATTR ENTRY[1] --+--.
2585 | ATTR ENTRY[2] --+--+--.
2587 | ATTR ENTRY[N] --+--+--+--.
2588 | ATTR DATA 0 <-' | | |
2589 | //////////// | | |
2590 | ATTR DATA 1 <----' | |
2592 | ATTR DATA 2 <-------' |
2595 | ATTR DATA N <----------'
2597 | Attribute Free Space
2599 '----> RESOURCE FORK
2600 ///////////// Variable Sized Data
2609 ------------------------------------------------------------
2611 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2612 stored as part of the Finder Info. The length in the Finder
2613 Info AppleDouble entry includes the length of the extended
2614 attribute header, attribute entries, and attribute data.
2619 * On Disk Data Structures
2621 * Note: Motorola 68K alignment and big-endian.
2623 * See RFC 1740 for additional information about the AppleDouble file format.
2627 #define ADH_MAGIC 0x00051607
2628 #define ADH_VERSION 0x00020000
2629 #define ADH_MACOSX "Mac OS X "
2632 * AppleDouble Entry ID's
2634 #define AD_DATA 1 /* Data fork */
2635 #define AD_RESOURCE 2 /* Resource fork */
2636 #define AD_REALNAME 3 /* File's name on home file system */
2637 #define AD_COMMENT 4 /* Standard Mac comment */
2638 #define AD_ICONBW 5 /* Mac black & white icon */
2639 #define AD_ICONCOLOR 6 /* Mac color icon */
2640 #define AD_UNUSED 7 /* Not used */
2641 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2642 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2643 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2644 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2645 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2646 #define AD_AFPNAME 13 /* Short name on AFP server */
2647 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2648 #define AD_AFPDIRID 15 /* AFP directory ID */
2649 #define AD_ATTRIBUTES AD_FINDERINFO
2652 #define ATTR_FILE_PREFIX "._"
2653 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2655 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2657 /* Implementation Limits */
2658 #define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */
2659 #define ATTR_MAX_NAME_LEN 128
2660 #define ATTR_MAX_HDR_SIZE (65536+18)
2663 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2664 * size supported (including the attribute entries). All of
2665 * the attribute entries must reside within this limit.
2669 #define FINDERINFOSIZE 32
2671 typedef struct apple_double_entry
2673 u_int32_t type
; /* entry type: see list, 0 invalid */
2674 u_int32_t offset
; /* entry data offset from the beginning of the file. */
2675 u_int32_t length
; /* entry data length in bytes. */
2676 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
2679 typedef struct apple_double_header
2681 u_int32_t magic
; /* == ADH_MAGIC */
2682 u_int32_t version
; /* format version: 2 = 0x00020000 */
2683 u_int32_t filler
[4];
2684 u_int16_t numEntries
; /* number of entries which follow */
2685 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
2686 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
2687 u_int8_t pad
[2]; /* get better alignment inside attr_header */
2688 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
2691 /* Entries are aligned on 4 byte boundaries */
2692 typedef struct attr_entry
2694 u_int32_t offset
; /* file offset to data */
2695 u_int32_t length
; /* size of attribute data */
2697 u_int8_t namelen
; /* length of name including NULL termination char */
2698 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2699 } __attribute__((aligned(2), packed
)) attr_entry_t
;
2703 /* Header + entries must fit into 64K */
2704 typedef struct attr_header
2706 apple_double_header_t appledouble
;
2707 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
2708 u_int32_t debug_tag
; /* for debugging == file id of owning file */
2709 u_int32_t total_size
; /* total size of attribute header + entries + data */
2710 u_int32_t data_start
; /* file offset to attribute data area */
2711 u_int32_t data_length
; /* length of attribute data area */
2712 u_int32_t reserved
[3];
2714 u_int16_t num_attrs
;
2715 } __attribute__((aligned(2), packed
)) attr_header_t
;
2717 /* Empty Resource Fork Header */
2718 /* This comes by way of xnu's vfs_xattr.c */
2719 typedef struct rsrcfork_header
{
2720 u_int32_t fh_DataOffset
;
2721 u_int32_t fh_MapOffset
;
2722 u_int32_t fh_DataLength
;
2723 u_int32_t fh_MapLength
;
2724 u_int8_t systemData
[112];
2725 u_int8_t appData
[128];
2726 u_int32_t mh_DataOffset
;
2727 u_int32_t mh_MapOffset
;
2728 u_int32_t mh_DataLength
;
2729 u_int32_t mh_MapLength
;
2731 u_int16_t mh_RefNum
;
2733 u_int8_t mh_InMemoryAttr
;
2736 u_int16_t typeCount
;
2737 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
2738 #define RF_FIRST_RESOURCE 256
2739 #define RF_NULL_MAP_LENGTH 30
2740 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2742 static const rsrcfork_header_t empty_rsrcfork_header
= {
2743 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
2744 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
2746 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
2747 { RF_EMPTY_TAG
, }, // systemData
2749 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
2750 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
2752 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
2756 0, // mh_InMemoryAttr
2757 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
2758 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
2759 OSSwapHostToBigInt16(-1), // typeCount
2762 #define SWAP16(x) OSSwapBigToHostInt16(x)
2763 #define SWAP32(x) OSSwapBigToHostInt32(x)
2764 #define SWAP64(x) OSSwapBigToHostInt64(x)
2766 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2768 #define ATTR_ENTRY_LENGTH(namelen) \
2769 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2771 #define ATTR_NEXT(ae) \
2772 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2774 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2777 * Endian swap Apple Double header
2780 swap_adhdr(apple_double_header_t
*adh
)
2782 #if BYTE_ORDER == LITTLE_ENDIAN
2786 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
2788 adh
->magic
= SWAP32 (adh
->magic
);
2789 adh
->version
= SWAP32 (adh
->version
);
2790 adh
->numEntries
= SWAP16 (adh
->numEntries
);
2792 for (i
= 0; i
< count
; i
++)
2794 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
2795 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
2796 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
2804 * Endian swap extended attributes header
2807 swap_attrhdr(attr_header_t
*ah
)
2809 #if BYTE_ORDER == LITTLE_ENDIAN
2814 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
2816 ah
->magic
= SWAP32 (ah
->magic
);
2817 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
2818 ah
->total_size
= SWAP32 (ah
->total_size
);
2819 ah
->data_start
= SWAP32 (ah
->data_start
);
2820 ah
->data_length
= SWAP32 (ah
->data_length
);
2821 ah
->flags
= SWAP16 (ah
->flags
);
2822 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
2824 ae
= (attr_entry_t
*)(&ah
[1]);
2825 for (i
= 0; i
< count
; i
++)
2827 attr_entry_t
*next
= ATTR_NEXT(ae
);
2828 ae
->offset
= SWAP32 (ae
->offset
);
2829 ae
->length
= SWAP32 (ae
->length
);
2830 ae
->flags
= SWAP16 (ae
->flags
);
2838 static const u_int32_t emptyfinfo
[8] = {0};
2841 * Given an Apple Double file in src, turn it into a
2842 * normal file (possibly with multiple forks, EAs, and
2845 static int copyfile_unpack(copyfile_state_t s
)
2848 void * buffer
, * endptr
, * dataptr
= NULL
;
2849 apple_double_header_t
*adhdr
;
2853 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
2854 hdrsize
= (ssize_t
)s
->sb
.st_size
;
2856 hdrsize
= ATTR_MAX_HDR_SIZE
;
2858 buffer
= calloc(1, hdrsize
);
2859 if (buffer
== NULL
) {
2860 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize
);
2864 endptr
= (char*)buffer
+ hdrsize
;
2866 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
2870 copyfile_debug(1, "pread returned: %zd", bytes
);
2874 if (bytes
< hdrsize
)
2877 "pread couldn't read entire header: %d of %d",
2878 (int)bytes
, (int)s
->sb
.st_size
);
2882 adhdr
= (apple_double_header_t
*)buffer
;
2885 * Check for Apple Double file.
2887 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
2888 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
2889 SWAP32(adhdr
->version
) != ADH_VERSION
||
2890 SWAP16(adhdr
->numEntries
) != 2 ||
2891 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
2893 if (COPYFILE_VERBOSE
& s
->flags
)
2894 copyfile_warn("Not a valid Apple Double header");
2901 * Remove any extended attributes on the target.
2904 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2906 char *namebuf
, *name
;
2908 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
2913 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
2916 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
2917 (void)fremovexattr(s
->dst_fd
, name
, 0);
2923 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
2928 * Extract the extended attributes.
2931 * This assumes that the data is already in memory (not
2932 * the case when there are lots of attributes or one of
2933 * the attributes is very large.
2935 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
2937 attr_header_t
*attrhdr
;
2938 attr_entry_t
*entry
;
2942 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
2943 copyfile_warn("bad attribute header: %zu < %zu", hdrsize
, sizeof(attr_header_t
));
2948 attrhdr
= (attr_header_t
*)buffer
;
2949 swap_attrhdr(attrhdr
);
2950 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
2952 if (COPYFILE_VERBOSE
& s
->flags
)
2953 copyfile_warn("bad attribute header");
2957 count
= attrhdr
->num_attrs
;
2958 entry
= (attr_entry_t
*)&attrhdr
[1];
2960 for (i
= 0; i
< count
; i
++)
2964 * First we do some simple sanity checking.
2965 * +) See if entry is within the buffer's range;
2967 * +) Check the attribute name length; if it's longer than the
2968 * maximum, we truncate it down. (We could error out as well;
2969 * I'm not sure which is the better way to go here.)
2971 * +) If, given the name length, it goes beyond the end of
2972 * the buffer, error out.
2974 * +) If the last byte isn't a NUL, make it a NUL. (Since we
2975 * truncated the name length above, we truncate the name here.)
2977 * +) If entry->offset is so large that it causes dataptr to
2978 * go beyond the end of the buffer -- or, worse, so large that
2979 * it wraps around! -- we error out.
2981 * +) If entry->length would cause the entry to go beyond the
2982 * end of the buffer (or, worse, wrap around to before it),
2983 * *or* if the length is larger than the hdrsize, we error out.
2984 * (An explanation of that: what we're checking for there is
2985 * the small range of values such that offset+length would cause
2986 * it to go beyond endptr, and then wrap around past buffer. We
2987 * care about this because we are passing entry->length down to
2988 * fgetxattr() below, and an erroneously large value could cause
2989 * problems there. By making sure that it's less than hdrsize,
2990 * which has already been sanity-checked above, we're safe.
2991 * That may mean that the check against < buffer is unnecessary.)
2993 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
2994 if (COPYFILE_VERBOSE
& s
->flags
)
2995 copyfile_warn("Incomplete or corrupt attribute entry");
3001 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
3002 if (COPYFILE_VERBOSE
& s
->flags
)
3003 copyfile_warn("Incomplete or corrupt attribute entry");
3009 if (entry
->namelen
< 2) {
3010 if (COPYFILE_VERBOSE
& s
->flags
)
3011 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
3017 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
3018 if (COPYFILE_VERBOSE
& s
->flags
)
3019 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
3025 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
3026 if (COPYFILE_VERBOSE
& s
->flags
)
3027 copyfile_warn("Incomplete or corrupt attribute entry");
3033 /* Because namelen includes the NUL, we check one byte back */
3034 if (entry
->name
[entry
->namelen
-1] != 0) {
3035 if (COPYFILE_VERBOSE
& s
->flags
)
3036 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3042 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3043 entry
->name
, entry
->length
, entry
->offset
);
3046 dataptr
= (char *)attrhdr
+ entry
->offset
;
3048 if (dataptr
> endptr
|| dataptr
< buffer
) {
3049 copyfile_debug(1, "Entry %d overflows: offset = %u", i
, entry
->offset
);
3051 s
->err
= EINVAL
; /* Invalid buffer */
3055 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
3056 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
3057 (entry
->length
> (size_t)hdrsize
)) {
3058 if (COPYFILE_VERBOSE
& s
->flags
)
3059 copyfile_warn("Incomplete or corrupt attribute entry");
3060 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3061 i
, entry
->offset
, entry
->length
);
3063 s
->err
= EINVAL
; /* Invalid buffer */
3068 dataptr
= malloc(entry
->length
);
3069 if (dataptr
== NULL
) {
3070 copyfile_debug(1, "no memory for %u bytes\n", entry
->length
);
3075 if (pread(s
->src_fd
, dataptr
, entry
->length
, entry
->offset
) != (ssize_t
)entry
->length
) {
3076 copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry
->length
, entry
->offset
);
3083 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
3085 qtn_file_t tqinfo
= NULL
;
3087 if (s
->qinfo
== NULL
)
3089 tqinfo
= qtn_file_alloc();
3093 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
3095 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
3096 qtn_file_free(tqinfo
);
3108 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
3110 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
3113 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
3114 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3115 s
->xattr_name
= NULL
;
3116 if (rv
== COPYFILE_QUIT
) {
3117 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3121 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3126 if (tqinfo
&& !s
->qinfo
)
3128 qtn_file_free(tqinfo
);
3131 /* Look for ACL data */
3132 else if (strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
3137 char *tcp
= dataptr
;
3139 if (entry
->length
== 0) {
3140 /* Not sure how we got here, but we had one case
3141 * where it was 0. In a normal EA, we can have a 0-byte
3142 * payload. That means nothing in this case, so we'll
3143 * simply skip the EA.
3149 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3150 * however, may not be NUL-terminated. So in that case, we need to
3151 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3153 if (tcp
[entry
->length
- 1] != 0) {
3154 char *tmpstr
= malloc(entry
->length
+ 1);
3155 if (tmpstr
== NULL
) {
3159 strlcpy(tmpstr
, tcp
, entry
->length
+ 1);
3160 acl
= acl_from_text(tmpstr
);
3163 acl
= acl_from_text(tcp
);
3170 if ((fsec_tmp
= filesec_init()) == NULL
)
3172 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
3174 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
3177 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
3179 if (errno
== ENOTSUP
)
3181 if (retry
&& !copyfile_unset_acl(s
))
3187 copyfile_warn("setting security information");
3193 filesec_free(fsec_tmp
);
3200 /* And, finally, everything else */
3203 if (s
->copyIntent
||
3204 _PreserveEA((char*)entry
->name
, s
->copyIntent
) == 1) {
3207 s
->xattr_name
= strdup((char*)entry
->name
);
3209 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3210 if (s
->xattr_name
) {
3211 free(s
->xattr_name
);
3212 s
->xattr_name
= NULL
;
3214 if (rv
== COPYFILE_QUIT
) {
3220 if (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0) == -1) {
3221 if (COPYFILE_VERBOSE
& s
->flags
)
3222 copyfile_warn("error %d setting attribute %s", errno
, entry
->name
);
3226 s
->xattr_name
= strdup((char*)entry
->name
);
3227 rv
= (s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3228 if (s
->xattr_name
) {
3229 free(s
->xattr_name
);
3230 s
->xattr_name
= NULL
;
3232 if (rv
== COPYFILE_QUIT
) {
3240 } else if (s
->statuscb
) {
3242 s
->xattr_name
= strdup((char*)entry
->name
);
3243 s
->totalCopied
= entry
->length
;
3244 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3245 if (s
->xattr_name
) {
3246 free(s
->xattr_name
);
3247 s
->xattr_name
= NULL
;
3249 if (rv
== COPYFILE_QUIT
) {
3261 entry
= ATTR_NEXT(entry
);
3266 * Extract the Finder Info.
3268 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
3273 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
3277 enum { kFinderInvisibleMask
= 1 << 14 };
3279 newFinfo
= (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
;
3280 fFlags
= (uint16_t*)&newFinfo
[8];
3281 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
3284 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3285 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3286 s
->xattr_name
= NULL
;
3287 if (rv
== COPYFILE_QUIT
) {
3291 } else if (rv
== COPYFILE_SKIP
) {
3295 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
3299 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3300 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3301 s
->xattr_name
= NULL
;
3302 if (rv
== COPYFILE_QUIT
) {
3309 } else if (s
->statuscb
) {
3311 s
->xattr_name
= (char *)XATTR_FINDERINFO_NAME
;
3312 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3313 s
->xattr_name
= NULL
;
3314 if (rv
== COPYFILE_QUIT
) {
3320 if (SWAP16(*fFlags
) & kFinderInvisibleMask
)
3321 s
->internal_flags
|= cfMakeFileInvisible
;
3326 * Extract the Resource Fork.
3328 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
3329 adhdr
->entries
[1].length
> 0)
3331 void * rsrcforkdata
= NULL
;
3335 struct timeval tval
[2];
3337 length
= adhdr
->entries
[1].length
;
3338 offset
= adhdr
->entries
[1].offset
;
3339 rsrcforkdata
= malloc(length
);
3341 if (rsrcforkdata
== NULL
) {
3342 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3348 if (fstat(s
->dst_fd
, &sb
) < 0)
3350 copyfile_debug(1, "couldn't stat destination file");
3355 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
3356 if (bytes
< (ssize_t
)length
)
3360 copyfile_debug(1, "couldn't read resource fork");
3365 "couldn't read resource fork (only read %d bytes of %d)",
3366 (int)bytes
, (int)length
);
3373 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3374 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3375 s
->xattr_name
= NULL
;
3376 if (rv
== COPYFILE_QUIT
) {
3382 } else if (rv
== COPYFILE_SKIP
) {
3386 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
3390 * For filesystems that do not natively support named attributes,
3391 * the kernel creates an AppleDouble file that -- for compatabilty
3392 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3393 * structure that says there are no resources. So, if fsetxattr has
3394 * failed, and the resource fork is that empty structure, *and* the
3395 * target file is a directory, then we do nothing with it.
3397 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
3398 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
3399 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
3400 copyfile_debug(2, "not setting empty resource fork on directory");
3406 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3407 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3408 s
->xattr_name
= NULL
;
3409 if (rv
== COPYFILE_CONTINUE
) {
3414 copyfile_debug(1, "error %d setting resource fork attribute", error
);
3417 } else if (s
->statuscb
) {
3419 s
->xattr_name
= (char *)XATTR_RESOURCEFORK_NAME
;
3420 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3421 s
->xattr_name
= NULL
;
3422 if (rv
== COPYFILE_QUIT
) {
3430 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3431 XATTR_RESOURCEFORK_NAME
, (int)length
);
3433 if (!(s
->flags
& COPYFILE_STAT
))
3435 tval
[0].tv_sec
= sb
.st_atime
;
3436 tval
[1].tv_sec
= sb
.st_mtime
;
3437 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
3439 if (futimes(s
->dst_fd
, tval
))
3440 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
3447 if (COPYFILE_STAT
& s
->flags
)
3449 error
= copyfile_stat(s
);
3452 if (buffer
) free(buffer
);
3453 if (dataptr
) free(dataptr
);
3457 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3460 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
3461 size_t qlen
= sizeof(qbuf
);
3463 if (s
->qinfo
== NULL
)
3469 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
3475 *buf
= malloc(qlen
);
3478 memcpy(*buf
, qbuf
, qlen
);
3485 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3491 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
3493 if (errno
!= ENOENT
)
3496 if (COPYFILE_VERBOSE
& s
->flags
)
3497 copyfile_warn("getting acl");
3503 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
3506 * acl_to_text() doesn't include the NUL at the endo
3507 * in it's count (*len). It does, however, promise to
3508 * return a valid C string, so we need to up the count
3512 *buf
= malloc(*len
);
3514 memcpy(*buf
, acl_text
, *len
);
3519 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
3526 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
3529 char *databuf
= NULL
;
3534 * do COPYFILE_COPY_XATTR here; no need to
3535 * the work if we want to skip.
3542 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3544 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3545 s
->xattr_name
= NULL
;
3546 if (rv
== COPYFILE_SKIP
) {
3550 if (rv
== COPYFILE_QUIT
) {
3556 /* Get the resource fork size */
3557 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
3559 if (COPYFILE_VERBOSE
& s
->flags
)
3560 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
3564 if (datasize
> INT_MAX
) {
3572 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3575 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3576 s
->xattr_name
= NULL
;
3577 if (rv
== COPYFILE_QUIT
) {
3583 if ((databuf
= malloc(datasize
)) == NULL
)
3585 copyfile_warn("malloc");
3590 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
3592 if (COPYFILE_VERBOSE
& s
->flags
)
3593 copyfile_warn("couldn't read entire resource fork");
3598 /* Write the resource fork to disk. */
3599 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
3601 if (COPYFILE_VERBOSE
& s
->flags
)
3602 copyfile_warn("couldn't write resource fork");
3607 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3608 if (rv
== COPYFILE_QUIT
) {
3613 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3614 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
3615 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
3618 if (ret
== -1 && s
->statuscb
)
3621 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3622 if (rv
== COPYFILE_CONTINUE
)
3625 if (s
->xattr_name
) {
3626 s
->xattr_name
= NULL
;
3633 * Do status callback here
3634 * If ret == -1, then error callback
3640 * The opposite of copyfile_unpack(), obviously.
3642 static int copyfile_pack(copyfile_state_t s
)
3644 char *attrnamebuf
= NULL
, *endnamebuf
;
3645 void *databuf
= NULL
;
3646 attr_header_t
*filehdr
, *endfilehdr
;
3647 attr_entry_t
*entry
;
3648 ssize_t listsize
= 0;
3654 int hasrsrcfork
= 0;
3656 int seenq
= 0; // Have we seen any quarantine info already?
3658 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_HDR_SIZE
);
3660 if (filehdr
== NULL
) {
3664 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_HDR_SIZE
);
3667 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
3668 if (attrnamebuf
== NULL
) {
3672 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
3676 * Fill in the Apple Double Header defaults.
3678 filehdr
->appledouble
.magic
= ADH_MAGIC
;
3679 filehdr
->appledouble
.version
= ADH_VERSION
;
3680 filehdr
->appledouble
.numEntries
= 2;
3681 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
3682 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
3683 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
3684 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
3685 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
3686 filehdr
->appledouble
.entries
[1].length
= 0;
3687 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
3690 * Fill in the initial Attribute Header.
3692 filehdr
->magic
= ATTR_HDR_MAGIC
;
3693 filehdr
->debug_tag
= 0;
3694 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
3697 * Collect the attribute names.
3699 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3702 * Test if there are acls to copy
3704 if (COPYFILE_ACL
& s
->flags
)
3706 acl_t temp_acl
= NULL
;
3707 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
3709 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
3712 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
3713 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
3714 endnamebuf
= attrnamebuf
+ offset
;
3720 if (COPYFILE_XATTR
& s
->flags
)
3722 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3723 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
3725 copyfile_debug(2, "no extended attributes found (%d)", errno
);
3727 if (listsize
> left
)
3729 copyfile_debug(1, "extended attribute list too long");
3733 endnamebuf
= attrnamebuf
+ offset
+ (listsize
> 0 ? listsize
: 0);
3734 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
3740 sort_xattrname_list(attrnamebuf
, endnamebuf
- attrnamebuf
);
3742 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
3744 namelen
= strlen(nameptr
) + 1;
3745 /* Skip over FinderInfo or Resource Fork names */
3746 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
3747 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
3750 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
3754 /* The system should prevent this from happening, but... */
3755 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
3756 namelen
= XATTR_MAXNAMELEN
+ 1;
3758 if (s
->copyIntent
&&
3759 _PreserveEA(nameptr
, s
->copyIntent
) == 0) {
3761 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
3762 memmove(nameptr
, nameptr
+ namelen
, amt
);
3763 endnamebuf
-= namelen
;
3764 /* Set namelen to 0 so continue doesn't miss names */
3771 char eaname
[namelen
];
3772 bcopy(nameptr
, eaname
, namelen
);
3773 eaname
[namelen
] = 0; // Just to be sure!
3774 s
->xattr_name
= eaname
;
3775 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3776 s
->xattr_name
= NULL
;
3777 if (rv
== COPYFILE_QUIT
) {
3781 } else if (rv
== COPYFILE_SKIP
) {
3782 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
3783 memmove(nameptr
, nameptr
+ namelen
, amt
);
3784 endnamebuf
-= namelen
;
3785 /* Set namelen to 0 so continue doesn't miss names */
3790 entry
->namelen
= namelen
;
3792 if (nameptr
+ namelen
> endnamebuf
) {
3797 bcopy(nameptr
, &entry
->name
[0], namelen
);
3798 copyfile_debug(2, "copied name [%s]", entry
->name
);
3800 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
3801 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
3803 if ((void*)entry
>= (void*)endfilehdr
) {
3808 /* Update the attributes header. */
3809 filehdr
->num_attrs
++;
3810 filehdr
->data_start
+= (u_int32_t
)entrylen
;
3815 * If we have any quarantine data, we always pack it.
3816 * But if we've already got it in the EA list, don't put it in again.
3818 if (s
->qinfo
&& !seenq
)
3820 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3821 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3822 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
3827 * Collect the attribute data.
3829 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3831 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
+ 1)
3833 namelen
= strlen(nameptr
);
3835 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
3836 copyfile_pack_acl(s
, &databuf
, &datasize
);
3837 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
3839 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
3841 /* Check for Finder Info. */
3842 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
3847 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3848 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3849 s
->xattr_name
= NULL
;
3850 if (rv
== COPYFILE_QUIT
)
3852 s
->xattr_name
= NULL
;
3857 else if (rv
== COPYFILE_SKIP
)
3859 s
->xattr_name
= NULL
;
3863 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3864 s
->xattr_name
= NULL
;
3865 if (rv
== COPYFILE_QUIT
)
3872 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
3877 s
->xattr_name
= strdup(nameptr
);
3878 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3879 if (s
->xattr_name
) {
3880 free(s
->xattr_name
);
3881 s
->xattr_name
= NULL
;
3883 if (rv
== COPYFILE_QUIT
) {
3888 if (COPYFILE_VERBOSE
& s
->flags
)
3889 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3890 } else if (datasize
!= 32)
3892 if (COPYFILE_VERBOSE
& s
->flags
)
3893 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
3896 if (COPYFILE_VERBOSE
& s
->flags
)
3897 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3898 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
3901 s
->xattr_name
= strdup(nameptr
);
3902 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3903 if (s
->xattr_name
) {
3904 free(s
->xattr_name
);
3905 s
->xattr_name
= NULL
;
3907 if (rv
== COPYFILE_QUIT
) {
3913 continue; /* finder info doesn't have an attribute entry */
3915 /* Check for Resource Fork. */
3916 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
3922 /* Just a normal attribute. */
3926 s
->xattr_name
= strdup(nameptr
);
3928 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3929 if (s
->xattr_name
) {
3930 free(s
->xattr_name
);
3931 s
->xattr_name
= NULL
;
3934 * Due to the nature of the packed file, we can't skip at this point.
3936 if (rv
== COPYFILE_QUIT
)
3943 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
3948 if (COPYFILE_VERBOSE
& s
->flags
)
3949 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3953 s
->xattr_name
= strdup(nameptr
);
3954 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3955 if (s
->xattr_name
) {
3956 free(s
->xattr_name
);
3957 s
->xattr_name
= NULL
;
3959 if (rv
== COPYFILE_QUIT
)
3968 if (datasize
> XATTR_MAXATTRLEN
)
3970 if (COPYFILE_VERBOSE
& s
->flags
)
3971 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
3974 databuf
= malloc(datasize
);
3975 if (databuf
== NULL
) {
3979 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
3982 s
->xattr_name
= strdup(nameptr
);
3983 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3984 if (s
->xattr_name
) {
3985 free(s
->xattr_name
);
3986 s
->xattr_name
= NULL
;
3988 if (rv
== COPYFILE_QUIT
) {
3996 entry
->length
= (u_int32_t
)datasize
;
3997 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
3999 filehdr
->data_length
+= (u_int32_t
)datasize
;
4003 * This assumes that the data is fits in memory (not
4004 * the case when there are lots of attributes or one of
4005 * the attributes is very large.
4007 if (entry
->offset
> ATTR_MAX_SIZE
||
4008 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
4011 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
4014 if (pwrite(s
->dst_fd
, databuf
, datasize
, entry
->offset
) != datasize
) {
4020 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
4022 /* bump to next entry */
4023 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
4024 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
4027 /* Now we know where the resource fork data starts. */
4028 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
4030 /* We also know the size of the "Finder Info entry. */
4031 filehdr
->appledouble
.entries
[0].length
=
4032 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
4034 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
4036 /* Copy Resource Fork. */
4037 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
4040 /* Write the header to disk. */
4041 datasize
= filehdr
->data_start
;
4043 swap_adhdr(&filehdr
->appledouble
);
4044 swap_attrhdr(filehdr
);
4046 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
4048 if (COPYFILE_VERBOSE
& s
->flags
)
4049 copyfile_warn("couldn't write file header");
4054 if (filehdr
) free(filehdr
);
4055 if (attrnamebuf
) free(attrnamebuf
);
4060 return copyfile_stat(s
);