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