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