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