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>
37 #include <sys/xattr.h>
38 #include <sys/syscall.h>
39 #include <sys/param.h>
41 #include <libkern/OSByteOrder.h>
42 #include <membership.h>
46 struct _copyfile_state
54 copyfile_flags_t flags
;
59 static int copyfile_open (copyfile_state_t
);
60 static int copyfile_close (copyfile_state_t
);
61 static int copyfile_data (copyfile_state_t
);
62 static int copyfile_stat (copyfile_state_t
);
63 static int copyfile_security (copyfile_state_t
);
64 static int copyfile_xattr (copyfile_state_t
);
65 static int copyfile_pack (copyfile_state_t
);
66 static int copyfile_unpack (copyfile_state_t
);
68 static copyfile_flags_t
copyfile_check (copyfile_state_t
);
69 static int copyfile_fix_perms(copyfile_state_t
, filesec_t
*, int);
71 #define COPYFILE_DEBUG (1<<31)
73 #ifndef _COPYFILE_TEST
74 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
75 # define copyfile_debug(d, str, ...) \
76 if (s && (d <= s->debug)) {\
77 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
80 #define copyfile_warn(str, ...) \
81 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
82 # define copyfile_debug(d, str, ...) \
83 if (s && (d <= s->debug)) {\
84 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
88 int copyfile(const char *src
, const char *dst
, copyfile_state_t state
, copyfile_flags_t flags
)
91 copyfile_state_t s
= state
;
92 filesec_t original_fsec
;
95 original_fsec
= filesec_init();
96 if (s
== NULL
&& (s
= copyfile_init()) == NULL
)
101 if (s
->src_fd
!= -2 && s
->src
&& !strncmp(src
, s
->src
, MAXPATHLEN
))
103 s
->src
= strdup(src
);
108 if (s
->dst_fd
!= -2 && s
->dst
&& !strncmp(dst
, s
->dst
, MAXPATHLEN
))
110 s
->dst
= strdup(dst
);
115 if (COPYFILE_DEBUG
& s
->flags
)
118 if ((e
= getenv("COPYFILE_DEBUG")))
120 s
->debug
= strtol(e
, NULL
, 0);
124 copyfile_debug(1, "debug value set to: %d\n", s
->debug
);
127 if (COPYFILE_CHECK
& flags
)
128 return copyfile_check(s
);
130 if (copyfile_open(s
) < 0)
134 if (s
->dst_fd
== -2 || s
->src_fd
== -2)
137 if (COPYFILE_PACK
& flags
)
139 if (copyfile_pack(s
) < 0)
144 } else if (COPYFILE_UNPACK
& flags
)
146 if (copyfile_unpack(s
) < 0)
150 if (COPYFILE_SECURITY
& flags
)
152 if (copyfile_security(s
) < 0)
154 copyfile_warn("error processing security information");
157 } else if (COPYFILE_UNPACK
& flags
)
159 fix_perms
= !copyfile_fix_perms(s
, &original_fsec
, 1);
160 if (copyfile_unpack(s
) < 0)
164 if (COPYFILE_SECURITY
& flags
)
166 copyfile_warn("error processing stat information");
170 fix_perms
= !copyfile_fix_perms(s
, &original_fsec
, 1);
172 if (COPYFILE_XATTR
& flags
)
174 if (copyfile_xattr(s
) < 0)
176 copyfile_warn("error processing extended attributes");
180 if (COPYFILE_DATA
& flags
)
182 if (copyfile_data(s
) < 0)
184 copyfile_warn("error processing data");
186 if (s
->dst
&& unlink(s
->dst
))
187 copyfile_warn("%s: remove", s
->src
);
195 copyfile_fix_perms(s
, &original_fsec
, 0);
197 filesec_free(original_fsec
);
200 ret
-= copyfile_free(s
);
204 copyfile_state_t
copyfile_init(void)
206 copyfile_state_t s
= (copyfile_state_t
) calloc(1, sizeof(struct _copyfile_state
));
212 s
->fsec
= filesec_init();
218 int copyfile_free(copyfile_state_t s
)
223 filesec_free(s
->fsec
);
229 if (copyfile_close(s
) < 0)
231 copyfile_warn("error closing files");
239 static int copyfile_close(copyfile_state_t s
)
244 if (s
->dst_fd
!= -2 && close(s
->dst_fd
))
246 copyfile_warn("close on %s", s
->dst
);
252 static int copyfile_fix_perms(copyfile_state_t s
, filesec_t
*fsec
, int on
)
261 if(statx_np(s
->dst
, &sb
, *fsec
))
264 tmp_fsec
= filesec_dup(*fsec
);
266 if (!filesec_get_property(tmp_fsec
, FILESEC_ACL
, &acl
))
269 acl_permset_t permset
;
272 if (mbr_uid_to_uuid(getuid(), qual
) != 0)
275 if (acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
) == -1)
277 if (acl_get_permset(entry
, &permset
) == -1)
279 if (acl_clear_perms(permset
) == -1)
281 if (acl_add_perm(permset
, ACL_WRITE_DATA
) == -1)
283 if (acl_add_perm(permset
, ACL_WRITE_ATTRIBUTES
) == -1)
285 if (acl_add_perm(permset
, ACL_WRITE_EXTATTRIBUTES
) == -1)
287 if (acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
) == -1)
290 if(acl_set_permset(entry
, permset
) == -1)
292 if(acl_set_qualifier(entry
, qual
) == -1)
295 if (filesec_set_property(tmp_fsec
, FILESEC_ACL
, &acl
) != 0)
299 if (filesec_get_property(tmp_fsec
, FILESEC_MODE
, &mode
) == 0)
304 if (filesec_set_property(tmp_fsec
, FILESEC_MODE
, &mode
) != 0)
308 if (fchmodx_np(s
->dst_fd
, tmp_fsec
) < 0 && errno
!= ENOTSUP
)
309 copyfile_warn("setting security information");
310 filesec_free(tmp_fsec
);
312 if (fchmodx_np(s
->dst_fd
, *fsec
) < 0 && errno
!= ENOTSUP
)
313 copyfile_warn("setting security information");
322 static int copyfile_open(copyfile_state_t s
)
324 int oflags
= O_EXCL
| O_CREAT
;
326 if (s
->src
&& s
->src_fd
== -2)
328 if ((COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
329 (s
->src
, &s
->sb
, s
->fsec
))
331 copyfile_warn("stat on %s", s
->src
);
334 if ((s
->src_fd
= open(s
->src
, O_RDONLY
, 0)) < 0)
336 copyfile_warn("open on %s", s
->src
);
341 if (s
->dst
&& s
->dst_fd
== -2)
343 if (COPYFILE_DATA
& s
->flags
|| COPYFILE_PACK
& s
->flags
)
346 if (COPYFILE_ACL
& ~s
->flags
)
348 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, NULL
) == -1)
350 copyfile_debug(1, "unsetting acl attribute on %s", s
->dst
);
353 if (COPYFILE_STAT
& ~s
->flags
)
355 if (filesec_set_property(s
->fsec
, FILESEC_MODE
, NULL
) == -1)
357 copyfile_debug(1, "unsetting mode attribute on %s", s
->dst
);
360 if (COPYFILE_PACK
& s
->flags
)
363 if (filesec_set_property(s
->fsec
, FILESEC_MODE
, &m
) == -1)
365 mode_t m
= S_IRUSR
| S_IWUSR
;
366 if (filesec_set_property(s
->fsec
, FILESEC_MODE
, &m
) == -1)
368 copyfile_debug(1, "setting mode attribute on %s", s
->dst
);
371 if (filesec_set_property(s
->fsec
, FILESEC_OWNER
, NULL
) == -1)
373 copyfile_debug(1, "unsetting uid attribute on %s", s
->dst
);
375 if (filesec_set_property(s
->fsec
, FILESEC_UUID
, NULL
) == -1)
377 copyfile_debug(1, "unsetting uuid attribute on %s", s
->dst
);
379 if (filesec_set_property(s
->fsec
, FILESEC_GROUP
, NULL
) == -1)
381 copyfile_debug(1, "unsetting gid attribute on %s", s
->dst
);
385 if (COPYFILE_UNLINK
& s
->flags
&& unlink(s
->dst
) < 0)
387 copyfile_warn("%s: remove", s
->dst
);
391 while((s
->dst_fd
= openx_np(s
->dst
, oflags
, s
->fsec
)) < 0)
395 oflags
= oflags
& ~O_CREAT
;
398 copyfile_warn("open on %s", s
->dst
);
405 static copyfile_flags_t
copyfile_check(copyfile_state_t s
)
408 copyfile_flags_t ret
= 0;
414 if (COPYFILE_XATTR
& s
->flags
)
415 if (listxattr(s
->src
, 0, 0, 0) > 0)
416 ret
|= COPYFILE_XATTR
;
418 if (COPYFILE_ACL
& s
->flags
)
420 (COPYFILE_NOFOLLOW_SRC
& s
->flags
? lstatx_np
: statx_np
)
421 (s
->src
, &s
->sb
, s
->fsec
);
423 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) == 0)
430 static int copyfile_data(copyfile_state_t s
)
437 if ((bp
= malloc((size_t)s
->sb
.st_blksize
)) == NULL
)
440 warnx("malloc failed");
443 blen
= s
->sb
.st_blksize
;
445 while ((nread
= read(s
->src_fd
, bp
, (size_t)blen
)) > 0)
447 if (write(s
->dst_fd
, bp
, (size_t)nread
) != nread
)
449 copyfile_warn("writing to %s", s
->dst
);
455 copyfile_warn("reading from %s", s
->src
);
461 if (ftruncate(s
->dst_fd
, s
->sb
.st_size
) < 0)
467 static int copyfile_security(copyfile_state_t s
)
469 filesec_t fsec_dst
= filesec_init();
474 acl_entry_t entry_src
= NULL
, entry_dst
= NULL
;
475 acl_t acl_src
, acl_dst
;
476 int inited_dst
= 0, inited_src
= 0, ret
= 0;
478 if (COPYFILE_ACL
& s
->flags
)
480 if(fstatx_np(s
->dst_fd
, &sb
, fsec_dst
))
485 if (filesec_get_property(fsec_dst
, FILESEC_ACL
, &acl_dst
))
489 acl_dst
= acl_init(4);
499 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl_src
))
505 acl_dst
= acl_init(4);
515 for (;acl_get_entry(acl_src
,
516 entry_src
== NULL
? ACL_FIRST_ENTRY
: ACL_NEXT_ENTRY
,
519 acl_get_flagset_np(entry_src
, &flags
);
520 if (!acl_get_flag_np(flags
, ACL_ENTRY_INHERITED
))
522 if ((ret
= acl_create_entry(&acl_dst
, &entry_dst
)) == -1)
525 if ((ret
= acl_copy_entry(entry_dst
, entry_src
)) == -1)
528 copyfile_debug(1, "copied acl entry from %s to %s", s
->src
, s
->dst
);
533 if (!filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl_dst
))
535 copyfile_debug(1, "altered acl");
539 if (fchmodx_np(s
->dst_fd
, s
->fsec
) < 0 && errno
!= ENOTSUP
)
540 copyfile_warn("setting security information: %s", s
->dst
);
543 filesec_free(fsec_dst
);
544 if (inited_src
) acl_free(acl_src
);
545 if (inited_dst
) acl_free(acl_dst
);
550 static int copyfile_stat(copyfile_state_t s
)
552 struct timeval tval
[2];
554 * NFS doesn't support chflags; ignore errors unless there's reason
555 * to believe we're losing bits. (Note, this still won't be right
556 * if the server supports flags and we were trying to *remove* flags
557 * on a file that we copied, i.e., that we didn't create.)
559 if (chflags(s
->dst
, (u_long
)s
->sb
.st_flags
))
560 if (errno
!= EOPNOTSUPP
|| s
->sb
.st_flags
!= 0)
561 copyfile_warn("%s: set flags (was: 0%07o)", s
->dst
, s
->sb
.st_flags
);
563 tval
[0].tv_sec
= s
->sb
.st_atime
;
564 tval
[1].tv_sec
= s
->sb
.st_mtime
;
565 tval
[0].tv_usec
= tval
[1].tv_usec
= 0;
566 if (utimes(s
->dst
, tval
))
567 copyfile_warn("%s: set times", s
->dst
);
571 static int copyfile_xattr(copyfile_state_t s
)
577 size_t bufsize
= 4096;
583 if (COPYFILE_NOFOLLOW_SRC
& s
->flags
)
584 flags
|= XATTR_NOFOLLOW
;
586 /* delete EAs on destination */
587 if ((nsize
= flistxattr(s
->dst_fd
, 0, 0, 0)) > 0)
589 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
592 nsize
= flistxattr(s
->dst_fd
, namebuf
, nsize
, 0);
595 for (name
= namebuf
; name
< namebuf
+ nsize
; name
+= strlen(name
) + 1)
596 fremovexattr(s
->dst_fd
, name
,flags
);
599 } else if (nsize
< 0)
601 if (errno
== ENOTSUP
)
607 /* get name list of EAs on source */
608 if ((nsize
= flistxattr(s
->src_fd
, 0, 0, 0)) < 0)
610 if (errno
== ENOTSUP
)
614 } else if (nsize
== 0)
617 if ((namebuf
= (char *) malloc(nsize
)) == NULL
)
620 nsize
= flistxattr(s
->src_fd
, namebuf
, nsize
, 0);
625 if ((xa_dataptr
= (void *) malloc(bufsize
)) == NULL
)
628 for (name
= namebuf
; name
< namebuf
+ nsize
; name
+= strlen(name
) + 1)
630 if ((xa_size
= fgetxattr(s
->src_fd
, name
, 0, 0, 0, flags
)) < 0)
636 if (xa_size
> bufsize
)
640 (void *) realloc((void *) xa_dataptr
, bufsize
)) == NULL
)
647 if ((asize
= fgetxattr(s
->src_fd
, name
, xa_dataptr
, xa_size
, 0, flags
)) < 0)
653 if (xa_size
!= asize
)
656 if (fsetxattr(s
->dst_fd
, name
, xa_dataptr
, xa_size
, 0, flags
) < 0)
662 free((void *) xa_dataptr
);
667 #ifdef _COPYFILE_TEST
668 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
670 struct {char *s
; int v
;} opts
[] = {
672 COPYFILE_OPTION(STAT
)
673 COPYFILE_OPTION(XATTR
)
674 COPYFILE_OPTION(DATA
)
675 COPYFILE_OPTION(SECURITY
)
676 COPYFILE_OPTION(METADATA
)
678 COPYFILE_OPTION(NOFOLLOW_SRC
)
679 COPYFILE_OPTION(NOFOLLOW_DST
)
680 COPYFILE_OPTION(NOFOLLOW
)
681 COPYFILE_OPTION(EXCL
)
682 COPYFILE_OPTION(MOVE
)
683 COPYFILE_OPTION(UNLINK
)
684 COPYFILE_OPTION(PACK
)
685 COPYFILE_OPTION(UNPACK
)
686 COPYFILE_OPTION(CHECK
)
687 COPYFILE_OPTION(VERBOSE
)
688 COPYFILE_OPTION(DEBUG
)
692 int main(int c
, char *v
[])
698 errx(1, "insufficient arguments");
702 for (i
= 0; opts
[i
].s
!= NULL
; ++i
)
704 if (strcasecmp(opts
[i
].s
, v
[c
]) == 0)
706 printf("option %d: %s <- %d\n", c
, opts
[i
].s
, opts
[i
].v
);
713 return copyfile(v
[1], v
[2], NULL
, flags
);
717 * Apple Double Create
719 * Create an Apple Double "._" file from a file's extented attributes
721 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
725 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
727 #define XATTR_MAXATTRLEN (4*1024)
731 Typical "._" AppleDouble Header File layout:
732 ------------------------------------------------------------
737 .-- AD ENTRY[0] Finder Info Entry (must be first)
738 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
740 | ///////////// Fixed Size Data (32 bytes)
744 | ATTR ENTRY[1] --+--.
745 | ATTR ENTRY[2] --+--+--.
747 | ATTR ENTRY[N] --+--+--+--.
748 | ATTR DATA 0 <-' | | |
750 | ATTR DATA 1 <----' | |
752 | ATTR DATA 2 <-------' |
755 | ATTR DATA N <----------'
757 | Attribute Free Space
760 ///////////// Variable Sized Data
769 ------------------------------------------------------------
771 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
772 stored as part of the Finder Info. The length in the Finder
773 Info AppleDouble entry includes the length of the extended
774 attribute header, attribute entries, and attribute data.
779 * On Disk Data Structures
781 * Note: Motorola 68K alignment and big-endian.
783 * See RFC 1740 for additional information about the AppleDouble file format.
787 #define ADH_MAGIC 0x00051607
788 #define ADH_VERSION 0x00020000
789 #define ADH_MACOSX "Mac OS X "
792 * AppleDouble Entry ID's
794 #define AD_DATA 1 /* Data fork */
795 #define AD_RESOURCE 2 /* Resource fork */
796 #define AD_REALNAME 3 /* FileÕs name on home file system */
797 #define AD_COMMENT 4 /* Standard Mac comment */
798 #define AD_ICONBW 5 /* Mac black & white icon */
799 #define AD_ICONCOLOR 6 /* Mac color icon */
800 #define AD_UNUSED 7 /* Not used */
801 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
802 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
803 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
804 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
805 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
806 #define AD_AFPNAME 13 /* Short name on AFP server */
807 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
808 #define AD_AFPDIRID 15 /* AFP directory ID */
809 #define AD_ATTRIBUTES AD_FINDERINFO
812 #define ATTR_FILE_PREFIX "._"
813 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
815 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
817 /* Implementation Limits */
818 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
819 #define ATTR_MAX_NAME_LEN 128
820 #define ATTR_MAX_HDR_SIZE (65536+18)
823 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
824 * size supported (including the attribute entries). All of
825 * the attribute entries must reside within this limit.
829 #pragma options align=mac68k
831 #define FINDERINFOSIZE 32
833 typedef struct apple_double_entry
835 u_int32_t type
; /* entry type: see list, 0 invalid */
836 u_int32_t offset
; /* entry data offset from the beginning of the file. */
837 u_int32_t length
; /* entry data length in bytes. */
838 } apple_double_entry_t
;
841 typedef struct apple_double_header
843 u_int32_t magic
; /* == ADH_MAGIC */
844 u_int32_t version
; /* format version: 2 = 0x00020000 */
846 u_int16_t numEntries
; /* number of entries which follow */
847 apple_double_entry_t entries
[2]; /* 'finfo' & 'rsrc' always exist */
848 u_int8_t finfo
[FINDERINFOSIZE
]; /* Must start with Finder Info (32 bytes) */
849 u_int8_t pad
[2]; /* get better alignment inside attr_header */
850 } apple_double_header_t
;
853 /* Entries are aligned on 4 byte boundaries */
854 typedef struct attr_entry
856 u_int32_t offset
; /* file offset to data */
857 u_int32_t length
; /* size of attribute data */
859 u_int8_t namelen
; /* length of name including NULL termination char */
860 u_int8_t name
[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
864 /* Header + entries must fit into 64K */
865 typedef struct attr_header
867 apple_double_header_t appledouble
;
868 u_int32_t magic
; /* == ATTR_HDR_MAGIC */
869 u_int32_t debug_tag
; /* for debugging == file id of owning file */
870 u_int32_t total_size
; /* total size of attribute header + entries + data */
871 u_int32_t data_start
; /* file offset to attribute data area */
872 u_int32_t data_length
; /* length of attribute data area */
873 u_int32_t reserved
[3];
879 #pragma options align=reset
881 #define SWAP16(x) OSSwapBigToHostInt16(x)
882 #define SWAP32(x) OSSwapBigToHostInt32(x)
883 #define SWAP64(x) OSSwapBigToHostInt64(x)
885 #define ATTR_ALIGN 3L /* Use four-byte alignment */
887 #define ATTR_ENTRY_LENGTH(namelen) \
888 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
890 #define ATTR_NEXT(ae) \
891 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
893 #define XATTR_SECURITY_NAME "com.apple.acl.text"
896 * Endian swap Apple Double header
899 swap_adhdr(apple_double_header_t
*adh
)
901 #if BYTE_ORDER == LITTLE_ENDIAN
905 count
= (adh
->magic
== ADH_MAGIC
) ? adh
->numEntries
: SWAP16(adh
->numEntries
);
907 adh
->magic
= SWAP32 (adh
->magic
);
908 adh
->version
= SWAP32 (adh
->version
);
909 adh
->numEntries
= SWAP16 (adh
->numEntries
);
911 for (i
= 0; i
< count
; i
++)
913 adh
->entries
[i
].type
= SWAP32 (adh
->entries
[i
].type
);
914 adh
->entries
[i
].offset
= SWAP32 (adh
->entries
[i
].offset
);
915 adh
->entries
[i
].length
= SWAP32 (adh
->entries
[i
].length
);
921 * Endian swap extended attributes header
924 swap_attrhdr(attr_header_t
*ah
)
926 #if BYTE_ORDER == LITTLE_ENDIAN
931 count
= (ah
->magic
== ATTR_HDR_MAGIC
) ? ah
->num_attrs
: SWAP16(ah
->num_attrs
);
933 ah
->magic
= SWAP32 (ah
->magic
);
934 ah
->debug_tag
= SWAP32 (ah
->debug_tag
);
935 ah
->total_size
= SWAP32 (ah
->total_size
);
936 ah
->data_start
= SWAP32 (ah
->data_start
);
937 ah
->data_length
= SWAP32 (ah
->data_length
);
938 ah
->flags
= SWAP16 (ah
->flags
);
939 ah
->num_attrs
= SWAP16 (ah
->num_attrs
);
941 ae
= (attr_entry_t
*)(&ah
[1]);
942 for (i
= 0; i
< count
; i
++, ae
++)
944 ae
->offset
= SWAP32 (ae
->offset
);
945 ae
->length
= SWAP32 (ae
->length
);
946 ae
->flags
= SWAP16 (ae
->flags
);
951 static u_int32_t emptyfinfo
[8] = {0};
953 static int copyfile_unpack(copyfile_state_t s
)
957 apple_double_header_t
*adhdr
;
961 if (s
->sb
.st_size
< ATTR_MAX_HDR_SIZE
)
962 hdrsize
= s
->sb
.st_size
;
964 hdrsize
= ATTR_MAX_HDR_SIZE
;
966 buffer
= calloc(1, hdrsize
);
967 bytes
= pread(s
->src_fd
, buffer
, hdrsize
, 0);
971 copyfile_debug(1, "pread returned: %d", bytes
);
978 "pread couldn't read entire header: %d of %d",
979 (int)bytes
, (int)s
->sb
.st_size
);
983 adhdr
= (apple_double_header_t
*)buffer
;
986 * Check for Apple Double file.
988 if (bytes
< sizeof(apple_double_header_t
) - 2 ||
989 SWAP32(adhdr
->magic
) != ADH_MAGIC
||
990 SWAP32(adhdr
->version
) != ADH_VERSION
||
991 SWAP16(adhdr
->numEntries
) != 2 ||
992 SWAP32(adhdr
->entries
[0].type
) != AD_FINDERINFO
)
994 if (COPYFILE_VERBOSE
& s
->flags
)
995 copyfile_warn("Not a valid Apple Double header");
1002 * Extract the extended attributes.
1005 * This assumes that the data is already in memory (not
1006 * the case when there are lots of attributes or one of
1007 * the attributes is very large.
1009 if (adhdr
->entries
[0].length
> FINDERINFOSIZE
)
1011 attr_header_t
*attrhdr
;
1012 attr_entry_t
*entry
;
1016 attrhdr
= (attr_header_t
*)buffer
;
1017 swap_attrhdr(attrhdr
);
1018 if (attrhdr
->magic
!= ATTR_HDR_MAGIC
)
1020 if (COPYFILE_VERBOSE
& s
->flags
)
1021 copyfile_warn("bad attribute header");
1025 count
= attrhdr
->num_attrs
;
1026 entry
= (attr_entry_t
*)&attrhdr
[1];
1027 for (i
= 0; i
< count
; i
++)
1031 copyfile_debug(2, "extracting \"%s\" (%d bytes)",
1032 entry
->name
, entry
->length
);
1033 dataptr
= (char *)attrhdr
+ entry
->offset
;
1035 if (COPYFILE_ACL
& s
->flags
&& strncmp(entry
->name
, XATTR_SECURITY_NAME
, strlen(XATTR_SECURITY_NAME
)) == 0)
1038 if ((acl
= acl_from_text(dataptr
)) != NULL
)
1040 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
1043 if ((acl
= acl_from_text(dataptr
)) != NULL
)
1045 if (filesec_set_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
1047 copyfile_debug(1, "setting acl");
1049 else if (fchmodx_np(s
->dst_fd
, s
->fsec
) < 0 && errno
!= ENOTSUP
)
1050 copyfile_warn("setting security information");
1054 if (COPYFILE_XATTR
& s
->flags
&& (fsetxattr(s
->dst_fd
, entry
->name
, dataptr
, entry
->length
, 0, 0))) {
1055 if (COPYFILE_VERBOSE
& s
->flags
)
1056 copyfile_warn("error %d setting attribute %s", error
, entry
->name
);
1059 else if (fchmodx_np(s
->dst_fd
, s
->fsec
) < 0 && errno
!= ENOTSUP
)
1060 copyfile_warn("setting security information");
1064 if (COPYFILE_XATTR
& s
->flags
&& (fsetxattr(s
->dst_fd
, entry
->name
, dataptr
, entry
->length
, 0, 0))) {
1065 if (COPYFILE_VERBOSE
& s
->flags
)
1066 copyfile_warn("error %d setting attribute %s", error
, entry
->name
);
1069 entry
= ATTR_NEXT(entry
);
1074 * Extract the Finder Info.
1076 if (bcmp((u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, emptyfinfo
, sizeof(emptyfinfo
)) != 0)
1078 copyfile_debug(1, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME
);
1079 error
= fsetxattr(s
->dst_fd
, XATTR_FINDERINFO_NAME
, (u_int8_t
*)buffer
+ adhdr
->entries
[0].offset
, sizeof(emptyfinfo
), 0, 0);
1085 * Extract the Resource Fork.
1087 if (adhdr
->entries
[1].type
== AD_RESOURCE
&&
1088 adhdr
->entries
[1].length
> 0)
1090 void * rsrcforkdata
;
1094 length
= adhdr
->entries
[1].length
;
1095 offset
= adhdr
->entries
[1].offset
;
1096 rsrcforkdata
= malloc(length
);
1098 bytes
= pread(s
->src_fd
, rsrcforkdata
, length
, offset
);
1103 copyfile_debug(1, "couldn't read resource fork");
1108 "couldn't read resource fork (only read %d bytes of %d)",
1109 (int)bytes
, (int)length
);
1114 error
= fsetxattr(s
->dst_fd
, XATTR_RESOURCEFORK_NAME
, rsrcforkdata
, bytes
, 0, 0);
1117 copyfile_debug(1, "error %d setting resource fork attribute", error
);
1121 copyfile_debug(1, "extracting \"%s\" (%d bytes)",
1122 XATTR_RESOURCEFORK_NAME
, (int)length
);
1130 static int copyfile_pack_acl(copyfile_state_t s
, void **buf
, ssize_t
*len
)
1136 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &acl
) < 0)
1138 if (errno
!= ENOENT
)
1141 if (COPYFILE_VERBOSE
& s
->flags
)
1142 copyfile_warn("getting acl");
1147 if ((acl_text
= acl_to_text(acl
, len
)) != NULL
)
1149 *buf
= malloc(*len
);
1150 memcpy(*buf
, acl_text
, *len
);
1153 copyfile_debug(1, "copied acl (%ld) %p", *len
, *buf
);
1158 static int copyfile_pack_rsrcfork(copyfile_state_t s
, attr_header_t
*filehdr
)
1163 /* Get the resource fork size */
1164 if ((datasize
= fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, NULL
, 0, 0, 0)) < 0)
1166 if (COPYFILE_VERBOSE
& s
->flags
)
1167 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME
, errno
);
1171 if ((databuf
= malloc(datasize
)) == NULL
)
1173 copyfile_warn("malloc");
1177 if (fgetxattr(s
->src_fd
, XATTR_RESOURCEFORK_NAME
, databuf
, datasize
, 0, 0) != datasize
)
1179 if (COPYFILE_VERBOSE
& s
->flags
)
1180 copyfile_warn("couldn't read entire resource fork");
1184 /* Write the resource fork to disk. */
1185 if (pwrite(s
->dst_fd
, databuf
, datasize
, filehdr
->appledouble
.entries
[1].offset
) != datasize
)
1187 if (COPYFILE_VERBOSE
& s
->flags
)
1188 copyfile_warn("couldn't write resource fork");
1190 copyfile_debug(1, "copied %d bytes of \"%s\" data @ offset 0x%08x",
1191 datasize
, XATTR_RESOURCEFORK_NAME
, filehdr
->appledouble
.entries
[1].offset
);
1192 filehdr
->appledouble
.entries
[1].length
= datasize
;
1199 static int copyfile_pack(copyfile_state_t s
)
1203 attr_header_t
*filehdr
;
1204 attr_entry_t
*entry
;
1211 int hasrsrcfork
= 0;
1214 filehdr
= (attr_header_t
*) calloc(1, ATTR_MAX_SIZE
);
1215 attrnamebuf
= calloc(1, ATTR_MAX_HDR_SIZE
);
1218 * Fill in the Apple Double Header defaults.
1220 filehdr
->appledouble
.magic
= SWAP32 (ADH_MAGIC
);
1221 filehdr
->appledouble
.version
= SWAP32 (ADH_VERSION
);
1222 filehdr
->appledouble
.numEntries
= SWAP16 (2);
1223 filehdr
->appledouble
.entries
[0].type
= SWAP32 (AD_FINDERINFO
);
1224 filehdr
->appledouble
.entries
[0].offset
= SWAP32 (offsetof(apple_double_header_t
, finfo
));
1225 filehdr
->appledouble
.entries
[0].length
= SWAP32 (FINDERINFOSIZE
);
1226 filehdr
->appledouble
.entries
[1].type
= SWAP32 (AD_RESOURCE
);
1227 filehdr
->appledouble
.entries
[1].offset
= SWAP32 (offsetof(apple_double_header_t
, pad
));
1228 filehdr
->appledouble
.entries
[1].length
= 0;
1229 bcopy(ADH_MACOSX
, filehdr
->appledouble
.filler
, sizeof(filehdr
->appledouble
.filler
));
1232 * Fill in the initial Attribute Header.
1234 filehdr
->magic
= SWAP32 (ATTR_HDR_MAGIC
);
1235 filehdr
->debug_tag
= SWAP32 (s
->sb
.st_ino
);
1236 filehdr
->data_start
= SWAP32 (sizeof(attr_header_t
));
1239 * Collect the attribute names.
1241 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
1244 * Test if there are acls to copy
1246 if (COPYFILE_ACL
& s
->flags
)
1248 if (filesec_get_property(s
->fsec
, FILESEC_ACL
, &datasize
) < 0)
1250 copyfile_debug(1, "no acl entries found (%d)", datasize
< 0 ? errno
: 0);
1253 offset
= strlen(XATTR_SECURITY_NAME
) + 1;
1254 strcpy(attrnamebuf
, XATTR_SECURITY_NAME
);
1258 if (COPYFILE_XATTR
& s
->flags
)
1260 if ((listsize
= flistxattr(s
->src_fd
, attrnamebuf
+ offset
, ATTR_MAX_HDR_SIZE
, 0)) <= 0)
1262 copyfile_debug(1, "no extended attributes found (%d)", errno
);
1264 if (listsize
> ATTR_MAX_HDR_SIZE
)
1266 copyfile_debug(1, "extended attribute list too long");
1267 listsize
= ATTR_MAX_HDR_SIZE
;
1272 for (nameptr
= attrnamebuf
; nameptr
< attrnamebuf
+ listsize
; nameptr
+= namelen
)
1274 namelen
= strlen(nameptr
) + 1;
1275 /* Skip over FinderInfo or Resource Fork names */
1276 if (strncmp(nameptr
, XATTR_FINDERINFO_NAME
, strlen(XATTR_FINDERINFO_NAME
)) == 0 ||
1277 strncmp(nameptr
, XATTR_RESOURCEFORK_NAME
, strlen(XATTR_RESOURCEFORK_NAME
)) == 0)
1280 entry
->namelen
= namelen
;
1282 bcopy(nameptr
, &entry
->name
[0], namelen
);
1283 copyfile_debug(2, "copied name [%s]", entry
->name
);
1285 entrylen
= ATTR_ENTRY_LENGTH(namelen
);
1286 entry
= (attr_entry_t
*)(((char *)entry
) + entrylen
);
1288 /* Update the attributes header. */
1289 filehdr
->num_attrs
++;
1290 filehdr
->data_start
+= entrylen
;
1295 * Collect the attribute data.
1297 entry
= (attr_entry_t
*)((char *)filehdr
+ sizeof(attr_header_t
));
1299 for (nameptr
= attrnamebuf
; nameptr
< attrnamebuf
+ listsize
; nameptr
+= namelen
+ 1)
1302 namelen
= strlen(nameptr
);
1304 if (strncmp(nameptr
, XATTR_SECURITY_NAME
, strlen(XATTR_SECURITY_NAME
)) == 0)
1305 copyfile_pack_acl(s
, &databuf
, &datasize
);
1307 /* Check for Finder Info. */
1308 if (strncmp(nameptr
, XATTR_FINDERINFO_NAME
, strlen(XATTR_FINDERINFO_NAME
)) == 0)
1310 datasize
= fgetxattr(s
->src_fd
, nameptr
, (u_int8_t
*)filehdr
+ filehdr
->appledouble
.entries
[0].offset
, 32, 0, 0);
1313 if (COPYFILE_VERBOSE
& s
->flags
)
1314 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
1315 } else if (datasize
!= 32)
1317 if (COPYFILE_VERBOSE
& s
->flags
)
1318 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize
, nameptr
);
1321 if (COPYFILE_VERBOSE
& s
->flags
)
1322 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
1323 XATTR_FINDERINFO_NAME
, filehdr
->appledouble
.entries
[0].offset
);
1325 continue; /* finder info doesn't have an attribute entry */
1327 /* Check for Resource Fork. */
1328 if (strncmp(nameptr
, XATTR_RESOURCEFORK_NAME
, strlen(XATTR_RESOURCEFORK_NAME
)) == 0)
1334 /* Just a normal attribute. */
1335 datasize
= fgetxattr(s
->src_fd
, nameptr
, NULL
, 0, 0, 0);
1340 if (COPYFILE_VERBOSE
& s
->flags
)
1341 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr
, errno
);
1344 if (datasize
> XATTR_MAXATTRLEN
)
1346 if (COPYFILE_VERBOSE
& s
->flags
)
1347 copyfile_warn("skipping attr \"%s\" (too big)", nameptr
);
1350 databuf
= malloc(datasize
);
1351 datasize
= fgetxattr(s
->src_fd
, nameptr
, databuf
, datasize
, 0, 0);
1354 entry
->length
= datasize
;
1355 entry
->offset
= filehdr
->data_start
+ filehdr
->data_length
;
1357 filehdr
->data_length
+= datasize
;
1360 * This assumes that the data is fits in memory (not
1361 * the case when there are lots of attributes or one of
1362 * the attributes is very large.
1364 bcopy(databuf
, (char*)filehdr
+ entry
->offset
, datasize
);
1367 copyfile_debug(1, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize
, nameptr
, entry
->offset
);
1369 /* bump to next entry */
1370 entrylen
= ATTR_ENTRY_LENGTH(entry
->namelen
);
1371 entry
= (attr_entry_t
*)((char *)entry
+ entrylen
);
1374 if (filehdr
->data_length
> 0)
1376 /* Now we know where the resource fork data starts. */
1377 filehdr
->appledouble
.entries
[1].offset
= (filehdr
->data_start
+ filehdr
->data_length
);
1379 /* We also know the size of the "Finder Info entry. */
1380 filehdr
->appledouble
.entries
[0].length
=
1381 filehdr
->appledouble
.entries
[1].offset
- filehdr
->appledouble
.entries
[0].offset
;
1383 filehdr
->total_size
= SWAP32 (filehdr
->appledouble
.entries
[1].offset
);
1386 /* Copy Resource Fork. */
1387 if (hasrsrcfork
&& (error
= copyfile_pack_rsrcfork(s
, filehdr
)))
1390 /* Write the header to disk. */
1391 datasize
= filehdr
->appledouble
.entries
[1].offset
;
1393 if (pwrite(s
->dst_fd
, filehdr
, datasize
, 0) != datasize
)
1395 if (COPYFILE_VERBOSE
& s
->flags
)
1396 copyfile_warn("couldn't write file header");
1407 return copyfile_stat(s
);