]> git.saurik.com Git - apple/copyfile.git/blob - copyfile.c
copyfile-41.tar.gz
[apple/copyfile.git] / copyfile.c
1 /*
2 * Copyright (c) 2004 Apple Computer, 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/syscall.h>
40 #include <sys/param.h>
41 #include <sys/mount.h>
42 #include <sys/acl.h>
43 #include <libkern/OSByteOrder.h>
44 #include <membership.h>
45
46 #include <quarantine.h>
47
48 #define XATTR_QUARANTINE_NAME qtn_xattr_name
49
50 #include "copyfile.h"
51
52 /*
53 * The state structure keeps track of
54 * the source filename, the destination filename, their
55 * associated file-descriptors, the stat infomration for the
56 * source file, the security information for the source file,
57 * the flags passed in for the copy, a pointer to place statistics
58 * (not currently implemented), debug flags, and a pointer to callbacks
59 * (not currently implemented).
60 */
61 struct _copyfile_state
62 {
63 char *src;
64 char *dst;
65 int src_fd;
66 int dst_fd;
67 struct stat sb;
68 filesec_t fsec;
69 copyfile_flags_t flags;
70 void *stats;
71 uint32_t debug;
72 void *callbacks;
73 qtn_file_t qinfo; /* Quarantine information -- probably NULL */
74 };
75
76 /*
77 * Internally, the process is broken into a series of
78 * private functions.
79 */
80 static int copyfile_open (copyfile_state_t);
81 static int copyfile_close (copyfile_state_t);
82 static int copyfile_data (copyfile_state_t);
83 static int copyfile_stat (copyfile_state_t);
84 static int copyfile_security (copyfile_state_t);
85 static int copyfile_xattr (copyfile_state_t);
86 static int copyfile_pack (copyfile_state_t);
87 static int copyfile_unpack (copyfile_state_t);
88
89 static copyfile_flags_t copyfile_check (copyfile_state_t);
90 static filesec_t copyfile_fix_perms(copyfile_state_t, filesec_t *);
91 static int copyfile_preamble(copyfile_state_t *s, copyfile_flags_t flags);
92 static int copyfile_internal(copyfile_state_t state, copyfile_flags_t flags);
93 static int copyfile_unset_posix_fsec(filesec_t);
94 static int copyfile_quarantine(copyfile_state_t);
95
96 #define COPYFILE_DEBUG (1<<31)
97 #define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
98
99 #ifndef _COPYFILE_TEST
100 # define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
101 # define copyfile_debug(d, str, ...) \
102 do { \
103 if (s && (d <= s->debug)) {\
104 syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
105 } \
106 } while (0)
107 #else
108 #define copyfile_warn(str, ...) \
109 fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
110 # define copyfile_debug(d, str, ...) \
111 do { \
112 if (s && (d <= s->debug)) {\
113 fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
114 } \
115 } while(0)
116 #endif
117
118 static int copyfile_quarantine(copyfile_state_t s)
119 {
120 int rv = 0;
121 if (s->qinfo == NULL)
122 {
123 int error;
124 s->qinfo = qtn_file_alloc();
125 if (s->qinfo == NULL)
126 {
127 rv = -1;
128 goto done;
129 }
130 if ((error = qtn_file_init_with_fd(s->qinfo, s->src_fd)) != 0)
131 {
132 qtn_file_free(s->qinfo);
133 s->qinfo = NULL;
134 errno = error;
135 rv = -1;
136 goto done;
137 }
138 }
139 done:
140 return rv;
141 }
142
143 /*
144 * fcopyfile() is used to copy a source file descriptor to a destination file
145 * descriptor. This allows an application to figure out how it wants to open
146 * the files (doing various security checks, perhaps), and then just pass in
147 * the file descriptors.
148 */
149 int fcopyfile(int src_fd, int dst_fd, copyfile_state_t state, copyfile_flags_t flags)
150 {
151 int ret = 0;
152 copyfile_state_t s = state;
153 struct stat dst_sb;
154
155 if (src_fd < 0 || dst_fd < 0)
156 {
157 errno = EINVAL;
158 return -1;
159 }
160
161 if (copyfile_preamble(&s, flags) < 0)
162 return -1;
163
164 copyfile_debug(2, "set src_fd <- %d", src_fd);
165 if (s->src_fd == -2 && src_fd > -1)
166 {
167 s->src_fd = src_fd;
168 if (fstatx_np(s->src_fd, &s->sb, s->fsec) != 0)
169 {
170 if (errno == ENOTSUP)
171 fstat(s->src_fd, &s->sb);
172 else
173 {
174 copyfile_warn("fstatx_np on src fd %d", s->src_fd);
175 return -1;
176 }
177 }
178 }
179
180 /* prevent copying on unsupported types */
181 switch (s->sb.st_mode & S_IFMT)
182 {
183 case S_IFLNK:
184 case S_IFDIR:
185 case S_IFREG:
186 break;
187 default:
188 errno = ENOTSUP;
189 return -1;
190 }
191
192 copyfile_debug(2, "set dst_fd <- %d", dst_fd);
193 if (s->dst_fd == -2 && dst_fd > -1)
194 s->dst_fd = dst_fd;
195
196 (void)fstat(s->dst_fd, &dst_sb);
197 (void)fchmod(s->dst_fd, (dst_sb.st_mode & ~S_IFMT) | (S_IRUSR | S_IWUSR));
198
199 (void)copyfile_quarantine(s);
200
201 ret = copyfile_internal(s, flags);
202
203 if (ret >= 0 && !(s->flags & COPYFILE_STAT))
204 {
205 (void)fchmod(s->dst_fd, dst_sb.st_mode & ~S_IFMT);
206 }
207
208 if (state == NULL)
209 copyfile_state_free(s);
210
211 return ret;
212
213 }
214
215 /*
216 * the original copyfile() routine; this copies a source file to a destination
217 * file. Note that because we need to set the names in the state variable, this
218 * is not just the same as opening the two files, and then calling fcopyfile().
219 * Oh, if only life were that simple!
220 */
221 int copyfile(const char *src, const char *dst, copyfile_state_t state, copyfile_flags_t flags)
222 {
223 int ret = 0;
224 copyfile_state_t s = state;
225 filesec_t original_fsec = NULL;
226 filesec_t permissive_fsec = NULL;
227 struct stat sb;
228
229 if (src == NULL && dst == NULL)
230 {
231 errno = EINVAL;
232 return -1;
233 }
234
235 if (copyfile_preamble(&s, flags) < 0)
236 {
237 return -1;
238 }
239
240 /*
241 * This macro is... well, it's not the worst thing you can do with cpp, not
242 * by a long shot. Essentially, we are setting the filename (src or dst)
243 * in the state structure; since the structure may not have been cleared out
244 * before being used again, we do some of the cleanup here: if the given
245 * filename (e.g., src) is set, and state->src is not equal to that, then
246 * we need to check to see if the file descriptor had been opened, and if so,
247 * close it. After that, we set state->src to be a copy of the given filename,
248 * releasing the old copy if necessary.
249 */
250 #define COPYFILE_SET_FNAME(NAME, S) \
251 do { \
252 if (NAME != NULL) { \
253 if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) { \
254 copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
255 if (S->NAME##_fd != -2 && S->NAME##_fd > -1) { \
256 copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd); \
257 close(S->NAME##_fd); \
258 S->NAME##_fd = -2; \
259 } \
260 } \
261 if (S->NAME) { \
262 free(S->NAME); \
263 S->NAME = NULL; \
264 } \
265 if ((S->NAME = strdup(NAME)) == NULL) \
266 return -1; \
267 } \
268 } while (0)
269
270 COPYFILE_SET_FNAME(src, s);
271 COPYFILE_SET_FNAME(dst, s);
272
273 /*
274 * Get a copy of the source file's security settings
275 */
276 if ((original_fsec = filesec_init()) == NULL)
277 goto error_exit;
278
279 if(statx_np(s->dst, &sb, original_fsec) == 0)
280 {
281 /*
282 * copyfile_fix_perms() will make a copy of the permission set,
283 * and insert at the beginning an ACE that ensures we can write
284 * to the file and set attributes.
285 */
286
287 if((permissive_fsec = copyfile_fix_perms(s, &original_fsec)) != NULL)
288 {
289 /*
290 * Set the permissions for the destination to our copy.
291 * We should get ENOTSUP from any filesystem that simply
292 * doesn't support it.
293 */
294 if (chmodx_np(s->dst, permissive_fsec) < 0 && errno != ENOTSUP)
295 {
296 copyfile_warn("setting security information");
297 filesec_free(permissive_fsec);
298 permissive_fsec = NULL;
299 }
300 }
301 }
302
303 /*
304 * If COPYFILE_CHECK is set in flags, then all we are going to do
305 * is see what kinds of things WOULD have been copied (see
306 * copyfile_check() below). We return that value.
307 */
308 if (COPYFILE_CHECK & flags)
309 {
310 ret = copyfile_check(s);
311 goto exit;
312 } else if ((ret = copyfile_open(s)) < 0)
313 goto error_exit;
314
315 ret = copyfile_internal(s, flags);
316
317 /* If we haven't reset the file security information
318 * (COPYFILE_SECURITY is not set in flags)
319 * restore back the permissions the file had originally
320 *
321 * One of the reasons this seems so complicated is that
322 * it is partially at odds with copyfile_security().
323 *
324 * Simplisticly, we are simply trying to make sure we
325 * only copy what was requested, and that we don't stomp
326 * on what wasn't requsted.
327 */
328
329 if (permissive_fsec && (s->flags & COPYFILE_SECURITY) != COPYFILE_SECURITY) {
330 if (s->flags & COPYFILE_ACL) {
331 /* Just need to reset the BSD information -- mode, owner, group */
332 (void)fchown(s->dst_fd, sb.st_uid, sb.st_gid);
333 (void)fchmod(s->dst_fd, sb.st_mode);
334 } else {
335 /*
336 * flags is either COPYFILE_STAT, or neither; if it's
337 * neither, then we restore both ACL and POSIX permissions;
338 * if it's STAT, however, then we only want to restore the
339 * ACL (which may be empty). We do that by removing the
340 * POSIX information from the filesec object.
341 */
342 if (s->flags & COPYFILE_STAT) {
343 copyfile_unset_posix_fsec(original_fsec);
344 }
345 if (fchmodx_np(s->dst_fd, original_fsec) < 0 && errno != ENOTSUP)
346 copyfile_warn("restoring security information");
347 }
348 }
349 exit:
350 if (state == NULL)
351 copyfile_state_free(s);
352
353 if (original_fsec)
354 filesec_free(original_fsec);
355 if (permissive_fsec)
356 filesec_free(permissive_fsec);
357
358 return ret;
359
360 error_exit:
361 ret = -1;
362 goto exit;
363 }
364
365 /*
366 * Shared prelude to the {f,}copyfile(). This initializes the
367 * state variable, if necessary, and also checks for both debugging
368 * and disabling environment variables.
369 */
370 static int copyfile_preamble(copyfile_state_t *state, copyfile_flags_t flags)
371 {
372 copyfile_state_t s;
373
374 if (*state == NULL)
375 {
376 if ((*state = copyfile_state_alloc()) == NULL)
377 return -1;
378 }
379
380 s = *state;
381
382 if (COPYFILE_DEBUG & flags)
383 {
384 char *e;
385 if ((e = getenv(COPYFILE_DEBUG_VAR)))
386 {
387 errno = 0;
388 s->debug = (uint32_t)strtol(e, NULL, 0);
389
390 /* clamp s->debug to 1 if the environment variable is not parsable */
391 if (s->debug == 0 && errno != 0)
392 s->debug = 1;
393 }
394 copyfile_debug(2, "debug value set to: %d", s->debug);
395 }
396
397 #if 0
398 /* Temporarily disabled */
399 if (getenv(COPYFILE_DISABLE_VAR) != NULL)
400 {
401 copyfile_debug(1, "copyfile disabled");
402 return 2;
403 }
404 #endif
405 copyfile_debug(2, "setting flags: %d", s->flags);
406 s->flags = flags;
407
408 return 0;
409 }
410
411 /*
412 * The guts of {f,}copyfile().
413 * This looks through the flags in a particular order, and calls the
414 * associated functions.
415 */
416 static int copyfile_internal(copyfile_state_t s, copyfile_flags_t flags)
417 {
418 int ret = 0;
419
420 if (s->dst_fd < 0 || s->src_fd < 0)
421 {
422 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
423 s->src_fd, s->dst_fd);
424 errno = EINVAL;
425 return -1;
426 }
427
428 /*
429 * COPYFILE_PACK causes us to create an Apple Double version of the
430 * source file, and puts it into the destination file. See
431 * copyfile_pack() below for all the gory details.
432 */
433 if (COPYFILE_PACK & flags)
434 {
435 if ((ret = copyfile_pack(s)) < 0)
436 {
437 unlink(s->dst);
438 goto exit;
439 }
440 goto exit;
441 }
442
443 /*
444 * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
445 * The goal there is to take an Apple Double file, and turn it
446 * into a normal file (with data fork, resource fork, modes,
447 * extended attributes, ACLs, etc.).
448 */
449 if (COPYFILE_UNPACK & flags)
450 {
451 if ((ret = copyfile_unpack(s)) < 0)
452 goto error_exit;
453 goto exit;
454 }
455
456 /*
457 * If we have quarantine info set, we attempt
458 * to apply it to dst_fd. We don't care if
459 * it fails, not yet anyway.
460 */
461 if (s->qinfo)
462 (void)qtn_file_apply_to_fd(s->qinfo, s->dst_fd);
463
464 /*
465 * COPYFILE_XATTR tells us to copy the extended attributes;
466 * this is seperate from the extended security (aka ACLs),
467 * however. If we succeed in this, we continue to the next
468 * stage; if we fail, we return with an error value. Note
469 * that we fail if the errno is ENOTSUP, but we don't print
470 * a warning in that case.
471 */
472 if (COPYFILE_XATTR & flags)
473 {
474 if ((ret = copyfile_xattr(s)) < 0)
475 {
476 if (errno != ENOTSUP)
477 copyfile_warn("error processing extended attributes");
478 goto exit;
479 }
480 }
481
482 /*
483 * Simialr to above, this tells us whether or not to copy
484 * the non-meta data portion of the file. We attempt to
485 * remove (via unlink) the destination file if we fail.
486 */
487 if (COPYFILE_DATA & flags)
488 {
489 if ((ret = copyfile_data(s)) < 0)
490 {
491 copyfile_warn("error processing data");
492 if (s->dst && unlink(s->dst))
493 copyfile_warn("%s: remove", s->src);
494 goto exit;
495 }
496 }
497
498 /*
499 * COPYFILE_SECURITY requests that we copy the security, both
500 * extended and mundane (that is, ACLs and POSIX).
501 */
502 if (COPYFILE_SECURITY & flags)
503 {
504 if ((ret = copyfile_security(s)) < 0)
505 {
506 copyfile_warn("error processing security information");
507 goto exit;
508 }
509 }
510
511 if (COPYFILE_STAT & flags)
512 {
513 if ((ret = copyfile_stat(s)) < 0)
514 {
515 copyfile_warn("error processing POSIX information");
516 goto exit;
517 }
518 }
519
520 exit:
521 return ret;
522
523 error_exit:
524 ret = -1;
525 goto exit;
526 }
527
528 /*
529 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
530 */
531 copyfile_state_t copyfile_state_alloc(void)
532 {
533 copyfile_state_t s = (copyfile_state_t) calloc(1, sizeof(struct _copyfile_state));
534
535 if (s != NULL)
536 {
537 s->src_fd = -2;
538 s->dst_fd = -2;
539 s->fsec = filesec_init();
540 } else
541 errno = ENOMEM;
542
543 return s;
544 }
545
546 /*
547 * copyfile_state_free() returns the memory allocated to the state structure.
548 * It also closes the file descriptors, if they've been opened.
549 */
550 int copyfile_state_free(copyfile_state_t s)
551 {
552 if (s != NULL)
553 {
554 if (s->fsec)
555 filesec_free(s->fsec);
556
557 if (s->qinfo)
558 qtn_file_free(s->qinfo);
559
560 if (copyfile_close(s) < 0)
561 {
562 copyfile_warn("error closing files");
563 return -1;
564 }
565 if (s->dst)
566 free(s->dst);
567 if (s->src)
568 free(s->src);
569 free(s);
570 }
571 return 0;
572 }
573
574 /*
575 * Should we worry if we can't close the source? NFS says we
576 * should, but it's pretty late for us at this point.
577 */
578 static int copyfile_close(copyfile_state_t s)
579 {
580 if (s->src && s->src_fd >= 0)
581 close(s->src_fd);
582
583 if (s->dst && s->dst_fd >= 0) {
584 if (close(s->dst_fd))
585 return -1;
586 }
587
588 return 0;
589 }
590
591 /*
592 * The purpose of this function is to set up a set of permissions
593 * (ACL and traditional) that lets us write to the file. In the
594 * case of ACLs, we do this by putting in a first entry that lets
595 * us write data, attributes, and extended attributes. In the case
596 * of traditional permissions, we set the S_IWUSR (user-write)
597 * bit.
598 */
599 static filesec_t copyfile_fix_perms(copyfile_state_t s __unused, filesec_t *fsec)
600 {
601 filesec_t ret_fsec = NULL;
602 mode_t mode;
603 acl_t acl = NULL;
604
605 if ((ret_fsec = filesec_dup(*fsec)) == NULL)
606 goto error_exit;
607
608 if (filesec_get_property(ret_fsec, FILESEC_ACL, &acl) == 0)
609 {
610 acl_entry_t entry;
611 acl_permset_t permset;
612 uuid_t qual;
613
614 if (mbr_uid_to_uuid(getuid(), qual) != 0)
615 goto error_exit;
616
617 /*
618 * First, we create an entry, and give it the special name
619 * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
620 * After that, we clear out all the permissions in it, and
621 * add three permissions: WRITE_DATA, WRITE_ATTRIBUTES, and
622 * WRITE_EXTATTRIBUTES. We put these into an ACE that allows
623 * the functionality, and put this into the ACL.
624 */
625 if (acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY) == -1)
626 goto error_exit;
627 if (acl_get_permset(entry, &permset) == -1)
628 goto error_exit;
629 if (acl_clear_perms(permset) == -1)
630 goto error_exit;
631 if (acl_add_perm(permset, ACL_WRITE_DATA) == -1)
632 goto error_exit;
633 if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1)
634 goto error_exit;
635 if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1)
636 goto error_exit;
637 if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1)
638 goto error_exit;
639
640 if(acl_set_permset(entry, permset) == -1)
641 goto error_exit;
642 if(acl_set_qualifier(entry, qual) == -1)
643 goto error_exit;
644
645 if (filesec_set_property(ret_fsec, FILESEC_ACL, &acl) != 0)
646 goto error_exit;
647 }
648
649 /*
650 * This is for the normal, mundane, POSIX permission model.
651 * We make sure that we can write to the file.
652 */
653 if (filesec_get_property(ret_fsec, FILESEC_MODE, &mode) == 0)
654 {
655 if ((mode & (S_IWUSR | S_IRUSR)) != (S_IWUSR | S_IRUSR))
656 {
657 mode |= S_IWUSR|S_IRUSR;
658 if (filesec_set_property(ret_fsec, FILESEC_MODE, &mode) != 0)
659 goto error_exit;
660 }
661 }
662
663 exit:
664 if (acl)
665 acl_free(acl);
666
667 return ret_fsec;
668
669 error_exit:
670 if (ret_fsec)
671 {
672 filesec_free(ret_fsec);
673 ret_fsec = NULL;
674 }
675 goto exit;
676 }
677
678 /*
679 * Used to clear out the BSD/POSIX security information from
680 * a filesec
681 */
682 static int
683 copyfile_unset_posix_fsec(filesec_t fsec)
684 {
685 (void)filesec_set_property(fsec, FILESEC_OWNER, _FILESEC_UNSET_PROPERTY);
686 (void)filesec_set_property(fsec, FILESEC_GROUP, _FILESEC_UNSET_PROPERTY);
687 (void)filesec_set_property(fsec, FILESEC_MODE, _FILESEC_UNSET_PROPERTY);
688 return 0;
689 }
690
691 /*
692 * Used to remove acl information from a filesec_t
693 * Unsetting the acl alone in Tiger was insufficient
694 */
695 static int copyfile_unset_acl(copyfile_state_t s)
696 {
697 int ret = 0;
698 if (filesec_set_property(s->fsec, FILESEC_ACL, NULL) == -1)
699 {
700 copyfile_debug(5, "unsetting acl attribute on %s", s->dst);
701 ++ret;
702 }
703 if (filesec_set_property(s->fsec, FILESEC_UUID, NULL) == -1)
704 {
705 copyfile_debug(5, "unsetting uuid attribute on %s", s->dst);
706 ++ret;
707 }
708 if (filesec_set_property(s->fsec, FILESEC_GRPUUID, NULL) == -1)
709 {
710 copyfile_debug(5, "unsetting group uuid attribute on %s", s->dst);
711 ++ret;
712 }
713 return ret;
714 }
715
716 /*
717 * copyfile_open() does what one expects: it opens up the files
718 * given in the state structure, if they're not already open.
719 * It also does some type validation, to ensure that we only
720 * handle file types we know about.
721 */
722 static int copyfile_open(copyfile_state_t s)
723 {
724 int oflags = O_EXCL | O_CREAT | O_WRONLY;
725 int islnk = 0, isdir = 0;
726 int osrc = 0, dsrc = 0;
727
728 if (s->src && s->src_fd == -2)
729 {
730 if ((COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
731 (s->src, &s->sb, s->fsec))
732 {
733 copyfile_warn("stat on %s", s->src);
734 return -1;
735 }
736
737 /* prevent copying on unsupported types */
738 switch (s->sb.st_mode & S_IFMT)
739 {
740 case S_IFLNK:
741 islnk = 1;
742 if (s->sb.st_size > (off_t)SIZE_T_MAX) {
743 errno = ENOMEM; /* too big for us to copy */
744 return -1;
745 }
746 osrc = O_SYMLINK;
747 break;
748 case S_IFDIR:
749 isdir = 1;
750 break;
751 case S_IFREG:
752 break;
753 default:
754 errno = ENOTSUP;
755 return -1;
756 }
757 /*
758 * If we're packing, then we are actually
759 * creating a file, no matter what the source
760 * was.
761 */
762 if (s->flags & COPYFILE_PACK) {
763 /*
764 * O_SYMLINK and O_NOFOLLOW are not compatible options:
765 * if the file is a symlink, and O_NOFOLLOW is specified,
766 * open will return ELOOP, whether or not O_SYMLINK is set.
767 * However, we know whether or not it was a symlink from
768 * the stat above (although there is a potentiaal for a race
769 * condition here, but it will err on the side of returning
770 * ELOOP from open).
771 */
772 if (!islnk)
773 osrc = (s->flags & COPYFILE_NOFOLLOW_SRC) ? O_NOFOLLOW : 0;
774 isdir = islnk = 0;
775 }
776
777 if ((s->src_fd = open(s->src, O_RDONLY | osrc , 0)) < 0)
778 {
779 copyfile_warn("open on %s", s->src);
780 return -1;
781 } else
782 copyfile_debug(2, "open successful on source (%s)", s->src);
783
784 (void)copyfile_quarantine(s);
785 }
786
787 if (s->dst && s->dst_fd == -2)
788 {
789 /*
790 * COPYFILE_UNLINK tells us to try removing the destination
791 * before we create it. We don't care if the file doesn't
792 * exist, so we ignore ENOENT.
793 */
794 if (COPYFILE_UNLINK & s->flags)
795 {
796 if (remove(s->dst) < 0 && errno != ENOENT)
797 {
798 copyfile_warn("%s: remove", s->dst);
799 return -1;
800 }
801 }
802
803 if (s->flags & COPYFILE_NOFOLLOW_DST)
804 dsrc = O_NOFOLLOW;
805
806 if (islnk) {
807 size_t sz = (size_t)s->sb.st_size + 1;
808 char *bp;
809
810 bp = calloc(1, sz);
811 if (bp == NULL) {
812 copyfile_warn("cannot allocate %d bytes", sz);
813 return -1;
814 }
815 if (readlink(s->src, bp, sz-1) == -1) {
816 copyfile_warn("cannot readlink %s", s->src);
817 free(bp);
818 return -1;
819 }
820 if (symlink(bp, s->dst) == -1) {
821 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
822 copyfile_warn("Cannot make symlink %s", s->dst);
823 free(bp);
824 return -1;
825 }
826 }
827 free(bp);
828 s->dst_fd = open(s->dst, O_RDONLY | O_SYMLINK);
829 if (s->dst_fd == -1) {
830 copyfile_warn("Cannot open symlink %s for reading", s->dst);
831 return -1;
832 }
833 } else if (isdir) {
834 mode_t mode;
835 mode = s->sb.st_mode & ~S_IFMT;
836
837 if (mkdir(s->dst, mode) == -1) {
838 if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
839 copyfile_warn("Cannot make directory %s", s->dst);
840 return -1;
841 }
842 }
843 s->dst_fd = open(s->dst, O_RDONLY | dsrc);
844 if (s->dst_fd == -1) {
845 copyfile_warn("Cannot open directory %s for reading", s->dst);
846 return -1;
847 }
848 } else while((s->dst_fd = open(s->dst, oflags | dsrc, s->sb.st_mode | S_IWUSR)) < 0)
849 {
850 /*
851 * We set S_IWUSR because fsetxattr does not -- at the time this comment
852 * was written -- allow one to set an extended attribute on a file descriptor
853 * for a read-only file, even if the file descriptor is opened for writing.
854 * This will only matter if the file does not already exist.
855 */
856 switch(errno)
857 {
858 case EEXIST:
859 copyfile_debug(3, "open failed, retrying (%s)", s->dst);
860 if (s->flags & COPYFILE_EXCL)
861 break;
862 oflags = oflags & ~O_CREAT;
863 if (s->flags & (COPYFILE_PACK | COPYFILE_DATA))
864 {
865 copyfile_debug(4, "truncating existing file (%s)", s->dst);
866 oflags |= O_TRUNC;
867 }
868 continue;
869 case EACCES:
870 if(chmod(s->dst, (s->sb.st_mode | S_IWUSR) & ~S_IFMT) == 0)
871 continue;
872 else {
873 break;
874 }
875 case EISDIR:
876 copyfile_debug(3, "open failed because it is a directory (%s)", s->dst);
877 if ((s->flags & COPYFILE_EXCL) ||
878 (!isdir && (s->flags & COPYFILE_DATA)))
879 break;
880 oflags = (oflags & ~O_WRONLY) | O_RDONLY;
881 continue;
882 }
883 copyfile_warn("open on %s", s->dst);
884 return -1;
885 }
886 copyfile_debug(2, "open successful on destination (%s)", s->dst);
887 }
888
889 if (s->dst_fd < 0 || s->src_fd < 0)
890 {
891 copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
892 s->src_fd, s->dst_fd);
893 errno = EINVAL;
894 return -1;
895 }
896 return 0;
897 }
898
899
900 /*
901 * copyfile_check(), as described above, essentially tells you
902 * what you'd have to copy, if you wanted it to copy the things
903 * you asked it to copy.
904 * In other words, if you pass in COPYFILE_ALL, and the file in
905 * question had no extended attributes but did have an ACL, you'd
906 * get back COPYFILE_ACL.
907 */
908 static copyfile_flags_t copyfile_check(copyfile_state_t s)
909 {
910 acl_t acl = NULL;
911 copyfile_flags_t ret = 0;
912 int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC);
913 qtn_file_t qinfo;
914
915 if (!s->src)
916 {
917 errno = EINVAL;
918 return -1;
919 }
920
921 /* check EAs */
922 if (COPYFILE_XATTR & s->flags)
923 if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0)
924 {
925 ret |= COPYFILE_XATTR;
926 }
927
928 if (COPYFILE_ACL & s->flags)
929 {
930 (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
931 (s->src, &s->sb, s->fsec);
932
933 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0)
934 ret |= COPYFILE_ACL;
935 }
936
937 copyfile_debug(2, "check result: %d (%s)", ret, s->src);
938
939 if (acl)
940 acl_free(acl);
941
942 if (s->qinfo) {
943 /* If the state has had quarantine info set already, we use that */
944 ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
945 } else {
946 qinfo = qtn_file_alloc();
947 /*
948 * For quarantine information, we need to see if the source file
949 * has any. Since it may be a symlink, however, and we may, or
950 * not be following, *and* there's no qtn* routine which can optionally
951 * follow or not follow a symlink, we need to instead work around
952 * this limitation.
953 */
954 if (qinfo) {
955 int fd;
956 int qret = 0;
957 struct stat sbuf;
958
959 /*
960 * If we care about not following symlinks, *and* the file exists
961 * (which is to say, lstat doesn't return an error), *and* the file
962 * is a symlink, then we open it up (with O_SYMLINK), and use
963 * qtn_file_init_with_fd(); if none of that is true, however, then
964 * we can simply use qtn_file_init_with_path().
965 */
966 if (nofollow
967 && lstat(s->src, &sbuf) == 0
968 && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) {
969 fd = open(s->src, O_RDONLY | O_SYMLINK);
970 if (fd != -1) {
971 if (!qtn_file_init_with_fd(qinfo, fd)) {
972 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
973 }
974 close(fd);
975 }
976 } else {
977 if (!qtn_file_init_with_path(qinfo, s->src)) {
978 qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
979 }
980 }
981 qtn_file_free(qinfo);
982 ret |= qret;
983 }
984 }
985 return ret;
986 }
987
988 /*
989 * Attempt to copy the data section of a file. Using blockisize
990 * is not necessarily the fastest -- it might be desirable to
991 * specify a blocksize, somehow. But it's a size that should be
992 * guaranteed to work.
993 */
994 static int copyfile_data(copyfile_state_t s)
995 {
996 size_t blen;
997 char *bp = 0;
998 ssize_t nread;
999 int ret = 0;
1000 size_t iBlocksize = 0;
1001 struct statfs sfs;
1002
1003 if (fstatfs(s->src_fd, &sfs) == -1) {
1004 iBlocksize = s->sb.st_blksize;
1005 } else {
1006 iBlocksize = sfs.f_iosize;
1007 }
1008
1009 if ((bp = malloc(iBlocksize)) == NULL)
1010 return -1;
1011
1012 blen = iBlocksize;
1013
1014 /* If supported, do preallocation for Xsan / HFS volumes */
1015 #ifdef F_PREALLOCATE
1016 {
1017 fstore_t fst;
1018
1019 fst.fst_flags = 0;
1020 fst.fst_posmode = F_PEOFPOSMODE;
1021 fst.fst_offset = 0;
1022 fst.fst_length = s->sb.st_size;
1023 /* Ignore errors; this is merely advisory. */
1024 (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst);
1025 }
1026 #endif
1027
1028 while ((nread = read(s->src_fd, bp, blen)) > 0)
1029 {
1030 size_t nwritten;
1031 size_t left = nread;
1032 void *ptr = bp;
1033
1034 while (left > 0) {
1035 int loop = 0;
1036 nwritten = write(s->dst_fd, ptr, left);
1037 switch (nwritten) {
1038 case 0:
1039 if (++loop > 5) {
1040 copyfile_warn("writing to output %d times resulted in 0 bytes written", loop);
1041 ret = -1;
1042 errno = EAGAIN;
1043 goto exit;
1044 }
1045 break;
1046 case -1:
1047 copyfile_warn("writing to output file got error");
1048 ret = -1;
1049 goto exit;
1050 default:
1051 left -= nwritten;
1052 ptr = ((char*)ptr) + nwritten;
1053 break;
1054 }
1055 }
1056 }
1057 if (nread < 0)
1058 {
1059 copyfile_warn("reading from %s", s->src);
1060 goto exit;
1061 }
1062
1063 if (ftruncate(s->dst_fd, s->sb.st_size) < 0)
1064 {
1065 ret = -1;
1066 goto exit;
1067 }
1068
1069 exit:
1070 free(bp);
1071 return ret;
1072 }
1073
1074 /*
1075 * copyfile_security() will copy the ACL set, and the
1076 * POSIX set. Complexities come when dealing with
1077 * inheritied permissions, and when dealing with both
1078 * POSIX and ACL permissions.
1079 */
1080 static int copyfile_security(copyfile_state_t s)
1081 {
1082 int copied = 0;
1083 acl_flagset_t flags;
1084 struct stat sb;
1085 acl_entry_t entry_src = NULL, entry_dst = NULL;
1086 acl_t acl_src = NULL, acl_dst = NULL;
1087 int ret = 0;
1088 filesec_t tmp_fsec = NULL;
1089 filesec_t fsec_dst = filesec_init();
1090
1091 if (fsec_dst == NULL)
1092 return -1;
1093
1094
1095 if (COPYFILE_ACL & s->flags)
1096 {
1097 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src))
1098 {
1099 if (errno == ENOENT)
1100 goto no_acl;
1101 else
1102 goto error_exit;
1103 }
1104
1105 /* grab the destination acl
1106 cannot assume it's empty due to inheritance
1107 */
1108 if(fstatx_np(s->dst_fd, &sb, fsec_dst))
1109 goto error_exit;
1110
1111 if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst))
1112 {
1113 if (errno == ENOENT)
1114 acl_dst = acl_init(4);
1115 else
1116 goto error_exit;
1117 }
1118
1119 for (;acl_get_entry(acl_src,
1120 entry_src == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
1121 &entry_src) == 0;)
1122 {
1123 acl_get_flagset_np(entry_src, &flags);
1124 if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
1125 {
1126 if ((ret = acl_create_entry(&acl_dst, &entry_dst)) == -1)
1127 goto error_exit;
1128
1129 if ((ret = acl_copy_entry(entry_dst, entry_src)) == -1)
1130 goto error_exit;
1131
1132 copyfile_debug(2, "copied acl entry from %s to %s", s->src, s->dst);
1133 copied++;
1134 }
1135 }
1136 if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_dst))
1137 {
1138 copyfile_debug(3, "altered acl");
1139 }
1140 }
1141 no_acl:
1142 /*
1143 * The following code is attempting to ensure that only the requested
1144 * security information gets copied over to the destination file.
1145 * We essentially have four cases: COPYFILE_ACL, COPYFILE_STAT,
1146 * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
1147 * this function).
1148 *
1149 * If we have both flags, we copy everything; if we have ACL but not STAT,
1150 * we remove the POSIX information from the filesec object, and apply the
1151 * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
1152 * the extended version.
1153 */
1154 tmp_fsec = filesec_dup(s->fsec);
1155 if (tmp_fsec == NULL) {
1156 goto error_exit;
1157 }
1158
1159 switch (COPYFILE_SECURITY & s->flags) {
1160 case COPYFILE_ACL:
1161 copyfile_unset_posix_fsec(tmp_fsec);
1162 /* FALLTHROUGH */
1163 case COPYFILE_ACL | COPYFILE_STAT:
1164 if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) {
1165 if (errno == ENOTSUP) {
1166 if (COPYFILE_STAT & s->flags)
1167 fchmod(s->dst_fd, s->sb.st_mode);
1168 } else
1169 copyfile_warn("setting security information: %s", s->dst);
1170 }
1171 break;
1172 case COPYFILE_STAT:
1173 fchmod(s->dst_fd, s->sb.st_mode);
1174 break;
1175 }
1176 filesec_free(tmp_fsec);
1177 exit:
1178 filesec_free(fsec_dst);
1179 if (acl_src) acl_free(acl_src);
1180 if (acl_dst) acl_free(acl_dst);
1181
1182 return ret;
1183
1184 error_exit:
1185 ret = -1;
1186 goto exit;
1187
1188 }
1189
1190 /*
1191 * Attempt to set the destination file's stat information -- including
1192 * flags and time-related fields -- to the source's.
1193 */
1194 static int copyfile_stat(copyfile_state_t s)
1195 {
1196 struct timeval tval[2];
1197 /*
1198 * NFS doesn't support chflags; ignore errors unless there's reason
1199 * to believe we're losing bits. (Note, this still won't be right
1200 * if the server supports flags and we were trying to *remove* flags
1201 * on a file that we copied, i.e., that we didn't create.)
1202 */
1203 if (fchflags(s->dst_fd, (u_int)s->sb.st_flags))
1204 if (errno != EOPNOTSUPP || s->sb.st_flags != 0)
1205 copyfile_warn("%s: set flags (was: 0%07o)", s->dst, s->sb.st_flags);
1206
1207 /* If this fails, we don't care */
1208 (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
1209
1210 /* This may have already been done in copyfile_security() */
1211 (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT);
1212
1213 tval[0].tv_sec = s->sb.st_atime;
1214 tval[1].tv_sec = s->sb.st_mtime;
1215 tval[0].tv_usec = tval[1].tv_usec = 0;
1216 if (futimes(s->dst_fd, tval))
1217 copyfile_warn("%s: set times", s->dst);
1218 return 0;
1219 }
1220
1221 /*
1222 * Similar to copyfile_security() in some ways; this
1223 * routine copies the extended attributes from the source,
1224 * and sets them on the destination.
1225 * The procedure is pretty simple, even if it is verbose:
1226 * for each named attribute on the destination, get its name, and
1227 * remove it. We should have none after that.
1228 * For each named attribute on the source, get its name, get its
1229 * data, and set it on the destination.
1230 */
1231 static int copyfile_xattr(copyfile_state_t s)
1232 {
1233 char *name;
1234 char *namebuf, *end;
1235 ssize_t xa_size;
1236 void *xa_dataptr;
1237 ssize_t bufsize = 4096;
1238 ssize_t asize;
1239 ssize_t nsize;
1240 int ret = 0;
1241
1242 /* delete EAs on destination */
1243 if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
1244 {
1245 if ((namebuf = (char *) malloc(nsize)) == NULL)
1246 return -1;
1247 else
1248 nsize = flistxattr(s->dst_fd, namebuf, nsize, 0);
1249
1250 if (nsize > 0) {
1251 /*
1252 * With this, end points to the last byte of the allocated buffer
1253 * This *should* be NUL, from flistxattr, but if it's not, we can
1254 * set it anyway -- it'll result in a truncated name, which then
1255 * shouldn't match when we get them later.
1256 */
1257 end = namebuf + nsize - 1;
1258 if (*end != 0)
1259 *end = 0;
1260 for (name = namebuf; name <= end; name += strlen(name) + 1) {
1261 /* If the quarantine information shows up as an EA, we skip over it */
1262 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) {
1263 continue;
1264 }
1265 fremovexattr(s->dst_fd, name,0);
1266 }
1267 }
1268 free(namebuf);
1269 } else
1270 if (nsize < 0)
1271 {
1272 if (errno == ENOTSUP)
1273 return 0;
1274 else
1275 return -1;
1276 }
1277
1278 /* get name list of EAs on source */
1279 if ((nsize = flistxattr(s->src_fd, 0, 0, 0)) < 0)
1280 {
1281 if (errno == ENOTSUP)
1282 return 0;
1283 else
1284 return -1;
1285 } else
1286 if (nsize == 0)
1287 return 0;
1288
1289 if ((namebuf = (char *) malloc(nsize)) == NULL)
1290 return -1;
1291 else
1292 nsize = flistxattr(s->src_fd, namebuf, nsize, 0);
1293
1294 if (nsize <= 0) {
1295 free(namebuf);
1296 return (int)nsize;
1297 }
1298
1299 /*
1300 * With this, end points to the last byte of the allocated buffer
1301 * This *should* be NUL, from flistxattr, but if it's not, we can
1302 * set it anyway -- it'll result in a truncated name, which then
1303 * shouldn't match when we get them later.
1304 */
1305 end = namebuf + nsize - 1;
1306 if (*end != 0)
1307 *end = 0;
1308
1309 if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) {
1310 free(namebuf);
1311 return -1;
1312 }
1313
1314 for (name = namebuf; name <= end; name += strlen(name) + 1)
1315 {
1316 /* If the quarantine information shows up as an EA, we skip over it */
1317 if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0)
1318 continue;
1319
1320 if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, 0)) < 0)
1321 {
1322 ret = -1;
1323 continue;
1324 }
1325
1326 if (xa_size > bufsize)
1327 {
1328 void *tdptr = xa_dataptr;
1329 bufsize = xa_size;
1330 if ((xa_dataptr =
1331 (void *) realloc((void *) xa_dataptr, bufsize)) == NULL)
1332 {
1333 free(tdptr);
1334 ret = -1;
1335 continue;
1336 }
1337 }
1338
1339 if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, 0)) < 0)
1340 {
1341 ret = -1;
1342 continue;
1343 }
1344
1345 if (xa_size != asize)
1346 xa_size = asize;
1347
1348 if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, 0) < 0)
1349 {
1350 ret = -1;
1351 continue;
1352 }
1353 }
1354 if (namebuf)
1355 free(namebuf);
1356 free((void *) xa_dataptr);
1357 return ret;
1358 }
1359
1360 /*
1361 * API interface into getting data from the opaque data type.
1362 */
1363 int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
1364 {
1365 if (ret == NULL)
1366 {
1367 errno = EFAULT;
1368 return -1;
1369 }
1370
1371 switch(flag)
1372 {
1373 case COPYFILE_STATE_SRC_FD:
1374 *(int*)ret = s->src_fd;
1375 break;
1376 case COPYFILE_STATE_DST_FD:
1377 *(int*)ret = s->dst_fd;
1378 break;
1379 case COPYFILE_STATE_SRC_FILENAME:
1380 *(char**)ret = s->src;
1381 break;
1382 case COPYFILE_STATE_DST_FILENAME:
1383 *(char**)ret = s->dst;
1384 break;
1385 case COPYFILE_STATE_QUARANTINE:
1386 *(qtn_file_t*)ret = s->qinfo;
1387 break;
1388 #if 0
1389 case COPYFILE_STATE_STATS:
1390 ret = s->stats.global;
1391 break;
1392 case COPYFILE_STATE_PROGRESS_CB:
1393 ret = s->callbacks.progress;
1394 break;
1395 #endif
1396 default:
1397 errno = EINVAL;
1398 ret = NULL;
1399 return -1;
1400 }
1401 return 0;
1402 }
1403
1404 /*
1405 * Public API for setting state data (remember that the state is
1406 * an opaque data type).
1407 */
1408 int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
1409 {
1410 #define copyfile_set_string(DST, SRC) \
1411 do { \
1412 if (SRC != NULL) { \
1413 DST = strdup((char *)SRC); \
1414 } else { \
1415 if (DST != NULL) { \
1416 free(DST); \
1417 } \
1418 DST = NULL; \
1419 } \
1420 } while (0)
1421
1422 if (thing == NULL)
1423 {
1424 errno = EFAULT;
1425 return -1;
1426 }
1427
1428 switch(flag)
1429 {
1430 case COPYFILE_STATE_SRC_FD:
1431 s->src_fd = *(int*)thing;
1432 break;
1433 case COPYFILE_STATE_DST_FD:
1434 s->dst_fd = *(int*)thing;
1435 break;
1436 case COPYFILE_STATE_SRC_FILENAME:
1437 copyfile_set_string(s->src, thing);
1438 break;
1439 case COPYFILE_STATE_DST_FILENAME:
1440 copyfile_set_string(s->dst, thing);
1441 break;
1442 case COPYFILE_STATE_QUARANTINE:
1443 if (s->qinfo)
1444 {
1445 qtn_file_free(s->qinfo);
1446 s->qinfo = NULL;
1447 }
1448 if (*(qtn_file_t*)thing)
1449 s->qinfo = qtn_file_clone(*(qtn_file_t*)thing);
1450 break;
1451 #if 0
1452 case COPYFILE_STATE_STATS:
1453 s->stats.global = thing;
1454 break;
1455 case COPYFILE_STATE_PROGRESS_CB:
1456 s->callbacks.progress = thing;
1457 break;
1458 #endif
1459 default:
1460 errno = EINVAL;
1461 return -1;
1462 }
1463 return 0;
1464 #undef copyfile_set_string
1465 }
1466
1467
1468 /*
1469 * Make this a standalone program for testing purposes by
1470 * defining _COPYFILE_TEST.
1471 */
1472 #ifdef _COPYFILE_TEST
1473 #define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
1474
1475 struct {char *s; int v;} opts[] = {
1476 COPYFILE_OPTION(ACL)
1477 COPYFILE_OPTION(STAT)
1478 COPYFILE_OPTION(XATTR)
1479 COPYFILE_OPTION(DATA)
1480 COPYFILE_OPTION(SECURITY)
1481 COPYFILE_OPTION(METADATA)
1482 COPYFILE_OPTION(ALL)
1483 COPYFILE_OPTION(NOFOLLOW_SRC)
1484 COPYFILE_OPTION(NOFOLLOW_DST)
1485 COPYFILE_OPTION(NOFOLLOW)
1486 COPYFILE_OPTION(EXCL)
1487 COPYFILE_OPTION(MOVE)
1488 COPYFILE_OPTION(UNLINK)
1489 COPYFILE_OPTION(PACK)
1490 COPYFILE_OPTION(UNPACK)
1491 COPYFILE_OPTION(CHECK)
1492 COPYFILE_OPTION(VERBOSE)
1493 COPYFILE_OPTION(DEBUG)
1494 {NULL, 0}
1495 };
1496
1497 int main(int c, char *v[])
1498 {
1499 int i;
1500 int flags = 0;
1501
1502 if (c < 3)
1503 errx(1, "insufficient arguments");
1504
1505 while(c-- > 3)
1506 {
1507 for (i = 0; opts[i].s != NULL; ++i)
1508 {
1509 if (strcasecmp(opts[i].s, v[c]) == 0)
1510 {
1511 printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v);
1512 flags |= opts[i].v;
1513 break;
1514 }
1515 }
1516 }
1517
1518 return copyfile(v[1], v[2], NULL, flags);
1519 }
1520 #endif
1521 /*
1522 * Apple Double Create
1523 *
1524 * Create an Apple Double "._" file from a file's extented attributes
1525 *
1526 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
1527 */
1528
1529
1530 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
1531
1532 #define XATTR_MAXATTRLEN (4*1024)
1533
1534
1535 /*
1536 Typical "._" AppleDouble Header File layout:
1537 ------------------------------------------------------------
1538 MAGIC 0x00051607
1539 VERSION 0x00020000
1540 FILLER 0
1541 COUNT 2
1542 .-- AD ENTRY[0] Finder Info Entry (must be first)
1543 .--+-- AD ENTRY[1] Resource Fork Entry (must be last)
1544 | '-> FINDER INFO
1545 | ///////////// Fixed Size Data (32 bytes)
1546 | EXT ATTR HDR
1547 | /////////////
1548 | ATTR ENTRY[0] --.
1549 | ATTR ENTRY[1] --+--.
1550 | ATTR ENTRY[2] --+--+--.
1551 | ... | | |
1552 | ATTR ENTRY[N] --+--+--+--.
1553 | ATTR DATA 0 <-' | | |
1554 | //////////// | | |
1555 | ATTR DATA 1 <----' | |
1556 | ///////////// | |
1557 | ATTR DATA 2 <-------' |
1558 | ///////////// |
1559 | ... |
1560 | ATTR DATA N <----------'
1561 | /////////////
1562 | Attribute Free Space
1563 |
1564 '----> RESOURCE FORK
1565 ///////////// Variable Sized Data
1566 /////////////
1567 /////////////
1568 /////////////
1569 /////////////
1570 /////////////
1571 ...
1572 /////////////
1573
1574 ------------------------------------------------------------
1575
1576 NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
1577 stored as part of the Finder Info. The length in the Finder
1578 Info AppleDouble entry includes the length of the extended
1579 attribute header, attribute entries, and attribute data.
1580 */
1581
1582
1583 /*
1584 * On Disk Data Structures
1585 *
1586 * Note: Motorola 68K alignment and big-endian.
1587 *
1588 * See RFC 1740 for additional information about the AppleDouble file format.
1589 *
1590 */
1591
1592 #define ADH_MAGIC 0x00051607
1593 #define ADH_VERSION 0x00020000
1594 #define ADH_MACOSX "Mac OS X "
1595
1596 /*
1597 * AppleDouble Entry ID's
1598 */
1599 #define AD_DATA 1 /* Data fork */
1600 #define AD_RESOURCE 2 /* Resource fork */
1601 #define AD_REALNAME 3 /* File's name on home file system */
1602 #define AD_COMMENT 4 /* Standard Mac comment */
1603 #define AD_ICONBW 5 /* Mac black & white icon */
1604 #define AD_ICONCOLOR 6 /* Mac color icon */
1605 #define AD_UNUSED 7 /* Not used */
1606 #define AD_FILEDATES 8 /* File dates; create, modify, etc */
1607 #define AD_FINDERINFO 9 /* Mac Finder info & extended info */
1608 #define AD_MACINFO 10 /* Mac file info, attributes, etc */
1609 #define AD_PRODOSINFO 11 /* Pro-DOS file info, attrib., etc */
1610 #define AD_MSDOSINFO 12 /* MS-DOS file info, attributes, etc */
1611 #define AD_AFPNAME 13 /* Short name on AFP server */
1612 #define AD_AFPINFO 14 /* AFP file info, attrib., etc */
1613 #define AD_AFPDIRID 15 /* AFP directory ID */
1614 #define AD_ATTRIBUTES AD_FINDERINFO
1615
1616
1617 #define ATTR_FILE_PREFIX "._"
1618 #define ATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
1619
1620 #define ATTR_BUF_SIZE 4096 /* default size of the attr file and how much we'll grow by */
1621
1622 /* Implementation Limits */
1623 #define ATTR_MAX_SIZE (128*1024) /* 128K maximum attribute data size */
1624 #define ATTR_MAX_NAME_LEN 128
1625 #define ATTR_MAX_HDR_SIZE (65536+18)
1626
1627 /*
1628 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
1629 * size supported (including the attribute entries). All of
1630 * the attribute entries must reside within this limit.
1631 */
1632
1633
1634 #define FINDERINFOSIZE 32
1635
1636 typedef struct apple_double_entry
1637 {
1638 u_int32_t type; /* entry type: see list, 0 invalid */
1639 u_int32_t offset; /* entry data offset from the beginning of the file. */
1640 u_int32_t length; /* entry data length in bytes. */
1641 } __attribute__((aligned(2), packed)) apple_double_entry_t;
1642
1643
1644 typedef struct apple_double_header
1645 {
1646 u_int32_t magic; /* == ADH_MAGIC */
1647 u_int32_t version; /* format version: 2 = 0x00020000 */
1648 u_int32_t filler[4];
1649 u_int16_t numEntries; /* number of entries which follow */
1650 apple_double_entry_t entries[2]; /* 'finfo' & 'rsrc' always exist */
1651 u_int8_t finfo[FINDERINFOSIZE]; /* Must start with Finder Info (32 bytes) */
1652 u_int8_t pad[2]; /* get better alignment inside attr_header */
1653 } __attribute__((aligned(2), packed)) apple_double_header_t;
1654
1655
1656 /* Entries are aligned on 4 byte boundaries */
1657 typedef struct attr_entry
1658 {
1659 u_int32_t offset; /* file offset to data */
1660 u_int32_t length; /* size of attribute data */
1661 u_int16_t flags;
1662 u_int8_t namelen; /* length of name including NULL termination char */
1663 u_int8_t name[1]; /* NULL-terminated UTF-8 name (up to 128 bytes max) */
1664 } __attribute__((aligned(2), packed)) attr_entry_t;
1665
1666
1667
1668 /* Header + entries must fit into 64K */
1669 typedef struct attr_header
1670 {
1671 apple_double_header_t appledouble;
1672 u_int32_t magic; /* == ATTR_HDR_MAGIC */
1673 u_int32_t debug_tag; /* for debugging == file id of owning file */
1674 u_int32_t total_size; /* total size of attribute header + entries + data */
1675 u_int32_t data_start; /* file offset to attribute data area */
1676 u_int32_t data_length; /* length of attribute data area */
1677 u_int32_t reserved[3];
1678 u_int16_t flags;
1679 u_int16_t num_attrs;
1680 } __attribute__((aligned(2), packed)) attr_header_t;
1681
1682 /* Empty Resource Fork Header */
1683 /* This comes by way of xnu's vfs_xattr.c */
1684 typedef struct rsrcfork_header {
1685 u_int32_t fh_DataOffset;
1686 u_int32_t fh_MapOffset;
1687 u_int32_t fh_DataLength;
1688 u_int32_t fh_MapLength;
1689 u_int8_t systemData[112];
1690 u_int8_t appData[128];
1691 u_int32_t mh_DataOffset;
1692 u_int32_t mh_MapOffset;
1693 u_int32_t mh_DataLength;
1694 u_int32_t mh_MapLength;
1695 u_int32_t mh_Next;
1696 u_int16_t mh_RefNum;
1697 u_int8_t mh_Attr;
1698 u_int8_t mh_InMemoryAttr;
1699 u_int16_t mh_Types;
1700 u_int16_t mh_Names;
1701 u_int16_t typeCount;
1702 } rsrcfork_header_t;
1703 #define RF_FIRST_RESOURCE 256
1704 #define RF_NULL_MAP_LENGTH 30
1705 #define RF_EMPTY_TAG "This resource fork intentionally left blank "
1706
1707 static const rsrcfork_header_t empty_rsrcfork_header = {
1708 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_DataOffset
1709 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // fh_MapOffset
1710 0, // fh_DataLength
1711 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // fh_MapLength
1712 { RF_EMPTY_TAG, }, // systemData
1713 { 0 }, // appData
1714 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_DataOffset
1715 OSSwapHostToBigInt32(RF_FIRST_RESOURCE), // mh_MapOffset
1716 0, // mh_DataLength
1717 OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH), // mh_MapLength
1718 0, // mh_Next
1719 0, // mh_RefNum
1720 0, // mh_Attr
1721 0, // mh_InMemoryAttr
1722 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2), // mh_Types
1723 OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH), // mh_Names
1724 OSSwapHostToBigInt16(-1), // typeCount
1725 };
1726
1727 #define SWAP16(x) OSSwapBigToHostInt16(x)
1728 #define SWAP32(x) OSSwapBigToHostInt32(x)
1729 #define SWAP64(x) OSSwapBigToHostInt64(x)
1730
1731 #define ATTR_ALIGN 3L /* Use four-byte alignment */
1732
1733 #define ATTR_ENTRY_LENGTH(namelen) \
1734 ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
1735
1736 #define ATTR_NEXT(ae) \
1737 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
1738
1739 #define XATTR_SECURITY_NAME "com.apple.acl.text"
1740
1741 /*
1742 * Endian swap Apple Double header
1743 */
1744 static void
1745 swap_adhdr(apple_double_header_t *adh)
1746 {
1747 #if BYTE_ORDER == LITTLE_ENDIAN
1748 int count;
1749 int i;
1750
1751 count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
1752
1753 adh->magic = SWAP32 (adh->magic);
1754 adh->version = SWAP32 (adh->version);
1755 adh->numEntries = SWAP16 (adh->numEntries);
1756
1757 for (i = 0; i < count; i++)
1758 {
1759 adh->entries[i].type = SWAP32 (adh->entries[i].type);
1760 adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
1761 adh->entries[i].length = SWAP32 (adh->entries[i].length);
1762 }
1763 #else
1764 (void)adh;
1765 #endif
1766 }
1767
1768 /*
1769 * Endian swap extended attributes header
1770 */
1771 static void
1772 swap_attrhdr(attr_header_t *ah)
1773 {
1774 #if BYTE_ORDER == LITTLE_ENDIAN
1775 attr_entry_t *ae;
1776 int count;
1777 int i;
1778
1779 count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
1780
1781 ah->magic = SWAP32 (ah->magic);
1782 ah->debug_tag = SWAP32 (ah->debug_tag);
1783 ah->total_size = SWAP32 (ah->total_size);
1784 ah->data_start = SWAP32 (ah->data_start);
1785 ah->data_length = SWAP32 (ah->data_length);
1786 ah->flags = SWAP16 (ah->flags);
1787 ah->num_attrs = SWAP16 (ah->num_attrs);
1788
1789 ae = (attr_entry_t *)(&ah[1]);
1790 for (i = 0; i < count; i++)
1791 {
1792 attr_entry_t *next = ATTR_NEXT(ae);
1793 ae->offset = SWAP32 (ae->offset);
1794 ae->length = SWAP32 (ae->length);
1795 ae->flags = SWAP16 (ae->flags);
1796 ae = next;
1797 }
1798 #else
1799 (void)ah;
1800 #endif
1801 }
1802
1803 static const u_int32_t emptyfinfo[8] = {0};
1804
1805 /*
1806 * Given an Apple Double file in src, turn it into a
1807 * normal file (possibly with multiple forks, EAs, and
1808 * ACLs) in dst.
1809 */
1810 static int copyfile_unpack(copyfile_state_t s)
1811 {
1812 ssize_t bytes;
1813 void * buffer, * endptr;
1814 apple_double_header_t *adhdr;
1815 ssize_t hdrsize;
1816 int error = 0;
1817
1818 if (s->sb.st_size < ATTR_MAX_HDR_SIZE)
1819 hdrsize = (ssize_t)s->sb.st_size;
1820 else
1821 hdrsize = ATTR_MAX_HDR_SIZE;
1822
1823 buffer = calloc(1, hdrsize);
1824 if (buffer == NULL) {
1825 copyfile_debug(1, "copyfile_unpack: calloc(1, %u) returned NULL", hdrsize);
1826 error = -1;
1827 goto exit;
1828 } else
1829 endptr = (char*)buffer + hdrsize;
1830
1831 bytes = pread(s->src_fd, buffer, hdrsize, 0);
1832
1833 if (bytes < 0)
1834 {
1835 copyfile_debug(1, "pread returned: %d", bytes);
1836 error = -1;
1837 goto exit;
1838 }
1839 if (bytes < hdrsize)
1840 {
1841 copyfile_debug(1,
1842 "pread couldn't read entire header: %d of %d",
1843 (int)bytes, (int)s->sb.st_size);
1844 error = -1;
1845 goto exit;
1846 }
1847 adhdr = (apple_double_header_t *)buffer;
1848
1849 /*
1850 * Check for Apple Double file.
1851 */
1852 if ((size_t)bytes < sizeof(apple_double_header_t) - 2 ||
1853 SWAP32(adhdr->magic) != ADH_MAGIC ||
1854 SWAP32(adhdr->version) != ADH_VERSION ||
1855 SWAP16(adhdr->numEntries) != 2 ||
1856 SWAP32(adhdr->entries[0].type) != AD_FINDERINFO)
1857 {
1858 if (COPYFILE_VERBOSE & s->flags)
1859 copyfile_warn("Not a valid Apple Double header");
1860 error = -1;
1861 goto exit;
1862 }
1863 swap_adhdr(adhdr);
1864
1865 /*
1866 * Remove any extended attributes on the target.
1867 */
1868
1869 if (COPYFILE_XATTR & s->flags)
1870 {
1871 if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
1872 {
1873 char *namebuf, *name;
1874
1875 if ((namebuf = (char*) malloc(bytes)) == NULL)
1876 {
1877 errno = ENOMEM;
1878 goto exit;
1879 }
1880 bytes = flistxattr(s->dst_fd, namebuf, bytes, 0);
1881
1882 if (bytes > 0)
1883 for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1)
1884 (void)fremovexattr(s->dst_fd, name, 0);
1885
1886 free(namebuf);
1887 }
1888 else if (bytes < 0)
1889 {
1890 if (errno != ENOTSUP)
1891 goto exit;
1892 }
1893 }
1894
1895 /*
1896 * Extract the extended attributes.
1897 *
1898 * >>> WARNING <<<
1899 * This assumes that the data is already in memory (not
1900 * the case when there are lots of attributes or one of
1901 * the attributes is very large.
1902 */
1903 if (adhdr->entries[0].length > FINDERINFOSIZE)
1904 {
1905 attr_header_t *attrhdr;
1906 attr_entry_t *entry;
1907 int count;
1908 int i;
1909
1910 if ((size_t)hdrsize < sizeof(attr_header_t)) {
1911 copyfile_warn("bad attribute header: %u < %u", hdrsize, sizeof(attr_header_t));
1912 error = -1;
1913 goto exit;
1914 }
1915
1916 attrhdr = (attr_header_t *)buffer;
1917 swap_attrhdr(attrhdr);
1918 if (attrhdr->magic != ATTR_HDR_MAGIC)
1919 {
1920 if (COPYFILE_VERBOSE & s->flags)
1921 copyfile_warn("bad attribute header");
1922 error = -1;
1923 goto exit;
1924 }
1925 count = attrhdr->num_attrs;
1926 entry = (attr_entry_t *)&attrhdr[1];
1927
1928 for (i = 0; i < count; i++)
1929 {
1930 void * dataptr;
1931
1932 /*
1933 * First we do some simple sanity checking.
1934 * +) See if entry is within the buffer's range;
1935 *
1936 * +) Check the attribute name length; if it's longer than the
1937 * maximum, we truncate it down. (We could error out as well;
1938 * I'm not sure which is the better way to go here.)
1939 *
1940 * +) If, given the name length, it goes beyond the end of
1941 * the buffer, error out.
1942 *
1943 * +) If the last byte isn't a NUL, make it a NUL. (Since we
1944 * truncated the name length above, we truncate the name here.)
1945 *
1946 * +) If entry->offset is so large that it causes dataptr to
1947 * go beyond the end of the buffer -- or, worse, so large that
1948 * it wraps around! -- we error out.
1949 *
1950 * +) If entry->length would cause the entry to go beyond the
1951 * end of the buffer (or, worse, wrap around to before it),
1952 * *or* if the length is larger than the hdrsize, we error out.
1953 * (An explanation of that: what we're checking for there is
1954 * the small range of values such that offset+length would cause
1955 * it to go beyond endptr, and then wrap around past buffer. We
1956 * care about this because we are passing entry->length down to
1957 * fgetxattr() below, and an erroneously large value could cause
1958 * problems there. By making sure that it's less than hdrsize,
1959 * which has already been sanity-checked above, we're safe.
1960 * That may mean that the check against < buffer is unnecessary.)
1961 */
1962 if ((void*)entry >= endptr || (void*)entry < buffer) {
1963 if (COPYFILE_VERBOSE & s->flags)
1964 copyfile_warn("Incomplete or corrupt attribute entry");
1965 error = -1;
1966 goto exit;
1967 }
1968
1969 if (((char*)entry + sizeof(*entry)) > (char*)endptr) {
1970 if (COPYFILE_VERBOSE & s->flags)
1971 copyfile_warn("Incomplete or corrupt attribute entry");
1972 error = -1;
1973 goto exit;
1974 }
1975
1976 if (entry->namelen < 2) {
1977 if (COPYFILE_VERBOSE & s->flags)
1978 copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen);
1979 error = -1;
1980 goto exit;
1981 }
1982
1983 if (entry->namelen > XATTR_MAXNAMELEN + 1) {
1984 if (COPYFILE_VERBOSE & s->flags)
1985 copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen);
1986 error = -1;
1987 goto exit;
1988 }
1989
1990 if ((void*)(entry->name + entry->namelen) > endptr) {
1991 if (COPYFILE_VERBOSE & s->flags)
1992 copyfile_warn("Incomplete or corrupt attribute entry");
1993 error = -1;
1994 goto exit;
1995 }
1996
1997 /* Because namelen includes the NUL, we check one byte back */
1998 if (entry->name[entry->namelen-1] != 0) {
1999 if (COPYFILE_VERBOSE & s->flags)
2000 copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
2001 error = -1;
2002 goto exit;
2003 }
2004
2005 copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
2006 entry->name, entry->length, entry->offset);
2007
2008 dataptr = (char *)attrhdr + entry->offset;
2009
2010 if (dataptr > endptr || dataptr < buffer) {
2011 copyfile_debug(1, "Entry %d overflows: offset = %u", entry->offset);
2012 error = -1;
2013 goto exit;
2014 }
2015 if (((char*)dataptr + entry->length) > (char*)endptr ||
2016 (((char*)dataptr + entry->length) < (char*)buffer) ||
2017 (entry->length > (size_t)hdrsize)) {
2018 if (COPYFILE_VERBOSE & s->flags)
2019 copyfile_warn("Incomplete or corrupt attribute entry");
2020 copyfile_debug(1, "Entry %d length overflows: offset = %u, length = %u",
2021 entry->offset, entry->length);
2022 error = -1;
2023 goto exit;
2024 }
2025
2026 if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
2027 {
2028 qtn_file_t tqinfo = NULL;
2029
2030 if (s->qinfo == NULL)
2031 {
2032 tqinfo = qtn_file_alloc();
2033 if (tqinfo)
2034 {
2035 int x;
2036 if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0)
2037 {
2038 copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x));
2039 qtn_file_free(tqinfo);
2040 tqinfo = NULL;
2041 }
2042 }
2043 }
2044 else
2045 {
2046 tqinfo = s->qinfo;
2047 }
2048 if (tqinfo)
2049 {
2050 int x;
2051 x = qtn_file_apply_to_fd(tqinfo, s->dst_fd);
2052 if (x != 0)
2053 copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x));
2054 }
2055 if (tqinfo && !s->qinfo)
2056 {
2057 qtn_file_free(tqinfo);
2058 }
2059 }
2060 /* Look for ACL data */
2061 else if (COPYFILE_ACL & s->flags && strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)
2062 {
2063 acl_t acl;
2064 struct stat sb;
2065 int retry = 1;
2066 char *tcp = dataptr;
2067
2068 /*
2069 * acl_from_text() requires a NUL-terminated string. The ACL EA,
2070 * however, may not be NUL-terminated. So in that case, we need to
2071 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
2072 */
2073 if (tcp[entry->length - 1] != 0) {
2074 char *tmpstr = malloc(entry->length + 1);
2075 if (tmpstr == NULL) {
2076 error = -1;
2077 goto exit;
2078 }
2079 strlcpy(tmpstr, tcp, entry->length + 1);
2080 acl = acl_from_text(tmpstr);
2081 free(tmpstr);
2082 } else {
2083 acl = acl_from_text(tcp);
2084 }
2085
2086 if (acl != NULL)
2087 {
2088 filesec_t fsec_tmp;
2089
2090 if ((fsec_tmp = filesec_init()) == NULL)
2091 error = -1;
2092 else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0)
2093 error = -1;
2094 else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0)
2095 error = -1;
2096 else {
2097 while (fchmodx_np(s->dst_fd, fsec_tmp) < 0)
2098 {
2099 if (errno == ENOTSUP)
2100 {
2101 if (retry && !copyfile_unset_acl(s))
2102 {
2103 retry = 0;
2104 continue;
2105 }
2106 }
2107 copyfile_warn("setting security information");
2108 error = -1;
2109 break;
2110 }
2111 }
2112 acl_free(acl);
2113 filesec_free(fsec_tmp);
2114
2115 if (error == -1)
2116 goto exit;
2117 }
2118 }
2119 /* And, finally, everything else */
2120 else if (COPYFILE_XATTR & s->flags && (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0))) {
2121 if (COPYFILE_VERBOSE & s->flags)
2122 copyfile_warn("error %d setting attribute %s", error, entry->name);
2123 break;
2124 }
2125 entry = ATTR_NEXT(entry);
2126 }
2127 }
2128
2129 /*
2130 * Extract the Finder Info.
2131 */
2132 if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) {
2133 error = -1;
2134 goto exit;
2135 }
2136
2137 if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0)
2138 {
2139 copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME);
2140 error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0);
2141 if (error)
2142 goto exit;
2143 }
2144
2145 /*
2146 * Extract the Resource Fork.
2147 */
2148 if (adhdr->entries[1].type == AD_RESOURCE &&
2149 adhdr->entries[1].length > 0)
2150 {
2151 void * rsrcforkdata = NULL;
2152 size_t length;
2153 off_t offset;
2154 struct stat sb;
2155 struct timeval tval[2];
2156
2157 length = adhdr->entries[1].length;
2158 offset = adhdr->entries[1].offset;
2159 rsrcforkdata = malloc(length);
2160
2161 if (rsrcforkdata == NULL) {
2162 copyfile_debug(1, "could not allocate %u bytes for rsrcforkdata",
2163 length);
2164 error = -1;
2165 goto bad;
2166 }
2167
2168 if (fstat(s->dst_fd, &sb) < 0)
2169 {
2170 copyfile_debug(1, "couldn't stat destination file");
2171 error = -1;
2172 goto bad;
2173 }
2174
2175 bytes = pread(s->src_fd, rsrcforkdata, length, offset);
2176 if (bytes < (ssize_t)length)
2177 {
2178 if (bytes == -1)
2179 {
2180 copyfile_debug(1, "couldn't read resource fork");
2181 }
2182 else
2183 {
2184 copyfile_debug(1,
2185 "couldn't read resource fork (only read %d bytes of %d)",
2186 (int)bytes, (int)length);
2187 }
2188 error = -1;
2189 goto bad;
2190 }
2191 error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0);
2192 if (error)
2193 {
2194 /*
2195 * For filesystems that do not natively support named attributes,
2196 * the kernel creates an AppleDouble file that -- for compatabilty
2197 * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
2198 * structure that says there are no resources. So, if fsetxattr has
2199 * failed, and the resource fork is that empty structure, *and* the
2200 * target file is a directory, then we do nothing with it.
2201 */
2202 if ((bytes == sizeof(rsrcfork_header_t)) &&
2203 ((sb.st_mode & S_IFMT) == S_IFDIR) &&
2204 (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) {
2205 copyfile_debug(2, "not setting empty resource fork on directory");
2206 error = errno = 0;
2207 goto bad;
2208 }
2209 copyfile_debug(1, "error %d setting resource fork attribute", error);
2210 error = -1;
2211 goto bad;
2212 }
2213 copyfile_debug(3, "extracting \"%s\" (%d bytes)",
2214 XATTR_RESOURCEFORK_NAME, (int)length);
2215
2216 if (!(s->flags & COPYFILE_STAT))
2217 {
2218 tval[0].tv_sec = sb.st_atime;
2219 tval[1].tv_sec = sb.st_mtime;
2220 tval[0].tv_usec = tval[1].tv_usec = 0;
2221
2222 if (futimes(s->dst_fd, tval))
2223 copyfile_warn("%s: set times", s->dst);
2224 }
2225 bad:
2226 if (rsrcforkdata)
2227 free(rsrcforkdata);
2228 }
2229
2230 if (COPYFILE_STAT & s->flags)
2231 {
2232 error = copyfile_stat(s);
2233 }
2234 exit:
2235 if (buffer) free(buffer);
2236 return error;
2237 }
2238
2239 static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len)
2240 {
2241 int ret = 0;
2242 char qbuf[QTN_SERIALIZED_DATA_MAX];
2243 size_t qlen = sizeof(qbuf);
2244
2245 if (s->qinfo == NULL)
2246 {
2247 ret = -1;
2248 goto done;
2249 }
2250
2251 if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0)
2252 {
2253 ret = -1;
2254 goto done;
2255 }
2256
2257 *buf = malloc(qlen);
2258 if (*buf)
2259 {
2260 memcpy(*buf, qbuf, qlen);
2261 *len = qlen;
2262 }
2263 done:
2264 return ret;
2265 }
2266
2267 static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len)
2268 {
2269 int ret = 0;
2270 acl_t acl = NULL;
2271 char *acl_text;
2272
2273 if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0)
2274 {
2275 if (errno != ENOENT)
2276 {
2277 ret = -1;
2278 if (COPYFILE_VERBOSE & s->flags)
2279 copyfile_warn("getting acl");
2280 }
2281 *len = 0;
2282 goto exit;
2283 }
2284
2285 if ((acl_text = acl_to_text(acl, len)) != NULL)
2286 {
2287 /*
2288 * acl_to_text() doesn't include the NUL at the endo
2289 * in it's count (*len). It does, however, promise to
2290 * return a valid C string, so we need to up the count
2291 * by 1.
2292 */
2293 *len = *len + 1;
2294 *buf = malloc(*len);
2295 if (*buf)
2296 memcpy(*buf, acl_text, *len);
2297 else
2298 *len = 0;
2299 acl_free(acl_text);
2300 }
2301 copyfile_debug(2, "copied acl (%ld) %p", *len, *buf);
2302 exit:
2303 if (acl)
2304 acl_free(acl);
2305 return ret;
2306 }
2307
2308 static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr)
2309 {
2310 ssize_t datasize;
2311 char *databuf = NULL;
2312 int ret = 0;
2313
2314 /* Get the resource fork size */
2315 if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0)
2316 {
2317 if (COPYFILE_VERBOSE & s->flags)
2318 copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno);
2319 return -1;
2320 }
2321
2322 if (datasize > INT_MAX) {
2323 errno = EINVAL;
2324 ret = -1;
2325 goto done;
2326 }
2327
2328 if ((databuf = malloc(datasize)) == NULL)
2329 {
2330 copyfile_warn("malloc");
2331 ret = -1;
2332 goto done;
2333 }
2334
2335 if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize)
2336 {
2337 if (COPYFILE_VERBOSE & s->flags)
2338 copyfile_warn("couldn't read entire resource fork");
2339 ret = -1;
2340 goto done;
2341 }
2342
2343 /* Write the resource fork to disk. */
2344 if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize)
2345 {
2346 if (COPYFILE_VERBOSE & s->flags)
2347 copyfile_warn("couldn't write resource fork");
2348 }
2349 copyfile_debug(3, "copied %d bytes of \"%s\" data @ offset 0x%08x",
2350 datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset);
2351 filehdr->appledouble.entries[1].length = (u_int32_t)datasize;
2352
2353 done:
2354 if (databuf)
2355 free(databuf);
2356
2357 return ret;
2358 }
2359
2360 /*
2361 * The opposite of copyfile_unpack(), obviously.
2362 */
2363 static int copyfile_pack(copyfile_state_t s)
2364 {
2365 char *attrnamebuf = NULL, *endnamebuf;
2366 void *databuf = NULL;
2367 attr_header_t *filehdr, *endfilehdr;
2368 attr_entry_t *entry;
2369 ssize_t listsize = 0;
2370 char *nameptr;
2371 size_t namelen;
2372 size_t entrylen;
2373 ssize_t datasize;
2374 size_t offset = 0;
2375 int hasrsrcfork = 0;
2376 int error = 0;
2377 int seenq = 0; // Have we seen any quarantine info already?
2378
2379 filehdr = (attr_header_t *) calloc(1, ATTR_MAX_SIZE);
2380 if (filehdr == NULL) {
2381 error = -1;
2382 goto exit;
2383 } else {
2384 endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_SIZE);
2385 }
2386
2387 attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
2388 if (attrnamebuf == NULL) {
2389 error = -1;
2390 goto exit;
2391 } else {
2392 endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE;
2393 }
2394
2395 /*
2396 * Fill in the Apple Double Header defaults.
2397 */
2398 filehdr->appledouble.magic = ADH_MAGIC;
2399 filehdr->appledouble.version = ADH_VERSION;
2400 filehdr->appledouble.numEntries = 2;
2401 filehdr->appledouble.entries[0].type = AD_FINDERINFO;
2402 filehdr->appledouble.entries[0].offset = (u_int32_t)offsetof(apple_double_header_t, finfo);
2403 filehdr->appledouble.entries[0].length = FINDERINFOSIZE;
2404 filehdr->appledouble.entries[1].type = AD_RESOURCE;
2405 filehdr->appledouble.entries[1].offset = (u_int32_t)offsetof(apple_double_header_t, pad);
2406 filehdr->appledouble.entries[1].length = 0;
2407 bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler));
2408
2409 /*
2410 * Fill in the initial Attribute Header.
2411 */
2412 filehdr->magic = ATTR_HDR_MAGIC;
2413 filehdr->debug_tag = s->sb.st_ino;
2414 filehdr->data_start = (u_int32_t)sizeof(attr_header_t);
2415
2416 /*
2417 * Collect the attribute names.
2418 */
2419 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
2420
2421 /*
2422 * Test if there are acls to copy
2423 */
2424 if (COPYFILE_ACL & s->flags)
2425 {
2426 acl_t temp_acl = NULL;
2427 if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0)
2428 {
2429 copyfile_debug(2, "no acl entries found (errno = %d)", errno);
2430 } else
2431 {
2432 offset = strlen(XATTR_SECURITY_NAME) + 1;
2433 strcpy(attrnamebuf, XATTR_SECURITY_NAME);
2434 }
2435 if (temp_acl)
2436 acl_free(temp_acl);
2437 }
2438
2439 if (COPYFILE_XATTR & s->flags)
2440 {
2441 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
2442 if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0)
2443 {
2444 copyfile_debug(2, "no extended attributes found (%d)", errno);
2445 }
2446 if (listsize > left)
2447 {
2448 copyfile_debug(1, "extended attribute list too long");
2449 listsize = left;
2450 }
2451
2452 listsize += offset;
2453 endnamebuf = attrnamebuf + listsize;
2454 if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) {
2455 error = -1;
2456 goto exit;
2457 }
2458
2459 for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen)
2460 {
2461 namelen = strlen(nameptr) + 1;
2462 /* Skip over FinderInfo or Resource Fork names */
2463 if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 ||
2464 strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) {
2465 continue;
2466 }
2467 if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) {
2468 seenq = 1;
2469 }
2470
2471 /* The system should prevent this from happening, but... */
2472 if (namelen > XATTR_MAXNAMELEN + 1) {
2473 namelen = XATTR_MAXNAMELEN + 1;
2474 }
2475 entry->namelen = namelen;
2476 entry->flags = 0;
2477 if (nameptr + namelen > endnamebuf) {
2478 error = -1;
2479 goto exit;
2480 }
2481 bcopy(nameptr, &entry->name[0], namelen);
2482 copyfile_debug(2, "copied name [%s]", entry->name);
2483
2484 entrylen = ATTR_ENTRY_LENGTH(namelen);
2485 entry = (attr_entry_t *)(((char *)entry) + entrylen);
2486
2487 if ((void*)entry >= (void*)endfilehdr) {
2488 error = -1;
2489 goto exit;
2490 }
2491
2492 /* Update the attributes header. */
2493 filehdr->num_attrs++;
2494 filehdr->data_start += (u_int32_t)entrylen;
2495 }
2496 }
2497
2498 /*
2499 * If we have any quarantine data, we always pack it.
2500 * But if we've already got it in the EA list, don't put it in again.
2501 */
2502 if (s->qinfo && !seenq)
2503 {
2504 ssize_t left = ATTR_MAX_HDR_SIZE - offset;
2505 /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
2506 offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1;
2507 }
2508
2509 seenq = 0;
2510 /*
2511 * Collect the attribute data.
2512 */
2513 entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
2514
2515 for (nameptr = attrnamebuf; nameptr < attrnamebuf + listsize; nameptr += namelen + 1)
2516 {
2517 namelen = strlen(nameptr);
2518
2519 if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0)
2520 copyfile_pack_acl(s, &databuf, &datasize);
2521 else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0)
2522 {
2523 copyfile_pack_quarantine(s, &databuf, &datasize);
2524 }
2525 /* Check for Finder Info. */
2526 else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0)
2527 {
2528 datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0);
2529 if (datasize < 0)
2530 {
2531 if (COPYFILE_VERBOSE & s->flags)
2532 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
2533 } else if (datasize != 32)
2534 {
2535 if (COPYFILE_VERBOSE & s->flags)
2536 copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr);
2537 } else
2538 {
2539 if (COPYFILE_VERBOSE & s->flags)
2540 copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
2541 XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset);
2542 }
2543 continue; /* finder info doesn't have an attribute entry */
2544 }
2545 /* Check for Resource Fork. */
2546 else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0)
2547 {
2548 hasrsrcfork = 1;
2549 continue;
2550 } else
2551 {
2552 /* Just a normal attribute. */
2553 datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0);
2554 if (datasize == 0)
2555 goto next;
2556 if (datasize < 0)
2557 {
2558 if (COPYFILE_VERBOSE & s->flags)
2559 copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
2560 goto next;
2561 }
2562 if (datasize > XATTR_MAXATTRLEN)
2563 {
2564 if (COPYFILE_VERBOSE & s->flags)
2565 copyfile_warn("skipping attr \"%s\" (too big)", nameptr);
2566 goto next;
2567 }
2568 databuf = malloc(datasize);
2569 if (databuf == NULL) {
2570 error = -1;
2571 continue;
2572 }
2573 datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0);
2574 }
2575
2576 entry->length = (u_int32_t)datasize;
2577 entry->offset = filehdr->data_start + filehdr->data_length;
2578
2579 filehdr->data_length += (u_int32_t)datasize;
2580 /*
2581 * >>> WARNING <<<
2582 * This assumes that the data is fits in memory (not
2583 * the case when there are lots of attributes or one of
2584 * the attributes is very large.
2585 */
2586 if (entry->offset > ATTR_MAX_SIZE ||
2587 (entry->offset + datasize > ATTR_MAX_SIZE)) {
2588 error = 1;
2589 } else {
2590 bcopy(databuf, (char*)filehdr + entry->offset, datasize);
2591 }
2592 free(databuf);
2593
2594 copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
2595 next:
2596 /* bump to next entry */
2597 entrylen = ATTR_ENTRY_LENGTH(entry->namelen);
2598 entry = (attr_entry_t *)((char *)entry + entrylen);
2599 }
2600
2601 if (filehdr->data_length > 0)
2602 {
2603 /* Now we know where the resource fork data starts. */
2604 filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
2605
2606 /* We also know the size of the "Finder Info entry. */
2607 filehdr->appledouble.entries[0].length =
2608 filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
2609
2610 filehdr->total_size = filehdr->appledouble.entries[1].offset;
2611 }
2612
2613 /* Copy Resource Fork. */
2614 if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
2615 goto exit;
2616
2617 /* Write the header to disk. */
2618 datasize = filehdr->appledouble.entries[1].offset;
2619
2620 swap_adhdr(&filehdr->appledouble);
2621 swap_attrhdr(filehdr);
2622
2623 if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize)
2624 {
2625 if (COPYFILE_VERBOSE & s->flags)
2626 copyfile_warn("couldn't write file header");
2627 error = -1;
2628 goto exit;
2629 }
2630 exit:
2631 if (filehdr) free(filehdr);
2632 if (attrnamebuf) free(attrnamebuf);
2633
2634 if (error)
2635 return error;
2636 else
2637 return copyfile_stat(s);
2638 }