]> git.saurik.com Git - apple/copyfile.git/blob - copyfile.c
copyfile-127.tar.gz
[apple/copyfile.git] / copyfile.c
1 /*
2 * Copyright (c) 2004-2010 Apple, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <err.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #include <sys/acl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdint.h>
32 #include <syslog.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <sys/errno.h>
36 #include <sys/stat.h>
37 #include <sys/time.h>
38 #include <sys/xattr.h>
39 #include <sys/attr.h>
40 #include <sys/syscall.h>
41 #include <sys/param.h>
42 #include <sys/mount.h>
43 #include <sys/acl.h>
44 #include <libkern/OSByteOrder.h>
45 #include <membership.h>
46 #include <fts.h>
47 #include <libgen.h>
48
49 #include <System/sys/content_protection.h>
50
51 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
52 # include <Kernel/sys/decmpfs.h>
53 #endif
54
55 #include <TargetConditionals.h>
56 #if !TARGET_OS_IPHONE
57 #include <quarantine.h>
58
59 #define XATTR_QUARANTINE_NAME qtn_xattr_name
60 #else /* TARGET_OS_IPHONE */
61 #define qtn_file_t void *
62 #define QTN_SERIALIZED_DATA_MAX 0
63 static void * qtn_file_alloc(void) { return NULL; }
64 static int qtn_file_init_with_fd(void *x, int y) { return -1; }
65 static int qtn_file_init_with_path(void *x, const char *path) { return -1; }
66 static int qtn_file_init_with_data(void *x, const void *data, size_t len) { return -1; }
67 static void qtn_file_free(void *x) { return; }
68 static int qtn_file_apply_to_fd(void *x, int y) { return 0; }
69 static char *qtn_error(int x) { return NULL; }
70 static int qtn_file_to_data(void *x, char *y, size_t z) { return -1; }
71 static void *qtn_file_clone(void *x) { return NULL; }
72 #define XATTR_QUARANTINE_NAME "figgledidiggledy"
73 #endif /* TARGET_OS_IPHONE */
74
75 #include "copyfile.h"
76 #include "copyfile_private.h"
77 #include "xattr_flags.h"
78
79 enum cfInternalFlags {
80 cfDelayAce = 1 << 0, /* set if ACE shouldn't be set until post-order traversal */
81 cfMakeFileInvisible = 1 << 1, /* set if kFinderInvisibleMask is on src */
82 cfSawDecmpEA = 1 << 2, /* set if we've seen a com.apple.decmpfs xattr */
83 cfSrcProtSupportValid = 1 << 3, /* set if cfSrcSupportsCProtect is valid */
84 cfSrcSupportsCProtect = 1 << 4, /* set if src supports MNT_CPROTECT */
85 cfDstProtSupportValid = 1 << 5, /* set if cfDstSupportsCProtect is valid */
86 cfDstSupportsCProtect = 1 << 6, /* set if dst supports MNT_CPROTECT */
87 };
88
89 #define COPYFILE_MNT_CPROTECT_MASK (cfSrcProtSupportValid | cfSrcSupportsCProtect | cfDstProtSupportValid | cfDstSupportsCProtect)
90
91 /*
92 * The state structure keeps track of
93 * the source filename, the destination filename, their
94 * associated file-descriptors, the stat infomration for the
95 * source file, the security information for the source file,
96 * the flags passed in for the copy, a pointer to place statistics
97 * (not currently implemented), debug flags, and a pointer to callbacks
98 * (not currently implemented).
99 */
100 struct _copyfile_state
101 {
102 char *src;
103 char *dst;
104 int src_fd;
105 int dst_fd;
106 struct stat sb;
107 filesec_t fsec;
108 copyfile_flags_t flags;
109 unsigned int internal_flags;
110 void *stats;
111 uint32_t debug;
112 copyfile_callback_t statuscb;
113 void *ctx;
114 qtn_file_t qinfo; /* Quarantine information -- probably NULL */
115 filesec_t original_fsec;
116 filesec_t permissive_fsec;
117 off_t totalCopied;
118 int err;
119 char *xattr_name;
120 xattr_operation_intent_t copyIntent;
121 };
122
123 #define GET_PROT_CLASS(fd) fcntl((fd), F_GETPROTECTIONCLASS)
124 #define SET_PROT_CLASS(fd, prot_class) fcntl((fd), F_SETPROTECTIONCLASS, (prot_class))
125
126 struct acl_entry {
127 u_int32_t ae_magic;
128 #define _ACL_ENTRY_MAGIC 0xac1ac101
129 u_int32_t ae_tag;
130 guid_t ae_applicable;
131 u_int32_t ae_flags;
132 u_int32_t ae_perms;
133 };
134
135 #define PACE(ace) do { \
136 struct acl_entry *__t = (struct acl_entry*)(ace); \
137 fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
138 } while (0)
139
140 #define PACL(ace) \
141 do { \
142 ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
143 fprintf(stderr, "%s(%d): " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
144 } while (0)
145
146 static int
147 acl_compare_permset_np(acl_permset_t p1, acl_permset_t p2)
148 {
149 struct pm { u_int32_t ap_perms; } *ps1, *ps2;
150 ps1 = (struct pm*) p1;
151 ps2 = (struct pm*) p2;
152
153 return ((ps1->ap_perms == ps2->ap_perms) ? 1 : 0);
154 }
155
156
157 static int
158 doesdecmpfs(int fd) {
159 #ifdef DECMPFS_XATTR_NAME
160 int rv;
161 struct attrlist attrs;
162 char volroot[MAXPATHLEN + 1];
163 struct statfs sfs;
164 struct {
165 uint32_t length;
166 vol_capabilities_attr_t volAttrs;
167 } volattrs;
168
169 (void)fstatfs(fd, &sfs);
170 strlcpy(volroot, sfs.f_mntonname, sizeof(volroot));
171
172 memset(&attrs, 0, sizeof(attrs));
173 attrs.bitmapcount = ATTR_BIT_MAP_COUNT;
174 attrs.volattr = ATTR_VOL_CAPABILITIES;
175
176 rv = getattrlist(volroot, &attrs, &volattrs, sizeof(volattrs), 0);
177
178 if (rv != -1 &&
179 (volattrs.volAttrs.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION) &&
180 (volattrs.volAttrs.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_DECMPFS_COMPRESSION)) {
181 return 1;
182 }
183 #endif
184 return 0;
185 }
186
187 static int
188 does_copy_protection(int fd)
189 {
190 struct statfs sfs;
191
192 if (fstatfs(fd, &sfs) == -1)
193 return -1;
194
195 return ((sfs.f_flags & MNT_CPROTECT) == MNT_CPROTECT);
196 }
197
198 static void
199 sort_xattrname_list(void *start, size_t length)
200 {
201 char **ptrs = NULL;
202 int nel;
203 char *tmp;
204 int indx = 0;
205
206 /* If it's not a proper C string at the end, don't do anything */
207 if (((char*)start)[length] != 0)
208 return;
209 /*
210 * In order to sort the list of names, we need to
211 * make a list of pointers to strings. To do that,
212 * we need to run through the buffer, and find the
213 * beginnings of strings.
214 */
215 nel = 10; // Most files don't have many EAs
216 ptrs = (char**)calloc(nel, sizeof(char*));
217
218 if (ptrs == NULL)
219 goto done;
220
221 #ifdef DEBUG
222 {
223 char *curPtr = start;
224 while (curPtr < (char*)start + length) {
225 printf("%s\n", curPtr);
226 curPtr += strlen(curPtr) + 1;
227 }
228 }
229 #endif
230
231 tmp = ptrs[indx++] = (char*)start;
232
233 while (tmp = memchr(tmp, 0, ((char*)start + length) - tmp)) {
234 if (indx == nel) {
235 nel += 10;
236 ptrs = realloc(ptrs, sizeof(char**) * nel);
237 if (ptrs == NULL)
238 goto done;
239 }
240 ptrs[indx++] = ++tmp;
241 }
242 #ifdef DEBUG
243 printf("Unsorted:\n");
244 for (nel = 0; nel < indx-1; nel++) {
245 printf("\tEA %d = `%s'\n", nel, ptrs[nel]);
246 }
247 #endif
248 qsort_b(ptrs, indx-1, sizeof(char*), ^(const void *left, const void *right) {
249 int rv;
250 char *lstr = *(char**)left, *rstr = *(char**)right;
251 rv = strcmp(lstr, rstr);
252 return rv;
253 });
254 #ifdef DEBUG
255 printf("Sorted:\n");
256 for (nel = 0; nel < indx-1; nel++) {
257 printf("\tEA %d = `%s'\n", nel, ptrs[nel]);
258 }
259 #endif
260 /*
261 * Now that it's sorted, we need to make a copy, so we can
262 * move the strings around into the new order. Then we
263 * copy that on top of the old buffer, and we're done.
264 */
265 char *copy = malloc(length);
266 if (copy) {
267 int i;
268 char *curPtr = copy;
269
270 for (i = 0; i < indx-1; i++) {
271 size_t len = strlen(ptrs[i]);
272 memcpy(curPtr, ptrs[i], len+1);
273 curPtr += len+1;
274 }
275 memcpy(start, copy, length);
276 free(copy);
277 }
278
279 done:
280 if (ptrs)
281 free(ptrs);
282 return;
283 }
284
285 /*
286 * Internally, the process is broken into a series of
287 * private functions.
288 */
289 static int copyfile_open (copyfile_state_t);
290 static int copyfile_close (copyfile_state_t);
291 static int copyfile_data (copyfile_state_t);
292 static int copyfile_stat (copyfile_state_t);
293 static int copyfile_security (copyfile_state_t);
294 static int copyfile_xattr (copyfile_state_t);
295 static int copyfile_pack (copyfile_state_t);
296 static int copyfile_unpack (copyfile_state_t);
297
298 static copyfile_flags_t copyfile_check (copyfile_state_t);
299 static filesec_t copyfile_fix_perms(copyfile_state_t, filesec_t *);
300 static int copyfile_preamble(copyfile_state_t *s, copyfile_flags_t flags);
301 static int copyfile_internal(copyfile_state_t state, copyfile_flags_t flags);
302 static int copyfile_unset_posix_fsec(filesec_t);
303 static int copyfile_quarantine(copyfile_state_t);
304
305 #define COPYFILE_DEBUG (1<<31)
306 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
307
308 #ifndef _COPYFILE_TEST
309 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
310 # define copyfile_debug(d, str, ...) \
311 do { \
312 if (s && (d <= s->debug)) {\
313 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
314 } \
315 } while (0)
316 #else
317 #define copyfile_warn(str, ...) \
318 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
319 # define copyfile_debug(d, str, ...) \
320 do { \
321 if (s && (d <= s->debug)) {\
322 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
323 } \
324 } while(0)
325 #endif
326
327 static int copyfile_quarantine(copyfile_state_t s)
328 {
329 int rv = 0;
330 if (s->qinfo == NULL)
331 {
332 int error;
333 s->qinfo = qtn_file_alloc();
334 if (s->qinfo == NULL)
335 {
336 rv = -1;
337 goto done;
338 }
339 if ((error = qtn_file_init_with_fd(s->qinfo, s->src_fd)) != 0)
340 {
341 qtn_file_free(s->qinfo);
342 s->qinfo = NULL;
343 rv = -1;
344 goto done;
345 }
346 }
347 done:
348 return rv;
349 }
350
351 static int
352 add_uberace(acl_t *acl)
353 {
354 acl_entry_t entry;
355 acl_permset_t permset;
356 uuid_t qual;
357
358 if (mbr_uid_to_uuid(getuid(), qual) != 0)
359 goto error_exit;
360
361 /*
362 * First, we create an entry, and give it the special name
363 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
364 * After that, we clear out all the permissions in it, and
365 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
366 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
367 * the functionality, and put this into the ACL.
368 */
369 if (acl_create_entry_np(acl, &entry, ACL_FIRST_ENTRY) == -1)
370 goto error_exit;
371 if (acl_get_permset(entry, &permset) == -1) {
372 copyfile_warn("acl_get_permset");
373 goto error_exit;
374 }
375 if (acl_clear_perms(permset) == -1) {
376 copyfile_warn("acl_clear_permset");
377 goto error_exit;
378 }
379 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1) {
380 copyfile_warn("add ACL_WRITE_DATA");
381 goto error_exit;
382 }
383 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1) {
384 copyfile_warn("add ACL_WRITE_ATTRIBUTES");
385 goto error_exit;
386 }
387 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1) {
388 copyfile_warn("add ACL_WRITE_EXTATTRIBUTES");
389 goto error_exit;
390 }
391 if (acl_add_perm(permset, ACL_APPEND_DATA) == -1) {
392 copyfile_warn("add ACL_APPEND_DATA");
393 goto error_exit;
394 }
395 if (acl_add_perm(permset, ACL_WRITE_SECURITY) == -1) {
396 copyfile_warn("add ACL_WRITE_SECURITY");
397 goto error_exit;
398 }
399 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1) {
400 copyfile_warn("set ACL_EXTENDED_ALLOW");
401 goto error_exit;
402 }
403
404 if(acl_set_permset(entry, permset) == -1) {
405 copyfile_warn("acl_set_permset");
406 goto error_exit;
407 }
408 if(acl_set_qualifier(entry, qual) == -1) {
409 copyfile_warn("acl_set_qualifier");
410 goto error_exit;
411 }
412
413 return 0;
414 error_exit:
415 return -1;
416 }
417
418 static int
419 is_uberace(acl_entry_t ace)
420 {
421 int retval = 0;
422 acl_permset_t perms, tperms;
423 acl_t tacl;
424 acl_entry_t tentry;
425 acl_tag_t tag;
426 guid_t *qual = NULL;
427 uuid_t myuuid;
428
429 // Who am I, and who is the ACE for?
430 mbr_uid_to_uuid(geteuid(), myuuid);
431 qual = (guid_t*)acl_get_qualifier(ace);
432
433 // Need to create a temporary acl, so I can get the uberace template.
434 tacl = acl_init(1);
435 if (tacl == NULL) {
436 goto done;
437 }
438 add_uberace(&tacl);
439 if (acl_get_entry(tacl, ACL_FIRST_ENTRY, &tentry) != 0) {
440 goto done;
441 }
442 acl_get_permset(tentry, &tperms);
443
444 // Now I need to get
445 acl_get_tag_type(ace, &tag);
446 acl_get_permset(ace, &perms);
447
448 if (tag == ACL_EXTENDED_ALLOW &&
449 (memcmp(qual, myuuid, sizeof(myuuid)) == 0) &&
450 acl_compare_permset_np(tperms, perms))
451 retval = 1;
452
453 done:
454
455 if (qual)
456 acl_free(qual);
457
458 if (tacl)
459 acl_free(tacl);
460
461 return retval;
462 }
463
464 static void
465 remove_uberace(int fd, struct stat *sbuf)
466 {
467 filesec_t fsec = NULL;
468 acl_t acl = NULL;
469 acl_entry_t entry;
470 struct stat sb;
471
472 fsec = filesec_init();
473 if (fsec == NULL) {
474 goto noacl;
475 }
476
477 if (fstatx_np(fd, &sb, fsec) != 0) {
478 if (errno == ENOTSUP)
479 goto noacl;
480 goto done;
481 }
482
483 if (filesec_get_property(fsec, FILESEC_ACL, &acl) != 0) {
484 goto done;
485 }
486
487 if (acl_get_entry(acl, ACL_FIRST_ENTRY, &entry) == 0) {
488 if (is_uberace(entry))
489 {
490 mode_t m = sbuf->st_mode & ~S_IFMT;
491
492 if (acl_delete_entry(acl, entry) != 0 ||
493 filesec_set_property(fsec, FILESEC_ACL, &acl) != 0 ||
494 filesec_set_property(fsec, FILESEC_MODE, &m) != 0 ||
495 fchmodx_np(fd, fsec) != 0)
496 goto noacl;
497 }
498 }
499
500 done:
501 if (acl)
502 acl_free(acl);
503 if (fsec)
504 filesec_free(fsec);
505 return;
506
507 noacl:
508 fchmod(fd, sbuf->st_mode & ~S_IFMT);
509 goto done;
510 }
511
512 static void
513 reset_security(copyfile_state_t s)
514 {
515 /* If we haven't reset the file security information
516 * (COPYFILE_SECURITY is not set in flags)
517 * restore back the permissions the file had originally
518 *
519 * One of the reasons this seems so complicated is that
520 * it is partially at odds with copyfile_security().
521 *
522 * Simplisticly, we are simply trying to make sure we
523 * only copy what was requested, and that we don't stomp
524 * on what wasn't requested.
525 */
526
527 #ifdef COPYFILE_RECURSIVE
528 if (s->dst_fd > -1) {
529 struct stat sbuf;
530
531 if (s->src_fd > -1 && (s->flags & COPYFILE_STAT))
532 fstat(s->src_fd, &sbuf);
533 else
534 fstat(s->dst_fd, &sbuf);
535
536 if (!(s->internal_flags & cfDelayAce))
537 remove_uberace(s->dst_fd, &sbuf);
538 }
539 #else
540 if (s->permissive_fsec && (s->flags & COPYFILE_SECURITY) != COPYFILE_SECURITY) {
541 if (s->flags & COPYFILE_ACL) {
542 /* Just need to reset the BSD information -- mode, owner, group */
543 (void)fchown(s->dst_fd, s->dst_sb.st_uid, s->dst_sb.st_gid);
544 (void)fchmod(s->dst_fd, s->dst_sb.st_mode);
545 } else {
546 /*
547 * flags is either COPYFILE_STAT, or neither; if it's
548 * neither, then we restore both ACL and POSIX permissions;
549 * if it's STAT, however, then we only want to restore the
550 * ACL (which may be empty). We do that by removing the
551 * POSIX information from the filesec object.
552 */
553 if (s->flags & COPYFILE_STAT) {
554 copyfile_unset_posix_fsec(s->original_fsec);
555 }
556 if (fchmodx_np(s->dst_fd, s->original_fsec) < 0 && errno != ENOTSUP)
557 copyfile_warn("restoring security information");
558 }
559 }
560
561 if (s->permissive_fsec) {
562 filesec_free(s->permissive_fsec);
563 s->permissive_fsec = NULL;
564 }
565
566 if (s->original_fsec) {
567 filesec_free(s->original_fsec);
568 s->original_fsec = NULL;
569 }
570 #endif
571
572 return;
573 }
574
575 /*
576 * copytree -- recursively copy a hierarchy.
577 *
578 * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
579 * Care is taken to keep the ACLs set up correctly, in addition to the
580 * normal copying that is done. (When copying a hierarchy, we can't
581 * get rid of the "allow-all-writes" ACE on a directory until we're done
582 * copying the *contents* of the directory.)
583 *
584 * The other big difference from copyfile (for the moment) is that copytree()
585 * will use a call-back function to pass along information about what is
586 * about to be copied, and whether or not it succeeded.
587 *
588 * copytree() is called from copyfile() -- but copytree() itself then calls
589 * copyfile() to copy each individual object.
590 *
591 * XXX - no effort is made to handle overlapping hierarchies at the moment.
592 *
593 */
594
595 static int
596 copytree(copyfile_state_t s)
597 {
598 char *slash;
599 int retval = 0;
600 int (*sfunc)(const char *, struct stat *);
601 copyfile_callback_t status = NULL;
602 char srcisdir = 0, dstisdir = 0, dstexists = 0;
603 struct stat sbuf;
604 char *src, *dst;
605 const char *dstpathsep = "";
606 #ifdef NOTYET
607 char srcpath[PATH_MAX * 2 + 1], dstpath[PATH_MAX * 2 + 1];
608 #endif
609 char *srcroot;
610 FTS *fts = NULL;
611 FTSENT *ftsent;
612 ssize_t offset = 0;
613 const char *paths[2] = { 0 };
614 unsigned int flags = 0;
615 int fts_flags = FTS_NOCHDIR;
616 dev_t last_dev = s->sb.st_dev;
617
618 if (s == NULL) {
619 errno = EINVAL;
620 retval = -1;
621 goto done;
622 }
623 if (s->flags & (COPYFILE_MOVE | COPYFILE_UNLINK | COPYFILE_CHECK | COPYFILE_PACK | COPYFILE_UNPACK)) {
624 errno = EINVAL;
625 retval = -1;
626 goto done;
627 }
628
629 flags = s->flags & (COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_VERBOSE | COPYFILE_EXCL);
630
631 paths[0] = src = s->src;
632 dst = s->dst;
633
634 if (src == NULL || dst == NULL) {
635 errno = EINVAL;
636 retval = -1;
637 goto done;
638 }
639
640 sfunc = (flags & COPYFILE_NOFOLLOW_SRC) ? lstat : stat;
641 if ((sfunc)(src, &sbuf) == -1) {
642 retval = -1;
643 goto done;
644 }
645 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
646 srcisdir = 1;
647 }
648
649 sfunc = (flags & COPYFILE_NOFOLLOW_DST) ? lstat : stat;
650 if ((sfunc)(dst, &sbuf) == -1) {
651 if (errno != ENOENT) {
652 retval = -1;
653 goto done;
654 }
655 } else {
656 dstexists = 1;
657 if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
658 dstisdir = 1;
659 }
660 }
661
662 #ifdef NOTYET
663 // This doesn't handle filesystem crossing and case sensitivity
664 // So there's got to be a better way
665
666 if (realpath(src, srcpath) == NULL) {
667 retval = -1;
668 goto done;
669 }
670
671 if (realpath(dst, dstpath) == NULL &&
672 (errno == ENOENT && realpath(dirname(dst), dstpath) == NULL)) {
673 retval = -1;
674 goto done;
675 }
676 if (strstr(srcpath, dstpath) != NULL) {
677 errno = EINVAL;
678 retval = -1;
679 goto done;
680 }
681 #endif
682 srcroot = basename((char*)src);
683 if (srcroot == NULL) {
684 retval = -1;
685 goto done;
686 }
687
688 /*
689 * To work on as well:
690 * We have a few cases when copying a hierarchy:
691 * 1) src is a non-directory, dst is a directory;
692 * 2) src is a non-directory, dst is a non-directory;
693 * 3) src is a non-directory, dst does not exist;
694 * 4) src is a directory, dst is a directory;
695 * 5) src is a directory, dst is a non-directory;
696 * 6) src is a directory, dst does not exist
697 *
698 * (1) copies src to dst/basename(src).
699 * (2) fails if COPYFILE_EXCL is set, otherwise copies src to dst.
700 * (3) and (6) copy src to the name dst.
701 * (4) copies the contents of src to the contents of dst.
702 * (5) is an error.
703 */
704
705 if (dstisdir) {
706 // copy /path/to/src to /path/to/dst/src
707 // Append "/" and (fts_path - strlen(basename(src))) to dst?
708 dstpathsep = "/";
709 slash = strrchr(src, '/');
710 if (slash == NULL)
711 offset = 0;
712 else
713 offset = slash - src + 1;
714 } else {
715 // copy /path/to/src to /path/to/dst
716 // append (fts_path + strlen(src)) to dst?
717 dstpathsep = "";
718 offset = strlen(src);
719 }
720
721 if (s->flags | COPYFILE_NOFOLLOW_SRC)
722 fts_flags |= FTS_PHYSICAL;
723 else
724 fts_flags |= FTS_LOGICAL;
725
726 fts = fts_open((char * const *)paths, fts_flags, NULL);
727
728 status = s->statuscb;
729 while ((ftsent = fts_read(fts)) != NULL) {
730 int rv = 0;
731 char *dstfile = NULL;
732 int cmd = 0;
733 copyfile_state_t tstate = copyfile_state_alloc();
734 if (tstate == NULL) {
735 errno = ENOMEM;
736 retval = -1;
737 break;
738 }
739 tstate->statuscb = s->statuscb;
740 tstate->ctx = s->ctx;
741 if (last_dev == ftsent->fts_dev) {
742 tstate->internal_flags |= (s->internal_flags & COPYFILE_MNT_CPROTECT_MASK);
743 } else {
744 last_dev = ftsent->fts_dev;
745 }
746 asprintf(&dstfile, "%s%s%s", dst, dstpathsep, ftsent->fts_path + offset);
747 if (dstfile == NULL) {
748 copyfile_state_free(tstate);
749 errno = ENOMEM;
750 retval = -1;
751 break;
752 }
753 switch (ftsent->fts_info) {
754 case FTS_D:
755 tstate->internal_flags |= cfDelayAce;
756 cmd = COPYFILE_RECURSE_DIR;
757 break;
758 case FTS_SL:
759 case FTS_SLNONE:
760 case FTS_DEFAULT:
761 case FTS_F:
762 cmd = COPYFILE_RECURSE_FILE;
763 break;
764 case FTS_DP:
765 cmd = COPYFILE_RECURSE_DIR_CLEANUP;
766 break;
767 case FTS_DNR:
768 case FTS_ERR:
769 case FTS_NS:
770 case FTS_NSOK:
771 default:
772 errno = ftsent->fts_errno;
773 if (status) {
774 rv = (*status)(COPYFILE_RECURSE_ERROR, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
775 if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) {
776 errno = 0;
777 goto skipit;
778 }
779 if (rv == COPYFILE_QUIT) {
780 retval = -1;
781 goto stopit;
782 }
783 } else {
784 retval = -1;
785 goto stopit;
786 }
787 case FTS_DOT:
788 goto skipit;
789
790 }
791
792 if (cmd == COPYFILE_RECURSE_DIR || cmd == COPYFILE_RECURSE_FILE) {
793 if (status) {
794 rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx);
795 if (rv == COPYFILE_SKIP) {
796 if (cmd == COPYFILE_RECURSE_DIR) {
797 rv = fts_set(fts, ftsent, FTS_SKIP);
798 if (rv == -1) {
799 rv = (*status)(0, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
800 if (rv == COPYFILE_QUIT)
801 retval = -1;
802 }
803 }
804 goto skipit;
805 }
806 if (rv == COPYFILE_QUIT) {
807 retval = -1; errno = 0;
808 goto stopit;
809 }
810 }
811 int tmp_flags = (cmd == COPYFILE_RECURSE_DIR) ? (flags & ~COPYFILE_STAT) : flags;
812 rv = copyfile(ftsent->fts_path, dstfile, tstate, tmp_flags);
813 if (rv < 0) {
814 if (status) {
815 rv = (*status)(cmd, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
816 if (rv == COPYFILE_QUIT) {
817 retval = -1;
818 goto stopit;
819 } else
820 rv = 0;
821 goto skipit;
822 } else {
823 retval = -1;
824 goto stopit;
825 }
826 }
827 if (status) {
828 rv = (*status)(cmd, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx);
829 if (rv == COPYFILE_QUIT) {
830 retval = -1; errno = 0;
831 goto stopit;
832 }
833 }
834 } else if (cmd == COPYFILE_RECURSE_DIR_CLEANUP) {
835 if (status) {
836 rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx);
837 if (rv == COPYFILE_QUIT) {
838 retval = -1; errno = 0;
839 goto stopit;
840 } else if (rv == COPYFILE_SKIP) {
841 rv = 0;
842 goto skipit;
843 }
844 }
845 rv = copyfile(ftsent->fts_path, dstfile, tstate, (flags & COPYFILE_NOFOLLOW) | COPYFILE_STAT);
846 if (rv < 0) {
847 if (status) {
848 rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
849 if (rv == COPYFILE_QUIT) {
850 retval = -1;
851 goto stopit;
852 } else if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) {
853 if (rv == COPYFILE_CONTINUE)
854 errno = 0;
855 retval = 0;
856 goto skipit;
857 }
858 } else {
859 retval = -1;
860 goto stopit;
861 }
862 } else {
863 if (status) {
864 rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx);
865 if (rv == COPYFILE_QUIT) {
866 retval = -1; errno = 0;
867 goto stopit;
868 }
869 }
870 }
871
872 rv = 0;
873 }
874 skipit:
875 stopit:
876 s->internal_flags &= ~COPYFILE_MNT_CPROTECT_MASK;
877 s->internal_flags |= (tstate->internal_flags & COPYFILE_MNT_CPROTECT_MASK);
878
879 copyfile_state_free(tstate);
880 free(dstfile);
881 if (retval == -1)
882 break;
883 }
884
885 done:
886 if (fts)
887 fts_close(fts);
888
889 return retval;
890 }
891
892 /*
893 * fcopyfile() is used to copy a source file descriptor to a destination file
894 * descriptor. This allows an application to figure out how it wants to open
895 * the files (doing various security checks, perhaps), and then just pass in
896 * the file descriptors.
897 */
898 int fcopyfile(int src_fd, int dst_fd, copyfile_state_t state, copyfile_flags_t flags)
899 {
900 int ret = 0;
901 copyfile_state_t s = state;
902 struct stat dst_sb;
903
904 if (src_fd < 0 || dst_fd < 0)
905 {
906 errno = EINVAL;
907 return -1;
908 }
909
910 if (copyfile_preamble(&s, flags) < 0)
911 return -1;
912
913 copyfile_debug(2, "set src_fd <- %d", src_fd);
914 if (s->src_fd == -2 && src_fd > -1)
915 {
916 s->src_fd = src_fd;
917 if (fstatx_np(s->src_fd, &s->sb, s->fsec) != 0)
918 {
919 if (errno == ENOTSUP || errno == EPERM)
920 fstat(s->src_fd, &s->sb);
921 else
922 {
923 copyfile_warn("fstatx_np on src fd %d", s->src_fd);
924 return -1;
925 }
926 }
927 }
928
929 /* prevent copying on unsupported types */
930 switch (s->sb.st_mode & S_IFMT)
931 {
932 case S_IFLNK:
933 case S_IFDIR:
934 case S_IFREG:
935 break;
936 default:
937 errno = ENOTSUP;
938 return -1;
939 }
940
941 copyfile_debug(2, "set dst_fd <- %d", dst_fd);
942 if (s->dst_fd == -2 && dst_fd > -1)
943 s->dst_fd = dst_fd;
944
945 (void)fstat(s->dst_fd, &dst_sb);
946 (void)fchmod(s->dst_fd, (dst_sb.st_mode & ~S_IFMT) | (S_IRUSR | S_IWUSR));
947
948 (void)copyfile_quarantine(s);
949
950 ret = copyfile_internal(s, flags);
951
952 if (ret >= 0 && !(s->flags & COPYFILE_STAT))
953 {
954 (void)fchmod(s->dst_fd, dst_sb.st_mode & ~S_IFMT);
955 }
956
957 if (s->err) {
958 errno = s->err;
959 s->err = 0;
960 }
961 if (state == NULL) {
962 int t = errno;
963 copyfile_state_free(s);
964 errno = t;
965 }
966
967 return ret;
968
969 }
970
971 /*
972 * the original copyfile() routine; this copies a source file to a destination
973 * file. Note that because we need to set the names in the state variable, this
974 * is not just the same as opening the two files, and then calling fcopyfile().
975 * Oh, if only life were that simple!
976 */
977 int copyfile(const char *src, const char *dst, copyfile_state_t state, copyfile_flags_t flags)
978 {
979 int ret = 0;
980 int createdst = 0;
981 copyfile_state_t s = state;
982 struct stat dst_sb;
983
984 if (src == NULL && dst == NULL)
985 {
986 errno = EINVAL;
987 return -1;
988 }
989
990 if (copyfile_preamble(&s, flags) < 0)
991 {
992 return -1;
993 }
994
995 /*
996 * This macro is... well, it's not the worst thing you can do with cpp, not
997 * by a long shot. Essentially, we are setting the filename (src or dst)
998 * in the state structure; since the structure may not have been cleared out
999 * before being used again, we do some of the cleanup here: if the given
1000 * filename (e.g., src) is set, and state->src is not equal to that, then
1001 * we need to check to see if the file descriptor had been opened, and if so,
1002 * close it. After that, we set state->src to be a copy of the given filename,
1003 * releasing the old copy if necessary.
1004 */
1005 #define COPYFILE_SET_FNAME(NAME, S) \
1006 do { \
1007 if (NAME != NULL) { \
1008 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
1009 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
1010 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
1011 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
1012 close(S->NAME##_fd); \
1013 S->NAME##_fd = -2; \
1014 } \
1015 } \
1016 if (S->NAME) { \
1017 free(S->NAME); \
1018 S->NAME = NULL; \
1019 } \
1020 if ((NAME) && (S->NAME = strdup(NAME)) == NULL) \
1021 return -1; \
1022 } \
1023 } while (0)
1024
1025 COPYFILE_SET_FNAME(src, s);
1026 COPYFILE_SET_FNAME(dst, s);
1027
1028 if (s->flags & COPYFILE_RECURSIVE) {
1029 ret = copytree(s);
1030 goto exit;
1031 }
1032
1033 /*
1034 * Get a copy of the source file's security settings
1035 */
1036 if (s->original_fsec) {
1037 filesec_free(s->original_fsec);
1038 s->original_fsec = NULL;
1039 }
1040 if ((s->original_fsec = filesec_init()) == NULL)
1041 goto error_exit;
1042
1043 if ((s->flags & COPYFILE_NOFOLLOW_DST) && lstat(s->dst, &dst_sb) == 0 &&
1044 ((dst_sb.st_mode & S_IFMT) == S_IFLNK)) {
1045 if (s->permissive_fsec)
1046 free(s->permissive_fsec);
1047 s->permissive_fsec = NULL;
1048 } else if(statx_np(s->dst, &dst_sb, s->original_fsec) == 0)
1049 {
1050 /*
1051 * copyfile_fix_perms() will make a copy of the permission set,
1052 * and insert at the beginning an ACE that ensures we can write
1053 * to the file and set attributes.
1054 */
1055
1056 if((s->permissive_fsec = copyfile_fix_perms(s, &s->original_fsec)) != NULL)
1057 {
1058 /*
1059 * Set the permissions for the destination to our copy.
1060 * We should get ENOTSUP from any filesystem that simply
1061 * doesn't support it.
1062 */
1063 if (chmodx_np(s->dst, s->permissive_fsec) < 0 && errno != ENOTSUP)
1064 {
1065 copyfile_warn("setting security information");
1066 filesec_free(s->permissive_fsec);
1067 s->permissive_fsec = NULL;
1068 }
1069 }
1070 } else if (errno == ENOENT) {
1071 createdst = 1;
1072 }
1073
1074 /*
1075 * If COPYFILE_CHECK is set in flags, then all we are going to do
1076 * is see what kinds of things WOULD have been copied (see
1077 * copyfile_check() below). We return that value.
1078 */
1079 if (COPYFILE_CHECK & flags)
1080 {
1081 ret = copyfile_check(s);
1082 goto exit;
1083 } else if ((ret = copyfile_open(s)) < 0)
1084 goto error_exit;
1085
1086 (void)fcntl(s->src_fd, F_NOCACHE, 1);
1087 (void)fcntl(s->dst_fd, F_NOCACHE, 1);
1088 #ifdef F_SINGLE_WRITER
1089 (void)fcntl(s->dst_fd, F_SINGLE_WRITER, 1);
1090 #endif
1091
1092 ret = copyfile_internal(s, flags);
1093 if (ret == -1)
1094 goto error_exit;
1095
1096 #ifdef COPYFILE_RECURSIVE
1097 if (!(flags & COPYFILE_STAT)) {
1098 if (!createdst)
1099 {
1100 /* Just need to reset the BSD information -- mode, owner, group */
1101 (void)fchown(s->dst_fd, dst_sb.st_uid, dst_sb.st_gid);
1102 (void)fchmod(s->dst_fd, dst_sb.st_mode);
1103 }
1104 }
1105 #endif
1106
1107 reset_security(s);
1108
1109 if (s->src && (flags & COPYFILE_MOVE))
1110 (void)remove(s->src);
1111
1112 exit:
1113 if (state == NULL) {
1114 int t = errno;
1115 copyfile_state_free(s);
1116 errno = t;
1117 }
1118
1119 return ret;
1120
1121 error_exit:
1122 ret = -1;
1123 if (s->err) {
1124 errno = s->err;
1125 s->err = 0;
1126 }
1127 goto exit;
1128 }
1129
1130 /*
1131 * Shared prelude to the {f,}copyfile(). This initializes the
1132 * state variable, if necessary, and also checks for both debugging
1133 * and disabling environment variables.
1134 */
1135 static int copyfile_preamble(copyfile_state_t *state, copyfile_flags_t flags)
1136 {
1137 copyfile_state_t s;
1138
1139 if (*state == NULL)
1140 {
1141 if ((*state = copyfile_state_alloc()) == NULL)
1142 return -1;
1143 }
1144
1145 s = *state;
1146
1147 if (COPYFILE_DEBUG & flags)
1148 {
1149 char *e;
1150 if ((e = getenv(COPYFILE_DEBUG_VAR)))
1151 {
1152 errno = 0;
1153 s->debug = (uint32_t)strtol(e, NULL, 0);
1154
1155 /* clamp s->debug to 1 if the environment variable is not parsable */
1156 if (s->debug == 0 && errno != 0)
1157 s->debug = 1;
1158 }
1159 copyfile_debug(2, "debug value set to: %d", s->debug);
1160 }
1161
1162 #if 0
1163 /* Temporarily disabled */
1164 if (getenv(COPYFILE_DISABLE_VAR) != NULL)
1165 {
1166 copyfile_debug(1, "copyfile disabled");
1167 return 2;
1168 }
1169 #endif
1170 copyfile_debug(2, "setting flags: %d", s->flags);
1171 s->flags = flags;
1172
1173 return 0;
1174 }
1175
1176 /*
1177 * The guts of {f,}copyfile().
1178 * This looks through the flags in a particular order, and calls the
1179 * associated functions.
1180 */
1181 static int copyfile_internal(copyfile_state_t s, copyfile_flags_t flags)
1182 {
1183 int ret = 0;
1184
1185 if (s->dst_fd < 0 || s->src_fd < 0)
1186 {
1187 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s->src_fd, s->dst_fd);
1188 s->err = EINVAL;
1189 return -1;
1190 }
1191
1192 /*
1193 * COPYFILE_PACK causes us to create an Apple Double version of the
1194 * source file, and puts it into the destination file. See
1195 * copyfile_pack() below for all the gory details.
1196 */
1197 if (COPYFILE_PACK & flags)
1198 {
1199 if ((ret = copyfile_pack(s)) < 0)
1200 {
1201 if (s->dst) unlink(s->dst);
1202 goto exit;
1203 }
1204 goto exit;
1205 }
1206
1207 /*
1208 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1209 * The goal there is to take an Apple Double file, and turn it
1210 * into a normal file (with data fork, resource fork, modes,
1211 * extended attributes, ACLs, etc.).
1212 */
1213 if (COPYFILE_UNPACK & flags)
1214 {
1215 if ((ret = copyfile_unpack(s)) < 0)
1216 goto error_exit;
1217 goto exit;
1218 }
1219
1220 /*
1221 * If we have quarantine info set, we attempt
1222 * to apply it to dst_fd. We don't care if
1223 * it fails, not yet anyway.
1224 */
1225 if (s->qinfo) {
1226 int qr = qtn_file_apply_to_fd(s->qinfo, s->dst_fd);
1227 if (qr != 0) {
1228 if (s->statuscb) {
1229 int rv;
1230
1231 s->xattr_name = (char*)XATTR_QUARANTINE_NAME;
1232 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
1233 s->xattr_name = NULL;
1234 if (rv == COPYFILE_QUIT) {
1235 s->err = errno = (qr < 0 ? ENOTSUP : qr);
1236 ret = -1;
1237 goto exit;
1238 }
1239 } else {
1240 s->err = errno = (qr < 0 ? ENOTSUP : qr);
1241 ret = -1;
1242 goto exit;
1243 }
1244 }
1245 }
1246
1247 /*
1248 * COPYFILE_XATTR tells us to copy the extended attributes;
1249 * this is seperate from the extended security (aka ACLs),
1250 * however. If we succeed in this, we continue to the next
1251 * stage; if we fail, we return with an error value. Note
1252 * that we fail if the errno is ENOTSUP, but we don't print
1253 * a warning in that case.
1254 */
1255 if (COPYFILE_XATTR & flags)
1256 {
1257 if ((ret = copyfile_xattr(s)) < 0)
1258 {
1259 if (errno != ENOTSUP && errno != EPERM)
1260 copyfile_warn("error processing extended attributes");
1261 goto exit;
1262 }
1263 }
1264
1265 /*
1266 * Simialr to above, this tells us whether or not to copy
1267 * the non-meta data portion of the file. We attempt to
1268 * remove (via unlink) the destination file if we fail.
1269 */
1270 if (COPYFILE_DATA & flags)
1271 {
1272 if ((ret = copyfile_data(s)) < 0)
1273 {
1274 copyfile_warn("error processing data");
1275 if (s->dst && unlink(s->dst))
1276 copyfile_warn("%s: remove", s->src ? s->src : "(null src)");
1277 goto exit;
1278 }
1279 }
1280
1281 /*
1282 * COPYFILE_SECURITY requests that we copy the security, both
1283 * extended and mundane (that is, ACLs and POSIX).
1284 */
1285 if (COPYFILE_SECURITY & flags)
1286 {
1287 if ((ret = copyfile_security(s)) < 0)
1288 {
1289 copyfile_warn("error processing security information");
1290 goto exit;
1291 }
1292 }
1293
1294 if (COPYFILE_STAT & flags)
1295 {
1296 if ((ret = copyfile_stat(s)) < 0)
1297 {
1298 copyfile_warn("error processing POSIX information");
1299 goto exit;
1300 }
1301 }
1302
1303 exit:
1304 return ret;
1305
1306 error_exit:
1307 ret = -1;
1308 goto exit;
1309 }
1310
1311 /*
1312 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1313 */
1314 copyfile_state_t copyfile_state_alloc(void)
1315 {
1316 copyfile_state_t s = (copyfile_state_t) calloc(1, sizeof(struct _copyfile_state));
1317
1318 if (s != NULL)
1319 {
1320 s->src_fd = -2;
1321 s->dst_fd = -2;
1322 if (s->fsec) {
1323 filesec_free(s->fsec);
1324 s->fsec = NULL;
1325 }
1326 s->fsec = filesec_init();
1327 } else
1328 errno = ENOMEM;
1329
1330 return s;
1331 }
1332
1333 /*
1334 * copyfile_state_free() returns the memory allocated to the state structure.
1335 * It also closes the file descriptors, if they've been opened.
1336 */
1337 int copyfile_state_free(copyfile_state_t s)
1338 {
1339 if (s != NULL)
1340 {
1341 if (s->fsec)
1342 filesec_free(s->fsec);
1343
1344 if (s->original_fsec)
1345 filesec_free(s->original_fsec);
1346
1347 if (s->permissive_fsec)
1348 filesec_free(s->permissive_fsec);
1349
1350 if (s->qinfo)
1351 qtn_file_free(s->qinfo);
1352
1353 if (copyfile_close(s) < 0)
1354 {
1355 copyfile_warn("error closing files");
1356 return -1;
1357 }
1358 if (s->xattr_name)
1359 free(s->xattr_name);
1360 if (s->dst)
1361 free(s->dst);
1362 if (s->src)
1363 free(s->src);
1364 free(s);
1365 }
1366 return 0;
1367 }
1368
1369 /*
1370 * Should we worry if we can't close the source? NFS says we
1371 * should, but it's pretty late for us at this point.
1372 */
1373 static int copyfile_close(copyfile_state_t s)
1374 {
1375 if (s->src && s->src_fd >= 0)
1376 close(s->src_fd);
1377
1378 if (s->dst && s->dst_fd >= 0) {
1379 if (close(s->dst_fd))
1380 return -1;
1381 }
1382
1383 return 0;
1384 }
1385
1386 /*
1387 * The purpose of this function is to set up a set of permissions
1388 * (ACL and traditional) that lets us write to the file. In the
1389 * case of ACLs, we do this by putting in a first entry that lets
1390 * us write data, attributes, and extended attributes. In the case
1391 * of traditional permissions, we set the S_IWUSR (user-write)
1392 * bit.
1393 */
1394 static filesec_t copyfile_fix_perms(copyfile_state_t s __unused, filesec_t *fsec)
1395 {
1396 filesec_t ret_fsec = NULL;
1397 mode_t mode;
1398 acl_t acl = NULL;
1399
1400 if ((ret_fsec = filesec_dup(*fsec)) == NULL)
1401 goto error_exit;
1402
1403 if (filesec_get_property(ret_fsec, FILESEC_ACL, &acl) == 0)
1404 {
1405 #ifdef COPYFILE_RECURSIVE
1406 if (add_uberace(&acl))
1407 goto error_exit;
1408 #else
1409 acl_entry_t entry;
1410 acl_permset_t permset;
1411 uuid_t qual;
1412
1413 if (mbr_uid_to_uuid(getuid(), qual) != 0)
1414 goto error_exit;
1415
1416 /*
1417 * First, we create an entry, and give it the special name
1418 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1419 * After that, we clear out all the permissions in it, and
1420 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1421 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1422 * the functionality, and put this into the ACL.
1423 */
1424 if (acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY) == -1)
1425 goto error_exit;
1426 if (acl_get_permset(entry, &permset) == -1)
1427 goto error_exit;
1428 if (acl_clear_perms(permset) == -1)
1429 goto error_exit;
1430 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1)
1431 goto error_exit;
1432 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1)
1433 goto error_exit;
1434 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1)
1435 goto error_exit;
1436 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1)
1437 goto error_exit;
1438
1439 if(acl_set_permset(entry, permset) == -1)
1440 goto error_exit;
1441 if(acl_set_qualifier(entry, qual) == -1)
1442 goto error_exit;
1443 #endif
1444
1445 if (filesec_set_property(ret_fsec, FILESEC_ACL, &acl) != 0)
1446 goto error_exit;
1447 }
1448
1449 /*
1450 * This is for the normal, mundane, POSIX permission model.
1451 * We make sure that we can write to the file.
1452 */
1453 if (filesec_get_property(ret_fsec, FILESEC_MODE, &mode) == 0)
1454 {
1455 if ((mode & (S_IWUSR | S_IRUSR)) != (S_IWUSR | S_IRUSR))
1456 {
1457 mode |= S_IWUSR|S_IRUSR;
1458 if (filesec_set_property(ret_fsec, FILESEC_MODE, &mode) != 0)
1459 goto error_exit;
1460 }
1461 }
1462
1463 exit:
1464 if (acl)
1465 acl_free(acl);
1466
1467 return ret_fsec;
1468
1469 error_exit:
1470 if (ret_fsec)
1471 {
1472 filesec_free(ret_fsec);
1473 ret_fsec = NULL;
1474 }
1475 goto exit;
1476 }
1477
1478 /*
1479 * Used to clear out the BSD/POSIX security information from
1480 * a filesec
1481 */
1482 static int
1483 copyfile_unset_posix_fsec(filesec_t fsec)
1484 {
1485 (void)filesec_set_property(fsec, FILESEC_OWNER, _FILESEC_UNSET_PROPERTY);
1486 (void)filesec_set_property(fsec, FILESEC_GROUP, _FILESEC_UNSET_PROPERTY);
1487 (void)filesec_set_property(fsec, FILESEC_MODE, _FILESEC_UNSET_PROPERTY);
1488 return 0;
1489 }
1490
1491 /*
1492 * Used to remove acl information from a filesec_t
1493 * Unsetting the acl alone in Tiger was insufficient
1494 */
1495 static int copyfile_unset_acl(copyfile_state_t s)
1496 {
1497 int ret = 0;
1498 if (filesec_set_property(s->fsec, FILESEC_ACL, NULL) == -1)
1499 {
1500 copyfile_debug(5, "unsetting acl attribute on %s", s->dst ? s->dst : "(null dst)");
1501 ++ret;
1502 }
1503 if (filesec_set_property(s->fsec, FILESEC_UUID, NULL) == -1)
1504 {
1505 copyfile_debug(5, "unsetting uuid attribute on %s", s->dst ? s->dst : "(null dst)");
1506 ++ret;
1507 }
1508 if (filesec_set_property(s->fsec, FILESEC_GRPUUID, NULL) == -1)
1509 {
1510 copyfile_debug(5, "unsetting group uuid attribute on %s", s->dst ? s->dst : "(null dst)");
1511 ++ret;
1512 }
1513 return ret;
1514 }
1515
1516 /*
1517 * copyfile_open() does what one expects: it opens up the files
1518 * given in the state structure, if they're not already open.
1519 * It also does some type validation, to ensure that we only
1520 * handle file types we know about.
1521 */
1522 static int copyfile_open(copyfile_state_t s)
1523 {
1524 int oflags = O_EXCL | O_CREAT | O_WRONLY;
1525 int islnk = 0, isdir = 0, isreg = 0;
1526 int osrc = 0, dsrc = 0;
1527 int prot_class = PROTECTION_CLASS_DEFAULT;
1528 int set_cprot_explicit = 0;
1529 int error = 0;
1530
1531 if (s->src && s->src_fd == -2)
1532 {
1533 if ((COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
1534 (s->src, &s->sb, s->fsec))
1535 {
1536 copyfile_warn("stat on %s", s->src);
1537 return -1;
1538 }
1539
1540 /* prevent copying on unsupported types */
1541 switch (s->sb.st_mode & S_IFMT)
1542 {
1543 case S_IFLNK:
1544 islnk = 1;
1545 if ((size_t)s->sb.st_size > SIZE_T_MAX) {
1546 s->err = ENOMEM; /* too big for us to copy */
1547 return -1;
1548 }
1549 osrc = O_SYMLINK;
1550 break;
1551 case S_IFDIR:
1552 isdir = 1;
1553 break;
1554 case S_IFREG:
1555 isreg = 1;
1556 break;
1557 default:
1558 if (!(strcmp(s->src, "/dev/null") == 0 && (s->flags & COPYFILE_METADATA))) {
1559 s->err = ENOTSUP;
1560 return -1;
1561 }
1562 }
1563 /*
1564 * If we're packing, then we are actually
1565 * creating a file, no matter what the source
1566 * was.
1567 */
1568 if (s->flags & COPYFILE_PACK) {
1569 /*
1570 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1571 * if the file is a symlink, and O_NOFOLLOW is specified,
1572 * open will return ELOOP, whether or not O_SYMLINK is set.
1573 * However, we know whether or not it was a symlink from
1574 * the stat above (although there is a potentiaal for a race
1575 * condition here, but it will err on the side of returning
1576 * ELOOP from open).
1577 */
1578 if (!islnk)
1579 osrc = (s->flags & COPYFILE_NOFOLLOW_SRC) ? O_NOFOLLOW : 0;
1580 isdir = islnk = 0;
1581 }
1582
1583 if ((s->src_fd = open(s->src, O_RDONLY | osrc , 0)) < 0)
1584 {
1585 copyfile_warn("open on %s", s->src);
1586 return -1;
1587 }
1588 copyfile_debug(2, "open successful on source (%s)", s->src);
1589
1590 (void)copyfile_quarantine(s);
1591 }
1592
1593 if (s->dst && s->dst_fd == -2)
1594 {
1595 /*
1596 * COPYFILE_UNLINK tells us to try removing the destination
1597 * before we create it. We don't care if the file doesn't
1598 * exist, so we ignore ENOENT.
1599 */
1600 if (COPYFILE_UNLINK & s->flags)
1601 {
1602 if (remove(s->dst) < 0 && errno != ENOENT)
1603 {
1604 copyfile_warn("%s: remove", s->dst);
1605 return -1;
1606 }
1607 }
1608
1609 if (s->flags & COPYFILE_NOFOLLOW_DST) {
1610 struct stat st;
1611
1612 dsrc = O_NOFOLLOW;
1613 if (lstat(s->dst, &st) != -1) {
1614 if ((st.st_mode & S_IFMT) == S_IFLNK)
1615 dsrc = O_SYMLINK;
1616 }
1617 }
1618
1619 if (!(s->internal_flags & cfSrcProtSupportValid))
1620 {
1621 if ((error = does_copy_protection(s->src_fd)) > 0)
1622 {
1623 s->internal_flags |= cfSrcSupportsCProtect;
1624 }
1625 else if (error < 0)
1626 {
1627 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s->src, errno);
1628 return -1;
1629 }
1630 s->internal_flags |= cfSrcProtSupportValid;
1631 }
1632
1633 /* copy protection is only valid for regular files and directories. */
1634 if ((isreg || isdir) && (s->internal_flags & cfSrcSupportsCProtect))
1635 {
1636 prot_class = GET_PROT_CLASS(s->src_fd);
1637 if (prot_class < 0)
1638 {
1639 copyfile_warn("GET_PROT_CLASS failed on (%s) with error <%d>", s->src, errno);
1640 return -1;
1641 }
1642 }
1643
1644 if (islnk) {
1645 size_t sz = (size_t)s->sb.st_size + 1;
1646 char *bp;
1647
1648 bp = calloc(1, sz);
1649 if (bp == NULL) {
1650 copyfile_warn("cannot allocate %zd bytes", sz);
1651 return -1;
1652 }
1653 if (readlink(s->src, bp, sz-1) == -1) {
1654 copyfile_warn("cannot readlink %s", s->src);
1655 free(bp);
1656 return -1;
1657 }
1658 if (symlink(bp, s->dst) == -1) {
1659 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
1660 copyfile_warn("Cannot make symlink %s", s->dst);
1661 free(bp);
1662 return -1;
1663 }
1664 }
1665 free(bp);
1666 s->dst_fd = open(s->dst, O_RDONLY | O_SYMLINK);
1667 if (s->dst_fd == -1) {
1668 copyfile_warn("Cannot open symlink %s for reading", s->dst);
1669 return -1;
1670 }
1671 } else if (isdir) {
1672 mode_t mode;
1673 mode = (s->sb.st_mode & ~S_IFMT) | S_IRWXU;
1674
1675 if (mkdir(s->dst, mode) == -1) {
1676 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
1677 copyfile_warn("Cannot make directory %s", s->dst);
1678 return -1;
1679 }
1680 }
1681 s->dst_fd = open(s->dst, O_RDONLY | dsrc);
1682 if (s->dst_fd == -1) {
1683 copyfile_warn("Cannot open directory %s for reading", s->dst);
1684 return -1;
1685 }
1686 set_cprot_explicit = 1;
1687 } else while((s->dst_fd = open_dprotected_np(s->dst, oflags | dsrc, prot_class, 0, s->sb.st_mode | S_IWUSR)) < 0)
1688 {
1689 /*
1690 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1691 * was written -- allow one to set an extended attribute on a file descriptor
1692 * for a read-only file, even if the file descriptor is opened for writing.
1693 * This will only matter if the file does not already exist.
1694 */
1695 switch(errno)
1696 {
1697 case EEXIST:
1698 copyfile_debug(3, "open failed, retrying (%s)", s->dst);
1699 if (s->flags & COPYFILE_EXCL)
1700 break;
1701 oflags = oflags & ~O_CREAT;
1702 /* if O_CREAT isn't set in open_dprotected_np, it won't set protection class.
1703 * Set the flag here so we know to do it later.
1704 */
1705 set_cprot_explicit = 1;
1706 if (s->flags & (COPYFILE_PACK | COPYFILE_DATA))
1707 {
1708 copyfile_debug(4, "truncating existing file (%s)", s->dst);
1709 oflags |= O_TRUNC;
1710 }
1711 continue;
1712 case EACCES:
1713 if(chmod(s->dst, (s->sb.st_mode | S_IWUSR) & ~S_IFMT) == 0)
1714 continue;
1715 else {
1716 /*
1717 * If we're trying to write to a directory to which we don't
1718 * have access, the create above would have failed, but chmod
1719 * here would have given us ENOENT. But the real error is
1720 * still one of access, so we change the errno we're reporting.
1721 * This could cause confusion with a race condition.
1722 */
1723
1724 if (errno == ENOENT)
1725 errno = EACCES;
1726 break;
1727 }
1728 case EISDIR:
1729 copyfile_debug(3, "open failed because it is a directory (%s)", s->dst);
1730 if (((s->flags & COPYFILE_EXCL) ||
1731 (!isdir && (s->flags & COPYFILE_DATA)))
1732 && !(s->flags & COPYFILE_UNPACK))
1733 break;
1734 oflags = (oflags & ~(O_WRONLY|O_CREAT|O_TRUNC)) | O_RDONLY;
1735 continue;
1736 }
1737 copyfile_warn("open on %s", s->dst);
1738 return -1;
1739 }
1740 copyfile_debug(2, "open successful on destination (%s)", s->dst);
1741
1742 if (s->internal_flags & cfSrcSupportsCProtect)
1743 {
1744 if (!(s->internal_flags & cfDstProtSupportValid))
1745 {
1746 if ((error = does_copy_protection(s->dst_fd)) > 0)
1747 {
1748 s->internal_flags |= cfDstSupportsCProtect;
1749 }
1750 else if (error < 0)
1751 {
1752 copyfile_warn("does_copy_protection failed on (%s) with error <%d>", s->dst, errno);
1753 return -1;
1754 }
1755 s->internal_flags |= cfDstProtSupportValid;
1756 }
1757
1758 if ((isreg || isdir)
1759 && set_cprot_explicit
1760 && (s->internal_flags & cfDstSupportsCProtect))
1761 {
1762 /* Protection class is set in open_dprotected_np for regular files that aren't truncated.
1763 * We set the protection class here for truncated files and directories.
1764 */
1765 if (SET_PROT_CLASS(s->dst_fd, prot_class) != 0)
1766 {
1767 copyfile_warn("SET_PROT_CLASS failed on (%s) with error <%d>", s->dst, errno);
1768 return -1;
1769 }
1770 }
1771 }
1772 }
1773
1774 if (s->dst_fd < 0 || s->src_fd < 0)
1775 {
1776 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1777 s->src_fd, s->dst_fd);
1778 s->err = EINVAL;
1779 return -1;
1780 }
1781 return 0;
1782 }
1783
1784
1785 /*
1786 * copyfile_check(), as described above, essentially tells you
1787 * what you'd have to copy, if you wanted it to copy the things
1788 * you asked it to copy.
1789 * In other words, if you pass in COPYFILE_ALL, and the file in
1790 * question had no extended attributes but did have an ACL, you'd
1791 * get back COPYFILE_ACL.
1792 */
1793 static copyfile_flags_t copyfile_check(copyfile_state_t s)
1794 {
1795 acl_t acl = NULL;
1796 copyfile_flags_t ret = 0;
1797 int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC);
1798 qtn_file_t qinfo;
1799
1800 if (!s->src)
1801 {
1802 s->err = EINVAL;
1803 return -1;
1804 }
1805
1806 /* check EAs */
1807 if (COPYFILE_XATTR & s->flags)
1808 if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0)
1809 {
1810 ret |= COPYFILE_XATTR;
1811 }
1812
1813 if (COPYFILE_ACL & s->flags)
1814 {
1815 (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
1816 (s->src, &s->sb, s->fsec);
1817
1818 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0)
1819 ret |= COPYFILE_ACL;
1820 }
1821
1822 copyfile_debug(2, "check result: %d (%s)", ret, s->src);
1823
1824 if (acl)
1825 acl_free(acl);
1826
1827 if (s->qinfo) {
1828 /* If the state has had quarantine info set already, we use that */
1829 ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1830 } else {
1831 qinfo = qtn_file_alloc();
1832 /*
1833 * For quarantine information, we need to see if the source file
1834 * has any. Since it may be a symlink, however, and we may, or
1835 * not be following, *and* there's no qtn* routine which can optionally
1836 * follow or not follow a symlink, we need to instead work around
1837 * this limitation.
1838 */
1839 if (qinfo) {
1840 int fd;
1841 int qret = 0;
1842 struct stat sbuf;
1843
1844 /*
1845 * If we care about not following symlinks, *and* the file exists
1846 * (which is to say, lstat doesn't return an error), *and* the file
1847 * is a symlink, then we open it up (with O_SYMLINK), and use
1848 * qtn_file_init_with_fd(); if none of that is true, however, then
1849 * we can simply use qtn_file_init_with_path().
1850 */
1851 if (nofollow
1852 && lstat(s->src, &sbuf) == 0
1853 && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) {
1854 fd = open(s->src, O_RDONLY | O_SYMLINK);
1855 if (fd != -1) {
1856 if (!qtn_file_init_with_fd(qinfo, fd)) {
1857 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1858 }
1859 close(fd);
1860 }
1861 } else {
1862 if (!qtn_file_init_with_path(qinfo, s->src)) {
1863 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1864 }
1865 }
1866 qtn_file_free(qinfo);
1867 ret |= qret;
1868 }
1869 }
1870 return ret;
1871 }
1872
1873 /*
1874 * Attempt to copy the data section of a file. Using blockisize
1875 * is not necessarily the fastest -- it might be desirable to
1876 * specify a blocksize, somehow. But it's a size that should be
1877 * guaranteed to work.
1878 */
1879 static int copyfile_data(copyfile_state_t s)
1880 {
1881 size_t blen;
1882 char *bp = 0;
1883 ssize_t nread;
1884 int ret = 0;
1885 size_t iBlocksize = 0;
1886 size_t oBlocksize = 0;
1887 const size_t onegig = 1 << 30;
1888 struct statfs sfs;
1889 copyfile_callback_t status = s->statuscb;
1890
1891 /* Unless it's a normal file, we don't copy. For now, anyway */
1892 if ((s->sb.st_mode & S_IFMT) != S_IFREG)
1893 return 0;
1894
1895 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
1896 if (s->internal_flags & cfSawDecmpEA) {
1897 if (s->sb.st_flags & UF_COMPRESSED) {
1898 if ((s->flags & COPYFILE_STAT) == 0) {
1899 if (fchflags(s->dst_fd, UF_COMPRESSED) == 0) {
1900 goto exit;
1901 }
1902 }
1903 }
1904 }
1905 #endif
1906
1907 if (fstatfs(s->src_fd, &sfs) == -1) {
1908 iBlocksize = s->sb.st_blksize;
1909 } else {
1910 iBlocksize = sfs.f_iosize;
1911 }
1912
1913 /* Work-around for 6453525, limit blocksize to 1G */
1914 if (iBlocksize > onegig) {
1915 iBlocksize = onegig;
1916 }
1917
1918 if ((bp = malloc(iBlocksize)) == NULL)
1919 return -1;
1920
1921 if (fstatfs(s->dst_fd, &sfs) == -1 || sfs.f_iosize == 0) {
1922 oBlocksize = iBlocksize;
1923 } else {
1924 oBlocksize = sfs.f_iosize;
1925 if (oBlocksize > onegig)
1926 oBlocksize = onegig;
1927 }
1928
1929 blen = iBlocksize;
1930
1931 s->totalCopied = 0;
1932 /* If supported, do preallocation for Xsan / HFS volumes */
1933 #ifdef F_PREALLOCATE
1934 {
1935 fstore_t fst;
1936
1937 fst.fst_flags = 0;
1938 fst.fst_posmode = F_PEOFPOSMODE;
1939 fst.fst_offset = 0;
1940 fst.fst_length = s->sb.st_size;
1941 /* Ignore errors; this is merely advisory. */
1942 (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst);
1943 }
1944 #endif
1945
1946 while ((nread = read(s->src_fd, bp, blen)) > 0)
1947 {
1948 ssize_t nwritten;
1949 size_t left = nread;
1950 void *ptr = bp;
1951 int loop = 0;
1952
1953 while (left > 0) {
1954 nwritten = write(s->dst_fd, ptr, MIN(left, oBlocksize));
1955 switch (nwritten) {
1956 case 0:
1957 if (++loop > 5) {
1958 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop);
1959 ret = -1;
1960 s->err = EAGAIN;
1961 goto exit;
1962 }
1963 break;
1964 case -1:
1965 copyfile_warn("writing to output file got error");
1966 if (status) {
1967 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
1968 if (rv == COPYFILE_SKIP) { // Skip the data copy
1969 ret = 0;
1970 goto exit;
1971 }
1972 if (rv == COPYFILE_CONTINUE) { // Retry the write
1973 errno = 0;
1974 continue;
1975 }
1976 }
1977 ret = -1;
1978 goto exit;
1979 default:
1980 left -= nwritten;
1981 ptr = ((char*)ptr) + nwritten;
1982 loop = 0;
1983 break;
1984 }
1985 s->totalCopied += nwritten;
1986 if (status) {
1987 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
1988 if (rv == COPYFILE_QUIT) {
1989 ret = -1; s->err = errno = ECANCELED;
1990 goto exit;
1991 }
1992 }
1993 }
1994 }
1995 if (nread < 0)
1996 {
1997 copyfile_warn("reading from %s", s->src ? s->src : "(null src)");
1998 ret = -1;
1999 goto exit;
2000 }
2001
2002 if (ftruncate(s->dst_fd, s->totalCopied) < 0)
2003 {
2004 ret = -1;
2005 goto exit;
2006 }
2007
2008 exit:
2009 if (ret == -1)
2010 {
2011 s->err = errno;
2012 }
2013 free(bp);
2014 return ret;
2015 }
2016
2017 /*
2018 * copyfile_security() will copy the ACL set, and the
2019 * POSIX set. Complexities come when dealing with
2020 * inheritied permissions, and when dealing with both
2021 * POSIX and ACL permissions.
2022 */
2023 static int copyfile_security(copyfile_state_t s)
2024 {
2025 int copied = 0;
2026 struct stat sb;
2027 acl_t acl_src = NULL, acl_tmp = NULL, acl_dst = NULL;
2028 int ret = 0;
2029 filesec_t tmp_fsec = NULL;
2030 filesec_t fsec_dst = filesec_init();
2031
2032 if (fsec_dst == NULL)
2033 return -1;
2034
2035
2036 if (COPYFILE_ACL & s->flags)
2037 {
2038 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src))
2039 {
2040 if (errno == ENOENT)
2041 acl_src = NULL;
2042 else
2043 goto error_exit;
2044 }
2045
2046 /* grab the destination acl
2047 cannot assume it's empty due to inheritance
2048 */
2049 if(fstatx_np(s->dst_fd, &sb, fsec_dst))
2050 goto error_exit;
2051
2052 if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst))
2053 {
2054 if (errno == ENOENT)
2055 acl_dst = NULL;
2056 else
2057 goto error_exit;
2058 }
2059
2060 if (acl_src == NULL && acl_dst == NULL)
2061 goto no_acl;
2062
2063 acl_tmp = acl_init(4);
2064 if (acl_tmp == NULL)
2065 goto error_exit;
2066
2067 if (acl_src) {
2068 acl_entry_t ace = NULL;
2069 acl_entry_t tmp = NULL;
2070 for (copied = 0;
2071 acl_get_entry(acl_src,
2072 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
2073 &ace) == 0;)
2074 {
2075 acl_flagset_t flags = { 0 };
2076 acl_get_flagset_np(ace, &flags);
2077 if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
2078 {
2079 if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1)
2080 goto error_exit;
2081
2082 if ((ret = acl_copy_entry(tmp, ace)) == -1)
2083 goto error_exit;
2084
2085 copyfile_debug(2, "copied acl entry from %s to %s",
2086 s->src ? s->src : "(null src)",
2087 s->dst ? s->dst : "(null tmp)");
2088 copied++;
2089 }
2090 }
2091 }
2092 if (acl_dst) {
2093 acl_entry_t ace = NULL;
2094 acl_entry_t tmp = NULL;
2095 acl_flagset_t flags = { 0 };
2096 for (copied = 0;acl_get_entry(acl_dst,
2097 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
2098 &ace) == 0;)
2099 {
2100 acl_get_flagset_np(ace, &flags);
2101 if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
2102 {
2103 if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1)
2104 goto error_exit;
2105
2106 if ((ret = acl_copy_entry(tmp, ace)) == -1)
2107 goto error_exit;
2108
2109 copyfile_debug(2, "copied acl entry from %s to %s",
2110 s->src ? s->src : "(null dst)",
2111 s->dst ? s->dst : "(null tmp)");
2112 copied++;
2113 }
2114 }
2115 }
2116 if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_tmp))
2117 {
2118 copyfile_debug(3, "altered acl");
2119 }
2120 }
2121 no_acl:
2122 /*
2123 * The following code is attempting to ensure that only the requested
2124 * security information gets copied over to the destination file.
2125 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2126 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2127 * this function).
2128 *
2129 * If we have both flags, we copy everything; if we have ACL but not STAT,
2130 * we remove the POSIX information from the filesec object, and apply the
2131 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2132 * the extended version.
2133 */
2134 tmp_fsec = filesec_dup(s->fsec);
2135 if (tmp_fsec == NULL) {
2136 goto error_exit;
2137 }
2138
2139 switch (COPYFILE_SECURITY & s->flags) {
2140 case COPYFILE_ACL:
2141 copyfile_unset_posix_fsec(tmp_fsec);
2142 /* FALLTHROUGH */
2143 case COPYFILE_ACL | COPYFILE_STAT:
2144 if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) {
2145 acl_t acl = NULL;
2146 /*
2147 * The call could have failed for a number of reasons, since
2148 * it does a number of things: it changes the mode of the file,
2149 * sets the owner and group, and applies an ACL (if one exists).
2150 * The typical failure is going to be trying to set the group of
2151 * the destination file to match the source file, when the process
2152 * doesn't have permission to put files in that group. We try to
2153 * work around this by breaking the steps out and doing them
2154 * discretely. We don't care if the fchown fails, but we do care
2155 * if the mode or ACL can't be set. For historical reasons, we
2156 * simply log those failures, however.
2157 *
2158 * Big warning here: we may NOT have COPYFILE_STAT set, since
2159 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2160 */
2161
2162 #define NS(x) ((x) ? (x) : "(null string)")
2163 if ((s->flags & COPYFILE_STAT) &&
2164 fchmod(s->dst_fd, s->sb.st_mode) == -1) {
2165 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s->dst), NS(s->src));
2166 }
2167 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
2168 if (filesec_get_property(tmp_fsec, FILESEC_ACL, &acl) == 0) {
2169 if (acl_set_fd(s->dst_fd, acl) == -1) {
2170 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s->dst), NS(s->src));
2171 }
2172 acl_free(acl);
2173 }
2174 }
2175 #undef NS
2176 break;
2177 case COPYFILE_STAT:
2178 (void)fchmod(s->dst_fd, s->sb.st_mode);
2179 break;
2180 }
2181 filesec_free(tmp_fsec);
2182 exit:
2183 filesec_free(fsec_dst);
2184 if (acl_src) acl_free(acl_src);
2185 if (acl_dst) acl_free(acl_dst);
2186 if (acl_tmp) acl_free(acl_tmp);
2187
2188 return ret;
2189
2190 error_exit:
2191 ret = -1;
2192 goto exit;
2193
2194 }
2195
2196 /*
2197 * Attempt to set the destination file's stat information -- including
2198 * flags and time-related fields -- to the source's.
2199 */
2200 static int copyfile_stat(copyfile_state_t s)
2201 {
2202 struct timeval tval[2];
2203 unsigned int added_flags = 0, dst_flags = 0;
2204 struct stat dst_sb;
2205
2206 /*
2207 * NFS doesn't support chflags; ignore errors as a result, since
2208 * we don't return failure for this.
2209 */
2210 if (s->internal_flags & cfMakeFileInvisible)
2211 added_flags |= UF_HIDDEN;
2212
2213 /*
2214 * We need to check if SF_RESTRICTED was set on the destination
2215 * by the kernel. If it was, don't drop it.
2216 */
2217 if (fstat(s->dst_fd, &dst_sb))
2218 return -1;
2219 if (dst_sb.st_flags & SF_RESTRICTED)
2220 added_flags |= SF_RESTRICTED;
2221
2222 /* Copy file flags, masking out any we don't want to preserve */
2223 dst_flags = (s->sb.st_flags & ~COPYFILE_OMIT_FLAGS) | added_flags;
2224 (void)fchflags(s->dst_fd, dst_flags);
2225
2226 /* If this fails, we don't care */
2227 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
2228
2229 /* This may have already been done in copyfile_security() */
2230 (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT);
2231
2232 tval[0].tv_sec = s->sb.st_atime;
2233 tval[1].tv_sec = s->sb.st_mtime;
2234 tval[0].tv_usec = tval[1].tv_usec = 0;
2235 (void)futimes(s->dst_fd, tval);
2236
2237 return 0;
2238 }
2239
2240 /*
2241 * Similar to copyfile_security() in some ways; this
2242 * routine copies the extended attributes from the source,
2243 * and sets them on the destination.
2244 * The procedure is pretty simple, even if it is verbose:
2245 * for each named attribute on the destination, get its name, and
2246 * remove it. We should have none after that.
2247 * For each named attribute on the source, get its name, get its
2248 * data, and set it on the destination.
2249 */
2250 static int copyfile_xattr(copyfile_state_t s)
2251 {
2252 char *name;
2253 char *namebuf, *end;
2254 ssize_t xa_size;
2255 void *xa_dataptr;
2256 ssize_t bufsize = 4096;
2257 ssize_t asize;
2258 ssize_t nsize;
2259 int ret = 0;
2260 int look_for_decmpea = 0;
2261
2262 /* delete EAs on destination */
2263 if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
2264 {
2265 if ((namebuf = (char *) malloc(nsize)) == NULL)
2266 return -1;
2267 else
2268 nsize = flistxattr(s->dst_fd, namebuf, nsize, 0);
2269
2270 if (nsize > 0) {
2271 /*
2272 * With this, end points to the last byte of the allocated buffer
2273 * This *should* be NUL, from flistxattr, but if it's not, we can
2274 * set it anyway -- it'll result in a truncated name, which then
2275 * shouldn't match when we get them later.
2276 */
2277 end = namebuf + nsize - 1;
2278 if (*end != 0)
2279 *end = 0;
2280 for (name = namebuf; name <= end; name += strlen(name) + 1) {
2281 /* If the quarantine information shows up as an EA, we skip over it */
2282 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) {
2283 continue;
2284 }
2285 fremovexattr(s->dst_fd, name,0);
2286 }
2287 }
2288 free(namebuf);
2289 } else
2290 if (nsize < 0)
2291 {
2292 if (errno == ENOTSUP || errno == EPERM)
2293 return 0;
2294 else
2295 return -1;
2296 }
2297
2298 #ifdef DECMPFS_XATTR_NAME
2299 if ((s->flags & COPYFILE_DATA) &&
2300 (s->sb.st_flags & UF_COMPRESSED) &&
2301 doesdecmpfs(s->src_fd) &&
2302 doesdecmpfs(s->dst_fd)) {
2303 look_for_decmpea = XATTR_SHOWCOMPRESSION;
2304 }
2305 #endif
2306
2307 /* get name list of EAs on source */
2308 if ((nsize = flistxattr(s->src_fd, 0, 0, look_for_decmpea)) < 0)
2309 {
2310 if (errno == ENOTSUP || errno == EPERM)
2311 return 0;
2312 else
2313 return -1;
2314 } else
2315 if (nsize == 0)
2316 return 0;
2317
2318 if ((namebuf = (char *) malloc(nsize)) == NULL)
2319 return -1;
2320 else
2321 nsize = flistxattr(s->src_fd, namebuf, nsize, look_for_decmpea);
2322
2323 if (nsize <= 0) {
2324 free(namebuf);
2325 return (int)nsize;
2326 }
2327
2328 /*
2329 * With this, end points to the last byte of the allocated buffer
2330 * This *should* be NUL, from flistxattr, but if it's not, we can
2331 * set it anyway -- it'll result in a truncated name, which then
2332 * shouldn't match when we get them later.
2333 */
2334 end = namebuf + nsize - 1;
2335 if (*end != 0)
2336 *end = 0;
2337
2338 if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) {
2339 free(namebuf);
2340 return -1;
2341 }
2342
2343 for (name = namebuf; name <= end; name += strlen(name) + 1)
2344 {
2345 if (s->xattr_name) {
2346 free(s->xattr_name);
2347 s->xattr_name = NULL;
2348 }
2349
2350 /* If the quarantine information shows up as an EA, we skip over it */
2351 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0)
2352 continue;
2353
2354 if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, look_for_decmpea)) < 0)
2355 {
2356 continue;
2357 }
2358
2359 if (xa_size > bufsize)
2360 {
2361 void *tdptr = xa_dataptr;
2362 bufsize = xa_size;
2363 if ((xa_dataptr =
2364 (void *) realloc((void *) xa_dataptr, bufsize)) == NULL)
2365 {
2366 free(tdptr);
2367 ret = -1;
2368 continue;
2369 }
2370 }
2371
2372 if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea)) < 0)
2373 {
2374 continue;
2375 }
2376
2377 if (xa_size != asize)
2378 xa_size = asize;
2379
2380 #ifdef DECMPFS_XATTR_NAME
2381 if (strncmp(name, DECMPFS_XATTR_NAME, end-name) == 0)
2382 {
2383 decmpfs_disk_header *hdr = xa_dataptr;
2384
2385 /*
2386 * If the EA has the decmpfs name, but is too
2387 * small, or doesn't have the right magic number,
2388 * or isn't the right type, we'll just skip it.
2389 * This means it won't end up in the destination
2390 * file, and data copy will happen normally.
2391 */
2392 if ((size_t)xa_size < sizeof(decmpfs_disk_header)) {
2393 continue;
2394 }
2395 if (OSSwapLittleToHostInt32(hdr->compression_magic) != DECMPFS_MAGIC) {
2396 continue;
2397 }
2398 /*
2399 * From AppleFSCompression documentation:
2400 * "It is incumbent on the aware copy engine to identify
2401 * the type of compression being used, and to perform an
2402 * unaware copy of any file it does not recognize."
2403 *
2404 * Compression Types are defined in:
2405 * "AppleFSCompression/Common/compressorCommon.h"
2406 *
2407 * Unfortunately, they don't provide a way to dynamically
2408 * determine what possible compression_type values exist,
2409 * so we have to update this every time a new compression_type
2410 * is added. Types 7->10 were added in 10.10, Types 11 & 12
2411 * were added in 10.11.
2412 *
2413 * Ubiquity faulting file compression type 0x80000001 are
2414 * deprecated as of Yosemite, per rdar://17714998 don't copy the
2415 * decmpfs xattr on these files, zero byte files are safer
2416 * than a fault nobody knows how to handle.
2417 */
2418 switch (OSSwapLittleToHostInt32(hdr->compression_type)) {
2419 case 3: /* zlib-compressed data in xattr */
2420 case 4: /* 64k chunked zlib-compressed data in resource fork */
2421
2422 case 7: /* LZVN-compressed data in xattr */
2423 case 8: /* 64k chunked LZVN-compressed data in resource fork */
2424
2425 case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */
2426 case 10: /* 64k chunked uncompressed data in resource fork */
2427
2428 case 11: /* LZFSE-compressed data in xattr */
2429 case 12: /* 64k chunked LZFSE-compressed data in resource fork */
2430
2431 /* valid compression type, we want to copy. */
2432 break;
2433
2434 case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */
2435 copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.",
2436 s->src ? s->src : "(null string)");
2437 continue;
2438
2439 case 6: /* unused */
2440 case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */
2441 default:
2442 copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s",
2443 OSSwapLittleToHostInt32(hdr->compression_type), name, s->src ? s->src : "(null string)");
2444 continue;
2445 }
2446 s->internal_flags |= cfSawDecmpEA;
2447 }
2448 #endif
2449
2450 // If we have a copy intention stated, and the EA is to be ignored, we ignore it
2451 if (s->copyIntent
2452 && xattr_preserve_for_intent(name, s->copyIntent) == 0)
2453 continue;
2454
2455 s->xattr_name = strdup(name);
2456
2457 if (s->statuscb) {
2458 int rv;
2459 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
2460 if (rv == COPYFILE_QUIT) {
2461 s->err = ECANCELED;
2462 goto out;
2463 } else if (rv == COPYFILE_SKIP) {
2464 continue;
2465 }
2466 }
2467 if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea) < 0)
2468 {
2469 if (s->statuscb)
2470 {
2471 int rv;
2472 if (s->xattr_name == NULL)
2473 s->xattr_name = strdup(name);
2474 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
2475 if (rv == COPYFILE_QUIT)
2476 {
2477 s->err = ECANCELED;
2478 ret = -1;
2479 goto out;
2480 }
2481 }
2482 else
2483 {
2484 ret = -1;
2485 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name, strerror(errno));
2486 continue;
2487 }
2488 }
2489 if (s->statuscb) {
2490 int rv;
2491 if (s->xattr_name == NULL)
2492 s->xattr_name = strdup(name);
2493
2494 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
2495 if (rv == COPYFILE_QUIT) {
2496 s->err = ECANCELED;
2497 goto out;
2498 }
2499 }
2500 }
2501 out:
2502 if (namebuf)
2503 free(namebuf);
2504 free((void *) xa_dataptr);
2505 if (s->xattr_name) {
2506 free(s->xattr_name);
2507 s->xattr_name = NULL;
2508 }
2509 return ret;
2510 }
2511
2512 /*
2513 * API interface into getting data from the opaque data type.
2514 */
2515 int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
2516 {
2517 if (ret == NULL)
2518 {
2519 errno = EFAULT;
2520 return -1;
2521 }
2522
2523 switch(flag)
2524 {
2525 case COPYFILE_STATE_SRC_FD:
2526 *(int*)ret = s->src_fd;
2527 break;
2528 case COPYFILE_STATE_DST_FD:
2529 *(int*)ret = s->dst_fd;
2530 break;
2531 case COPYFILE_STATE_SRC_FILENAME:
2532 *(char**)ret = s->src;
2533 break;
2534 case COPYFILE_STATE_DST_FILENAME:
2535 *(char**)ret = s->dst;
2536 break;
2537 case COPYFILE_STATE_QUARANTINE:
2538 *(qtn_file_t*)ret = s->qinfo;
2539 break;
2540 #if 0
2541 case COPYFILE_STATE_STATS:
2542 ret = s->stats.global;
2543 break;
2544 case COPYFILE_STATE_PROGRESS_CB:
2545 ret = s->callbacks.progress;
2546 break;
2547 #endif
2548 #ifdef COPYFILE_STATE_STATUS_CB
2549 case COPYFILE_STATE_STATUS_CB:
2550 *(copyfile_callback_t*)ret = s->statuscb;
2551 break;
2552 case COPYFILE_STATE_STATUS_CTX:
2553 *(void**)ret = s->ctx;
2554 break;
2555 case COPYFILE_STATE_COPIED:
2556 *(off_t*)ret = s->totalCopied;
2557 break;
2558 #endif
2559 #ifdef COPYFILE_STATE_XATTRNAME
2560 case COPYFILE_STATE_XATTRNAME:
2561 *(char**)ret = s->xattr_name;
2562 break;
2563 #endif
2564 #ifdef COPYFILE_STATE_INTENT
2565 case COPYFILE_STATE_INTENT:
2566 *(xattr_operation_intent_t*)ret = s->copyIntent;
2567 break;
2568 #endif
2569 default:
2570 errno = EINVAL;
2571 ret = NULL;
2572 return -1;
2573 }
2574 return 0;
2575 }
2576
2577 /*
2578 * Public API for setting state data (remember that the state is
2579 * an opaque data type).
2580 */
2581 int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
2582 {
2583 #define copyfile_set_string(DST, SRC) \
2584 do { \
2585 if (SRC != NULL) { \
2586 DST = strdup((char *)SRC); \
2587 } else { \
2588 if (DST != NULL) { \
2589 free(DST); \
2590 } \
2591 DST = NULL; \
2592 } \
2593 } while (0)
2594
2595 if (thing == NULL)
2596 {
2597 errno = EFAULT;
2598 return -1;
2599 }
2600
2601 switch(flag)
2602 {
2603 case COPYFILE_STATE_SRC_FD:
2604 s->src_fd = *(int*)thing;
2605 break;
2606 case COPYFILE_STATE_DST_FD:
2607 s->dst_fd = *(int*)thing;
2608 break;
2609 case COPYFILE_STATE_SRC_FILENAME:
2610 copyfile_set_string(s->src, thing);
2611 break;
2612 case COPYFILE_STATE_DST_FILENAME:
2613 copyfile_set_string(s->dst, thing);
2614 break;
2615 case COPYFILE_STATE_QUARANTINE:
2616 if (s->qinfo)
2617 {
2618 qtn_file_free(s->qinfo);
2619 s->qinfo = NULL;
2620 }
2621 if (*(qtn_file_t*)thing)
2622 s->qinfo = qtn_file_clone(*(qtn_file_t*)thing);
2623 break;
2624 #if 0
2625 case COPYFILE_STATE_STATS:
2626 s->stats.global = thing;
2627 break;
2628 case COPYFILE_STATE_PROGRESS_CB:
2629 s->callbacks.progress = thing;
2630 break;
2631 #endif
2632 #ifdef COPYFILE_STATE_STATUS_CB
2633 case COPYFILE_STATE_STATUS_CB:
2634 s->statuscb = (copyfile_callback_t)thing;
2635 break;
2636 case COPYFILE_STATE_STATUS_CTX:
2637 s->ctx = (void*)thing;
2638 break;
2639 #endif
2640 #ifdef COPYFILE_STATE_INTENT
2641 case COPYFILE_STATE_INTENT:
2642 s->copyIntent = *(xattr_operation_intent_t*)thing;
2643 break;
2644 #endif
2645 default:
2646 errno = EINVAL;
2647 return -1;
2648 }
2649 return 0;
2650 #undef copyfile_set_string
2651 }
2652
2653
2654 /*
2655 * Make this a standalone program for testing purposes by
2656 * defining _COPYFILE_TEST.
2657 */
2658 #ifdef _COPYFILE_TEST
2659 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2660
2661 struct {char *s; int v;} opts[] = {
2662 COPYFILE_OPTION(ACL)
2663 COPYFILE_OPTION(STAT)
2664 COPYFILE_OPTION(XATTR)
2665 COPYFILE_OPTION(DATA)
2666 COPYFILE_OPTION(SECURITY)
2667 COPYFILE_OPTION(METADATA)
2668 COPYFILE_OPTION(ALL)
2669 COPYFILE_OPTION(NOFOLLOW_SRC)
2670 COPYFILE_OPTION(NOFOLLOW_DST)
2671 COPYFILE_OPTION(NOFOLLOW)
2672 COPYFILE_OPTION(EXCL)
2673 COPYFILE_OPTION(MOVE)
2674 COPYFILE_OPTION(UNLINK)
2675 COPYFILE_OPTION(PACK)
2676 COPYFILE_OPTION(UNPACK)
2677 COPYFILE_OPTION(CHECK)
2678 COPYFILE_OPTION(VERBOSE)
2679 COPYFILE_OPTION(DEBUG)
2680 {NULL, 0}
2681 };
2682
2683 int main(int c, char *v[])
2684 {
2685 int i;
2686 int flags = 0;
2687
2688 if (c < 3)
2689 errx(1, "insufficient arguments");
2690
2691 while(c-- > 3)
2692 {
2693 for (i = 0; opts[i].s != NULL; ++i)
2694 {
2695 if (strcasecmp(opts[i].s, v[c]) == 0)
2696 {
2697 printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v);
2698 flags |= opts[i].v;
2699 break;
2700 }
2701 }
2702 }
2703
2704 return copyfile(v[1], v[2], NULL, flags);
2705 }
2706 #endif
2707 /*
2708 * Apple Double Create
2709 *
2710 * Create an Apple Double "._" file from a file's extented attributes
2711 *
2712 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2713 */
2714
2715
2716 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2717
2718 #define XATTR_MAXATTRLEN (16*1024*1024)
2719
2720
2721 /*
2722 Typical "._" AppleDouble Header File layout:
2723 ------------------------------------------------------------
2724 MAGIC 0x00051607
2725 VERSION 0x00020000
2726 FILLER 0
2727 COUNT 2
2728 .-- AD ENTRY[0] Finder Info Entry (must be first)
2729 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2730 | '-> FINDER INFO
2731 | ///////////// Fixed Size Data (32 bytes)
2732 | EXT ATTR HDR
2733 | /////////////
2734 | ATTR ENTRY[0] --.
2735 | ATTR ENTRY[1] --+--.
2736 | ATTR ENTRY[2] --+--+--.
2737 | ... | | |
2738 | ATTR ENTRY[N] --+--+--+--.
2739 | ATTR DATA 0 <-' | | |
2740 | //////////// | | |
2741 | ATTR DATA 1 <----' | |
2742 | ///////////// | |
2743 | ATTR DATA 2 <-------' |
2744 | ///////////// |
2745 | ... |
2746 | ATTR DATA N <----------'
2747 | /////////////
2748 | Attribute Free Space
2749 |
2750 '----> RESOURCE FORK
2751 ///////////// Variable Sized Data
2752 /////////////
2753 /////////////
2754 /////////////
2755 /////////////
2756 /////////////
2757 ...
2758 /////////////
2759
2760 ------------------------------------------------------------
2761
2762 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2763 stored as part of the Finder Info. The length in the Finder
2764 Info AppleDouble entry includes the length of the extended
2765 attribute header, attribute entries, and attribute data.
2766 */
2767
2768
2769 /*
2770 * On Disk Data Structures
2771 *
2772 * Note: Motorola 68K alignment and big-endian.
2773 *
2774 * See RFC 1740 for additional information about the AppleDouble file format.
2775 *
2776 */
2777
2778 #define ADH_MAGIC 0x00051607
2779 #define ADH_VERSION 0x00020000
2780 #define ADH_MACOSX "Mac OS X "
2781
2782 /*
2783 * AppleDouble Entry ID's
2784 */
2785 #define AD_DATA 1 /* Data fork */
2786 #define AD_RESOURCE 2 /* Resource fork */
2787 #define AD_REALNAME 3 /* File's name on home file system */
2788 #define AD_COMMENT 4 /* Standard Mac comment */
2789 #define AD_ICONBW 5 /* Mac black & white icon */
2790 #define AD_ICONCOLOR 6 /* Mac color icon */
2791 #define AD_UNUSED 7 /* Not used */
2792 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2793 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2794 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2795 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2796 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2797 #define AD_AFPNAME 13 /* Short name on AFP server */
2798 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2799 #define AD_AFPDIRID 15 /* AFP directory ID */
2800 #define AD_ATTRIBUTES AD_FINDERINFO
2801
2802
2803 #define ATTR_FILE_PREFIX "._"
2804 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2805
2806 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2807
2808 /* Implementation Limits */
2809 #define ATTR_MAX_SIZE (16*1024*1024) /* 16 megabyte maximum attribute data size */
2810 #define ATTR_MAX_NAME_LEN 128
2811 #define ATTR_MAX_HDR_SIZE (65536+18)
2812
2813 /*
2814 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2815 * size supported (including the attribute entries). All of
2816 * the attribute entries must reside within this limit.
2817 */
2818
2819
2820 #define FINDERINFOSIZE 32
2821
2822 typedef struct apple_double_entry
2823 {
2824 u_int32_t type; /* entry type: see list, 0 invalid */
2825 u_int32_t offset; /* entry data offset from the beginning of the file. */
2826 u_int32_t length; /* entry data length in bytes. */
2827 } __attribute__((aligned(2), packed)) apple_double_entry_t;
2828
2829
2830 typedef struct apple_double_header
2831 {
2832 u_int32_t magic; /* == ADH_MAGIC */
2833 u_int32_t version; /* format version: 2 = 0x00020000 */
2834 u_int32_t filler[4];
2835 u_int16_t numEntries; /* number of entries which follow */
2836 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */
2837 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */
2838 u_int8_t pad[2]; /* get better alignment inside attr_header */
2839 } __attribute__((aligned(2), packed)) apple_double_header_t;
2840
2841
2842 /* Entries are aligned on 4 byte boundaries */
2843 typedef struct attr_entry
2844 {
2845 u_int32_t offset; /* file offset to data */
2846 u_int32_t length; /* size of attribute data */
2847 u_int16_t flags;
2848 u_int8_t namelen; /* length of name including NULL termination char */
2849 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2850 } __attribute__((aligned(2), packed)) attr_entry_t;
2851
2852
2853
2854 /* Header + entries must fit into 64K */
2855 typedef struct attr_header
2856 {
2857 apple_double_header_t appledouble;
2858 u_int32_t magic; /* == ATTR_HDR_MAGIC */
2859 u_int32_t debug_tag; /* for debugging == file id of owning file */
2860 u_int32_t total_size; /* total size of attribute header + entries + data */
2861 u_int32_t data_start; /* file offset to attribute data area */
2862 u_int32_t data_length; /* length of attribute data area */
2863 u_int32_t reserved[3];
2864 u_int16_t flags;
2865 u_int16_t num_attrs;
2866 } __attribute__((aligned(2), packed)) attr_header_t;
2867
2868 /* Empty Resource Fork Header */
2869 /* This comes by way of xnu's vfs_xattr.c */
2870 typedef struct rsrcfork_header {
2871 u_int32_t fh_DataOffset;
2872 u_int32_t fh_MapOffset;
2873 u_int32_t fh_DataLength;
2874 u_int32_t fh_MapLength;
2875 u_int8_t systemData[112];
2876 u_int8_t appData[128];
2877 u_int32_t mh_DataOffset;
2878 u_int32_t mh_MapOffset;
2879 u_int32_t mh_DataLength;
2880 u_int32_t mh_MapLength;
2881 u_int32_t mh_Next;
2882 u_int16_t mh_RefNum;
2883 u_int8_t mh_Attr;
2884 u_int8_t mh_InMemoryAttr;
2885 u_int16_t mh_Types;
2886 u_int16_t mh_Names;
2887 u_int16_t typeCount;
2888 } __attribute__((aligned(2), packed)) rsrcfork_header_t;
2889 #define RF_FIRST_RESOURCE 256
2890 #define RF_NULL_MAP_LENGTH 30
2891 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2892
2893 static const rsrcfork_header_t empty_rsrcfork_header = {
2894 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_DataOffset
2895 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_MapOffset
2896 0, // fh_DataLength
2897 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // fh_MapLength
2898 { RF_EMPTY_TAG, }, // systemData
2899 { 0 }, // appData
2900 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_DataOffset
2901 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_MapOffset
2902 0, // mh_DataLength
2903 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // mh_MapLength
2904 0, // mh_Next
2905 0, // mh_RefNum
2906 0, // mh_Attr
2907 0, // mh_InMemoryAttr
2908 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2), // mh_Types
2909 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH), // mh_Names
2910 OSSwapHostToBigInt16(-1), // typeCount
2911 };
2912
2913 #define SWAP16(x) OSSwapBigToHostInt16(x)
2914 #define SWAP32(x) OSSwapBigToHostInt32(x)
2915 #define SWAP64(x) OSSwapBigToHostInt64(x)
2916
2917 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2918
2919 #define ATTR_ENTRY_LENGTH(namelen) \
2920 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2921
2922 #define ATTR_NEXT(ae) \
2923 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2924
2925 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2926
2927 /*
2928 * Endian swap Apple Double header
2929 */
2930 static void
2931 swap_adhdr(apple_double_header_t *adh)
2932 {
2933 #if BYTE_ORDER == LITTLE_ENDIAN
2934 int count;
2935 int i;
2936
2937 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
2938
2939 adh->magic = SWAP32 (adh->magic);
2940 adh->version = SWAP32 (adh->version);
2941 adh->numEntries = SWAP16 (adh->numEntries);
2942
2943 for (i = 0; i < count; i++)
2944 {
2945 adh->entries[i].type = SWAP32 (adh->entries[i].type);
2946 adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
2947 adh->entries[i].length = SWAP32 (adh->entries[i].length);
2948 }
2949 #else
2950 (void)adh;
2951 #endif
2952 }
2953
2954 /*
2955 * Endian swap a single attr_entry_t
2956 */
2957 static void
2958 swap_attrhdr_entry(attr_entry_t *ae)
2959 {
2960 #if BYTE_ORDER == LITTLE_ENDIAN
2961 ae->offset = SWAP32 (ae->offset);
2962 ae->length = SWAP32 (ae->length);
2963 ae->flags = SWAP16 (ae->flags);
2964 #else
2965 (void)ae;
2966 #endif
2967 }
2968
2969 /*
2970 * For a validated/endian swapped attr_header_t*
2971 * ah, endian swap all of the entries.
2972 */
2973 static void
2974 swap_attrhdr_entries(attr_header_t *ah)
2975 {
2976 #if BYTE_ORDER == LITTLE_ENDIAN
2977 int i;
2978 int count;
2979 attr_entry_t *entry;
2980 attr_entry_t *next;
2981
2982 /* If we're in copyfile_pack, num_args is native endian,
2983 * if we're in _unpack, num_args is big endian. Use
2984 * the magic number to test for endianess.
2985 */
2986 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
2987
2988 entry = (attr_entry_t *)(&ah[1]);
2989 for (i = 0; i < count; i++) {
2990 next = ATTR_NEXT(entry);
2991 swap_attrhdr_entry(entry);
2992 entry = next;
2993 }
2994 #else
2995 (void)ah;
2996 #endif
2997 }
2998
2999 /*
3000 * Endian swap extended attributes header
3001 */
3002 static void
3003 swap_attrhdr(attr_header_t *ah)
3004 {
3005 #if BYTE_ORDER == LITTLE_ENDIAN
3006 ah->magic = SWAP32 (ah->magic);
3007 ah->debug_tag = SWAP32 (ah->debug_tag);
3008 ah->total_size = SWAP32 (ah->total_size);
3009 ah->data_start = SWAP32 (ah->data_start);
3010 ah->data_length = SWAP32 (ah->data_length);
3011 ah->flags = SWAP16 (ah->flags);
3012 ah->num_attrs = SWAP16 (ah->num_attrs);
3013 #else
3014 (void)ah;
3015 #endif
3016 }
3017
3018 static const u_int32_t emptyfinfo[8] = {0};
3019
3020 /*
3021 * Given an Apple Double file in src, turn it into a
3022 * normal file (possibly with multiple forks, EAs, and
3023 * ACLs) in dst.
3024 */
3025 static int copyfile_unpack(copyfile_state_t s)
3026 {
3027 ssize_t bytes;
3028 void * buffer, * endptr, * dataptr = NULL;
3029 apple_double_header_t *adhdr;
3030 ssize_t hdrsize;
3031 int error = 0;
3032
3033 if (s->sb.st_size < ATTR_MAX_HDR_SIZE)
3034 hdrsize = (ssize_t)s->sb.st_size;
3035 else
3036 hdrsize = ATTR_MAX_HDR_SIZE;
3037
3038 buffer = calloc(1, hdrsize);
3039 if (buffer == NULL) {
3040 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize);
3041 error = -1;
3042 goto exit;
3043 } else
3044 endptr = (char*)buffer + hdrsize;
3045
3046 bytes = pread(s->src_fd, buffer, hdrsize, 0);
3047
3048 if (bytes < 0)
3049 {
3050 copyfile_debug(1, "pread returned: %zd", bytes);
3051 error = -1;
3052 goto exit;
3053 }
3054 if (bytes < hdrsize)
3055 {
3056 copyfile_debug(1,
3057 "pread couldn't read entire header: %d of %d",
3058 (int)bytes, (int)s->sb.st_size);
3059 error = -1;
3060 goto exit;
3061 }
3062 adhdr = (apple_double_header_t *)buffer;
3063
3064 /*
3065 * Check for Apple Double file.
3066 */
3067 if ((size_t)bytes < sizeof(apple_double_header_t) - 2 ||
3068 SWAP32(adhdr->magic) != ADH_MAGIC ||
3069 SWAP32(adhdr->version) != ADH_VERSION ||
3070 SWAP16(adhdr->numEntries) != 2 ||
3071 SWAP32(adhdr->entries[0].type) != AD_FINDERINFO)
3072 {
3073 if (COPYFILE_VERBOSE & s->flags)
3074 copyfile_warn("Not a valid Apple Double header");
3075 error = -1;
3076 goto exit;
3077 }
3078 swap_adhdr(adhdr);
3079
3080 /*
3081 * Remove any extended attributes on the target.
3082 */
3083
3084 if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
3085 {
3086 char *namebuf, *name;
3087
3088 if ((namebuf = (char*) malloc(bytes)) == NULL)
3089 {
3090 s->err = ENOMEM;
3091 goto exit;
3092 }
3093 bytes = flistxattr(s->dst_fd, namebuf, bytes, 0);
3094
3095 if (bytes > 0)
3096 for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1)
3097 (void)fremovexattr(s->dst_fd, name, 0);
3098
3099 free(namebuf);
3100 }
3101 else if (bytes < 0)
3102 {
3103 if (errno != ENOTSUP && errno != EPERM)
3104 goto exit;
3105 }
3106
3107 /*
3108 * Extract the extended attributes.
3109 *
3110 * >>> WARNING <<<
3111 * This assumes that the data is already in memory (not
3112 * the case when there are lots of attributes or one of
3113 * the attributes is very large.
3114 */
3115 if (adhdr->entries[0].length > FINDERINFOSIZE)
3116 {
3117 attr_header_t *attrhdr;
3118 attr_entry_t *entry;
3119 int count;
3120 int i;
3121
3122 if ((size_t)hdrsize < sizeof(attr_header_t)) {
3123 copyfile_warn("bad attribute header: %zu < %zu", hdrsize, sizeof(attr_header_t));
3124 error = -1;
3125 goto exit;
3126 }
3127
3128 attrhdr = (attr_header_t *)buffer;
3129 swap_attrhdr(attrhdr);
3130 if (attrhdr->magic != ATTR_HDR_MAGIC)
3131 {
3132 if (COPYFILE_VERBOSE & s->flags)
3133 copyfile_warn("bad attribute header");
3134 error = -1;
3135 goto exit;
3136 }
3137 count = attrhdr->num_attrs;
3138 entry = (attr_entry_t *)&attrhdr[1];
3139
3140 for (i = 0; i < count; i++)
3141 {
3142 /*
3143 * First we do some simple sanity checking.
3144 * +) See if entry is within the buffer's range;
3145 *
3146 * +) Check the attribute name length; if it's longer than the
3147 * maximum, we truncate it down. (We could error out as well;
3148 * I'm not sure which is the better way to go here.)
3149 *
3150 * +) If, given the name length, it goes beyond the end of
3151 * the buffer, error out.
3152 *
3153 * +) If the last byte isn't a NUL, make it a NUL. (Since we
3154 * truncated the name length above, we truncate the name here.)
3155 *
3156 * +) If entry->offset is so large that it causes dataptr to
3157 * go beyond the end of the buffer -- or, worse, so large that
3158 * it wraps around! -- we error out.
3159 *
3160 * +) If entry->length would cause the entry to go beyond the
3161 * end of the buffer (or, worse, wrap around to before it),
3162 * *or* if the length is larger than the hdrsize, we error out.
3163 * (An explanation of that: what we're checking for there is
3164 * the small range of values such that offset+length would cause
3165 * it to go beyond endptr, and then wrap around past buffer. We
3166 * care about this because we are passing entry->length down to
3167 * fgetxattr() below, and an erroneously large value could cause
3168 * problems there. By making sure that it's less than hdrsize,
3169 * which has already been sanity-checked above, we're safe.
3170 * That may mean that the check against < buffer is unnecessary.)
3171 */
3172 if ((void*)entry >= endptr || (void*)entry < buffer) {
3173 if (COPYFILE_VERBOSE & s->flags)
3174 copyfile_warn("Incomplete or corrupt attribute entry");
3175 error = -1;
3176 s->err = EINVAL;
3177 goto exit;
3178 }
3179
3180 if (((char*)entry + sizeof(*entry)) > (char*)endptr) {
3181 if (COPYFILE_VERBOSE & s->flags)
3182 copyfile_warn("Incomplete or corrupt attribute entry");
3183 error = -1;
3184 s->err = EINVAL;
3185 goto exit;
3186 }
3187
3188 /*
3189 * Endian swap the entry we're looking at. Previously
3190 * we did this swap as part of swap_attrhdr, but that
3191 * allowed a maliciously constructed file to overrun
3192 * our allocation. Instead do the swap after we've verified
3193 * the entry struct is within the buffer's range.
3194 */
3195 swap_attrhdr_entry(entry);
3196
3197 if (entry->namelen < 2) {
3198 if (COPYFILE_VERBOSE & s->flags)
3199 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen);
3200 error = -1;
3201 s->err = EINVAL;
3202 goto exit;
3203 }
3204
3205 if (entry->namelen > XATTR_MAXNAMELEN + 1) {
3206 if (COPYFILE_VERBOSE & s->flags)
3207 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen);
3208 error = -1;
3209 s->err = EINVAL;
3210 goto exit;
3211 }
3212
3213 if ((void*)(entry->name + entry->namelen) > endptr) {
3214 if (COPYFILE_VERBOSE & s->flags)
3215 copyfile_warn("Incomplete or corrupt attribute entry");
3216 error = -1;
3217 s->err = EINVAL;
3218 goto exit;
3219 }
3220
3221 /* Because namelen includes the NUL, we check one byte back */
3222 if (entry->name[entry->namelen-1] != 0) {
3223 if (COPYFILE_VERBOSE & s->flags)
3224 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3225 error = -1;
3226 s->err = EINVAL;
3227 goto exit;
3228 }
3229
3230 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3231 entry->name, entry->length, entry->offset);
3232
3233 #if 0
3234 dataptr = (char *)attrhdr + entry->offset;
3235
3236 if (dataptr > endptr || dataptr < buffer) {
3237 copyfile_debug(1, "Entry %d overflows: offset = %u", i, entry->offset);
3238 error = -1;
3239 s->err = EINVAL; /* Invalid buffer */
3240 goto exit;
3241 }
3242
3243 if (((char*)dataptr + entry->length) > (char*)endptr ||
3244 (((char*)dataptr + entry->length) < (char*)buffer) ||
3245 (entry->length > (size_t)hdrsize)) {
3246 if (COPYFILE_VERBOSE & s->flags)
3247 copyfile_warn("Incomplete or corrupt attribute entry");
3248 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3249 i, entry->offset, entry->length);
3250 error = -1;
3251 s->err = EINVAL; /* Invalid buffer */
3252 goto exit;
3253 }
3254
3255 #else
3256 dataptr = malloc(entry->length);
3257 if (dataptr == NULL) {
3258 copyfile_debug(1, "no memory for %u bytes\n", entry->length);
3259 error = -1;
3260 s->err = ENOMEM;
3261 goto exit;
3262 }
3263 if (pread(s->src_fd, dataptr, entry->length, entry->offset) != (ssize_t)entry->length) {
3264 copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry->length, entry->offset);
3265 error = -1;
3266 s->err = EINVAL;
3267 goto exit;
3268 }
3269 #endif
3270
3271 if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
3272 {
3273 qtn_file_t tqinfo = NULL;
3274
3275 if (s->qinfo == NULL)
3276 {
3277 tqinfo = qtn_file_alloc();
3278 if (tqinfo)
3279 {
3280 int x;
3281 if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0)
3282 {
3283 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x));
3284 qtn_file_free(tqinfo);
3285 tqinfo = NULL;
3286 }
3287 }
3288 }
3289 else
3290 {
3291 tqinfo = s->qinfo;
3292 }
3293 if (tqinfo)
3294 {
3295 int x;
3296 x = qtn_file_apply_to_fd(tqinfo, s->dst_fd);
3297 if (x != 0) {
3298 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x));
3299 if (s->statuscb) {
3300 int rv;
3301 s->xattr_name = (char*)XATTR_QUARANTINE_NAME;
3302 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3303 s->xattr_name = NULL;
3304 if (rv == COPYFILE_QUIT) {
3305 error = s->err = x < 0 ? ENOTSUP : errno;
3306 goto exit;
3307 }
3308 } else {
3309 error = s->err = x < 0 ? ENOTSUP : errno;
3310 goto exit;
3311 }
3312 }
3313 }
3314 if (tqinfo && !s->qinfo)
3315 {
3316 qtn_file_free(tqinfo);
3317 }
3318 }
3319 /* Look for ACL data */
3320 else if (strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)
3321 {
3322 acl_t acl;
3323 struct stat sb;
3324 int retry = 1;
3325 char *tcp = dataptr;
3326
3327 if (entry->length == 0) {
3328 /* Not sure how we got here, but we had one case
3329 * where it was 0. In a normal EA, we can have a 0-byte
3330 * payload. That means nothing in this case, so we'll
3331 * simply skip the EA.
3332 */
3333 error = 0;
3334 goto acl_done;
3335 }
3336 /*
3337 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3338 * however, may not be NUL-terminated. So in that case, we need to
3339 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3340 */
3341 if (tcp[entry->length - 1] != 0) {
3342 char *tmpstr = malloc(entry->length + 1);
3343 if (tmpstr == NULL) {
3344 error = -1;
3345 goto exit;
3346 }
3347 strlcpy(tmpstr, tcp, entry->length + 1);
3348 acl = acl_from_text(tmpstr);
3349 free(tmpstr);
3350 } else {
3351 acl = acl_from_text(tcp);
3352 }
3353
3354 if (acl != NULL)
3355 {
3356 filesec_t fsec_tmp;
3357
3358 if ((fsec_tmp = filesec_init()) == NULL)
3359 error = -1;
3360 else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0)
3361 error = -1;
3362 else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0)
3363 error = -1;
3364 else {
3365 while (fchmodx_np(s->dst_fd, fsec_tmp) < 0)
3366 {
3367 if (errno == ENOTSUP)
3368 {
3369 if (retry && !copyfile_unset_acl(s))
3370 {
3371 retry = 0;
3372 continue;
3373 }
3374 }
3375 copyfile_warn("setting security information");
3376 error = -1;
3377 break;
3378 }
3379 }
3380 acl_free(acl);
3381 filesec_free(fsec_tmp);
3382
3383 acl_done:
3384 if (error == -1)
3385 goto exit;
3386 }
3387 }
3388 /* And, finally, everything else */
3389 else
3390 {
3391 if (s->copyIntent ||
3392 xattr_preserve_for_intent((char*)entry->name, s->copyIntent) == 1) {
3393 if (s->statuscb) {
3394 int rv;
3395 s->xattr_name = strdup((char*)entry->name);
3396 s->totalCopied = 0;
3397 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3398 if (s->xattr_name) {
3399 free(s->xattr_name);
3400 s->xattr_name = NULL;
3401 }
3402 if (rv == COPYFILE_QUIT) {
3403 s->err = ECANCELED;
3404 error = -1;
3405 goto exit;
3406 }
3407 }
3408 if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
3409 if (COPYFILE_VERBOSE & s->flags)
3410 copyfile_warn("error %d setting attribute %s", errno, entry->name);
3411 if (s->statuscb) {
3412 int rv;
3413
3414 s->xattr_name = strdup((char*)entry->name);
3415 rv = (s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3416 if (s->xattr_name) {
3417 free(s->xattr_name);
3418 s->xattr_name = NULL;
3419 }
3420 if (rv == COPYFILE_QUIT) {
3421 error = -1;
3422 goto exit;
3423 }
3424 } else {
3425 error = -1;
3426 goto exit;
3427 }
3428 } else if (s->statuscb) {
3429 int rv;
3430 s->xattr_name = strdup((char*)entry->name);
3431 s->totalCopied = entry->length;
3432 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3433 if (s->xattr_name) {
3434 free(s->xattr_name);
3435 s->xattr_name = NULL;
3436 }
3437 if (rv == COPYFILE_QUIT) {
3438 error = -1;
3439 s->err = ECANCELED;
3440 goto exit;
3441 }
3442 }
3443 }
3444 }
3445 if (dataptr) {
3446 free(dataptr);
3447 dataptr = NULL;
3448 }
3449 entry = ATTR_NEXT(entry);
3450 }
3451 }
3452
3453 /*
3454 * Extract the Finder Info.
3455 */
3456 if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) {
3457 error = -1;
3458 goto exit;
3459 }
3460
3461 if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0)
3462 {
3463 uint16_t *fFlags;
3464 uint8_t *newFinfo;
3465 enum { kFinderInvisibleMask = 1 << 14 };
3466
3467 newFinfo = (u_int8_t*)buffer + adhdr->entries[0].offset;
3468 fFlags = (uint16_t*)&newFinfo[8];
3469 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME);
3470 if (s->statuscb) {
3471 int rv;
3472 s->xattr_name = (char*)XATTR_FINDERINFO_NAME;
3473 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3474 s->xattr_name = NULL;
3475 if (rv == COPYFILE_QUIT) {
3476 error = -1;
3477 s->err = ECANCELED;
3478 goto exit;
3479 } else if (rv == COPYFILE_SKIP) {
3480 goto skip_fi;
3481 }
3482 }
3483 error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0);
3484 if (error) {
3485 if (s->statuscb) {
3486 int rv;
3487 s->xattr_name = (char *)XATTR_FINDERINFO_NAME;
3488 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3489 s->xattr_name = NULL;
3490 if (rv == COPYFILE_QUIT) {
3491 error = -1;
3492 s->err = ECANCELED;
3493 goto exit;
3494 }
3495 }
3496 goto exit;
3497 } else if (s->statuscb) {
3498 int rv;
3499 s->xattr_name = (char *)XATTR_FINDERINFO_NAME;
3500 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3501 s->xattr_name = NULL;
3502 if (rv == COPYFILE_QUIT) {
3503 error = -1;
3504 s->err = ECANCELED;
3505 goto exit;
3506 }
3507 }
3508 if (SWAP16(*fFlags) & kFinderInvisibleMask)
3509 s->internal_flags |= cfMakeFileInvisible;
3510 }
3511 skip_fi:
3512
3513 /*
3514 * Extract the Resource Fork.
3515 */
3516 if (adhdr->entries[1].type == AD_RESOURCE &&
3517 adhdr->entries[1].length > 0)
3518 {
3519 void * rsrcforkdata = NULL;
3520 size_t length;
3521 off_t offset;
3522 struct stat sb;
3523 struct timeval tval[2];
3524
3525 length = adhdr->entries[1].length;
3526 offset = adhdr->entries[1].offset;
3527 rsrcforkdata = malloc(length);
3528
3529 if (rsrcforkdata == NULL) {
3530 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3531 length);
3532 error = -1;
3533 goto bad;
3534 }
3535
3536 if (fstat(s->dst_fd, &sb) < 0)
3537 {
3538 copyfile_debug(1, "couldn't stat destination file");
3539 error = -1;
3540 goto bad;
3541 }
3542
3543 bytes = pread(s->src_fd, rsrcforkdata, length, offset);
3544 if (bytes < (ssize_t)length)
3545 {
3546 if (bytes == -1)
3547 {
3548 copyfile_debug(1, "couldn't read resource fork");
3549 }
3550 else
3551 {
3552 copyfile_debug(1,
3553 "couldn't read resource fork (only read %d bytes of %d)",
3554 (int)bytes, (int)length);
3555 }
3556 error = -1;
3557 goto bad;
3558 }
3559 if (s->statuscb) {
3560 int rv;
3561 s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
3562 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3563 s->xattr_name = NULL;
3564 if (rv == COPYFILE_QUIT) {
3565 error = -1;
3566 s->err = ECANCELED;
3567 if (rsrcforkdata)
3568 free(rsrcforkdata);
3569 goto exit;
3570 } else if (rv == COPYFILE_SKIP) {
3571 goto bad;
3572 }
3573 }
3574 error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0);
3575 if (error)
3576 {
3577 /*
3578 * For filesystems that do not natively support named attributes,
3579 * the kernel creates an AppleDouble file that -- for compatabilty
3580 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3581 * structure that says there are no resources. So, if fsetxattr has
3582 * failed, and the resource fork is that empty structure, *and* the
3583 * target file is a directory, then we do nothing with it.
3584 */
3585 if ((bytes == sizeof(rsrcfork_header_t)) &&
3586 ((sb.st_mode & S_IFMT) == S_IFDIR) &&
3587 (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) {
3588 copyfile_debug(2, "not setting empty resource fork on directory");
3589 error = errno = 0;
3590 goto bad;
3591 }
3592 if (s->statuscb) {
3593 int rv;
3594 s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
3595 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3596 s->xattr_name = NULL;
3597 if (rv == COPYFILE_CONTINUE) {
3598 error = errno = 0;
3599 goto bad;
3600 }
3601 }
3602 copyfile_debug(1, "error %d setting resource fork attribute", error);
3603 error = -1;
3604 goto bad;
3605 } else if (s->statuscb) {
3606 int rv;
3607 s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
3608 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3609 s->xattr_name = NULL;
3610 if (rv == COPYFILE_QUIT) {
3611 error = -1;
3612 s->err = ECANCELED;
3613 if (rsrcforkdata)
3614 free(rsrcforkdata);
3615 goto exit;
3616 }
3617 }
3618 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3619 XATTR_RESOURCEFORK_NAME, (int)length);
3620
3621 if (!(s->flags & COPYFILE_STAT))
3622 {
3623 tval[0].tv_sec = sb.st_atime;
3624 tval[1].tv_sec = sb.st_mtime;
3625 tval[0].tv_usec = tval[1].tv_usec = 0;
3626
3627 if (futimes(s->dst_fd, tval))
3628 copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
3629 }
3630 bad:
3631 if (rsrcforkdata)
3632 free(rsrcforkdata);
3633 }
3634
3635 if (COPYFILE_STAT & s->flags)
3636 {
3637 error = copyfile_stat(s);
3638 }
3639 exit:
3640 if (buffer) free(buffer);
3641 if (dataptr) free(dataptr);
3642 return error;
3643 }
3644
3645 static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len)
3646 {
3647 int ret = 0;
3648 char qbuf[QTN_SERIALIZED_DATA_MAX];
3649 size_t qlen = sizeof(qbuf);
3650
3651 if (s->qinfo == NULL)
3652 {
3653 ret = -1;
3654 goto done;
3655 }
3656
3657 if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0)
3658 {
3659 ret = -1;
3660 goto done;
3661 }
3662
3663 *buf = malloc(qlen);
3664 if (*buf)
3665 {
3666 memcpy(*buf, qbuf, qlen);
3667 *len = qlen;
3668 }
3669 done:
3670 return ret;
3671 }
3672
3673 static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len)
3674 {
3675 int ret = 0;
3676 acl_t acl = NULL;
3677 char *acl_text;
3678
3679 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0)
3680 {
3681 if (errno != ENOENT)
3682 {
3683 ret = -1;
3684 if (COPYFILE_VERBOSE & s->flags)
3685 copyfile_warn("getting acl");
3686 }
3687 *len = 0;
3688 goto exit;
3689 }
3690
3691 if ((acl_text = acl_to_text(acl, len)) != NULL)
3692 {
3693 /*
3694 * acl_to_text() doesn't include the NUL at the endo
3695 * in it's count (*len). It does, however, promise to
3696 * return a valid C string, so we need to up the count
3697 * by 1.
3698 */
3699 *len = *len + 1;
3700 *buf = malloc(*len);
3701 if (*buf)
3702 memcpy(*buf, acl_text, *len);
3703 else
3704 *len = 0;
3705 acl_free(acl_text);
3706 }
3707 copyfile_debug(2, "copied acl (%ld) %p", *len, *buf);
3708 exit:
3709 if (acl)
3710 acl_free(acl);
3711 return ret;
3712 }
3713
3714 static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr)
3715 {
3716 ssize_t datasize;
3717 char *databuf = NULL;
3718 int ret = 0;
3719
3720 /*
3721 * XXX
3722 * do COPYFILE_COPY_XATTR here; no need to
3723 * the work if we want to skip.
3724 */
3725
3726 if (s->statuscb)
3727 {
3728 int rv;
3729
3730 s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME;
3731
3732 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3733 s->xattr_name = NULL;
3734 if (rv == COPYFILE_SKIP) {
3735 ret = 0;
3736 goto done;
3737 }
3738 if (rv == COPYFILE_QUIT) {
3739 ret = -1;
3740 s->err = ECANCELED;
3741 goto done;
3742 }
3743 }
3744 /* Get the resource fork size */
3745 if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0)
3746 {
3747 if (COPYFILE_VERBOSE & s->flags)
3748 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno);
3749 return -1;
3750 }
3751
3752 if (datasize > INT_MAX) {
3753 s->err = EINVAL;
3754 ret = -1;
3755 goto done;
3756 }
3757
3758 if (s->statuscb) {
3759 int rv;
3760 s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME;
3761
3762 s->totalCopied = 0;
3763 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
3764 s->xattr_name = NULL;
3765 if (rv == COPYFILE_QUIT) {
3766 s->err = ECANCELED;
3767 ret = -1;
3768 goto done;
3769 }
3770 }
3771 if ((databuf = malloc(datasize)) == NULL)
3772 {
3773 copyfile_warn("malloc");
3774 ret = -1;
3775 goto done;
3776 }
3777
3778 if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize)
3779 {
3780 if (COPYFILE_VERBOSE & s->flags)
3781 copyfile_warn("couldn't read entire resource fork");
3782 ret = -1;
3783 goto done;
3784 }
3785
3786 /* Write the resource fork to disk. */
3787 if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize)
3788 {
3789 if (COPYFILE_VERBOSE & s->flags)
3790 copyfile_warn("couldn't write resource fork");
3791 }
3792 if (s->statuscb)
3793 {
3794 int rv;
3795 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3796 if (rv == COPYFILE_QUIT) {
3797 ret = -1;
3798 goto done;
3799 }
3800 }
3801 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3802 datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset);
3803 filehdr->appledouble.entries[1].length = (u_int32_t)datasize;
3804
3805 done:
3806 if (ret == -1 && s->statuscb)
3807 {
3808 int rv;
3809 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3810 if (rv == COPYFILE_CONTINUE)
3811 ret = 0;
3812 }
3813 if (s->xattr_name) {
3814 s->xattr_name = NULL;
3815 }
3816 if (databuf)
3817 free(databuf);
3818
3819 /*
3820 * XXX
3821 * Do status callback here
3822 * If ret == -1, then error callback
3823 */
3824 return ret;
3825 }
3826
3827 /*
3828 * The opposite of copyfile_unpack(), obviously.
3829 */
3830 static int copyfile_pack(copyfile_state_t s)
3831 {
3832 char *attrnamebuf = NULL, *endnamebuf;
3833 void *databuf = NULL;
3834 attr_header_t *filehdr, *endfilehdr;
3835 attr_entry_t *entry;
3836 ssize_t listsize = 0;
3837 char *nameptr;
3838 size_t namelen;
3839 size_t entrylen;
3840 ssize_t datasize;
3841 size_t offset = 0;
3842 int hasrsrcfork = 0;
3843 int error = 0;
3844 int seenq = 0; // Have we seen any quarantine info already?
3845
3846 filehdr = (attr_header_t *) calloc(1, ATTR_MAX_HDR_SIZE);
3847
3848 if (filehdr == NULL) {
3849 error = -1;
3850 goto exit;
3851 } else {
3852 endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_HDR_SIZE);
3853 }
3854
3855 attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
3856 if (attrnamebuf == NULL) {
3857 error = -1;
3858 goto exit;
3859 } else {
3860 endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE;
3861 }
3862
3863 /*
3864 * Fill in the Apple Double Header defaults.
3865 */
3866 filehdr->appledouble.magic = ADH_MAGIC;
3867 filehdr->appledouble.version = ADH_VERSION;
3868 filehdr->appledouble.numEntries = 2;
3869 filehdr->appledouble.entries[0].type = AD_FINDERINFO;
3870 filehdr->appledouble.entries[0].offset = (u_int32_t)offsetof(apple_double_header_t, finfo);
3871 filehdr->appledouble.entries[0].length = FINDERINFOSIZE;
3872 filehdr->appledouble.entries[1].type = AD_RESOURCE;
3873 filehdr->appledouble.entries[1].offset = (u_int32_t)offsetof(apple_double_header_t, pad);
3874 filehdr->appledouble.entries[1].length = 0;
3875 bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler));
3876
3877 /*
3878 * Fill in the initial Attribute Header.
3879 */
3880 filehdr->magic = ATTR_HDR_MAGIC;
3881 filehdr->debug_tag = 0;
3882 filehdr->data_start = (u_int32_t)sizeof(attr_header_t);
3883
3884 /*
3885 * Collect the attribute names.
3886 */
3887 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3888
3889 /*
3890 * Test if there are acls to copy
3891 */
3892 if (COPYFILE_ACL & s->flags)
3893 {
3894 acl_t temp_acl = NULL;
3895 if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0)
3896 {
3897 copyfile_debug(2, "no acl entries found (errno = %d)", errno);
3898 } else
3899 {
3900 offset = strlen(XATTR_SECURITY_NAME) + 1;
3901 strcpy(attrnamebuf, XATTR_SECURITY_NAME);
3902 endnamebuf = attrnamebuf + offset;
3903 }
3904 if (temp_acl)
3905 acl_free(temp_acl);
3906 }
3907
3908 if (COPYFILE_XATTR & s->flags)
3909 {
3910 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3911 if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0)
3912 {
3913 copyfile_debug(2, "no extended attributes found (%d)", errno);
3914 }
3915 if (listsize > left)
3916 {
3917 copyfile_debug(1, "extended attribute list too long");
3918 listsize = left;
3919 }
3920
3921 endnamebuf = attrnamebuf + offset + (listsize > 0 ? listsize : 0);
3922 if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) {
3923 error = -1;
3924 goto exit;
3925 }
3926
3927 if (listsize > 0)
3928 sort_xattrname_list(attrnamebuf, endnamebuf - attrnamebuf);
3929
3930 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen)
3931 {
3932 namelen = strlen(nameptr) + 1;
3933 /* Skip over FinderInfo or Resource Fork names */
3934 if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 ||
3935 strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) {
3936 continue;
3937 }
3938 if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) {
3939 seenq = 1;
3940 }
3941
3942 /* The system should prevent this from happening, but... */
3943 if (namelen > XATTR_MAXNAMELEN + 1) {
3944 namelen = XATTR_MAXNAMELEN + 1;
3945 }
3946 if (s->copyIntent &&
3947 xattr_preserve_for_intent(nameptr, s->copyIntent) == 0) {
3948 // Skip it
3949 size_t amt = endnamebuf - (nameptr + namelen);
3950 memmove(nameptr, nameptr + namelen, amt);
3951 endnamebuf -= namelen;
3952 /* Set namelen to 0 so continue doesn't miss names */
3953 namelen = 0;
3954 continue;
3955 }
3956
3957 if (s->statuscb) {
3958 int rv;
3959 char eaname[namelen];
3960 bcopy(nameptr, eaname, namelen);
3961 eaname[namelen - 1] = 0; // Just to be sure!
3962 s->xattr_name = eaname;
3963 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3964 s->xattr_name = NULL;
3965 if (rv == COPYFILE_QUIT) {
3966 error = -1;
3967 s->err = ECANCELED;
3968 goto exit;
3969 } else if (rv == COPYFILE_SKIP) {
3970 size_t amt = endnamebuf - (nameptr + namelen);
3971 memmove(nameptr, nameptr + namelen, amt);
3972 endnamebuf -= namelen;
3973 /* Set namelen to 0 so continue doesn't miss names */
3974 namelen = 0;
3975 continue;
3976 }
3977 }
3978 entry->namelen = namelen;
3979 entry->flags = 0;
3980 if (nameptr + namelen > endnamebuf) {
3981 error = -1;
3982 goto exit;
3983 }
3984
3985 bcopy(nameptr, &entry->name[0], namelen);
3986 copyfile_debug(2, "copied name [%s]", entry->name);
3987
3988 entrylen = ATTR_ENTRY_LENGTH(namelen);
3989 entry = (attr_entry_t *)(((char *)entry) + entrylen);
3990
3991 if ((void*)entry >= (void*)endfilehdr) {
3992 error = -1;
3993 goto exit;
3994 }
3995
3996 /* Update the attributes header. */
3997 filehdr->num_attrs++;
3998 filehdr->data_start += (u_int32_t)entrylen;
3999 }
4000 }
4001
4002 /*
4003 * If we have any quarantine data, we always pack it.
4004 * But if we've already got it in the EA list, don't put it in again.
4005 */
4006 if (s->qinfo && !seenq)
4007 {
4008 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
4009 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
4010 offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1;
4011 }
4012
4013 seenq = 0;
4014 /*
4015 * Collect the attribute data.
4016 */
4017 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
4018
4019 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen + 1)
4020 {
4021 namelen = strlen(nameptr);
4022
4023 if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0)
4024 copyfile_pack_acl(s, &databuf, &datasize);
4025 else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0)
4026 {
4027 copyfile_pack_quarantine(s, &databuf, &datasize);
4028 }
4029 /* Check for Finder Info. */
4030 else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0)
4031 {
4032 if (s->statuscb)
4033 {
4034 int rv;
4035 s->xattr_name = (char*)XATTR_FINDERINFO_NAME;
4036 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
4037 s->xattr_name = NULL;
4038 if (rv == COPYFILE_QUIT)
4039 {
4040 s->xattr_name = NULL;
4041 s->err = ECANCELED;
4042 error = -1;
4043 goto exit;
4044 }
4045 else if (rv == COPYFILE_SKIP)
4046 {
4047 s->xattr_name = NULL;
4048 continue;
4049 }
4050 s->totalCopied = 0;
4051 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
4052 s->xattr_name = NULL;
4053 if (rv == COPYFILE_QUIT)
4054 {
4055 s->err = ECANCELED;
4056 error = -1;
4057 goto exit;
4058 }
4059 }
4060 datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0);
4061 if (datasize < 0)
4062 {
4063 if (s->statuscb) {
4064 int rv;
4065 s->xattr_name = strdup(nameptr);
4066 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
4067 if (s->xattr_name) {
4068 free(s->xattr_name);
4069 s->xattr_name = NULL;
4070 }
4071 if (rv == COPYFILE_QUIT) {
4072 error = -1;
4073 goto exit;
4074 }
4075 }
4076 if (COPYFILE_VERBOSE & s->flags)
4077 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
4078 } else if (datasize != 32)
4079 {
4080 if (COPYFILE_VERBOSE & s->flags)
4081 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr);
4082 } else
4083 {
4084 if (COPYFILE_VERBOSE & s->flags)
4085 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
4086 XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset);
4087 if (s->statuscb) {
4088 int rv;
4089 s->xattr_name = strdup(nameptr);
4090 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
4091 if (s->xattr_name) {
4092 free(s->xattr_name);
4093 s->xattr_name = NULL;
4094 }
4095 if (rv == COPYFILE_QUIT) {
4096 error = -1;
4097 goto exit;
4098 }
4099 }
4100 }
4101 continue; /* finder info doesn't have an attribute entry */
4102 }
4103 /* Check for Resource Fork. */
4104 else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0)
4105 {
4106 hasrsrcfork = 1;
4107 continue;
4108 } else
4109 {
4110 /* Just a normal attribute. */
4111 if (s->statuscb)
4112 {
4113 int rv;
4114 s->xattr_name = strdup(nameptr);
4115 s->totalCopied = 0;
4116 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
4117 if (s->xattr_name) {
4118 free(s->xattr_name);
4119 s->xattr_name = NULL;
4120 }
4121 /*
4122 * Due to the nature of the packed file, we can't skip at this point.
4123 */
4124 if (rv == COPYFILE_QUIT)
4125 {
4126 s->err = ECANCELED;
4127 error = -1;
4128 goto exit;
4129 }
4130 }
4131 datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0);
4132 if (datasize == 0)
4133 goto next;
4134 if (datasize < 0)
4135 {
4136 if (COPYFILE_VERBOSE & s->flags)
4137 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
4138 if (s->statuscb)
4139 {
4140 int rv;
4141 s->xattr_name = strdup(nameptr);
4142 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
4143 if (s->xattr_name) {
4144 free(s->xattr_name);
4145 s->xattr_name = NULL;
4146 }
4147 if (rv == COPYFILE_QUIT)
4148 {
4149 s->err = ECANCELED;
4150 error = -1;
4151 goto exit;
4152 }
4153 }
4154 goto next;
4155 }
4156 if (datasize > XATTR_MAXATTRLEN)
4157 {
4158 if (COPYFILE_VERBOSE & s->flags)
4159 copyfile_warn("skipping attr \"%s\" (too big)", nameptr);
4160 goto next;
4161 }
4162 databuf = malloc(datasize);
4163 if (databuf == NULL) {
4164 error = -1;
4165 continue;
4166 }
4167 datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0);
4168 if (s->statuscb) {
4169 int rv;
4170 s->xattr_name = strdup(nameptr);
4171 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
4172 if (s->xattr_name) {
4173 free(s->xattr_name);
4174 s->xattr_name = NULL;
4175 }
4176 if (rv == COPYFILE_QUIT) {
4177 s->err = ECANCELED;
4178 error = -1;
4179 goto exit;
4180 }
4181 }
4182 }
4183
4184 entry->length = (u_int32_t)datasize;
4185 entry->offset = filehdr->data_start + filehdr->data_length;
4186
4187 filehdr->data_length += (u_int32_t)datasize;
4188 #if 0
4189 /*
4190 * >>> WARNING <<<
4191 * This assumes that the data is fits in memory (not
4192 * the case when there are lots of attributes or one of
4193 * the attributes is very large.
4194 */
4195 if (entry->offset > ATTR_MAX_SIZE ||
4196 (entry->offset + datasize > ATTR_MAX_SIZE)) {
4197 error = 1;
4198 } else {
4199 bcopy(databuf, (char*)filehdr + entry->offset, datasize);
4200 }
4201 #else
4202 if (pwrite(s->dst_fd, databuf, datasize, entry->offset) != datasize) {
4203 error = 1;
4204 }
4205 #endif
4206 free(databuf);
4207
4208 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
4209 next:
4210 /* bump to next entry */
4211 entrylen = ATTR_ENTRY_LENGTH(entry->namelen);
4212 entry = (attr_entry_t *)((char *)entry + entrylen);
4213 }
4214
4215 /* Now we know where the resource fork data starts. */
4216 filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
4217
4218 /* We also know the size of the "Finder Info entry. */
4219 filehdr->appledouble.entries[0].length =
4220 filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
4221
4222 filehdr->total_size = filehdr->appledouble.entries[1].offset;
4223
4224 /* Copy Resource Fork. */
4225 if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
4226 goto exit;
4227
4228 /* Write the header to disk. */
4229 datasize = filehdr->data_start;
4230
4231 swap_adhdr(&filehdr->appledouble);
4232 swap_attrhdr(filehdr);
4233 swap_attrhdr_entries(filehdr);
4234
4235 if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize)
4236 {
4237 if (COPYFILE_VERBOSE & s->flags)
4238 copyfile_warn("couldn't write file header");
4239 error = -1;
4240 goto exit;
4241 }
4242 exit:
4243 if (filehdr) free(filehdr);
4244 if (attrnamebuf) free(attrnamebuf);
4245
4246 if (error)
4247 return error;
4248 else
4249 return copyfile_stat(s);
4250 }