]> git.saurik.com Git - apple/copyfile.git/blob - copyfile.c
a1861ea2f4dbf992a660be6cd22c434272a11ed3
[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 ((NAME) && (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) {
1002 filesec_free(s->original_fsec);
1003 s->original_fsec = NULL;
1004 }
1005 if ((s->original_fsec = filesec_init()) == NULL)
1006 goto error_exit;
1007
1008 if ((s->flags & COPYFILE_NOFOLLOW_DST) && lstat(s->dst, &dst_sb) == 0 &&
1009 ((dst_sb.st_mode & S_IFMT) == S_IFLNK)) {
1010 if (s->permissive_fsec)
1011 free(s->permissive_fsec);
1012 s->permissive_fsec = NULL;
1013 } else if(statx_np(s->dst, &dst_sb, s->original_fsec) == 0)
1014 {
1015 /*
1016 * copyfile_fix_perms() will make a copy of the permission set,
1017 * and insert at the beginning an ACE that ensures we can write
1018 * to the file and set attributes.
1019 */
1020
1021 if((s->permissive_fsec = copyfile_fix_perms(s, &s->original_fsec)) != NULL)
1022 {
1023 /*
1024 * Set the permissions for the destination to our copy.
1025 * We should get ENOTSUP from any filesystem that simply
1026 * doesn't support it.
1027 */
1028 if (chmodx_np(s->dst, s->permissive_fsec) < 0 && errno != ENOTSUP)
1029 {
1030 copyfile_warn("setting security information");
1031 filesec_free(s->permissive_fsec);
1032 s->permissive_fsec = NULL;
1033 }
1034 }
1035 } else if (errno == ENOENT) {
1036 createdst = 1;
1037 }
1038
1039 /*
1040 * If COPYFILE_CHECK is set in flags, then all we are going to do
1041 * is see what kinds of things WOULD have been copied (see
1042 * copyfile_check() below). We return that value.
1043 */
1044 if (COPYFILE_CHECK & flags)
1045 {
1046 ret = copyfile_check(s);
1047 goto exit;
1048 } else if ((ret = copyfile_open(s)) < 0)
1049 goto error_exit;
1050
1051 (void)fcntl(s->src_fd, F_NOCACHE, 1);
1052 (void)fcntl(s->dst_fd, F_NOCACHE, 1);
1053
1054 ret = copyfile_internal(s, flags);
1055 if (ret == -1)
1056 goto error_exit;
1057
1058 #ifdef COPYFILE_RECURSIVE
1059 if (!(flags & COPYFILE_STAT)) {
1060 if (!createdst)
1061 {
1062 /* Just need to reset the BSD information -- mode, owner, group */
1063 (void)fchown(s->dst_fd, dst_sb.st_uid, dst_sb.st_gid);
1064 (void)fchmod(s->dst_fd, dst_sb.st_mode);
1065 }
1066 }
1067 #endif
1068
1069 reset_security(s);
1070
1071 if (s->src && (flags & COPYFILE_MOVE))
1072 (void)remove(s->src);
1073
1074 exit:
1075 if (state == NULL) {
1076 int t = errno;
1077 copyfile_state_free(s);
1078 errno = t;
1079 }
1080
1081 return ret;
1082
1083 error_exit:
1084 ret = -1;
1085 if (s->err) {
1086 errno = s->err;
1087 s->err = 0;
1088 }
1089 goto exit;
1090 }
1091
1092 /*
1093 * Shared prelude to the {f,}copyfile(). This initializes the
1094 * state variable, if necessary, and also checks for both debugging
1095 * and disabling environment variables.
1096 */
1097 static int copyfile_preamble(copyfile_state_t *state, copyfile_flags_t flags)
1098 {
1099 copyfile_state_t s;
1100
1101 if (*state == NULL)
1102 {
1103 if ((*state = copyfile_state_alloc()) == NULL)
1104 return -1;
1105 }
1106
1107 s = *state;
1108
1109 if (COPYFILE_DEBUG & flags)
1110 {
1111 char *e;
1112 if ((e = getenv(COPYFILE_DEBUG_VAR)))
1113 {
1114 errno = 0;
1115 s->debug = (uint32_t)strtol(e, NULL, 0);
1116
1117 /* clamp s->debug to 1 if the environment variable is not parsable */
1118 if (s->debug == 0 && errno != 0)
1119 s->debug = 1;
1120 }
1121 copyfile_debug(2, "debug value set to: %d", s->debug);
1122 }
1123
1124 #if 0
1125 /* Temporarily disabled */
1126 if (getenv(COPYFILE_DISABLE_VAR) != NULL)
1127 {
1128 copyfile_debug(1, "copyfile disabled");
1129 return 2;
1130 }
1131 #endif
1132 copyfile_debug(2, "setting flags: %d", s->flags);
1133 s->flags = flags;
1134
1135 return 0;
1136 }
1137
1138 /*
1139 * The guts of {f,}copyfile().
1140 * This looks through the flags in a particular order, and calls the
1141 * associated functions.
1142 */
1143 static int copyfile_internal(copyfile_state_t s, copyfile_flags_t flags)
1144 {
1145 int ret = 0;
1146
1147 if (s->dst_fd < 0 || s->src_fd < 0)
1148 {
1149 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s->src_fd, s->dst_fd);
1150 s->err = EINVAL;
1151 return -1;
1152 }
1153
1154 /*
1155 * COPYFILE_PACK causes us to create an Apple Double version of the
1156 * source file, and puts it into the destination file. See
1157 * copyfile_pack() below for all the gory details.
1158 */
1159 if (COPYFILE_PACK & flags)
1160 {
1161 if ((ret = copyfile_pack(s)) < 0)
1162 {
1163 if (s->dst) unlink(s->dst);
1164 goto exit;
1165 }
1166 goto exit;
1167 }
1168
1169 /*
1170 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
1171 * The goal there is to take an Apple Double file, and turn it
1172 * into a normal file (with data fork, resource fork, modes,
1173 * extended attributes, ACLs, etc.).
1174 */
1175 if (COPYFILE_UNPACK & flags)
1176 {
1177 if ((ret = copyfile_unpack(s)) < 0)
1178 goto error_exit;
1179 goto exit;
1180 }
1181
1182 /*
1183 * If we have quarantine info set, we attempt
1184 * to apply it to dst_fd. We don't care if
1185 * it fails, not yet anyway.
1186 */
1187 if (s->qinfo) {
1188 int qr = qtn_file_apply_to_fd(s->qinfo, s->dst_fd);
1189 if (qr != 0) {
1190 if (s->statuscb) {
1191 int rv;
1192
1193 s->xattr_name = (char*)XATTR_QUARANTINE_NAME;
1194 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
1195 s->xattr_name = NULL;
1196 if (rv == COPYFILE_QUIT) {
1197 s->err = errno = (qr < 0 ? ENOTSUP : qr);
1198 ret = -1;
1199 goto exit;
1200 }
1201 } else {
1202 s->err = errno = (qr < 0 ? ENOTSUP : qr);
1203 ret = -1;
1204 goto exit;
1205 }
1206 }
1207 }
1208
1209 /*
1210 * COPYFILE_XATTR tells us to copy the extended attributes;
1211 * this is seperate from the extended security (aka ACLs),
1212 * however. If we succeed in this, we continue to the next
1213 * stage; if we fail, we return with an error value. Note
1214 * that we fail if the errno is ENOTSUP, but we don't print
1215 * a warning in that case.
1216 */
1217 if (COPYFILE_XATTR & flags)
1218 {
1219 if ((ret = copyfile_xattr(s)) < 0)
1220 {
1221 if (errno != ENOTSUP && errno != EPERM)
1222 copyfile_warn("error processing extended attributes");
1223 goto exit;
1224 }
1225 }
1226
1227 /*
1228 * Simialr to above, this tells us whether or not to copy
1229 * the non-meta data portion of the file. We attempt to
1230 * remove (via unlink) the destination file if we fail.
1231 */
1232 if (COPYFILE_DATA & flags)
1233 {
1234 if ((ret = copyfile_data(s)) < 0)
1235 {
1236 copyfile_warn("error processing data");
1237 if (s->dst && unlink(s->dst))
1238 copyfile_warn("%s: remove", s->src ? s->src : "(null src)");
1239 goto exit;
1240 }
1241 }
1242
1243 /*
1244 * COPYFILE_SECURITY requests that we copy the security, both
1245 * extended and mundane (that is, ACLs and POSIX).
1246 */
1247 if (COPYFILE_SECURITY & flags)
1248 {
1249 if ((ret = copyfile_security(s)) < 0)
1250 {
1251 copyfile_warn("error processing security information");
1252 goto exit;
1253 }
1254 }
1255
1256 if (COPYFILE_STAT & flags)
1257 {
1258 if ((ret = copyfile_stat(s)) < 0)
1259 {
1260 copyfile_warn("error processing POSIX information");
1261 goto exit;
1262 }
1263 }
1264
1265 exit:
1266 return ret;
1267
1268 error_exit:
1269 ret = -1;
1270 goto exit;
1271 }
1272
1273 /*
1274 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1275 */
1276 copyfile_state_t copyfile_state_alloc(void)
1277 {
1278 copyfile_state_t s = (copyfile_state_t) calloc(1, sizeof(struct _copyfile_state));
1279
1280 if (s != NULL)
1281 {
1282 s->src_fd = -2;
1283 s->dst_fd = -2;
1284 if (s->fsec) {
1285 filesec_free(s->fsec);
1286 s->fsec = NULL;
1287 }
1288 s->fsec = filesec_init();
1289 } else
1290 errno = ENOMEM;
1291
1292 return s;
1293 }
1294
1295 /*
1296 * copyfile_state_free() returns the memory allocated to the state structure.
1297 * It also closes the file descriptors, if they've been opened.
1298 */
1299 int copyfile_state_free(copyfile_state_t s)
1300 {
1301 if (s != NULL)
1302 {
1303 if (s->fsec)
1304 filesec_free(s->fsec);
1305
1306 if (s->original_fsec)
1307 filesec_free(s->original_fsec);
1308
1309 if (s->permissive_fsec)
1310 filesec_free(s->permissive_fsec);
1311
1312 if (s->qinfo)
1313 qtn_file_free(s->qinfo);
1314
1315 if (copyfile_close(s) < 0)
1316 {
1317 copyfile_warn("error closing files");
1318 return -1;
1319 }
1320 if (s->xattr_name)
1321 free(s->xattr_name);
1322 if (s->dst)
1323 free(s->dst);
1324 if (s->src)
1325 free(s->src);
1326 free(s);
1327 }
1328 return 0;
1329 }
1330
1331 /*
1332 * Should we worry if we can't close the source? NFS says we
1333 * should, but it's pretty late for us at this point.
1334 */
1335 static int copyfile_close(copyfile_state_t s)
1336 {
1337 if (s->src && s->src_fd >= 0)
1338 close(s->src_fd);
1339
1340 if (s->dst && s->dst_fd >= 0) {
1341 if (close(s->dst_fd))
1342 return -1;
1343 }
1344
1345 return 0;
1346 }
1347
1348 /*
1349 * The purpose of this function is to set up a set of permissions
1350 * (ACL and traditional) that lets us write to the file. In the
1351 * case of ACLs, we do this by putting in a first entry that lets
1352 * us write data, attributes, and extended attributes. In the case
1353 * of traditional permissions, we set the S_IWUSR (user-write)
1354 * bit.
1355 */
1356 static filesec_t copyfile_fix_perms(copyfile_state_t s __unused, filesec_t *fsec)
1357 {
1358 filesec_t ret_fsec = NULL;
1359 mode_t mode;
1360 acl_t acl = NULL;
1361
1362 if ((ret_fsec = filesec_dup(*fsec)) == NULL)
1363 goto error_exit;
1364
1365 if (filesec_get_property(ret_fsec, FILESEC_ACL, &acl) == 0)
1366 {
1367 #ifdef COPYFILE_RECURSIVE
1368 if (add_uberace(&acl))
1369 goto error_exit;
1370 #else
1371 acl_entry_t entry;
1372 acl_permset_t permset;
1373 uuid_t qual;
1374
1375 if (mbr_uid_to_uuid(getuid(), qual) != 0)
1376 goto error_exit;
1377
1378 /*
1379 * First, we create an entry, and give it the special name
1380 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
1381 * After that, we clear out all the permissions in it, and
1382 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
1383 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
1384 * the functionality, and put this into the ACL.
1385 */
1386 if (acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY) == -1)
1387 goto error_exit;
1388 if (acl_get_permset(entry, &permset) == -1)
1389 goto error_exit;
1390 if (acl_clear_perms(permset) == -1)
1391 goto error_exit;
1392 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1)
1393 goto error_exit;
1394 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1)
1395 goto error_exit;
1396 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1)
1397 goto error_exit;
1398 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1)
1399 goto error_exit;
1400
1401 if(acl_set_permset(entry, permset) == -1)
1402 goto error_exit;
1403 if(acl_set_qualifier(entry, qual) == -1)
1404 goto error_exit;
1405 #endif
1406
1407 if (filesec_set_property(ret_fsec, FILESEC_ACL, &acl) != 0)
1408 goto error_exit;
1409 }
1410
1411 /*
1412 * This is for the normal, mundane, POSIX permission model.
1413 * We make sure that we can write to the file.
1414 */
1415 if (filesec_get_property(ret_fsec, FILESEC_MODE, &mode) == 0)
1416 {
1417 if ((mode & (S_IWUSR | S_IRUSR)) != (S_IWUSR | S_IRUSR))
1418 {
1419 mode |= S_IWUSR|S_IRUSR;
1420 if (filesec_set_property(ret_fsec, FILESEC_MODE, &mode) != 0)
1421 goto error_exit;
1422 }
1423 }
1424
1425 exit:
1426 if (acl)
1427 acl_free(acl);
1428
1429 return ret_fsec;
1430
1431 error_exit:
1432 if (ret_fsec)
1433 {
1434 filesec_free(ret_fsec);
1435 ret_fsec = NULL;
1436 }
1437 goto exit;
1438 }
1439
1440 /*
1441 * Used to clear out the BSD/POSIX security information from
1442 * a filesec
1443 */
1444 static int
1445 copyfile_unset_posix_fsec(filesec_t fsec)
1446 {
1447 (void)filesec_set_property(fsec, FILESEC_OWNER, _FILESEC_UNSET_PROPERTY);
1448 (void)filesec_set_property(fsec, FILESEC_GROUP, _FILESEC_UNSET_PROPERTY);
1449 (void)filesec_set_property(fsec, FILESEC_MODE, _FILESEC_UNSET_PROPERTY);
1450 return 0;
1451 }
1452
1453 /*
1454 * Used to remove acl information from a filesec_t
1455 * Unsetting the acl alone in Tiger was insufficient
1456 */
1457 static int copyfile_unset_acl(copyfile_state_t s)
1458 {
1459 int ret = 0;
1460 if (filesec_set_property(s->fsec, FILESEC_ACL, NULL) == -1)
1461 {
1462 copyfile_debug(5, "unsetting acl attribute on %s", s->dst ? s->dst : "(null dst)");
1463 ++ret;
1464 }
1465 if (filesec_set_property(s->fsec, FILESEC_UUID, NULL) == -1)
1466 {
1467 copyfile_debug(5, "unsetting uuid attribute on %s", s->dst ? s->dst : "(null dst)");
1468 ++ret;
1469 }
1470 if (filesec_set_property(s->fsec, FILESEC_GRPUUID, NULL) == -1)
1471 {
1472 copyfile_debug(5, "unsetting group uuid attribute on %s", s->dst ? s->dst : "(null dst)");
1473 ++ret;
1474 }
1475 return ret;
1476 }
1477
1478 /*
1479 * copyfile_open() does what one expects: it opens up the files
1480 * given in the state structure, if they're not already open.
1481 * It also does some type validation, to ensure that we only
1482 * handle file types we know about.
1483 */
1484 static int copyfile_open(copyfile_state_t s)
1485 {
1486 int oflags = O_EXCL | O_CREAT | O_WRONLY;
1487 int islnk = 0, isdir = 0;
1488 int osrc = 0, dsrc = 0;
1489
1490 if (s->src && s->src_fd == -2)
1491 {
1492 if ((COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
1493 (s->src, &s->sb, s->fsec))
1494 {
1495 copyfile_warn("stat on %s", s->src);
1496 return -1;
1497 }
1498
1499 /* prevent copying on unsupported types */
1500 switch (s->sb.st_mode & S_IFMT)
1501 {
1502 case S_IFLNK:
1503 islnk = 1;
1504 if ((size_t)s->sb.st_size > SIZE_T_MAX) {
1505 s->err = ENOMEM; /* too big for us to copy */
1506 return -1;
1507 }
1508 osrc = O_SYMLINK;
1509 break;
1510 case S_IFDIR:
1511 isdir = 1;
1512 break;
1513 case S_IFREG:
1514 break;
1515 default:
1516 if (!(strcmp(s->src, "/dev/null") == 0 && (s->flags & COPYFILE_METADATA))) {
1517 s->err = ENOTSUP;
1518 return -1;
1519 }
1520 }
1521 /*
1522 * If we're packing, then we are actually
1523 * creating a file, no matter what the source
1524 * was.
1525 */
1526 if (s->flags & COPYFILE_PACK) {
1527 /*
1528 * O_SYMLINK and O_NOFOLLOW are not compatible options:
1529 * if the file is a symlink, and O_NOFOLLOW is specified,
1530 * open will return ELOOP, whether or not O_SYMLINK is set.
1531 * However, we know whether or not it was a symlink from
1532 * the stat above (although there is a potentiaal for a race
1533 * condition here, but it will err on the side of returning
1534 * ELOOP from open).
1535 */
1536 if (!islnk)
1537 osrc = (s->flags & COPYFILE_NOFOLLOW_SRC) ? O_NOFOLLOW : 0;
1538 isdir = islnk = 0;
1539 }
1540
1541 if ((s->src_fd = open(s->src, O_RDONLY | osrc , 0)) < 0)
1542 {
1543 copyfile_warn("open on %s", s->src);
1544 return -1;
1545 } else
1546 copyfile_debug(2, "open successful on source (%s)", s->src);
1547
1548 (void)copyfile_quarantine(s);
1549 }
1550
1551 if (s->dst && s->dst_fd == -2)
1552 {
1553 /*
1554 * COPYFILE_UNLINK tells us to try removing the destination
1555 * before we create it. We don't care if the file doesn't
1556 * exist, so we ignore ENOENT.
1557 */
1558 if (COPYFILE_UNLINK & s->flags)
1559 {
1560 if (remove(s->dst) < 0 && errno != ENOENT)
1561 {
1562 copyfile_warn("%s: remove", s->dst);
1563 return -1;
1564 }
1565 }
1566
1567 if (s->flags & COPYFILE_NOFOLLOW_DST) {
1568 struct stat st;
1569
1570 dsrc = O_NOFOLLOW;
1571 if (lstat(s->dst, &st) != -1) {
1572 if ((st.st_mode & S_IFMT) == S_IFLNK)
1573 dsrc = O_SYMLINK;
1574 }
1575 }
1576
1577 if (islnk) {
1578 size_t sz = (size_t)s->sb.st_size + 1;
1579 char *bp;
1580
1581 bp = calloc(1, sz);
1582 if (bp == NULL) {
1583 copyfile_warn("cannot allocate %zd bytes", sz);
1584 return -1;
1585 }
1586 if (readlink(s->src, bp, sz-1) == -1) {
1587 copyfile_warn("cannot readlink %s", s->src);
1588 free(bp);
1589 return -1;
1590 }
1591 if (symlink(bp, s->dst) == -1) {
1592 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
1593 copyfile_warn("Cannot make symlink %s", s->dst);
1594 free(bp);
1595 return -1;
1596 }
1597 }
1598 free(bp);
1599 s->dst_fd = open(s->dst, O_RDONLY | O_SYMLINK);
1600 if (s->dst_fd == -1) {
1601 copyfile_warn("Cannot open symlink %s for reading", s->dst);
1602 return -1;
1603 }
1604 } else if (isdir) {
1605 mode_t mode;
1606 mode = (s->sb.st_mode & ~S_IFMT) | S_IRWXU;
1607
1608 if (mkdir(s->dst, mode) == -1) {
1609 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
1610 copyfile_warn("Cannot make directory %s", s->dst);
1611 return -1;
1612 }
1613 }
1614 s->dst_fd = open(s->dst, O_RDONLY | dsrc);
1615 if (s->dst_fd == -1) {
1616 copyfile_warn("Cannot open directory %s for reading", s->dst);
1617 return -1;
1618 }
1619 } else while((s->dst_fd = open(s->dst, oflags | dsrc, s->sb.st_mode | S_IWUSR)) < 0)
1620 {
1621 /*
1622 * We set S_IWUSR because fsetxattr does not -- at the time this comment
1623 * was written -- allow one to set an extended attribute on a file descriptor
1624 * for a read-only file, even if the file descriptor is opened for writing.
1625 * This will only matter if the file does not already exist.
1626 */
1627 switch(errno)
1628 {
1629 case EEXIST:
1630 copyfile_debug(3, "open failed, retrying (%s)", s->dst);
1631 if (s->flags & COPYFILE_EXCL)
1632 break;
1633 oflags = oflags & ~O_CREAT;
1634 if (s->flags & (COPYFILE_PACK | COPYFILE_DATA))
1635 {
1636 copyfile_debug(4, "truncating existing file (%s)", s->dst);
1637 oflags |= O_TRUNC;
1638 }
1639 continue;
1640 case EACCES:
1641 if(chmod(s->dst, (s->sb.st_mode | S_IWUSR) & ~S_IFMT) == 0)
1642 continue;
1643 else {
1644 /*
1645 * If we're trying to write to a directory to which we don't
1646 * have access, the create above would have failed, but chmod
1647 * here would have given us ENOENT. But the real error is
1648 * still one of access, so we change the errno we're reporting.
1649 * This could cause confusion with a race condition.
1650 */
1651
1652 if (errno == ENOENT)
1653 errno = EACCES;
1654 break;
1655 }
1656 case EISDIR:
1657 copyfile_debug(3, "open failed because it is a directory (%s)", s->dst);
1658 if (((s->flags & COPYFILE_EXCL) ||
1659 (!isdir && (s->flags & COPYFILE_DATA)))
1660 && !(s->flags & COPYFILE_UNPACK))
1661 break;
1662 oflags = (oflags & ~(O_WRONLY|O_CREAT|O_TRUNC)) | O_RDONLY;
1663 continue;
1664 }
1665 copyfile_warn("open on %s", s->dst);
1666 return -1;
1667 }
1668 copyfile_debug(2, "open successful on destination (%s)", s->dst);
1669 }
1670
1671 if (s->dst_fd < 0 || s->src_fd < 0)
1672 {
1673 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
1674 s->src_fd, s->dst_fd);
1675 s->err = EINVAL;
1676 return -1;
1677 }
1678 return 0;
1679 }
1680
1681
1682 /*
1683 * copyfile_check(), as described above, essentially tells you
1684 * what you'd have to copy, if you wanted it to copy the things
1685 * you asked it to copy.
1686 * In other words, if you pass in COPYFILE_ALL, and the file in
1687 * question had no extended attributes but did have an ACL, you'd
1688 * get back COPYFILE_ACL.
1689 */
1690 static copyfile_flags_t copyfile_check(copyfile_state_t s)
1691 {
1692 acl_t acl = NULL;
1693 copyfile_flags_t ret = 0;
1694 int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC);
1695 qtn_file_t qinfo;
1696
1697 if (!s->src)
1698 {
1699 s->err = EINVAL;
1700 return -1;
1701 }
1702
1703 /* check EAs */
1704 if (COPYFILE_XATTR & s->flags)
1705 if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0)
1706 {
1707 ret |= COPYFILE_XATTR;
1708 }
1709
1710 if (COPYFILE_ACL & s->flags)
1711 {
1712 (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
1713 (s->src, &s->sb, s->fsec);
1714
1715 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0)
1716 ret |= COPYFILE_ACL;
1717 }
1718
1719 copyfile_debug(2, "check result: %d (%s)", ret, s->src);
1720
1721 if (acl)
1722 acl_free(acl);
1723
1724 if (s->qinfo) {
1725 /* If the state has had quarantine info set already, we use that */
1726 ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1727 } else {
1728 qinfo = qtn_file_alloc();
1729 /*
1730 * For quarantine information, we need to see if the source file
1731 * has any. Since it may be a symlink, however, and we may, or
1732 * not be following, *and* there's no qtn* routine which can optionally
1733 * follow or not follow a symlink, we need to instead work around
1734 * this limitation.
1735 */
1736 if (qinfo) {
1737 int fd;
1738 int qret = 0;
1739 struct stat sbuf;
1740
1741 /*
1742 * If we care about not following symlinks, *and* the file exists
1743 * (which is to say, lstat doesn't return an error), *and* the file
1744 * is a symlink, then we open it up (with O_SYMLINK), and use
1745 * qtn_file_init_with_fd(); if none of that is true, however, then
1746 * we can simply use qtn_file_init_with_path().
1747 */
1748 if (nofollow
1749 && lstat(s->src, &sbuf) == 0
1750 && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) {
1751 fd = open(s->src, O_RDONLY | O_SYMLINK);
1752 if (fd != -1) {
1753 if (!qtn_file_init_with_fd(qinfo, fd)) {
1754 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1755 }
1756 close(fd);
1757 }
1758 } else {
1759 if (!qtn_file_init_with_path(qinfo, s->src)) {
1760 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
1761 }
1762 }
1763 qtn_file_free(qinfo);
1764 ret |= qret;
1765 }
1766 }
1767 return ret;
1768 }
1769
1770 /*
1771 * Attempt to copy the data section of a file. Using blockisize
1772 * is not necessarily the fastest -- it might be desirable to
1773 * specify a blocksize, somehow. But it's a size that should be
1774 * guaranteed to work.
1775 */
1776 static int copyfile_data(copyfile_state_t s)
1777 {
1778 size_t blen;
1779 char *bp = 0;
1780 ssize_t nread;
1781 int ret = 0;
1782 size_t iBlocksize = 0;
1783 size_t oBlocksize = 0;
1784 const size_t onegig = 1 << 30;
1785 struct statfs sfs;
1786 copyfile_callback_t status = s->statuscb;
1787
1788 /* Unless it's a normal file, we don't copy. For now, anyway */
1789 if ((s->sb.st_mode & S_IFMT) != S_IFREG)
1790 return 0;
1791
1792 #ifdef VOL_CAP_FMT_DECMPFS_COMPRESSION
1793 if (s->internal_flags & cfSawDecmpEA) {
1794 if (s->sb.st_flags & UF_COMPRESSED) {
1795 if ((s->flags & COPYFILE_STAT) == 0) {
1796 if (fchflags(s->dst_fd, UF_COMPRESSED) == 0) {
1797 goto exit;
1798 }
1799 }
1800 }
1801 }
1802 #endif
1803
1804 if (fstatfs(s->src_fd, &sfs) == -1) {
1805 iBlocksize = s->sb.st_blksize;
1806 } else {
1807 iBlocksize = sfs.f_iosize;
1808 }
1809
1810 /* Work-around for 6453525, limit blocksize to 1G */
1811 if (iBlocksize > onegig) {
1812 iBlocksize = onegig;
1813 }
1814
1815 if ((bp = malloc(iBlocksize)) == NULL)
1816 return -1;
1817
1818 if (fstatfs(s->dst_fd, &sfs) == -1 || sfs.f_iosize == 0) {
1819 oBlocksize = iBlocksize;
1820 } else {
1821 oBlocksize = sfs.f_iosize;
1822 if (oBlocksize > onegig)
1823 oBlocksize = onegig;
1824 }
1825
1826 blen = iBlocksize;
1827
1828 s->totalCopied = 0;
1829 /* If supported, do preallocation for Xsan / HFS volumes */
1830 #ifdef F_PREALLOCATE
1831 {
1832 fstore_t fst;
1833
1834 fst.fst_flags = 0;
1835 fst.fst_posmode = F_PEOFPOSMODE;
1836 fst.fst_offset = 0;
1837 fst.fst_length = s->sb.st_size;
1838 /* Ignore errors; this is merely advisory. */
1839 (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst);
1840 }
1841 #endif
1842
1843 while ((nread = read(s->src_fd, bp, blen)) > 0)
1844 {
1845 ssize_t nwritten;
1846 size_t left = nread;
1847 void *ptr = bp;
1848 int loop = 0;
1849
1850 while (left > 0) {
1851 nwritten = write(s->dst_fd, ptr, MIN(left, oBlocksize));
1852 switch (nwritten) {
1853 case 0:
1854 if (++loop > 5) {
1855 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop);
1856 ret = -1;
1857 s->err = EAGAIN;
1858 goto exit;
1859 }
1860 break;
1861 case -1:
1862 copyfile_warn("writing to output file got error");
1863 if (status) {
1864 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
1865 if (rv == COPYFILE_SKIP) { // Skip the data copy
1866 ret = 0;
1867 goto exit;
1868 }
1869 if (rv == COPYFILE_CONTINUE) { // Retry the write
1870 errno = 0;
1871 continue;
1872 }
1873 }
1874 ret = -1;
1875 goto exit;
1876 default:
1877 left -= nwritten;
1878 ptr = ((char*)ptr) + nwritten;
1879 loop = 0;
1880 break;
1881 }
1882 s->totalCopied += nwritten;
1883 if (status) {
1884 int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
1885 if (rv == COPYFILE_QUIT) {
1886 ret = -1; s->err = errno = ECANCELED;
1887 goto exit;
1888 }
1889 }
1890 }
1891 }
1892 if (nread < 0)
1893 {
1894 copyfile_warn("reading from %s", s->src ? s->src : "(null src)");
1895 ret = -1;
1896 goto exit;
1897 }
1898
1899 if (ftruncate(s->dst_fd, s->totalCopied) < 0)
1900 {
1901 ret = -1;
1902 goto exit;
1903 }
1904
1905 exit:
1906 if (ret == -1)
1907 {
1908 s->err = errno;
1909 }
1910 free(bp);
1911 return ret;
1912 }
1913
1914 /*
1915 * copyfile_security() will copy the ACL set, and the
1916 * POSIX set. Complexities come when dealing with
1917 * inheritied permissions, and when dealing with both
1918 * POSIX and ACL permissions.
1919 */
1920 static int copyfile_security(copyfile_state_t s)
1921 {
1922 int copied = 0;
1923 struct stat sb;
1924 acl_t acl_src = NULL, acl_tmp = NULL, acl_dst = NULL;
1925 int ret = 0;
1926 filesec_t tmp_fsec = NULL;
1927 filesec_t fsec_dst = filesec_init();
1928
1929 if (fsec_dst == NULL)
1930 return -1;
1931
1932
1933 if (COPYFILE_ACL & s->flags)
1934 {
1935 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src))
1936 {
1937 if (errno == ENOENT)
1938 acl_src = NULL;
1939 else
1940 goto error_exit;
1941 }
1942
1943 /* grab the destination acl
1944 cannot assume it's empty due to inheritance
1945 */
1946 if(fstatx_np(s->dst_fd, &sb, fsec_dst))
1947 goto error_exit;
1948
1949 if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst))
1950 {
1951 if (errno == ENOENT)
1952 acl_dst = NULL;
1953 else
1954 goto error_exit;
1955 }
1956
1957 if (acl_src == NULL && acl_dst == NULL)
1958 goto no_acl;
1959
1960 acl_tmp = acl_init(4);
1961 if (acl_tmp == NULL)
1962 goto error_exit;
1963
1964 if (acl_src) {
1965 acl_entry_t ace = NULL;
1966 acl_entry_t tmp = NULL;
1967 for (copied = 0;
1968 acl_get_entry(acl_src,
1969 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
1970 &ace) == 0;)
1971 {
1972 acl_flagset_t flags = { 0 };
1973 acl_get_flagset_np(ace, &flags);
1974 if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
1975 {
1976 if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1)
1977 goto error_exit;
1978
1979 if ((ret = acl_copy_entry(tmp, ace)) == -1)
1980 goto error_exit;
1981
1982 copyfile_debug(2, "copied acl entry from %s to %s",
1983 s->src ? s->src : "(null src)",
1984 s->dst ? s->dst : "(null tmp)");
1985 copied++;
1986 }
1987 }
1988 }
1989 if (acl_dst) {
1990 acl_entry_t ace = NULL;
1991 acl_entry_t tmp = NULL;
1992 acl_flagset_t flags = { 0 };
1993 for (copied = 0;acl_get_entry(acl_dst,
1994 ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
1995 &ace) == 0;)
1996 {
1997 acl_get_flagset_np(ace, &flags);
1998 if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
1999 {
2000 if ((ret = acl_create_entry(&acl_tmp, &tmp)) == -1)
2001 goto error_exit;
2002
2003 if ((ret = acl_copy_entry(tmp, ace)) == -1)
2004 goto error_exit;
2005
2006 copyfile_debug(2, "copied acl entry from %s to %s",
2007 s->src ? s->src : "(null dst)",
2008 s->dst ? s->dst : "(null tmp)");
2009 copied++;
2010 }
2011 }
2012 }
2013 if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_tmp))
2014 {
2015 copyfile_debug(3, "altered acl");
2016 }
2017 }
2018 no_acl:
2019 /*
2020 * The following code is attempting to ensure that only the requested
2021 * security information gets copied over to the destination file.
2022 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
2023 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
2024 * this function).
2025 *
2026 * If we have both flags, we copy everything; if we have ACL but not STAT,
2027 * we remove the POSIX information from the filesec object, and apply the
2028 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
2029 * the extended version.
2030 */
2031 tmp_fsec = filesec_dup(s->fsec);
2032 if (tmp_fsec == NULL) {
2033 goto error_exit;
2034 }
2035
2036 switch (COPYFILE_SECURITY & s->flags) {
2037 case COPYFILE_ACL:
2038 copyfile_unset_posix_fsec(tmp_fsec);
2039 /* FALLTHROUGH */
2040 case COPYFILE_ACL | COPYFILE_STAT:
2041 if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) {
2042 acl_t acl = NULL;
2043 /*
2044 * The call could have failed for a number of reasons, since
2045 * it does a number of things: it changes the mode of the file,
2046 * sets the owner and group, and applies an ACL (if one exists).
2047 * The typical failure is going to be trying to set the group of
2048 * the destination file to match the source file, when the process
2049 * doesn't have permission to put files in that group. We try to
2050 * work around this by breaking the steps out and doing them
2051 * discretely. We don't care if the fchown fails, but we do care
2052 * if the mode or ACL can't be set. For historical reasons, we
2053 * simply log those failures, however.
2054 *
2055 * Big warning here: we may NOT have COPYFILE_STAT set, since
2056 * we fell-through from COPYFILE_ACL. So check for the fchmod.
2057 */
2058
2059 #define NS(x) ((x) ? (x) : "(null string)")
2060 if ((s->flags & COPYFILE_STAT) &&
2061 fchmod(s->dst_fd, s->sb.st_mode) == -1) {
2062 copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s->dst), NS(s->src));
2063 }
2064 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
2065 if (filesec_get_property(tmp_fsec, FILESEC_ACL, &acl) == 0) {
2066 if (acl_set_fd(s->dst_fd, acl) == -1) {
2067 copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s->dst), NS(s->src));
2068 }
2069 acl_free(acl);
2070 }
2071 }
2072 #undef NS
2073 break;
2074 case COPYFILE_STAT:
2075 (void)fchmod(s->dst_fd, s->sb.st_mode);
2076 break;
2077 }
2078 filesec_free(tmp_fsec);
2079 exit:
2080 filesec_free(fsec_dst);
2081 if (acl_src) acl_free(acl_src);
2082 if (acl_dst) acl_free(acl_dst);
2083 if (acl_tmp) acl_free(acl_tmp);
2084
2085 return ret;
2086
2087 error_exit:
2088 ret = -1;
2089 goto exit;
2090
2091 }
2092
2093 /*
2094 * Attempt to set the destination file's stat information -- including
2095 * flags and time-related fields -- to the source's.
2096 */
2097 static int copyfile_stat(copyfile_state_t s)
2098 {
2099 struct timeval tval[2];
2100 unsigned int added_flags = 0;
2101
2102 /*
2103 * NFS doesn't support chflags; ignore errors as a result, since
2104 * we don't return failure for this.
2105 */
2106 if (s->internal_flags & cfMakeFileInvisible)
2107 added_flags |= UF_HIDDEN;
2108
2109 (void)fchflags(s->dst_fd, (u_int)s->sb.st_flags | added_flags);
2110
2111 /* If this fails, we don't care */
2112 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
2113
2114 /* This may have already been done in copyfile_security() */
2115 (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT);
2116
2117 tval[0].tv_sec = s->sb.st_atime;
2118 tval[1].tv_sec = s->sb.st_mtime;
2119 tval[0].tv_usec = tval[1].tv_usec = 0;
2120 (void)futimes(s->dst_fd, tval);
2121
2122 return 0;
2123 }
2124
2125 /*
2126 * Similar to copyfile_security() in some ways; this
2127 * routine copies the extended attributes from the source,
2128 * and sets them on the destination.
2129 * The procedure is pretty simple, even if it is verbose:
2130 * for each named attribute on the destination, get its name, and
2131 * remove it. We should have none after that.
2132 * For each named attribute on the source, get its name, get its
2133 * data, and set it on the destination.
2134 */
2135 static int copyfile_xattr(copyfile_state_t s)
2136 {
2137 char *name;
2138 char *namebuf, *end;
2139 ssize_t xa_size;
2140 void *xa_dataptr;
2141 ssize_t bufsize = 4096;
2142 ssize_t asize;
2143 ssize_t nsize;
2144 int ret = 0;
2145 int look_for_decmpea = 0;
2146
2147 /* delete EAs on destination */
2148 if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
2149 {
2150 if ((namebuf = (char *) malloc(nsize)) == NULL)
2151 return -1;
2152 else
2153 nsize = flistxattr(s->dst_fd, namebuf, nsize, 0);
2154
2155 if (nsize > 0) {
2156 /*
2157 * With this, end points to the last byte of the allocated buffer
2158 * This *should* be NUL, from flistxattr, but if it's not, we can
2159 * set it anyway -- it'll result in a truncated name, which then
2160 * shouldn't match when we get them later.
2161 */
2162 end = namebuf + nsize - 1;
2163 if (*end != 0)
2164 *end = 0;
2165 for (name = namebuf; name <= end; name += strlen(name) + 1) {
2166 /* If the quarantine information shows up as an EA, we skip over it */
2167 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) {
2168 continue;
2169 }
2170 fremovexattr(s->dst_fd, name,0);
2171 }
2172 }
2173 free(namebuf);
2174 } else
2175 if (nsize < 0)
2176 {
2177 if (errno == ENOTSUP || errno == EPERM)
2178 return 0;
2179 else
2180 return -1;
2181 }
2182
2183 #ifdef DECMPFS_XATTR_NAME
2184 if ((s->flags & COPYFILE_DATA) &&
2185 (s->sb.st_flags & UF_COMPRESSED) &&
2186 doesdecmpfs(s->src_fd) &&
2187 doesdecmpfs(s->dst_fd)) {
2188 look_for_decmpea = XATTR_SHOWCOMPRESSION;
2189 }
2190 #endif
2191
2192 /* get name list of EAs on source */
2193 if ((nsize = flistxattr(s->src_fd, 0, 0, look_for_decmpea)) < 0)
2194 {
2195 if (errno == ENOTSUP || errno == EPERM)
2196 return 0;
2197 else
2198 return -1;
2199 } else
2200 if (nsize == 0)
2201 return 0;
2202
2203 if ((namebuf = (char *) malloc(nsize)) == NULL)
2204 return -1;
2205 else
2206 nsize = flistxattr(s->src_fd, namebuf, nsize, look_for_decmpea);
2207
2208 if (nsize <= 0) {
2209 free(namebuf);
2210 return (int)nsize;
2211 }
2212
2213 /*
2214 * With this, end points to the last byte of the allocated buffer
2215 * This *should* be NUL, from flistxattr, but if it's not, we can
2216 * set it anyway -- it'll result in a truncated name, which then
2217 * shouldn't match when we get them later.
2218 */
2219 end = namebuf + nsize - 1;
2220 if (*end != 0)
2221 *end = 0;
2222
2223 if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) {
2224 free(namebuf);
2225 return -1;
2226 }
2227
2228 for (name = namebuf; name <= end; name += strlen(name) + 1)
2229 {
2230 if (s->xattr_name) {
2231 free(s->xattr_name);
2232 s->xattr_name = NULL;
2233 }
2234
2235 /* If the quarantine information shows up as an EA, we skip over it */
2236 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0)
2237 continue;
2238
2239 if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, look_for_decmpea)) < 0)
2240 {
2241 continue;
2242 }
2243
2244 if (xa_size > bufsize)
2245 {
2246 void *tdptr = xa_dataptr;
2247 bufsize = xa_size;
2248 if ((xa_dataptr =
2249 (void *) realloc((void *) xa_dataptr, bufsize)) == NULL)
2250 {
2251 free(tdptr);
2252 ret = -1;
2253 continue;
2254 }
2255 }
2256
2257 if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea)) < 0)
2258 {
2259 continue;
2260 }
2261
2262 if (xa_size != asize)
2263 xa_size = asize;
2264
2265 #ifdef DECMPFS_XATTR_NAME
2266 if (strncmp(name, DECMPFS_XATTR_NAME, end-name) == 0)
2267 {
2268 decmpfs_disk_header *hdr = xa_dataptr;
2269
2270 /*
2271 * If the EA has the decmpfs name, but is too
2272 * small, or doesn't have the right magic number,
2273 * or isn't the right type, we'll just skip it.
2274 * This means it won't end up in the destination
2275 * file, and data copy will happen normally.
2276 */
2277 if ((size_t)xa_size < sizeof(decmpfs_disk_header)) {
2278 continue;
2279 }
2280 if (OSSwapLittleToHostInt32(hdr->compression_magic) != DECMPFS_MAGIC) {
2281 continue;
2282 }
2283 if (OSSwapLittleToHostInt32(hdr->compression_type) != 3 &&
2284 OSSwapLittleToHostInt32(hdr->compression_type) != 4) {
2285 continue;
2286 }
2287 s->internal_flags |= cfSawDecmpEA;
2288 }
2289 #endif
2290
2291 s->xattr_name = strdup(name);
2292
2293 if (s->statuscb) {
2294 int rv;
2295 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
2296 if (rv == COPYFILE_QUIT) {
2297 s->err = ECANCELED;
2298 goto out;
2299 } else if (rv == COPYFILE_SKIP) {
2300 continue;
2301 }
2302 }
2303 if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea) < 0)
2304 {
2305 if (s->statuscb)
2306 {
2307 int rv;
2308 if (s->xattr_name == NULL)
2309 s->xattr_name = strdup(name);
2310 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
2311 if (rv == COPYFILE_QUIT)
2312 {
2313 s->err = ECANCELED;
2314 ret = -1;
2315 goto out;
2316 }
2317 }
2318 else
2319 {
2320 ret = -1;
2321 copyfile_warn("could not set attributes %s on destination file descriptor: %s", name, strerror(errno));
2322 continue;
2323 }
2324 }
2325 if (s->statuscb) {
2326 int rv;
2327 if (s->xattr_name == NULL)
2328 s->xattr_name = strdup(name);
2329
2330 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
2331 if (rv == COPYFILE_QUIT) {
2332 s->err = ECANCELED;
2333 goto out;
2334 }
2335 }
2336 }
2337 out:
2338 if (namebuf)
2339 free(namebuf);
2340 free((void *) xa_dataptr);
2341 if (s->xattr_name) {
2342 free(s->xattr_name);
2343 s->xattr_name = NULL;
2344 }
2345 return ret;
2346 }
2347
2348 /*
2349 * API interface into getting data from the opaque data type.
2350 */
2351 int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
2352 {
2353 if (ret == NULL)
2354 {
2355 errno = EFAULT;
2356 return -1;
2357 }
2358
2359 switch(flag)
2360 {
2361 case COPYFILE_STATE_SRC_FD:
2362 *(int*)ret = s->src_fd;
2363 break;
2364 case COPYFILE_STATE_DST_FD:
2365 *(int*)ret = s->dst_fd;
2366 break;
2367 case COPYFILE_STATE_SRC_FILENAME:
2368 *(char**)ret = s->src;
2369 break;
2370 case COPYFILE_STATE_DST_FILENAME:
2371 *(char**)ret = s->dst;
2372 break;
2373 case COPYFILE_STATE_QUARANTINE:
2374 *(qtn_file_t*)ret = s->qinfo;
2375 break;
2376 #if 0
2377 case COPYFILE_STATE_STATS:
2378 ret = s->stats.global;
2379 break;
2380 case COPYFILE_STATE_PROGRESS_CB:
2381 ret = s->callbacks.progress;
2382 break;
2383 #endif
2384 #ifdef COPYFILE_STATE_STATUS_CB
2385 case COPYFILE_STATE_STATUS_CB:
2386 *(copyfile_callback_t*)ret = s->statuscb;
2387 break;
2388 case COPYFILE_STATE_STATUS_CTX:
2389 *(void**)ret = s->ctx;
2390 break;
2391 case COPYFILE_STATE_COPIED:
2392 *(off_t*)ret = s->totalCopied;
2393 break;
2394 #endif
2395 #ifdef COPYFILE_STATE_XATTRNAME
2396 case COPYFILE_STATE_XATTRNAME:
2397 *(char**)ret = s->xattr_name;
2398 break;
2399 #endif
2400 default:
2401 errno = EINVAL;
2402 ret = NULL;
2403 return -1;
2404 }
2405 return 0;
2406 }
2407
2408 /*
2409 * Public API for setting state data (remember that the state is
2410 * an opaque data type).
2411 */
2412 int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
2413 {
2414 #define copyfile_set_string(DST, SRC) \
2415 do { \
2416 if (SRC != NULL) { \
2417 DST = strdup((char *)SRC); \
2418 } else { \
2419 if (DST != NULL) { \
2420 free(DST); \
2421 } \
2422 DST = NULL; \
2423 } \
2424 } while (0)
2425
2426 if (thing == NULL)
2427 {
2428 errno = EFAULT;
2429 return -1;
2430 }
2431
2432 switch(flag)
2433 {
2434 case COPYFILE_STATE_SRC_FD:
2435 s->src_fd = *(int*)thing;
2436 break;
2437 case COPYFILE_STATE_DST_FD:
2438 s->dst_fd = *(int*)thing;
2439 break;
2440 case COPYFILE_STATE_SRC_FILENAME:
2441 copyfile_set_string(s->src, thing);
2442 break;
2443 case COPYFILE_STATE_DST_FILENAME:
2444 copyfile_set_string(s->dst, thing);
2445 break;
2446 case COPYFILE_STATE_QUARANTINE:
2447 if (s->qinfo)
2448 {
2449 qtn_file_free(s->qinfo);
2450 s->qinfo = NULL;
2451 }
2452 if (*(qtn_file_t*)thing)
2453 s->qinfo = qtn_file_clone(*(qtn_file_t*)thing);
2454 break;
2455 #if 0
2456 case COPYFILE_STATE_STATS:
2457 s->stats.global = thing;
2458 break;
2459 case COPYFILE_STATE_PROGRESS_CB:
2460 s->callbacks.progress = thing;
2461 break;
2462 #endif
2463 #ifdef COPYFILE_STATE_STATUS_CB
2464 case COPYFILE_STATE_STATUS_CB:
2465 s->statuscb = (copyfile_callback_t)thing;
2466 break;
2467 case COPYFILE_STATE_STATUS_CTX:
2468 s->ctx = (void*)thing;
2469 break;
2470 #endif
2471 default:
2472 errno = EINVAL;
2473 return -1;
2474 }
2475 return 0;
2476 #undef copyfile_set_string
2477 }
2478
2479
2480 /*
2481 * Make this a standalone program for testing purposes by
2482 * defining _COPYFILE_TEST.
2483 */
2484 #ifdef _COPYFILE_TEST
2485 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2486
2487 struct {char *s; int v;} opts[] = {
2488 COPYFILE_OPTION(ACL)
2489 COPYFILE_OPTION(STAT)
2490 COPYFILE_OPTION(XATTR)
2491 COPYFILE_OPTION(DATA)
2492 COPYFILE_OPTION(SECURITY)
2493 COPYFILE_OPTION(METADATA)
2494 COPYFILE_OPTION(ALL)
2495 COPYFILE_OPTION(NOFOLLOW_SRC)
2496 COPYFILE_OPTION(NOFOLLOW_DST)
2497 COPYFILE_OPTION(NOFOLLOW)
2498 COPYFILE_OPTION(EXCL)
2499 COPYFILE_OPTION(MOVE)
2500 COPYFILE_OPTION(UNLINK)
2501 COPYFILE_OPTION(PACK)
2502 COPYFILE_OPTION(UNPACK)
2503 COPYFILE_OPTION(CHECK)
2504 COPYFILE_OPTION(VERBOSE)
2505 COPYFILE_OPTION(DEBUG)
2506 {NULL, 0}
2507 };
2508
2509 int main(int c, char *v[])
2510 {
2511 int i;
2512 int flags = 0;
2513
2514 if (c < 3)
2515 errx(1, "insufficient arguments");
2516
2517 while(c-- > 3)
2518 {
2519 for (i = 0; opts[i].s != NULL; ++i)
2520 {
2521 if (strcasecmp(opts[i].s, v[c]) == 0)
2522 {
2523 printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v);
2524 flags |= opts[i].v;
2525 break;
2526 }
2527 }
2528 }
2529
2530 return copyfile(v[1], v[2], NULL, flags);
2531 }
2532 #endif
2533 /*
2534 * Apple Double Create
2535 *
2536 * Create an Apple Double "._" file from a file's extented attributes
2537 *
2538 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2539 */
2540
2541
2542 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
2543
2544 #define XATTR_MAXATTRLEN (32*1024)
2545
2546
2547 /*
2548 Typical "._" AppleDouble Header File layout:
2549 ------------------------------------------------------------
2550 MAGIC 0x00051607
2551 VERSION 0x00020000
2552 FILLER 0
2553 COUNT 2
2554 .-- AD ENTRY[0] Finder Info Entry (must be first)
2555 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
2556 | '-> FINDER INFO
2557 | ///////////// Fixed Size Data (32 bytes)
2558 | EXT ATTR HDR
2559 | /////////////
2560 | ATTR ENTRY[0] --.
2561 | ATTR ENTRY[1] --+--.
2562 | ATTR ENTRY[2] --+--+--.
2563 | ... | | |
2564 | ATTR ENTRY[N] --+--+--+--.
2565 | ATTR DATA 0 <-' | | |
2566 | //////////// | | |
2567 | ATTR DATA 1 <----' | |
2568 | ///////////// | |
2569 | ATTR DATA 2 <-------' |
2570 | ///////////// |
2571 | ... |
2572 | ATTR DATA N <----------'
2573 | /////////////
2574 | Attribute Free Space
2575 |
2576 '----> RESOURCE FORK
2577 ///////////// Variable Sized Data
2578 /////////////
2579 /////////////
2580 /////////////
2581 /////////////
2582 /////////////
2583 ...
2584 /////////////
2585
2586 ------------------------------------------------------------
2587
2588 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2589 stored as part of the Finder Info. The length in the Finder
2590 Info AppleDouble entry includes the length of the extended
2591 attribute header, attribute entries, and attribute data.
2592 */
2593
2594
2595 /*
2596 * On Disk Data Structures
2597 *
2598 * Note: Motorola 68K alignment and big-endian.
2599 *
2600 * See RFC 1740 for additional information about the AppleDouble file format.
2601 *
2602 */
2603
2604 #define ADH_MAGIC 0x00051607
2605 #define ADH_VERSION 0x00020000
2606 #define ADH_MACOSX "Mac OS X "
2607
2608 /*
2609 * AppleDouble Entry ID's
2610 */
2611 #define AD_DATA 1 /* Data fork */
2612 #define AD_RESOURCE 2 /* Resource fork */
2613 #define AD_REALNAME 3 /* File's name on home file system */
2614 #define AD_COMMENT 4 /* Standard Mac comment */
2615 #define AD_ICONBW 5 /* Mac black & white icon */
2616 #define AD_ICONCOLOR 6 /* Mac color icon */
2617 #define AD_UNUSED 7 /* Not used */
2618 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
2619 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
2620 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
2621 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
2622 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
2623 #define AD_AFPNAME 13 /* Short name on AFP server */
2624 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
2625 #define AD_AFPDIRID 15 /* AFP directory ID */
2626 #define AD_ATTRIBUTES AD_FINDERINFO
2627
2628
2629 #define ATTR_FILE_PREFIX "._"
2630 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
2631
2632 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
2633
2634 /* Implementation Limits */
2635 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
2636 #define ATTR_MAX_NAME_LEN 128
2637 #define ATTR_MAX_HDR_SIZE (65536+18)
2638
2639 /*
2640 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2641 * size supported (including the attribute entries). All of
2642 * the attribute entries must reside within this limit.
2643 */
2644
2645
2646 #define FINDERINFOSIZE 32
2647
2648 typedef struct apple_double_entry
2649 {
2650 u_int32_t type; /* entry type: see list, 0 invalid */
2651 u_int32_t offset; /* entry data offset from the beginning of the file. */
2652 u_int32_t length; /* entry data length in bytes. */
2653 } __attribute__((aligned(2), packed)) apple_double_entry_t;
2654
2655
2656 typedef struct apple_double_header
2657 {
2658 u_int32_t magic; /* == ADH_MAGIC */
2659 u_int32_t version; /* format version: 2 = 0x00020000 */
2660 u_int32_t filler[4];
2661 u_int16_t numEntries; /* number of entries which follow */
2662 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */
2663 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */
2664 u_int8_t pad[2]; /* get better alignment inside attr_header */
2665 } __attribute__((aligned(2), packed)) apple_double_header_t;
2666
2667
2668 /* Entries are aligned on 4 byte boundaries */
2669 typedef struct attr_entry
2670 {
2671 u_int32_t offset; /* file offset to data */
2672 u_int32_t length; /* size of attribute data */
2673 u_int16_t flags;
2674 u_int8_t namelen; /* length of name including NULL termination char */
2675 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2676 } __attribute__((aligned(2), packed)) attr_entry_t;
2677
2678
2679
2680 /* Header + entries must fit into 64K */
2681 typedef struct attr_header
2682 {
2683 apple_double_header_t appledouble;
2684 u_int32_t magic; /* == ATTR_HDR_MAGIC */
2685 u_int32_t debug_tag; /* for debugging == file id of owning file */
2686 u_int32_t total_size; /* total size of attribute header + entries + data */
2687 u_int32_t data_start; /* file offset to attribute data area */
2688 u_int32_t data_length; /* length of attribute data area */
2689 u_int32_t reserved[3];
2690 u_int16_t flags;
2691 u_int16_t num_attrs;
2692 } __attribute__((aligned(2), packed)) attr_header_t;
2693
2694 /* Empty Resource Fork Header */
2695 /* This comes by way of xnu's vfs_xattr.c */
2696 typedef struct rsrcfork_header {
2697 u_int32_t fh_DataOffset;
2698 u_int32_t fh_MapOffset;
2699 u_int32_t fh_DataLength;
2700 u_int32_t fh_MapLength;
2701 u_int8_t systemData[112];
2702 u_int8_t appData[128];
2703 u_int32_t mh_DataOffset;
2704 u_int32_t mh_MapOffset;
2705 u_int32_t mh_DataLength;
2706 u_int32_t mh_MapLength;
2707 u_int32_t mh_Next;
2708 u_int16_t mh_RefNum;
2709 u_int8_t mh_Attr;
2710 u_int8_t mh_InMemoryAttr;
2711 u_int16_t mh_Types;
2712 u_int16_t mh_Names;
2713 u_int16_t typeCount;
2714 } __attribute__((aligned(2), packed)) rsrcfork_header_t;
2715 #define RF_FIRST_RESOURCE 256
2716 #define RF_NULL_MAP_LENGTH 30
2717 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
2718
2719 static const rsrcfork_header_t empty_rsrcfork_header = {
2720 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_DataOffset
2721 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_MapOffset
2722 0, // fh_DataLength
2723 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // fh_MapLength
2724 { RF_EMPTY_TAG, }, // systemData
2725 { 0 }, // appData
2726 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_DataOffset
2727 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_MapOffset
2728 0, // mh_DataLength
2729 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // mh_MapLength
2730 0, // mh_Next
2731 0, // mh_RefNum
2732 0, // mh_Attr
2733 0, // mh_InMemoryAttr
2734 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2), // mh_Types
2735 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH), // mh_Names
2736 OSSwapHostToBigInt16(-1), // typeCount
2737 };
2738
2739 #define SWAP16(x) OSSwapBigToHostInt16(x)
2740 #define SWAP32(x) OSSwapBigToHostInt32(x)
2741 #define SWAP64(x) OSSwapBigToHostInt64(x)
2742
2743 #define ATTR_ALIGN 3L /* Use four-byte alignment */
2744
2745 #define ATTR_ENTRY_LENGTH(namelen) \
2746 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2747
2748 #define ATTR_NEXT(ae) \
2749 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2750
2751 #define XATTR_SECURITY_NAME "com.apple.acl.text"
2752
2753 /*
2754 * Endian swap Apple Double header
2755 */
2756 static void
2757 swap_adhdr(apple_double_header_t *adh)
2758 {
2759 #if BYTE_ORDER == LITTLE_ENDIAN
2760 int count;
2761 int i;
2762
2763 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
2764
2765 adh->magic = SWAP32 (adh->magic);
2766 adh->version = SWAP32 (adh->version);
2767 adh->numEntries = SWAP16 (adh->numEntries);
2768
2769 for (i = 0; i < count; i++)
2770 {
2771 adh->entries[i].type = SWAP32 (adh->entries[i].type);
2772 adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
2773 adh->entries[i].length = SWAP32 (adh->entries[i].length);
2774 }
2775 #else
2776 (void)adh;
2777 #endif
2778 }
2779
2780 /*
2781 * Endian swap extended attributes header
2782 */
2783 static void
2784 swap_attrhdr(attr_header_t *ah)
2785 {
2786 #if BYTE_ORDER == LITTLE_ENDIAN
2787 attr_entry_t *ae;
2788 int count;
2789 int i;
2790
2791 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
2792
2793 ah->magic = SWAP32 (ah->magic);
2794 ah->debug_tag = SWAP32 (ah->debug_tag);
2795 ah->total_size = SWAP32 (ah->total_size);
2796 ah->data_start = SWAP32 (ah->data_start);
2797 ah->data_length = SWAP32 (ah->data_length);
2798 ah->flags = SWAP16 (ah->flags);
2799 ah->num_attrs = SWAP16 (ah->num_attrs);
2800
2801 ae = (attr_entry_t *)(&ah[1]);
2802 for (i = 0; i < count; i++)
2803 {
2804 attr_entry_t *next = ATTR_NEXT(ae);
2805 ae->offset = SWAP32 (ae->offset);
2806 ae->length = SWAP32 (ae->length);
2807 ae->flags = SWAP16 (ae->flags);
2808 ae = next;
2809 }
2810 #else
2811 (void)ah;
2812 #endif
2813 }
2814
2815 static const u_int32_t emptyfinfo[8] = {0};
2816
2817 /*
2818 * Given an Apple Double file in src, turn it into a
2819 * normal file (possibly with multiple forks, EAs, and
2820 * ACLs) in dst.
2821 */
2822 static int copyfile_unpack(copyfile_state_t s)
2823 {
2824 ssize_t bytes;
2825 void * buffer, * endptr;
2826 apple_double_header_t *adhdr;
2827 ssize_t hdrsize;
2828 int error = 0;
2829
2830 if (s->sb.st_size < ATTR_MAX_HDR_SIZE)
2831 hdrsize = (ssize_t)s->sb.st_size;
2832 else
2833 hdrsize = ATTR_MAX_HDR_SIZE;
2834
2835 buffer = calloc(1, hdrsize);
2836 if (buffer == NULL) {
2837 copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize);
2838 error = -1;
2839 goto exit;
2840 } else
2841 endptr = (char*)buffer + hdrsize;
2842
2843 bytes = pread(s->src_fd, buffer, hdrsize, 0);
2844
2845 if (bytes < 0)
2846 {
2847 copyfile_debug(1, "pread returned: %zd", bytes);
2848 error = -1;
2849 goto exit;
2850 }
2851 if (bytes < hdrsize)
2852 {
2853 copyfile_debug(1,
2854 "pread couldn't read entire header: %d of %d",
2855 (int)bytes, (int)s->sb.st_size);
2856 error = -1;
2857 goto exit;
2858 }
2859 adhdr = (apple_double_header_t *)buffer;
2860
2861 /*
2862 * Check for Apple Double file.
2863 */
2864 if ((size_t)bytes < sizeof(apple_double_header_t) - 2 ||
2865 SWAP32(adhdr->magic) != ADH_MAGIC ||
2866 SWAP32(adhdr->version) != ADH_VERSION ||
2867 SWAP16(adhdr->numEntries) != 2 ||
2868 SWAP32(adhdr->entries[0].type) != AD_FINDERINFO)
2869 {
2870 if (COPYFILE_VERBOSE & s->flags)
2871 copyfile_warn("Not a valid Apple Double header");
2872 error = -1;
2873 goto exit;
2874 }
2875 swap_adhdr(adhdr);
2876
2877 /*
2878 * Remove any extended attributes on the target.
2879 */
2880
2881 if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
2882 {
2883 char *namebuf, *name;
2884
2885 if ((namebuf = (char*) malloc(bytes)) == NULL)
2886 {
2887 s->err = ENOMEM;
2888 goto exit;
2889 }
2890 bytes = flistxattr(s->dst_fd, namebuf, bytes, 0);
2891
2892 if (bytes > 0)
2893 for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1)
2894 (void)fremovexattr(s->dst_fd, name, 0);
2895
2896 free(namebuf);
2897 }
2898 else if (bytes < 0)
2899 {
2900 if (errno != ENOTSUP && errno != EPERM)
2901 goto exit;
2902 }
2903
2904 /*
2905 * Extract the extended attributes.
2906 *
2907 * >>> WARNING <<<
2908 * This assumes that the data is already in memory (not
2909 * the case when there are lots of attributes or one of
2910 * the attributes is very large.
2911 */
2912 if (adhdr->entries[0].length > FINDERINFOSIZE)
2913 {
2914 attr_header_t *attrhdr;
2915 attr_entry_t *entry;
2916 int count;
2917 int i;
2918
2919 if ((size_t)hdrsize < sizeof(attr_header_t)) {
2920 copyfile_warn("bad attribute header: %zu < %zu", hdrsize, sizeof(attr_header_t));
2921 error = -1;
2922 goto exit;
2923 }
2924
2925 attrhdr = (attr_header_t *)buffer;
2926 swap_attrhdr(attrhdr);
2927 if (attrhdr->magic != ATTR_HDR_MAGIC)
2928 {
2929 if (COPYFILE_VERBOSE & s->flags)
2930 copyfile_warn("bad attribute header");
2931 error = -1;
2932 goto exit;
2933 }
2934 count = attrhdr->num_attrs;
2935 entry = (attr_entry_t *)&attrhdr[1];
2936
2937 for (i = 0; i < count; i++)
2938 {
2939 void * dataptr;
2940
2941 /*
2942 * First we do some simple sanity checking.
2943 * +) See if entry is within the buffer's range;
2944 *
2945 * +) Check the attribute name length; if it's longer than the
2946 * maximum, we truncate it down. (We could error out as well;
2947 * I'm not sure which is the better way to go here.)
2948 *
2949 * +) If, given the name length, it goes beyond the end of
2950 * the buffer, error out.
2951 *
2952 * +) If the last byte isn't a NUL, make it a NUL. (Since we
2953 * truncated the name length above, we truncate the name here.)
2954 *
2955 * +) If entry->offset is so large that it causes dataptr to
2956 * go beyond the end of the buffer -- or, worse, so large that
2957 * it wraps around! -- we error out.
2958 *
2959 * +) If entry->length would cause the entry to go beyond the
2960 * end of the buffer (or, worse, wrap around to before it),
2961 * *or* if the length is larger than the hdrsize, we error out.
2962 * (An explanation of that: what we're checking for there is
2963 * the small range of values such that offset+length would cause
2964 * it to go beyond endptr, and then wrap around past buffer. We
2965 * care about this because we are passing entry->length down to
2966 * fgetxattr() below, and an erroneously large value could cause
2967 * problems there. By making sure that it's less than hdrsize,
2968 * which has already been sanity-checked above, we're safe.
2969 * That may mean that the check against < buffer is unnecessary.)
2970 */
2971 if ((void*)entry >= endptr || (void*)entry < buffer) {
2972 if (COPYFILE_VERBOSE & s->flags)
2973 copyfile_warn("Incomplete or corrupt attribute entry");
2974 error = -1;
2975 s->err = EINVAL;
2976 goto exit;
2977 }
2978
2979 if (((char*)entry + sizeof(*entry)) > (char*)endptr) {
2980 if (COPYFILE_VERBOSE & s->flags)
2981 copyfile_warn("Incomplete or corrupt attribute entry");
2982 error = -1;
2983 s->err = EINVAL;
2984 goto exit;
2985 }
2986
2987 if (entry->namelen < 2) {
2988 if (COPYFILE_VERBOSE & s->flags)
2989 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen);
2990 error = -1;
2991 s->err = EINVAL;
2992 goto exit;
2993 }
2994
2995 if (entry->namelen > XATTR_MAXNAMELEN + 1) {
2996 if (COPYFILE_VERBOSE & s->flags)
2997 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen);
2998 error = -1;
2999 s->err = EINVAL;
3000 goto exit;
3001 }
3002
3003 if ((void*)(entry->name + entry->namelen) > endptr) {
3004 if (COPYFILE_VERBOSE & s->flags)
3005 copyfile_warn("Incomplete or corrupt attribute entry");
3006 error = -1;
3007 s->err = EINVAL;
3008 goto exit;
3009 }
3010
3011 /* Because namelen includes the NUL, we check one byte back */
3012 if (entry->name[entry->namelen-1] != 0) {
3013 if (COPYFILE_VERBOSE & s->flags)
3014 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3015 error = -1;
3016 s->err = EINVAL;
3017 goto exit;
3018 }
3019
3020 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3021 entry->name, entry->length, entry->offset);
3022
3023 dataptr = (char *)attrhdr + entry->offset;
3024
3025 if (dataptr > endptr || dataptr < buffer) {
3026 copyfile_debug(1, "Entry %d overflows: offset = %u", i, entry->offset);
3027 error = -1;
3028 s->err = EINVAL; /* Invalid buffer */
3029 goto exit;
3030 }
3031 if (((char*)dataptr + entry->length) > (char*)endptr ||
3032 (((char*)dataptr + entry->length) < (char*)buffer) ||
3033 (entry->length > (size_t)hdrsize)) {
3034 if (COPYFILE_VERBOSE & s->flags)
3035 copyfile_warn("Incomplete or corrupt attribute entry");
3036 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
3037 i, entry->offset, entry->length);
3038 error = -1;
3039 s->err = EINVAL; /* Invalid buffer */
3040 goto exit;
3041 }
3042
3043 if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
3044 {
3045 qtn_file_t tqinfo = NULL;
3046
3047 if (s->qinfo == NULL)
3048 {
3049 tqinfo = qtn_file_alloc();
3050 if (tqinfo)
3051 {
3052 int x;
3053 if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0)
3054 {
3055 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x));
3056 qtn_file_free(tqinfo);
3057 tqinfo = NULL;
3058 }
3059 }
3060 }
3061 else
3062 {
3063 tqinfo = s->qinfo;
3064 }
3065 if (tqinfo)
3066 {
3067 int x;
3068 x = qtn_file_apply_to_fd(tqinfo, s->dst_fd);
3069 if (x != 0) {
3070 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x));
3071 if (s->statuscb) {
3072 int rv;
3073 s->xattr_name = (char*)XATTR_QUARANTINE_NAME;
3074 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3075 s->xattr_name = NULL;
3076 if (rv == COPYFILE_QUIT) {
3077 error = s->err = x < 0 ? ENOTSUP : errno;
3078 goto exit;
3079 }
3080 } else {
3081 error = s->err = x < 0 ? ENOTSUP : errno;
3082 goto exit;
3083 }
3084 }
3085 }
3086 if (tqinfo && !s->qinfo)
3087 {
3088 qtn_file_free(tqinfo);
3089 }
3090 }
3091 /* Look for ACL data */
3092 else if (strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)
3093 {
3094 acl_t acl;
3095 struct stat sb;
3096 int retry = 1;
3097 char *tcp = dataptr;
3098
3099 if (entry->length == 0) {
3100 /* Not sure how we got here, but we had one case
3101 * where it was 0. In a normal EA, we can have a 0-byte
3102 * payload. That means nothing in this case, so we'll
3103 * simply skip the EA.
3104 */
3105 error = 0;
3106 goto acl_done;
3107 }
3108 /*
3109 * acl_from_text() requires a NUL-terminated string. The ACL EA,
3110 * however, may not be NUL-terminated. So in that case, we need to
3111 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3112 */
3113 if (tcp[entry->length - 1] != 0) {
3114 char *tmpstr = malloc(entry->length + 1);
3115 if (tmpstr == NULL) {
3116 error = -1;
3117 goto exit;
3118 }
3119 strlcpy(tmpstr, tcp, entry->length + 1);
3120 acl = acl_from_text(tmpstr);
3121 free(tmpstr);
3122 } else {
3123 acl = acl_from_text(tcp);
3124 }
3125
3126 if (acl != NULL)
3127 {
3128 filesec_t fsec_tmp;
3129
3130 if ((fsec_tmp = filesec_init()) == NULL)
3131 error = -1;
3132 else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0)
3133 error = -1;
3134 else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0)
3135 error = -1;
3136 else {
3137 while (fchmodx_np(s->dst_fd, fsec_tmp) < 0)
3138 {
3139 if (errno == ENOTSUP)
3140 {
3141 if (retry && !copyfile_unset_acl(s))
3142 {
3143 retry = 0;
3144 continue;
3145 }
3146 }
3147 copyfile_warn("setting security information");
3148 error = -1;
3149 break;
3150 }
3151 }
3152 acl_free(acl);
3153 filesec_free(fsec_tmp);
3154
3155 acl_done:
3156 if (error == -1)
3157 goto exit;
3158 }
3159 }
3160 /* And, finally, everything else */
3161 else
3162 {
3163 if (s->statuscb) {
3164 int rv;
3165 s->xattr_name = strdup((char*)entry->name);
3166 s->totalCopied = 0;
3167 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3168 if (s->xattr_name) {
3169 free(s->xattr_name);
3170 s->xattr_name = NULL;
3171 }
3172 if (rv == COPYFILE_QUIT) {
3173 s->err = ECANCELED;
3174 error = -1;
3175 goto exit;
3176 }
3177 }
3178 if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
3179 if (COPYFILE_VERBOSE & s->flags)
3180 copyfile_warn("error %d setting attribute %s", error, entry->name);
3181 if (s->statuscb) {
3182 int rv;
3183
3184 s->xattr_name = strdup((char*)entry->name);
3185 rv = (s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3186 if (s->xattr_name) {
3187 free(s->xattr_name);
3188 s->xattr_name = NULL;
3189 }
3190 if (rv == COPYFILE_QUIT) {
3191 error = -1;
3192 goto exit;
3193 }
3194 } else {
3195 error = -1;
3196 goto exit;
3197 }
3198 } else if (s->statuscb) {
3199 int rv;
3200 s->xattr_name = strdup((char*)entry->name);
3201 s->totalCopied = entry->length;
3202 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3203 if (s->xattr_name) {
3204 free(s->xattr_name);
3205 s->xattr_name = NULL;
3206 }
3207 if (rv == COPYFILE_QUIT) {
3208 error = -1;
3209 s->err = ECANCELED;
3210 goto exit;
3211 }
3212 }
3213 }
3214 entry = ATTR_NEXT(entry);
3215 }
3216 }
3217
3218 /*
3219 * Extract the Finder Info.
3220 */
3221 if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) {
3222 error = -1;
3223 goto exit;
3224 }
3225
3226 if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0)
3227 {
3228 uint16_t *fFlags;
3229 uint8_t *newFinfo;
3230 enum { kFinderInvisibleMask = 1 << 14 };
3231
3232 newFinfo = (u_int8_t*)buffer + adhdr->entries[0].offset;
3233 fFlags = (uint16_t*)&newFinfo[8];
3234 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME);
3235 if (s->statuscb) {
3236 int rv;
3237 s->xattr_name = (char*)XATTR_FINDERINFO_NAME;
3238 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3239 s->xattr_name = NULL;
3240 if (rv == COPYFILE_QUIT) {
3241 error = -1;
3242 s->err = ECANCELED;
3243 goto exit;
3244 } else if (rv == COPYFILE_SKIP) {
3245 goto skip_fi;
3246 }
3247 }
3248 error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0);
3249 if (error) {
3250 if (s->statuscb) {
3251 int rv;
3252 s->xattr_name = XATTR_FINDERINFO_NAME;
3253 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3254 s->xattr_name = NULL;
3255 if (rv == COPYFILE_QUIT) {
3256 error = -1;
3257 s->err = ECANCELED;
3258 goto exit;
3259 }
3260 }
3261 goto exit;
3262 } else if (s->statuscb) {
3263 int rv;
3264 s->xattr_name = XATTR_FINDERINFO_NAME;
3265 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3266 s->xattr_name = NULL;
3267 if (rv == COPYFILE_QUIT) {
3268 error = -1;
3269 s->err = ECANCELED;
3270 goto exit;
3271 }
3272 }
3273 if (SWAP16(*fFlags) & kFinderInvisibleMask)
3274 s->internal_flags |= cfMakeFileInvisible;
3275 }
3276 skip_fi:
3277
3278 /*
3279 * Extract the Resource Fork.
3280 */
3281 if (adhdr->entries[1].type == AD_RESOURCE &&
3282 adhdr->entries[1].length > 0)
3283 {
3284 void * rsrcforkdata = NULL;
3285 size_t length;
3286 off_t offset;
3287 struct stat sb;
3288 struct timeval tval[2];
3289
3290 length = adhdr->entries[1].length;
3291 offset = adhdr->entries[1].offset;
3292 rsrcforkdata = malloc(length);
3293
3294 if (rsrcforkdata == NULL) {
3295 copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3296 length);
3297 error = -1;
3298 goto bad;
3299 }
3300
3301 if (fstat(s->dst_fd, &sb) < 0)
3302 {
3303 copyfile_debug(1, "couldn't stat destination file");
3304 error = -1;
3305 goto bad;
3306 }
3307
3308 bytes = pread(s->src_fd, rsrcforkdata, length, offset);
3309 if (bytes < (ssize_t)length)
3310 {
3311 if (bytes == -1)
3312 {
3313 copyfile_debug(1, "couldn't read resource fork");
3314 }
3315 else
3316 {
3317 copyfile_debug(1,
3318 "couldn't read resource fork (only read %d bytes of %d)",
3319 (int)bytes, (int)length);
3320 }
3321 error = -1;
3322 goto bad;
3323 }
3324 if (s->statuscb) {
3325 int rv;
3326 s->xattr_name = XATTR_RESOURCEFORK_NAME;
3327 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3328 s->xattr_name = NULL;
3329 if (rv == COPYFILE_QUIT) {
3330 error = -1;
3331 s->err = ECANCELED;
3332 if (rsrcforkdata)
3333 free(rsrcforkdata);
3334 goto exit;
3335 } else if (rv == COPYFILE_SKIP) {
3336 goto bad;
3337 }
3338 }
3339 error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0);
3340 if (error)
3341 {
3342 /*
3343 * For filesystems that do not natively support named attributes,
3344 * the kernel creates an AppleDouble file that -- for compatabilty
3345 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3346 * structure that says there are no resources. So, if fsetxattr has
3347 * failed, and the resource fork is that empty structure, *and* the
3348 * target file is a directory, then we do nothing with it.
3349 */
3350 if ((bytes == sizeof(rsrcfork_header_t)) &&
3351 ((sb.st_mode & S_IFMT) == S_IFDIR) &&
3352 (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) {
3353 copyfile_debug(2, "not setting empty resource fork on directory");
3354 error = errno = 0;
3355 goto bad;
3356 }
3357 if (s->statuscb) {
3358 int rv;
3359 s->xattr_name = XATTR_RESOURCEFORK_NAME;
3360 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3361 s->xattr_name = NULL;
3362 if (rv == COPYFILE_CONTINUE) {
3363 error = errno = 0;
3364 goto bad;
3365 }
3366 }
3367 copyfile_debug(1, "error %d setting resource fork attribute", error);
3368 error = -1;
3369 goto bad;
3370 } else if (s->statuscb) {
3371 int rv;
3372 s->xattr_name = XATTR_RESOURCEFORK_NAME;
3373 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3374 s->xattr_name = NULL;
3375 if (rv == COPYFILE_QUIT) {
3376 error = -1;
3377 s->err = ECANCELED;
3378 if (rsrcforkdata)
3379 free(rsrcforkdata);
3380 goto exit;
3381 }
3382 }
3383 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3384 XATTR_RESOURCEFORK_NAME, (int)length);
3385
3386 if (!(s->flags & COPYFILE_STAT))
3387 {
3388 tval[0].tv_sec = sb.st_atime;
3389 tval[1].tv_sec = sb.st_mtime;
3390 tval[0].tv_usec = tval[1].tv_usec = 0;
3391
3392 if (futimes(s->dst_fd, tval))
3393 copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
3394 }
3395 bad:
3396 if (rsrcforkdata)
3397 free(rsrcforkdata);
3398 }
3399
3400 if (COPYFILE_STAT & s->flags)
3401 {
3402 error = copyfile_stat(s);
3403 }
3404 exit:
3405 if (buffer) free(buffer);
3406 return error;
3407 }
3408
3409 static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len)
3410 {
3411 int ret = 0;
3412 char qbuf[QTN_SERIALIZED_DATA_MAX];
3413 size_t qlen = sizeof(qbuf);
3414
3415 if (s->qinfo == NULL)
3416 {
3417 ret = -1;
3418 goto done;
3419 }
3420
3421 if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0)
3422 {
3423 ret = -1;
3424 goto done;
3425 }
3426
3427 *buf = malloc(qlen);
3428 if (*buf)
3429 {
3430 memcpy(*buf, qbuf, qlen);
3431 *len = qlen;
3432 }
3433 done:
3434 return ret;
3435 }
3436
3437 static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len)
3438 {
3439 int ret = 0;
3440 acl_t acl = NULL;
3441 char *acl_text;
3442
3443 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0)
3444 {
3445 if (errno != ENOENT)
3446 {
3447 ret = -1;
3448 if (COPYFILE_VERBOSE & s->flags)
3449 copyfile_warn("getting acl");
3450 }
3451 *len = 0;
3452 goto exit;
3453 }
3454
3455 if ((acl_text = acl_to_text(acl, len)) != NULL)
3456 {
3457 /*
3458 * acl_to_text() doesn't include the NUL at the endo
3459 * in it's count (*len). It does, however, promise to
3460 * return a valid C string, so we need to up the count
3461 * by 1.
3462 */
3463 *len = *len + 1;
3464 *buf = malloc(*len);
3465 if (*buf)
3466 memcpy(*buf, acl_text, *len);
3467 else
3468 *len = 0;
3469 acl_free(acl_text);
3470 }
3471 copyfile_debug(2, "copied acl (%ld) %p", *len, *buf);
3472 exit:
3473 if (acl)
3474 acl_free(acl);
3475 return ret;
3476 }
3477
3478 static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr)
3479 {
3480 ssize_t datasize;
3481 char *databuf = NULL;
3482 int ret = 0;
3483
3484 /*
3485 * XXX
3486 * do COPYFILE_COPY_XATTR here; no need to
3487 * the work if we want to skip.
3488 */
3489
3490 if (s->statuscb)
3491 {
3492 int rv;
3493
3494 s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME;
3495
3496 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3497 s->xattr_name = NULL;
3498 if (rv == COPYFILE_SKIP) {
3499 ret = 0;
3500 goto done;
3501 }
3502 if (rv == COPYFILE_QUIT) {
3503 ret = -1;
3504 s->err = ECANCELED;
3505 goto done;
3506 }
3507 }
3508 /* Get the resource fork size */
3509 if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0)
3510 {
3511 if (COPYFILE_VERBOSE & s->flags)
3512 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno);
3513 return -1;
3514 }
3515
3516 if (datasize > INT_MAX) {
3517 s->err = EINVAL;
3518 ret = -1;
3519 goto done;
3520 }
3521
3522 if (s->statuscb) {
3523 int rv;
3524 s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME;
3525
3526 s->totalCopied = 0;
3527 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
3528 s->xattr_name = NULL;
3529 if (rv == COPYFILE_QUIT) {
3530 s->err = ECANCELED;
3531 ret = -1;
3532 goto done;
3533 }
3534 }
3535 if ((databuf = malloc(datasize)) == NULL)
3536 {
3537 copyfile_warn("malloc");
3538 ret = -1;
3539 goto done;
3540 }
3541
3542 if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize)
3543 {
3544 if (COPYFILE_VERBOSE & s->flags)
3545 copyfile_warn("couldn't read entire resource fork");
3546 ret = -1;
3547 goto done;
3548 }
3549
3550 /* Write the resource fork to disk. */
3551 if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize)
3552 {
3553 if (COPYFILE_VERBOSE & s->flags)
3554 copyfile_warn("couldn't write resource fork");
3555 }
3556 if (s->statuscb)
3557 {
3558 int rv;
3559 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3560 if (rv == COPYFILE_QUIT) {
3561 ret = -1;
3562 goto done;
3563 }
3564 }
3565 copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3566 datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset);
3567 filehdr->appledouble.entries[1].length = (u_int32_t)datasize;
3568
3569 done:
3570 if (ret == -1 && s->statuscb)
3571 {
3572 int rv;
3573 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3574 if (rv == COPYFILE_CONTINUE)
3575 ret = 0;
3576 }
3577 if (s->xattr_name) {
3578 s->xattr_name = NULL;
3579 }
3580 if (databuf)
3581 free(databuf);
3582
3583 /*
3584 * XXX
3585 * Do status callback here
3586 * If ret == -1, then error callback
3587 */
3588 return ret;
3589 }
3590
3591 /*
3592 * The opposite of copyfile_unpack(), obviously.
3593 */
3594 static int copyfile_pack(copyfile_state_t s)
3595 {
3596 char *attrnamebuf = NULL, *endnamebuf;
3597 void *databuf = NULL;
3598 attr_header_t *filehdr, *endfilehdr;
3599 attr_entry_t *entry;
3600 ssize_t listsize = 0;
3601 char *nameptr;
3602 size_t namelen;
3603 size_t entrylen;
3604 ssize_t datasize;
3605 size_t offset = 0;
3606 int hasrsrcfork = 0;
3607 int error = 0;
3608 int seenq = 0; // Have we seen any quarantine info already?
3609
3610 filehdr = (attr_header_t *) calloc(1, ATTR_MAX_SIZE);
3611 if (filehdr == NULL) {
3612 error = -1;
3613 goto exit;
3614 } else {
3615 endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_SIZE);
3616 }
3617
3618 attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
3619 if (attrnamebuf == NULL) {
3620 error = -1;
3621 goto exit;
3622 } else {
3623 endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE;
3624 }
3625
3626 /*
3627 * Fill in the Apple Double Header defaults.
3628 */
3629 filehdr->appledouble.magic = ADH_MAGIC;
3630 filehdr->appledouble.version = ADH_VERSION;
3631 filehdr->appledouble.numEntries = 2;
3632 filehdr->appledouble.entries[0].type = AD_FINDERINFO;
3633 filehdr->appledouble.entries[0].offset = (u_int32_t)offsetof(apple_double_header_t, finfo);
3634 filehdr->appledouble.entries[0].length = FINDERINFOSIZE;
3635 filehdr->appledouble.entries[1].type = AD_RESOURCE;
3636 filehdr->appledouble.entries[1].offset = (u_int32_t)offsetof(apple_double_header_t, pad);
3637 filehdr->appledouble.entries[1].length = 0;
3638 bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler));
3639
3640 /*
3641 * Fill in the initial Attribute Header.
3642 */
3643 filehdr->magic = ATTR_HDR_MAGIC;
3644 filehdr->debug_tag = 0;
3645 filehdr->data_start = (u_int32_t)sizeof(attr_header_t);
3646
3647 /*
3648 * Collect the attribute names.
3649 */
3650 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3651
3652 /*
3653 * Test if there are acls to copy
3654 */
3655 if (COPYFILE_ACL & s->flags)
3656 {
3657 acl_t temp_acl = NULL;
3658 if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0)
3659 {
3660 copyfile_debug(2, "no acl entries found (errno = %d)", errno);
3661 } else
3662 {
3663 offset = strlen(XATTR_SECURITY_NAME) + 1;
3664 strcpy(attrnamebuf, XATTR_SECURITY_NAME);
3665 endnamebuf = attrnamebuf + offset;
3666 }
3667 if (temp_acl)
3668 acl_free(temp_acl);
3669 }
3670
3671 if (COPYFILE_XATTR & s->flags)
3672 {
3673 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3674 if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0)
3675 {
3676 copyfile_debug(2, "no extended attributes found (%d)", errno);
3677 }
3678 if (listsize > left)
3679 {
3680 copyfile_debug(1, "extended attribute list too long");
3681 listsize = left;
3682 }
3683
3684 endnamebuf = attrnamebuf + offset + (listsize > 0 ? listsize : 0);
3685 if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) {
3686 error = -1;
3687 goto exit;
3688 }
3689
3690 if (listsize > 0)
3691 sort_xattrname_list(attrnamebuf, endnamebuf - attrnamebuf);
3692
3693 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen)
3694 {
3695 namelen = strlen(nameptr) + 1;
3696 /* Skip over FinderInfo or Resource Fork names */
3697 if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 ||
3698 strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) {
3699 continue;
3700 }
3701 if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) {
3702 seenq = 1;
3703 }
3704
3705 /* The system should prevent this from happening, but... */
3706 if (namelen > XATTR_MAXNAMELEN + 1) {
3707 namelen = XATTR_MAXNAMELEN + 1;
3708 }
3709 if (s->statuscb) {
3710 int rv;
3711 char eaname[namelen];
3712 bcopy(nameptr, eaname, namelen);
3713 eaname[namelen] = 0; // Just to be sure!
3714 s->xattr_name = eaname;
3715 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3716 s->xattr_name = NULL;
3717 if (rv == COPYFILE_QUIT) {
3718 error = -1;
3719 s->err = ECANCELED;
3720 goto exit;
3721 } else if (rv == COPYFILE_SKIP) {
3722 size_t amt = endnamebuf - (nameptr + namelen);
3723 memmove(nameptr, nameptr + namelen, amt);
3724 endnamebuf -= namelen;
3725 /* Set namelen to 0 so continue doesn't miss names */
3726 namelen = 0;
3727 continue;
3728 }
3729 }
3730 entry->namelen = namelen;
3731 entry->flags = 0;
3732 if (nameptr + namelen > endnamebuf) {
3733 error = -1;
3734 goto exit;
3735 }
3736
3737 bcopy(nameptr, &entry->name[0], namelen);
3738 copyfile_debug(2, "copied name [%s]", entry->name);
3739
3740 entrylen = ATTR_ENTRY_LENGTH(namelen);
3741 entry = (attr_entry_t *)(((char *)entry) + entrylen);
3742
3743 if ((void*)entry >= (void*)endfilehdr) {
3744 error = -1;
3745 goto exit;
3746 }
3747
3748 /* Update the attributes header. */
3749 filehdr->num_attrs++;
3750 filehdr->data_start += (u_int32_t)entrylen;
3751 }
3752 }
3753
3754 /*
3755 * If we have any quarantine data, we always pack it.
3756 * But if we've already got it in the EA list, don't put it in again.
3757 */
3758 if (s->qinfo && !seenq)
3759 {
3760 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3761 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3762 offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1;
3763 }
3764
3765 seenq = 0;
3766 /*
3767 * Collect the attribute data.
3768 */
3769 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3770
3771 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen + 1)
3772 {
3773 namelen = strlen(nameptr);
3774
3775 if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0)
3776 copyfile_pack_acl(s, &databuf, &datasize);
3777 else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0)
3778 {
3779 copyfile_pack_quarantine(s, &databuf, &datasize);
3780 }
3781 /* Check for Finder Info. */
3782 else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0)
3783 {
3784 if (s->statuscb)
3785 {
3786 int rv;
3787 s->xattr_name = (char*)XATTR_FINDERINFO_NAME;
3788 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3789 s->xattr_name = NULL;
3790 if (rv == COPYFILE_QUIT)
3791 {
3792 s->xattr_name = NULL;
3793 s->err = ECANCELED;
3794 error = -1;
3795 goto exit;
3796 }
3797 else if (rv == COPYFILE_SKIP)
3798 {
3799 s->xattr_name = NULL;
3800 continue;
3801 }
3802 s->totalCopied = 0;
3803 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
3804 s->xattr_name = NULL;
3805 if (rv == COPYFILE_QUIT)
3806 {
3807 s->err = ECANCELED;
3808 error = -1;
3809 goto exit;
3810 }
3811 }
3812 datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0);
3813 if (datasize < 0)
3814 {
3815 if (s->statuscb) {
3816 int rv;
3817 s->xattr_name = strdup(nameptr);
3818 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3819 if (s->xattr_name) {
3820 free(s->xattr_name);
3821 s->xattr_name = NULL;
3822 }
3823 if (rv == COPYFILE_QUIT) {
3824 error = -1;
3825 goto exit;
3826 }
3827 }
3828 if (COPYFILE_VERBOSE & s->flags)
3829 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
3830 } else if (datasize != 32)
3831 {
3832 if (COPYFILE_VERBOSE & s->flags)
3833 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr);
3834 } else
3835 {
3836 if (COPYFILE_VERBOSE & s->flags)
3837 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3838 XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset);
3839 if (s->statuscb) {
3840 int rv;
3841 s->xattr_name = strdup(nameptr);
3842 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3843 if (s->xattr_name) {
3844 free(s->xattr_name);
3845 s->xattr_name = NULL;
3846 }
3847 if (rv == COPYFILE_QUIT) {
3848 error = -1;
3849 goto exit;
3850 }
3851 }
3852 }
3853 continue; /* finder info doesn't have an attribute entry */
3854 }
3855 /* Check for Resource Fork. */
3856 else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0)
3857 {
3858 hasrsrcfork = 1;
3859 continue;
3860 } else
3861 {
3862 /* Just a normal attribute. */
3863 if (s->statuscb)
3864 {
3865 int rv;
3866 s->xattr_name = strdup(nameptr);
3867 s->totalCopied = 0;
3868 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
3869 if (s->xattr_name) {
3870 free(s->xattr_name);
3871 s->xattr_name = NULL;
3872 }
3873 /*
3874 * Due to the nature of the packed file, we can't skip at this point.
3875 */
3876 if (rv == COPYFILE_QUIT)
3877 {
3878 s->err = ECANCELED;
3879 error = -1;
3880 goto exit;
3881 }
3882 }
3883 datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0);
3884 if (datasize == 0)
3885 goto next;
3886 if (datasize < 0)
3887 {
3888 if (COPYFILE_VERBOSE & s->flags)
3889 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
3890 if (s->statuscb)
3891 {
3892 int rv;
3893 s->xattr_name = strdup(nameptr);
3894 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3895 if (s->xattr_name) {
3896 free(s->xattr_name);
3897 s->xattr_name = NULL;
3898 }
3899 if (rv == COPYFILE_QUIT)
3900 {
3901 s->err = ECANCELED;
3902 error = -1;
3903 goto exit;
3904 }
3905 }
3906 goto next;
3907 }
3908 if (datasize > XATTR_MAXATTRLEN)
3909 {
3910 if (COPYFILE_VERBOSE & s->flags)
3911 copyfile_warn("skipping attr \"%s\" (too big)", nameptr);
3912 goto next;
3913 }
3914 databuf = malloc(datasize);
3915 if (databuf == NULL) {
3916 error = -1;
3917 continue;
3918 }
3919 datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0);
3920 if (s->statuscb) {
3921 int rv;
3922 s->xattr_name = strdup(nameptr);
3923 rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3924 if (s->xattr_name) {
3925 free(s->xattr_name);
3926 s->xattr_name = NULL;
3927 }
3928 if (rv == COPYFILE_QUIT) {
3929 s->err = ECANCELED;
3930 error = -1;
3931 goto exit;
3932 }
3933 }
3934 }
3935
3936 entry->length = (u_int32_t)datasize;
3937 entry->offset = filehdr->data_start + filehdr->data_length;
3938
3939 filehdr->data_length += (u_int32_t)datasize;
3940 /*
3941 * >>> WARNING <<<
3942 * This assumes that the data is fits in memory (not
3943 * the case when there are lots of attributes or one of
3944 * the attributes is very large.
3945 */
3946 if (entry->offset > ATTR_MAX_SIZE ||
3947 (entry->offset + datasize > ATTR_MAX_SIZE)) {
3948 error = 1;
3949 } else {
3950 bcopy(databuf, (char*)filehdr + entry->offset, datasize);
3951 }
3952 free(databuf);
3953
3954 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
3955 next:
3956 /* bump to next entry */
3957 entrylen = ATTR_ENTRY_LENGTH(entry->namelen);
3958 entry = (attr_entry_t *)((char *)entry + entrylen);
3959 }
3960
3961 if (filehdr->data_length > 0)
3962 {
3963 /* Now we know where the resource fork data starts. */
3964 filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
3965
3966 /* We also know the size of the "Finder Info entry. */
3967 filehdr->appledouble.entries[0].length =
3968 filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
3969
3970 filehdr->total_size = filehdr->appledouble.entries[1].offset;
3971 }
3972
3973 /* Copy Resource Fork. */
3974 if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
3975 goto exit;
3976
3977 /* Write the header to disk. */
3978 datasize = filehdr->appledouble.entries[1].offset;
3979
3980 swap_adhdr(&filehdr->appledouble);
3981 swap_attrhdr(filehdr);
3982
3983 if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize)
3984 {
3985 if (COPYFILE_VERBOSE & s->flags)
3986 copyfile_warn("couldn't write file header");
3987 error = -1;
3988 goto exit;
3989 }
3990 exit:
3991 if (filehdr) free(filehdr);
3992 if (attrnamebuf) free(attrnamebuf);
3993
3994 if (error)
3995 return error;
3996 else
3997 return copyfile_stat(s);
3998 }