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
61static void * qtn_file_alloc(void) { return NULL; }
62static int qtn_file_init_with_fd(void *x, int y) { return -1; }
63static int qtn_file_init_with_path(void *x, const char *path) { return -1; }
64static int qtn_file_init_with_data(void *x, const void *data, size_t len) { return -1; }
65static void qtn_file_free(void *x) { return; }
66static int qtn_file_apply_to_fd(void *x, int y) { return 0; }
67static char *qtn_error(int x) { return NULL; }
68static int qtn_file_to_data(void *x, char *y, size_t z) { return -1; }
69static 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_flags.h"
76
77enum 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 */
92struct _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    xattr_operation_intent_t copyIntent;
113};
114
115struct 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
135static int
136acl_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
146static int
147doesdecmpfs(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
177static void
178sort_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
258done:
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 */
268static int copyfile_open	(copyfile_state_t);
269static int copyfile_close	(copyfile_state_t);
270static int copyfile_data	(copyfile_state_t);
271static int copyfile_stat	(copyfile_state_t);
272static int copyfile_security	(copyfile_state_t);
273static int copyfile_xattr	(copyfile_state_t);
274static int copyfile_pack	(copyfile_state_t);
275static int copyfile_unpack	(copyfile_state_t);
276
277static copyfile_flags_t copyfile_check	(copyfile_state_t);
278static filesec_t copyfile_fix_perms(copyfile_state_t, filesec_t *);
279static int copyfile_preamble(copyfile_state_t *s, copyfile_flags_t flags);
280static int copyfile_internal(copyfile_state_t state, copyfile_flags_t flags);
281static int copyfile_unset_posix_fsec(filesec_t);
282static 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
306static 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    }
326done:
327    return rv;
328}
329
330static int
331add_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;
393error_exit:
394	return -1;
395}
396
397static int
398is_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
432done:
433
434	if (qual)
435		acl_free(qual);
436
437	if (tacl)
438		acl_free(tacl);
439
440	return retval;
441}
442
443static void
444remove_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
479done:
480	if (acl)
481		acl_free(acl);
482	if (fsec)
483		filesec_free(fsec);
484	return;
485
486noacl:
487	fchmod(fd, sbuf->st_mode & ~S_IFMT);
488	goto done;
489}
490
491static void
492reset_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
574static int
575copytree(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		}
847skipit:
848stopit:
849		copyfile_state_free(tstate);
850		free(dstfile);
851		if (retval == -1)
852			break;
853	}
854
855done:
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 */
868int 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 */
947int 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
1082exit:
1083    if (state == NULL) {
1084	int t = errno;
1085	copyfile_state_free(s);
1086	errno = t;
1087    }
1088
1089    return ret;
1090
1091error_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 */
1105static 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 */
1151static 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
1273exit:
1274    return ret;
1275
1276error_exit:
1277    ret = -1;
1278    goto exit;
1279}
1280
1281/*
1282 * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
1283 */
1284copyfile_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 */
1307int 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 */
1343static 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 */
1364static 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
1433exit:
1434    if (acl)
1435	acl_free(acl);
1436
1437    return ret_fsec;
1438
1439error_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 */
1452static int
1453copyfile_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 */
1465static 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 */
1492static 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 */
1698static 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 */
1784static 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
1913exit:
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 */
1928static 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    }
2026no_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);
2087exit:
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
2095error_exit:
2096    ret = -1;
2097goto 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 */
2105static int copyfile_stat(copyfile_state_t s)
2106{
2107    struct timeval tval[2];
2108    unsigned int added_flags = 0, dst_flags = 0;
2109    struct stat dst_sb;
2110
2111    /*
2112     * NFS doesn't support chflags; ignore errors as a result, since
2113     * we don't return failure for this.
2114     */
2115    if (s->internal_flags & cfMakeFileInvisible)
2116	added_flags |= UF_HIDDEN;
2117
2118    /*
2119    * We need to check if SF_RESTRICTED was set on the destination
2120    * by the kernel.  If it was, don't drop it.
2121    */
2122    if (fstat(s->dst_fd, &dst_sb))
2123	return -1;
2124    if (dst_sb.st_flags & SF_RESTRICTED)
2125	added_flags |= SF_RESTRICTED;
2126
2127    /* Copy file flags, masking out any we don't want to preserve */
2128    dst_flags = (s->sb.st_flags & ~COPYFILE_OMIT_FLAGS) | added_flags;
2129    (void)fchflags(s->dst_fd, dst_flags);
2130
2131    /* If this fails, we don't care */
2132    (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
2133
2134    /* This may have already been done in copyfile_security() */
2135    (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT);
2136
2137    tval[0].tv_sec = s->sb.st_atime;
2138    tval[1].tv_sec = s->sb.st_mtime;
2139    tval[0].tv_usec = tval[1].tv_usec = 0;
2140    (void)futimes(s->dst_fd, tval);
2141
2142    return 0;
2143}
2144
2145/*
2146 * Similar to copyfile_security() in some ways; this
2147 * routine copies the extended attributes from the source,
2148 * and sets them on the destination.
2149 * The procedure is pretty simple, even if it is verbose:
2150 * for each named attribute on the destination, get its name, and
2151 * remove it.  We should have none after that.
2152 * For each named attribute on the source, get its name, get its
2153 * data, and set it on the destination.
2154 */
2155static int copyfile_xattr(copyfile_state_t s)
2156{
2157    char *name;
2158    char *namebuf, *end;
2159    ssize_t xa_size;
2160    void *xa_dataptr;
2161    ssize_t bufsize = 4096;
2162    ssize_t asize;
2163    ssize_t nsize;
2164    int ret = 0;
2165    int look_for_decmpea = 0;
2166
2167    /* delete EAs on destination */
2168    if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
2169    {
2170	if ((namebuf = (char *) malloc(nsize)) == NULL)
2171	    return -1;
2172	else
2173	    nsize = flistxattr(s->dst_fd, namebuf, nsize, 0);
2174
2175	if (nsize > 0) {
2176	    /*
2177	     * With this, end points to the last byte of the allocated buffer
2178	     * This *should* be NUL, from flistxattr, but if it's not, we can
2179	     * set it anyway -- it'll result in a truncated name, which then
2180	     * shouldn't match when we get them later.
2181	     */
2182	    end = namebuf + nsize - 1;
2183	    if (*end != 0)
2184		*end = 0;
2185	    for (name = namebuf; name <= end; name += strlen(name) + 1) {
2186		/* If the quarantine information shows up as an EA, we skip over it */
2187		if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) {
2188		    continue;
2189		}
2190		fremovexattr(s->dst_fd, name,0);
2191	    }
2192	}
2193	free(namebuf);
2194    } else
2195    if (nsize < 0)
2196    {
2197	if (errno == ENOTSUP || errno == EPERM)
2198	    return 0;
2199	else
2200	    return -1;
2201    }
2202
2203#ifdef DECMPFS_XATTR_NAME
2204    if ((s->flags & COPYFILE_DATA) &&
2205	(s->sb.st_flags & UF_COMPRESSED) &&
2206	doesdecmpfs(s->src_fd) &&
2207	doesdecmpfs(s->dst_fd)) {
2208	look_for_decmpea = XATTR_SHOWCOMPRESSION;
2209    }
2210#endif
2211
2212    /* get name list of EAs on source */
2213    if ((nsize = flistxattr(s->src_fd, 0, 0, look_for_decmpea)) < 0)
2214    {
2215	if (errno == ENOTSUP || errno == EPERM)
2216	    return 0;
2217	else
2218	    return -1;
2219    } else
2220    if (nsize == 0)
2221	return 0;
2222
2223    if ((namebuf = (char *) malloc(nsize)) == NULL)
2224	return -1;
2225    else
2226	nsize = flistxattr(s->src_fd, namebuf, nsize, look_for_decmpea);
2227
2228    if (nsize <= 0) {
2229	free(namebuf);
2230	return (int)nsize;
2231    }
2232
2233    /*
2234     * With this, end points to the last byte of the allocated buffer
2235     * This *should* be NUL, from flistxattr, but if it's not, we can
2236     * set it anyway -- it'll result in a truncated name, which then
2237     * shouldn't match when we get them later.
2238     */
2239    end = namebuf + nsize - 1;
2240    if (*end != 0)
2241	*end = 0;
2242
2243    if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) {
2244	free(namebuf);
2245	return -1;
2246    }
2247
2248    for (name = namebuf; name <= end; name += strlen(name) + 1)
2249    {
2250	if (s->xattr_name) {
2251		free(s->xattr_name);
2252		s->xattr_name = NULL;
2253	}
2254
2255	/* If the quarantine information shows up as an EA, we skip over it */
2256	if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0)
2257	    continue;
2258
2259	if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, look_for_decmpea)) < 0)
2260	{
2261	    continue;
2262	}
2263
2264	if (xa_size > bufsize)
2265	{
2266	    void *tdptr = xa_dataptr;
2267	    bufsize = xa_size;
2268	    if ((xa_dataptr =
2269		(void *) realloc((void *) xa_dataptr, bufsize)) == NULL)
2270	    {
2271		free(tdptr);
2272		ret = -1;
2273		continue;
2274	    }
2275	}
2276
2277	if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea)) < 0)
2278	{
2279	    continue;
2280	}
2281
2282	if (xa_size != asize)
2283	    xa_size = asize;
2284
2285#ifdef DECMPFS_XATTR_NAME
2286	if (strncmp(name, DECMPFS_XATTR_NAME, end-name) == 0)
2287	{
2288	    decmpfs_disk_header *hdr = xa_dataptr;
2289
2290	    /*
2291	     * If the EA has the decmpfs name, but is too
2292	     * small, or doesn't have the right magic number,
2293	     * or isn't the right type, we'll just skip it.
2294	     * This means it won't end up in the destination
2295	     * file, and data copy will happen normally.
2296	     */
2297	    if ((size_t)xa_size < sizeof(decmpfs_disk_header)) {
2298		continue;
2299	    }
2300	    if (OSSwapLittleToHostInt32(hdr->compression_magic) != DECMPFS_MAGIC) {
2301		continue;
2302	    }
2303	    /*
2304	     * From AppleFSCompression documentation:
2305	     * "It is incumbent on the aware copy engine to identify
2306	     *  the type of compression being used, and to perform an
2307	     *  unaware copy of any file it does not recognize."
2308	     *
2309	     * Compression Types are defined in:
2310	     * "AppleFSCompression/Common/compressorCommon.h"
2311	     *
2312	     * Unfortunately, they don't provide a way to dynamically
2313	     * determine what possible compression_type values exist,
2314	     * so we have to update this every time a new compression_type
2315	     * is added (Types 7->10 were added in Yosemite)
2316	     *
2317	     * Ubiquity faulting file compression type 0x80000001 are
2318	     * deprecated as of Yosemite, per rdar://17714998 don't copy the
2319	     * decmpfs xattr on these files, zero byte files are safer
2320	     * than a fault nobody knows how to handle.
2321	     */
2322	    switch (OSSwapLittleToHostInt32(hdr->compression_type)) {
2323		case 3: /* zlib-compressed data in xattr */
2324		case 4: /* 64k chunked zlib-compressed data in resource fork */
2325
2326		case 7: /* LZVN-compressed data in xattr */
2327		case 8: /* 64k chunked LZVN-compressed data in resource fork */
2328
2329		case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */
2330		case 10: /* 64k chunked uncompressed data in resource fork */
2331
2332			/* valid compression type, we want to copy. */
2333			break;
2334
2335		case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */
2336			copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.",
2337				      s->src ? s->src : "(null string)");
2338			continue;
2339
2340		case 6: /* unused */
2341		case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */
2342		default:
2343			copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s",
2344				      OSSwapLittleToHostInt32(hdr->compression_type), name, s->src ? s->src : "(null string)");
2345			continue;
2346	    }
2347	    s->internal_flags |= cfSawDecmpEA;
2348	}
2349#endif
2350
2351	// If we have a copy intention stated, and the EA is to be ignored, we ignore it
2352	if (s->copyIntent
2353	    && xattr_preserve_for_intent(name, s->copyIntent) == 0)
2354		continue;
2355
2356	s->xattr_name = strdup(name);
2357
2358	if (s->statuscb) {
2359		int rv;
2360		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
2361		if (rv == COPYFILE_QUIT) {
2362			s->err = ECANCELED;
2363			goto out;
2364		} else if (rv == COPYFILE_SKIP) {
2365			continue;
2366		}
2367	}
2368	if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, look_for_decmpea) < 0)
2369	{
2370	    if (s->statuscb)
2371	    {
2372		int rv;
2373		if (s->xattr_name == NULL)
2374			s->xattr_name = strdup(name);
2375		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
2376		if (rv == COPYFILE_QUIT)
2377		{
2378		    s->err = ECANCELED;
2379		    ret = -1;
2380		    goto out;
2381		}
2382	    }
2383	    else
2384	    {
2385		ret = -1;
2386		copyfile_warn("could not set attributes %s on destination file descriptor: %s", name, strerror(errno));
2387		continue;
2388	    }
2389	}
2390	if (s->statuscb) {
2391		int rv;
2392		if (s->xattr_name == NULL)
2393			s->xattr_name = strdup(name);
2394
2395		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
2396		if (rv == COPYFILE_QUIT) {
2397			s->err = ECANCELED;
2398			goto out;
2399		}
2400	}
2401    }
2402out:
2403    if (namebuf)
2404	free(namebuf);
2405    free((void *) xa_dataptr);
2406    if (s->xattr_name) {
2407	free(s->xattr_name);
2408	s->xattr_name = NULL;
2409    }
2410    return ret;
2411}
2412
2413/*
2414 * API interface into getting data from the opaque data type.
2415 */
2416int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
2417{
2418    if (ret == NULL)
2419    {
2420	errno = EFAULT;
2421	return -1;
2422    }
2423
2424    switch(flag)
2425    {
2426	case COPYFILE_STATE_SRC_FD:
2427	    *(int*)ret = s->src_fd;
2428	    break;
2429	case COPYFILE_STATE_DST_FD:
2430	    *(int*)ret = s->dst_fd;
2431	    break;
2432	case COPYFILE_STATE_SRC_FILENAME:
2433	    *(char**)ret = s->src;
2434	    break;
2435	case COPYFILE_STATE_DST_FILENAME:
2436	    *(char**)ret = s->dst;
2437	    break;
2438	case COPYFILE_STATE_QUARANTINE:
2439	    *(qtn_file_t*)ret = s->qinfo;
2440	    break;
2441#if 0
2442	case COPYFILE_STATE_STATS:
2443	    ret = s->stats.global;
2444	    break;
2445	case COPYFILE_STATE_PROGRESS_CB:
2446	    ret = s->callbacks.progress;
2447	    break;
2448#endif
2449#ifdef	COPYFILE_STATE_STATUS_CB
2450	case COPYFILE_STATE_STATUS_CB:
2451	    *(copyfile_callback_t*)ret = s->statuscb;
2452	    break;
2453	case COPYFILE_STATE_STATUS_CTX:
2454	    *(void**)ret = s->ctx;
2455	    break;
2456	case COPYFILE_STATE_COPIED:
2457	    *(off_t*)ret = s->totalCopied;
2458	    break;
2459#endif
2460#ifdef COPYFILE_STATE_XATTRNAME
2461	case COPYFILE_STATE_XATTRNAME:
2462		*(char**)ret = s->xattr_name;
2463		break;
2464#endif
2465#ifdef COPYFILE_STATE_INTENT
2466       case COPYFILE_STATE_INTENT:
2467           *(xattr_operation_intent_t*)ret = s->copyIntent;
2468	   break;
2469#endif
2470	default:
2471	    errno = EINVAL;
2472	    ret = NULL;
2473	    return -1;
2474    }
2475    return 0;
2476}
2477
2478/*
2479 * Public API for setting state data (remember that the state is
2480 * an opaque data type).
2481 */
2482int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
2483{
2484#define copyfile_set_string(DST, SRC) \
2485    do {					\
2486	if (SRC != NULL) {			\
2487	    DST = strdup((char *)SRC);		\
2488	} else {				\
2489	    if (DST != NULL) {			\
2490		free(DST);			\
2491	    }					\
2492	    DST = NULL;				\
2493	}					\
2494    } while (0)
2495
2496    if (thing == NULL)
2497    {
2498	errno = EFAULT;
2499	return  -1;
2500    }
2501
2502    switch(flag)
2503    {
2504	case COPYFILE_STATE_SRC_FD:
2505	    s->src_fd = *(int*)thing;
2506	    break;
2507	case COPYFILE_STATE_DST_FD:
2508	     s->dst_fd = *(int*)thing;
2509	    break;
2510	case COPYFILE_STATE_SRC_FILENAME:
2511	    copyfile_set_string(s->src, thing);
2512	    break;
2513	case COPYFILE_STATE_DST_FILENAME:
2514	    copyfile_set_string(s->dst, thing);
2515	    break;
2516	case COPYFILE_STATE_QUARANTINE:
2517	    if (s->qinfo)
2518	    {
2519		qtn_file_free(s->qinfo);
2520		s->qinfo = NULL;
2521	    }
2522	    if (*(qtn_file_t*)thing)
2523		s->qinfo = qtn_file_clone(*(qtn_file_t*)thing);
2524	    break;
2525#if 0
2526	case COPYFILE_STATE_STATS:
2527	     s->stats.global = thing;
2528	    break;
2529	case COPYFILE_STATE_PROGRESS_CB:
2530	     s->callbacks.progress = thing;
2531	    break;
2532#endif
2533#ifdef COPYFILE_STATE_STATUS_CB
2534	case COPYFILE_STATE_STATUS_CB:
2535	    s->statuscb = (copyfile_callback_t)thing;
2536	    break;
2537	case COPYFILE_STATE_STATUS_CTX:
2538	    s->ctx = (void*)thing;
2539	    break;
2540#endif
2541#ifdef COPYFILE_STATE_INTENT
2542       case COPYFILE_STATE_INTENT:
2543           s->copyIntent = *(xattr_operation_intent_t*)thing;
2544	   break;
2545#endif
2546	default:
2547	    errno = EINVAL;
2548	    return -1;
2549    }
2550    return 0;
2551#undef copyfile_set_string
2552}
2553
2554
2555/*
2556 * Make this a standalone program for testing purposes by
2557 * defining _COPYFILE_TEST.
2558 */
2559#ifdef _COPYFILE_TEST
2560#define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
2561
2562struct {char *s; int v;} opts[] = {
2563    COPYFILE_OPTION(ACL)
2564    COPYFILE_OPTION(STAT)
2565    COPYFILE_OPTION(XATTR)
2566    COPYFILE_OPTION(DATA)
2567    COPYFILE_OPTION(SECURITY)
2568    COPYFILE_OPTION(METADATA)
2569    COPYFILE_OPTION(ALL)
2570    COPYFILE_OPTION(NOFOLLOW_SRC)
2571    COPYFILE_OPTION(NOFOLLOW_DST)
2572    COPYFILE_OPTION(NOFOLLOW)
2573    COPYFILE_OPTION(EXCL)
2574    COPYFILE_OPTION(MOVE)
2575    COPYFILE_OPTION(UNLINK)
2576    COPYFILE_OPTION(PACK)
2577    COPYFILE_OPTION(UNPACK)
2578    COPYFILE_OPTION(CHECK)
2579    COPYFILE_OPTION(VERBOSE)
2580    COPYFILE_OPTION(DEBUG)
2581    {NULL, 0}
2582};
2583
2584int main(int c, char *v[])
2585{
2586    int i;
2587    int flags = 0;
2588
2589    if (c < 3)
2590	errx(1, "insufficient arguments");
2591
2592    while(c-- > 3)
2593    {
2594	for (i = 0; opts[i].s != NULL; ++i)
2595	{
2596	    if (strcasecmp(opts[i].s, v[c]) == 0)
2597	    {
2598		printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v);
2599		flags |= opts[i].v;
2600		break;
2601	    }
2602	}
2603    }
2604
2605    return copyfile(v[1], v[2], NULL, flags);
2606}
2607#endif
2608/*
2609 * Apple Double Create
2610 *
2611 * Create an Apple Double "._" file from a file's extented attributes
2612 *
2613 * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
2614 */
2615
2616
2617#define offsetof(type, member)	((size_t)(&((type *)0)->member))
2618
2619#define	XATTR_MAXATTRLEN   (16*1024*1024)
2620
2621
2622/*
2623   Typical "._" AppleDouble Header File layout:
2624  ------------------------------------------------------------
2625         MAGIC          0x00051607
2626         VERSION        0x00020000
2627         FILLER         0
2628         COUNT          2
2629     .-- AD ENTRY[0]    Finder Info Entry (must be first)
2630  .--+-- AD ENTRY[1]    Resource Fork Entry (must be last)
2631  |  '-> FINDER INFO
2632  |      /////////////  Fixed Size Data (32 bytes)
2633  |      EXT ATTR HDR
2634  |      /////////////
2635  |      ATTR ENTRY[0] --.
2636  |      ATTR ENTRY[1] --+--.
2637  |      ATTR ENTRY[2] --+--+--.
2638  |         ...          |  |  |
2639  |      ATTR ENTRY[N] --+--+--+--.
2640  |      ATTR DATA 0   <-'  |  |  |
2641  |      ////////////       |  |  |
2642  |      ATTR DATA 1   <----'  |  |
2643  |      /////////////         |  |
2644  |      ATTR DATA 2   <-------'  |
2645  |      /////////////            |
2646  |         ...                   |
2647  |      ATTR DATA N   <----------'
2648  |      /////////////
2649  |                      Attribute Free Space
2650  |
2651  '----> RESOURCE FORK
2652         /////////////   Variable Sized Data
2653         /////////////
2654         /////////////
2655         /////////////
2656         /////////////
2657         /////////////
2658            ...
2659         /////////////
2660
2661  ------------------------------------------------------------
2662
2663   NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
2664   stored as part of the Finder Info.  The length in the Finder
2665   Info AppleDouble entry includes the length of the extended
2666   attribute header, attribute entries, and attribute data.
2667*/
2668
2669
2670/*
2671 * On Disk Data Structures
2672 *
2673 * Note: Motorola 68K alignment and big-endian.
2674 *
2675 * See RFC 1740 for additional information about the AppleDouble file format.
2676 *
2677 */
2678
2679#define ADH_MAGIC     0x00051607
2680#define ADH_VERSION   0x00020000
2681#define ADH_MACOSX    "Mac OS X        "
2682
2683/*
2684 * AppleDouble Entry ID's
2685 */
2686#define AD_DATA          1   /* Data fork */
2687#define AD_RESOURCE      2   /* Resource fork */
2688#define AD_REALNAME      3   /* File's name on home file system */
2689#define AD_COMMENT       4   /* Standard Mac comment */
2690#define AD_ICONBW        5   /* Mac black & white icon */
2691#define AD_ICONCOLOR     6   /* Mac color icon */
2692#define AD_UNUSED        7   /* Not used */
2693#define AD_FILEDATES     8   /* File dates; create, modify, etc */
2694#define AD_FINDERINFO    9   /* Mac Finder info & extended info */
2695#define AD_MACINFO      10   /* Mac file info, attributes, etc */
2696#define AD_PRODOSINFO   11   /* Pro-DOS file info, attrib., etc */
2697#define AD_MSDOSINFO    12   /* MS-DOS file info, attributes, etc */
2698#define AD_AFPNAME      13   /* Short name on AFP server */
2699#define AD_AFPINFO      14   /* AFP file info, attrib., etc */
2700#define AD_AFPDIRID     15   /* AFP directory ID */
2701#define AD_ATTRIBUTES   AD_FINDERINFO
2702
2703
2704#define ATTR_FILE_PREFIX   "._"
2705#define ATTR_HDR_MAGIC     0x41545452   /* 'ATTR' */
2706
2707#define ATTR_BUF_SIZE      4096        /* default size of the attr file and how much we'll grow by */
2708
2709/* Implementation Limits */
2710#define ATTR_MAX_SIZE      (16*1024*1024)	/* 16 megabyte maximum attribute data size */
2711#define ATTR_MAX_NAME_LEN  128
2712#define ATTR_MAX_HDR_SIZE  (65536+18)
2713
2714/*
2715 * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
2716 * size supported (including the attribute entries). All of
2717 * the attribute entries must reside within this limit.
2718 */
2719
2720
2721#define FINDERINFOSIZE	32
2722
2723typedef struct apple_double_entry
2724{
2725	u_int32_t   type;     /* entry type: see list, 0 invalid */
2726	u_int32_t   offset;   /* entry data offset from the beginning of the file. */
2727	u_int32_t   length;   /* entry data length in bytes. */
2728} __attribute__((aligned(2), packed)) apple_double_entry_t;
2729
2730
2731typedef struct apple_double_header
2732{
2733	u_int32_t   magic;         /* == ADH_MAGIC */
2734	u_int32_t   version;       /* format version: 2 = 0x00020000 */
2735	u_int32_t   filler[4];
2736	u_int16_t   numEntries;	   /* number of entries which follow */
2737	apple_double_entry_t   entries[2];  /* 'finfo' & 'rsrc' always exist */
2738	u_int8_t    finfo[FINDERINFOSIZE];  /* Must start with Finder Info (32 bytes) */
2739	u_int8_t    pad[2];        /* get better alignment inside attr_header */
2740} __attribute__((aligned(2), packed)) apple_double_header_t;
2741
2742
2743/* Entries are aligned on 4 byte boundaries */
2744typedef struct attr_entry
2745{
2746	u_int32_t   offset;    /* file offset to data */
2747	u_int32_t   length;    /* size of attribute data */
2748	u_int16_t   flags;
2749	u_int8_t    namelen;   /* length of name including NULL termination char */
2750	u_int8_t    name[1];   /* NULL-terminated UTF-8 name (up to 128 bytes max) */
2751} __attribute__((aligned(2), packed)) attr_entry_t;
2752
2753
2754
2755/* Header + entries must fit into 64K */
2756typedef struct attr_header
2757{
2758	apple_double_header_t  appledouble;
2759	u_int32_t   magic;        /* == ATTR_HDR_MAGIC */
2760	u_int32_t   debug_tag;    /* for debugging == file id of owning file */
2761	u_int32_t   total_size;   /* total size of attribute header + entries + data */
2762	u_int32_t   data_start;   /* file offset to attribute data area */
2763	u_int32_t   data_length;  /* length of attribute data area */
2764	u_int32_t   reserved[3];
2765	u_int16_t   flags;
2766	u_int16_t   num_attrs;
2767} __attribute__((aligned(2), packed)) attr_header_t;
2768
2769/* Empty Resource Fork Header */
2770/* This comes by way of xnu's vfs_xattr.c */
2771typedef struct rsrcfork_header {
2772	u_int32_t	fh_DataOffset;
2773	u_int32_t	fh_MapOffset;
2774	u_int32_t	fh_DataLength;
2775	u_int32_t	fh_MapLength;
2776	u_int8_t	systemData[112];
2777	u_int8_t	appData[128];
2778	u_int32_t	mh_DataOffset;
2779	u_int32_t	mh_MapOffset;
2780	u_int32_t	mh_DataLength;
2781	u_int32_t	mh_MapLength;
2782	u_int32_t	mh_Next;
2783	u_int16_t	mh_RefNum;
2784	u_int8_t	mh_Attr;
2785	u_int8_t	mh_InMemoryAttr;
2786	u_int16_t	mh_Types;
2787	u_int16_t	mh_Names;
2788	u_int16_t	typeCount;
2789} __attribute__((aligned(2), packed)) rsrcfork_header_t;
2790#define RF_FIRST_RESOURCE    256
2791#define RF_NULL_MAP_LENGTH    30
2792#define RF_EMPTY_TAG  "This resource fork intentionally left blank   "
2793
2794static const rsrcfork_header_t empty_rsrcfork_header = {
2795	OSSwapHostToBigInt32(RF_FIRST_RESOURCE),	// fh_DataOffset
2796	OSSwapHostToBigInt32(RF_FIRST_RESOURCE),	// fh_MapOffset
2797	0,						// fh_DataLength
2798	OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH),	// fh_MapLength
2799	{ RF_EMPTY_TAG, },				// systemData
2800	{ 0 },						// appData
2801	OSSwapHostToBigInt32(RF_FIRST_RESOURCE),	// mh_DataOffset
2802	OSSwapHostToBigInt32(RF_FIRST_RESOURCE),	// mh_MapOffset
2803	0,						// mh_DataLength
2804	OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH),	// mh_MapLength
2805	0,						// mh_Next
2806	0,						// mh_RefNum
2807	0,						// mh_Attr
2808	0,						// mh_InMemoryAttr
2809	OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2),	// mh_Types
2810	OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH),	// mh_Names
2811	OSSwapHostToBigInt16(-1),			// typeCount
2812};
2813
2814#define SWAP16(x)	OSSwapBigToHostInt16(x)
2815#define SWAP32(x)	OSSwapBigToHostInt32(x)
2816#define SWAP64(x)	OSSwapBigToHostInt64(x)
2817
2818#define ATTR_ALIGN 3L  /* Use four-byte alignment */
2819
2820#define ATTR_ENTRY_LENGTH(namelen)  \
2821        ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
2822
2823#define ATTR_NEXT(ae)  \
2824	 (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
2825
2826#define	XATTR_SECURITY_NAME	  "com.apple.acl.text"
2827
2828/*
2829 * Endian swap Apple Double header
2830 */
2831static void
2832swap_adhdr(apple_double_header_t *adh)
2833{
2834#if BYTE_ORDER == LITTLE_ENDIAN
2835	int count;
2836	int i;
2837
2838	count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
2839
2840	adh->magic      = SWAP32 (adh->magic);
2841	adh->version    = SWAP32 (adh->version);
2842	adh->numEntries = SWAP16 (adh->numEntries);
2843
2844	for (i = 0; i < count; i++)
2845	{
2846		adh->entries[i].type   = SWAP32 (adh->entries[i].type);
2847		adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
2848		adh->entries[i].length = SWAP32 (adh->entries[i].length);
2849	}
2850#else
2851	(void)adh;
2852#endif
2853}
2854
2855/*
2856 * Endian swap a single attr_entry_t
2857 */
2858static void
2859swap_attrhdr_entry(attr_entry_t *ae)
2860{
2861#if BYTE_ORDER == LITTLE_ENDIAN
2862     ae->offset = SWAP32 (ae->offset);
2863     ae->length = SWAP32 (ae->length);
2864     ae->flags  = SWAP16 (ae->flags);
2865#else
2866     (void)ae;
2867#endif
2868}
2869
2870/*
2871 * For a validated/endian swapped attr_header_t*
2872 * ah, endian swap all of the entries.
2873 */
2874static void
2875swap_attrhdr_entries(attr_header_t *ah)
2876{
2877#if BYTE_ORDER == LITTLE_ENDIAN
2878     int i;
2879     int count;
2880     attr_entry_t *entry;
2881     attr_entry_t *next;
2882
2883     /* If we're in copyfile_pack, num_args is native endian,
2884      * if we're in _unpack, num_args is big endian. Use
2885      * the magic number to test for  endianess.
2886      */
2887     count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
2888
2889     entry = (attr_entry_t *)(&ah[1]);
2890     for (i = 0; i < count; i++) {
2891          next = ATTR_NEXT(entry);
2892          swap_attrhdr_entry(entry);
2893          entry = next;
2894     }
2895#else
2896    (void)ah;
2897#endif
2898}
2899
2900/*
2901 * Endian swap extended attributes header
2902 */
2903static void
2904swap_attrhdr(attr_header_t *ah)
2905{
2906#if BYTE_ORDER == LITTLE_ENDIAN
2907	ah->magic       = SWAP32 (ah->magic);
2908	ah->debug_tag   = SWAP32 (ah->debug_tag);
2909	ah->total_size  = SWAP32 (ah->total_size);
2910	ah->data_start  = SWAP32 (ah->data_start);
2911	ah->data_length = SWAP32 (ah->data_length);
2912	ah->flags       = SWAP16 (ah->flags);
2913	ah->num_attrs   = SWAP16 (ah->num_attrs);
2914#else
2915	(void)ah;
2916#endif
2917}
2918
2919static const u_int32_t emptyfinfo[8] = {0};
2920
2921/*
2922 * Given an Apple Double file in src, turn it into a
2923 * normal file (possibly with multiple forks, EAs, and
2924 * ACLs) in dst.
2925 */
2926static int copyfile_unpack(copyfile_state_t s)
2927{
2928    ssize_t bytes;
2929    void * buffer, * endptr, * dataptr = NULL;
2930    apple_double_header_t *adhdr;
2931    ssize_t hdrsize;
2932    int error = 0;
2933
2934    if (s->sb.st_size < ATTR_MAX_HDR_SIZE)
2935	hdrsize = (ssize_t)s->sb.st_size;
2936    else
2937	hdrsize = ATTR_MAX_HDR_SIZE;
2938
2939    buffer = calloc(1, hdrsize);
2940    if (buffer == NULL) {
2941	copyfile_debug(1, "copyfile_unpack: calloc(1, %zu) returned NULL", hdrsize);
2942	error = -1;
2943	goto exit;
2944    } else
2945	endptr = (char*)buffer + hdrsize;
2946
2947    bytes = pread(s->src_fd, buffer, hdrsize, 0);
2948
2949    if (bytes < 0)
2950    {
2951	copyfile_debug(1, "pread returned: %zd", bytes);
2952	error = -1;
2953	goto exit;
2954    }
2955    if (bytes < hdrsize)
2956    {
2957	copyfile_debug(1,
2958	    "pread couldn't read entire header: %d of %d",
2959	    (int)bytes, (int)s->sb.st_size);
2960	error = -1;
2961	goto exit;
2962    }
2963    adhdr = (apple_double_header_t *)buffer;
2964
2965    /*
2966     * Check for Apple Double file.
2967     */
2968    if ((size_t)bytes < sizeof(apple_double_header_t) - 2 ||
2969	SWAP32(adhdr->magic) != ADH_MAGIC ||
2970	SWAP32(adhdr->version) != ADH_VERSION ||
2971	SWAP16(adhdr->numEntries) != 2 ||
2972	SWAP32(adhdr->entries[0].type) != AD_FINDERINFO)
2973    {
2974	if (COPYFILE_VERBOSE & s->flags)
2975	    copyfile_warn("Not a valid Apple Double header");
2976	error = -1;
2977	goto exit;
2978    }
2979    swap_adhdr(adhdr);
2980
2981    /*
2982     * Remove any extended attributes on the target.
2983     */
2984
2985    if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
2986    {
2987	char *namebuf, *name;
2988
2989	if ((namebuf = (char*) malloc(bytes)) == NULL)
2990	{
2991	    s->err = ENOMEM;
2992	    goto exit;
2993	}
2994    bytes = flistxattr(s->dst_fd, namebuf, bytes, 0);
2995
2996    if (bytes > 0)
2997	for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1)
2998	    (void)fremovexattr(s->dst_fd, name, 0);
2999
3000    free(namebuf);
3001    }
3002    else if (bytes < 0)
3003    {
3004	if (errno != ENOTSUP && errno != EPERM)
3005	    goto exit;
3006    }
3007
3008    /*
3009     * Extract the extended attributes.
3010     *
3011     * >>>  WARNING <<<
3012     * This assumes that the data is already in memory (not
3013     * the case when there are lots of attributes or one of
3014     * the attributes is very large.
3015     */
3016    if (adhdr->entries[0].length > FINDERINFOSIZE)
3017    {
3018	attr_header_t *attrhdr;
3019	attr_entry_t *entry;
3020	int count;
3021	int i;
3022
3023	if ((size_t)hdrsize < sizeof(attr_header_t)) {
3024		copyfile_warn("bad attribute header:  %zu < %zu", hdrsize, sizeof(attr_header_t));
3025		error = -1;
3026		goto exit;
3027	}
3028
3029	attrhdr = (attr_header_t *)buffer;
3030	swap_attrhdr(attrhdr);
3031	if (attrhdr->magic != ATTR_HDR_MAGIC)
3032	{
3033	    if (COPYFILE_VERBOSE & s->flags)
3034		    copyfile_warn("bad attribute header");
3035	    error = -1;
3036	    goto exit;
3037	}
3038	count = attrhdr->num_attrs;
3039	entry = (attr_entry_t *)&attrhdr[1];
3040
3041	for (i = 0; i < count; i++)
3042	{
3043	    /*
3044	     * First we do some simple sanity checking.
3045	     * +) See if entry is within the buffer's range;
3046	     *
3047	     * +) Check the attribute name length; if it's longer than the
3048	     * maximum, we truncate it down.  (We could error out as well;
3049	     * I'm not sure which is the better way to go here.)
3050	     *
3051	     * +) If, given the name length, it goes beyond the end of
3052	     * the buffer, error out.
3053	     *
3054	     * +) If the last byte isn't a NUL, make it a NUL.  (Since we
3055	     * truncated the name length above, we truncate the name here.)
3056	     *
3057	     * +) If entry->offset is so large that it causes dataptr to
3058	     * go beyond the end of the buffer -- or, worse, so large that
3059	     * it wraps around! -- we error out.
3060	     *
3061	     * +) If entry->length would cause the entry to go beyond the
3062	     * end of the buffer (or, worse, wrap around to before it),
3063	     * *or* if the length is larger than the hdrsize, we error out.
3064	     * (An explanation of that:  what we're checking for there is
3065	     * the small range of values such that offset+length would cause
3066	     * it to go beyond endptr, and then wrap around past buffer.  We
3067	     * care about this because we are passing entry->length down to
3068	     * fgetxattr() below, and an erroneously large value could cause
3069	     * problems there.  By making sure that it's less than hdrsize,
3070	     * which has already been sanity-checked above, we're safe.
3071	     * That may mean that the check against < buffer is unnecessary.)
3072	     */
3073	    if ((void*)entry >= endptr || (void*)entry < buffer) {
3074		if (COPYFILE_VERBOSE & s->flags)
3075		    copyfile_warn("Incomplete or corrupt attribute entry");
3076		error = -1;
3077		s->err = EINVAL;
3078		goto exit;
3079	    }
3080
3081	    if (((char*)entry + sizeof(*entry)) > (char*)endptr) {
3082		if (COPYFILE_VERBOSE & s->flags)
3083		    copyfile_warn("Incomplete or corrupt attribute entry");
3084		error = -1;
3085		s->err = EINVAL;
3086		goto exit;
3087	    }
3088
3089        /*
3090	     * Endian swap the entry we're looking at. Previously
3091	     * we did this swap as part of swap_attrhdr, but that
3092	     * allowed a maliciously constructed file to overrun
3093	     * our allocation. Instead do the swap after we've verified
3094	     * the entry struct is within the buffer's range.
3095	     */
3096	    swap_attrhdr_entry(entry);
3097
3098	    if (entry->namelen < 2) {
3099		if (COPYFILE_VERBOSE & s->flags)
3100		    copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen);
3101		    error = -1;
3102		    s->err = EINVAL;
3103		    goto exit;
3104	    }
3105
3106	    if (entry->namelen > XATTR_MAXNAMELEN + 1) {
3107		if (COPYFILE_VERBOSE & s->flags)
3108		    copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen);
3109		error = -1;
3110		s->err = EINVAL;
3111		goto exit;
3112	    }
3113
3114	    if ((void*)(entry->name + entry->namelen) > endptr) {
3115		if (COPYFILE_VERBOSE & s->flags)
3116		    copyfile_warn("Incomplete or corrupt attribute entry");
3117		error = -1;
3118		s->err = EINVAL;
3119		goto exit;
3120	    }
3121
3122	    /* Because namelen includes the NUL, we check one byte back */
3123	    if (entry->name[entry->namelen-1] != 0) {
3124		if (COPYFILE_VERBOSE & s->flags)
3125		    copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
3126		error = -1;
3127		s->err = EINVAL;
3128		goto exit;
3129	    }
3130
3131	    copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
3132		entry->name, entry->length, entry->offset);
3133
3134#if 0
3135	    dataptr = (char *)attrhdr + entry->offset;
3136
3137	    if (dataptr > endptr || dataptr < buffer) {
3138		copyfile_debug(1, "Entry %d overflows:  offset = %u", i, entry->offset);
3139		error = -1;
3140		s->err = EINVAL;	/* Invalid buffer */
3141		goto exit;
3142	    }
3143
3144	    if (((char*)dataptr + entry->length) > (char*)endptr ||
3145		(((char*)dataptr + entry->length) < (char*)buffer) ||
3146		(entry->length > (size_t)hdrsize)) {
3147		if (COPYFILE_VERBOSE & s->flags)
3148		    copyfile_warn("Incomplete or corrupt attribute entry");
3149		copyfile_debug(1, "Entry %d length overflows:  offset = %u, length = %u",
3150			i, entry->offset, entry->length);
3151		error = -1;
3152		s->err = EINVAL;	/* Invalid buffer */
3153		goto exit;
3154	    }
3155
3156#else
3157	    dataptr = malloc(entry->length);
3158	    if (dataptr == NULL) {
3159		    copyfile_debug(1, "no memory for %u bytes\n", entry->length);
3160		    error = -1;
3161		    s->err = ENOMEM;
3162		    goto exit;
3163	    }
3164	    if (pread(s->src_fd, dataptr, entry->length, entry->offset) != (ssize_t)entry->length) {
3165		    copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry->length, entry->offset);
3166		    error = -1;
3167		    s->err = EINVAL;
3168		    goto exit;
3169	    }
3170#endif
3171
3172	    if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
3173	    {
3174		qtn_file_t tqinfo = NULL;
3175
3176		if (s->qinfo == NULL)
3177		{
3178		    tqinfo = qtn_file_alloc();
3179		    if (tqinfo)
3180		    {
3181			int x;
3182			if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0)
3183			{
3184			    copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x));
3185			    qtn_file_free(tqinfo);
3186			    tqinfo = NULL;
3187			}
3188		    }
3189		}
3190		else
3191		{
3192		    tqinfo = s->qinfo;
3193		}
3194		if (tqinfo)
3195		{
3196			int x;
3197			x = qtn_file_apply_to_fd(tqinfo, s->dst_fd);
3198			if (x != 0) {
3199			    copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x));
3200				if (s->statuscb) {
3201					int rv;
3202					s->xattr_name = (char*)XATTR_QUARANTINE_NAME;
3203					rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3204					s->xattr_name = NULL;
3205					if (rv == COPYFILE_QUIT) {
3206						error = s->err = x < 0 ? ENOTSUP : errno;
3207						goto exit;
3208					}
3209				} else {
3210			    		error = s->err = x < 0 ? ENOTSUP : errno;
3211			    		goto exit;
3212				}
3213			}
3214		}
3215		if (tqinfo && !s->qinfo)
3216		{
3217		    qtn_file_free(tqinfo);
3218		}
3219	    }
3220	    /* Look for ACL data */
3221	    else if (strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)
3222	    {
3223		acl_t acl;
3224		struct stat sb;
3225		int retry = 1;
3226		char *tcp = dataptr;
3227
3228		if (entry->length == 0) {
3229			/* Not sure how we got here, but we had one case
3230			 * where it was 0.  In a normal EA, we can have a 0-byte
3231			 * payload.  That means nothing in this case, so we'll
3232			 * simply skip the EA.
3233			 */
3234			error = 0;
3235			goto acl_done;
3236		}
3237		/*
3238		 * acl_from_text() requires a NUL-terminated string.  The ACL EA,
3239		 * however, may not be NUL-terminated.  So in that case, we need to
3240		 * copy it to a +1 sized buffer, to ensure it's got a terminated string.
3241		 */
3242		if (tcp[entry->length - 1] != 0) {
3243			char *tmpstr = malloc(entry->length + 1);
3244			if (tmpstr == NULL) {
3245				error = -1;
3246				goto exit;
3247			}
3248			strlcpy(tmpstr, tcp, entry->length + 1);
3249			acl = acl_from_text(tmpstr);
3250			free(tmpstr);
3251		} else {
3252			acl = acl_from_text(tcp);
3253		}
3254
3255		if (acl != NULL)
3256		{
3257		    filesec_t fsec_tmp;
3258
3259		    if ((fsec_tmp = filesec_init()) == NULL)
3260			error = -1;
3261		    else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0)
3262			error = -1;
3263		    else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0)
3264			error = -1;
3265		    else {
3266			while (fchmodx_np(s->dst_fd, fsec_tmp) < 0)
3267			{
3268			    if (errno == ENOTSUP)
3269			    {
3270				    if (retry && !copyfile_unset_acl(s))
3271				    {
3272					retry = 0;
3273					continue;
3274				    }
3275			    }
3276			    copyfile_warn("setting security information");
3277			    error = -1;
3278			    break;
3279			}
3280		    }
3281		    acl_free(acl);
3282		    filesec_free(fsec_tmp);
3283
3284acl_done:
3285		    if (error == -1)
3286			goto exit;
3287		}
3288	    }
3289	    /* And, finally, everything else */
3290	    else
3291	    {
3292		if (s->copyIntent ||
3293		    xattr_preserve_for_intent((char*)entry->name, s->copyIntent) == 1) {
3294			if (s->statuscb) {
3295				int rv;
3296				s->xattr_name = strdup((char*)entry->name);
3297				s->totalCopied = 0;
3298				rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3299				if (s->xattr_name) {
3300					free(s->xattr_name);
3301					s->xattr_name = NULL;
3302				}
3303				if (rv == COPYFILE_QUIT) {
3304					s->err = ECANCELED;
3305					error = -1;
3306					goto exit;
3307				}
3308			}
3309			if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
3310				if (COPYFILE_VERBOSE & s->flags)
3311					copyfile_warn("error %d setting attribute %s", errno, entry->name);
3312				if (s->statuscb) {
3313					int rv;
3314
3315					s->xattr_name = strdup((char*)entry->name);
3316					rv = (s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3317					if (s->xattr_name) {
3318						free(s->xattr_name);
3319						s->xattr_name = NULL;
3320					}
3321					if (rv == COPYFILE_QUIT) {
3322						error = -1;
3323						goto exit;
3324					}
3325				} else {
3326					error = -1;
3327					goto exit;
3328				}
3329			} else if (s->statuscb) {
3330				int rv;
3331				s->xattr_name = strdup((char*)entry->name);
3332				s->totalCopied = entry->length;
3333				rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3334				if (s->xattr_name) {
3335					free(s->xattr_name);
3336					s->xattr_name = NULL;
3337				}
3338				if (rv == COPYFILE_QUIT) {
3339					error = -1;
3340					s->err = ECANCELED;
3341					goto exit;
3342				}
3343			}
3344		}
3345	    }
3346	    if (dataptr) {
3347		    free(dataptr);
3348		    dataptr = NULL;
3349	    }
3350	    entry = ATTR_NEXT(entry);
3351	}
3352    }
3353
3354    /*
3355     * Extract the Finder Info.
3356     */
3357    if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) {
3358	error = -1;
3359	goto exit;
3360    }
3361
3362    if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0)
3363    {
3364	uint16_t *fFlags;
3365	uint8_t *newFinfo;
3366	enum { kFinderInvisibleMask = 1 << 14 };
3367
3368	newFinfo = (u_int8_t*)buffer + adhdr->entries[0].offset;
3369	fFlags = (uint16_t*)&newFinfo[8];
3370	copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME);
3371	if (s->statuscb) {
3372		int rv;
3373		s->xattr_name = (char*)XATTR_FINDERINFO_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			goto exit;
3380		} else if (rv == COPYFILE_SKIP) {
3381			goto skip_fi;
3382		}
3383	}
3384	error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0);
3385	if (error) {
3386		if (s->statuscb) {
3387			int rv;
3388			s->xattr_name = (char *)XATTR_FINDERINFO_NAME;
3389			rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3390			s->xattr_name = NULL;
3391			if (rv == COPYFILE_QUIT) {
3392				error = -1;
3393				s->err = ECANCELED;
3394				goto exit;
3395			}
3396		}
3397	    goto exit;
3398	} else if (s->statuscb) {
3399		int rv;
3400		s->xattr_name = (char *)XATTR_FINDERINFO_NAME;
3401		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3402		s->xattr_name = NULL;
3403		if (rv == COPYFILE_QUIT) {
3404			error = -1;
3405			s->err = ECANCELED;
3406			goto exit;
3407		}
3408	}
3409	if (SWAP16(*fFlags) & kFinderInvisibleMask)
3410		s->internal_flags |= cfMakeFileInvisible;
3411    }
3412skip_fi:
3413
3414    /*
3415     * Extract the Resource Fork.
3416     */
3417    if (adhdr->entries[1].type == AD_RESOURCE &&
3418	adhdr->entries[1].length > 0)
3419    {
3420	void * rsrcforkdata = NULL;
3421	size_t length;
3422	off_t offset;
3423	struct stat sb;
3424	struct timeval tval[2];
3425
3426	length = adhdr->entries[1].length;
3427	offset = adhdr->entries[1].offset;
3428	rsrcforkdata = malloc(length);
3429
3430	if (rsrcforkdata == NULL) {
3431		copyfile_debug(1, "could not allocate %zu bytes for rsrcforkdata",
3432			length);
3433		error = -1;
3434		goto bad;
3435	}
3436
3437	if (fstat(s->dst_fd, &sb) < 0)
3438	{
3439		copyfile_debug(1, "couldn't stat destination file");
3440		error = -1;
3441		goto bad;
3442	}
3443
3444	bytes = pread(s->src_fd, rsrcforkdata, length, offset);
3445	if (bytes < (ssize_t)length)
3446	{
3447	    if (bytes == -1)
3448	    {
3449		copyfile_debug(1, "couldn't read resource fork");
3450	    }
3451	    else
3452	    {
3453		copyfile_debug(1,
3454		    "couldn't read resource fork (only read %d bytes of %d)",
3455		    (int)bytes, (int)length);
3456	    }
3457	    error = -1;
3458	    goto bad;
3459	}
3460	if (s->statuscb) {
3461		int rv;
3462		s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
3463		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3464		s->xattr_name = NULL;
3465		if (rv == COPYFILE_QUIT) {
3466			error = -1;
3467			s->err = ECANCELED;
3468			if (rsrcforkdata)
3469				free(rsrcforkdata);
3470			goto exit;
3471		} else if (rv == COPYFILE_SKIP) {
3472			goto bad;
3473		}
3474	}
3475	error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0);
3476	if (error)
3477	{
3478	     /*
3479	      * For filesystems that do not natively support named attributes,
3480	      * the kernel creates an AppleDouble file that -- for compatabilty
3481	      * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
3482	      * structure that says there are no resources.  So, if fsetxattr has
3483	      * failed, and the resource fork is that empty structure, *and* the
3484	      * target file is a directory, then we do nothing with it.
3485	      */
3486	    if ((bytes == sizeof(rsrcfork_header_t)) &&
3487		((sb.st_mode & S_IFMT) == S_IFDIR)  &&
3488		(memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) {
3489		    copyfile_debug(2, "not setting empty resource fork on directory");
3490		    error = errno = 0;
3491		    goto bad;
3492	    }
3493	    if (s->statuscb) {
3494		int rv;
3495		s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
3496		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3497		s->xattr_name = NULL;
3498		if (rv == COPYFILE_CONTINUE) {
3499			error = errno = 0;
3500			goto bad;
3501		}
3502	    }
3503	    copyfile_debug(1, "error %d setting resource fork attribute", error);
3504	    error = -1;
3505	    goto bad;
3506	} else if (s->statuscb) {
3507		int rv;
3508		s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
3509		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3510		s->xattr_name = NULL;
3511		if (rv == COPYFILE_QUIT) {
3512			error = -1;
3513			s->err = ECANCELED;
3514			if (rsrcforkdata)
3515				free(rsrcforkdata);
3516			goto exit;
3517		}
3518	}
3519	copyfile_debug(3, "extracting \"%s\" (%d bytes)",
3520		    XATTR_RESOURCEFORK_NAME, (int)length);
3521
3522	if (!(s->flags & COPYFILE_STAT))
3523	{
3524	    tval[0].tv_sec = sb.st_atime;
3525	    tval[1].tv_sec = sb.st_mtime;
3526	    tval[0].tv_usec = tval[1].tv_usec = 0;
3527
3528	    if (futimes(s->dst_fd, tval))
3529		copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
3530	}
3531bad:
3532	if (rsrcforkdata)
3533	    free(rsrcforkdata);
3534    }
3535
3536    if (COPYFILE_STAT & s->flags)
3537    {
3538	error = copyfile_stat(s);
3539    }
3540exit:
3541    if (buffer) free(buffer);
3542    if (dataptr) free(dataptr);
3543    return error;
3544}
3545
3546static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len)
3547{
3548    int ret = 0;
3549    char qbuf[QTN_SERIALIZED_DATA_MAX];
3550    size_t qlen = sizeof(qbuf);
3551
3552    if (s->qinfo == NULL)
3553    {
3554	ret = -1;
3555	goto done;
3556    }
3557
3558    if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0)
3559    {
3560	ret = -1;
3561	goto done;
3562    }
3563
3564    *buf = malloc(qlen);
3565    if (*buf)
3566    {
3567	memcpy(*buf, qbuf, qlen);
3568	*len = qlen;
3569    }
3570done:
3571    return ret;
3572}
3573
3574static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len)
3575{
3576    int ret = 0;
3577    acl_t acl = NULL;
3578    char *acl_text;
3579
3580    if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0)
3581    {
3582	if (errno != ENOENT)
3583	{
3584	    ret = -1;
3585	    if (COPYFILE_VERBOSE & s->flags)
3586		copyfile_warn("getting acl");
3587	}
3588	*len = 0;
3589	goto exit;
3590    }
3591
3592    if ((acl_text = acl_to_text(acl, len)) != NULL)
3593    {
3594	/*
3595	 * acl_to_text() doesn't include the NUL at the endo
3596	 * in it's count (*len).  It does, however, promise to
3597	 * return a valid C string, so we need to up the count
3598	 * by 1.
3599	 */
3600	*len = *len + 1;
3601	*buf = malloc(*len);
3602	if (*buf)
3603	    memcpy(*buf, acl_text, *len);
3604	else
3605	    *len = 0;
3606	acl_free(acl_text);
3607    }
3608    copyfile_debug(2, "copied acl (%ld) %p", *len, *buf);
3609exit:
3610    if (acl)
3611	acl_free(acl);
3612    return ret;
3613}
3614
3615static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr)
3616{
3617    ssize_t datasize;
3618    char *databuf = NULL;
3619    int ret = 0;
3620
3621/*
3622 * XXX
3623 * do COPYFILE_COPY_XATTR here; no need to
3624 * the work if we want to skip.
3625 */
3626
3627    if (s->statuscb)
3628    {
3629	int rv;
3630
3631	s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME;
3632
3633	rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3634	s->xattr_name = NULL;
3635	if (rv == COPYFILE_SKIP) {
3636		ret = 0;
3637		goto done;
3638	}
3639	if (rv == COPYFILE_QUIT) {
3640		ret = -1;
3641		s->err = ECANCELED;
3642		goto done;
3643	}
3644    }
3645    /* Get the resource fork size */
3646    if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0)
3647    {
3648	if (COPYFILE_VERBOSE & s->flags)
3649	    copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno);
3650	return -1;
3651    }
3652
3653    if (datasize > INT_MAX) {
3654	s->err = EINVAL;
3655	ret = -1;
3656	goto done;
3657    }
3658
3659    if (s->statuscb) {
3660	int rv;
3661	s->xattr_name = (char*)XATTR_RESOURCEFORK_NAME;
3662
3663	s->totalCopied = 0;
3664	rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
3665	s->xattr_name = NULL;
3666	if (rv == COPYFILE_QUIT) {
3667		s->err = ECANCELED;
3668		ret = -1;
3669		goto done;
3670	}
3671    }
3672    if ((databuf = malloc(datasize)) == NULL)
3673    {
3674	copyfile_warn("malloc");
3675	ret = -1;
3676	goto done;
3677    }
3678
3679    if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize)
3680    {
3681	if (COPYFILE_VERBOSE & s->flags)
3682	    copyfile_warn("couldn't read entire resource fork");
3683	ret = -1;
3684	goto done;
3685    }
3686
3687    /* Write the resource fork to disk. */
3688    if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize)
3689    {
3690	if (COPYFILE_VERBOSE & s->flags)
3691	    copyfile_warn("couldn't write resource fork");
3692    }
3693    if (s->statuscb)
3694    {
3695	int rv;
3696	rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3697	if (rv == COPYFILE_QUIT) {
3698	    ret = -1;
3699	    goto done;
3700	}
3701    }
3702    copyfile_debug(3, "copied %zd bytes of \"%s\" data @ offset 0x%08x",
3703	datasize, XATTR_RESOURCEFORK_NAME, filehdr->appledouble.entries[1].offset);
3704    filehdr->appledouble.entries[1].length = (u_int32_t)datasize;
3705
3706done:
3707    if (ret == -1 && s->statuscb)
3708    {
3709	int rv;
3710	rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3711	if (rv == COPYFILE_CONTINUE)
3712	    ret = 0;
3713    }
3714    if (s->xattr_name) {
3715	s->xattr_name = NULL;
3716    }
3717    if (databuf)
3718	free(databuf);
3719
3720/*
3721 * XXX
3722 * Do status callback here
3723 * If ret == -1, then error callback
3724 */
3725    return ret;
3726}
3727
3728/*
3729 * The opposite of copyfile_unpack(), obviously.
3730 */
3731static int copyfile_pack(copyfile_state_t s)
3732{
3733    char *attrnamebuf = NULL, *endnamebuf;
3734    void *databuf = NULL;
3735    attr_header_t *filehdr, *endfilehdr;
3736    attr_entry_t *entry;
3737    ssize_t listsize = 0;
3738    char *nameptr;
3739    size_t namelen;
3740    size_t entrylen;
3741    ssize_t datasize;
3742    size_t offset = 0;
3743    int hasrsrcfork = 0;
3744    int error = 0;
3745    int seenq = 0;	// Have we seen any quarantine info already?
3746
3747    filehdr = (attr_header_t *) calloc(1, ATTR_MAX_HDR_SIZE);
3748
3749    if (filehdr == NULL) {
3750	error = -1;
3751	goto exit;
3752    } else {
3753	    endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_HDR_SIZE);
3754    }
3755
3756    attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
3757    if (attrnamebuf == NULL) {
3758	error = -1;
3759	goto exit;
3760    } else {
3761	endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE;
3762    }
3763
3764    /*
3765     * Fill in the Apple Double Header defaults.
3766     */
3767    filehdr->appledouble.magic              = ADH_MAGIC;
3768    filehdr->appledouble.version            = ADH_VERSION;
3769    filehdr->appledouble.numEntries         = 2;
3770    filehdr->appledouble.entries[0].type    = AD_FINDERINFO;
3771    filehdr->appledouble.entries[0].offset  = (u_int32_t)offsetof(apple_double_header_t, finfo);
3772    filehdr->appledouble.entries[0].length  = FINDERINFOSIZE;
3773    filehdr->appledouble.entries[1].type    = AD_RESOURCE;
3774    filehdr->appledouble.entries[1].offset  = (u_int32_t)offsetof(apple_double_header_t, pad);
3775    filehdr->appledouble.entries[1].length  = 0;
3776    bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler));
3777
3778    /*
3779     * Fill in the initial Attribute Header.
3780     */
3781    filehdr->magic       = ATTR_HDR_MAGIC;
3782    filehdr->debug_tag   = 0;
3783    filehdr->data_start  = (u_int32_t)sizeof(attr_header_t);
3784
3785    /*
3786     * Collect the attribute names.
3787     */
3788    entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3789
3790    /*
3791     * Test if there are acls to copy
3792     */
3793    if (COPYFILE_ACL & s->flags)
3794    {
3795	acl_t temp_acl = NULL;
3796	if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0)
3797	{
3798	    copyfile_debug(2, "no acl entries found (errno = %d)", errno);
3799	} else
3800	{
3801	    offset = strlen(XATTR_SECURITY_NAME) + 1;
3802	    strcpy(attrnamebuf, XATTR_SECURITY_NAME);
3803	    endnamebuf = attrnamebuf + offset;
3804	}
3805	if (temp_acl)
3806	    acl_free(temp_acl);
3807    }
3808
3809    if (COPYFILE_XATTR & s->flags)
3810    {
3811	ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3812        if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0)
3813	{
3814	    copyfile_debug(2, "no extended attributes found (%d)", errno);
3815	}
3816	if (listsize > left)
3817	{
3818	    copyfile_debug(1, "extended attribute list too long");
3819	    listsize = left;
3820	}
3821
3822	endnamebuf = attrnamebuf + offset + (listsize > 0 ? listsize : 0);
3823	if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) {
3824		error = -1;
3825		goto exit;
3826	}
3827
3828	if (listsize > 0)
3829		sort_xattrname_list(attrnamebuf, endnamebuf - attrnamebuf);
3830
3831	for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen)
3832	{
3833	    namelen = strlen(nameptr) + 1;
3834	    /* Skip over FinderInfo or Resource Fork names */
3835	    if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 ||
3836		strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) {
3837		    continue;
3838	    }
3839	    if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) {
3840		seenq = 1;
3841	    }
3842
3843	    /* The system should prevent this from happening, but... */
3844	    if (namelen > XATTR_MAXNAMELEN + 1) {
3845		namelen = XATTR_MAXNAMELEN + 1;
3846	    }
3847	    if (s->copyIntent &&
3848		xattr_preserve_for_intent(nameptr, s->copyIntent) == 0) {
3849		    // Skip it
3850		    size_t amt = endnamebuf - (nameptr + namelen);
3851		    memmove(nameptr, nameptr + namelen, amt);
3852		    endnamebuf -= namelen;
3853		    /* Set namelen to 0 so continue doesn't miss names */
3854		    namelen = 0;
3855		    continue;
3856	    }
3857
3858	    if (s->statuscb) {
3859		int rv;
3860		char eaname[namelen];
3861		bcopy(nameptr, eaname, namelen);
3862		eaname[namelen - 1] = 0; // Just to be sure!
3863		s->xattr_name = eaname;
3864		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3865		s->xattr_name = NULL;
3866		if (rv == COPYFILE_QUIT) {
3867			error = -1;
3868			s->err = ECANCELED;
3869			goto exit;
3870		} else if (rv == COPYFILE_SKIP) {
3871			size_t amt = endnamebuf - (nameptr + namelen);
3872			memmove(nameptr, nameptr + namelen, amt);
3873			endnamebuf -= namelen;
3874			/* Set namelen to 0 so continue doesn't miss names */
3875			namelen = 0;
3876			continue;
3877		}
3878	    }
3879	    entry->namelen = namelen;
3880	    entry->flags = 0;
3881	    if (nameptr + namelen > endnamebuf) {
3882		error = -1;
3883		goto exit;
3884	    }
3885
3886	    bcopy(nameptr, &entry->name[0], namelen);
3887	    copyfile_debug(2, "copied name [%s]", entry->name);
3888
3889	    entrylen = ATTR_ENTRY_LENGTH(namelen);
3890	    entry = (attr_entry_t *)(((char *)entry) + entrylen);
3891
3892	    if ((void*)entry >= (void*)endfilehdr) {
3893		    error = -1;
3894		    goto exit;
3895	    }
3896
3897	    /* Update the attributes header. */
3898	    filehdr->num_attrs++;
3899	    filehdr->data_start += (u_int32_t)entrylen;
3900	}
3901    }
3902
3903    /*
3904     * If we have any quarantine data, we always pack it.
3905     * But if we've already got it in the EA list, don't put it in again.
3906     */
3907    if (s->qinfo && !seenq)
3908    {
3909	ssize_t left = ATTR_MAX_HDR_SIZE - offset;
3910	/* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
3911	offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1;
3912    }
3913
3914    seenq = 0;
3915    /*
3916     * Collect the attribute data.
3917     */
3918    entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
3919
3920    for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen + 1)
3921    {
3922	namelen = strlen(nameptr);
3923
3924	if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0)
3925	    copyfile_pack_acl(s, &databuf, &datasize);
3926	else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0)
3927	{
3928	    copyfile_pack_quarantine(s, &databuf, &datasize);
3929	}
3930	/* Check for Finder Info. */
3931	else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0)
3932	{
3933	    if (s->statuscb)
3934	    {
3935		int rv;
3936		s->xattr_name = (char*)XATTR_FINDERINFO_NAME;
3937		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
3938		s->xattr_name = NULL;
3939		if (rv == COPYFILE_QUIT)
3940		{
3941		    s->xattr_name = NULL;
3942		    s->err = ECANCELED;
3943		    error = -1;
3944		    goto exit;
3945		}
3946		else if (rv == COPYFILE_SKIP)
3947		{
3948		    s->xattr_name = NULL;
3949		    continue;
3950		}
3951		s->totalCopied = 0;
3952		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
3953		s->xattr_name = NULL;
3954		if (rv == COPYFILE_QUIT)
3955		{
3956		    s->err = ECANCELED;
3957		    error = -1;
3958		    goto exit;
3959		}
3960	    }
3961	    datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0);
3962	    if (datasize < 0)
3963	    {
3964		    if (s->statuscb) {
3965			int rv;
3966			s->xattr_name = strdup(nameptr);
3967			rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
3968			if (s->xattr_name) {
3969				free(s->xattr_name);
3970				s->xattr_name = NULL;
3971			}
3972			if (rv == COPYFILE_QUIT) {
3973				error = -1;
3974				goto exit;
3975			}
3976		    }
3977		    if (COPYFILE_VERBOSE & s->flags)
3978			copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
3979	    } else if (datasize != 32)
3980	    {
3981		    if (COPYFILE_VERBOSE & s->flags)
3982			copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr);
3983	    } else
3984	    {
3985		    if (COPYFILE_VERBOSE & s->flags)
3986			copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
3987			    XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset);
3988		    if (s->statuscb) {
3989			int rv;
3990			s->xattr_name = strdup(nameptr);
3991			rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
3992			if (s->xattr_name) {
3993				free(s->xattr_name);
3994				s->xattr_name = NULL;
3995			}
3996			if (rv == COPYFILE_QUIT) {
3997				error = -1;
3998				goto exit;
3999			}
4000		    }
4001	    }
4002	    continue;  /* finder info doesn't have an attribute entry */
4003	}
4004	/* Check for Resource Fork. */
4005	else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0)
4006	{
4007	    hasrsrcfork = 1;
4008	    continue;
4009	} else
4010	{
4011	    /* Just a normal attribute. */
4012	    if (s->statuscb)
4013	    {
4014		int rv;
4015		s->xattr_name = strdup(nameptr);
4016		s->totalCopied = 0;
4017		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_PROGRESS, s, s->src, s->dst, s->ctx);
4018		if (s->xattr_name) {
4019			free(s->xattr_name);
4020			s->xattr_name = NULL;
4021		}
4022		/*
4023		 * Due to the nature of the packed file, we can't skip at this point.
4024		 */
4025		if (rv == COPYFILE_QUIT)
4026		{
4027		    s->err = ECANCELED;
4028		    error = -1;
4029		    goto exit;
4030		}
4031	    }
4032	    datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0);
4033	    if (datasize == 0)
4034		goto next;
4035	    if (datasize < 0)
4036	    {
4037		if (COPYFILE_VERBOSE & s->flags)
4038		    copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
4039		if (s->statuscb)
4040		{
4041		    int rv;
4042		    s->xattr_name = strdup(nameptr);
4043		    rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
4044		    if (s->xattr_name) {
4045			free(s->xattr_name);
4046			s->xattr_name = NULL;
4047		    }
4048		    if (rv == COPYFILE_QUIT)
4049		    {
4050			s->err = ECANCELED;
4051			error = -1;
4052			goto exit;
4053		    }
4054		}
4055		goto next;
4056	    }
4057	    if (datasize > XATTR_MAXATTRLEN)
4058	    {
4059		if (COPYFILE_VERBOSE & s->flags)
4060		    copyfile_warn("skipping attr \"%s\" (too big)", nameptr);
4061		goto next;
4062	    }
4063	    databuf = malloc(datasize);
4064	    if (databuf == NULL) {
4065		error = -1;
4066		continue;
4067	    }
4068	    datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0);
4069	    if (s->statuscb) {
4070		int rv;
4071		s->xattr_name = strdup(nameptr);
4072		rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
4073		if (s->xattr_name) {
4074			free(s->xattr_name);
4075			s->xattr_name = NULL;
4076		}
4077		if (rv == COPYFILE_QUIT) {
4078			s->err = ECANCELED;
4079			error = -1;
4080			goto exit;
4081		}
4082	    }
4083	}
4084
4085	entry->length = (u_int32_t)datasize;
4086	entry->offset = filehdr->data_start + filehdr->data_length;
4087
4088	filehdr->data_length += (u_int32_t)datasize;
4089#if 0
4090	/*
4091	 * >>>  WARNING <<<
4092	 * This assumes that the data is fits in memory (not
4093	 * the case when there are lots of attributes or one of
4094	 * the attributes is very large.
4095	 */
4096	if (entry->offset > ATTR_MAX_SIZE ||
4097		(entry->offset + datasize > ATTR_MAX_SIZE)) {
4098		error = 1;
4099	} else {
4100		bcopy(databuf, (char*)filehdr + entry->offset, datasize);
4101	}
4102#else
4103	if (pwrite(s->dst_fd, databuf, datasize, entry->offset) != datasize) {
4104		error = 1;
4105	}
4106#endif
4107	free(databuf);
4108
4109	copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
4110next:
4111	/* bump to next entry */
4112	entrylen = ATTR_ENTRY_LENGTH(entry->namelen);
4113	entry = (attr_entry_t *)((char *)entry + entrylen);
4114    }
4115
4116    /* Now we know where the resource fork data starts. */
4117    filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
4118
4119    /* We also know the size of the "Finder Info entry. */
4120    filehdr->appledouble.entries[0].length =
4121	    filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
4122
4123    filehdr->total_size  = filehdr->appledouble.entries[1].offset;
4124
4125    /* Copy Resource Fork. */
4126    if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
4127	goto exit;
4128
4129    /* Write the header to disk. */
4130    datasize = filehdr->data_start;
4131
4132    swap_adhdr(&filehdr->appledouble);
4133    swap_attrhdr(filehdr);
4134    swap_attrhdr_entries(filehdr);
4135
4136    if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize)
4137    {
4138	if (COPYFILE_VERBOSE & s->flags)
4139	    copyfile_warn("couldn't write file header");
4140	error = -1;
4141	goto exit;
4142    }
4143exit:
4144    if (filehdr) free(filehdr);
4145    if (attrnamebuf) free(attrnamebuf);
4146
4147    if (error)
4148	return error;
4149    else
4150	return copyfile_stat(s);
4151}
4152