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>
54 #if !TARGET_OS_EMBEDDED
55 #include <quarantine.h>
57 #define XATTR_QUARANTINE_NAME qtn_xattr_name
58 #else /* TARGET_OS_EMBEDDED */
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 void qtn_file_free(void *x
) { return; }
64 static int qtn_file_apply_to_fd(void *x
, int y
) { return 0; }
65 static char *qtn_error(int x
) { return NULL
; }
66 static int qtn_file_to_data(void *x
, char *y
, size_t z
) { return -1; }
67 static void *qtn_file_clone(void *x
) { return NULL
; }
68 #define XATTR_QUARANTINE_NAME "figgledidiggledy"
69 #endif /* TARGET_OS_EMBEDDED */
73 enum cfInternalFlags
{
75 cfMakeFileInvisible
= 1 << 1,
76 cfSawDecmpEA
= 1 << 2,
80 * The state structure keeps track of
81 * the source filename, the destination filename, their
82 * associated file-descriptors, the stat infomration for the
83 * source file, the security information for the source file,
84 * the flags passed in for the copy, a pointer to place statistics
85 * (not currently implemented), debug flags, and a pointer to callbacks
86 * (not currently implemented).
88 struct _copyfile_state
96 copyfile_flags_t flags
;
97 unsigned int internal_flags
;
100 copyfile_callback_t statuscb
;
102 qtn_file_t qinfo
; /* Quarantine information -- probably NULL */
103 filesec_t original_fsec
;
104 filesec_t permissive_fsec
;
112 #define _ACL_ENTRY_MAGIC 0xac1ac101
114 guid_t ae_applicable
;
119 #define PACE(ace) do { \
120 struct acl_entry *__t = (struct acl_entry*)(ace); \
121 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
126 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
127 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
131 acl_compare_permset_np(acl_permset_t p1
, acl_permset_t p2
)
133 struct pm
{ u_int32_t ap_perms
; } *ps1
, *ps2
;
134 ps1
= (struct pm
*) p1
;
135 ps2
= (struct pm
*) p2
;
137 return ((ps1
->ap_perms
== ps2
->ap_perms
) ? 1 : 0);
142 doesdecmpfs(int fd
) {
143 #ifdef DECMPFS_XATTR_NAME
145 struct attrlist attrs
;
146 char volroot
[MAXPATHLEN
+ 1];
150 vol_capabilities_attr_t volAttrs
;
153 (void)fstatfs(fd
, &sfs
);
154 strlcpy(volroot
, sfs
.f_mntonname
, sizeof(volroot
));
156 memset(&attrs
, 0, sizeof(attrs
));
157 attrs
.bitmapcount
= ATTR_BIT_MAP_COUNT
;
158 attrs
.volattr
= ATTR_VOL_CAPABILITIES
;
160 rv
= getattrlist(volroot
, &attrs
, &volattrs
, sizeof(volattrs
), 0);
163 (volattrs
.volAttrs
.capabilities
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
) &&
164 (volattrs
.volAttrs
.valid
[VOL_CAPABILITIES_FORMAT
] & VOL_CAP_FMT_DECMPFS_COMPRESSION
)) {
173 sort_xattrname_list(void *start
, size_t length
)
180 /* If it's not a proper C string at the end, don't do anything */
181 if (((char*)start
)[length
] != 0)
184 * In order to sort the list of names, we need to
185 * make a list of pointers to strings. To do that,
186 * we need to run through the buffer, and find the
187 * beginnings of strings.
189 nel
= 10; // Most files don't have many EAs
190 ptrs
= (char**)calloc(nel
, sizeof(char*));
197 char *curPtr
= start
;
198 while (curPtr
< (char*)start
+ length
) {
199 printf("%s\n", curPtr
);
200 curPtr
+= strlen(curPtr
) + 1;
205 tmp
= ptrs
[indx
++] = (char*)start
;
207 while (tmp
= memchr(tmp
, 0, ((char*)start
+ length
) - tmp
)) {
210 ptrs
= realloc(ptrs
, sizeof(char**) * nel
);
214 ptrs
[indx
++] = ++tmp
;
217 printf("Unsorted:\n");
218 for (nel
= 0; nel
< indx
-1; nel
++) {
219 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
222 qsort_b(ptrs
, indx
-1, sizeof(char*), ^(const void *left
, const void *right
) {
224 char *lstr
= *(char**)left
, *rstr
= *(char**)right
;
225 rv
= strcmp(lstr
, rstr
);
230 for (nel
= 0; nel
< indx
-1; nel
++) {
231 printf("\tEA %d = `%s'\n", nel
, ptrs
[nel
]);
235 * Now that it's sorted, we need to make a copy, so we can
236 * move the strings around into the new order. Then we
237 * copy that on top of the old buffer, and we're done.
239 char *copy
= malloc(length
);
244 for (i
= 0; i
< indx
-1; i
++) {
245 size_t len
= strlen(ptrs
[i
]);
246 memcpy(curPtr
, ptrs
[i
], len
+1);
249 memcpy(start
, copy
, length
);
260 * Internally, the process is broken into a series of
263 static int copyfile_open (copyfile_state_t
);
264 static int copyfile_close (copyfile_state_t
);
265 static int copyfile_data (copyfile_state_t
);
266 static int copyfile_stat (copyfile_state_t
);
267 static int copyfile_security (copyfile_state_t
);
268 static int copyfile_xattr (copyfile_state_t
);
269 static int copyfile_pack (copyfile_state_t
);
270 static int copyfile_unpack (copyfile_state_t
);
272 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
273 static filesec_t
copyfile_fix_perms(copyfile_state_t
, filesec_t
*);
274 static int copyfile_preamble(copyfile_state_t
*s
, copyfile_flags_t flags
);
275 static int copyfile_internal(copyfile_state_t state
, copyfile_flags_t flags
);
276 static int copyfile_unset_posix_fsec(filesec_t
);
277 static int copyfile_quarantine(copyfile_state_t
);
279 #define COPYFILE_DEBUG (1<<31)
280 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
282 #ifndef _COPYFILE_TEST
283 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
284 # define copyfile_debug(d, str, ...) \
286 if (s && (d <= s->debug)) {\
287 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
291 #define copyfile_warn(str, ...) \
292 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
293 # define copyfile_debug(d, str, ...) \
295 if (s && (d <= s->debug)) {\
296 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
301 static int copyfile_quarantine(copyfile_state_t s
)
304 if (s
->qinfo
== NULL
)
307 s
->qinfo
= qtn_file_alloc();
308 if (s
->qinfo
== NULL
)
313 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
315 qtn_file_free(s
->qinfo
);
326 add_uberace(acl_t
*acl
)
329 acl_permset_t permset
;
332 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
336 * First, we create an entry, and give it the special name
337 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
338 * After that, we clear out all the permissions in it, and
339 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
340 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
341 * the functionality, and put this into the ACL.
343 if (acl_create_entry_np(acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
345 if (acl_get_permset(entry
, &permset
) == -1) {
346 copyfile_warn("acl_get_permset");
349 if (acl_clear_perms(permset
) == -1) {
350 copyfile_warn("acl_clear_permset");
353 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1) {
354 copyfile_warn("add ACL_WRITE_DATA");
357 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1) {
358 copyfile_warn("add ACL_WRITE_ATTRIBUTES");
361 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1) {
362 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES");
365 if (acl_add_perm(permset
, ACL_APPEND_DATA
) == -1) {
366 copyfile_warn("add ACL_APPEND_DATA");
369 if (acl_add_perm(permset
, ACL_WRITE_SECURITY
) == -1) {
370 copyfile_warn("add ACL_WRITE_SECURITY");
373 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1) {
374 copyfile_warn("set ACL_EXTENDED_ALLOW");
378 if(acl_set_permset(entry
, permset
) == -1) {
379 copyfile_warn("acl_set_permset");
382 if(acl_set_qualifier(entry
, qual
) == -1) {
383 copyfile_warn("acl_set_qualifier");
393 is_uberace(acl_entry_t ace
)
396 acl_permset_t perms
, tperms
;
403 // Who am I, and who is the ACE for?
404 mbr_uid_to_uuid(geteuid(), myuuid
);
405 qual
= (guid_t
*)acl_get_qualifier(ace
);
407 // Need to create a temporary acl, so I can get the uberace template.
413 if (acl_get_entry(tacl
, ACL_FIRST_ENTRY
, &tentry
) != 0) {
416 acl_get_permset(tentry
, &tperms
);
419 acl_get_tag_type(ace
, &tag
);
420 acl_get_permset(ace
, &perms
);
422 if (tag
== ACL_EXTENDED_ALLOW
&&
423 (memcmp(qual
, myuuid
, sizeof(myuuid
)) == 0) &&
424 acl_compare_permset_np(tperms
, perms
))
439 remove_uberace(int fd
, struct stat
*sbuf
)
441 filesec_t fsec
= NULL
;
446 fsec
= filesec_init();
451 if (fstatx_np(fd
, &sb
, fsec
) != 0) {
452 if (errno
== ENOTSUP
)
457 if (filesec_get_property(fsec
, FILESEC_ACL
, &acl
) != 0) {
461 if (acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
) == 0) {
462 if (is_uberace(entry
))
464 mode_t m
= sbuf
->st_mode
& ~S_IFMT
;
466 if (acl_delete_entry(acl
, entry
) != 0 ||
467 filesec_set_property(fsec
, FILESEC_ACL
, &acl
) != 0 ||
468 filesec_set_property(fsec
, FILESEC_MODE
, &m
) != 0 ||
469 fchmodx_np(fd
, fsec
) != 0)
482 fchmod(fd
, sbuf
->st_mode
& ~S_IFMT
);
487 reset_security(copyfile_state_t s
)
489 /* If we haven't reset the file security information
490 * (COPYFILE_SECURITY is not set in flags)
491 * restore back the permissions the file had originally
493 * One of the reasons this seems so complicated is that
494 * it is partially at odds with copyfile_security().
496 * Simplisticly, we are simply trying to make sure we
497 * only copy what was requested, and that we don't stomp
498 * on what wasn't requested.
501 #ifdef COPYFILE_RECURSIVE
502 if (s
->dst_fd
> -1) {
505 if (s
->src_fd
> -1 && (s
->flags
& COPYFILE_STAT
))
506 fstat(s
->src_fd
, &sbuf
);
508 fstat(s
->dst_fd
, &sbuf
);
510 if (!(s
->internal_flags
& cfDelayAce
))
511 remove_uberace(s
->dst_fd
, &sbuf
);
514 if (s
->permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
515 if (s
->flags
& COPYFILE_ACL
) {
516 /* Just need to reset the BSD information -- mode, owner, group */
517 (void)fchown(s
->dst_fd
, s
->dst_sb
.st_uid
, s
->dst_sb
.st_gid
);
518 (void)fchmod(s
->dst_fd
, s
->dst_sb
.st_mode
);
521 * flags is either COPYFILE_STAT, or neither; if it's
522 * neither, then we restore both ACL and POSIX permissions;
523 * if it's STAT, however, then we only want to restore the
524 * ACL (which may be empty). We do that by removing the
525 * POSIX information from the filesec object.
527 if (s
->flags
& COPYFILE_STAT
) {
528 copyfile_unset_posix_fsec(s
->original_fsec
);
530 if (fchmodx_np(s
->dst_fd
, s
->original_fsec
) < 0 && errno
!= ENOTSUP
)
531 copyfile_warn("restoring security information");
535 if (s
->permissive_fsec
) {
536 filesec_free(s
->permissive_fsec
);
537 s
->permissive_fsec
= NULL
;
540 if (s
->original_fsec
) {
541 filesec_free(s
->original_fsec
);
542 s
->original_fsec
= NULL
;
550 * copytree -- recursively copy a hierarchy.
552 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
553 * Care is taken to keep the ACLs set up correctly, in addition to the
554 * normal copying that is done. (When copying a hierarchy, we can't
555 * get rid of the "allow-all-writes" ACE on a directory until we're done
556 * copying the *contents* of the directory.)
558 * The other big difference from copyfile (for the moment) is that copytree()
559 * will use a call-back function to pass along information about what is
560 * about to be copied, and whether or not it succeeded.
562 * copytree() is called from copyfile() -- but copytree() itself then calls
563 * copyfile() to copy each individual object.
565 * XXX - no effort is made to handle overlapping hierarchies at the moment.
570 copytree(copyfile_state_t s
)
574 int (*sfunc
)(const char *, struct stat
*);
575 copyfile_callback_t status
= NULL
;
576 char srcisdir
= 0, dstisdir
= 0, dstexists
= 0;
579 const char *dstpathsep
= "";
581 char srcpath
[PATH_MAX
* 2 + 1], dstpath
[PATH_MAX
* 2 + 1];
587 const char *paths
[2] = { 0 };
588 unsigned int flags
= 0;
589 int fts_flags
= FTS_NOCHDIR
;
596 if (s
->flags
& (COPYFILE_MOVE
| COPYFILE_UNLINK
| COPYFILE_CHECK
| COPYFILE_PACK
| COPYFILE_UNPACK
)) {
602 flags
= s
->flags
& (COPYFILE_ALL
| COPYFILE_NOFOLLOW
| COPYFILE_VERBOSE
);
604 paths
[0] = src
= s
->src
;
607 if (src
== NULL
|| dst
== NULL
) {
613 sfunc
= (flags
& COPYFILE_NOFOLLOW_SRC
) ? lstat
: stat
;
614 if ((sfunc
)(src
, &sbuf
) == -1) {
618 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
622 sfunc
= (flags
& COPYFILE_NOFOLLOW_DST
) ? lstat
: stat
;
623 if ((sfunc
)(dst
, &sbuf
) == -1) {
624 if (errno
!= ENOENT
) {
630 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
636 // This doesn't handle filesystem crossing and case sensitivity
637 // So there's got to be a better way
639 if (realpath(src
, srcpath
) == NULL
) {
644 if (realpath(dst
, dstpath
) == NULL
&&
645 (errno
== ENOENT
&& realpath(dirname(dst
), dstpath
) == NULL
)) {
649 if (strstr(srcpath
, dstpath
) != NULL
) {
655 srcroot
= basename((char*)src
);
656 if (srcroot
== NULL
) {
662 * To work on as well:
663 * We have a few cases when copying a hierarchy:
664 * 1) src is a non-directory, dst is a directory;
665 * 2) src is a non-directory, dst is a non-directory;
666 * 3) src is a non-directory, dst does not exist;
667 * 4) src is a directory, dst is a directory;
668 * 5) src is a directory, dst is a non-directory;
669 * 6) src is a directory, dst does not exist
671 * (1) copies src to dst/basename(src).
672 * (2) fails if COPYFILE_EXCLUSIVE is set, otherwise copies src to dst.
673 * (3) and (6) copy src to the name dst.
674 * (4) copies the contents of src to the contents of dst.
679 // copy /path/to/src to /path/to/dst/src
680 // Append "/" and (fts_path - strlen(basename(src))) to dst?
682 slash
= strrchr(src
, '/');
686 offset
= slash
- src
+ 1;
688 // copy /path/to/src to /path/to/dst
689 // append (fts_path + strlen(src)) to dst?
691 offset
= strlen(src
);
694 if (s
->flags
| COPYFILE_NOFOLLOW_SRC
)
695 fts_flags
|= FTS_PHYSICAL
;
697 fts_flags
|= FTS_LOGICAL
;
699 fts
= fts_open((char * const *)paths
, fts_flags
, NULL
);
701 status
= s
->statuscb
;
702 while ((ftsent
= fts_read(fts
)) != NULL
) {
704 char *dstfile
= NULL
;
706 copyfile_state_t tstate
= copyfile_state_alloc();
707 if (tstate
== NULL
) {
712 tstate
->statuscb
= s
->statuscb
;
713 tstate
->ctx
= s
->ctx
;
714 asprintf(&dstfile
, "%s%s%s", dst
, dstpathsep
, ftsent
->fts_path
+ offset
);
715 if (dstfile
== NULL
) {
716 copyfile_state_free(tstate
);
721 switch (ftsent
->fts_info
) {
723 tstate
->internal_flags
|= cfDelayAce
;
724 cmd
= COPYFILE_RECURSE_DIR
;
730 cmd
= COPYFILE_RECURSE_FILE
;
733 cmd
= COPYFILE_RECURSE_DIR_CLEANUP
;
740 errno
= ftsent
->fts_errno
;
742 rv
= (*status
)(COPYFILE_RECURSE_ERROR
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
743 if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
747 if (rv
== COPYFILE_QUIT
) {
760 if (cmd
== COPYFILE_RECURSE_DIR
|| cmd
== COPYFILE_RECURSE_FILE
) {
762 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
763 if (rv
== COPYFILE_SKIP
) {
764 if (cmd
== COPYFILE_RECURSE_DIR
) {
765 rv
= fts_set(fts
, ftsent
, FTS_SKIP
);
767 rv
= (*status
)(0, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
768 if (rv
== COPYFILE_QUIT
)
774 if (rv
== COPYFILE_QUIT
) {
775 retval
= -1; errno
= 0;
779 int tmp_flags
= (cmd
== COPYFILE_RECURSE_DIR
) ? (flags
& ~COPYFILE_STAT
) : flags
;
780 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, tmp_flags
);
783 rv
= (*status
)(cmd
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
784 if (rv
== COPYFILE_QUIT
) {
796 rv
= (*status
)(cmd
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
797 if (rv
== COPYFILE_QUIT
) {
798 retval
= -1; errno
= 0;
802 } else if (cmd
== COPYFILE_RECURSE_DIR_CLEANUP
) {
804 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
805 if (rv
== COPYFILE_QUIT
) {
806 retval
= -1; errno
= 0;
808 } else if (rv
== COPYFILE_SKIP
) {
813 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, (flags
& COPYFILE_NOFOLLOW
) | COPYFILE_STAT
);
816 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
817 if (rv
== COPYFILE_QUIT
) {
820 } else if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
821 if (rv
== COPYFILE_CONTINUE
)
832 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
833 if (rv
== COPYFILE_QUIT
) {
834 retval
= -1; errno
= 0;
844 copyfile_state_free(tstate
);
858 * fcopyfile() is used to copy a source file descriptor to a destination file
859 * descriptor. This allows an application to figure out how it wants to open
860 * the files (doing various security checks, perhaps), and then just pass in
861 * the file descriptors.
863 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
866 copyfile_state_t s
= state
;
869 if (src_fd
< 0 || dst_fd
< 0)
875 if (copyfile_preamble(&s
, flags
) < 0)
878 copyfile_debug(2, "set src_fd <- %d", src_fd
);
879 if (s
->src_fd
== -2 && src_fd
> -1)
882 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
884 if (errno
== ENOTSUP
|| errno
== EPERM
)
885 fstat(s
->src_fd
, &s
->sb
);
888 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
894 /* prevent copying on unsupported types */
895 switch (s
->sb
.st_mode
& S_IFMT
)
906 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
907 if (s
->dst_fd
== -2 && dst_fd
> -1)
910 (void)fstat(s
->dst_fd
, &dst_sb
);
911 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
913 (void)copyfile_quarantine(s
);
915 ret
= copyfile_internal(s
, flags
);
917 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
919 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
928 copyfile_state_free(s
);
937 * the original copyfile() routine; this copies a source file to a destination
938 * file. Note that because we need to set the names in the state variable, this
939 * is not just the same as opening the two files, and then calling fcopyfile().
940 * Oh, if only life were that simple!
942 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
946 copyfile_state_t s
= state
;
949 if (src
== NULL
&& dst
== NULL
)
955 if (copyfile_preamble(&s
, flags
) < 0)
961 * This macro is... well, it's not the worst thing you can do with cpp, not
962 * by a long shot. Essentially, we are setting the filename (src or dst)
963 * in the state structure; since the structure may not have been cleared out
964 * before being used again, we do some of the cleanup here: if the given
965 * filename (e.g., src) is set, and state->src is not equal to that, then
966 * we need to check to see if the file descriptor had been opened, and if so,
967 * close it. After that, we set state->src to be a copy of the given filename,
968 * releasing the old copy if necessary.
970 #define COPYFILE_SET_FNAME(NAME, S) \
972 if (NAME != NULL) { \
973 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
974 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
975 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
976 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
977 close(S->NAME##_fd); \
985 if ((S->NAME = strdup(NAME)) == NULL) \
990 COPYFILE_SET_FNAME(src
, s
);
991 COPYFILE_SET_FNAME(dst
, s
);
993 if (s
->flags
& COPYFILE_RECURSIVE
) {
999 * Get a copy of the source file's security settings
1001 if ((s
->original_fsec
= filesec_init()) == NULL
)
1004 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
1005 ((dst_sb
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1006 if (s
->permissive_fsec
)
1007 free(s
->permissive_fsec
);
1008 s
->permissive_fsec
= NULL
;
1009 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
1012 * copyfile_fix_perms() will make a copy of the permission set,
1013 * and insert at the beginning an ACE that ensures we can write
1014 * to the file and set attributes.
1017 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
1020 * Set the permissions for the destination to our copy.
1021 * We should get ENOTSUP from any filesystem that simply
1022 * doesn't support it.
1024 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
1026 copyfile_warn("setting security information");
1027 filesec_free(s
->permissive_fsec
);
1028 s
->permissive_fsec
= NULL
;
1031 } else if (errno
== ENOENT
) {
1036 * If COPYFILE_CHECK is set in flags, then all we are going to do
1037 * is see what kinds of things WOULD have been copied (see
1038 * copyfile_check() below). We return that value.
1040 if (COPYFILE_CHECK
& flags
)
1042 ret
= copyfile_check(s
);
1044 } else if ((ret
= copyfile_open(s
)) < 0)
1047 (void)fcntl(s
->src_fd
, F_NOCACHE
, 1);
1048 (void)fcntl(s
->dst_fd
, F_NOCACHE
, 1);
1050 ret
= copyfile_internal(s
, flags
);
1054 #ifdef COPYFILE_RECURSIVE
1055 if (!(flags
& COPYFILE_STAT
)) {
1058 /* Just need to reset the BSD information -- mode, owner, group */
1059 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
1060 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
1067 if (s
->src
&& (flags
& COPYFILE_MOVE
))
1068 (void)remove(s
->src
);
1071 if (state
== NULL
) {
1073 copyfile_state_free(s
);
1089 * Shared prelude to the {f,}copyfile(). This initializes the
1090 * state variable, if necessary, and also checks for both debugging
1091 * and disabling environment variables.
1093 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
1099 if ((*state
= copyfile_state_alloc()) == NULL
)
1105 if (COPYFILE_DEBUG
& flags
)
1108 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
1111 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
1113 /* clamp s->debug to 1 if the environment variable is not parsable */
1114 if (s
->debug
== 0 && errno
!= 0)
1117 copyfile_debug(2, "debug value set to: %d", s
->debug
);
1121 /* Temporarily disabled */
1122 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
1124 copyfile_debug(1, "copyfile disabled");
1128 copyfile_debug(2, "setting flags: %d", s
->flags
);
1135 * The guts of {f,}copyfile().
1136 * This looks through the flags in a particular order, and calls the
1137 * associated functions.
1139 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
1143 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1145 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1151 * COPYFILE_PACK causes us to create an Apple Double version of the
1152 * source file, and puts it into the destination file. See
1153 * copyfile_pack() below for all the gory details.
1155 if (COPYFILE_PACK
& flags
)
1157 if ((ret
= copyfile_pack(s
)) < 0)
1159 if (s
->dst
) unlink(s
->dst
);
1166 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1167 * The goal there is to take an Apple Double file, and turn it
1168 * into a normal file (with data fork, resource fork, modes,
1169 * extended attributes, ACLs, etc.).
1171 if (COPYFILE_UNPACK
& flags
)
1173 if ((ret
= copyfile_unpack(s
)) < 0)
1179 * If we have quarantine info set, we attempt
1180 * to apply it to dst_fd. We don't care if
1181 * it fails, not yet anyway.
1184 int qr
= qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1189 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
1190 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1191 s
->xattr_name
= NULL
;
1192 if (rv
== COPYFILE_QUIT
) {
1193 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1198 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1206 * COPYFILE_XATTR tells us to copy the extended attributes;
1207 * this is seperate from the extended security (aka ACLs),
1208 * however. If we succeed in this, we continue to the next
1209 * stage; if we fail, we return with an error value. Note
1210 * that we fail if the errno is ENOTSUP, but we don't print
1211 * a warning in that case.
1213 if (COPYFILE_XATTR
& flags
)
1215 if ((ret
= copyfile_xattr(s
)) < 0)
1217 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1218 copyfile_warn("error processing extended attributes");
1224 * Simialr to above, this tells us whether or not to copy
1225 * the non-meta data portion of the file. We attempt to
1226 * remove (via unlink) the destination file if we fail.
1228 if (COPYFILE_DATA
& flags
)
1230 if ((ret
= copyfile_data(s
)) < 0)
1232 copyfile_warn("error processing data");
1233 if (s
->dst
&& unlink(s
->dst
))
1234 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1240 * COPYFILE_SECURITY requests that we copy the security, both
1241 * extended and mundane (that is, ACLs and POSIX).
1243 if (COPYFILE_SECURITY
& flags
)
1245 if ((ret
= copyfile_security(s
)) < 0)
1247 copyfile_warn("error processing security information");
1252 if (COPYFILE_STAT
& flags
)
1254 if ((ret
= copyfile_stat(s
)) < 0)
1256 copyfile_warn("error processing POSIX information");
1270 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1272 copyfile_state_t
copyfile_state_alloc(void)
1274 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1280 s
->fsec
= filesec_init();
1288 * copyfile_state_free() returns the memory allocated to the state structure.
1289 * It also closes the file descriptors, if they've been opened.
1291 int copyfile_state_free(copyfile_state_t s
)
1296 filesec_free(s
->fsec
);
1298 if (s
->original_fsec
)
1299 filesec_free(s
->original_fsec
);
1301 if (s
->permissive_fsec
)
1302 filesec_free(s
->permissive_fsec
);
1305 qtn_file_free(s
->qinfo
);
1307 if (copyfile_close(s
) < 0)
1309 copyfile_warn("error closing files");
1313 free(s
->xattr_name
);
1324 * Should we worry if we can't close the source? NFS says we
1325 * should, but it's pretty late for us at this point.
1327 static int copyfile_close(copyfile_state_t s
)
1329 if (s
->src
&& s
->src_fd
>= 0)
1332 if (s
->dst
&& s
->dst_fd
>= 0) {
1333 if (close(s
->dst_fd
))
1341 * The purpose of this function is to set up a set of permissions
1342 * (ACL and traditional) that lets us write to the file. In the
1343 * case of ACLs, we do this by putting in a first entry that lets
1344 * us write data, attributes, and extended attributes. In the case
1345 * of traditional permissions, we set the S_IWUSR (user-write)
1348 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1350 filesec_t ret_fsec
= NULL
;
1354 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1357 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1359 #ifdef COPYFILE_RECURSIVE
1360 if (add_uberace(&acl
))
1364 acl_permset_t permset
;
1367 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1371 * First, we create an entry, and give it the special name
1372 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1373 * After that, we clear out all the permissions in it, and
1374 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1375 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1376 * the functionality, and put this into the ACL.
1378 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1380 if (acl_get_permset(entry
, &permset
) == -1)
1382 if (acl_clear_perms(permset
) == -1)
1384 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1386 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1388 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1390 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1393 if(acl_set_permset(entry
, permset
) == -1)
1395 if(acl_set_qualifier(entry
, qual
) == -1)
1399 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1404 * This is for the normal, mundane, POSIX permission model.
1405 * We make sure that we can write to the file.
1407 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1409 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1411 mode
|= S_IWUSR
|S_IRUSR
;
1412 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1426 filesec_free(ret_fsec
);
1433 * Used to clear out the BSD/POSIX security information from
1437 copyfile_unset_posix_fsec(filesec_t fsec
)
1439 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1440 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1441 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1446 * Used to remove acl information from a filesec_t
1447 * Unsetting the acl alone in Tiger was insufficient
1449 static int copyfile_unset_acl(copyfile_state_t s
)
1452 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1454 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1457 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1459 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1462 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1464 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1471 * copyfile_open() does what one expects: it opens up the files
1472 * given in the state structure, if they're not already open.
1473 * It also does some type validation, to ensure that we only
1474 * handle file types we know about.
1476 static int copyfile_open(copyfile_state_t s
)
1478 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
1479 int islnk
= 0, isdir
= 0;
1480 int osrc
= 0, dsrc
= 0;
1482 if (s
->src
&& s
->src_fd
== -2)
1484 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1485 (s
->src
, &s
->sb
, s
->fsec
))
1487 copyfile_warn("stat on %s", s
->src
);
1491 /* prevent copying on unsupported types */
1492 switch (s
->sb
.st_mode
& S_IFMT
)
1496 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1497 s
->err
= ENOMEM
; /* too big for us to copy */
1508 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1514 * If we're packing, then we are actually
1515 * creating a file, no matter what the source
1518 if (s
->flags
& COPYFILE_PACK
) {
1520 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1521 * if the file is a symlink, and O_NOFOLLOW is specified,
1522 * open will return ELOOP, whether or not O_SYMLINK is set.
1523 * However, we know whether or not it was a symlink from
1524 * the stat above (although there is a potentiaal for a race
1525 * condition here, but it will err on the side of returning
1529 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1533 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1535 copyfile_warn("open on %s", s
->src
);
1538 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1540 (void)copyfile_quarantine(s
);
1543 if (s
->dst
&& s
->dst_fd
== -2)
1546 * COPYFILE_UNLINK tells us to try removing the destination
1547 * before we create it. We don't care if the file doesn't
1548 * exist, so we ignore ENOENT.
1550 if (COPYFILE_UNLINK
& s
->flags
)
1552 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1554 copyfile_warn("%s: remove", s
->dst
);
1559 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1563 if (lstat(s
->dst
, &st
) != -1) {
1564 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1570 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1575 copyfile_warn("cannot allocate %zd bytes", sz
);
1578 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1579 copyfile_warn("cannot readlink %s", s
->src
);
1583 if (symlink(bp
, s
->dst
) == -1) {
1584 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1585 copyfile_warn("Cannot make symlink %s", s
->dst
);
1591 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1592 if (s
->dst_fd
== -1) {
1593 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1598 mode
= (s
->sb
.st_mode
& ~S_IFMT
) | S_IRWXU
;
1600 if (mkdir(s
->dst
, mode
) == -1) {
1601 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1602 copyfile_warn("Cannot make directory %s", s
->dst
);
1606 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1607 if (s
->dst_fd
== -1) {
1608 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1611 } else while((s
->dst_fd
= open(s
->dst
, oflags
| dsrc
, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1614 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1615 * was written -- allow one to set an extended attribute on a file descriptor
1616 * for a read-only file, even if the file descriptor is opened for writing.
1617 * This will only matter if the file does not already exist.
1622 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1623 if (s
->flags
& COPYFILE_EXCL
)
1625 oflags
= oflags
& ~O_CREAT
;
1626 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
1628 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
1633 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
1637 * If we're trying to write to a directory to which we don't
1638 * have access, the create above would have failed, but chmod
1639 * here would have given us ENOENT. But the real error is
1640 * still one of access, so we change the errno we're reporting.
1641 * This could cause confusion with a race condition.
1644 if (errno
== ENOENT
)
1649 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
1650 if (((s
->flags
& COPYFILE_EXCL
) ||
1651 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
1652 && !(s
->flags
& COPYFILE_UNPACK
))
1654 oflags
= (oflags
& ~(O_WRONLY
|O_CREAT
|O_TRUNC
)) | O_RDONLY
;
1657 copyfile_warn("open on %s", s
->dst
);
1660 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
1663 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1665 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1666 s
->src_fd
, s
->dst_fd
);
1675 * copyfile_check(), as described above, essentially tells you
1676 * what you'd have to copy, if you wanted it to copy the things
1677 * you asked it to copy.
1678 * In other words, if you pass in COPYFILE_ALL, and the file in
1679 * question had no extended attributes but did have an ACL, you'd
1680 * get back COPYFILE_ACL.
1682 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
1685 copyfile_flags_t ret
= 0;
1686 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
1696 if (COPYFILE_XATTR
& s
->flags
)
1697 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
1699 ret
|= COPYFILE_XATTR
;
1702 if (COPYFILE_ACL
& s
->flags
)
1704 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1705 (s
->src
, &s
->sb
, s
->fsec
);
1707 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
1708 ret
|= COPYFILE_ACL
;
1711 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
1717 /* If the state has had quarantine info set already, we use that */
1718 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1720 qinfo
= qtn_file_alloc();
1722 * For quarantine information, we need to see if the source file
1723 * has any. Since it may be a symlink, however, and we may, or
1724 * not be following, *and* there's no qtn* routine which can optionally
1725 * follow or not follow a symlink, we need to instead work around
1734 * If we care about not following symlinks, *and* the file exists
1735 * (which is to say, lstat doesn't return an error), *and* the file
1736 * is a symlink, then we open it up (with O_SYMLINK), and use
1737 * qtn_file_init_with_fd(); if none of that is true, however, then
1738 * we can simply use qtn_file_init_with_path().
1741 && lstat(s
->src
, &sbuf
) == 0
1742 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1743 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
1745 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
1746 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1751 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
1752 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1755 qtn_file_free(qinfo
);
1763 * Attempt to copy the data section of a file. Using blockisize
1764 * is not necessarily the fastest -- it might be desirable to
1765 * specify a blocksize, somehow. But it's a size that should be
1766 * guaranteed to work.
1768 static int copyfile_data(copyfile_state_t s
)
1774 size_t iBlocksize
= 0;
1775 size_t oBlocksize
= 0;
1776 const size_t onegig
= 1 << 30;
1778 copyfile_callback_t status
= s
->statuscb
;
1780 /* Unless it's a normal file, we don't copy. For now, anyway */
1781 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
1784 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
1785 if (s
->internal_flags
& cfSawDecmpEA
) {
1786 if (s
->sb
.st_flags
& UF_COMPRESSED
) {
1787 if ((s
->flags
& COPYFILE_STAT
) == 0) {
1788 if (fchflags(s
->dst_fd
, UF_COMPRESSED
) == 0) {
1796 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
1797 iBlocksize
= s
->sb
.st_blksize
;
1799 iBlocksize
= sfs
.f_iosize
;
1802 /* Work-around for 6453525, limit blocksize to 1G */
1803 if (iBlocksize
> onegig
) {
1804 iBlocksize
= onegig
;
1807 if ((bp
= malloc(iBlocksize
)) == NULL
)
1810 if (fstatfs(s
->dst_fd
, &sfs
) == -1 || sfs
.f_iosize
== 0) {
1811 oBlocksize
= iBlocksize
;
1813 oBlocksize
= sfs
.f_iosize
;
1814 if (oBlocksize
> onegig
)
1815 oBlocksize
= onegig
;
1821 /* If supported, do preallocation for Xsan / HFS volumes */
1822 #ifdef F_PREALLOCATE
1827 fst
.fst_posmode
= F_PEOFPOSMODE
;
1829 fst
.fst_length
= s
->sb
.st_size
;
1830 /* Ignore errors; this is merely advisory. */
1831 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
1835 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
1838 size_t left
= nread
;
1843 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
1847 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
1854 copyfile_warn("writing to output file got error");
1856 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1857 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
1861 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
1870 ptr
= ((char*)ptr
) + nwritten
;
1874 s
->totalCopied
+= nwritten
;
1876 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
1877 if (rv
== COPYFILE_QUIT
) {
1878 ret
= -1; s
->err
= errno
= ECANCELED
;
1886 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
1891 if (ftruncate(s
->dst_fd
, s
->totalCopied
) < 0)
1907 * copyfile_security() will copy the ACL set, and the
1908 * POSIX set. Complexities come when dealing with
1909 * inheritied permissions, and when dealing with both
1910 * POSIX and ACL permissions.
1912 static int copyfile_security(copyfile_state_t s
)
1916 acl_t acl_src
= NULL
, acl_tmp
= NULL
, acl_dst
= NULL
;
1918 filesec_t tmp_fsec
= NULL
;
1919 filesec_t fsec_dst
= filesec_init();
1921 if (fsec_dst
== NULL
)
1925 if (COPYFILE_ACL
& s
->flags
)
1927 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
1929 if (errno
== ENOENT
)
1935 /* grab the destination acl
1936 cannot assume it's empty due to inheritance
1938 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
1941 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
1943 if (errno
== ENOENT
)
1949 if (acl_src
== NULL
&& acl_dst
== NULL
)
1952 acl_tmp
= acl_init(4);
1953 if (acl_tmp
== NULL
)
1957 acl_entry_t ace
= NULL
;
1958 acl_entry_t tmp
= NULL
;
1960 acl_get_entry(acl_src
,
1961 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1964 acl_flagset_t flags
= { 0 };
1965 acl_get_flagset_np(ace
, &flags
);
1966 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
1968 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
1971 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
1974 copyfile_debug(2, "copied acl entry from %s to %s",
1975 s
->src
? s
->src
: "(null src)",
1976 s
->dst
? s
->dst
: "(null tmp)");
1982 acl_entry_t ace
= NULL
;
1983 acl_entry_t tmp
= NULL
;
1984 acl_flagset_t flags
= { 0 };
1985 for (copied
= 0;acl_get_entry(acl_dst
,
1986 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1989 acl_get_flagset_np(ace
, &flags
);
1990 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
1992 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
1995 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
1998 copyfile_debug(2, "copied acl entry from %s to %s",
1999 s
->src
? s
->src
: "(null dst)",
2000 s
->dst
? s
->dst
: "(null tmp)");
2005 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_tmp
))
2007 copyfile_debug(3, "altered acl");
2012 * The following code is attempting to ensure that only the requested
2013 * security information gets copied over to the destination file.
2014 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2015 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2018 * If we have both flags, we copy everything; if we have ACL but not STAT,
2019 * we remove the POSIX information from the filesec object, and apply the
2020 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2021 * the extended version.
2023 tmp_fsec
= filesec_dup(s
->fsec
);
2024 if (tmp_fsec
== NULL
) {
2028 switch (COPYFILE_SECURITY
& s
->flags
) {
2030 copyfile_unset_posix_fsec(tmp_fsec
);
2032 case COPYFILE_ACL
| COPYFILE_STAT
:
2033 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
2036 * The call could have failed for a number of reasons, since
2037 * it does a number of things: it changes the mode of the file,
2038 * sets the owner and group, and applies an ACL (if one exists).
2039 * The typical failure is going to be trying to set the group of
2040 * the destination file to match the source file, when the process
2041 * doesn't have permission to put files in that group. We try to
2042 * work around this by breaking the steps out and doing them
2043 * discretely. We don't care if the fchown fails, but we do care
2044 * if the mode or ACL can't be set. For historical reasons, we
2045 * simply log those failures, however.
2047 * Big warning here: we may NOT have COPYFILE_STAT set, since
2048 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2051 #define NS(x) ((x) ? (x) : "(null string)")
2052 if ((s
->flags
& COPYFILE_STAT
) &&
2053 fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
2054 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
2056 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2057 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
2058 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
2059 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
2067 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
2070 filesec_free(tmp_fsec
);
2072 filesec_free(fsec_dst
);
2073 if (acl_src
) acl_free(acl_src
);
2074 if (acl_dst
) acl_free(acl_dst
);
2075 if (acl_tmp
) acl_free(acl_tmp
);
2086 * Attempt to set the destination file's stat information -- including
2087 * flags and time-related fields -- to the source's.
2089 static int copyfile_stat(copyfile_state_t s
)
2091 struct timeval tval
[2];
2092 unsigned int added_flags
= 0;
2095 * NFS doesn't support chflags; ignore errors as a result, since
2096 * we don't return failure for this.
2098 if (s
->internal_flags
& cfMakeFileInvisible
)
2099 added_flags
|= UF_HIDDEN
;
2101 (void)fchflags(s
->dst_fd
, (u_int
)s
->sb
.st_flags
| added_flags
);
2103 /* If this fails, we don't care */
2104 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2106 /* This may have already been done in copyfile_security() */
2107 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
2109 tval
[0].tv_sec
= s
->sb
.st_atime
;
2110 tval
[1].tv_sec
= s
->sb
.st_mtime
;
2111 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
2112 (void)futimes(s
->dst_fd
, tval
);
2118 * Similar to copyfile_security() in some ways; this
2119 * routine copies the extended attributes from the source,
2120 * and sets them on the destination.
2121 * The procedure is pretty simple, even if it is verbose:
2122 * for each named attribute on the destination, get its name, and
2123 * remove it. We should have none after that.
2124 * For each named attribute on the source, get its name, get its
2125 * data, and set it on the destination.
2127 static int copyfile_xattr(copyfile_state_t s
)
2130 char *namebuf
, *end
;
2133 ssize_t bufsize
= 4096;
2137 int look_for_decmpea
= 0;
2139 /* delete EAs on destination */
2140 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2142 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2145 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
2149 * With this, end points to the last byte of the allocated buffer
2150 * This *should* be NUL, from flistxattr, but if it's not, we can
2151 * set it anyway -- it'll result in a truncated name, which then
2152 * shouldn't match when we get them later.
2154 end
= namebuf
+ nsize
- 1;
2157 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
2158 /* If the quarantine information shows up as an EA, we skip over it */
2159 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
2162 fremovexattr(s
->dst_fd
, name
,0);
2169 if (errno
== ENOTSUP
|| errno
== EPERM
)
2175 #ifdef DECMPFS_XATTR_NAME
2176 if ((s
->flags
& COPYFILE_DATA
) &&
2177 (s
->sb
.st_flags
& UF_COMPRESSED
) &&
2178 doesdecmpfs(s
->src_fd
) &&
2179 doesdecmpfs(s
->dst_fd
)) {
2180 look_for_decmpea
= XATTR_SHOWCOMPRESSION
;
2184 /* get name list of EAs on source */
2185 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, look_for_decmpea
)) < 0)
2187 if (errno
== ENOTSUP
|| errno
== EPERM
)
2195 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2198 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, look_for_decmpea
);
2206 * With this, end points to the last byte of the allocated buffer
2207 * This *should* be NUL, from flistxattr, but if it's not, we can
2208 * set it anyway -- it'll result in a truncated name, which then
2209 * shouldn't match when we get them later.
2211 end
= namebuf
+ nsize
- 1;
2215 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
2220 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
2222 /* If the quarantine information shows up as an EA, we skip over it */
2223 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
2226 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, look_for_decmpea
)) < 0)
2231 if (xa_size
> bufsize
)
2233 void *tdptr
= xa_dataptr
;
2236 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
2244 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
)) < 0)
2249 if (xa_size
!= asize
)
2252 #ifdef DECMPFS_XATTR_NAME
2253 if (strncmp(name
, DECMPFS_XATTR_NAME
, end
-name
) == 0)
2255 decmpfs_disk_header
*hdr
= xa_dataptr
;
2258 * If the EA has the decmpfs name, but is too
2259 * small, or doesn't have the right magic number,
2260 * or isn't the right type, we'll just skip it.
2261 * This means it won't end up in the destination
2262 * file, and data copy will happen normally.
2264 if ((size_t)xa_size
< sizeof(decmpfs_disk_header
)) {
2267 if (OSSwapLittleToHostInt32(hdr
->compression_magic
) != DECMPFS_MAGIC
) {
2270 if (OSSwapLittleToHostInt32(hdr
->compression_type
) != 3 &&
2271 OSSwapLittleToHostInt32(hdr
->compression_type
) != 4) {
2274 s
->internal_flags
|= cfSawDecmpEA
;
2278 if (s
->xattr_name
) {
2279 free(s
->xattr_name
);
2280 s
->xattr_name
= NULL
;
2282 s
->xattr_name
= strdup(name
);
2286 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
2287 if (rv
== COPYFILE_QUIT
) {
2290 } else if (rv
== COPYFILE_SKIP
) {
2294 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
) < 0)
2299 if (s
->xattr_name
== NULL
)
2300 s
->xattr_name
= strdup(name
);
2301 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2302 if (rv
== COPYFILE_QUIT
)
2312 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name
, strerror(errno
));
2318 if (s
->xattr_name
== NULL
)
2319 s
->xattr_name
= strdup(name
);
2321 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
2322 if (rv
== COPYFILE_QUIT
) {
2331 free((void *) xa_dataptr
);
2332 if (s
->xattr_name
) {
2333 free(s
->xattr_name
);
2334 s
->xattr_name
= NULL
;
2340 * API interface into getting data from the opaque data type.
2342 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
2352 case COPYFILE_STATE_SRC_FD
:
2353 *(int*)ret
= s
->src_fd
;
2355 case COPYFILE_STATE_DST_FD
:
2356 *(int*)ret
= s
->dst_fd
;
2358 case COPYFILE_STATE_SRC_FILENAME
:
2359 *(char**)ret
= s
->src
;
2361 case COPYFILE_STATE_DST_FILENAME
:
2362 *(char**)ret
= s
->dst
;
2364 case COPYFILE_STATE_QUARANTINE
:
2365 *(qtn_file_t
*)ret
= s
->qinfo
;
2368 case COPYFILE_STATE_STATS
:
2369 ret
= s
->stats
.global
;
2371 case COPYFILE_STATE_PROGRESS_CB
:
2372 ret
= s
->callbacks
.progress
;
2375 #ifdef COPYFILE_STATE_STATUS_CB
2376 case COPYFILE_STATE_STATUS_CB
:
2377 *(copyfile_callback_t
*)ret
= s
->statuscb
;
2379 case COPYFILE_STATE_STATUS_CTX
:
2380 *(void**)ret
= s
->ctx
;
2382 case COPYFILE_STATE_COPIED
:
2383 *(off_t
*)ret
= s
->totalCopied
;
2386 #ifdef COPYFILE_STATE_XATTRNAME
2387 case COPYFILE_STATE_XATTRNAME
:
2388 *(char**)ret
= s
->xattr_name
;
2400 * Public API for setting state data (remember that the state is
2401 * an opaque data type).
2403 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
2405 #define copyfile_set_string(DST, SRC) \
2407 if (SRC != NULL) { \
2408 DST = strdup((char *)SRC); \
2410 if (DST != NULL) { \
2425 case COPYFILE_STATE_SRC_FD
:
2426 s
->src_fd
= *(int*)thing
;
2428 case COPYFILE_STATE_DST_FD
:
2429 s
->dst_fd
= *(int*)thing
;
2431 case COPYFILE_STATE_SRC_FILENAME
:
2432 copyfile_set_string(s
->src
, thing
);
2434 case COPYFILE_STATE_DST_FILENAME
:
2435 copyfile_set_string(s
->dst
, thing
);
2437 case COPYFILE_STATE_QUARANTINE
:
2440 qtn_file_free(s
->qinfo
);
2443 if (*(qtn_file_t
*)thing
)
2444 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
2447 case COPYFILE_STATE_STATS
:
2448 s
->stats
.global
= thing
;
2450 case COPYFILE_STATE_PROGRESS_CB
:
2451 s
->callbacks
.progress
= thing
;
2454 #ifdef COPYFILE_STATE_STATUS_CB
2455 case COPYFILE_STATE_STATUS_CB
:
2456 s
->statuscb
= (copyfile_callback_t
)thing
;
2458 case COPYFILE_STATE_STATUS_CTX
:
2459 s
->ctx
= (void*)thing
;
2467 #undef copyfile_set_string
2472 * Make this a standalone program for testing purposes by
2473 * defining _COPYFILE_TEST.
2475 #ifdef _COPYFILE_TEST
2476 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2478 struct {char *s
; int v
;} opts
[] = {
2479 COPYFILE_OPTION(ACL
)
2480 COPYFILE_OPTION(STAT
)
2481 COPYFILE_OPTION(XATTR
)
2482 COPYFILE_OPTION(DATA
)
2483 COPYFILE_OPTION(SECURITY
)
2484 COPYFILE_OPTION(METADATA
)
2485 COPYFILE_OPTION(ALL
)
2486 COPYFILE_OPTION(NOFOLLOW_SRC
)
2487 COPYFILE_OPTION(NOFOLLOW_DST
)
2488 COPYFILE_OPTION(NOFOLLOW
)
2489 COPYFILE_OPTION(EXCL
)
2490 COPYFILE_OPTION(MOVE
)
2491 COPYFILE_OPTION(UNLINK
)
2492 COPYFILE_OPTION(PACK
)
2493 COPYFILE_OPTION(UNPACK
)
2494 COPYFILE_OPTION(CHECK
)
2495 COPYFILE_OPTION(VERBOSE
)
2496 COPYFILE_OPTION(DEBUG
)
2500 int main(int c
, char *v
[])
2506 errx(1, "insufficient arguments");
2510 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
2512 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
2514 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
2521 return copyfile(v
[1], v
[2], NULL
, flags
);
2525 * Apple Double Create
2527 * Create an Apple Double "._" file from a file's extented attributes
2529 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2533 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2535 #define XATTR_MAXATTRLEN (32*1024)
2539 Typical "._" AppleDouble Header File layout:
2540 ------------------------------------------------------------
2545 .-- AD ENTRY[0] Finder Info Entry (must be first)
2546 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2548 | ///////////// Fixed Size Data (32 bytes)
2552 | ATTR ENTRY[1] --+--.
2553 | ATTR ENTRY[2] --+--+--.
2555 | ATTR ENTRY[N] --+--+--+--.
2556 | ATTR DATA 0 <-' | | |
2557 | //////////// | | |
2558 | ATTR DATA 1 <----' | |
2560 | ATTR DATA 2 <-------' |
2563 | ATTR DATA N <----------'
2565 | Attribute Free Space
2567 '----> RESOURCE FORK
2568 ///////////// Variable Sized Data
2577 ------------------------------------------------------------
2579 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2580 stored as part of the Finder Info. The length in the Finder
2581 Info AppleDouble entry includes the length of the extended
2582 attribute header, attribute entries, and attribute data.
2587 * On Disk Data Structures
2589 * Note: Motorola 68K alignment and big-endian.
2591 * See RFC 1740 for additional information about the AppleDouble file format.
2595 #define ADH_MAGIC 0x00051607
2596 #define ADH_VERSION 0x00020000
2597 #define ADH_MACOSX "Mac OS X "
2600 * AppleDouble Entry ID's
2602 #define AD_DATA 1 /* Data fork */
2603 #define AD_RESOURCE 2 /* Resource fork */
2604 #define AD_REALNAME 3 /* File's name on home file system */
2605 #define AD_COMMENT 4 /* Standard Mac comment */
2606 #define AD_ICONBW 5 /* Mac black & white icon */
2607 #define AD_ICONCOLOR 6 /* Mac color icon */
2608 #define AD_UNUSED 7 /* Not used */
2609 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2610 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2611 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2612 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2613 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2614 #define AD_AFPNAME 13 /* Short name on AFP server */
2615 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2616 #define AD_AFPDIRID 15 /* AFP directory ID */
2617 #define AD_ATTRIBUTES AD_FINDERINFO
2620 #define ATTR_FILE_PREFIX "._"
2621 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2623 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2625 /* Implementation Limits */
2626 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
2627 #define ATTR_MAX_NAME_LEN 128
2628 #define ATTR_MAX_HDR_SIZE (65536+18)
2631 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2632 * size supported (including the attribute entries). All of
2633 * the attribute entries must reside within this limit.
2637 #define FINDERINFOSIZE 32
2639 typedef struct apple_double_entry
2641 u_int32_t type
; /* entry type: see list, 0 invalid */
2642 u_int32_t offset
; /* entry data offset from the beginning of the file. */
2643 u_int32_t length
; /* entry data length in bytes. */
2644 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
2647 typedef struct apple_double_header
2649 u_int32_t magic
; /* == ADH_MAGIC */
2650 u_int32_t version
; /* format version: 2 = 0x00020000 */
2651 u_int32_t filler
[4];
2652 u_int16_t numEntries
; /* number of entries which follow */
2653 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
2654 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
2655 u_int8_t pad
[2]; /* get better alignment inside attr_header */
2656 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
2659 /* Entries are aligned on 4 byte boundaries */
2660 typedef struct attr_entry
2662 u_int32_t offset
; /* file offset to data */
2663 u_int32_t length
; /* size of attribute data */
2665 u_int8_t namelen
; /* length of name including NULL termination char */
2666 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2667 } __attribute__((aligned(2), packed
)) attr_entry_t
;
2671 /* Header + entries must fit into 64K */
2672 typedef struct attr_header
2674 apple_double_header_t appledouble
;
2675 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
2676 u_int32_t debug_tag
; /* for debugging == file id of owning file */
2677 u_int32_t total_size
; /* total size of attribute header + entries + data */
2678 u_int32_t data_start
; /* file offset to attribute data area */
2679 u_int32_t data_length
; /* length of attribute data area */
2680 u_int32_t reserved
[3];
2682 u_int16_t num_attrs
;
2683 } __attribute__((aligned(2), packed
)) attr_header_t
;
2685 /* Empty Resource Fork Header */
2686 /* This comes by way of xnu's vfs_xattr.c */
2687 typedef struct rsrcfork_header
{
2688 u_int32_t fh_DataOffset
;
2689 u_int32_t fh_MapOffset
;
2690 u_int32_t fh_DataLength
;
2691 u_int32_t fh_MapLength
;
2692 u_int8_t systemData
[112];
2693 u_int8_t appData
[128];
2694 u_int32_t mh_DataOffset
;
2695 u_int32_t mh_MapOffset
;
2696 u_int32_t mh_DataLength
;
2697 u_int32_t mh_MapLength
;
2699 u_int16_t mh_RefNum
;
2701 u_int8_t mh_InMemoryAttr
;
2704 u_int16_t typeCount
;
2705 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
2706 #define RF_FIRST_RESOURCE 256
2707 #define RF_NULL_MAP_LENGTH 30
2708 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2710 static const rsrcfork_header_t empty_rsrcfork_header
= {
2711 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
2712 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
2714 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
2715 { RF_EMPTY_TAG
, }, // systemData
2717 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
2718 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
2720 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
2724 0, // mh_InMemoryAttr
2725 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
2726 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
2727 OSSwapHostToBigInt16(-1), // typeCount
2730 #define SWAP16(x) OSSwapBigToHostInt16(x)
2731 #define SWAP32(x) OSSwapBigToHostInt32(x)
2732 #define SWAP64(x) OSSwapBigToHostInt64(x)
2734 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2736 #define ATTR_ENTRY_LENGTH(namelen) \
2737 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2739 #define ATTR_NEXT(ae) \
2740 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2742 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2745 * Endian swap Apple Double header
2748 swap_adhdr(apple_double_header_t
*adh
)
2750 #if BYTE_ORDER == LITTLE_ENDIAN
2754 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
2756 adh
->magic
= SWAP32 (adh
->magic
);
2757 adh
->version
= SWAP32 (adh
->version
);
2758 adh
->numEntries
= SWAP16 (adh
->numEntries
);
2760 for (i
= 0; i
< count
; i
++)
2762 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
2763 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
2764 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
2772 * Endian swap extended attributes header
2775 swap_attrhdr(attr_header_t
*ah
)
2777 #if BYTE_ORDER == LITTLE_ENDIAN
2782 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
2784 ah
->magic
= SWAP32 (ah
->magic
);
2785 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
2786 ah
->total_size
= SWAP32 (ah
->total_size
);
2787 ah
->data_start
= SWAP32 (ah
->data_start
);
2788 ah
->data_length
= SWAP32 (ah
->data_length
);
2789 ah
->flags
= SWAP16 (ah
->flags
);
2790 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
2792 ae
= (attr_entry_t
*)(&ah
[1]);
2793 for (i
= 0; i
< count
; i
++)
2795 attr_entry_t
*next
= ATTR_NEXT(ae
);
2796 ae
->offset
= SWAP32 (ae
->offset
);
2797 ae
->length
= SWAP32 (ae
->length
);
2798 ae
->flags
= SWAP16 (ae
->flags
);
2806 static const u_int32_t emptyfinfo
[8] = {0};
2809 * Given an Apple Double file in src, turn it into a
2810 * normal file (possibly with multiple forks, EAs, and
2813 static int copyfile_unpack(copyfile_state_t s
)
2816 void * buffer
, * endptr
;
2817 apple_double_header_t
*adhdr
;
2821 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
2822 hdrsize
= (ssize_t
)s
->sb
.st_size
;
2824 hdrsize
= ATTR_MAX_HDR_SIZE
;
2826 buffer
= calloc(1, hdrsize
);
2827 if (buffer
== NULL
) {
2828 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize
);
2832 endptr
= (char*)buffer
+ hdrsize
;
2834 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
2838 copyfile_debug(1, "pread returned: %zd", bytes
);
2842 if (bytes
< hdrsize
)
2845 "pread couldn't read entire header: %d of %d",
2846 (int)bytes
, (int)s
->sb
.st_size
);
2850 adhdr
= (apple_double_header_t
*)buffer
;
2853 * Check for Apple Double file.
2855 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
2856 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
2857 SWAP32(adhdr
->version
) != ADH_VERSION
||
2858 SWAP16(adhdr
->numEntries
) != 2 ||
2859 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
2861 if (COPYFILE_VERBOSE
& s
->flags
)
2862 copyfile_warn("Not a valid Apple Double header");
2869 * Remove any extended attributes on the target.
2872 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2874 char *namebuf
, *name
;
2876 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
2881 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
2884 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
2885 (void)fremovexattr(s
->dst_fd
, name
, 0);
2891 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
2896 * Extract the extended attributes.
2899 * This assumes that the data is already in memory (not
2900 * the case when there are lots of attributes or one of
2901 * the attributes is very large.
2903 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
2905 attr_header_t
*attrhdr
;
2906 attr_entry_t
*entry
;
2910 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
2911 copyfile_warn("bad attribute header: %zu < %zu", hdrsize
, sizeof(attr_header_t
));
2916 attrhdr
= (attr_header_t
*)buffer
;
2917 swap_attrhdr(attrhdr
);
2918 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
2920 if (COPYFILE_VERBOSE
& s
->flags
)
2921 copyfile_warn("bad attribute header");
2925 count
= attrhdr
->num_attrs
;
2926 entry
= (attr_entry_t
*)&attrhdr
[1];
2928 for (i
= 0; i
< count
; i
++)
2933 * First we do some simple sanity checking.
2934 * +) See if entry is within the buffer's range;
2936 * +) Check the attribute name length; if it's longer than the
2937 * maximum, we truncate it down. (We could error out as well;
2938 * I'm not sure which is the better way to go here.)
2940 * +) If, given the name length, it goes beyond the end of
2941 * the buffer, error out.
2943 * +) If the last byte isn't a NUL, make it a NUL. (Since we
2944 * truncated the name length above, we truncate the name here.)
2946 * +) If entry->offset is so large that it causes dataptr to
2947 * go beyond the end of the buffer -- or, worse, so large that
2948 * it wraps around! -- we error out.
2950 * +) If entry->length would cause the entry to go beyond the
2951 * end of the buffer (or, worse, wrap around to before it),
2952 * *or* if the length is larger than the hdrsize, we error out.
2953 * (An explanation of that: what we're checking for there is
2954 * the small range of values such that offset+length would cause
2955 * it to go beyond endptr, and then wrap around past buffer. We
2956 * care about this because we are passing entry->length down to
2957 * fgetxattr() below, and an erroneously large value could cause
2958 * problems there. By making sure that it's less than hdrsize,
2959 * which has already been sanity-checked above, we're safe.
2960 * That may mean that the check against < buffer is unnecessary.)
2962 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
2963 if (COPYFILE_VERBOSE
& s
->flags
)
2964 copyfile_warn("Incomplete or corrupt attribute entry");
2970 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
2971 if (COPYFILE_VERBOSE
& s
->flags
)
2972 copyfile_warn("Incomplete or corrupt attribute entry");
2978 if (entry
->namelen
< 2) {
2979 if (COPYFILE_VERBOSE
& s
->flags
)
2980 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
2986 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
2987 if (COPYFILE_VERBOSE
& s
->flags
)
2988 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
2994 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
2995 if (COPYFILE_VERBOSE
& s
->flags
)
2996 copyfile_warn("Incomplete or corrupt attribute entry");
3002 /* Because namelen includes the NUL, we check one byte back */
3003 if (entry
->name
[entry
->namelen
-1] != 0) {
3004 if (COPYFILE_VERBOSE
& s
->flags
)
3005 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3011 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3012 entry
->name
, entry
->length
, entry
->offset
);
3014 dataptr
= (char *)attrhdr
+ entry
->offset
;
3016 if (dataptr
> endptr
|| dataptr
< buffer
) {
3017 copyfile_debug(1, "Entry %d overflows: offset = %u", i
, entry
->offset
);
3019 s
->err
= EINVAL
; /* Invalid buffer */
3022 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
3023 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
3024 (entry
->length
> (size_t)hdrsize
)) {
3025 if (COPYFILE_VERBOSE
& s
->flags
)
3026 copyfile_warn("Incomplete or corrupt attribute entry");
3027 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3028 i
, entry
->offset
, entry
->length
);
3030 s
->err
= EINVAL
; /* Invalid buffer */
3034 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
3036 qtn_file_t tqinfo
= NULL
;
3038 if (s
->qinfo
== NULL
)
3040 tqinfo
= qtn_file_alloc();
3044 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
3046 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
3047 qtn_file_free(tqinfo
);
3059 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
3061 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
3064 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
3065 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3066 s
->xattr_name
= NULL
;
3067 if (rv
== COPYFILE_QUIT
) {
3068 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3072 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3077 if (tqinfo
&& !s
->qinfo
)
3079 qtn_file_free(tqinfo
);
3082 /* Look for ACL data */
3083 else if (strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
3088 char *tcp
= dataptr
;
3090 if (entry
->length
== 0) {
3091 /* Not sure how we got here, but we had one case
3092 * where it was 0. In a normal EA, we can have a 0-byte
3093 * payload. That means nothing in this case, so we'll
3094 * simply skip the EA.
3100 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3101 * however, may not be NUL-terminated. So in that case, we need to
3102 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3104 if (tcp
[entry
->length
- 1] != 0) {
3105 char *tmpstr
= malloc(entry
->length
+ 1);
3106 if (tmpstr
== NULL
) {
3110 strlcpy(tmpstr
, tcp
, entry
->length
+ 1);
3111 acl
= acl_from_text(tmpstr
);
3114 acl
= acl_from_text(tcp
);
3121 if ((fsec_tmp
= filesec_init()) == NULL
)
3123 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
3125 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
3128 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
3130 if (errno
== ENOTSUP
)
3132 if (retry
&& !copyfile_unset_acl(s
))
3138 copyfile_warn("setting security information");
3144 filesec_free(fsec_tmp
);
3151 /* And, finally, everything else */
3156 s
->xattr_name
= strdup((char*)entry
->name
);
3158 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3159 if (rv
== COPYFILE_QUIT
) {
3165 if (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0) == -1) {
3166 if (COPYFILE_VERBOSE
& s
->flags
)
3167 copyfile_warn("error %d setting attribute %s", error
, entry
->name
);
3171 s
->xattr_name
= strdup((char*)entry
->name
);
3172 rv
= (s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3173 if (s
->xattr_name
) {
3174 free(s
->xattr_name
);
3175 s
->xattr_name
= NULL
;
3177 if (rv
== COPYFILE_QUIT
) {
3185 } else if (s
->statuscb
) {
3187 s
->xattr_name
= strdup((char*)entry
->name
);
3188 s
->totalCopied
= entry
->length
;
3189 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3190 if (s
->xattr_name
) {
3191 free(s
->xattr_name
);
3192 s
->xattr_name
= NULL
;
3194 if (rv
== COPYFILE_QUIT
) {
3201 entry
= ATTR_NEXT(entry
);
3206 * Extract the Finder Info.
3208 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
3213 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
3217 enum { kFinderInvisibleMask
= 1 << 14 };
3219 newFinfo
= (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
;
3220 fFlags
= (uint16_t*)&newFinfo
[8];
3221 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
3224 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3225 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3226 s
->xattr_name
= NULL
;
3227 if (rv
== COPYFILE_QUIT
) {
3231 } else if (rv
== COPYFILE_SKIP
) {
3235 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
3239 s
->xattr_name
= XATTR_FINDERINFO_NAME
;
3240 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3241 s
->xattr_name
= NULL
;
3242 if (rv
== COPYFILE_QUIT
) {
3249 } else if (s
->statuscb
) {
3251 s
->xattr_name
= XATTR_FINDERINFO_NAME
;
3252 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3253 s
->xattr_name
= NULL
;
3254 if (rv
== COPYFILE_QUIT
) {
3260 if (SWAP16(*fFlags
) & kFinderInvisibleMask
)
3261 s
->internal_flags
|= cfMakeFileInvisible
;
3266 * Extract the Resource Fork.
3268 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
3269 adhdr
->entries
[1].length
> 0)
3271 void * rsrcforkdata
= NULL
;
3275 struct timeval tval
[2];
3277 length
= adhdr
->entries
[1].length
;
3278 offset
= adhdr
->entries
[1].offset
;
3279 rsrcforkdata
= malloc(length
);
3281 if (rsrcforkdata
== NULL
) {
3282 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3288 if (fstat(s
->dst_fd
, &sb
) < 0)
3290 copyfile_debug(1, "couldn't stat destination file");
3295 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
3296 if (bytes
< (ssize_t
)length
)
3300 copyfile_debug(1, "couldn't read resource fork");
3305 "couldn't read resource fork (only read %d bytes of %d)",
3306 (int)bytes
, (int)length
);
3313 s
->xattr_name
= XATTR_RESOURCEFORK_NAME
;
3314 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3315 s
->xattr_name
= NULL
;
3316 if (rv
== COPYFILE_QUIT
) {
3322 } else if (rv
== COPYFILE_SKIP
) {
3326 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
3330 * For filesystems that do not natively support named attributes,
3331 * the kernel creates an AppleDouble file that -- for compatabilty
3332 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3333 * structure that says there are no resources. So, if fsetxattr has
3334 * failed, and the resource fork is that empty structure, *and* the
3335 * target file is a directory, then we do nothing with it.
3337 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
3338 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
3339 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
3340 copyfile_debug(2, "not setting empty resource fork on directory");
3346 s
->xattr_name
= XATTR_RESOURCEFORK_NAME
;
3347 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3348 s
->xattr_name
= NULL
;
3349 if (rv
== COPYFILE_CONTINUE
) {
3354 copyfile_debug(1, "error %d setting resource fork attribute", error
);
3357 } else if (s
->statuscb
) {
3359 s
->xattr_name
= XATTR_RESOURCEFORK_NAME
;
3360 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3361 s
->xattr_name
= NULL
;
3362 if (rv
== COPYFILE_QUIT
) {
3370 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3371 XATTR_RESOURCEFORK_NAME
, (int)length
);
3373 if (!(s
->flags
& COPYFILE_STAT
))
3375 tval
[0].tv_sec
= sb
.st_atime
;
3376 tval
[1].tv_sec
= sb
.st_mtime
;
3377 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
3379 if (futimes(s
->dst_fd
, tval
))
3380 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
3387 if (COPYFILE_STAT
& s
->flags
)
3389 error
= copyfile_stat(s
);
3392 if (buffer
) free(buffer
);
3396 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3399 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
3400 size_t qlen
= sizeof(qbuf
);
3402 if (s
->qinfo
== NULL
)
3408 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
3414 *buf
= malloc(qlen
);
3417 memcpy(*buf
, qbuf
, qlen
);
3424 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3430 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
3432 if (errno
!= ENOENT
)
3435 if (COPYFILE_VERBOSE
& s
->flags
)
3436 copyfile_warn("getting acl");
3442 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
3445 * acl_to_text() doesn't include the NUL at the endo
3446 * in it's count (*len). It does, however, promise to
3447 * return a valid C string, so we need to up the count
3451 *buf
= malloc(*len
);
3453 memcpy(*buf
, acl_text
, *len
);
3458 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
3465 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
3468 char *databuf
= NULL
;
3473 * do COPYFILE_COPY_XATTR here; no need to
3474 * the work if we want to skip.
3481 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3483 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3484 if (rv
== COPYFILE_SKIP
) {
3488 if (rv
== COPYFILE_QUIT
) {
3494 /* Get the resource fork size */
3495 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
3497 if (COPYFILE_VERBOSE
& s
->flags
)
3498 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
3502 if (datasize
> INT_MAX
) {
3510 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3513 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3514 s
->xattr_name
= NULL
;
3515 if (rv
== COPYFILE_QUIT
) {
3521 if ((databuf
= malloc(datasize
)) == NULL
)
3523 copyfile_warn("malloc");
3528 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
3530 if (COPYFILE_VERBOSE
& s
->flags
)
3531 copyfile_warn("couldn't read entire resource fork");
3536 /* Write the resource fork to disk. */
3537 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
3539 if (COPYFILE_VERBOSE
& s
->flags
)
3540 copyfile_warn("couldn't write resource fork");
3545 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3546 if (rv
== COPYFILE_QUIT
) {
3551 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3552 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
3553 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
3556 if (ret
== -1 && s
->statuscb
)
3559 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3560 if (rv
== COPYFILE_CONTINUE
)
3563 if (s
->xattr_name
) {
3564 s
->xattr_name
= NULL
;
3571 * Do status callback here
3572 * If ret == -1, then error callback
3578 * The opposite of copyfile_unpack(), obviously.
3580 static int copyfile_pack(copyfile_state_t s
)
3582 char *attrnamebuf
= NULL
, *endnamebuf
;
3583 void *databuf
= NULL
;
3584 attr_header_t
*filehdr
, *endfilehdr
;
3585 attr_entry_t
*entry
;
3586 ssize_t listsize
= 0;
3592 int hasrsrcfork
= 0;
3594 int seenq
= 0; // Have we seen any quarantine info already?
3596 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_SIZE
);
3597 if (filehdr
== NULL
) {
3601 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_SIZE
);
3604 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
3605 if (attrnamebuf
== NULL
) {
3609 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
3613 * Fill in the Apple Double Header defaults.
3615 filehdr
->appledouble
.magic
= ADH_MAGIC
;
3616 filehdr
->appledouble
.version
= ADH_VERSION
;
3617 filehdr
->appledouble
.numEntries
= 2;
3618 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
3619 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
3620 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
3621 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
3622 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
3623 filehdr
->appledouble
.entries
[1].length
= 0;
3624 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
3627 * Fill in the initial Attribute Header.
3629 filehdr
->magic
= ATTR_HDR_MAGIC
;
3630 filehdr
->debug_tag
= 0;
3631 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
3634 * Collect the attribute names.
3636 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3639 * Test if there are acls to copy
3641 if (COPYFILE_ACL
& s
->flags
)
3643 acl_t temp_acl
= NULL
;
3644 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
3646 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
3649 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
3650 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
3651 endnamebuf
= attrnamebuf
+ offset
;
3657 if (COPYFILE_XATTR
& s
->flags
)
3659 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3660 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
3662 copyfile_debug(2, "no extended attributes found (%d)", errno
);
3664 if (listsize
> left
)
3666 copyfile_debug(1, "extended attribute list too long");
3670 endnamebuf
= attrnamebuf
+ offset
+ (listsize
> 0 ? listsize
: 0);
3671 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
3677 sort_xattrname_list(attrnamebuf
, endnamebuf
- attrnamebuf
);
3679 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
3681 namelen
= strlen(nameptr
) + 1;
3682 /* Skip over FinderInfo or Resource Fork names */
3683 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
3684 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
3687 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
3691 /* The system should prevent this from happening, but... */
3692 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
3693 namelen
= XATTR_MAXNAMELEN
+ 1;
3697 char eaname
[namelen
];
3698 bcopy(nameptr
, eaname
, namelen
);
3699 eaname
[namelen
] = 0; // Just to be sure!
3700 s
->xattr_name
= eaname
;
3701 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3702 s
->xattr_name
= NULL
;
3703 if (rv
== COPYFILE_QUIT
) {
3707 } else if (rv
== COPYFILE_SKIP
) {
3708 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
3709 memmove(nameptr
, nameptr
+ namelen
, amt
);
3710 endnamebuf
-= namelen
;
3711 /* Set namelen to 0 so continue doesn't miss names */
3716 entry
->namelen
= namelen
;
3718 if (nameptr
+ namelen
> endnamebuf
) {
3723 bcopy(nameptr
, &entry
->name
[0], namelen
);
3724 copyfile_debug(2, "copied name [%s]", entry
->name
);
3726 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
3727 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
3729 if ((void*)entry
>= (void*)endfilehdr
) {
3734 /* Update the attributes header. */
3735 filehdr
->num_attrs
++;
3736 filehdr
->data_start
+= (u_int32_t
)entrylen
;
3741 * If we have any quarantine data, we always pack it.
3742 * But if we've already got it in the EA list, don't put it in again.
3744 if (s
->qinfo
&& !seenq
)
3746 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3747 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3748 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
3753 * Collect the attribute data.
3755 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3757 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
+ 1)
3759 namelen
= strlen(nameptr
);
3761 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
3762 copyfile_pack_acl(s
, &databuf
, &datasize
);
3763 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
3765 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
3767 /* Check for Finder Info. */
3768 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
3773 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3774 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3775 if (rv
== COPYFILE_QUIT
)
3777 s
->xattr_name
= NULL
;
3782 else if (rv
== COPYFILE_SKIP
)
3784 s
->xattr_name
= NULL
;
3788 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3789 s
->xattr_name
= NULL
;
3790 if (rv
== COPYFILE_QUIT
)
3797 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
3802 s
->xattr_name
= strdup(nameptr
);
3803 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3804 if (s
->xattr_name
) {
3805 free(s
->xattr_name
);
3806 s
->xattr_name
= NULL
;
3808 if (rv
== COPYFILE_QUIT
) {
3813 if (COPYFILE_VERBOSE
& s
->flags
)
3814 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3815 } else if (datasize
!= 32)
3817 if (COPYFILE_VERBOSE
& s
->flags
)
3818 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
3821 if (COPYFILE_VERBOSE
& s
->flags
)
3822 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3823 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
3826 s
->xattr_name
= strdup(nameptr
);
3827 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3828 if (s
->xattr_name
) {
3829 free(s
->xattr_name
);
3830 s
->xattr_name
= NULL
;
3832 if (rv
== COPYFILE_QUIT
) {
3838 continue; /* finder info doesn't have an attribute entry */
3840 /* Check for Resource Fork. */
3841 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
3847 /* Just a normal attribute. */
3851 s
->xattr_name
= strdup(nameptr
);
3853 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3854 if (s
->xattr_name
) {
3855 free(s
->xattr_name
);
3856 s
->xattr_name
= NULL
;
3859 * Due to the nature of the packed file, we can't skip at this point.
3861 if (rv
== COPYFILE_QUIT
)
3868 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
3873 if (COPYFILE_VERBOSE
& s
->flags
)
3874 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3878 s
->xattr_name
= strdup(nameptr
);
3879 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3880 if (s
->xattr_name
) {
3881 free(s
->xattr_name
);
3882 s
->xattr_name
= NULL
;
3884 if (rv
== COPYFILE_QUIT
)
3893 if (datasize
> XATTR_MAXATTRLEN
)
3895 if (COPYFILE_VERBOSE
& s
->flags
)
3896 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
3899 databuf
= malloc(datasize
);
3900 if (databuf
== NULL
) {
3904 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
3907 s
->xattr_name
= strdup(nameptr
);
3908 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3909 if (s
->xattr_name
) {
3910 free(s
->xattr_name
);
3911 s
->xattr_name
= NULL
;
3913 if (rv
== COPYFILE_QUIT
) {
3921 entry
->length
= (u_int32_t
)datasize
;
3922 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
3924 filehdr
->data_length
+= (u_int32_t
)datasize
;
3927 * This assumes that the data is fits in memory (not
3928 * the case when there are lots of attributes or one of
3929 * the attributes is very large.
3931 if (entry
->offset
> ATTR_MAX_SIZE
||
3932 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
3935 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
3939 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
3941 /* bump to next entry */
3942 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
3943 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
3946 if (filehdr
->data_length
> 0)
3948 /* Now we know where the resource fork data starts. */
3949 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
3951 /* We also know the size of the "Finder Info entry. */
3952 filehdr
->appledouble
.entries
[0].length
=
3953 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
3955 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
3958 /* Copy Resource Fork. */
3959 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
3962 /* Write the header to disk. */
3963 datasize
= filehdr
->appledouble
.entries
[1].offset
;
3965 swap_adhdr(&filehdr
->appledouble
);
3966 swap_attrhdr(filehdr
);
3968 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
3970 if (COPYFILE_VERBOSE
& s
->flags
)
3971 copyfile_warn("couldn't write file header");
3976 if (filehdr
) free(filehdr
);
3977 if (attrnamebuf
) free(attrnamebuf
);
3982 return copyfile_stat(s
);