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>
46 #include <quarantine.h>
48 #define XATTR_QUARANTINE_NAME qtn_xattr_name
53 * The state structure keeps track of
54 * the source filename, the destination filename, their
55 * associated file-descriptors, the stat infomration for the
56 * source file, the security information for the source file,
57 * the flags passed in for the copy, a pointer to place statistics
58 * (not currently implemented), debug flags, and a pointer to callbacks
59 * (not currently implemented).
61 struct _copyfile_state
69 copyfile_flags_t flags
;
73 qtn_file_t qinfo
; /* Quarantine information -- probably NULL */
77 * Internally, the process is broken into a series of
80 static int copyfile_open (copyfile_state_t
);
81 static int copyfile_close (copyfile_state_t
);
82 static int copyfile_data (copyfile_state_t
);
83 static int copyfile_stat (copyfile_state_t
);
84 static int copyfile_security (copyfile_state_t
);
85 static int copyfile_xattr (copyfile_state_t
);
86 static int copyfile_pack (copyfile_state_t
);
87 static int copyfile_unpack (copyfile_state_t
);
89 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
90 static filesec_t
copyfile_fix_perms(copyfile_state_t
, filesec_t
*);
91 static int copyfile_preamble(copyfile_state_t
*s
, copyfile_flags_t flags
);
92 static int copyfile_internal(copyfile_state_t state
, copyfile_flags_t flags
);
93 static int copyfile_unset_posix_fsec(filesec_t
);
94 static int copyfile_quarantine(copyfile_state_t
);
96 #define COPYFILE_DEBUG (1<<31)
97 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
99 #ifndef _COPYFILE_TEST
100 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
101 # define copyfile_debug(d, str, ...) \
103 if (s && (d <= s->debug)) {\
104 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
108 #define copyfile_warn(str, ...) \
109 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
110 # define copyfile_debug(d, str, ...) \
112 if (s && (d <= s->debug)) {\
113 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
118 static int copyfile_quarantine(copyfile_state_t s
)
121 if (s
->qinfo
== NULL
)
124 s
->qinfo
= qtn_file_alloc();
125 if (s
->qinfo
== NULL
)
130 if ((error
= qtn_file_init_with_fd(s
->qinfo
, s
->src_fd
)) != 0)
132 qtn_file_free(s
->qinfo
);
144 * fcopyfile() is used to copy a source file descriptor to a destination file
145 * descriptor. This allows an application to figure out how it wants to open
146 * the files (doing various security checks, perhaps), and then just pass in
147 * the file descriptors.
149 int fcopyfile(int src_fd
, int dst_fd
, copyfile_state_t state
, copyfile_flags_t flags
)
152 copyfile_state_t s
= state
;
155 if (src_fd
< 0 || dst_fd
< 0)
161 if (copyfile_preamble(&s
, flags
) < 0)
164 copyfile_debug(2, "set src_fd <- %d", src_fd
);
165 if (s
->src_fd
== -2 && src_fd
> -1)
168 if (fstatx_np(s
->src_fd
, &s
->sb
, s
->fsec
) != 0)
170 if (errno
== ENOTSUP
)
171 fstat(s
->src_fd
, &s
->sb
);
174 copyfile_warn("fstatx_np on src fd %d", s
->src_fd
);
180 /* prevent copying on unsupported types */
181 switch (s
->sb
.st_mode
& S_IFMT
)
192 copyfile_debug(2, "set dst_fd <- %d", dst_fd
);
193 if (s
->dst_fd
== -2 && dst_fd
> -1)
196 (void)fstat(s
->dst_fd
, &dst_sb
);
197 (void)fchmod(s
->dst_fd
, (dst_sb
.st_mode
& ~S_IFMT
) | (S_IRUSR
| S_IWUSR
));
199 (void)copyfile_quarantine(s
);
201 ret
= copyfile_internal(s
, flags
);
203 if (ret
>= 0 && !(s
->flags
& COPYFILE_STAT
))
205 (void)fchmod(s
->dst_fd
, dst_sb
.st_mode
& ~S_IFMT
);
209 copyfile_state_free(s
);
216 * the original copyfile() routine; this copies a source file to a destination
217 * file. Note that because we need to set the names in the state variable, this
218 * is not just the same as opening the two files, and then calling fcopyfile().
219 * Oh, if only life were that simple!
221 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
224 copyfile_state_t s
= state
;
225 filesec_t original_fsec
= NULL
;
226 filesec_t permissive_fsec
= NULL
;
229 if (src
== NULL
&& dst
== NULL
)
235 if (copyfile_preamble(&s
, flags
) < 0)
241 * This macro is... well, it's not the worst thing you can do with cpp, not
242 * by a long shot. Essentially, we are setting the filename (src or dst)
243 * in the state structure; since the structure may not have been cleared out
244 * before being used again, we do some of the cleanup here: if the given
245 * filename (e.g., src) is set, and state->src is not equal to that, then
246 * we need to check to see if the file descriptor had been opened, and if so,
247 * close it. After that, we set state->src to be a copy of the given filename,
248 * releasing the old copy if necessary.
250 #define COPYFILE_SET_FNAME(NAME, S) \
252 if (NAME != NULL) { \
253 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
254 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
255 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
256 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
257 close(S->NAME##_fd); \
265 if ((S->NAME = strdup(NAME)) == NULL) \
270 COPYFILE_SET_FNAME(src
, s
);
271 COPYFILE_SET_FNAME(dst
, s
);
274 * Get a copy of the source file's security settings
276 if ((original_fsec
= filesec_init()) == NULL
)
279 if(statx_np(s
->dst
, &sb
, original_fsec
) == 0)
282 * copyfile_fix_perms() will make a copy of the permission set,
283 * and insert at the beginning an ACE that ensures we can write
284 * to the file and set attributes.
287 if((permissive_fsec
= copyfile_fix_perms(s
, &original_fsec
)) != NULL
)
290 * Set the permissions for the destination to our copy.
291 * We should get ENOTSUP from any filesystem that simply
292 * doesn't support it.
294 if (chmodx_np(s
->dst
, permissive_fsec
) < 0 && errno
!= ENOTSUP
)
296 copyfile_warn("setting security information");
297 filesec_free(permissive_fsec
);
298 permissive_fsec
= NULL
;
304 * If COPYFILE_CHECK is set in flags, then all we are going to do
305 * is see what kinds of things WOULD have been copied (see
306 * copyfile_check() below). We return that value.
308 if (COPYFILE_CHECK
& flags
)
310 ret
= copyfile_check(s
);
312 } else if ((ret
= copyfile_open(s
)) < 0)
315 ret
= copyfile_internal(s
, flags
);
317 /* If we haven't reset the file security information
318 * (COPYFILE_SECURITY is not set in flags)
319 * restore back the permissions the file had originally
321 * One of the reasons this seems so complicated is that
322 * it is partially at odds with copyfile_security().
324 * Simplisticly, we are simply trying to make sure we
325 * only copy what was requested, and that we don't stomp
326 * on what wasn't requsted.
329 if (permissive_fsec
&& (s
->flags
& COPYFILE_SECURITY
) != COPYFILE_SECURITY
) {
330 if (s
->flags
& COPYFILE_ACL
) {
331 /* Just need to reset the BSD information -- mode, owner, group */
332 (void)fchown(s
->dst_fd
, sb
.st_uid
, sb
.st_gid
);
333 (void)fchmod(s
->dst_fd
, sb
.st_mode
);
336 * flags is either COPYFILE_STAT, or neither; if it's
337 * neither, then we restore both ACL and POSIX permissions;
338 * if it's STAT, however, then we only want to restore the
339 * ACL (which may be empty). We do that by removing the
340 * POSIX information from the filesec object.
342 if (s
->flags
& COPYFILE_STAT
) {
343 copyfile_unset_posix_fsec(original_fsec
);
345 if (fchmodx_np(s
->dst_fd
, original_fsec
) < 0 && errno
!= ENOTSUP
)
346 copyfile_warn("restoring security information");
351 copyfile_state_free(s
);
354 filesec_free(original_fsec
);
356 filesec_free(permissive_fsec
);
366 * Shared prelude to the {f,}copyfile(). This initializes the
367 * state variable, if necessary, and also checks for both debugging
368 * and disabling environment variables.
370 static int copyfile_preamble(copyfile_state_t
*state
, copyfile_flags_t flags
)
376 if ((*state
= copyfile_state_alloc()) == NULL
)
382 if (COPYFILE_DEBUG
& flags
)
385 if ((e
= getenv(COPYFILE_DEBUG_VAR
)))
388 s
->debug
= (uint32_t)strtol(e
, NULL
, 0);
390 /* clamp s->debug to 1 if the environment variable is not parsable */
391 if (s
->debug
== 0 && errno
!= 0)
394 copyfile_debug(2, "debug value set to: %d", s
->debug
);
398 /* Temporarily disabled */
399 if (getenv(COPYFILE_DISABLE_VAR
) != NULL
)
401 copyfile_debug(1, "copyfile disabled");
405 copyfile_debug(2, "setting flags: %d", s
->flags
);
412 * The guts of {f,}copyfile().
413 * This looks through the flags in a particular order, and calls the
414 * associated functions.
416 static int copyfile_internal(copyfile_state_t s
, copyfile_flags_t flags
)
420 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
422 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
423 s
->src_fd
, s
->dst_fd
);
429 * COPYFILE_PACK causes us to create an Apple Double version of the
430 * source file, and puts it into the destination file. See
431 * copyfile_pack() below for all the gory details.
433 if (COPYFILE_PACK
& flags
)
435 if ((ret
= copyfile_pack(s
)) < 0)
444 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
445 * The goal there is to take an Apple Double file, and turn it
446 * into a normal file (with data fork, resource fork, modes,
447 * extended attributes, ACLs, etc.).
449 if (COPYFILE_UNPACK
& flags
)
451 if ((ret
= copyfile_unpack(s
)) < 0)
457 * If we have quarantine info set, we attempt
458 * to apply it to dst_fd. We don't care if
459 * it fails, not yet anyway.
462 (void)qtn_file_apply_to_fd(s
->qinfo
, s
->dst_fd
);
465 * COPYFILE_XATTR tells us to copy the extended attributes;
466 * this is seperate from the extended security (aka ACLs),
467 * however. If we succeed in this, we continue to the next
468 * stage; if we fail, we return with an error value. Note
469 * that we fail if the errno is ENOTSUP, but we don't print
470 * a warning in that case.
472 if (COPYFILE_XATTR
& flags
)
474 if ((ret
= copyfile_xattr(s
)) < 0)
476 if (errno
!= ENOTSUP
)
477 copyfile_warn("error processing extended attributes");
483 * Simialr to above, this tells us whether or not to copy
484 * the non-meta data portion of the file. We attempt to
485 * remove (via unlink) the destination file if we fail.
487 if (COPYFILE_DATA
& flags
)
489 if ((ret
= copyfile_data(s
)) < 0)
491 copyfile_warn("error processing data");
492 if (s
->dst
&& unlink(s
->dst
))
493 copyfile_warn("%s: remove", s
->src
);
499 * COPYFILE_SECURITY requests that we copy the security, both
500 * extended and mundane (that is, ACLs and POSIX).
502 if (COPYFILE_SECURITY
& flags
)
504 if ((ret
= copyfile_security(s
)) < 0)
506 copyfile_warn("error processing security information");
511 if (COPYFILE_STAT
& flags
)
513 if ((ret
= copyfile_stat(s
)) < 0)
515 copyfile_warn("error processing POSIX information");
529 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
531 copyfile_state_t
copyfile_state_alloc(void)
533 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
539 s
->fsec
= filesec_init();
547 * copyfile_state_free() returns the memory allocated to the state structure.
548 * It also closes the file descriptors, if they've been opened.
550 int copyfile_state_free(copyfile_state_t s
)
555 filesec_free(s
->fsec
);
558 qtn_file_free(s
->qinfo
);
560 if (copyfile_close(s
) < 0)
562 copyfile_warn("error closing files");
575 * Should we worry if we can't close the source? NFS says we
576 * should, but it's pretty late for us at this point.
578 static int copyfile_close(copyfile_state_t s
)
580 if (s
->src
&& s
->src_fd
>= 0)
583 if (s
->dst
&& s
->dst_fd
>= 0) {
584 if (close(s
->dst_fd
))
592 * The purpose of this function is to set up a set of permissions
593 * (ACL and traditional) that lets us write to the file. In the
594 * case of ACLs, we do this by putting in a first entry that lets
595 * us write data, attributes, and extended attributes. In the case
596 * of traditional permissions, we set the S_IWUSR (user-write)
599 static filesec_t
copyfile_fix_perms(copyfile_state_t s __unused
, filesec_t
*fsec
)
601 filesec_t ret_fsec
= NULL
;
605 if ((ret_fsec
= filesec_dup(*fsec
)) == NULL
)
608 if (filesec_get_property(ret_fsec
, FILESEC_ACL
, &acl
) == 0)
611 acl_permset_t permset
;
614 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
618 * First, we create an entry, and give it the special name
619 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
620 * After that, we clear out all the permissions in it, and
621 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
622 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
623 * the functionality, and put this into the ACL.
625 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
627 if (acl_get_permset(entry
, &permset
) == -1)
629 if (acl_clear_perms(permset
) == -1)
631 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
633 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
635 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
637 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
640 if(acl_set_permset(entry
, permset
) == -1)
642 if(acl_set_qualifier(entry
, qual
) == -1)
645 if (filesec_set_property(ret_fsec
, FILESEC_ACL
, &acl
) != 0)
650 * This is for the normal, mundane, POSIX permission model.
651 * We make sure that we can write to the file.
653 if (filesec_get_property(ret_fsec
, FILESEC_MODE
, &mode
) == 0)
655 if ((mode
& (S_IWUSR
| S_IRUSR
)) != (S_IWUSR
| S_IRUSR
))
657 mode
|= S_IWUSR
|S_IRUSR
;
658 if (filesec_set_property(ret_fsec
, FILESEC_MODE
, &mode
) != 0)
672 filesec_free(ret_fsec
);
679 * Used to clear out the BSD/POSIX security information from
683 copyfile_unset_posix_fsec(filesec_t fsec
)
685 (void)filesec_set_property(fsec
, FILESEC_OWNER
, _FILESEC_UNSET_PROPERTY
);
686 (void)filesec_set_property(fsec
, FILESEC_GROUP
, _FILESEC_UNSET_PROPERTY
);
687 (void)filesec_set_property(fsec
, FILESEC_MODE
, _FILESEC_UNSET_PROPERTY
);
692 * Used to remove acl information from a filesec_t
693 * Unsetting the acl alone in Tiger was insufficient
695 static int copyfile_unset_acl(copyfile_state_t s
)
698 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
700 copyfile_debug(5, "unsetting acl attribute on %s", s
->dst
);
703 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
705 copyfile_debug(5, "unsetting uuid attribute on %s", s
->dst
);
708 if (filesec_set_property(s
->fsec
, FILESEC_GRPUUID
, NULL
) == -1)
710 copyfile_debug(5, "unsetting group uuid attribute on %s", s
->dst
);
717 * copyfile_open() does what one expects: it opens up the files
718 * given in the state structure, if they're not already open.
719 * It also does some type validation, to ensure that we only
720 * handle file types we know about.
722 static int copyfile_open(copyfile_state_t s
)
724 int oflags
= O_EXCL
| O_CREAT
| O_WRONLY
;
725 int islnk
= 0, isdir
= 0;
726 int osrc
= 0, dsrc
= 0;
728 if (s
->src
&& s
->src_fd
== -2)
730 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
731 (s
->src
, &s
->sb
, s
->fsec
))
733 copyfile_warn("stat on %s", s
->src
);
737 /* prevent copying on unsupported types */
738 switch (s
->sb
.st_mode
& S_IFMT
)
742 if (s
->sb
.st_size
> (off_t
)SIZE_T_MAX
) {
743 errno
= ENOMEM
; /* too big for us to copy */
758 * If we're packing, then we are actually
759 * creating a file, no matter what the source
762 if (s
->flags
& COPYFILE_PACK
) {
764 * O_SYMLINK and O_NOFOLLOW are not compatible options:
765 * if the file is a symlink, and O_NOFOLLOW is specified,
766 * open will return ELOOP, whether or not O_SYMLINK is set.
767 * However, we know whether or not it was a symlink from
768 * the stat above (although there is a potentiaal for a race
769 * condition here, but it will err on the side of returning
773 osrc
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
) ? O_NOFOLLOW
: 0;
777 if ((s
->src_fd
= open(s
->src
, O_RDONLY
| osrc
, 0)) < 0)
779 copyfile_warn("open on %s", s
->src
);
782 copyfile_debug(2, "open successful on source (%s)", s
->src
);
784 (void)copyfile_quarantine(s
);
787 if (s
->dst
&& s
->dst_fd
== -2)
790 * COPYFILE_UNLINK tells us to try removing the destination
791 * before we create it. We don't care if the file doesn't
792 * exist, so we ignore ENOENT.
794 if (COPYFILE_UNLINK
& s
->flags
)
796 if (remove(s
->dst
) < 0 && errno
!= ENOENT
)
798 copyfile_warn("%s: remove", s
->dst
);
803 if (s
->flags
& COPYFILE_NOFOLLOW_DST
)
807 size_t sz
= (size_t)s
->sb
.st_size
+ 1;
812 copyfile_warn("cannot allocate %d bytes", sz
);
815 if (readlink(s
->src
, bp
, sz
-1) == -1) {
816 copyfile_warn("cannot readlink %s", s
->src
);
820 if (symlink(bp
, s
->dst
) == -1) {
821 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
822 copyfile_warn("Cannot make symlink %s", s
->dst
);
828 s
->dst_fd
= open(s
->dst
, O_RDONLY
| O_SYMLINK
);
829 if (s
->dst_fd
== -1) {
830 copyfile_warn("Cannot open symlink %s for reading", s
->dst
);
835 mode
= s
->sb
.st_mode
& ~S_IFMT
;
837 if (mkdir(s
->dst
, mode
) == -1) {
838 if (errno
!= EEXIST
|| (s
->flags
& COPYFILE_EXCL
)) {
839 copyfile_warn("Cannot make directory %s", s
->dst
);
843 s
->dst_fd
= open(s
->dst
, O_RDONLY
| dsrc
);
844 if (s
->dst_fd
== -1) {
845 copyfile_warn("Cannot open directory %s for reading", s
->dst
);
848 } else while((s
->dst_fd
= open(s
->dst
, oflags
| dsrc
, s
->sb
.st_mode
| S_IWUSR
)) < 0)
851 * We set S_IWUSR because fsetxattr does not -- at the time this comment
852 * was written -- allow one to set an extended attribute on a file descriptor
853 * for a read-only file, even if the file descriptor is opened for writing.
854 * This will only matter if the file does not already exist.
859 copyfile_debug(3, "open failed, retrying (%s)", s
->dst
);
860 if (s
->flags
& COPYFILE_EXCL
)
862 oflags
= oflags
& ~O_CREAT
;
863 if (s
->flags
& (COPYFILE_PACK
| COPYFILE_DATA
))
865 copyfile_debug(4, "truncating existing file (%s)", s
->dst
);
870 if(chmod(s
->dst
, (s
->sb
.st_mode
| S_IWUSR
) & ~S_IFMT
) == 0)
876 copyfile_debug(3, "open failed because it is a directory (%s)", s
->dst
);
877 if ((s
->flags
& COPYFILE_EXCL
) ||
878 (!isdir
&& (s
->flags
& COPYFILE_DATA
)))
880 oflags
= (oflags
& ~O_WRONLY
) | O_RDONLY
;
883 copyfile_warn("open on %s", s
->dst
);
886 copyfile_debug(2, "open successful on destination (%s)", s
->dst
);
889 if (s
->dst_fd
< 0 || s
->src_fd
< 0)
891 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
892 s
->src_fd
, s
->dst_fd
);
901 * copyfile_check(), as described above, essentially tells you
902 * what you'd have to copy, if you wanted it to copy the things
903 * you asked it to copy.
904 * In other words, if you pass in COPYFILE_ALL, and the file in
905 * question had no extended attributes but did have an ACL, you'd
906 * get back COPYFILE_ACL.
908 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
911 copyfile_flags_t ret
= 0;
912 int nofollow
= (s
->flags
& COPYFILE_NOFOLLOW_SRC
);
922 if (COPYFILE_XATTR
& s
->flags
)
923 if (listxattr(s
->src
, 0, 0, nofollow
? XATTR_NOFOLLOW
: 0) > 0)
925 ret
|= COPYFILE_XATTR
;
928 if (COPYFILE_ACL
& s
->flags
)
930 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
931 (s
->src
, &s
->sb
, s
->fsec
);
933 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
937 copyfile_debug(2, "check result: %d (%s)", ret
, s
->src
);
943 /* If the state has had quarantine info set already, we use that */
944 ret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
946 qinfo
= qtn_file_alloc();
948 * For quarantine information, we need to see if the source file
949 * has any. Since it may be a symlink, however, and we may, or
950 * not be following, *and* there's no qtn* routine which can optionally
951 * follow or not follow a symlink, we need to instead work around
960 * If we care about not following symlinks, *and* the file exists
961 * (which is to say, lstat doesn't return an error), *and* the file
962 * is a symlink, then we open it up (with O_SYMLINK), and use
963 * qtn_file_init_with_fd(); if none of that is true, however, then
964 * we can simply use qtn_file_init_with_path().
967 && lstat(s
->src
, &sbuf
) == 0
968 && ((sbuf
.st_mode
& S_IFMT
) == S_IFLNK
)) {
969 fd
= open(s
->src
, O_RDONLY
| O_SYMLINK
);
971 if (!qtn_file_init_with_fd(qinfo
, fd
)) {
972 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
977 if (!qtn_file_init_with_path(qinfo
, s
->src
)) {
978 qret
|= ((s
->flags
& COPYFILE_XATTR
) ? COPYFILE_XATTR
: COPYFILE_ACL
);
981 qtn_file_free(qinfo
);
989 * Attempt to copy the data section of a file. Using blockisize
990 * is not necessarily the fastest -- it might be desirable to
991 * specify a blocksize, somehow. But it's a size that should be
992 * guaranteed to work.
994 static int copyfile_data(copyfile_state_t s
)
1000 size_t iBlocksize
= 0;
1003 if (fstatfs(s
->src_fd
, &sfs
) == -1) {
1004 iBlocksize
= s
->sb
.st_blksize
;
1006 iBlocksize
= sfs
.f_iosize
;
1009 if ((bp
= malloc(iBlocksize
)) == NULL
)
1014 /* If supported, do preallocation for Xsan / HFS volumes */
1015 #ifdef F_PREALLOCATE
1020 fst
.fst_posmode
= F_PEOFPOSMODE
;
1022 fst
.fst_length
= s
->sb
.st_size
;
1023 /* Ignore errors; this is merely advisory. */
1024 (void)fcntl(s
->dst_fd
, F_PREALLOCATE
, &fst
);
1028 while ((nread
= read(s
->src_fd
, bp
, blen
)) > 0)
1031 size_t left
= nread
;
1036 nwritten
= write(s
->dst_fd
, ptr
, left
);
1040 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop
);
1047 copyfile_warn("writing to output file got error");
1052 ptr
= ((char*)ptr
) + nwritten
;
1059 copyfile_warn("reading from %s", s
->src
);
1063 if (ftruncate(s
->dst_fd
, s
->sb
.st_size
) < 0)
1075 * copyfile_security() will copy the ACL set, and the
1076 * POSIX set. Complexities come when dealing with
1077 * inheritied permissions, and when dealing with both
1078 * POSIX and ACL permissions.
1080 static int copyfile_security(copyfile_state_t s
)
1083 acl_flagset_t flags
;
1085 acl_entry_t entry_src
= NULL
, entry_dst
= NULL
;
1086 acl_t acl_src
= NULL
, acl_dst
= NULL
;
1088 filesec_t tmp_fsec
= NULL
;
1089 filesec_t fsec_dst
= filesec_init();
1091 if (fsec_dst
== NULL
)
1095 if (COPYFILE_ACL
& s
->flags
)
1097 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
1099 if (errno
== ENOENT
)
1105 /* grab the destination acl
1106 cannot assume it's empty due to inheritance
1108 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
1111 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
1113 if (errno
== ENOENT
)
1114 acl_dst
= acl_init(4);
1119 for (;acl_get_entry(acl_src
,
1120 entry_src
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
1123 acl_get_flagset_np(entry_src
, &flags
);
1124 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
1126 if ((ret
= acl_create_entry(&acl_dst
, &entry_dst
)) == -1)
1129 if ((ret
= acl_copy_entry(entry_dst
, entry_src
)) == -1)
1132 copyfile_debug(2, "copied acl entry from %s to %s", s
->src
, s
->dst
);
1136 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_dst
))
1138 copyfile_debug(3, "altered acl");
1143 * The following code is attempting to ensure that only the requested
1144 * security information gets copied over to the destination file.
1145 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
1146 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
1149 * If we have both flags, we copy everything; if we have ACL but not STAT,
1150 * we remove the POSIX information from the filesec object, and apply the
1151 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
1152 * the extended version.
1154 tmp_fsec
= filesec_dup(s
->fsec
);
1155 if (tmp_fsec
== NULL
) {
1159 switch (COPYFILE_SECURITY
& s
->flags
) {
1161 copyfile_unset_posix_fsec(tmp_fsec
);
1163 case COPYFILE_ACL
| COPYFILE_STAT
:
1164 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0) {
1165 if (errno
== ENOTSUP
) {
1166 if (COPYFILE_STAT
& s
->flags
)
1167 fchmod(s
->dst_fd
, s
->sb
.st_mode
);
1169 copyfile_warn("setting security information: %s", s
->dst
);
1173 fchmod(s
->dst_fd
, s
->sb
.st_mode
);
1176 filesec_free(tmp_fsec
);
1178 filesec_free(fsec_dst
);
1179 if (acl_src
) acl_free(acl_src
);
1180 if (acl_dst
) acl_free(acl_dst
);
1191 * Attempt to set the destination file's stat information -- including
1192 * flags and time-related fields -- to the source's.
1194 static int copyfile_stat(copyfile_state_t s
)
1196 struct timeval tval
[2];
1198 * NFS doesn't support chflags; ignore errors unless there's reason
1199 * to believe we're losing bits. (Note, this still won't be right
1200 * if the server supports flags and we were trying to *remove* flags
1201 * on a file that we copied, i.e., that we didn't create.)
1203 if (fchflags(s
->dst_fd
, (u_int
)s
->sb
.st_flags
))
1204 if (errno
!= EOPNOTSUPP
|| s
->sb
.st_flags
!= 0)
1205 copyfile_warn("%s: set flags (was: 0%07o)", s
->dst
, s
->sb
.st_flags
);
1207 /* If this fails, we don't care */
1208 (void)fchown(s
->dst_fd
, s
->sb
.st_uid
, s
->sb
.st_gid
);
1210 /* This may have already been done in copyfile_security() */
1211 (void)fchmod(s
->dst_fd
, s
->sb
.st_mode
& ~S_IFMT
);
1213 tval
[0].tv_sec
= s
->sb
.st_atime
;
1214 tval
[1].tv_sec
= s
->sb
.st_mtime
;
1215 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
1216 if (futimes(s
->dst_fd
, tval
))
1217 copyfile_warn("%s: set times", s
->dst
);
1222 * Similar to copyfile_security() in some ways; this
1223 * routine copies the extended attributes from the source,
1224 * and sets them on the destination.
1225 * The procedure is pretty simple, even if it is verbose:
1226 * for each named attribute on the destination, get its name, and
1227 * remove it. We should have none after that.
1228 * For each named attribute on the source, get its name, get its
1229 * data, and set it on the destination.
1231 static int copyfile_xattr(copyfile_state_t s
)
1234 char *namebuf
, *end
;
1237 ssize_t bufsize
= 4096;
1242 /* delete EAs on destination */
1243 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
1245 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
1248 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
1252 * With this, end points to the last byte of the allocated buffer
1253 * This *should* be NUL, from flistxattr, but if it's not, we can
1254 * set it anyway -- it'll result in a truncated name, which then
1255 * shouldn't match when we get them later.
1257 end
= namebuf
+ nsize
- 1;
1260 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1) {
1261 /* If the quarantine information shows up as an EA, we skip over it */
1262 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0) {
1265 fremovexattr(s
->dst_fd
, name
,0);
1272 if (errno
== ENOTSUP
)
1278 /* get name list of EAs on source */
1279 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, 0)) < 0)
1281 if (errno
== ENOTSUP
)
1289 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
1292 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, 0);
1300 * With this, end points to the last byte of the allocated buffer
1301 * This *should* be NUL, from flistxattr, but if it's not, we can
1302 * set it anyway -- it'll result in a truncated name, which then
1303 * shouldn't match when we get them later.
1305 end
= namebuf
+ nsize
- 1;
1309 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
) {
1314 for (name
= namebuf
; name
<= end
; name
+= strlen(name
) + 1)
1316 /* If the quarantine information shows up as an EA, we skip over it */
1317 if (strncmp(name
, XATTR_QUARANTINE_NAME
, end
- name
) == 0)
1320 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, 0)) < 0)
1326 if (xa_size
> bufsize
)
1328 void *tdptr
= xa_dataptr
;
1331 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
1339 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, 0)) < 0)
1345 if (xa_size
!= asize
)
1348 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, 0) < 0)
1356 free((void *) xa_dataptr
);
1361 * API interface into getting data from the opaque data type.
1363 int copyfile_state_get(copyfile_state_t s
, uint32_t flag
, void *ret
)
1373 case COPYFILE_STATE_SRC_FD
:
1374 *(int*)ret
= s
->src_fd
;
1376 case COPYFILE_STATE_DST_FD
:
1377 *(int*)ret
= s
->dst_fd
;
1379 case COPYFILE_STATE_SRC_FILENAME
:
1380 *(char**)ret
= s
->src
;
1382 case COPYFILE_STATE_DST_FILENAME
:
1383 *(char**)ret
= s
->dst
;
1385 case COPYFILE_STATE_QUARANTINE
:
1386 *(qtn_file_t
*)ret
= s
->qinfo
;
1389 case COPYFILE_STATE_STATS
:
1390 ret
= s
->stats
.global
;
1392 case COPYFILE_STATE_PROGRESS_CB
:
1393 ret
= s
->callbacks
.progress
;
1405 * Public API for setting state data (remember that the state is
1406 * an opaque data type).
1408 int copyfile_state_set(copyfile_state_t s
, uint32_t flag
, const void * thing
)
1410 #define copyfile_set_string(DST, SRC) \
1412 if (SRC != NULL) { \
1413 DST = strdup((char *)SRC); \
1415 if (DST != NULL) { \
1430 case COPYFILE_STATE_SRC_FD
:
1431 s
->src_fd
= *(int*)thing
;
1433 case COPYFILE_STATE_DST_FD
:
1434 s
->dst_fd
= *(int*)thing
;
1436 case COPYFILE_STATE_SRC_FILENAME
:
1437 copyfile_set_string(s
->src
, thing
);
1439 case COPYFILE_STATE_DST_FILENAME
:
1440 copyfile_set_string(s
->dst
, thing
);
1442 case COPYFILE_STATE_QUARANTINE
:
1445 qtn_file_free(s
->qinfo
);
1448 if (*(qtn_file_t
*)thing
)
1449 s
->qinfo
= qtn_file_clone(*(qtn_file_t
*)thing
);
1452 case COPYFILE_STATE_STATS
:
1453 s
->stats
.global
= thing
;
1455 case COPYFILE_STATE_PROGRESS_CB
:
1456 s
->callbacks
.progress
= thing
;
1464 #undef copyfile_set_string
1469 * Make this a standalone program for testing purposes by
1470 * defining _COPYFILE_TEST.
1472 #ifdef _COPYFILE_TEST
1473 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
1475 struct {char *s
; int v
;} opts
[] = {
1476 COPYFILE_OPTION(ACL
)
1477 COPYFILE_OPTION(STAT
)
1478 COPYFILE_OPTION(XATTR
)
1479 COPYFILE_OPTION(DATA
)
1480 COPYFILE_OPTION(SECURITY
)
1481 COPYFILE_OPTION(METADATA
)
1482 COPYFILE_OPTION(ALL
)
1483 COPYFILE_OPTION(NOFOLLOW_SRC
)
1484 COPYFILE_OPTION(NOFOLLOW_DST
)
1485 COPYFILE_OPTION(NOFOLLOW
)
1486 COPYFILE_OPTION(EXCL
)
1487 COPYFILE_OPTION(MOVE
)
1488 COPYFILE_OPTION(UNLINK
)
1489 COPYFILE_OPTION(PACK
)
1490 COPYFILE_OPTION(UNPACK
)
1491 COPYFILE_OPTION(CHECK
)
1492 COPYFILE_OPTION(VERBOSE
)
1493 COPYFILE_OPTION(DEBUG
)
1497 int main(int c
, char *v
[])
1503 errx(1, "insufficient arguments");
1507 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
1509 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
1511 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
1518 return copyfile(v
[1], v
[2], NULL
, flags
);
1522 * Apple Double Create
1524 * Create an Apple Double "._" file from a file's extented attributes
1526 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
1530 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
1532 #define XATTR_MAXATTRLEN (4*1024)
1536 Typical "._" AppleDouble Header File layout:
1537 ------------------------------------------------------------
1542 .-- AD ENTRY[0] Finder Info Entry (must be first)
1543 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
1545 | ///////////// Fixed Size Data (32 bytes)
1549 | ATTR ENTRY[1] --+--.
1550 | ATTR ENTRY[2] --+--+--.
1552 | ATTR ENTRY[N] --+--+--+--.
1553 | ATTR DATA 0 <-' | | |
1554 | //////////// | | |
1555 | ATTR DATA 1 <----' | |
1557 | ATTR DATA 2 <-------' |
1560 | ATTR DATA N <----------'
1562 | Attribute Free Space
1564 '----> RESOURCE FORK
1565 ///////////// Variable Sized Data
1574 ------------------------------------------------------------
1576 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1577 stored as part of the Finder Info. The length in the Finder
1578 Info AppleDouble entry includes the length of the extended
1579 attribute header, attribute entries, and attribute data.
1584 * On Disk Data Structures
1586 * Note: Motorola 68K alignment and big-endian.
1588 * See RFC 1740 for additional information about the AppleDouble file format.
1592 #define ADH_MAGIC 0x00051607
1593 #define ADH_VERSION 0x00020000
1594 #define ADH_MACOSX "Mac OS X "
1597 * AppleDouble Entry ID's
1599 #define AD_DATA 1 /* Data fork */
1600 #define AD_RESOURCE 2 /* Resource fork */
1601 #define AD_REALNAME 3 /* File's name on home file system */
1602 #define AD_COMMENT 4 /* Standard Mac comment */
1603 #define AD_ICONBW 5 /* Mac black & white icon */
1604 #define AD_ICONCOLOR 6 /* Mac color icon */
1605 #define AD_UNUSED 7 /* Not used */
1606 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
1607 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
1608 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
1609 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
1610 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
1611 #define AD_AFPNAME 13 /* Short name on AFP server */
1612 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
1613 #define AD_AFPDIRID 15 /* AFP directory ID */
1614 #define AD_ATTRIBUTES AD_FINDERINFO
1617 #define ATTR_FILE_PREFIX "._"
1618 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
1620 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
1622 /* Implementation Limits */
1623 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
1624 #define ATTR_MAX_NAME_LEN 128
1625 #define ATTR_MAX_HDR_SIZE (65536+18)
1628 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
1629 * size supported (including the attribute entries). All of
1630 * the attribute entries must reside within this limit.
1634 #define FINDERINFOSIZE 32
1636 typedef struct apple_double_entry
1638 u_int32_t type
; /* entry type: see list, 0 invalid */
1639 u_int32_t offset
; /* entry data offset from the beginning of the file. */
1640 u_int32_t length
; /* entry data length in bytes. */
1641 } __attribute__((aligned(2), packed
)) apple_double_entry_t
;
1644 typedef struct apple_double_header
1646 u_int32_t magic
; /* == ADH_MAGIC */
1647 u_int32_t version
; /* format version: 2 = 0x00020000 */
1648 u_int32_t filler
[4];
1649 u_int16_t numEntries
; /* number of entries which follow */
1650 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
1651 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
1652 u_int8_t pad
[2]; /* get better alignment inside attr_header */
1653 } __attribute__((aligned(2), packed
)) apple_double_header_t
;
1656 /* Entries are aligned on 4 byte boundaries */
1657 typedef struct attr_entry
1659 u_int32_t offset
; /* file offset to data */
1660 u_int32_t length
; /* size of attribute data */
1662 u_int8_t namelen
; /* length of name including NULL termination char */
1663 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
1664 } __attribute__((aligned(2), packed
)) attr_entry_t
;
1668 /* Header + entries must fit into 64K */
1669 typedef struct attr_header
1671 apple_double_header_t appledouble
;
1672 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
1673 u_int32_t debug_tag
; /* for debugging == file id of owning file */
1674 u_int32_t total_size
; /* total size of attribute header + entries + data */
1675 u_int32_t data_start
; /* file offset to attribute data area */
1676 u_int32_t data_length
; /* length of attribute data area */
1677 u_int32_t reserved
[3];
1679 u_int16_t num_attrs
;
1680 } __attribute__((aligned(2), packed
)) attr_header_t
;
1682 /* Empty Resource Fork Header */
1683 /* This comes by way of xnu's vfs_xattr.c */
1684 typedef struct rsrcfork_header
{
1685 u_int32_t fh_DataOffset
;
1686 u_int32_t fh_MapOffset
;
1687 u_int32_t fh_DataLength
;
1688 u_int32_t fh_MapLength
;
1689 u_int8_t systemData
[112];
1690 u_int8_t appData
[128];
1691 u_int32_t mh_DataOffset
;
1692 u_int32_t mh_MapOffset
;
1693 u_int32_t mh_DataLength
;
1694 u_int32_t mh_MapLength
;
1696 u_int16_t mh_RefNum
;
1698 u_int8_t mh_InMemoryAttr
;
1701 u_int16_t typeCount
;
1702 } rsrcfork_header_t
;
1703 #define RF_FIRST_RESOURCE 256
1704 #define RF_NULL_MAP_LENGTH 30
1705 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
1707 static const rsrcfork_header_t empty_rsrcfork_header
= {
1708 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_DataOffset
1709 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // fh_MapOffset
1711 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // fh_MapLength
1712 { RF_EMPTY_TAG
, }, // systemData
1714 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_DataOffset
1715 OSSwapHostToBigInt32(RF_FIRST_RESOURCE
), // mh_MapOffset
1717 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH
), // mh_MapLength
1721 0, // mh_InMemoryAttr
1722 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
- 2), // mh_Types
1723 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH
), // mh_Names
1724 OSSwapHostToBigInt16(-1), // typeCount
1727 #define SWAP16(x) OSSwapBigToHostInt16(x)
1728 #define SWAP32(x) OSSwapBigToHostInt32(x)
1729 #define SWAP64(x) OSSwapBigToHostInt64(x)
1731 #define ATTR_ALIGN 3L /* Use four-byte alignment */
1733 #define ATTR_ENTRY_LENGTH(namelen) \
1734 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
1736 #define ATTR_NEXT(ae) \
1737 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
1739 #define XATTR_SECURITY_NAME "com.apple.acl.text"
1742 * Endian swap Apple Double header
1745 swap_adhdr(apple_double_header_t
*adh
)
1747 #if BYTE_ORDER == LITTLE_ENDIAN
1751 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
1753 adh
->magic
= SWAP32 (adh
->magic
);
1754 adh
->version
= SWAP32 (adh
->version
);
1755 adh
->numEntries
= SWAP16 (adh
->numEntries
);
1757 for (i
= 0; i
< count
; i
++)
1759 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
1760 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
1761 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
1769 * Endian swap extended attributes header
1772 swap_attrhdr(attr_header_t
*ah
)
1774 #if BYTE_ORDER == LITTLE_ENDIAN
1779 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
1781 ah
->magic
= SWAP32 (ah
->magic
);
1782 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
1783 ah
->total_size
= SWAP32 (ah
->total_size
);
1784 ah
->data_start
= SWAP32 (ah
->data_start
);
1785 ah
->data_length
= SWAP32 (ah
->data_length
);
1786 ah
->flags
= SWAP16 (ah
->flags
);
1787 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
1789 ae
= (attr_entry_t
*)(&ah
[1]);
1790 for (i
= 0; i
< count
; i
++)
1792 attr_entry_t
*next
= ATTR_NEXT(ae
);
1793 ae
->offset
= SWAP32 (ae
->offset
);
1794 ae
->length
= SWAP32 (ae
->length
);
1795 ae
->flags
= SWAP16 (ae
->flags
);
1803 static const u_int32_t emptyfinfo
[8] = {0};
1806 * Given an Apple Double file in src, turn it into a
1807 * normal file (possibly with multiple forks, EAs, and
1810 static int copyfile_unpack(copyfile_state_t s
)
1813 void * buffer
, * endptr
;
1814 apple_double_header_t
*adhdr
;
1818 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
1819 hdrsize
= (ssize_t
)s
->sb
.st_size
;
1821 hdrsize
= ATTR_MAX_HDR_SIZE
;
1823 buffer
= calloc(1, hdrsize
);
1824 if (buffer
== NULL
) {
1825 copyfile_debug(1, "copyfile_unpack: calloc(1, %u) returned NULL", hdrsize
);
1829 endptr
= (char*)buffer
+ hdrsize
;
1831 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
1835 copyfile_debug(1, "pread returned: %d", bytes
);
1839 if (bytes
< hdrsize
)
1842 "pread couldn't read entire header: %d of %d",
1843 (int)bytes
, (int)s
->sb
.st_size
);
1847 adhdr
= (apple_double_header_t
*)buffer
;
1850 * Check for Apple Double file.
1852 if ((size_t)bytes
< sizeof(apple_double_header_t
) - 2 ||
1853 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
1854 SWAP32(adhdr
->version
) != ADH_VERSION
||
1855 SWAP16(adhdr
->numEntries
) != 2 ||
1856 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
1858 if (COPYFILE_VERBOSE
& s
->flags
)
1859 copyfile_warn("Not a valid Apple Double header");
1866 * Remove any extended attributes on the target.
1869 if (COPYFILE_XATTR
& s
->flags
)
1871 if ((bytes
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
1873 char *namebuf
, *name
;
1875 if ((namebuf
= (char*) malloc(bytes
)) == NULL
)
1880 bytes
= flistxattr(s
->dst_fd
, namebuf
, bytes
, 0);
1883 for (name
= namebuf
; name
< namebuf
+ bytes
; name
+= strlen(name
) + 1)
1884 (void)fremovexattr(s
->dst_fd
, name
, 0);
1890 if (errno
!= ENOTSUP
)
1896 * Extract the extended attributes.
1899 * This assumes that the data is already in memory (not
1900 * the case when there are lots of attributes or one of
1901 * the attributes is very large.
1903 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
1905 attr_header_t
*attrhdr
;
1906 attr_entry_t
*entry
;
1910 if ((size_t)hdrsize
< sizeof(attr_header_t
)) {
1911 copyfile_warn("bad attribute header: %u < %u", hdrsize
, sizeof(attr_header_t
));
1916 attrhdr
= (attr_header_t
*)buffer
;
1917 swap_attrhdr(attrhdr
);
1918 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
1920 if (COPYFILE_VERBOSE
& s
->flags
)
1921 copyfile_warn("bad attribute header");
1925 count
= attrhdr
->num_attrs
;
1926 entry
= (attr_entry_t
*)&attrhdr
[1];
1928 for (i
= 0; i
< count
; i
++)
1933 * First we do some simple sanity checking.
1934 * +) See if entry is within the buffer's range;
1936 * +) Check the attribute name length; if it's longer than the
1937 * maximum, we truncate it down. (We could error out as well;
1938 * I'm not sure which is the better way to go here.)
1940 * +) If, given the name length, it goes beyond the end of
1941 * the buffer, error out.
1943 * +) If the last byte isn't a NUL, make it a NUL. (Since we
1944 * truncated the name length above, we truncate the name here.)
1946 * +) If entry->offset is so large that it causes dataptr to
1947 * go beyond the end of the buffer -- or, worse, so large that
1948 * it wraps around! -- we error out.
1950 * +) If entry->length would cause the entry to go beyond the
1951 * end of the buffer (or, worse, wrap around to before it),
1952 * *or* if the length is larger than the hdrsize, we error out.
1953 * (An explanation of that: what we're checking for there is
1954 * the small range of values such that offset+length would cause
1955 * it to go beyond endptr, and then wrap around past buffer. We
1956 * care about this because we are passing entry->length down to
1957 * fgetxattr() below, and an erroneously large value could cause
1958 * problems there. By making sure that it's less than hdrsize,
1959 * which has already been sanity-checked above, we're safe.
1960 * That may mean that the check against < buffer is unnecessary.)
1962 if ((void*)entry
>= endptr
|| (void*)entry
< buffer
) {
1963 if (COPYFILE_VERBOSE
& s
->flags
)
1964 copyfile_warn("Incomplete or corrupt attribute entry");
1969 if (((char*)entry
+ sizeof(*entry
)) > (char*)endptr
) {
1970 if (COPYFILE_VERBOSE
& s
->flags
)
1971 copyfile_warn("Incomplete or corrupt attribute entry");
1976 if (entry
->namelen
< 2) {
1977 if (COPYFILE_VERBOSE
& s
->flags
)
1978 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry
->namelen
);
1983 if (entry
->namelen
> XATTR_MAXNAMELEN
+ 1) {
1984 if (COPYFILE_VERBOSE
& s
->flags
)
1985 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry
->namelen
);
1990 if ((void*)(entry
->name
+ entry
->namelen
) > endptr
) {
1991 if (COPYFILE_VERBOSE
& s
->flags
)
1992 copyfile_warn("Incomplete or corrupt attribute entry");
1997 /* Because namelen includes the NUL, we check one byte back */
1998 if (entry
->name
[entry
->namelen
-1] != 0) {
1999 if (COPYFILE_VERBOSE
& s
->flags
)
2000 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
2005 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
2006 entry
->name
, entry
->length
, entry
->offset
);
2008 dataptr
= (char *)attrhdr
+ entry
->offset
;
2010 if (dataptr
> endptr
|| dataptr
< buffer
) {
2011 copyfile_debug(1, "Entry %d overflows: offset = %u", entry
->offset
);
2015 if (((char*)dataptr
+ entry
->length
) > (char*)endptr
||
2016 (((char*)dataptr
+ entry
->length
) < (char*)buffer
) ||
2017 (entry
->length
> (size_t)hdrsize
)) {
2018 if (COPYFILE_VERBOSE
& s
->flags
)
2019 copyfile_warn("Incomplete or corrupt attribute entry");
2020 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
2021 entry
->offset
, entry
->length
);
2026 if (strcmp((char*)entry
->name
, XATTR_QUARANTINE_NAME
) == 0)
2028 qtn_file_t tqinfo
= NULL
;
2030 if (s
->qinfo
== NULL
)
2032 tqinfo
= qtn_file_alloc();
2036 if ((x
= qtn_file_init_with_data(tqinfo
, dataptr
, entry
->length
)) != 0)
2038 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x
));
2039 qtn_file_free(tqinfo
);
2051 x
= qtn_file_apply_to_fd(tqinfo
, s
->dst_fd
);
2053 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x
));
2055 if (tqinfo
&& !s
->qinfo
)
2057 qtn_file_free(tqinfo
);
2060 /* Look for ACL data */
2061 else if (COPYFILE_ACL
& s
->flags
&& strcmp((char*)entry
->name
, XATTR_SECURITY_NAME
) == 0)
2066 char *tcp
= dataptr
;
2069 * acl_from_text() requires a NUL-terminated string. The ACL EA,
2070 * however, may not be NUL-terminated. So in that case, we need to
2071 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
2073 if (tcp
[entry
->length
- 1] != 0) {
2074 char *tmpstr
= malloc(entry
->length
+ 1);
2075 if (tmpstr
== NULL
) {
2079 strlcpy(tmpstr
, tcp
, entry
->length
+ 1);
2080 acl
= acl_from_text(tmpstr
);
2083 acl
= acl_from_text(tcp
);
2090 if ((fsec_tmp
= filesec_init()) == NULL
)
2092 else if((error
= fstatx_np(s
->dst_fd
, &sb
, fsec_tmp
)) < 0)
2094 else if (filesec_set_property(fsec_tmp
, FILESEC_ACL
, &acl
) < 0)
2097 while (fchmodx_np(s
->dst_fd
, fsec_tmp
) < 0)
2099 if (errno
== ENOTSUP
)
2101 if (retry
&& !copyfile_unset_acl(s
))
2107 copyfile_warn("setting security information");
2113 filesec_free(fsec_tmp
);
2119 /* And, finally, everything else */
2120 else if (COPYFILE_XATTR
& s
->flags
&& (fsetxattr(s
->dst_fd
, (char *)entry
->name
, dataptr
, entry
->length
, 0, 0))) {
2121 if (COPYFILE_VERBOSE
& s
->flags
)
2122 copyfile_warn("error %d setting attribute %s", error
, entry
->name
);
2125 entry
= ATTR_NEXT(entry
);
2130 * Extract the Finder Info.
2132 if (adhdr
->entries
[0].offset
> (hdrsize
- sizeof(emptyfinfo
))) {
2137 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
2139 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
2140 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
2146 * Extract the Resource Fork.
2148 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
2149 adhdr
->entries
[1].length
> 0)
2151 void * rsrcforkdata
= NULL
;
2155 struct timeval tval
[2];
2157 length
= adhdr
->entries
[1].length
;
2158 offset
= adhdr
->entries
[1].offset
;
2159 rsrcforkdata
= malloc(length
);
2161 if (rsrcforkdata
== NULL
) {
2162 copyfile_debug(1, "could not allocate %u bytes for rsrcforkdata",
2168 if (fstat(s
->dst_fd
, &sb
) < 0)
2170 copyfile_debug(1, "couldn't stat destination file");
2175 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
2176 if (bytes
< (ssize_t
)length
)
2180 copyfile_debug(1, "couldn't read resource fork");
2185 "couldn't read resource fork (only read %d bytes of %d)",
2186 (int)bytes
, (int)length
);
2191 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
2195 * For filesystems that do not natively support named attributes,
2196 * the kernel creates an AppleDouble file that -- for compatabilty
2197 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
2198 * structure that says there are no resources. So, if fsetxattr has
2199 * failed, and the resource fork is that empty structure, *and* the
2200 * target file is a directory, then we do nothing with it.
2202 if ((bytes
== sizeof(rsrcfork_header_t
)) &&
2203 ((sb
.st_mode
& S_IFMT
) == S_IFDIR
) &&
2204 (memcmp(rsrcforkdata
, &empty_rsrcfork_header
, bytes
) == 0)) {
2205 copyfile_debug(2, "not setting empty resource fork on directory");
2209 copyfile_debug(1, "error %d setting resource fork attribute", error
);
2213 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
2214 XATTR_RESOURCEFORK_NAME
, (int)length
);
2216 if (!(s
->flags
& COPYFILE_STAT
))
2218 tval
[0].tv_sec
= sb
.st_atime
;
2219 tval
[1].tv_sec
= sb
.st_mtime
;
2220 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
2222 if (futimes(s
->dst_fd
, tval
))
2223 copyfile_warn("%s: set times", s
->dst
);
2230 if (COPYFILE_STAT
& s
->flags
)
2232 error
= copyfile_stat(s
);
2235 if (buffer
) free(buffer
);
2239 static int copyfile_pack_quarantine(copyfile_state_t s
, void **buf
, ssize_t
*len
)
2242 char qbuf
[QTN_SERIALIZED_DATA_MAX
];
2243 size_t qlen
= sizeof(qbuf
);
2245 if (s
->qinfo
== NULL
)
2251 if (qtn_file_to_data(s
->qinfo
, qbuf
, &qlen
) != 0)
2257 *buf
= malloc(qlen
);
2260 memcpy(*buf
, qbuf
, qlen
);
2267 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
2273 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
2275 if (errno
!= ENOENT
)
2278 if (COPYFILE_VERBOSE
& s
->flags
)
2279 copyfile_warn("getting acl");
2285 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
2288 * acl_to_text() doesn't include the NUL at the endo
2289 * in it's count (*len). It does, however, promise to
2290 * return a valid C string, so we need to up the count
2294 *buf
= malloc(*len
);
2296 memcpy(*buf
, acl_text
, *len
);
2301 copyfile_debug(2, "copied acl (%ld) %p", *len
, *buf
);
2308 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
2311 char *databuf
= NULL
;
2314 /* Get the resource fork size */
2315 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
2317 if (COPYFILE_VERBOSE
& s
->flags
)
2318 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
2322 if (datasize
> INT_MAX
) {
2328 if ((databuf
= malloc(datasize
)) == NULL
)
2330 copyfile_warn("malloc");
2335 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
2337 if (COPYFILE_VERBOSE
& s
->flags
)
2338 copyfile_warn("couldn't read entire resource fork");
2343 /* Write the resource fork to disk. */
2344 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
2346 if (COPYFILE_VERBOSE
& s
->flags
)
2347 copyfile_warn("couldn't write resource fork");
2349 copyfile_debug(3, "copied %d bytes of \"%s\" data @ offset 0x%08x",
2350 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
2351 filehdr
->appledouble
.entries
[1].length
= (u_int32_t
)datasize
;
2361 * The opposite of copyfile_unpack(), obviously.
2363 static int copyfile_pack(copyfile_state_t s
)
2365 char *attrnamebuf
= NULL
, *endnamebuf
;
2366 void *databuf
= NULL
;
2367 attr_header_t
*filehdr
, *endfilehdr
;
2368 attr_entry_t
*entry
;
2369 ssize_t listsize
= 0;
2375 int hasrsrcfork
= 0;
2377 int seenq
= 0; // Have we seen any quarantine info already?
2379 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_SIZE
);
2380 if (filehdr
== NULL
) {
2384 endfilehdr
= (attr_header_t
*)(((char*)filehdr
) + ATTR_MAX_SIZE
);
2387 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
2388 if (attrnamebuf
== NULL
) {
2392 endnamebuf
= ((char*)attrnamebuf
) + ATTR_MAX_HDR_SIZE
;
2396 * Fill in the Apple Double Header defaults.
2398 filehdr
->appledouble
.magic
= ADH_MAGIC
;
2399 filehdr
->appledouble
.version
= ADH_VERSION
;
2400 filehdr
->appledouble
.numEntries
= 2;
2401 filehdr
->appledouble
.entries
[0].type
= AD_FINDERINFO
;
2402 filehdr
->appledouble
.entries
[0].offset
= (u_int32_t
)offsetof(apple_double_header_t
, finfo
);
2403 filehdr
->appledouble
.entries
[0].length
= FINDERINFOSIZE
;
2404 filehdr
->appledouble
.entries
[1].type
= AD_RESOURCE
;
2405 filehdr
->appledouble
.entries
[1].offset
= (u_int32_t
)offsetof(apple_double_header_t
, pad
);
2406 filehdr
->appledouble
.entries
[1].length
= 0;
2407 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
2410 * Fill in the initial Attribute Header.
2412 filehdr
->magic
= ATTR_HDR_MAGIC
;
2413 filehdr
->debug_tag
= s
->sb
.st_ino
;
2414 filehdr
->data_start
= (u_int32_t
)sizeof(attr_header_t
);
2417 * Collect the attribute names.
2419 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
2422 * Test if there are acls to copy
2424 if (COPYFILE_ACL
& s
->flags
)
2426 acl_t temp_acl
= NULL
;
2427 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &temp_acl
) < 0)
2429 copyfile_debug(2, "no acl entries found (errno = %d)", errno
);
2432 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
2433 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
2439 if (COPYFILE_XATTR
& s
->flags
)
2441 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
2442 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, left
, 0)) <= 0)
2444 copyfile_debug(2, "no extended attributes found (%d)", errno
);
2446 if (listsize
> left
)
2448 copyfile_debug(1, "extended attribute list too long");
2453 endnamebuf
= attrnamebuf
+ listsize
;
2454 if (endnamebuf
> (attrnamebuf
+ ATTR_MAX_HDR_SIZE
)) {
2459 for (nameptr
= attrnamebuf
; nameptr
< endnamebuf
; nameptr
+= namelen
)
2461 namelen
= strlen(nameptr
) + 1;
2462 /* Skip over FinderInfo or Resource Fork names */
2463 if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0 ||
2464 strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0) {
2467 if (strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0) {
2471 /* The system should prevent this from happening, but... */
2472 if (namelen
> XATTR_MAXNAMELEN
+ 1) {
2473 namelen
= XATTR_MAXNAMELEN
+ 1;
2475 entry
->namelen
= namelen
;
2477 if (nameptr
+ namelen
> endnamebuf
) {
2481 bcopy(nameptr
, &entry
->name
[0], namelen
);
2482 copyfile_debug(2, "copied name [%s]", entry
->name
);
2484 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
2485 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
2487 if ((void*)entry
>= (void*)endfilehdr
) {
2492 /* Update the attributes header. */
2493 filehdr
->num_attrs
++;
2494 filehdr
->data_start
+= (u_int32_t
)entrylen
;
2499 * If we have any quarantine data, we always pack it.
2500 * But if we've already got it in the EA list, don't put it in again.
2502 if (s
->qinfo
&& !seenq
)
2504 ssize_t left
= ATTR_MAX_HDR_SIZE
- offset
;
2505 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
2506 offset
+= strlcpy(attrnamebuf
+ offset
, XATTR_QUARANTINE_NAME
, left
) + 1;
2511 * Collect the attribute data.
2513 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
2515 for (nameptr
= attrnamebuf
; nameptr
< attrnamebuf
+ listsize
; nameptr
+= namelen
+ 1)
2517 namelen
= strlen(nameptr
);
2519 if (strcmp(nameptr
, XATTR_SECURITY_NAME
) == 0)
2520 copyfile_pack_acl(s
, &databuf
, &datasize
);
2521 else if (s
->qinfo
&& strcmp(nameptr
, XATTR_QUARANTINE_NAME
) == 0)
2523 copyfile_pack_quarantine(s
, &databuf
, &datasize
);
2525 /* Check for Finder Info. */
2526 else if (strcmp(nameptr
, XATTR_FINDERINFO_NAME
) == 0)
2528 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
2531 if (COPYFILE_VERBOSE
& s
->flags
)
2532 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
2533 } else if (datasize
!= 32)
2535 if (COPYFILE_VERBOSE
& s
->flags
)
2536 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
2539 if (COPYFILE_VERBOSE
& s
->flags
)
2540 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
2541 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
2543 continue; /* finder info doesn't have an attribute entry */
2545 /* Check for Resource Fork. */
2546 else if (strcmp(nameptr
, XATTR_RESOURCEFORK_NAME
) == 0)
2552 /* Just a normal attribute. */
2553 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
2558 if (COPYFILE_VERBOSE
& s
->flags
)
2559 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
2562 if (datasize
> XATTR_MAXATTRLEN
)
2564 if (COPYFILE_VERBOSE
& s
->flags
)
2565 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
2568 databuf
= malloc(datasize
);
2569 if (databuf
== NULL
) {
2573 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
2576 entry
->length
= (u_int32_t
)datasize
;
2577 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
2579 filehdr
->data_length
+= (u_int32_t
)datasize
;
2582 * This assumes that the data is fits in memory (not
2583 * the case when there are lots of attributes or one of
2584 * the attributes is very large.
2586 if (entry
->offset
> ATTR_MAX_SIZE
||
2587 (entry
->offset
+ datasize
> ATTR_MAX_SIZE
)) {
2590 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
2594 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
2596 /* bump to next entry */
2597 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
2598 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
2601 if (filehdr
->data_length
> 0)
2603 /* Now we know where the resource fork data starts. */
2604 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
2606 /* We also know the size of the "Finder Info entry. */
2607 filehdr
->appledouble
.entries
[0].length
=
2608 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
2610 filehdr
->total_size
= filehdr
->appledouble
.entries
[1].offset
;
2613 /* Copy Resource Fork. */
2614 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
2617 /* Write the header to disk. */
2618 datasize
= filehdr
->appledouble
.entries
[1].offset
;
2620 swap_adhdr(&filehdr
->appledouble
);
2621 swap_attrhdr(filehdr
);
2623 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
2625 if (COPYFILE_VERBOSE
& s
->flags
)
2626 copyfile_warn("couldn't write file header");
2631 if (filehdr
) free(filehdr
);
2632 if (attrnamebuf
) free(attrnamebuf
);
2637 return copyfile_stat(s
);