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 ((NAME) && (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
) {
1002 filesec_free(s
->original_fsec
);
1003 s
->original_fsec
= NULL
;
1005 if ((s
->original_fsec
= filesec_init()) == NULL
)
1008 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
1009 ((dst_sb
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1010 if (s
->permissive_fsec
)
1011 free(s
->permissive_fsec
);
1012 s
->permissive_fsec
= NULL
;
1013 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
1016 * copyfile_fix_perms() will make a copy of the permission set,
1017 * and insert at the beginning an ACE that ensures we can write
1018 * to the file and set attributes.
1021 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
1024 * Set the permissions for the destination to our copy.
1025 * We should get ENOTSUP from any filesystem that simply
1026 * doesn't support it.
1028 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
1030 copyfile_warn("setting security information");
1031 filesec_free(s
->permissive_fsec
);
1032 s
->permissive_fsec
= NULL
;
1035 } else if (errno
== ENOENT
) {
1040 * If COPYFILE_CHECK is set in flags, then all we are going to do
1041 * is see what kinds of things WOULD have been copied (see
1042 * copyfile_check() below). We return that value.
1044 if (COPYFILE_CHECK
& flags
)
1046 ret
= copyfile_check(s
);
1048 } else if ((ret
= copyfile_open(s
)) < 0)
1051 (void)fcntl(s
->src_fd
, F_NOCACHE
, 1);
1052 (void)fcntl(s
->dst_fd
, F_NOCACHE
, 1);
1054 ret
= copyfile_internal(s
, flags
);
1058 #ifdef COPYFILE_RECURSIVE
1059 if (!(flags
& COPYFILE_STAT
)) {
1062 /* Just need to reset the BSD information -- mode, owner, group */
1063 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
1064 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
1071 if (s
->src
&& (flags
& COPYFILE_MOVE
))
1072 (void)remove(s
->src
);
1075 if (state
== NULL
) {
1077 copyfile_state_free(s
);
1093 * Shared prelude to the {f,}copyfile(). This initializes the
1094 * state variable, if necessary, and also checks for both debugging
1095 * and disabling environment variables.
1097 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
1103 if ((*state
= copyfile_state_alloc()) == NULL
)
1109 if (COPYFILE_DEBUG
& flags
)
1112 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
1115 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
1117 /* clamp s->debug to 1 if the environment variable is not parsable */
1118 if (s
->debug
== 0 && errno
!= 0)
1121 copyfile_debug(2, "debug value set to: %d", s
->debug
);
1125 /* Temporarily disabled */
1126 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
1128 copyfile_debug(1, "copyfile disabled");
1132 copyfile_debug(2, "setting flags: %d", s
->flags
);
1139 * The guts of {f,}copyfile().
1140 * This looks through the flags in a particular order, and calls the
1141 * associated functions.
1143 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
1147 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1149 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1155 * COPYFILE_PACK causes us to create an Apple Double version of the
1156 * source file, and puts it into the destination file. See
1157 * copyfile_pack() below for all the gory details.
1159 if (COPYFILE_PACK
& flags
)
1161 if ((ret
= copyfile_pack(s
)) < 0)
1163 if (s
->dst
) unlink(s
->dst
);
1170 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1171 * The goal there is to take an Apple Double file, and turn it
1172 * into a normal file (with data fork, resource fork, modes,
1173 * extended attributes, ACLs, etc.).
1175 if (COPYFILE_UNPACK
& flags
)
1177 if ((ret
= copyfile_unpack(s
)) < 0)
1183 * If we have quarantine info set, we attempt
1184 * to apply it to dst_fd. We don't care if
1185 * it fails, not yet anyway.
1188 int qr
= qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1193 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
1194 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1195 s
->xattr_name
= NULL
;
1196 if (rv
== COPYFILE_QUIT
) {
1197 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1202 s
->err
= errno
= (qr
< 0 ? ENOTSUP
: qr
);
1210 * COPYFILE_XATTR tells us to copy the extended attributes;
1211 * this is seperate from the extended security (aka ACLs),
1212 * however. If we succeed in this, we continue to the next
1213 * stage; if we fail, we return with an error value. Note
1214 * that we fail if the errno is ENOTSUP, but we don't print
1215 * a warning in that case.
1217 if (COPYFILE_XATTR
& flags
)
1219 if ((ret
= copyfile_xattr(s
)) < 0)
1221 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1222 copyfile_warn("error processing extended attributes");
1228 * Simialr to above, this tells us whether or not to copy
1229 * the non-meta data portion of the file. We attempt to
1230 * remove (via unlink) the destination file if we fail.
1232 if (COPYFILE_DATA
& flags
)
1234 if ((ret
= copyfile_data(s
)) < 0)
1236 copyfile_warn("error processing data");
1237 if (s
->dst
&& unlink(s
->dst
))
1238 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1244 * COPYFILE_SECURITY requests that we copy the security, both
1245 * extended and mundane (that is, ACLs and POSIX).
1247 if (COPYFILE_SECURITY
& flags
)
1249 if ((ret
= copyfile_security(s
)) < 0)
1251 copyfile_warn("error processing security information");
1256 if (COPYFILE_STAT
& flags
)
1258 if ((ret
= copyfile_stat(s
)) < 0)
1260 copyfile_warn("error processing POSIX information");
1274 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1276 copyfile_state_t
copyfile_state_alloc(void)
1278 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1285 filesec_free(s
->fsec
);
1288 s
->fsec
= filesec_init();
1296 * copyfile_state_free() returns the memory allocated to the state structure.
1297 * It also closes the file descriptors, if they've been opened.
1299 int copyfile_state_free(copyfile_state_t s
)
1304 filesec_free(s
->fsec
);
1306 if (s
->original_fsec
)
1307 filesec_free(s
->original_fsec
);
1309 if (s
->permissive_fsec
)
1310 filesec_free(s
->permissive_fsec
);
1313 qtn_file_free(s
->qinfo
);
1315 if (copyfile_close(s
) < 0)
1317 copyfile_warn("error closing files");
1321 free(s
->xattr_name
);
1332 * Should we worry if we can't close the source? NFS says we
1333 * should, but it's pretty late for us at this point.
1335 static int copyfile_close(copyfile_state_t s
)
1337 if (s
->src
&& s
->src_fd
>= 0)
1340 if (s
->dst
&& s
->dst_fd
>= 0) {
1341 if (close(s
->dst_fd
))
1349 * The purpose of this function is to set up a set of permissions
1350 * (ACL and traditional) that lets us write to the file. In the
1351 * case of ACLs, we do this by putting in a first entry that lets
1352 * us write data, attributes, and extended attributes. In the case
1353 * of traditional permissions, we set the S_IWUSR (user-write)
1356 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1358 filesec_t ret_fsec
= NULL
;
1362 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1365 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1367 #ifdef COPYFILE_RECURSIVE
1368 if (add_uberace(&acl
))
1372 acl_permset_t permset
;
1375 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1379 * First, we create an entry, and give it the special name
1380 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1381 * After that, we clear out all the permissions in it, and
1382 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1383 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1384 * the functionality, and put this into the ACL.
1386 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1388 if (acl_get_permset(entry
, &permset
) == -1)
1390 if (acl_clear_perms(permset
) == -1)
1392 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1394 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1396 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1398 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1401 if(acl_set_permset(entry
, permset
) == -1)
1403 if(acl_set_qualifier(entry
, qual
) == -1)
1407 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1412 * This is for the normal, mundane, POSIX permission model.
1413 * We make sure that we can write to the file.
1415 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1417 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1419 mode
|= S_IWUSR
|S_IRUSR
;
1420 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1434 filesec_free(ret_fsec
);
1441 * Used to clear out the BSD/POSIX security information from
1445 copyfile_unset_posix_fsec(filesec_t fsec
)
1447 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1448 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1449 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1454 * Used to remove acl information from a filesec_t
1455 * Unsetting the acl alone in Tiger was insufficient
1457 static int copyfile_unset_acl(copyfile_state_t s
)
1460 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1462 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1465 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1467 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1470 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1472 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1479 * copyfile_open() does what one expects: it opens up the files
1480 * given in the state structure, if they're not already open.
1481 * It also does some type validation, to ensure that we only
1482 * handle file types we know about.
1484 static int copyfile_open(copyfile_state_t s
)
1486 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
1487 int islnk
= 0, isdir
= 0;
1488 int osrc
= 0, dsrc
= 0;
1490 if (s
->src
&& s
->src_fd
== -2)
1492 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1493 (s
->src
, &s
->sb
, s
->fsec
))
1495 copyfile_warn("stat on %s", s
->src
);
1499 /* prevent copying on unsupported types */
1500 switch (s
->sb
.st_mode
& S_IFMT
)
1504 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1505 s
->err
= ENOMEM
; /* too big for us to copy */
1516 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1522 * If we're packing, then we are actually
1523 * creating a file, no matter what the source
1526 if (s
->flags
& COPYFILE_PACK
) {
1528 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1529 * if the file is a symlink, and O_NOFOLLOW is specified,
1530 * open will return ELOOP, whether or not O_SYMLINK is set.
1531 * However, we know whether or not it was a symlink from
1532 * the stat above (although there is a potentiaal for a race
1533 * condition here, but it will err on the side of returning
1537 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1541 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1543 copyfile_warn("open on %s", s
->src
);
1546 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1548 (void)copyfile_quarantine(s
);
1551 if (s
->dst
&& s
->dst_fd
== -2)
1554 * COPYFILE_UNLINK tells us to try removing the destination
1555 * before we create it. We don't care if the file doesn't
1556 * exist, so we ignore ENOENT.
1558 if (COPYFILE_UNLINK
& s
->flags
)
1560 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1562 copyfile_warn("%s: remove", s
->dst
);
1567 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1571 if (lstat(s
->dst
, &st
) != -1) {
1572 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1578 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1583 copyfile_warn("cannot allocate %zd bytes", sz
);
1586 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1587 copyfile_warn("cannot readlink %s", s
->src
);
1591 if (symlink(bp
, s
->dst
) == -1) {
1592 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1593 copyfile_warn("Cannot make symlink %s", s
->dst
);
1599 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1600 if (s
->dst_fd
== -1) {
1601 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1606 mode
= (s
->sb
.st_mode
& ~S_IFMT
) | S_IRWXU
;
1608 if (mkdir(s
->dst
, mode
) == -1) {
1609 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1610 copyfile_warn("Cannot make directory %s", s
->dst
);
1614 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1615 if (s
->dst_fd
== -1) {
1616 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1619 } else while((s
->dst_fd
= open(s
->dst
, oflags
| dsrc
, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1622 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1623 * was written -- allow one to set an extended attribute on a file descriptor
1624 * for a read-only file, even if the file descriptor is opened for writing.
1625 * This will only matter if the file does not already exist.
1630 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1631 if (s
->flags
& COPYFILE_EXCL
)
1633 oflags
= oflags
& ~O_CREAT
;
1634 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
1636 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
1641 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
1645 * If we're trying to write to a directory to which we don't
1646 * have access, the create above would have failed, but chmod
1647 * here would have given us ENOENT. But the real error is
1648 * still one of access, so we change the errno we're reporting.
1649 * This could cause confusion with a race condition.
1652 if (errno
== ENOENT
)
1657 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
1658 if (((s
->flags
& COPYFILE_EXCL
) ||
1659 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
1660 && !(s
->flags
& COPYFILE_UNPACK
))
1662 oflags
= (oflags
& ~(O_WRONLY
|O_CREAT
|O_TRUNC
)) | O_RDONLY
;
1665 copyfile_warn("open on %s", s
->dst
);
1668 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
1671 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1673 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1674 s
->src_fd
, s
->dst_fd
);
1683 * copyfile_check(), as described above, essentially tells you
1684 * what you'd have to copy, if you wanted it to copy the things
1685 * you asked it to copy.
1686 * In other words, if you pass in COPYFILE_ALL, and the file in
1687 * question had no extended attributes but did have an ACL, you'd
1688 * get back COPYFILE_ACL.
1690 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
1693 copyfile_flags_t ret
= 0;
1694 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
1704 if (COPYFILE_XATTR
& s
->flags
)
1705 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
1707 ret
|= COPYFILE_XATTR
;
1710 if (COPYFILE_ACL
& s
->flags
)
1712 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1713 (s
->src
, &s
->sb
, s
->fsec
);
1715 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
1716 ret
|= COPYFILE_ACL
;
1719 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
1725 /* If the state has had quarantine info set already, we use that */
1726 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1728 qinfo
= qtn_file_alloc();
1730 * For quarantine information, we need to see if the source file
1731 * has any. Since it may be a symlink, however, and we may, or
1732 * not be following, *and* there's no qtn* routine which can optionally
1733 * follow or not follow a symlink, we need to instead work around
1742 * If we care about not following symlinks, *and* the file exists
1743 * (which is to say, lstat doesn't return an error), *and* the file
1744 * is a symlink, then we open it up (with O_SYMLINK), and use
1745 * qtn_file_init_with_fd(); if none of that is true, however, then
1746 * we can simply use qtn_file_init_with_path().
1749 && lstat(s
->src
, &sbuf
) == 0
1750 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1751 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
1753 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
1754 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1759 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
1760 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1763 qtn_file_free(qinfo
);
1771 * Attempt to copy the data section of a file. Using blockisize
1772 * is not necessarily the fastest -- it might be desirable to
1773 * specify a blocksize, somehow. But it's a size that should be
1774 * guaranteed to work.
1776 static int copyfile_data(copyfile_state_t s
)
1782 size_t iBlocksize
= 0;
1783 size_t oBlocksize
= 0;
1784 const size_t onegig
= 1 << 30;
1786 copyfile_callback_t status
= s
->statuscb
;
1788 /* Unless it's a normal file, we don't copy. For now, anyway */
1789 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
1792 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
1793 if (s
->internal_flags
& cfSawDecmpEA
) {
1794 if (s
->sb
.st_flags
& UF_COMPRESSED
) {
1795 if ((s
->flags
& COPYFILE_STAT
) == 0) {
1796 if (fchflags(s
->dst_fd
, UF_COMPRESSED
) == 0) {
1804 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
1805 iBlocksize
= s
->sb
.st_blksize
;
1807 iBlocksize
= sfs
.f_iosize
;
1810 /* Work-around for 6453525, limit blocksize to 1G */
1811 if (iBlocksize
> onegig
) {
1812 iBlocksize
= onegig
;
1815 if ((bp
= malloc(iBlocksize
)) == NULL
)
1818 if (fstatfs(s
->dst_fd
, &sfs
) == -1 || sfs
.f_iosize
== 0) {
1819 oBlocksize
= iBlocksize
;
1821 oBlocksize
= sfs
.f_iosize
;
1822 if (oBlocksize
> onegig
)
1823 oBlocksize
= onegig
;
1829 /* If supported, do preallocation for Xsan / HFS volumes */
1830 #ifdef F_PREALLOCATE
1835 fst
.fst_posmode
= F_PEOFPOSMODE
;
1837 fst
.fst_length
= s
->sb
.st_size
;
1838 /* Ignore errors; this is merely advisory. */
1839 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
1843 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
1846 size_t left
= nread
;
1851 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
1855 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
1862 copyfile_warn("writing to output file got error");
1864 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1865 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
1869 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
1878 ptr
= ((char*)ptr
) + nwritten
;
1882 s
->totalCopied
+= nwritten
;
1884 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
1885 if (rv
== COPYFILE_QUIT
) {
1886 ret
= -1; s
->err
= errno
= ECANCELED
;
1894 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
1899 if (ftruncate(s
->dst_fd
, s
->totalCopied
) < 0)
1915 * copyfile_security() will copy the ACL set, and the
1916 * POSIX set. Complexities come when dealing with
1917 * inheritied permissions, and when dealing with both
1918 * POSIX and ACL permissions.
1920 static int copyfile_security(copyfile_state_t s
)
1924 acl_t acl_src
= NULL
, acl_tmp
= NULL
, acl_dst
= NULL
;
1926 filesec_t tmp_fsec
= NULL
;
1927 filesec_t fsec_dst
= filesec_init();
1929 if (fsec_dst
== NULL
)
1933 if (COPYFILE_ACL
& s
->flags
)
1935 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
1937 if (errno
== ENOENT
)
1943 /* grab the destination acl
1944 cannot assume it's empty due to inheritance
1946 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
1949 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
1951 if (errno
== ENOENT
)
1957 if (acl_src
== NULL
&& acl_dst
== NULL
)
1960 acl_tmp
= acl_init(4);
1961 if (acl_tmp
== NULL
)
1965 acl_entry_t ace
= NULL
;
1966 acl_entry_t tmp
= NULL
;
1968 acl_get_entry(acl_src
,
1969 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1972 acl_flagset_t flags
= { 0 };
1973 acl_get_flagset_np(ace
, &flags
);
1974 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
1976 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
1979 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
1982 copyfile_debug(2, "copied acl entry from %s to %s",
1983 s
->src
? s
->src
: "(null src)",
1984 s
->dst
? s
->dst
: "(null tmp)");
1990 acl_entry_t ace
= NULL
;
1991 acl_entry_t tmp
= NULL
;
1992 acl_flagset_t flags
= { 0 };
1993 for (copied
= 0;acl_get_entry(acl_dst
,
1994 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1997 acl_get_flagset_np(ace
, &flags
);
1998 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
2000 if ((ret
= acl_create_entry(&acl_tmp
, &tmp
)) == -1)
2003 if ((ret
= acl_copy_entry(tmp
, ace
)) == -1)
2006 copyfile_debug(2, "copied acl entry from %s to %s",
2007 s
->src
? s
->src
: "(null dst)",
2008 s
->dst
? s
->dst
: "(null tmp)");
2013 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_tmp
))
2015 copyfile_debug(3, "altered acl");
2020 * The following code is attempting to ensure that only the requested
2021 * security information gets copied over to the destination file.
2022 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2023 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2026 * If we have both flags, we copy everything; if we have ACL but not STAT,
2027 * we remove the POSIX information from the filesec object, and apply the
2028 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2029 * the extended version.
2031 tmp_fsec
= filesec_dup(s
->fsec
);
2032 if (tmp_fsec
== NULL
) {
2036 switch (COPYFILE_SECURITY
& s
->flags
) {
2038 copyfile_unset_posix_fsec(tmp_fsec
);
2040 case COPYFILE_ACL
| COPYFILE_STAT
:
2041 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
2044 * The call could have failed for a number of reasons, since
2045 * it does a number of things: it changes the mode of the file,
2046 * sets the owner and group, and applies an ACL (if one exists).
2047 * The typical failure is going to be trying to set the group of
2048 * the destination file to match the source file, when the process
2049 * doesn't have permission to put files in that group. We try to
2050 * work around this by breaking the steps out and doing them
2051 * discretely. We don't care if the fchown fails, but we do care
2052 * if the mode or ACL can't be set. For historical reasons, we
2053 * simply log those failures, however.
2055 * Big warning here: we may NOT have COPYFILE_STAT set, since
2056 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2059 #define NS(x) ((x) ? (x) : "(null string)")
2060 if ((s
->flags
& COPYFILE_STAT
) &&
2061 fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
2062 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
2064 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2065 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
2066 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
2067 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
2075 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
2078 filesec_free(tmp_fsec
);
2080 filesec_free(fsec_dst
);
2081 if (acl_src
) acl_free(acl_src
);
2082 if (acl_dst
) acl_free(acl_dst
);
2083 if (acl_tmp
) acl_free(acl_tmp
);
2094 * Attempt to set the destination file's stat information -- including
2095 * flags and time-related fields -- to the source's.
2097 static int copyfile_stat(copyfile_state_t s
)
2099 struct timeval tval
[2];
2100 unsigned int added_flags
= 0;
2103 * NFS doesn't support chflags; ignore errors as a result, since
2104 * we don't return failure for this.
2106 if (s
->internal_flags
& cfMakeFileInvisible
)
2107 added_flags
|= UF_HIDDEN
;
2109 (void)fchflags(s
->dst_fd
, (u_int
)s
->sb
.st_flags
| added_flags
);
2111 /* If this fails, we don't care */
2112 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
2114 /* This may have already been done in copyfile_security() */
2115 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
2117 tval
[0].tv_sec
= s
->sb
.st_atime
;
2118 tval
[1].tv_sec
= s
->sb
.st_mtime
;
2119 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
2120 (void)futimes(s
->dst_fd
, tval
);
2126 * Similar to copyfile_security() in some ways; this
2127 * routine copies the extended attributes from the source,
2128 * and sets them on the destination.
2129 * The procedure is pretty simple, even if it is verbose:
2130 * for each named attribute on the destination, get its name, and
2131 * remove it. We should have none after that.
2132 * For each named attribute on the source, get its name, get its
2133 * data, and set it on the destination.
2135 static int copyfile_xattr(copyfile_state_t s
)
2138 char *namebuf
, *end
;
2141 ssize_t bufsize
= 4096;
2145 int look_for_decmpea
= 0;
2147 /* delete EAs on destination */
2148 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2150 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2153 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
2157 * With this, end points to the last byte of the allocated buffer
2158 * This *should* be NUL, from flistxattr, but if it's not, we can
2159 * set it anyway -- it'll result in a truncated name, which then
2160 * shouldn't match when we get them later.
2162 end
= namebuf
+ nsize
- 1;
2165 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
2166 /* If the quarantine information shows up as an EA, we skip over it */
2167 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
2170 fremovexattr(s
->dst_fd
, name
,0);
2177 if (errno
== ENOTSUP
|| errno
== EPERM
)
2183 #ifdef DECMPFS_XATTR_NAME
2184 if ((s
->flags
& COPYFILE_DATA
) &&
2185 (s
->sb
.st_flags
& UF_COMPRESSED
) &&
2186 doesdecmpfs(s
->src_fd
) &&
2187 doesdecmpfs(s
->dst_fd
)) {
2188 look_for_decmpea
= XATTR_SHOWCOMPRESSION
;
2192 /* get name list of EAs on source */
2193 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, look_for_decmpea
)) < 0)
2195 if (errno
== ENOTSUP
|| errno
== EPERM
)
2203 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2206 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, look_for_decmpea
);
2214 * With this, end points to the last byte of the allocated buffer
2215 * This *should* be NUL, from flistxattr, but if it's not, we can
2216 * set it anyway -- it'll result in a truncated name, which then
2217 * shouldn't match when we get them later.
2219 end
= namebuf
+ nsize
- 1;
2223 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
2228 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
2230 if (s
->xattr_name
) {
2231 free(s
->xattr_name
);
2232 s
->xattr_name
= NULL
;
2235 /* If the quarantine information shows up as an EA, we skip over it */
2236 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
2239 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, look_for_decmpea
)) < 0)
2244 if (xa_size
> bufsize
)
2246 void *tdptr
= xa_dataptr
;
2249 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
2257 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
)) < 0)
2262 if (xa_size
!= asize
)
2265 #ifdef DECMPFS_XATTR_NAME
2266 if (strncmp(name
, DECMPFS_XATTR_NAME
, end
-name
) == 0)
2268 decmpfs_disk_header
*hdr
= xa_dataptr
;
2271 * If the EA has the decmpfs name, but is too
2272 * small, or doesn't have the right magic number,
2273 * or isn't the right type, we'll just skip it.
2274 * This means it won't end up in the destination
2275 * file, and data copy will happen normally.
2277 if ((size_t)xa_size
< sizeof(decmpfs_disk_header
)) {
2280 if (OSSwapLittleToHostInt32(hdr
->compression_magic
) != DECMPFS_MAGIC
) {
2283 if (OSSwapLittleToHostInt32(hdr
->compression_type
) != 3 &&
2284 OSSwapLittleToHostInt32(hdr
->compression_type
) != 4) {
2287 s
->internal_flags
|= cfSawDecmpEA
;
2291 s
->xattr_name
= strdup(name
);
2295 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
2296 if (rv
== COPYFILE_QUIT
) {
2299 } else if (rv
== COPYFILE_SKIP
) {
2303 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, look_for_decmpea
) < 0)
2308 if (s
->xattr_name
== NULL
)
2309 s
->xattr_name
= strdup(name
);
2310 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
2311 if (rv
== COPYFILE_QUIT
)
2321 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name
, strerror(errno
));
2327 if (s
->xattr_name
== NULL
)
2328 s
->xattr_name
= strdup(name
);
2330 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
2331 if (rv
== COPYFILE_QUIT
) {
2340 free((void *) xa_dataptr
);
2341 if (s
->xattr_name
) {
2342 free(s
->xattr_name
);
2343 s
->xattr_name
= NULL
;
2349 * API interface into getting data from the opaque data type.
2351 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
2361 case COPYFILE_STATE_SRC_FD
:
2362 *(int*)ret
= s
->src_fd
;
2364 case COPYFILE_STATE_DST_FD
:
2365 *(int*)ret
= s
->dst_fd
;
2367 case COPYFILE_STATE_SRC_FILENAME
:
2368 *(char**)ret
= s
->src
;
2370 case COPYFILE_STATE_DST_FILENAME
:
2371 *(char**)ret
= s
->dst
;
2373 case COPYFILE_STATE_QUARANTINE
:
2374 *(qtn_file_t
*)ret
= s
->qinfo
;
2377 case COPYFILE_STATE_STATS
:
2378 ret
= s
->stats
.global
;
2380 case COPYFILE_STATE_PROGRESS_CB
:
2381 ret
= s
->callbacks
.progress
;
2384 #ifdef COPYFILE_STATE_STATUS_CB
2385 case COPYFILE_STATE_STATUS_CB
:
2386 *(copyfile_callback_t
*)ret
= s
->statuscb
;
2388 case COPYFILE_STATE_STATUS_CTX
:
2389 *(void**)ret
= s
->ctx
;
2391 case COPYFILE_STATE_COPIED
:
2392 *(off_t
*)ret
= s
->totalCopied
;
2395 #ifdef COPYFILE_STATE_XATTRNAME
2396 case COPYFILE_STATE_XATTRNAME
:
2397 *(char**)ret
= s
->xattr_name
;
2409 * Public API for setting state data (remember that the state is
2410 * an opaque data type).
2412 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
2414 #define copyfile_set_string(DST, SRC) \
2416 if (SRC != NULL) { \
2417 DST = strdup((char *)SRC); \
2419 if (DST != NULL) { \
2434 case COPYFILE_STATE_SRC_FD
:
2435 s
->src_fd
= *(int*)thing
;
2437 case COPYFILE_STATE_DST_FD
:
2438 s
->dst_fd
= *(int*)thing
;
2440 case COPYFILE_STATE_SRC_FILENAME
:
2441 copyfile_set_string(s
->src
, thing
);
2443 case COPYFILE_STATE_DST_FILENAME
:
2444 copyfile_set_string(s
->dst
, thing
);
2446 case COPYFILE_STATE_QUARANTINE
:
2449 qtn_file_free(s
->qinfo
);
2452 if (*(qtn_file_t
*)thing
)
2453 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
2456 case COPYFILE_STATE_STATS
:
2457 s
->stats
.global
= thing
;
2459 case COPYFILE_STATE_PROGRESS_CB
:
2460 s
->callbacks
.progress
= thing
;
2463 #ifdef COPYFILE_STATE_STATUS_CB
2464 case COPYFILE_STATE_STATUS_CB
:
2465 s
->statuscb
= (copyfile_callback_t
)thing
;
2467 case COPYFILE_STATE_STATUS_CTX
:
2468 s
->ctx
= (void*)thing
;
2476 #undef copyfile_set_string
2481 * Make this a standalone program for testing purposes by
2482 * defining _COPYFILE_TEST.
2484 #ifdef _COPYFILE_TEST
2485 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2487 struct {char *s
; int v
;} opts
[] = {
2488 COPYFILE_OPTION(ACL
)
2489 COPYFILE_OPTION(STAT
)
2490 COPYFILE_OPTION(XATTR
)
2491 COPYFILE_OPTION(DATA
)
2492 COPYFILE_OPTION(SECURITY
)
2493 COPYFILE_OPTION(METADATA
)
2494 COPYFILE_OPTION(ALL
)
2495 COPYFILE_OPTION(NOFOLLOW_SRC
)
2496 COPYFILE_OPTION(NOFOLLOW_DST
)
2497 COPYFILE_OPTION(NOFOLLOW
)
2498 COPYFILE_OPTION(EXCL
)
2499 COPYFILE_OPTION(MOVE
)
2500 COPYFILE_OPTION(UNLINK
)
2501 COPYFILE_OPTION(PACK
)
2502 COPYFILE_OPTION(UNPACK
)
2503 COPYFILE_OPTION(CHECK
)
2504 COPYFILE_OPTION(VERBOSE
)
2505 COPYFILE_OPTION(DEBUG
)
2509 int main(int c
, char *v
[])
2515 errx(1, "insufficient arguments");
2519 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
2521 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
2523 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
2530 return copyfile(v
[1], v
[2], NULL
, flags
);
2534 * Apple Double Create
2536 * Create an Apple Double "._" file from a file's extented attributes
2538 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2542 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2544 #define XATTR_MAXATTRLEN (32*1024)
2548 Typical "._" AppleDouble Header File layout:
2549 ------------------------------------------------------------
2554 .-- AD ENTRY[0] Finder Info Entry (must be first)
2555 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2557 | ///////////// Fixed Size Data (32 bytes)
2561 | ATTR ENTRY[1] --+--.
2562 | ATTR ENTRY[2] --+--+--.
2564 | ATTR ENTRY[N] --+--+--+--.
2565 | ATTR DATA 0 <-' | | |
2566 | //////////// | | |
2567 | ATTR DATA 1 <----' | |
2569 | ATTR DATA 2 <-------' |
2572 | ATTR DATA N <----------'
2574 | Attribute Free Space
2576 '----> RESOURCE FORK
2577 ///////////// Variable Sized Data
2586 ------------------------------------------------------------
2588 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2589 stored as part of the Finder Info. The length in the Finder
2590 Info AppleDouble entry includes the length of the extended
2591 attribute header, attribute entries, and attribute data.
2596 * On Disk Data Structures
2598 * Note: Motorola 68K alignment and big-endian.
2600 * See RFC 1740 for additional information about the AppleDouble file format.
2604 #define ADH_MAGIC 0x00051607
2605 #define ADH_VERSION 0x00020000
2606 #define ADH_MACOSX "Mac OS X "
2609 * AppleDouble Entry ID's
2611 #define AD_DATA 1 /* Data fork */
2612 #define AD_RESOURCE 2 /* Resource fork */
2613 #define AD_REALNAME 3 /* File's name on home file system */
2614 #define AD_COMMENT 4 /* Standard Mac comment */
2615 #define AD_ICONBW 5 /* Mac black & white icon */
2616 #define AD_ICONCOLOR 6 /* Mac color icon */
2617 #define AD_UNUSED 7 /* Not used */
2618 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2619 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2620 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2621 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2622 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2623 #define AD_AFPNAME 13 /* Short name on AFP server */
2624 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2625 #define AD_AFPDIRID 15 /* AFP directory ID */
2626 #define AD_ATTRIBUTES AD_FINDERINFO
2629 #define ATTR_FILE_PREFIX "._"
2630 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2632 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2634 /* Implementation Limits */
2635 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
2636 #define ATTR_MAX_NAME_LEN 128
2637 #define ATTR_MAX_HDR_SIZE (65536+18)
2640 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2641 * size supported (including the attribute entries). All of
2642 * the attribute entries must reside within this limit.
2646 #define FINDERINFOSIZE 32
2648 typedef struct apple_double_entry
2650 u_int32_t type
; /* entry type: see list, 0 invalid */
2651 u_int32_t offset
; /* entry data offset from the beginning of the file. */
2652 u_int32_t length
; /* entry data length in bytes. */
2653 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
2656 typedef struct apple_double_header
2658 u_int32_t magic
; /* == ADH_MAGIC */
2659 u_int32_t version
; /* format version: 2 = 0x00020000 */
2660 u_int32_t filler
[4];
2661 u_int16_t numEntries
; /* number of entries which follow */
2662 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
2663 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
2664 u_int8_t pad
[2]; /* get better alignment inside attr_header */
2665 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
2668 /* Entries are aligned on 4 byte boundaries */
2669 typedef struct attr_entry
2671 u_int32_t offset
; /* file offset to data */
2672 u_int32_t length
; /* size of attribute data */
2674 u_int8_t namelen
; /* length of name including NULL termination char */
2675 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2676 } __attribute__((aligned(2), packed
)) attr_entry_t
;
2680 /* Header + entries must fit into 64K */
2681 typedef struct attr_header
2683 apple_double_header_t appledouble
;
2684 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
2685 u_int32_t debug_tag
; /* for debugging == file id of owning file */
2686 u_int32_t total_size
; /* total size of attribute header + entries + data */
2687 u_int32_t data_start
; /* file offset to attribute data area */
2688 u_int32_t data_length
; /* length of attribute data area */
2689 u_int32_t reserved
[3];
2691 u_int16_t num_attrs
;
2692 } __attribute__((aligned(2), packed
)) attr_header_t
;
2694 /* Empty Resource Fork Header */
2695 /* This comes by way of xnu's vfs_xattr.c */
2696 typedef struct rsrcfork_header
{
2697 u_int32_t fh_DataOffset
;
2698 u_int32_t fh_MapOffset
;
2699 u_int32_t fh_DataLength
;
2700 u_int32_t fh_MapLength
;
2701 u_int8_t systemData
[112];
2702 u_int8_t appData
[128];
2703 u_int32_t mh_DataOffset
;
2704 u_int32_t mh_MapOffset
;
2705 u_int32_t mh_DataLength
;
2706 u_int32_t mh_MapLength
;
2708 u_int16_t mh_RefNum
;
2710 u_int8_t mh_InMemoryAttr
;
2713 u_int16_t typeCount
;
2714 } __attribute__((aligned(2), packed
)) rsrcfork_header_t
;
2715 #define RF_FIRST_RESOURCE 256
2716 #define RF_NULL_MAP_LENGTH 30
2717 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2719 static const rsrcfork_header_t empty_rsrcfork_header
= {
2720 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
2721 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
2723 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
2724 { RF_EMPTY_TAG
, }, // systemData
2726 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
2727 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
2729 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
2733 0, // mh_InMemoryAttr
2734 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
2735 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
2736 OSSwapHostToBigInt16(-1), // typeCount
2739 #define SWAP16(x) OSSwapBigToHostInt16(x)
2740 #define SWAP32(x) OSSwapBigToHostInt32(x)
2741 #define SWAP64(x) OSSwapBigToHostInt64(x)
2743 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2745 #define ATTR_ENTRY_LENGTH(namelen) \
2746 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2748 #define ATTR_NEXT(ae) \
2749 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2751 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2754 * Endian swap Apple Double header
2757 swap_adhdr(apple_double_header_t
*adh
)
2759 #if BYTE_ORDER == LITTLE_ENDIAN
2763 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
2765 adh
->magic
= SWAP32 (adh
->magic
);
2766 adh
->version
= SWAP32 (adh
->version
);
2767 adh
->numEntries
= SWAP16 (adh
->numEntries
);
2769 for (i
= 0; i
< count
; i
++)
2771 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
2772 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
2773 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
2781 * Endian swap extended attributes header
2784 swap_attrhdr(attr_header_t
*ah
)
2786 #if BYTE_ORDER == LITTLE_ENDIAN
2791 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
2793 ah
->magic
= SWAP32 (ah
->magic
);
2794 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
2795 ah
->total_size
= SWAP32 (ah
->total_size
);
2796 ah
->data_start
= SWAP32 (ah
->data_start
);
2797 ah
->data_length
= SWAP32 (ah
->data_length
);
2798 ah
->flags
= SWAP16 (ah
->flags
);
2799 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
2801 ae
= (attr_entry_t
*)(&ah
[1]);
2802 for (i
= 0; i
< count
; i
++)
2804 attr_entry_t
*next
= ATTR_NEXT(ae
);
2805 ae
->offset
= SWAP32 (ae
->offset
);
2806 ae
->length
= SWAP32 (ae
->length
);
2807 ae
->flags
= SWAP16 (ae
->flags
);
2815 static const u_int32_t emptyfinfo
[8] = {0};
2818 * Given an Apple Double file in src, turn it into a
2819 * normal file (possibly with multiple forks, EAs, and
2822 static int copyfile_unpack(copyfile_state_t s
)
2825 void * buffer
, * endptr
;
2826 apple_double_header_t
*adhdr
;
2830 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
2831 hdrsize
= (ssize_t
)s
->sb
.st_size
;
2833 hdrsize
= ATTR_MAX_HDR_SIZE
;
2835 buffer
= calloc(1, hdrsize
);
2836 if (buffer
== NULL
) {
2837 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize
);
2841 endptr
= (char*)buffer
+ hdrsize
;
2843 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
2847 copyfile_debug(1, "pread returned: %zd", bytes
);
2851 if (bytes
< hdrsize
)
2854 "pread couldn't read entire header: %d of %d",
2855 (int)bytes
, (int)s
->sb
.st_size
);
2859 adhdr
= (apple_double_header_t
*)buffer
;
2862 * Check for Apple Double file.
2864 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
2865 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
2866 SWAP32(adhdr
->version
) != ADH_VERSION
||
2867 SWAP16(adhdr
->numEntries
) != 2 ||
2868 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
2870 if (COPYFILE_VERBOSE
& s
->flags
)
2871 copyfile_warn("Not a valid Apple Double header");
2878 * Remove any extended attributes on the target.
2881 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2883 char *namebuf
, *name
;
2885 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
2890 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
2893 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
2894 (void)fremovexattr(s
->dst_fd
, name
, 0);
2900 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
2905 * Extract the extended attributes.
2908 * This assumes that the data is already in memory (not
2909 * the case when there are lots of attributes or one of
2910 * the attributes is very large.
2912 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
2914 attr_header_t
*attrhdr
;
2915 attr_entry_t
*entry
;
2919 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
2920 copyfile_warn("bad attribute header: %zu < %zu", hdrsize
, sizeof(attr_header_t
));
2925 attrhdr
= (attr_header_t
*)buffer
;
2926 swap_attrhdr(attrhdr
);
2927 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
2929 if (COPYFILE_VERBOSE
& s
->flags
)
2930 copyfile_warn("bad attribute header");
2934 count
= attrhdr
->num_attrs
;
2935 entry
= (attr_entry_t
*)&attrhdr
[1];
2937 for (i
= 0; i
< count
; i
++)
2942 * First we do some simple sanity checking.
2943 * +) See if entry is within the buffer's range;
2945 * +) Check the attribute name length; if it's longer than the
2946 * maximum, we truncate it down. (We could error out as well;
2947 * I'm not sure which is the better way to go here.)
2949 * +) If, given the name length, it goes beyond the end of
2950 * the buffer, error out.
2952 * +) If the last byte isn't a NUL, make it a NUL. (Since we
2953 * truncated the name length above, we truncate the name here.)
2955 * +) If entry->offset is so large that it causes dataptr to
2956 * go beyond the end of the buffer -- or, worse, so large that
2957 * it wraps around! -- we error out.
2959 * +) If entry->length would cause the entry to go beyond the
2960 * end of the buffer (or, worse, wrap around to before it),
2961 * *or* if the length is larger than the hdrsize, we error out.
2962 * (An explanation of that: what we're checking for there is
2963 * the small range of values such that offset+length would cause
2964 * it to go beyond endptr, and then wrap around past buffer. We
2965 * care about this because we are passing entry->length down to
2966 * fgetxattr() below, and an erroneously large value could cause
2967 * problems there. By making sure that it's less than hdrsize,
2968 * which has already been sanity-checked above, we're safe.
2969 * That may mean that the check against < buffer is unnecessary.)
2971 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
2972 if (COPYFILE_VERBOSE
& s
->flags
)
2973 copyfile_warn("Incomplete or corrupt attribute entry");
2979 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
2980 if (COPYFILE_VERBOSE
& s
->flags
)
2981 copyfile_warn("Incomplete or corrupt attribute entry");
2987 if (entry
->namelen
< 2) {
2988 if (COPYFILE_VERBOSE
& s
->flags
)
2989 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
2995 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
2996 if (COPYFILE_VERBOSE
& s
->flags
)
2997 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
3003 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
3004 if (COPYFILE_VERBOSE
& s
->flags
)
3005 copyfile_warn("Incomplete or corrupt attribute entry");
3011 /* Because namelen includes the NUL, we check one byte back */
3012 if (entry
->name
[entry
->namelen
-1] != 0) {
3013 if (COPYFILE_VERBOSE
& s
->flags
)
3014 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3020 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3021 entry
->name
, entry
->length
, entry
->offset
);
3023 dataptr
= (char *)attrhdr
+ entry
->offset
;
3025 if (dataptr
> endptr
|| dataptr
< buffer
) {
3026 copyfile_debug(1, "Entry %d overflows: offset = %u", i
, entry
->offset
);
3028 s
->err
= EINVAL
; /* Invalid buffer */
3031 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
3032 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
3033 (entry
->length
> (size_t)hdrsize
)) {
3034 if (COPYFILE_VERBOSE
& s
->flags
)
3035 copyfile_warn("Incomplete or corrupt attribute entry");
3036 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3037 i
, entry
->offset
, entry
->length
);
3039 s
->err
= EINVAL
; /* Invalid buffer */
3043 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
3045 qtn_file_t tqinfo
= NULL
;
3047 if (s
->qinfo
== NULL
)
3049 tqinfo
= qtn_file_alloc();
3053 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
3055 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
3056 qtn_file_free(tqinfo
);
3068 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
3070 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
3073 s
->xattr_name
= (char*)XATTR_QUARANTINE_NAME
;
3074 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3075 s
->xattr_name
= NULL
;
3076 if (rv
== COPYFILE_QUIT
) {
3077 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3081 error
= s
->err
= x
< 0 ? ENOTSUP
: errno
;
3086 if (tqinfo
&& !s
->qinfo
)
3088 qtn_file_free(tqinfo
);
3091 /* Look for ACL data */
3092 else if (strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
3097 char *tcp
= dataptr
;
3099 if (entry
->length
== 0) {
3100 /* Not sure how we got here, but we had one case
3101 * where it was 0. In a normal EA, we can have a 0-byte
3102 * payload. That means nothing in this case, so we'll
3103 * simply skip the EA.
3109 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3110 * however, may not be NUL-terminated. So in that case, we need to
3111 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3113 if (tcp
[entry
->length
- 1] != 0) {
3114 char *tmpstr
= malloc(entry
->length
+ 1);
3115 if (tmpstr
== NULL
) {
3119 strlcpy(tmpstr
, tcp
, entry
->length
+ 1);
3120 acl
= acl_from_text(tmpstr
);
3123 acl
= acl_from_text(tcp
);
3130 if ((fsec_tmp
= filesec_init()) == NULL
)
3132 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
3134 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
3137 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
3139 if (errno
== ENOTSUP
)
3141 if (retry
&& !copyfile_unset_acl(s
))
3147 copyfile_warn("setting security information");
3153 filesec_free(fsec_tmp
);
3160 /* And, finally, everything else */
3165 s
->xattr_name
= strdup((char*)entry
->name
);
3167 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3168 if (s
->xattr_name
) {
3169 free(s
->xattr_name
);
3170 s
->xattr_name
= NULL
;
3172 if (rv
== COPYFILE_QUIT
) {
3178 if (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0) == -1) {
3179 if (COPYFILE_VERBOSE
& s
->flags
)
3180 copyfile_warn("error %d setting attribute %s", error
, entry
->name
);
3184 s
->xattr_name
= strdup((char*)entry
->name
);
3185 rv
= (s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3186 if (s
->xattr_name
) {
3187 free(s
->xattr_name
);
3188 s
->xattr_name
= NULL
;
3190 if (rv
== COPYFILE_QUIT
) {
3198 } else if (s
->statuscb
) {
3200 s
->xattr_name
= strdup((char*)entry
->name
);
3201 s
->totalCopied
= entry
->length
;
3202 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3203 if (s
->xattr_name
) {
3204 free(s
->xattr_name
);
3205 s
->xattr_name
= NULL
;
3207 if (rv
== COPYFILE_QUIT
) {
3214 entry
= ATTR_NEXT(entry
);
3219 * Extract the Finder Info.
3221 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
3226 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
3230 enum { kFinderInvisibleMask
= 1 << 14 };
3232 newFinfo
= (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
;
3233 fFlags
= (uint16_t*)&newFinfo
[8];
3234 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
3237 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3238 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3239 s
->xattr_name
= NULL
;
3240 if (rv
== COPYFILE_QUIT
) {
3244 } else if (rv
== COPYFILE_SKIP
) {
3248 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
3252 s
->xattr_name
= XATTR_FINDERINFO_NAME
;
3253 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3254 s
->xattr_name
= NULL
;
3255 if (rv
== COPYFILE_QUIT
) {
3262 } else if (s
->statuscb
) {
3264 s
->xattr_name
= XATTR_FINDERINFO_NAME
;
3265 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3266 s
->xattr_name
= NULL
;
3267 if (rv
== COPYFILE_QUIT
) {
3273 if (SWAP16(*fFlags
) & kFinderInvisibleMask
)
3274 s
->internal_flags
|= cfMakeFileInvisible
;
3279 * Extract the Resource Fork.
3281 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
3282 adhdr
->entries
[1].length
> 0)
3284 void * rsrcforkdata
= NULL
;
3288 struct timeval tval
[2];
3290 length
= adhdr
->entries
[1].length
;
3291 offset
= adhdr
->entries
[1].offset
;
3292 rsrcforkdata
= malloc(length
);
3294 if (rsrcforkdata
== NULL
) {
3295 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3301 if (fstat(s
->dst_fd
, &sb
) < 0)
3303 copyfile_debug(1, "couldn't stat destination file");
3308 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
3309 if (bytes
< (ssize_t
)length
)
3313 copyfile_debug(1, "couldn't read resource fork");
3318 "couldn't read resource fork (only read %d bytes of %d)",
3319 (int)bytes
, (int)length
);
3326 s
->xattr_name
= XATTR_RESOURCEFORK_NAME
;
3327 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3328 s
->xattr_name
= NULL
;
3329 if (rv
== COPYFILE_QUIT
) {
3335 } else if (rv
== COPYFILE_SKIP
) {
3339 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
3343 * For filesystems that do not natively support named attributes,
3344 * the kernel creates an AppleDouble file that -- for compatabilty
3345 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3346 * structure that says there are no resources. So, if fsetxattr has
3347 * failed, and the resource fork is that empty structure, *and* the
3348 * target file is a directory, then we do nothing with it.
3350 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
3351 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
3352 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
3353 copyfile_debug(2, "not setting empty resource fork on directory");
3359 s
->xattr_name
= XATTR_RESOURCEFORK_NAME
;
3360 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3361 s
->xattr_name
= NULL
;
3362 if (rv
== COPYFILE_CONTINUE
) {
3367 copyfile_debug(1, "error %d setting resource fork attribute", error
);
3370 } else if (s
->statuscb
) {
3372 s
->xattr_name
= XATTR_RESOURCEFORK_NAME
;
3373 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3374 s
->xattr_name
= NULL
;
3375 if (rv
== COPYFILE_QUIT
) {
3383 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3384 XATTR_RESOURCEFORK_NAME
, (int)length
);
3386 if (!(s
->flags
& COPYFILE_STAT
))
3388 tval
[0].tv_sec
= sb
.st_atime
;
3389 tval
[1].tv_sec
= sb
.st_mtime
;
3390 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
3392 if (futimes(s
->dst_fd
, tval
))
3393 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
3400 if (COPYFILE_STAT
& s
->flags
)
3402 error
= copyfile_stat(s
);
3405 if (buffer
) free(buffer
);
3409 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3412 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
3413 size_t qlen
= sizeof(qbuf
);
3415 if (s
->qinfo
== NULL
)
3421 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
3427 *buf
= malloc(qlen
);
3430 memcpy(*buf
, qbuf
, qlen
);
3437 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3443 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
3445 if (errno
!= ENOENT
)
3448 if (COPYFILE_VERBOSE
& s
->flags
)
3449 copyfile_warn("getting acl");
3455 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
3458 * acl_to_text() doesn't include the NUL at the endo
3459 * in it's count (*len). It does, however, promise to
3460 * return a valid C string, so we need to up the count
3464 *buf
= malloc(*len
);
3466 memcpy(*buf
, acl_text
, *len
);
3471 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
3478 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
3481 char *databuf
= NULL
;
3486 * do COPYFILE_COPY_XATTR here; no need to
3487 * the work if we want to skip.
3494 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3496 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3497 s
->xattr_name
= NULL
;
3498 if (rv
== COPYFILE_SKIP
) {
3502 if (rv
== COPYFILE_QUIT
) {
3508 /* Get the resource fork size */
3509 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
3511 if (COPYFILE_VERBOSE
& s
->flags
)
3512 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
3516 if (datasize
> INT_MAX
) {
3524 s
->xattr_name
= (char*)XATTR_RESOURCEFORK_NAME
;
3527 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3528 s
->xattr_name
= NULL
;
3529 if (rv
== COPYFILE_QUIT
) {
3535 if ((databuf
= malloc(datasize
)) == NULL
)
3537 copyfile_warn("malloc");
3542 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
3544 if (COPYFILE_VERBOSE
& s
->flags
)
3545 copyfile_warn("couldn't read entire resource fork");
3550 /* Write the resource fork to disk. */
3551 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
3553 if (COPYFILE_VERBOSE
& s
->flags
)
3554 copyfile_warn("couldn't write resource fork");
3559 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3560 if (rv
== COPYFILE_QUIT
) {
3565 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3566 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
3567 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
3570 if (ret
== -1 && s
->statuscb
)
3573 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3574 if (rv
== COPYFILE_CONTINUE
)
3577 if (s
->xattr_name
) {
3578 s
->xattr_name
= NULL
;
3585 * Do status callback here
3586 * If ret == -1, then error callback
3592 * The opposite of copyfile_unpack(), obviously.
3594 static int copyfile_pack(copyfile_state_t s
)
3596 char *attrnamebuf
= NULL
, *endnamebuf
;
3597 void *databuf
= NULL
;
3598 attr_header_t
*filehdr
, *endfilehdr
;
3599 attr_entry_t
*entry
;
3600 ssize_t listsize
= 0;
3606 int hasrsrcfork
= 0;
3608 int seenq
= 0; // Have we seen any quarantine info already?
3610 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_SIZE
);
3611 if (filehdr
== NULL
) {
3615 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_SIZE
);
3618 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
3619 if (attrnamebuf
== NULL
) {
3623 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
3627 * Fill in the Apple Double Header defaults.
3629 filehdr
->appledouble
.magic
= ADH_MAGIC
;
3630 filehdr
->appledouble
.version
= ADH_VERSION
;
3631 filehdr
->appledouble
.numEntries
= 2;
3632 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
3633 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
3634 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
3635 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
3636 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
3637 filehdr
->appledouble
.entries
[1].length
= 0;
3638 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
3641 * Fill in the initial Attribute Header.
3643 filehdr
->magic
= ATTR_HDR_MAGIC
;
3644 filehdr
->debug_tag
= 0;
3645 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
3648 * Collect the attribute names.
3650 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3653 * Test if there are acls to copy
3655 if (COPYFILE_ACL
& s
->flags
)
3657 acl_t temp_acl
= NULL
;
3658 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
3660 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
3663 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
3664 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
3665 endnamebuf
= attrnamebuf
+ offset
;
3671 if (COPYFILE_XATTR
& s
->flags
)
3673 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3674 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
3676 copyfile_debug(2, "no extended attributes found (%d)", errno
);
3678 if (listsize
> left
)
3680 copyfile_debug(1, "extended attribute list too long");
3684 endnamebuf
= attrnamebuf
+ offset
+ (listsize
> 0 ? listsize
: 0);
3685 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
3691 sort_xattrname_list(attrnamebuf
, endnamebuf
- attrnamebuf
);
3693 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
3695 namelen
= strlen(nameptr
) + 1;
3696 /* Skip over FinderInfo or Resource Fork names */
3697 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
3698 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
3701 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
3705 /* The system should prevent this from happening, but... */
3706 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
3707 namelen
= XATTR_MAXNAMELEN
+ 1;
3711 char eaname
[namelen
];
3712 bcopy(nameptr
, eaname
, namelen
);
3713 eaname
[namelen
] = 0; // Just to be sure!
3714 s
->xattr_name
= eaname
;
3715 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3716 s
->xattr_name
= NULL
;
3717 if (rv
== COPYFILE_QUIT
) {
3721 } else if (rv
== COPYFILE_SKIP
) {
3722 size_t amt
= endnamebuf
- (nameptr
+ namelen
);
3723 memmove(nameptr
, nameptr
+ namelen
, amt
);
3724 endnamebuf
-= namelen
;
3725 /* Set namelen to 0 so continue doesn't miss names */
3730 entry
->namelen
= namelen
;
3732 if (nameptr
+ namelen
> endnamebuf
) {
3737 bcopy(nameptr
, &entry
->name
[0], namelen
);
3738 copyfile_debug(2, "copied name [%s]", entry
->name
);
3740 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
3741 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
3743 if ((void*)entry
>= (void*)endfilehdr
) {
3748 /* Update the attributes header. */
3749 filehdr
->num_attrs
++;
3750 filehdr
->data_start
+= (u_int32_t
)entrylen
;
3755 * If we have any quarantine data, we always pack it.
3756 * But if we've already got it in the EA list, don't put it in again.
3758 if (s
->qinfo
&& !seenq
)
3760 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3761 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3762 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
3767 * Collect the attribute data.
3769 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3771 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
+ 1)
3773 namelen
= strlen(nameptr
);
3775 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
3776 copyfile_pack_acl(s
, &databuf
, &datasize
);
3777 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
3779 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
3781 /* Check for Finder Info. */
3782 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
3787 s
->xattr_name
= (char*)XATTR_FINDERINFO_NAME
;
3788 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_START
, s
, s
->src
, s
->dst
, s
->ctx
);
3789 s
->xattr_name
= NULL
;
3790 if (rv
== COPYFILE_QUIT
)
3792 s
->xattr_name
= NULL
;
3797 else if (rv
== COPYFILE_SKIP
)
3799 s
->xattr_name
= NULL
;
3803 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3804 s
->xattr_name
= NULL
;
3805 if (rv
== COPYFILE_QUIT
)
3812 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
3817 s
->xattr_name
= strdup(nameptr
);
3818 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3819 if (s
->xattr_name
) {
3820 free(s
->xattr_name
);
3821 s
->xattr_name
= NULL
;
3823 if (rv
== COPYFILE_QUIT
) {
3828 if (COPYFILE_VERBOSE
& s
->flags
)
3829 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3830 } else if (datasize
!= 32)
3832 if (COPYFILE_VERBOSE
& s
->flags
)
3833 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
3836 if (COPYFILE_VERBOSE
& s
->flags
)
3837 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3838 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
3841 s
->xattr_name
= strdup(nameptr
);
3842 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3843 if (s
->xattr_name
) {
3844 free(s
->xattr_name
);
3845 s
->xattr_name
= NULL
;
3847 if (rv
== COPYFILE_QUIT
) {
3853 continue; /* finder info doesn't have an attribute entry */
3855 /* Check for Resource Fork. */
3856 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
3862 /* Just a normal attribute. */
3866 s
->xattr_name
= strdup(nameptr
);
3868 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
3869 if (s
->xattr_name
) {
3870 free(s
->xattr_name
);
3871 s
->xattr_name
= NULL
;
3874 * Due to the nature of the packed file, we can't skip at this point.
3876 if (rv
== COPYFILE_QUIT
)
3883 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
3888 if (COPYFILE_VERBOSE
& s
->flags
)
3889 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3893 s
->xattr_name
= strdup(nameptr
);
3894 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
3895 if (s
->xattr_name
) {
3896 free(s
->xattr_name
);
3897 s
->xattr_name
= NULL
;
3899 if (rv
== COPYFILE_QUIT
)
3908 if (datasize
> XATTR_MAXATTRLEN
)
3910 if (COPYFILE_VERBOSE
& s
->flags
)
3911 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
3914 databuf
= malloc(datasize
);
3915 if (databuf
== NULL
) {
3919 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
3922 s
->xattr_name
= strdup(nameptr
);
3923 rv
= (*s
->statuscb
)(COPYFILE_COPY_XATTR
, COPYFILE_FINISH
, s
, s
->src
, s
->dst
, s
->ctx
);
3924 if (s
->xattr_name
) {
3925 free(s
->xattr_name
);
3926 s
->xattr_name
= NULL
;
3928 if (rv
== COPYFILE_QUIT
) {
3936 entry
->length
= (u_int32_t
)datasize
;
3937 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
3939 filehdr
->data_length
+= (u_int32_t
)datasize
;
3942 * This assumes that the data is fits in memory (not
3943 * the case when there are lots of attributes or one of
3944 * the attributes is very large.
3946 if (entry
->offset
> ATTR_MAX_SIZE
||
3947 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
3950 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
3954 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
3956 /* bump to next entry */
3957 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
3958 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
3961 if (filehdr
->data_length
> 0)
3963 /* Now we know where the resource fork data starts. */
3964 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
3966 /* We also know the size of the "Finder Info entry. */
3967 filehdr
->appledouble
.entries
[0].length
=
3968 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
3970 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
3973 /* Copy Resource Fork. */
3974 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
3977 /* Write the header to disk. */
3978 datasize
= filehdr
->appledouble
.entries
[1].offset
;
3980 swap_adhdr(&filehdr
->appledouble
);
3981 swap_attrhdr(filehdr
);
3983 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
3985 if (COPYFILE_VERBOSE
& s
->flags
)
3986 copyfile_warn("couldn't write file header");
3991 if (filehdr
) free(filehdr
);
3992 if (attrnamebuf
) free(attrnamebuf
);
3997 return copyfile_stat(s
);