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