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