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