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