2 * Copyright (c) 2004 Apple Computer, 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>
39 #include <sys/syscall.h>
40 #include <sys/param.h>
41 #include <sys/mount.h>
43 #include <libkern/OSByteOrder.h>
44 #include <membership.h>
48 #include <TargetConditionals.h>
49 #if !TARGET_OS_EMBEDDED
50 #include <quarantine.h>
52 #define XATTR_QUARANTINE_NAME qtn_xattr_name
53 #else /* TARGET_OS_EMBEDDED */
54 #define qtn_file_t void *
55 #define QTN_SERIALIZED_DATA_MAX 0
56 static void * qtn_file_alloc(void) { return NULL
; }
57 static int qtn_file_init_with_fd(void *x
, int y
) { return -1; }
58 static void qtn_file_free(void *x
) { return; }
59 static int qtn_file_apply_to_fd(void *x
, int y
) { return -1; }
60 static char *qtn_error(int x
) { return NULL
; }
61 static int qtn_file_to_data(void *x
, char *y
, size_t z
) { return -1; }
62 static void *qtn_file_clone(void *x
) { return NULL
; }
63 #define XATTR_QUARANTINE_NAME "figgledidiggledy"
64 #endif /* TARGET_OS_EMBEDDED */
68 enum cfInternalFlags
{
73 * The state structure keeps track of
74 * the source filename, the destination filename, their
75 * associated file-descriptors, the stat infomration for the
76 * source file, the security information for the source file,
77 * the flags passed in for the copy, a pointer to place statistics
78 * (not currently implemented), debug flags, and a pointer to callbacks
79 * (not currently implemented).
81 struct _copyfile_state
89 copyfile_flags_t flags
;
90 unsigned int internal_flags
;
93 copyfile_callback_t statuscb
;
95 qtn_file_t qinfo
; /* Quarantine information -- probably NULL */
96 filesec_t original_fsec
;
97 filesec_t permissive_fsec
;
104 #define _ACL_ENTRY_MAGIC 0xac1ac101
106 guid_t ae_applicable
;
111 #define PACE(ace) do { \
112 struct acl_entry *__t = (struct acl_entry*)(ace); \
113 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
118 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
119 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
123 acl_compare_permset_np(acl_permset_t p1
, acl_permset_t p2
)
125 struct pm
{ u_int32_t ap_perms
; } *ps1
, *ps2
;
126 ps1
= (struct pm
*) p1
;
127 ps2
= (struct pm
*) p2
;
129 return ((ps1
->ap_perms
== ps2
->ap_perms
) ? 1 : 0);
133 * Internally, the process is broken into a series of
136 static int copyfile_open (copyfile_state_t
);
137 static int copyfile_close (copyfile_state_t
);
138 static int copyfile_data (copyfile_state_t
);
139 static int copyfile_stat (copyfile_state_t
);
140 static int copyfile_security (copyfile_state_t
);
141 static int copyfile_xattr (copyfile_state_t
);
142 static int copyfile_pack (copyfile_state_t
);
143 static int copyfile_unpack (copyfile_state_t
);
145 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
146 static filesec_t
copyfile_fix_perms(copyfile_state_t
, filesec_t
*);
147 static int copyfile_preamble(copyfile_state_t
*s
, copyfile_flags_t flags
);
148 static int copyfile_internal(copyfile_state_t state
, copyfile_flags_t flags
);
149 static int copyfile_unset_posix_fsec(filesec_t
);
150 static int copyfile_quarantine(copyfile_state_t
);
152 #define COPYFILE_DEBUG (1<<31)
153 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
155 #ifndef _COPYFILE_TEST
156 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
157 # define copyfile_debug(d, str, ...) \
159 if (s && (d <= s->debug)) {\
160 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
164 #define copyfile_warn(str, ...) \
165 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
166 # define copyfile_debug(d, str, ...) \
168 if (s && (d <= s->debug)) {\
169 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
174 static int copyfile_quarantine(copyfile_state_t s
)
177 if (s
->qinfo
== NULL
)
180 s
->qinfo
= qtn_file_alloc();
181 if (s
->qinfo
== NULL
)
186 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
188 qtn_file_free(s
->qinfo
);
199 add_uberace(acl_t
*acl
)
202 acl_permset_t permset
;
205 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
209 * First, we create an entry, and give it the special name
210 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
211 * After that, we clear out all the permissions in it, and
212 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
213 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
214 * the functionality, and put this into the ACL.
216 if (acl_create_entry_np(acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
218 if (acl_get_permset(entry
, &permset
) == -1)
220 if (acl_clear_perms(permset
) == -1)
222 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
224 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
226 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
228 if (acl_add_perm(permset
, ACL_APPEND_DATA
) == -1)
230 if (acl_add_perm(permset
, ACL_WRITE_SECURITY
) == -1)
232 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
235 if(acl_set_permset(entry
, permset
) == -1)
237 if(acl_set_qualifier(entry
, qual
) == -1)
246 is_uberace(acl_entry_t ace
)
249 acl_permset_t perms
, tperms
;
256 // Who am I, and who is the ACE for?
257 mbr_uid_to_uuid(geteuid(), myuuid
);
258 qual
= (guid_t
*)acl_get_qualifier(ace
);
260 // Need to create a temporary acl, so I can get the uberace template.
266 if (acl_get_entry(tacl
, ACL_FIRST_ENTRY
, &tentry
) != 0) {
269 acl_get_permset(tentry
, &tperms
);
272 acl_get_tag_type(ace
, &tag
);
273 acl_get_permset(ace
, &perms
);
275 if (tag
== ACL_EXTENDED_ALLOW
&&
276 (memcmp(qual
, myuuid
, sizeof(myuuid
)) == 0) &&
277 acl_compare_permset_np(tperms
, perms
))
289 remove_uberace(int fd
, struct stat
*sbuf
)
291 filesec_t fsec
= NULL
;
296 fsec
= filesec_init();
301 if (fstatx_np(fd
, &sb
, fsec
) != 0) {
302 if (errno
== ENOTSUP
)
307 if (filesec_get_property(fsec
, FILESEC_ACL
, &acl
) != 0) {
311 if (acl_get_entry(acl
, ACL_FIRST_ENTRY
, &entry
) == 0) {
312 if (is_uberace(entry
))
314 mode_t m
= sbuf
->st_mode
& ~S_IFMT
;
316 if (acl_delete_entry(acl
, entry
) != 0 ||
317 filesec_set_property(fsec
, FILESEC_ACL
, &acl
) != 0 ||
318 filesec_set_property(fsec
, FILESEC_MODE
, &m
) != 0 ||
319 fchmodx_np(fd
, fsec
) != 0)
332 fchmod(fd
, sbuf
->st_mode
& ~S_IFMT
);
337 reset_security(copyfile_state_t s
)
339 /* If we haven't reset the file security information
340 * (COPYFILE_SECURITY is not set in flags)
341 * restore back the permissions the file had originally
343 * One of the reasons this seems so complicated is that
344 * it is partially at odds with copyfile_security().
346 * Simplisticly, we are simply trying to make sure we
347 * only copy what was requested, and that we don't stomp
348 * on what wasn't requested.
351 #ifdef COPYFILE_RECURSIVE
352 if (s
->dst_fd
> -1) {
355 if (s
->src_fd
> -1 && (s
->flags
& COPYFILE_STAT
))
356 fstat(s
->src_fd
, &sbuf
);
358 fstat(s
->dst_fd
, &sbuf
);
360 if (!(s
->internal_flags
& cfDelayAce
))
361 remove_uberace(s
->dst_fd
, &sbuf
);
364 if (s
->permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
365 if (s
->flags
& COPYFILE_ACL
) {
366 /* Just need to reset the BSD information -- mode, owner, group */
367 (void)fchown(s
->dst_fd
, s
->dst_sb
.st_uid
, s
->dst_sb
.st_gid
);
368 (void)fchmod(s
->dst_fd
, s
->dst_sb
.st_mode
);
371 * flags is either COPYFILE_STAT, or neither; if it's
372 * neither, then we restore both ACL and POSIX permissions;
373 * if it's STAT, however, then we only want to restore the
374 * ACL (which may be empty). We do that by removing the
375 * POSIX information from the filesec object.
377 if (s
->flags
& COPYFILE_STAT
) {
378 copyfile_unset_posix_fsec(s
->original_fsec
);
380 if (fchmodx_np(s
->dst_fd
, s
->original_fsec
) < 0 && errno
!= ENOTSUP
)
381 copyfile_warn("restoring security information");
385 if (s
->permissive_fsec
) {
386 filesec_free(s
->permissive_fsec
);
387 s
->permissive_fsec
= NULL
;
390 if (s
->original_fsec
) {
391 filesec_free(s
->original_fsec
);
392 s
->original_fsec
= NULL
;
400 * copytree -- recursively copy a hierarchy.
402 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
403 * Care is taken to keep the ACLs set up correctly, in addition to the
404 * normal copying that is done. (When copying a hierarchy, we can't
405 * get rid of the "allow-all-writes" ACE on a directory until we're done
406 * copying the *contents* of the directory.)
408 * The other big difference from copyfile (for the moment) is that copytree()
409 * will use a call-back function to pass along information about what is
410 * about to be copied, and whether or not it succeeded.
412 * copytree() is called from copyfile() -- but copytree() itself then calls
413 * copyfile() to copy each individual object.
415 * XXX - no effort is made to handle overlapping hierarchies at the moment.
420 copytree(copyfile_state_t s
)
424 int (*sfunc
)(const char *, struct stat
*);
425 copyfile_callback_t status
= NULL
;
426 char srcisdir
= 0, dstisdir
= 0, dstexists
= 0;
429 const char *dstpathsep
= "";
431 char srcpath
[PATH_MAX
* 2 + 1], dstpath
[PATH_MAX
* 2 + 1];
437 const char *paths
[2] = { 0 };
438 unsigned int flags
= 0;
439 int fts_flags
= FTS_NOCHDIR
;
446 if (s
->flags
& (COPYFILE_MOVE
| COPYFILE_UNLINK
| COPYFILE_CHECK
| COPYFILE_PACK
| COPYFILE_UNPACK
)) {
452 flags
= s
->flags
& (COPYFILE_ALL
| COPYFILE_NOFOLLOW
| COPYFILE_VERBOSE
);
454 paths
[0] = src
= s
->src
;
457 if (src
== NULL
|| dst
== NULL
) {
463 sfunc
= (flags
& COPYFILE_NOFOLLOW_SRC
) ? lstat
: stat
;
464 if ((sfunc
)(src
, &sbuf
) == -1) {
468 if (sbuf
.st_mode
& S_IFDIR
) {
472 sfunc
= (flags
& COPYFILE_NOFOLLOW_DST
) ? lstat
: stat
;
473 if ((sfunc
)(dst
, &sbuf
) == -1) {
474 if (errno
!= ENOENT
) {
480 if ((sbuf
.st_mode
& S_IFMT
) == S_IFDIR
) {
486 // This doesn't handle filesystem crossing and case sensitivity
487 // So there's got to be a better way
489 if (realpath(src
, srcpath
) == NULL
) {
494 if (realpath(dst
, dstpath
) == NULL
&&
495 (errno
== ENOENT
&& realpath(dirname(dst
), dstpath
) == NULL
)) {
499 if (strstr(srcpath
, dstpath
) != NULL
) {
505 srcroot
= basename((char*)src
);
506 if (srcroot
== NULL
) {
512 * To work on as well:
513 * We have a few cases when copying a hierarchy:
514 * 1) src is a non-directory, dst is a directory;
515 * 2) src is a non-directory, dst is a non-directory;
516 * 3) src is a non-directory, dst does not exist;
517 * 4) src is a directory, dst is a directory;
518 * 5) src is a directory, dst is a non-directory;
519 * 6) src is a directory, dst does not exist
521 * (1) copies src to dst/basename(src).
522 * (2) fails if COPYFILE_EXCLUSIVE is set, otherwise copies src to dst.
523 * (3) and (6) copy src to the name dst.
524 * (4) copies the contents of src to the contents of dst.
529 // copy /path/to/src to /path/to/dst/src
530 // Append "/" and (fts_path - strlen(basename(src))) to dst?
532 slash
= strrchr(src
, '/');
536 offset
= slash
- src
+ 1;
538 // copy /path/to/src to /path/to/dst
539 // append (fts_path + strlen(src)) to dst?
541 offset
= strlen(src
);
544 if (s
->flags
| COPYFILE_NOFOLLOW_SRC
)
545 fts_flags
|= FTS_PHYSICAL
;
547 fts_flags
|= FTS_LOGICAL
;
549 fts
= fts_open((char * const *)paths
, fts_flags
, NULL
);
551 status
= s
->statuscb
;
552 while ((ftsent
= fts_read(fts
)) != NULL
) {
554 char *dstfile
= NULL
;
556 copyfile_state_t tstate
= copyfile_state_alloc();
557 if (tstate
== NULL
) {
562 tstate
->statuscb
= s
->statuscb
;
563 tstate
->ctx
= s
->ctx
;
564 asprintf(&dstfile
, "%s%s%s", dst
, dstpathsep
, ftsent
->fts_path
+ offset
);
565 if (dstfile
== NULL
) {
566 copyfile_state_free(tstate
);
571 switch (ftsent
->fts_info
) {
573 tstate
->internal_flags
|= cfDelayAce
;
574 cmd
= COPYFILE_RECURSE_DIR
;
580 cmd
= COPYFILE_RECURSE_FILE
;
583 cmd
= COPYFILE_RECURSE_DIR_CLEANUP
;
590 errno
= ftsent
->fts_errno
;
592 rv
= (*status
)(COPYFILE_RECURSE_ERROR
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
593 if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
597 if (rv
== COPYFILE_QUIT
) {
610 if (cmd
== COPYFILE_RECURSE_DIR
|| cmd
== COPYFILE_RECURSE_FILE
) {
612 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
613 if (rv
== COPYFILE_SKIP
) {
614 if (cmd
== COPYFILE_RECURSE_DIR
) {
615 rv
= fts_set(fts
, ftsent
, FTS_SKIP
);
617 rv
= (*status
)(0, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
618 if (rv
== COPYFILE_QUIT
)
624 if (rv
== COPYFILE_QUIT
) {
625 retval
= -1; errno
= 0;
629 rv
= copyfile(ftsent
->fts_path
, dstfile
, tstate
, flags
);
632 rv
= (*status
)(cmd
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
633 if (rv
== COPYFILE_QUIT
) {
645 rv
= (*status
)(cmd
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
646 if (rv
== COPYFILE_QUIT
) {
647 retval
= -1; errno
= 0;
651 } else if (cmd
== COPYFILE_RECURSE_DIR_CLEANUP
) {
655 rv
= (*status
)(cmd
, COPYFILE_START
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
656 if (rv
== COPYFILE_QUIT
) {
657 retval
= -1; errno
= 0;
659 } else if (rv
== COPYFILE_SKIP
) {
664 tfd
= open(dstfile
, O_RDONLY
);
667 if (s
->flags
& COPYFILE_STAT
) {
668 (s
->flags
& COPYFILE_NOFOLLOW_SRC
? lstat
: stat
)(ftsent
->fts_path
, &sb
);
670 (s
->flags
& COPYFILE_NOFOLLOW_DST
? lstat
: stat
)(dstfile
, &sb
);
672 remove_uberace(tfd
, &sb
);
675 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_FINISH
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
676 if (rv
== COPYFILE_QUIT
) {
683 rv
= (*status
)(COPYFILE_RECURSE_DIR_CLEANUP
, COPYFILE_ERR
, tstate
, ftsent
->fts_path
, dstfile
, s
->ctx
);
684 if (rv
== COPYFILE_QUIT
) {
687 } else if (rv
== COPYFILE_SKIP
|| rv
== COPYFILE_CONTINUE
) {
688 if (rv
== COPYFILE_CONTINUE
)
702 copyfile_state_free(tstate
);
716 * fcopyfile() is used to copy a source file descriptor to a destination file
717 * descriptor. This allows an application to figure out how it wants to open
718 * the files (doing various security checks, perhaps), and then just pass in
719 * the file descriptors.
721 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
724 copyfile_state_t s
= state
;
727 if (src_fd
< 0 || dst_fd
< 0)
733 if (copyfile_preamble(&s
, flags
) < 0)
736 copyfile_debug(2, "set src_fd <- %d", src_fd
);
737 if (s
->src_fd
== -2 && src_fd
> -1)
740 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
742 if (errno
== ENOTSUP
|| errno
== EPERM
)
743 fstat(s
->src_fd
, &s
->sb
);
746 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
752 /* prevent copying on unsupported types */
753 switch (s
->sb
.st_mode
& S_IFMT
)
764 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
765 if (s
->dst_fd
== -2 && dst_fd
> -1)
768 (void)fstat(s
->dst_fd
, &dst_sb
);
769 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
771 (void)copyfile_quarantine(s
);
773 ret
= copyfile_internal(s
, flags
);
775 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
777 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
786 copyfile_state_free(s
);
795 * the original copyfile() routine; this copies a source file to a destination
796 * file. Note that because we need to set the names in the state variable, this
797 * is not just the same as opening the two files, and then calling fcopyfile().
798 * Oh, if only life were that simple!
800 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
804 copyfile_state_t s
= state
;
807 if (src
== NULL
&& dst
== NULL
)
813 if (copyfile_preamble(&s
, flags
) < 0)
819 * This macro is... well, it's not the worst thing you can do with cpp, not
820 * by a long shot. Essentially, we are setting the filename (src or dst)
821 * in the state structure; since the structure may not have been cleared out
822 * before being used again, we do some of the cleanup here: if the given
823 * filename (e.g., src) is set, and state->src is not equal to that, then
824 * we need to check to see if the file descriptor had been opened, and if so,
825 * close it. After that, we set state->src to be a copy of the given filename,
826 * releasing the old copy if necessary.
828 #define COPYFILE_SET_FNAME(NAME, S) \
830 if (NAME != NULL) { \
831 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
832 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
833 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
834 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
835 close(S->NAME##_fd); \
843 if ((S->NAME = strdup(NAME)) == NULL) \
848 COPYFILE_SET_FNAME(src
, s
);
849 COPYFILE_SET_FNAME(dst
, s
);
851 if (s
->flags
& COPYFILE_RECURSIVE
) {
857 * Get a copy of the source file's security settings
859 if ((s
->original_fsec
= filesec_init()) == NULL
)
862 if ((s
->flags
& COPYFILE_NOFOLLOW_DST
) && lstat(s
->dst
, &dst_sb
) == 0 &&
863 (dst_sb
.st_mode
& S_IFLNK
)) {
864 if (s
->permissive_fsec
)
865 free(s
->permissive_fsec
);
866 s
->permissive_fsec
= NULL
;
867 } else if(statx_np(s
->dst
, &dst_sb
, s
->original_fsec
) == 0)
870 * copyfile_fix_perms() will make a copy of the permission set,
871 * and insert at the beginning an ACE that ensures we can write
872 * to the file and set attributes.
875 if((s
->permissive_fsec
= copyfile_fix_perms(s
, &s
->original_fsec
)) != NULL
)
878 * Set the permissions for the destination to our copy.
879 * We should get ENOTSUP from any filesystem that simply
880 * doesn't support it.
882 if (chmodx_np(s
->dst
, s
->permissive_fsec
) < 0 && errno
!= ENOTSUP
)
884 copyfile_warn("setting security information");
885 filesec_free(s
->permissive_fsec
);
886 s
->permissive_fsec
= NULL
;
889 } else if (errno
== ENOENT
) {
894 * If COPYFILE_CHECK is set in flags, then all we are going to do
895 * is see what kinds of things WOULD have been copied (see
896 * copyfile_check() below). We return that value.
898 if (COPYFILE_CHECK
& flags
)
900 ret
= copyfile_check(s
);
902 } else if ((ret
= copyfile_open(s
)) < 0)
905 ret
= copyfile_internal(s
, flags
);
909 #ifdef COPYFILE_RECURSIVE
910 if (!(flags
& COPYFILE_STAT
)) {
913 /* Just need to reset the BSD information -- mode, owner, group */
914 (void)fchown(s
->dst_fd
, dst_sb
.st_uid
, dst_sb
.st_gid
);
915 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
);
925 copyfile_state_free(s
);
941 * Shared prelude to the {f,}copyfile(). This initializes the
942 * state variable, if necessary, and also checks for both debugging
943 * and disabling environment variables.
945 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
951 if ((*state
= copyfile_state_alloc()) == NULL
)
957 if (COPYFILE_DEBUG
& flags
)
960 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
963 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
965 /* clamp s->debug to 1 if the environment variable is not parsable */
966 if (s
->debug
== 0 && errno
!= 0)
969 copyfile_debug(2, "debug value set to: %d", s
->debug
);
973 /* Temporarily disabled */
974 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
976 copyfile_debug(1, "copyfile disabled");
980 copyfile_debug(2, "setting flags: %d", s
->flags
);
987 * The guts of {f,}copyfile().
988 * This looks through the flags in a particular order, and calls the
989 * associated functions.
991 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
995 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
997 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s
->src_fd
, s
->dst_fd
);
1003 * COPYFILE_PACK causes us to create an Apple Double version of the
1004 * source file, and puts it into the destination file. See
1005 * copyfile_pack() below for all the gory details.
1007 if (COPYFILE_PACK
& flags
)
1009 if ((ret
= copyfile_pack(s
)) < 0)
1011 if (s
->dst
) unlink(s
->dst
);
1018 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1019 * The goal there is to take an Apple Double file, and turn it
1020 * into a normal file (with data fork, resource fork, modes,
1021 * extended attributes, ACLs, etc.).
1023 if (COPYFILE_UNPACK
& flags
)
1025 if ((ret
= copyfile_unpack(s
)) < 0)
1031 * If we have quarantine info set, we attempt
1032 * to apply it to dst_fd. We don't care if
1033 * it fails, not yet anyway.
1036 (void)qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
1039 * COPYFILE_XATTR tells us to copy the extended attributes;
1040 * this is seperate from the extended security (aka ACLs),
1041 * however. If we succeed in this, we continue to the next
1042 * stage; if we fail, we return with an error value. Note
1043 * that we fail if the errno is ENOTSUP, but we don't print
1044 * a warning in that case.
1046 if (COPYFILE_XATTR
& flags
)
1048 if ((ret
= copyfile_xattr(s
)) < 0)
1050 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
1051 copyfile_warn("error processing extended attributes");
1057 * Simialr to above, this tells us whether or not to copy
1058 * the non-meta data portion of the file. We attempt to
1059 * remove (via unlink) the destination file if we fail.
1061 if (COPYFILE_DATA
& flags
)
1063 if ((ret
= copyfile_data(s
)) < 0)
1065 copyfile_warn("error processing data");
1066 if (s
->dst
&& unlink(s
->dst
))
1067 copyfile_warn("%s: remove", s
->src
? s
->src
: "(null src)");
1073 * COPYFILE_SECURITY requests that we copy the security, both
1074 * extended and mundane (that is, ACLs and POSIX).
1076 if (COPYFILE_SECURITY
& flags
)
1078 if ((ret
= copyfile_security(s
)) < 0)
1080 copyfile_warn("error processing security information");
1085 if (COPYFILE_STAT
& flags
)
1087 if ((ret
= copyfile_stat(s
)) < 0)
1089 copyfile_warn("error processing POSIX information");
1103 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1105 copyfile_state_t
copyfile_state_alloc(void)
1107 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
1113 s
->fsec
= filesec_init();
1121 * copyfile_state_free() returns the memory allocated to the state structure.
1122 * It also closes the file descriptors, if they've been opened.
1124 int copyfile_state_free(copyfile_state_t s
)
1129 filesec_free(s
->fsec
);
1131 if (s
->original_fsec
)
1132 filesec_free(s
->original_fsec
);
1134 if (s
->permissive_fsec
)
1135 filesec_free(s
->permissive_fsec
);
1138 qtn_file_free(s
->qinfo
);
1140 if (copyfile_close(s
) < 0)
1142 copyfile_warn("error closing files");
1155 * Should we worry if we can't close the source? NFS says we
1156 * should, but it's pretty late for us at this point.
1158 static int copyfile_close(copyfile_state_t s
)
1160 if (s
->src
&& s
->src_fd
>= 0)
1163 if (s
->dst
&& s
->dst_fd
>= 0) {
1164 if (close(s
->dst_fd
))
1172 * The purpose of this function is to set up a set of permissions
1173 * (ACL and traditional) that lets us write to the file. In the
1174 * case of ACLs, we do this by putting in a first entry that lets
1175 * us write data, attributes, and extended attributes. In the case
1176 * of traditional permissions, we set the S_IWUSR (user-write)
1179 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
1181 filesec_t ret_fsec
= NULL
;
1185 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
1188 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
1190 #ifdef COPYFILE_RECURSIVE
1191 if (add_uberace(&acl
))
1195 acl_permset_t permset
;
1198 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
1202 * First, we create an entry, and give it the special name
1203 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1204 * After that, we clear out all the permissions in it, and
1205 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1206 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1207 * the functionality, and put this into the ACL.
1209 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
1211 if (acl_get_permset(entry
, &permset
) == -1)
1213 if (acl_clear_perms(permset
) == -1)
1215 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
1217 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
1219 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
1221 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
1224 if(acl_set_permset(entry
, permset
) == -1)
1226 if(acl_set_qualifier(entry
, qual
) == -1)
1230 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
1235 * This is for the normal, mundane, POSIX permission model.
1236 * We make sure that we can write to the file.
1238 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
1240 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
1242 mode
|= S_IWUSR
|S_IRUSR
;
1243 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
1257 filesec_free(ret_fsec
);
1264 * Used to clear out the BSD/POSIX security information from
1268 copyfile_unset_posix_fsec(filesec_t fsec
)
1270 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
1271 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
1272 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
1277 * Used to remove acl information from a filesec_t
1278 * Unsetting the acl alone in Tiger was insufficient
1280 static int copyfile_unset_acl(copyfile_state_t s
)
1283 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
1285 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1288 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
1290 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1293 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
1295 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
? s
->dst
: "(null dst)");
1302 * copyfile_open() does what one expects: it opens up the files
1303 * given in the state structure, if they're not already open.
1304 * It also does some type validation, to ensure that we only
1305 * handle file types we know about.
1307 static int copyfile_open(copyfile_state_t s
)
1309 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
1310 int islnk
= 0, isdir
= 0;
1311 int osrc
= 0, dsrc
= 0;
1313 if (s
->src
&& s
->src_fd
== -2)
1315 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1316 (s
->src
, &s
->sb
, s
->fsec
))
1318 copyfile_warn("stat on %s", s
->src
);
1322 /* prevent copying on unsupported types */
1323 switch (s
->sb
.st_mode
& S_IFMT
)
1327 if ((size_t)s
->sb
.st_size
> SIZE_T_MAX
) {
1328 s
->err
= ENOMEM
; /* too big for us to copy */
1339 if (!(strcmp(s
->src
, "/dev/null") == 0 && (s
->flags
& COPYFILE_METADATA
))) {
1345 * If we're packing, then we are actually
1346 * creating a file, no matter what the source
1349 if (s
->flags
& COPYFILE_PACK
) {
1351 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1352 * if the file is a symlink, and O_NOFOLLOW is specified,
1353 * open will return ELOOP, whether or not O_SYMLINK is set.
1354 * However, we know whether or not it was a symlink from
1355 * the stat above (although there is a potentiaal for a race
1356 * condition here, but it will err on the side of returning
1360 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
1364 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
1366 copyfile_warn("open on %s", s
->src
);
1369 copyfile_debug(2, "open successful on source (%s)", s
->src
);
1371 (void)copyfile_quarantine(s
);
1374 if (s
->dst
&& s
->dst_fd
== -2)
1377 * COPYFILE_UNLINK tells us to try removing the destination
1378 * before we create it. We don't care if the file doesn't
1379 * exist, so we ignore ENOENT.
1381 if (COPYFILE_UNLINK
& s
->flags
)
1383 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
1385 copyfile_warn("%s: remove", s
->dst
);
1390 if (s
->flags
& COPYFILE_NOFOLLOW_DST
) {
1394 if (lstat(s
->dst
, &st
) != -1) {
1395 if ((st
.st_mode
& S_IFMT
) == S_IFLNK
)
1401 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
1406 copyfile_warn("cannot allocate %d bytes", sz
);
1409 if (readlink(s
->src
, bp
, sz
-1) == -1) {
1410 copyfile_warn("cannot readlink %s", s
->src
);
1414 if (symlink(bp
, s
->dst
) == -1) {
1415 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1416 copyfile_warn("Cannot make symlink %s", s
->dst
);
1422 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
1423 if (s
->dst_fd
== -1) {
1424 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
1429 mode
= s
->sb
.st_mode
& ~S_IFMT
;
1431 if (mkdir(s
->dst
, mode
) == -1) {
1432 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
1433 copyfile_warn("Cannot make directory %s", s
->dst
);
1437 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
1438 if (s
->dst_fd
== -1) {
1439 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
1442 } else while((s
->dst_fd
= open(s
->dst
, oflags
| dsrc
, s
->sb
.st_mode
| S_IWUSR
)) < 0)
1445 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1446 * was written -- allow one to set an extended attribute on a file descriptor
1447 * for a read-only file, even if the file descriptor is opened for writing.
1448 * This will only matter if the file does not already exist.
1453 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
1454 if (s
->flags
& COPYFILE_EXCL
)
1456 oflags
= oflags
& ~O_CREAT
;
1457 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
1459 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
1464 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
1468 * If we're trying to write to a directory to which we don't
1469 * have access, the create above would have failed, but chmod
1470 * here would have given us ENOENT. But the real error is
1471 * still one of access, so we change the errno we're reporting.
1472 * This could cause confusion with a race condition.
1475 if (errno
== ENOENT
)
1480 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
1481 if ((s
->flags
& COPYFILE_EXCL
) ||
1482 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
1484 oflags
= (oflags
& ~O_WRONLY
) | O_RDONLY
;
1487 copyfile_warn("open on %s", s
->dst
);
1490 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
1493 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
1495 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1496 s
->src_fd
, s
->dst_fd
);
1505 * copyfile_check(), as described above, essentially tells you
1506 * what you'd have to copy, if you wanted it to copy the things
1507 * you asked it to copy.
1508 * In other words, if you pass in COPYFILE_ALL, and the file in
1509 * question had no extended attributes but did have an ACL, you'd
1510 * get back COPYFILE_ACL.
1512 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
1515 copyfile_flags_t ret
= 0;
1516 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
1526 if (COPYFILE_XATTR
& s
->flags
)
1527 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
1529 ret
|= COPYFILE_XATTR
;
1532 if (COPYFILE_ACL
& s
->flags
)
1534 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
1535 (s
->src
, &s
->sb
, s
->fsec
);
1537 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
1538 ret
|= COPYFILE_ACL
;
1541 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
1547 /* If the state has had quarantine info set already, we use that */
1548 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1550 qinfo
= qtn_file_alloc();
1552 * For quarantine information, we need to see if the source file
1553 * has any. Since it may be a symlink, however, and we may, or
1554 * not be following, *and* there's no qtn* routine which can optionally
1555 * follow or not follow a symlink, we need to instead work around
1564 * If we care about not following symlinks, *and* the file exists
1565 * (which is to say, lstat doesn't return an error), *and* the file
1566 * is a symlink, then we open it up (with O_SYMLINK), and use
1567 * qtn_file_init_with_fd(); if none of that is true, however, then
1568 * we can simply use qtn_file_init_with_path().
1571 && lstat(s
->src
, &sbuf
) == 0
1572 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
1573 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
1575 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
1576 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1581 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
1582 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
1585 qtn_file_free(qinfo
);
1593 * Attempt to copy the data section of a file. Using blockisize
1594 * is not necessarily the fastest -- it might be desirable to
1595 * specify a blocksize, somehow. But it's a size that should be
1596 * guaranteed to work.
1598 static int copyfile_data(copyfile_state_t s
)
1604 size_t iBlocksize
= 0;
1605 size_t oBlocksize
= 0;
1606 const size_t onegig
= 1 << 30;
1608 copyfile_callback_t status
= s
->statuscb
;
1610 /* Unless it's a normal file, we don't copy. For now, anyway */
1611 if ((s
->sb
.st_mode
& S_IFMT
) != S_IFREG
)
1614 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
1615 iBlocksize
= s
->sb
.st_blksize
;
1617 iBlocksize
= sfs
.f_iosize
;
1620 /* Work-around for 6453525, limit blocksize to 1G */
1621 if (iBlocksize
> onegig
) {
1622 iBlocksize
= onegig
;
1625 if ((bp
= malloc(iBlocksize
)) == NULL
)
1628 if (fstatfs(s
->dst_fd
, &sfs
) == -1 || sfs
.f_iosize
== 0) {
1629 oBlocksize
= iBlocksize
;
1631 oBlocksize
= sfs
.f_iosize
;
1632 if (oBlocksize
> onegig
)
1633 oBlocksize
= onegig
;
1639 /* If supported, do preallocation for Xsan / HFS volumes */
1640 #ifdef F_PREALLOCATE
1645 fst
.fst_posmode
= F_PEOFPOSMODE
;
1647 fst
.fst_length
= s
->sb
.st_size
;
1648 /* Ignore errors; this is merely advisory. */
1649 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
1653 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
1656 size_t left
= nread
;
1661 nwritten
= write(s
->dst_fd
, ptr
, MIN(left
, oBlocksize
));
1665 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
1672 copyfile_warn("writing to output file got error");
1674 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_ERR
, s
, s
->src
, s
->dst
, s
->ctx
);
1675 if (rv
== COPYFILE_SKIP
) { // Skip the data copy
1679 if (rv
== COPYFILE_CONTINUE
) { // Retry the write
1688 ptr
= ((char*)ptr
) + nwritten
;
1692 s
->totalCopied
+= nwritten
;
1694 int rv
= (*status
)(COPYFILE_COPY_DATA
, COPYFILE_PROGRESS
, s
, s
->src
, s
->dst
, s
->ctx
);
1695 if (rv
== COPYFILE_QUIT
) {
1696 ret
= -1; s
->err
= ECANCELED
;
1704 copyfile_warn("reading from %s", s
->src
? s
->src
: "(null src)");
1709 if (ftruncate(s
->dst_fd
, s
->sb
.st_size
) < 0)
1725 * copyfile_security() will copy the ACL set, and the
1726 * POSIX set. Complexities come when dealing with
1727 * inheritied permissions, and when dealing with both
1728 * POSIX and ACL permissions.
1730 static int copyfile_security(copyfile_state_t s
)
1733 int has_uberace
= 0;
1734 acl_flagset_t flags
;
1736 acl_entry_t entry_src
= NULL
, entry_dst
= NULL
;
1737 acl_t acl_src
= NULL
, acl_dst
= NULL
;
1739 filesec_t tmp_fsec
= NULL
;
1740 filesec_t fsec_dst
= filesec_init();
1742 if (fsec_dst
== NULL
)
1746 if (COPYFILE_ACL
& s
->flags
)
1748 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
1750 if (errno
== ENOENT
)
1756 /* grab the destination acl
1757 cannot assume it's empty due to inheritance
1759 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
1762 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
1764 if (errno
== ENOENT
)
1771 acl_t tmp
= acl_init(4);
1772 acl_entry_t ace
= NULL
;
1779 for (; acl_get_entry(acl_dst
,
1780 ace
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1783 if (count
++ == 0 && is_uberace(ace
)) {
1784 if ((ret
= acl_create_entry(&tmp
, &entry_dst
)) == -1)
1786 if ((ret
= acl_copy_entry(entry_dst
, ace
)) == -1)
1791 acl_get_flagset_np(ace
, &flags
);
1792 if (acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
1794 if ((ret
= acl_create_entry(&tmp
, &entry_dst
)) == -1)
1796 if ((ret
= acl_copy_entry(entry_dst
, ace
)) == -1)
1807 if (acl_src
== NULL
&& acl_dst
== NULL
)
1811 if (acl_dst
== NULL
)
1812 acl_dst
= acl_init(4);
1813 for (copied
= 0;acl_get_entry(acl_src
,
1814 entry_src
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1817 acl_get_flagset_np(entry_src
, &flags
);
1818 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
1820 if ((ret
= acl_create_entry(&acl_dst
, &entry_dst
)) == -1)
1823 if ((ret
= acl_copy_entry(entry_dst
, entry_src
)) == -1)
1826 copyfile_debug(2, "copied acl entry from %s to %s",
1827 s
->src
? s
->src
: "(null src)",
1828 s
->dst
? s
->dst
: "(null dst)");
1833 if (!has_uberace
&& (s
->internal_flags
& cfDelayAce
)) {
1834 if (add_uberace(&acl_dst
))
1837 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_dst
))
1839 copyfile_debug(3, "altered acl");
1844 * The following code is attempting to ensure that only the requested
1845 * security information gets copied over to the destination file.
1846 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
1847 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
1850 * If we have both flags, we copy everything; if we have ACL but not STAT,
1851 * we remove the POSIX information from the filesec object, and apply the
1852 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
1853 * the extended version.
1855 tmp_fsec
= filesec_dup(s
->fsec
);
1856 if (tmp_fsec
== NULL
) {
1860 switch (COPYFILE_SECURITY
& s
->flags
) {
1862 copyfile_unset_posix_fsec(tmp_fsec
);
1864 case COPYFILE_ACL
| COPYFILE_STAT
:
1865 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
1868 * The call could have failed for a number of reasons, since
1869 * it does a number of things: it changes the mode of the file,
1870 * sets the owner and group, and applies an ACL (if one exists).
1871 * The typical failure is going to be trying to set the group of
1872 * the destination file to match the source file, when the process
1873 * doesn't have permission to put files in that group. We try to
1874 * work around this by breaking the steps out and doing them
1875 * discretely. We don't care if the fchown fails, but we do care
1876 * if the mode or ACL can't be set. For historical reasons, we
1877 * simply log those failures, however.
1880 #define NS(x) ((x) ? (x) : "(null string)")
1881 if (fchmod(s
->dst_fd
, s
->sb
.st_mode
) == -1) {
1882 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s
->dst
), NS(s
->src
));
1884 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
1885 if (filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
) == 0) {
1886 if (acl_set_fd(s
->dst_fd
, acl
) == -1) {
1887 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s
->dst
), NS(s
->src
));
1895 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
);
1898 filesec_free(tmp_fsec
);
1900 filesec_free(fsec_dst
);
1901 if (acl_src
) acl_free(acl_src
);
1902 if (acl_dst
) acl_free(acl_dst
);
1913 * Attempt to set the destination file's stat information -- including
1914 * flags and time-related fields -- to the source's.
1916 static int copyfile_stat(copyfile_state_t s
)
1918 struct timeval tval
[2];
1920 * NFS doesn't support chflags; ignore errors unless there's reason
1921 * to believe we're losing bits. (Note, this still won't be right
1922 * if the server supports flags and we were trying to *remove* flags
1923 * on a file that we copied, i.e., that we didn't create.)
1925 if (fchflags(s
->dst_fd
, (u_int
)s
->sb
.st_flags
))
1926 if (errno
!= EOPNOTSUPP
|| s
->sb
.st_flags
!= 0)
1927 copyfile_warn("%s: set flags (was: 0%07o)", s
->dst
? s
->dst
: "(null dst)", s
->sb
.st_flags
);
1929 /* If this fails, we don't care */
1930 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
1932 /* This may have already been done in copyfile_security() */
1933 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
1935 tval
[0].tv_sec
= s
->sb
.st_atime
;
1936 tval
[1].tv_sec
= s
->sb
.st_mtime
;
1937 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
1938 if (futimes(s
->dst_fd
, tval
))
1939 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
1944 * Similar to copyfile_security() in some ways; this
1945 * routine copies the extended attributes from the source,
1946 * and sets them on the destination.
1947 * The procedure is pretty simple, even if it is verbose:
1948 * for each named attribute on the destination, get its name, and
1949 * remove it. We should have none after that.
1950 * For each named attribute on the source, get its name, get its
1951 * data, and set it on the destination.
1953 static int copyfile_xattr(copyfile_state_t s
)
1956 char *namebuf
, *end
;
1959 ssize_t bufsize
= 4096;
1964 /* delete EAs on destination */
1965 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
1967 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
1970 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
1974 * With this, end points to the last byte of the allocated buffer
1975 * This *should* be NUL, from flistxattr, but if it's not, we can
1976 * set it anyway -- it'll result in a truncated name, which then
1977 * shouldn't match when we get them later.
1979 end
= namebuf
+ nsize
- 1;
1982 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
1983 /* If the quarantine information shows up as an EA, we skip over it */
1984 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
1987 fremovexattr(s
->dst_fd
, name
,0);
1994 if (errno
== ENOTSUP
|| errno
== EPERM
)
2000 /* get name list of EAs on source */
2001 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, 0)) < 0)
2003 if (errno
== ENOTSUP
|| errno
== EPERM
)
2011 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
2014 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, 0);
2022 * With this, end points to the last byte of the allocated buffer
2023 * This *should* be NUL, from flistxattr, but if it's not, we can
2024 * set it anyway -- it'll result in a truncated name, which then
2025 * shouldn't match when we get them later.
2027 end
= namebuf
+ nsize
- 1;
2031 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
2036 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
2038 /* If the quarantine information shows up as an EA, we skip over it */
2039 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
2042 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, 0)) < 0)
2048 if (xa_size
> bufsize
)
2050 void *tdptr
= xa_dataptr
;
2053 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
2061 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, 0)) < 0)
2067 if (xa_size
!= asize
)
2070 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, 0) < 0)
2078 free((void *) xa_dataptr
);
2083 * API interface into getting data from the opaque data type.
2085 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
2095 case COPYFILE_STATE_SRC_FD
:
2096 *(int*)ret
= s
->src_fd
;
2098 case COPYFILE_STATE_DST_FD
:
2099 *(int*)ret
= s
->dst_fd
;
2101 case COPYFILE_STATE_SRC_FILENAME
:
2102 *(char**)ret
= s
->src
;
2104 case COPYFILE_STATE_DST_FILENAME
:
2105 *(char**)ret
= s
->dst
;
2107 case COPYFILE_STATE_QUARANTINE
:
2108 *(qtn_file_t
*)ret
= s
->qinfo
;
2111 case COPYFILE_STATE_STATS
:
2112 ret
= s
->stats
.global
;
2114 case COPYFILE_STATE_PROGRESS_CB
:
2115 ret
= s
->callbacks
.progress
;
2118 #ifdef COPYFILE_STATE_STATUS_CB
2119 case COPYFILE_STATE_STATUS_CB
:
2120 *(copyfile_callback_t
*)ret
= s
->statuscb
;
2122 case COPYFILE_STATE_STATUS_CTX
:
2123 *(void**)ret
= s
->ctx
;
2125 case COPYFILE_STATE_COPIED
:
2126 *(off_t
*)ret
= s
->totalCopied
;
2138 * Public API for setting state data (remember that the state is
2139 * an opaque data type).
2141 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
2143 #define copyfile_set_string(DST, SRC) \
2145 if (SRC != NULL) { \
2146 DST = strdup((char *)SRC); \
2148 if (DST != NULL) { \
2163 case COPYFILE_STATE_SRC_FD
:
2164 s
->src_fd
= *(int*)thing
;
2166 case COPYFILE_STATE_DST_FD
:
2167 s
->dst_fd
= *(int*)thing
;
2169 case COPYFILE_STATE_SRC_FILENAME
:
2170 copyfile_set_string(s
->src
, thing
);
2172 case COPYFILE_STATE_DST_FILENAME
:
2173 copyfile_set_string(s
->dst
, thing
);
2175 case COPYFILE_STATE_QUARANTINE
:
2178 qtn_file_free(s
->qinfo
);
2181 if (*(qtn_file_t
*)thing
)
2182 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
2185 case COPYFILE_STATE_STATS
:
2186 s
->stats
.global
= thing
;
2188 case COPYFILE_STATE_PROGRESS_CB
:
2189 s
->callbacks
.progress
= thing
;
2192 #ifdef COPYFILE_STATE_STATUS_CB
2193 case COPYFILE_STATE_STATUS_CB
:
2194 s
->statuscb
= (copyfile_callback_t
)thing
;
2196 case COPYFILE_STATE_STATUS_CTX
:
2197 s
->ctx
= (void*)thing
;
2205 #undef copyfile_set_string
2210 * Make this a standalone program for testing purposes by
2211 * defining _COPYFILE_TEST.
2213 #ifdef _COPYFILE_TEST
2214 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2216 struct {char *s
; int v
;} opts
[] = {
2217 COPYFILE_OPTION(ACL
)
2218 COPYFILE_OPTION(STAT
)
2219 COPYFILE_OPTION(XATTR
)
2220 COPYFILE_OPTION(DATA
)
2221 COPYFILE_OPTION(SECURITY
)
2222 COPYFILE_OPTION(METADATA
)
2223 COPYFILE_OPTION(ALL
)
2224 COPYFILE_OPTION(NOFOLLOW_SRC
)
2225 COPYFILE_OPTION(NOFOLLOW_DST
)
2226 COPYFILE_OPTION(NOFOLLOW
)
2227 COPYFILE_OPTION(EXCL
)
2228 COPYFILE_OPTION(MOVE
)
2229 COPYFILE_OPTION(UNLINK
)
2230 COPYFILE_OPTION(PACK
)
2231 COPYFILE_OPTION(UNPACK
)
2232 COPYFILE_OPTION(CHECK
)
2233 COPYFILE_OPTION(VERBOSE
)
2234 COPYFILE_OPTION(DEBUG
)
2238 int main(int c
, char *v
[])
2244 errx(1, "insufficient arguments");
2248 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
2250 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
2252 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
2259 return copyfile(v
[1], v
[2], NULL
, flags
);
2263 * Apple Double Create
2265 * Create an Apple Double "._" file from a file's extented attributes
2267 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2271 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2273 #define XATTR_MAXATTRLEN (4*1024)
2277 Typical "._" AppleDouble Header File layout:
2278 ------------------------------------------------------------
2283 .-- AD ENTRY[0] Finder Info Entry (must be first)
2284 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2286 | ///////////// Fixed Size Data (32 bytes)
2290 | ATTR ENTRY[1] --+--.
2291 | ATTR ENTRY[2] --+--+--.
2293 | ATTR ENTRY[N] --+--+--+--.
2294 | ATTR DATA 0 <-' | | |
2295 | //////////// | | |
2296 | ATTR DATA 1 <----' | |
2298 | ATTR DATA 2 <-------' |
2301 | ATTR DATA N <----------'
2303 | Attribute Free Space
2305 '----> RESOURCE FORK
2306 ///////////// Variable Sized Data
2315 ------------------------------------------------------------
2317 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2318 stored as part of the Finder Info. The length in the Finder
2319 Info AppleDouble entry includes the length of the extended
2320 attribute header, attribute entries, and attribute data.
2325 * On Disk Data Structures
2327 * Note: Motorola 68K alignment and big-endian.
2329 * See RFC 1740 for additional information about the AppleDouble file format.
2333 #define ADH_MAGIC 0x00051607
2334 #define ADH_VERSION 0x00020000
2335 #define ADH_MACOSX "Mac OS X "
2338 * AppleDouble Entry ID's
2340 #define AD_DATA 1 /* Data fork */
2341 #define AD_RESOURCE 2 /* Resource fork */
2342 #define AD_REALNAME 3 /* File's name on home file system */
2343 #define AD_COMMENT 4 /* Standard Mac comment */
2344 #define AD_ICONBW 5 /* Mac black & white icon */
2345 #define AD_ICONCOLOR 6 /* Mac color icon */
2346 #define AD_UNUSED 7 /* Not used */
2347 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2348 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2349 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2350 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2351 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2352 #define AD_AFPNAME 13 /* Short name on AFP server */
2353 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2354 #define AD_AFPDIRID 15 /* AFP directory ID */
2355 #define AD_ATTRIBUTES AD_FINDERINFO
2358 #define ATTR_FILE_PREFIX "._"
2359 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2361 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2363 /* Implementation Limits */
2364 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
2365 #define ATTR_MAX_NAME_LEN 128
2366 #define ATTR_MAX_HDR_SIZE (65536+18)
2369 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2370 * size supported (including the attribute entries). All of
2371 * the attribute entries must reside within this limit.
2375 #define FINDERINFOSIZE 32
2377 typedef struct apple_double_entry
2379 u_int32_t type
; /* entry type: see list, 0 invalid */
2380 u_int32_t offset
; /* entry data offset from the beginning of the file. */
2381 u_int32_t length
; /* entry data length in bytes. */
2382 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
2385 typedef struct apple_double_header
2387 u_int32_t magic
; /* == ADH_MAGIC */
2388 u_int32_t version
; /* format version: 2 = 0x00020000 */
2389 u_int32_t filler
[4];
2390 u_int16_t numEntries
; /* number of entries which follow */
2391 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
2392 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
2393 u_int8_t pad
[2]; /* get better alignment inside attr_header */
2394 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
2397 /* Entries are aligned on 4 byte boundaries */
2398 typedef struct attr_entry
2400 u_int32_t offset
; /* file offset to data */
2401 u_int32_t length
; /* size of attribute data */
2403 u_int8_t namelen
; /* length of name including NULL termination char */
2404 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2405 } __attribute__((aligned(2), packed
)) attr_entry_t
;
2409 /* Header + entries must fit into 64K */
2410 typedef struct attr_header
2412 apple_double_header_t appledouble
;
2413 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
2414 u_int32_t debug_tag
; /* for debugging == file id of owning file */
2415 u_int32_t total_size
; /* total size of attribute header + entries + data */
2416 u_int32_t data_start
; /* file offset to attribute data area */
2417 u_int32_t data_length
; /* length of attribute data area */
2418 u_int32_t reserved
[3];
2420 u_int16_t num_attrs
;
2421 } __attribute__((aligned(2), packed
)) attr_header_t
;
2423 /* Empty Resource Fork Header */
2424 /* This comes by way of xnu's vfs_xattr.c */
2425 typedef struct rsrcfork_header
{
2426 u_int32_t fh_DataOffset
;
2427 u_int32_t fh_MapOffset
;
2428 u_int32_t fh_DataLength
;
2429 u_int32_t fh_MapLength
;
2430 u_int8_t systemData
[112];
2431 u_int8_t appData
[128];
2432 u_int32_t mh_DataOffset
;
2433 u_int32_t mh_MapOffset
;
2434 u_int32_t mh_DataLength
;
2435 u_int32_t mh_MapLength
;
2437 u_int16_t mh_RefNum
;
2439 u_int8_t mh_InMemoryAttr
;
2442 u_int16_t typeCount
;
2443 } rsrcfork_header_t
;
2444 #define RF_FIRST_RESOURCE 256
2445 #define RF_NULL_MAP_LENGTH 30
2446 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2448 static const rsrcfork_header_t empty_rsrcfork_header
= {
2449 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
2450 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
2452 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
2453 { RF_EMPTY_TAG
, }, // systemData
2455 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
2456 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
2458 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
2462 0, // mh_InMemoryAttr
2463 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
2464 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
2465 OSSwapHostToBigInt16(-1), // typeCount
2468 #define SWAP16(x) OSSwapBigToHostInt16(x)
2469 #define SWAP32(x) OSSwapBigToHostInt32(x)
2470 #define SWAP64(x) OSSwapBigToHostInt64(x)
2472 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2474 #define ATTR_ENTRY_LENGTH(namelen) \
2475 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2477 #define ATTR_NEXT(ae) \
2478 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2480 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2483 * Endian swap Apple Double header
2486 swap_adhdr(apple_double_header_t
*adh
)
2488 #if BYTE_ORDER == LITTLE_ENDIAN
2492 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
2494 adh
->magic
= SWAP32 (adh
->magic
);
2495 adh
->version
= SWAP32 (adh
->version
);
2496 adh
->numEntries
= SWAP16 (adh
->numEntries
);
2498 for (i
= 0; i
< count
; i
++)
2500 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
2501 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
2502 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
2510 * Endian swap extended attributes header
2513 swap_attrhdr(attr_header_t
*ah
)
2515 #if BYTE_ORDER == LITTLE_ENDIAN
2520 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
2522 ah
->magic
= SWAP32 (ah
->magic
);
2523 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
2524 ah
->total_size
= SWAP32 (ah
->total_size
);
2525 ah
->data_start
= SWAP32 (ah
->data_start
);
2526 ah
->data_length
= SWAP32 (ah
->data_length
);
2527 ah
->flags
= SWAP16 (ah
->flags
);
2528 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
2530 ae
= (attr_entry_t
*)(&ah
[1]);
2531 for (i
= 0; i
< count
; i
++)
2533 attr_entry_t
*next
= ATTR_NEXT(ae
);
2534 ae
->offset
= SWAP32 (ae
->offset
);
2535 ae
->length
= SWAP32 (ae
->length
);
2536 ae
->flags
= SWAP16 (ae
->flags
);
2544 static const u_int32_t emptyfinfo
[8] = {0};
2547 * Given an Apple Double file in src, turn it into a
2548 * normal file (possibly with multiple forks, EAs, and
2551 static int copyfile_unpack(copyfile_state_t s
)
2554 void * buffer
, * endptr
;
2555 apple_double_header_t
*adhdr
;
2559 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
2560 hdrsize
= (ssize_t
)s
->sb
.st_size
;
2562 hdrsize
= ATTR_MAX_HDR_SIZE
;
2564 buffer
= calloc(1, hdrsize
);
2565 if (buffer
== NULL
) {
2566 copyfile_debug(1, "copyfile_unpack: calloc(1, %u) returned NULL", hdrsize
);
2570 endptr
= (char*)buffer
+ hdrsize
;
2572 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
2576 copyfile_debug(1, "pread returned: %d", bytes
);
2580 if (bytes
< hdrsize
)
2583 "pread couldn't read entire header: %d of %d",
2584 (int)bytes
, (int)s
->sb
.st_size
);
2588 adhdr
= (apple_double_header_t
*)buffer
;
2591 * Check for Apple Double file.
2593 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
2594 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
2595 SWAP32(adhdr
->version
) != ADH_VERSION
||
2596 SWAP16(adhdr
->numEntries
) != 2 ||
2597 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
2599 if (COPYFILE_VERBOSE
& s
->flags
)
2600 copyfile_warn("Not a valid Apple Double header");
2607 * Remove any extended attributes on the target.
2610 if (COPYFILE_XATTR
& s
->flags
)
2612 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
2614 char *namebuf
, *name
;
2616 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
2621 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
2624 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
2625 (void)fremovexattr(s
->dst_fd
, name
, 0);
2631 if (errno
!= ENOTSUP
&& errno
!= EPERM
)
2637 * Extract the extended attributes.
2640 * This assumes that the data is already in memory (not
2641 * the case when there are lots of attributes or one of
2642 * the attributes is very large.
2644 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
2646 attr_header_t
*attrhdr
;
2647 attr_entry_t
*entry
;
2651 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
2652 copyfile_warn("bad attribute header: %u < %u", hdrsize
, sizeof(attr_header_t
));
2657 attrhdr
= (attr_header_t
*)buffer
;
2658 swap_attrhdr(attrhdr
);
2659 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
2661 if (COPYFILE_VERBOSE
& s
->flags
)
2662 copyfile_warn("bad attribute header");
2666 count
= attrhdr
->num_attrs
;
2667 entry
= (attr_entry_t
*)&attrhdr
[1];
2669 for (i
= 0; i
< count
; i
++)
2674 * First we do some simple sanity checking.
2675 * +) See if entry is within the buffer's range;
2677 * +) Check the attribute name length; if it's longer than the
2678 * maximum, we truncate it down. (We could error out as well;
2679 * I'm not sure which is the better way to go here.)
2681 * +) If, given the name length, it goes beyond the end of
2682 * the buffer, error out.
2684 * +) If the last byte isn't a NUL, make it a NUL. (Since we
2685 * truncated the name length above, we truncate the name here.)
2687 * +) If entry->offset is so large that it causes dataptr to
2688 * go beyond the end of the buffer -- or, worse, so large that
2689 * it wraps around! -- we error out.
2691 * +) If entry->length would cause the entry to go beyond the
2692 * end of the buffer (or, worse, wrap around to before it),
2693 * *or* if the length is larger than the hdrsize, we error out.
2694 * (An explanation of that: what we're checking for there is
2695 * the small range of values such that offset+length would cause
2696 * it to go beyond endptr, and then wrap around past buffer. We
2697 * care about this because we are passing entry->length down to
2698 * fgetxattr() below, and an erroneously large value could cause
2699 * problems there. By making sure that it's less than hdrsize,
2700 * which has already been sanity-checked above, we're safe.
2701 * That may mean that the check against < buffer is unnecessary.)
2703 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
2704 if (COPYFILE_VERBOSE
& s
->flags
)
2705 copyfile_warn("Incomplete or corrupt attribute entry");
2711 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
2712 if (COPYFILE_VERBOSE
& s
->flags
)
2713 copyfile_warn("Incomplete or corrupt attribute entry");
2719 if (entry
->namelen
< 2) {
2720 if (COPYFILE_VERBOSE
& s
->flags
)
2721 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
2727 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
2728 if (COPYFILE_VERBOSE
& s
->flags
)
2729 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
2735 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
2736 if (COPYFILE_VERBOSE
& s
->flags
)
2737 copyfile_warn("Incomplete or corrupt attribute entry");
2743 /* Because namelen includes the NUL, we check one byte back */
2744 if (entry
->name
[entry
->namelen
-1] != 0) {
2745 if (COPYFILE_VERBOSE
& s
->flags
)
2746 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
2752 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
2753 entry
->name
, entry
->length
, entry
->offset
);
2755 dataptr
= (char *)attrhdr
+ entry
->offset
;
2757 if (dataptr
> endptr
|| dataptr
< buffer
) {
2758 copyfile_debug(1, "Entry %d overflows: offset = %u", entry
->offset
);
2760 s
->err
= EINVAL
; /* Invalid buffer */
2763 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
2764 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
2765 (entry
->length
> (size_t)hdrsize
)) {
2766 if (COPYFILE_VERBOSE
& s
->flags
)
2767 copyfile_warn("Incomplete or corrupt attribute entry");
2768 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
2769 entry
->offset
, entry
->length
);
2771 s
->err
= EINVAL
; /* Invalid buffer */
2775 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
2777 qtn_file_t tqinfo
= NULL
;
2779 if (s
->qinfo
== NULL
)
2781 tqinfo
= qtn_file_alloc();
2785 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
2787 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
2788 qtn_file_free(tqinfo
);
2800 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
2802 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
2804 if (tqinfo
&& !s
->qinfo
)
2806 qtn_file_free(tqinfo
);
2809 /* Look for ACL data */
2810 else if (COPYFILE_ACL
& s
->flags
&& strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
2815 char *tcp
= dataptr
;
2818 * acl_from_text() requires a NUL-terminated string. The ACL EA,
2819 * however, may not be NUL-terminated. So in that case, we need to
2820 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
2822 if (tcp
[entry
->length
- 1] != 0) {
2823 char *tmpstr
= malloc(entry
->length
+ 1);
2824 if (tmpstr
== NULL
) {
2828 strlcpy(tmpstr
, tcp
, entry
->length
+ 1);
2829 acl
= acl_from_text(tmpstr
);
2832 acl
= acl_from_text(tcp
);
2839 if ((fsec_tmp
= filesec_init()) == NULL
)
2841 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
2843 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
2846 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
2848 if (errno
== ENOTSUP
)
2850 if (retry
&& !copyfile_unset_acl(s
))
2856 copyfile_warn("setting security information");
2862 filesec_free(fsec_tmp
);
2868 /* And, finally, everything else */
2869 else if (COPYFILE_XATTR
& s
->flags
) {
2870 if (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0) == -1) {
2871 if (COPYFILE_VERBOSE
& s
->flags
)
2872 copyfile_warn("error %d setting attribute %s", error
, entry
->name
);
2877 entry
= ATTR_NEXT(entry
);
2882 * Extract the Finder Info.
2884 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
2889 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
2891 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
2892 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
2898 * Extract the Resource Fork.
2900 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
2901 adhdr
->entries
[1].length
> 0)
2903 void * rsrcforkdata
= NULL
;
2907 struct timeval tval
[2];
2909 length
= adhdr
->entries
[1].length
;
2910 offset
= adhdr
->entries
[1].offset
;
2911 rsrcforkdata
= malloc(length
);
2913 if (rsrcforkdata
== NULL
) {
2914 copyfile_debug(1, "could not allocate %u bytes for rsrcforkdata",
2920 if (fstat(s
->dst_fd
, &sb
) < 0)
2922 copyfile_debug(1, "couldn't stat destination file");
2927 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
2928 if (bytes
< (ssize_t
)length
)
2932 copyfile_debug(1, "couldn't read resource fork");
2937 "couldn't read resource fork (only read %d bytes of %d)",
2938 (int)bytes
, (int)length
);
2943 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
2947 * For filesystems that do not natively support named attributes,
2948 * the kernel creates an AppleDouble file that -- for compatabilty
2949 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
2950 * structure that says there are no resources. So, if fsetxattr has
2951 * failed, and the resource fork is that empty structure, *and* the
2952 * target file is a directory, then we do nothing with it.
2954 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
2955 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
2956 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
2957 copyfile_debug(2, "not setting empty resource fork on directory");
2961 copyfile_debug(1, "error %d setting resource fork attribute", error
);
2965 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
2966 XATTR_RESOURCEFORK_NAME
, (int)length
);
2968 if (!(s
->flags
& COPYFILE_STAT
))
2970 tval
[0].tv_sec
= sb
.st_atime
;
2971 tval
[1].tv_sec
= sb
.st_mtime
;
2972 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
2974 if (futimes(s
->dst_fd
, tval
))
2975 copyfile_warn("%s: set times", s
->dst
? s
->dst
: "(null dst)");
2982 if (COPYFILE_STAT
& s
->flags
)
2984 error
= copyfile_stat(s
);
2987 if (buffer
) free(buffer
);
2991 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
2994 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
2995 size_t qlen
= sizeof(qbuf
);
2997 if (s
->qinfo
== NULL
)
3003 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
3009 *buf
= malloc(qlen
);
3012 memcpy(*buf
, qbuf
, qlen
);
3019 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
3025 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
3027 if (errno
!= ENOENT
)
3030 if (COPYFILE_VERBOSE
& s
->flags
)
3031 copyfile_warn("getting acl");
3037 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
3040 * acl_to_text() doesn't include the NUL at the endo
3041 * in it's count (*len). It does, however, promise to
3042 * return a valid C string, so we need to up the count
3046 *buf
= malloc(*len
);
3048 memcpy(*buf
, acl_text
, *len
);
3053 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
3060 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
3063 char *databuf
= NULL
;
3066 /* Get the resource fork size */
3067 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
3069 if (COPYFILE_VERBOSE
& s
->flags
)
3070 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
3074 if (datasize
> INT_MAX
) {
3080 if ((databuf
= malloc(datasize
)) == NULL
)
3082 copyfile_warn("malloc");
3087 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
3089 if (COPYFILE_VERBOSE
& s
->flags
)
3090 copyfile_warn("couldn't read entire resource fork");
3095 /* Write the resource fork to disk. */
3096 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
3098 if (COPYFILE_VERBOSE
& s
->flags
)
3099 copyfile_warn("couldn't write resource fork");
3101 copyfile_debug(3, "copied %d bytes of \"%s\" data @ offset 0x%08x",
3102 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
3103 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
3113 * The opposite of copyfile_unpack(), obviously.
3115 static int copyfile_pack(copyfile_state_t s
)
3117 char *attrnamebuf
= NULL
, *endnamebuf
;
3118 void *databuf
= NULL
;
3119 attr_header_t
*filehdr
, *endfilehdr
;
3120 attr_entry_t
*entry
;
3121 ssize_t listsize
= 0;
3127 int hasrsrcfork
= 0;
3129 int seenq
= 0; // Have we seen any quarantine info already?
3131 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_SIZE
);
3132 if (filehdr
== NULL
) {
3136 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_SIZE
);
3139 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
3140 if (attrnamebuf
== NULL
) {
3144 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
3148 * Fill in the Apple Double Header defaults.
3150 filehdr
->appledouble
.magic
= ADH_MAGIC
;
3151 filehdr
->appledouble
.version
= ADH_VERSION
;
3152 filehdr
->appledouble
.numEntries
= 2;
3153 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
3154 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
3155 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
3156 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
3157 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
3158 filehdr
->appledouble
.entries
[1].length
= 0;
3159 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
3162 * Fill in the initial Attribute Header.
3164 filehdr
->magic
= ATTR_HDR_MAGIC
;
3165 filehdr
->debug_tag
= (u_int32_t
)s
->sb
.st_ino
;
3166 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
3169 * Collect the attribute names.
3171 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3174 * Test if there are acls to copy
3176 if (COPYFILE_ACL
& s
->flags
)
3178 acl_t temp_acl
= NULL
;
3179 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
3181 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
3184 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
3185 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
3191 if (COPYFILE_XATTR
& s
->flags
)
3193 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3194 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
3196 copyfile_debug(2, "no extended attributes found (%d)", errno
);
3198 if (listsize
> left
)
3200 copyfile_debug(1, "extended attribute list too long");
3205 endnamebuf
= attrnamebuf
+ listsize
;
3206 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
3211 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
3213 namelen
= strlen(nameptr
) + 1;
3214 /* Skip over FinderInfo or Resource Fork names */
3215 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
3216 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
3219 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
3223 /* The system should prevent this from happening, but... */
3224 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
3225 namelen
= XATTR_MAXNAMELEN
+ 1;
3227 entry
->namelen
= namelen
;
3229 if (nameptr
+ namelen
> endnamebuf
) {
3233 bcopy(nameptr
, &entry
->name
[0], namelen
);
3234 copyfile_debug(2, "copied name [%s]", entry
->name
);
3236 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
3237 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
3239 if ((void*)entry
>= (void*)endfilehdr
) {
3244 /* Update the attributes header. */
3245 filehdr
->num_attrs
++;
3246 filehdr
->data_start
+= (u_int32_t
)entrylen
;
3251 * If we have any quarantine data, we always pack it.
3252 * But if we've already got it in the EA list, don't put it in again.
3254 if (s
->qinfo
&& !seenq
)
3256 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
3257 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3258 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
3263 * Collect the attribute data.
3265 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
3267 for (nameptr
= attrnamebuf
; nameptr
< attrnamebuf
+ listsize
; nameptr
+= namelen
+ 1)
3269 namelen
= strlen(nameptr
);
3271 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
3272 copyfile_pack_acl(s
, &databuf
, &datasize
);
3273 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
3275 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
3277 /* Check for Finder Info. */
3278 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
3280 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
3283 if (COPYFILE_VERBOSE
& s
->flags
)
3284 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3285 } else if (datasize
!= 32)
3287 if (COPYFILE_VERBOSE
& s
->flags
)
3288 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
3291 if (COPYFILE_VERBOSE
& s
->flags
)
3292 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3293 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
3295 continue; /* finder info doesn't have an attribute entry */
3297 /* Check for Resource Fork. */
3298 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
3304 /* Just a normal attribute. */
3305 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
3310 if (COPYFILE_VERBOSE
& s
->flags
)
3311 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
3314 if (datasize
> XATTR_MAXATTRLEN
)
3316 if (COPYFILE_VERBOSE
& s
->flags
)
3317 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
3320 databuf
= malloc(datasize
);
3321 if (databuf
== NULL
) {
3325 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
3328 entry
->length
= (u_int32_t
)datasize
;
3329 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
3331 filehdr
->data_length
+= (u_int32_t
)datasize
;
3334 * This assumes that the data is fits in memory (not
3335 * the case when there are lots of attributes or one of
3336 * the attributes is very large.
3338 if (entry
->offset
> ATTR_MAX_SIZE
||
3339 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
3342 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
3346 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
3348 /* bump to next entry */
3349 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
3350 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
3353 if (filehdr
->data_length
> 0)
3355 /* Now we know where the resource fork data starts. */
3356 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
3358 /* We also know the size of the "Finder Info entry. */
3359 filehdr
->appledouble
.entries
[0].length
=
3360 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
3362 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
3365 /* Copy Resource Fork. */
3366 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
3369 /* Write the header to disk. */
3370 datasize
= filehdr
->appledouble
.entries
[1].offset
;
3372 swap_adhdr(&filehdr
->appledouble
);
3373 swap_attrhdr(filehdr
);
3375 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
3377 if (COPYFILE_VERBOSE
& s
->flags
)
3378 copyfile_warn("couldn't write file header");
3383 if (filehdr
) free(filehdr
);
3384 if (attrnamebuf
) free(attrnamebuf
);
3389 return copyfile_stat(s
);