<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.

</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/f58be6f0860560e8bea22d99ff53761c15a6f306">https://github.com/macports/macports-legacy-support/commit/f58be6f0860560e8bea22d99ff53761c15a6f306</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit f58be6f0860560e8bea22d99ff53761c15a6f306
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Fri Dec 27 16:38:58 2024 -0800

<span style='display:block; white-space:pre;color:#404040;'>    Replace copyfile wrapper with 10.6 copyfile.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    After applying many fixes to the old copyfile wrapper, it was still
</span><span style='display:block; white-space:pre;color:#404040;'>    hopeless on 10.4 due to a fatal internal bug in Apple's code.  This
</span><span style='display:block; white-space:pre;color:#404040;'>    change throws all that out and imports the entire copyfile
</span><span style='display:block; white-space:pre;color:#404040;'>    implementation from 10.6.  This should provide the full 10.6 copyfile
</span><span style='display:block; white-space:pre;color:#404040;'>    on 10.5, and a mostly full implementation on 10.4, after additional
</span><span style='display:block; white-space:pre;color:#404040;'>    10.4 fixes in the next commit.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    This retains the feature of Apple's copyfile that allows it to be
</span><span style='display:block; white-space:pre;color:#404040;'>    built as a standalone program for easier testing.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'>    Builds and passes the test on 10.5+.
</span><span style='display:block; white-space:pre;color:#404040;'>    Doesn't yet build on 10.4 (fixed in subsequent commit).
</span>---
 include/MacportsLegacySupport.h |    4 +-
 include/copyfile.h              |    4 +-
 src/.gitignore                  |    7 +
 src/Makefile                    |    4 +
 src/add_symbols.c               |    2 +-
 src/copyfile.c                  | 3446 ++++++++++++++++++++++++++++++++++++++-
 src/quarantine.h                |   70 +
 7 files changed, 3477 insertions(+), 60 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/MacportsLegacySupport.h b/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;color:#808080;'>index 89b85fc..4539c28 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -337,8 +337,8 @@
</span> /* copyfile and its associated functions have gained functionality over the years */
 #define __MPLS_SDK_SUPPORT_COPYFILE_TIGER__ (__MPLS_SDK_MAJOR < 1050)
 #define __MPLS_LIB_SUPPORT_COPYFILE_TIGER__ (__MPLS_TARGET_OSVER < 1050)
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#define __MPLS_SDK_SUPPORT_COPYFILE_WRAP__  (__MPLS_SDK_MAJOR < 1060)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#define __MPLS_LIB_SUPPORT_COPYFILE_WRAP__  (__MPLS_TARGET_OSVER < 1060)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MPLS_SDK_SUPPORT_COPYFILE_10_6__  (__MPLS_SDK_MAJOR < 1060)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MPLS_LIB_SUPPORT_COPYFILE_10_6__  (__MPLS_TARGET_OSVER < 1060)
</span> 
 /* _tlv_atexit and __cxa_thread_atexit */
 #define __MPLS_LIB_SUPPORT_ATEXIT_WRAP__   (__MPLS_TARGET_OSVER < 1070)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/copyfile.h b/include/copyfile.h
</span><span style='display:block; white-space:pre;color:#808080;'>index ece1126..07e0eed 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/copyfile.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/copyfile.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -58,7 +58,7 @@ __MP__END_DECLS
</span> 
 #endif /* !__MPLS_SDK_SUPPORT_COPYFILE_TIGER__ */
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#if __MPLS_SDK_SUPPORT_COPYFILE_WRAP__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MPLS_SDK_SUPPORT_COPYFILE_10_6__
</span> 
 /* Additional defs from the 10.6 copyfile.h */
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -85,6 +85,6 @@ typedef int (*copyfile_callback_t)(int, int, copyfile_state_t, const char *, con
</span> #define   COPYFILE_SKIP   1
 #define        COPYFILE_QUIT   2
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#endif /* __MPLS_SDK_SUPPORT_COPYFILE_WRAP__ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MPLS_SDK_SUPPORT_COPYFILE_10_6__ */
</span> 
 #endif /* _MACPORTS_COPYFILE_H_ */
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/.gitignore b/src/.gitignore
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..62cc70a
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/.gitignore
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!.gitignore
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.cc
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!*.xxc
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+!Makefile
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/Makefile b/src/Makefile
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..a4978c4
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/Makefile
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,4 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# Simple Makefile for building copyfile as standalone program.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+copyfile: copyfile.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   cc -D_COPYFILE_TEST -I../include $^ -o $@
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/add_symbols.c b/src/add_symbols.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 7f132fe..1dac4b6 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/add_symbols.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/add_symbols.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -25,7 +25,7 @@ extern const char pthread_setname_np_tmp4 __asm("$ld$add$os10.4$_pthread_setname
</span> extern const char pthread_setname_np_tmp5 __asm("$ld$add$os10.5$_pthread_setname_np"); __attribute__((visibility("default"))) const char pthread_setname_np_tmp5 = 0;
 #endif
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#if !(__MPLS_LIB_SUPPORT_COPYFILE_WRAP__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if !(__MPLS_LIB_SUPPORT_COPYFILE_10_6__)
</span> /* extern const char copyfile_state_get_tmp4 __asm("$ld$add$os10.4$_copyfile_state_get"); __attribute__((visibility("default"))) const char copyfile_state_get_tmp4 = 0; */
 extern const char copyfile_state_get_tmp5 __asm("$ld$add$os10.5$_copyfile_state_get"); __attribute__((visibility("default"))) const char copyfile_state_get_tmp5 = 0;
 #endif
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/copyfile.c b/src/copyfile.c
</span><span style='display:block; white-space:pre;color:#808080;'>index ef978ea..ceadd9b 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/src/copyfile.c
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/copyfile.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,78 +1,3414 @@
</span> /*
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * Copyright (c) 2022
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
</span>  *
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_START@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This file contains Original Code and/or Modifications of Original Code
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * as defined in and that are subject to the Apple Public Source License
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Version 2.0 (the 'License'). You may not use this file except in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * compliance with the License. Please obtain a copy of the License at
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * http://www.opensource.apple.com/apsl/ and read it before using this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The Original Code and all software distributed under the License are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Please see the License for the specific language governing rights and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * limitations under the License.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_END@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * NOTICE: This file was modified in December 2024 to allow
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * for use as a supporting file for MacPorts legacy support library.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This notice is included in support of clause 2.2 (b) of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Apple Public License, Version 2.0.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The original file is taken from the Apple public sources at:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * https://github.com/apple-oss-distributions/copyfile/blob/copyfile-66.1/copyfile.c
</span>  *
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Changes include:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   Using the system copyfile.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   Removing TARGET_OS_EMBEDDED support
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   Adding the legacy-support include and conditional
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   Changing to a private quarantine.h, due to absence of a public version
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   Fixing format warnings in debug messages
</span>  */
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * With _COPYFILE_TEST (Apple feature), it builds as a standalone program
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * for testing.  The legacy-support headers are optional in this case,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * provided that the SDK is 10.6+.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifndef _COPYFILE_TEST
</span> /* MP support header */
 #include "MacportsLegacySupport.h"
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-/* copyfile and its associated functions wrap */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#if __MPLS_LIB_SUPPORT_COPYFILE_WRAP__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if defined(_COPYFILE_TEST) || __MPLS_LIB_SUPPORT_COPYFILE_10_6__
</span> 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <err.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/types.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/acl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span> #include <stdlib.h>
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#include <dlfcn.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdint.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <syslog.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/errno.h>
</span> #include <sys/stat.h>
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/xattr.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/syscall.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/param.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/mount.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/acl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <libkern/OSByteOrder.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <membership.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fts.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <libgen.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "quarantine.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define    XATTR_QUARANTINE_NAME qtn_xattr_name
</span> 
 #include <copyfile.h>
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-int copyfile_state_get(copyfile_state_t s, uint32_t flag, void * dst)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+enum cfInternalFlags {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   cfDelayAce = 1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The state structure keeps track of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the source filename, the destination filename, their
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * associated file-descriptors, the stat infomration for the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * source file, the security information for the source file,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the flags passed in for the copy, a pointer to place statistics
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * (not currently implemented), debug flags, and a pointer to callbacks
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * (not currently implemented).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+struct _copyfile_state
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *src;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *dst;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int src_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int dst_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct stat sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_t fsec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_flags_t flags;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    unsigned int   internal_flags;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    void *stats;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    uint32_t debug;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_callback_t    statuscb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    void   *ctx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    qtn_file_t qinfo;      /* Quarantine information -- probably NULL */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_t original_fsec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_t permissive_fsec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    off_t totalCopied;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+struct acl_entry {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        u_int32_t       ae_magic;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define _ACL_ENTRY_MAGIC        0xac1ac101
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        u_int32_t       ae_tag;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        guid_t          ae_applicable;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        u_int32_t       ae_flags;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        u_int32_t       ae_perms;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define PACE(ace)  do { \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct acl_entry *__t = (struct acl_entry*)(ace); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fprintf(stderr, "%s(%d): " #ace " = { flags = %#x, perms = %#x }\n", __FUNCTION__, __LINE__, __t->ae_flags, __t->ae_perms); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define PACL(ace) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do { \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ssize_t __l; char *__cp = acl_to_text(ace, &__l); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fprintf(stderr, "%s(%d):  " #ace " = %s\n", __FUNCTION__, __LINE__, __cp ? __cp : "(null)"); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+acl_compare_permset_np(acl_permset_t p1, acl_permset_t p2)
</span> {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    int (*real_copyfile_state_get)(copyfile_state_t s, uint32_t flag, void * dst);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    int ret;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    char *file_name;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    int file_descriptor;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    struct stat file_stat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct pm { u_int32_t ap_perms; } *ps1, *ps2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ps1 = (struct pm*) p1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ps2 = (struct pm*) p2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ((ps1->ap_perms == ps2->ap_perms) ? 1 : 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Internally, the process is broken into a series of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * private functions.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_open   (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_close  (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_data   (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_stat   (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_security       (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_xattr  (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_pack   (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_unpack (copyfile_state_t);
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    real_copyfile_state_get = dlsym(RTLD_NEXT, "copyfile_state_get");
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    if (real_copyfile_state_get == NULL) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        exit(EXIT_FAILURE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static copyfile_flags_t copyfile_check     (copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static filesec_t copyfile_fix_perms(copyfile_state_t, filesec_t *);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_preamble(copyfile_state_t *s, copyfile_flags_t flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_internal(copyfile_state_t state, copyfile_flags_t flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_unset_posix_fsec(filesec_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_quarantine(copyfile_state_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define COPYFILE_DEBUG (1<<31)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define COPYFILE_DEBUG_VAR "COPYFILE_DEBUG"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifndef _COPYFILE_TEST
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# define copyfile_warn(str, ...) syslog(LOG_WARNING, str ": %m", ## __VA_ARGS__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# define copyfile_debug(d, str, ...) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do { \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s && (d <= s->debug)) {\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   syslog(LOG_DEBUG, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define copyfile_warn(str, ...) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    fprintf(stderr, "%s:%d:%s() " str ": %s\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__, (errno) ? strerror(errno) : "")
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# define copyfile_debug(d, str, ...) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    do { \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s && (d <= s->debug)) {\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fprintf(stderr, "%s:%d:%s() " str "\n", __FILE__, __LINE__ , __FUNCTION__, ## __VA_ARGS__); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } while(0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_quarantine(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int rv = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->qinfo == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int error;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->qinfo = qtn_file_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->qinfo == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       rv = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((error = qtn_file_init_with_fd(s->qinfo, s->src_fd)) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       qtn_file_free(s->qinfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       s->qinfo = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       rv = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span>     }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+done:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return rv;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    switch(flag)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+add_uberace(acl_t *acl)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_entry_t entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_permset_t permset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   uuid_t qual;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (mbr_uid_to_uuid(getuid(), qual) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * First, we create an entry, and give it the special name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * After that, we clear out all the permissions in it, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * add three permissions:  WRITE_DATA, WRITE_ATTRIBUTES, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * WRITE_EXTATTRIBUTES.  We put these into an ACE that allows
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * the functionality, and put this into the ACL.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_create_entry_np(acl, &entry, ACL_FIRST_ENTRY) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_get_permset(entry, &permset) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_clear_perms(permset) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_WRITE_DATA) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_APPEND_DATA) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_WRITE_SECURITY) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if(acl_set_permset(entry, permset) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if(acl_set_qualifier(entry, qual) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+error_exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+is_uberace(acl_entry_t ace)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int retval = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_permset_t perms, tperms;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_t tacl;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_entry_t tentry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_tag_t tag;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   guid_t *qual;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   uuid_t myuuid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // Who am I, and who is the ACE for?
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   mbr_uid_to_uuid(geteuid(), myuuid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   qual = (guid_t*)acl_get_qualifier(ace);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // Need to create a temporary acl, so I can get the uberace template.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   tacl = acl_init(1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (tacl == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   add_uberace(&tacl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_get_entry(tacl, ACL_FIRST_ENTRY, &tentry) != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_get_permset(tentry, &tperms);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // Now I need to get
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_get_tag_type(ace, &tag);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_get_permset(ace, &perms);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (tag == ACL_EXTENDED_ALLOW &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (memcmp(qual, myuuid, sizeof(myuuid)) == 0) &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_compare_permset_np(tperms, perms))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+done:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (tacl)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_free(tacl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return retval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+remove_uberace(int fd, struct stat *sbuf)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filesec_t fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_t acl = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_entry_t entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct stat sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fsec = filesec_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fsec == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto noacl;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fstatx_np(fd, &sb, fsec) != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (errno == ENOTSUP)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto noacl;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (filesec_get_property(fsec, FILESEC_ACL, &acl) != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_get_entry(acl, ACL_FIRST_ENTRY, &entry) == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (is_uberace(entry))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   mode_t m = sbuf->st_mode & ~S_IFMT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (acl_delete_entry(acl, entry) != 0 ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           filesec_set_property(fsec, FILESEC_ACL, &acl) != 0 ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           filesec_set_property(fsec, FILESEC_MODE, &m) != 0 ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           fchmodx_np(fd, fsec) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           goto noacl;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+done:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_free(acl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           filesec_free(fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+noacl:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fchmod(fd, sbuf->st_mode & ~S_IFMT);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+reset_security(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* If we haven't reset the file security information
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * (COPYFILE_SECURITY is not set in flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * restore back the permissions the file had originally
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * One of the reasons this seems so complicated is that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * it is partially at odds with copyfile_security().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Simplisticly, we are simply trying to make sure we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * only copy what was requested, and that we don't stomp
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * on what wasn't requested.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef COPYFILE_RECURSIVE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->dst_fd > -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct stat sbuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (s->src_fd > -1 && (s->flags & COPYFILE_STAT))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   fstat(s->src_fd, &sbuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   fstat(s->dst_fd, &sbuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!(s->internal_flags & cfDelayAce))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   remove_uberace(s->dst_fd, &sbuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->permissive_fsec && (s->flags & COPYFILE_SECURITY) != COPYFILE_SECURITY) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->flags & COPYFILE_ACL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /* Just need to reset the BSD information -- mode, owner, group */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (void)fchown(s->dst_fd, s->dst_sb.st_uid, s->dst_sb.st_gid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (void)fchmod(s->dst_fd, s->dst_sb.st_mode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * flags is either COPYFILE_STAT, or neither; if it's
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * neither, then we restore both ACL and POSIX permissions;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * if it's STAT, however, then we only want to restore the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * ACL (which may be empty).  We do that by removing the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * POSIX information from the filesec object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (s->flags & COPYFILE_STAT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_unset_posix_fsec(s->original_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (fchmodx_np(s->dst_fd, s->original_fsec) < 0 && errno != ENOTSUP)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("restoring security information");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->permissive_fsec) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filesec_free(s->permissive_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->permissive_fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->original_fsec) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filesec_free(s->original_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->original_fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copytree -- recursively copy a hierarchy.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Unlike normal copyfile(), copytree() can copy an entire hierarchy.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Care is taken to keep the ACLs set up correctly, in addition to the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * normal copying that is done.  (When copying a hierarchy, we can't
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * get rid of the "allow-all-writes" ACE on a directory until we're done
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copying the *contents* of the directory.)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The other big difference from copyfile (for the moment) is that copytree()
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * will use a call-back function to pass along information about what is
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * about to be copied, and whether or not it succeeded.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copytree() is called from copyfile() -- but copytree() itself then calls
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyfile() to copy each individual object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * XXX - no effort is made to handle overlapping hierarchies at the moment.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+copytree(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *slash;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int retval = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int (*sfunc)(const char *, struct stat *);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_callback_t status = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char srcisdir = 0, dstisdir = 0, dstexists = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct stat sbuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *src, *dst;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   const char *dstpathsep = "";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef NOTYET
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char srcpath[PATH_MAX * 2 + 1], dstpath[PATH_MAX * 2 + 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *srcroot;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   FTS *fts = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   FTSENT *ftsent;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ssize_t offset = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   const char *paths[2] =  { 0 };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unsigned int flags = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int fts_flags = FTS_NOCHDIR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->flags & (COPYFILE_MOVE | COPYFILE_UNLINK | COPYFILE_CHECK | COPYFILE_PACK | COPYFILE_UNPACK)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   flags = s->flags & (COPYFILE_ALL | COPYFILE_NOFOLLOW | COPYFILE_VERBOSE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   paths[0] = src = s->src;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   dst = s->dst;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (src == NULL || dst == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   sfunc = (flags & COPYFILE_NOFOLLOW_SRC) ? lstat : stat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((sfunc)(src, &sbuf) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (sbuf.st_mode & S_IFDIR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           srcisdir = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   sfunc = (flags & COPYFILE_NOFOLLOW_DST) ? lstat : stat;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((sfunc)(dst, &sbuf) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (errno != ENOENT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           dstexists = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if ((sbuf.st_mode & S_IFMT) == S_IFDIR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   dstisdir = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef NOTYET
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // This doesn't handle filesystem crossing and case sensitivity
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // So there's got to be a better way
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (realpath(src, srcpath) == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (realpath(dst, dstpath) == NULL &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (errno == ENOENT && realpath(dirname(dst), dstpath) == NULL)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (strstr(srcpath, dstpath) != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   srcroot = basename((char*)src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (srcroot == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * To work on as well:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * We have a few cases when copying a hierarchy:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * 1)  src is a non-directory, dst is a directory;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * 2)  src is a non-directory, dst is a non-directory;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * 3)  src is a non-directory, dst does not exist;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * 4)  src is a directory, dst is a directory;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * 5)  src is a directory, dst is a non-directory;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * 6)  src is a directory, dst does not exist
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * (1) copies src to dst/basename(src).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * (2) fails if COPYFILE_EXCLUSIVE is set, otherwise copies src to dst.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * (3) and (6) copy src to the name dst.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * (4) copies the contents of src to the contents of dst.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * (5) is an error.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (dstisdir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // copy /path/to/src to /path/to/dst/src
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // Append "/" and (fts_path - strlen(basename(src))) to dst?
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           dstpathsep = "/";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           slash = strrchr(src, '/');
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (slash == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   offset = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   offset = slash - src + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // copy /path/to/src to /path/to/dst
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           // append (fts_path + strlen(src)) to dst?
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           dstpathsep = "";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           offset = strlen(src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->flags | COPYFILE_NOFOLLOW_SRC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fts_flags |= FTS_PHYSICAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fts_flags |= FTS_LOGICAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fts = fts_open((char * const *)paths, fts_flags, NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   status = s->statuscb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   while ((ftsent = fts_read(fts)) != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int rv = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           char *dstfile = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int cmd = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_state_t tstate = copyfile_state_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (tstate == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   errno = ENOMEM;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           tstate->statuscb = s->statuscb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           tstate->ctx = s->ctx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           asprintf(&dstfile, "%s%s%s", dst, dstpathsep, ftsent->fts_path + offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (dstfile == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_state_free(tstate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   errno = ENOMEM;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           switch (ftsent->fts_info) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_D:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   tstate->internal_flags |= cfDelayAce;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   cmd = COPYFILE_RECURSE_DIR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_SL:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_SLNONE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_DEFAULT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_F:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   cmd = COPYFILE_RECURSE_FILE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_DP:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   cmd = COPYFILE_RECURSE_DIR_CLEANUP;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_DNR:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_ERR:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_NS:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_NSOK:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   errno = ftsent->fts_errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           rv = (*status)(COPYFILE_RECURSE_ERROR, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto skipit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case FTS_DOT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto skipit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (cmd == COPYFILE_RECURSE_DIR || cmd == COPYFILE_RECURSE_FILE) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_SKIP) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   if (cmd == COPYFILE_RECURSE_DIR) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           rv = fts_set(fts, ftsent, FTS_SKIP);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           if (rv == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                   rv = (*status)(0, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                   if (rv == COPYFILE_QUIT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto skipit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   retval = -1; errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   rv = copyfile(ftsent->fts_path, dstfile, tstate, flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (rv < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   rv = (*status)(cmd, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           rv = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto skipit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           rv = (*status)(cmd, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   retval = -1; errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else if (cmd == COPYFILE_RECURSE_DIR_CLEANUP) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   int tfd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           rv = (*status)(cmd, COPYFILE_START, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   retval = -1; errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           } else if (rv == COPYFILE_SKIP) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   rv = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto skipit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   tfd = open(dstfile,  O_RDONLY);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (tfd != -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           struct stat sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (s->flags & COPYFILE_STAT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   (s->flags & COPYFILE_NOFOLLOW_SRC ? lstat : stat)(ftsent->fts_path, &sb);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   (s->flags & COPYFILE_NOFOLLOW_DST ? lstat : stat)(dstfile, &sb);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           remove_uberace(tfd, &sb);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           close(tfd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_FINISH, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           rv = -1; errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   rv = (*status)(COPYFILE_RECURSE_DIR_CLEANUP, COPYFILE_ERR, tstate, ftsent->fts_path, dstfile, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   } else if (rv == COPYFILE_SKIP || rv == COPYFILE_CONTINUE) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           if (rv == COPYFILE_CONTINUE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                   errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           retval = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                           goto skipit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   retval = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto stopit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   rv = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+skipit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+stopit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_state_free(tstate);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(dstfile);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (retval == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+done:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fts)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fts_close(fts);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return retval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * fcopyfile() is used to copy a source file descriptor to a destination file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * descriptor.  This allows an application to figure out how it wants to open
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the files (doing various security checks, perhaps), and then just pass in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the file descriptors.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int fcopyfile(int src_fd, int dst_fd, copyfile_state_t state, copyfile_flags_t flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_state_t s = state;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct stat dst_sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (src_fd < 0 || dst_fd < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (copyfile_preamble(&s, flags) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_debug(2, "set src_fd <- %d", src_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->src_fd == -2 && src_fd > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->src_fd = src_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fstatx_np(s->src_fd, &s->sb, s->fsec) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (errno == ENOTSUP || errno == EPERM)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fstat(s->src_fd, &s->sb);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("fstatx_np on src fd %d", s->src_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* prevent copying on unsupported types */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    switch (s->sb.st_mode & S_IFMT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case S_IFLNK:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case S_IFDIR:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case S_IFREG:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       errno = ENOTSUP;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_debug(2, "set dst_fd <- %d", dst_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->dst_fd == -2 && dst_fd > -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->dst_fd = dst_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void)fstat(s->dst_fd, &dst_sb);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void)fchmod(s->dst_fd, (dst_sb.st_mode & ~S_IFMT) | (S_IRUSR | S_IWUSR));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void)copyfile_quarantine(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = copyfile_internal(s, flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret >= 0 && !(s->flags & COPYFILE_STAT))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)fchmod(s->dst_fd, dst_sb.st_mode & ~S_IFMT);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = s->err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->err = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (state == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int t = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_state_free(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the original copyfile() routine; this copies a source file to a destination
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * file.  Note that because we need to set the names in the state variable, this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * is not just the same as opening the two files, and then calling fcopyfile().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Oh, if only life were that simple!
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int copyfile(const char *src, const char *dst, copyfile_state_t state, copyfile_flags_t flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int createdst = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_state_t s = state;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct stat dst_sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (src == NULL && dst == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (copyfile_preamble(&s, flags) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This macro is... well, it's not the worst thing you can do with cpp, not
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  by a long shot.  Essentially, we are setting the filename (src or dst)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * in the state structure; since the structure may not have been cleared out
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * before being used again, we do some of the cleanup here:  if the given
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * filename (e.g., src) is set, and state->src is not equal to that, then
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * we need to check to see if the file descriptor had been opened, and if so,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * close it.  After that, we set state->src to be a copy of the given filename,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * releasing the old copy if necessary.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define COPYFILE_SET_FNAME(NAME, S) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do { \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (NAME != NULL) {                                                                    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (S->NAME != NULL && strncmp(NAME, S->NAME, MAXPATHLEN)) {                      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(2, "replacing string %s (%s) -> (%s)", #NAME, NAME, S->NAME);\
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (S->NAME##_fd != -2 && S->NAME##_fd > -1) {                             \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_debug(4, "closing %s fd: %d", #NAME, S->NAME##_fd);               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           close(S->NAME##_fd);                                                 \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           S->NAME##_fd = -2;                                                   \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }                                                                           \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }                                                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (S->NAME) {                                                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       free(S->NAME);                                                           \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       S->NAME = NULL;                                                          \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }                                                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((S->NAME = strdup(NAME)) == NULL)                                                \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;                                                                  \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }                                                                                      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_SET_FNAME(src, s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_SET_FNAME(dst, s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->flags & COPYFILE_RECURSIVE) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = copytree(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Get a copy of the source file's security settings
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((s->original_fsec = filesec_init()) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((s->flags & COPYFILE_NOFOLLOW_DST) && lstat(s->dst, &dst_sb) == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (dst_sb.st_mode & S_IFLNK)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->permissive_fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       free(s->permissive_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->permissive_fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else if(statx_np(s->dst, &dst_sb, s->original_fsec) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       * copyfile_fix_perms() will make a copy of the permission set,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       * and insert at the beginning an ACE that ensures we can write
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       * to the file and set attributes.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if((s->permissive_fsec = copyfile_fix_perms(s, &s->original_fsec)) != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * Set the permissions for the destination to our copy.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * We should get ENOTSUP from any filesystem that simply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * doesn't support it.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (chmodx_np(s->dst, s->permissive_fsec) < 0 && errno != ENOTSUP)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("setting security information");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           filesec_free(s->permissive_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->permissive_fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else if (errno == ENOENT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   createdst = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * If COPYFILE_CHECK is set in flags, then all we are going to do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * is see what kinds of things WOULD have been copied (see
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * copyfile_check() below).  We return that value.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_CHECK & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = copyfile_check(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else if ((ret = copyfile_open(s)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = copyfile_internal(s, flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef COPYFILE_RECURSIVE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!(flags & COPYFILE_STAT)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!createdst)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* Just need to reset the BSD information -- mode, owner, group */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)fchown(s->dst_fd, dst_sb.st_uid, dst_sb.st_gid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)fchmod(s->dst_fd, dst_sb.st_mode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    reset_security(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (state == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int t = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_state_free(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+error_exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = s->err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->err = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Shared prelude to the {f,}copyfile().  This initializes the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * state variable, if necessary, and also checks for both debugging
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * and disabling environment variables.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_preamble(copyfile_state_t *state, copyfile_flags_t flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_state_t s;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (*state == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((*state = copyfile_state_alloc()) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    s = *state;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_DEBUG & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   char *e;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((e = getenv(COPYFILE_DEBUG_VAR)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       s->debug = (uint32_t)strtol(e, NULL, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* clamp s->debug to 1 if the environment variable is not parsable */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (s->debug == 0 && errno != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->debug = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(2, "debug value set to: %d", s->debug);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Temporarily disabled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (getenv(COPYFILE_DISABLE_VAR) != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(1, "copyfile disabled");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_debug(2, "setting flags: %d", s->flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    s->flags = flags;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The guts of {f,}copyfile().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This looks through the flags in a particular order, and calls the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * associated functions.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_internal(copyfile_state_t s, copyfile_flags_t flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->dst_fd < 0 || s->src_fd < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)", s->src_fd, s->dst_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * COPYFILE_PACK causes us to create an Apple Double version of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * source file, and puts it into the destination file.  See
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * copyfile_pack() below for all the gory details.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_PACK & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((ret = copyfile_pack(s)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (s->dst) unlink(s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * COPYFILE_UNPACK is the undoing of COPYFILE_PACK, obviously.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * The goal there is to take an Apple Double file, and turn it
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * into a normal file (with data fork, resource fork, modes,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * extended attributes, ACLs, etc.).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_UNPACK & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((ret = copyfile_unpack(s)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * If we have quarantine info set, we attempt
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * to apply it to dst_fd.  We don't care if
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * it fails, not yet anyway.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->qinfo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)qtn_file_apply_to_fd(s->qinfo, s->dst_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * COPYFILE_XATTR tells us to copy the extended attributes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * this is seperate from the extended security (aka ACLs),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * however.  If we succeed in this, we continue to the next
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * stage; if we fail, we return with an error value.  Note
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * that we fail if the errno is ENOTSUP, but we don't print
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * a warning in that case.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_XATTR & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((ret = copyfile_xattr(s)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (errno != ENOTSUP && errno != EPERM)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("error processing extended attributes");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Simialr to above, this tells us whether or not to copy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * the non-meta data portion of the file.  We attempt to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * remove (via unlink) the destination file if we fail.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_DATA & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((ret = copyfile_data(s)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("error processing data");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (s->dst && unlink(s->dst))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("%s: remove", s->src ? s->src : "(null src)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * COPYFILE_SECURITY requests that we copy the security, both
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * extended and mundane (that is, ACLs and POSIX).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_SECURITY & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((ret = copyfile_security(s)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("error processing security information");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_STAT & flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((ret = copyfile_stat(s)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("error processing POSIX information");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+error_exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * A publicly-visible routine, copyfile_state_alloc() sets up the state variable.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+copyfile_state_t copyfile_state_alloc(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_state_t s = (copyfile_state_t) calloc(1, sizeof(struct _copyfile_state));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->src_fd = -2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->dst_fd = -2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->fsec = filesec_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = ENOMEM;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return s;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyfile_state_free() returns the memory allocated to the state structure.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * It also closes the file descriptors, if they've been opened.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int copyfile_state_free(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s != NULL)
</span>     {
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    case COPYFILE_STATE_COPIED:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        /* since copyfile did not recored how many bytes were copied, return the size of the destination file */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        /* first check if the file descriptor has been set */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        ret = real_copyfile_state_get(s, COPYFILE_STATE_DST_FD, &file_descriptor);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        if ( ret < 0 ) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            return ret;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        if ( file_descriptor != -2 ) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            ret = fstat(file_descriptor, &file_stat);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            return ret;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        } else {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        /* the file descriptor was not set, so check the file name */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            ret = real_copyfile_state_get(s, COPYFILE_STATE_DST_FILENAME, &file_name);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            if ( ret < 0 ) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                return ret;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            if ( file_name == NULL ) {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                /* neither the file descriptor nor the file name has been set */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                return real_copyfile_state_get(s, flag, dst);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-            ret = stat(file_name, &file_stat);
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        *(off_t*)dst = file_stat.st_size;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        return 0;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        break;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    case COPYFILE_STATE_STATUS_CB:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    case COPYFILE_STATE_STATUS_CTX:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        /* copyfile did not run the callback function, so return default (which is an error) */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-    default:
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-        return real_copyfile_state_get(s, flag, dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       filesec_free(s->fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->original_fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       filesec_free(s->original_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->permissive_fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       filesec_free(s->permissive_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->qinfo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       qtn_file_free(s->qinfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (copyfile_close(s) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("error closing files");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->dst)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       free(s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->src)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       free(s->src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Should we worry if we can't close the source?  NFS says we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * should, but it's pretty late for us at this point.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_close(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->src && s->src_fd >= 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   close(s->src_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->dst && s->dst_fd >= 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (close(s->dst_fd))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span>     }
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span>     return 0;
 }
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#endif /* __MPLS_LIB_SUPPORT_COPYFILE_WRAP__ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The purpose of this function is to set up a set of permissions
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * (ACL and traditional) that lets us write to the file.  In the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * case of ACLs, we do this by putting in a first entry that lets
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * us write data, attributes, and extended attributes.  In the case
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * of traditional permissions, we set the S_IWUSR (user-write)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * bit.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static filesec_t copyfile_fix_perms(copyfile_state_t s __unused, filesec_t *fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_t ret_fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    mode_t mode;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    acl_t acl = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((ret_fsec = filesec_dup(*fsec)) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filesec_get_property(ret_fsec, FILESEC_ACL, &acl) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef COPYFILE_RECURSIVE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (add_uberace(&acl))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_entry_t entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_permset_t permset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   uuid_t qual;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (mbr_uid_to_uuid(getuid(), qual) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * First, we create an entry, and give it the special name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * of ACL_FIRST_ENTRY, thus guaranteeing it will be first.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * After that, we clear out all the permissions in it, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * add three permissions:  WRITE_DATA, WRITE_ATTRIBUTES, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * WRITE_EXTATTRIBUTES.  We put these into an ACE that allows
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * the functionality, and put this into the ACL.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_get_permset(entry, &permset) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_clear_perms(permset) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_WRITE_DATA) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_WRITE_ATTRIBUTES) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_add_perm(permset, ACL_WRITE_EXTATTRIBUTES) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_set_tag_type(entry, ACL_EXTENDED_ALLOW) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if(acl_set_permset(entry, permset) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if(acl_set_qualifier(entry, qual) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (filesec_set_property(ret_fsec, FILESEC_ACL, &acl) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * This is for the normal, mundane, POSIX permission model.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * We make sure that we can write to the file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filesec_get_property(ret_fsec, FILESEC_MODE, &mode) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((mode & (S_IWUSR | S_IRUSR)) != (S_IWUSR | S_IRUSR))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       mode |= S_IWUSR|S_IRUSR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (filesec_set_property(ret_fsec, FILESEC_MODE, &mode) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (acl)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_free(acl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret_fsec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+error_exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret_fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filesec_free(ret_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret_fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Used to clear out the BSD/POSIX security information from
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * a filesec
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+copyfile_unset_posix_fsec(filesec_t fsec)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)filesec_set_property(fsec, FILESEC_OWNER, _FILESEC_UNSET_PROPERTY);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)filesec_set_property(fsec, FILESEC_GROUP, _FILESEC_UNSET_PROPERTY);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)filesec_set_property(fsec, FILESEC_MODE, _FILESEC_UNSET_PROPERTY);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Used to remove acl information from a filesec_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Unsetting the acl alone in Tiger was insufficient
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_unset_acl(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filesec_set_property(s->fsec, FILESEC_ACL, NULL) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(5, "unsetting acl attribute on %s", s->dst ? s->dst : "(null dst)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ++ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filesec_set_property(s->fsec, FILESEC_UUID, NULL) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(5, "unsetting uuid attribute on %s", s->dst ? s->dst : "(null dst)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ++ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filesec_set_property(s->fsec, FILESEC_GRPUUID, NULL) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(5, "unsetting group uuid attribute on %s", s->dst ? s->dst : "(null dst)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ++ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyfile_open() does what one expects:  it opens up the files
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * given in the state structure, if they're not already open.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * It also does some type validation, to ensure that we only
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * handle file types we know about.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_open(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int oflags = O_EXCL | O_CREAT | O_WRONLY;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int islnk = 0, isdir = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int osrc = 0, dsrc = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->src && s->src_fd == -2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (s->src, &s->sb, s->fsec))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("stat on %s", s->src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* prevent copying on unsupported types */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   switch (s->sb.st_mode & S_IFMT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       case S_IFLNK:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           islnk = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if ((size_t)s->sb.st_size > SIZE_T_MAX) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   s->err = ENOMEM;     /* too big for us to copy */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           osrc = O_SYMLINK;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       case S_IFDIR:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           isdir = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       case S_IFREG:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!(strcmp(s->src, "/dev/null") == 0 && (s->flags & COPYFILE_METADATA))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   s->err = ENOTSUP;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * If we're packing, then we are actually
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * creating a file, no matter what the source
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * was.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->flags & COPYFILE_PACK) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * O_SYMLINK and O_NOFOLLOW are not compatible options:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * if the file is a symlink, and O_NOFOLLOW is specified,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * open will return ELOOP, whether or not O_SYMLINK is set.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * However, we know whether or not it was a symlink from
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * the stat above (although there is a potentiaal for a race
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * condition here, but it will err on the side of returning
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * ELOOP from open).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!islnk)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   osrc = (s->flags & COPYFILE_NOFOLLOW_SRC) ? O_NOFOLLOW : 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           isdir = islnk = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((s->src_fd = open(s->src, O_RDONLY | osrc , 0)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("open on %s", s->src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(2, "open successful on source (%s)", s->src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)copyfile_quarantine(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->dst && s->dst_fd == -2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * COPYFILE_UNLINK tells us to try removing the destination
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * before we create it.  We don't care if the file doesn't
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * exist, so we ignore ENOENT.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (COPYFILE_UNLINK & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (remove(s->dst) < 0 && errno != ENOENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("%s: remove", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (s->flags & COPYFILE_NOFOLLOW_DST) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct stat st;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           dsrc = O_NOFOLLOW;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (lstat(s->dst, &st) != -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((st.st_mode & S_IFMT) == S_IFLNK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           dsrc = O_SYMLINK;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (islnk) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           size_t sz = (size_t)s->sb.st_size + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           char *bp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           bp = calloc(1, sz);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (bp == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("cannot allocate %d bytes", (int) sz);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (readlink(s->src, bp, sz-1) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("cannot readlink %s", s->src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   free(bp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (symlink(bp, s->dst) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           copyfile_warn("Cannot make symlink %s", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           free(bp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(bp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->dst_fd = open(s->dst, O_RDONLY | O_SYMLINK);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (s->dst_fd == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("Cannot open symlink %s for reading", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else if (isdir) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           mode_t mode;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           mode = s->sb.st_mode & ~S_IFMT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (mkdir(s->dst, mode) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (errno != EEXIST || (s->flags & COPYFILE_EXCL)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           copyfile_warn("Cannot make directory %s", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->dst_fd = open(s->dst, O_RDONLY | dsrc);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (s->dst_fd == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("Cannot open directory %s for reading", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else while((s->dst_fd = open(s->dst, oflags | dsrc, s->sb.st_mode | S_IWUSR)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * We set S_IWUSR because fsetxattr does not -- at the time this comment
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * was written -- allow one to set an extended attribute on a file descriptor
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * for a read-only file, even if the file descriptor is opened for writing.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * This will only matter if the file does not already exist.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       switch(errno)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case EEXIST:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_debug(3, "open failed, retrying (%s)", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (s->flags & COPYFILE_EXCL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               oflags = oflags & ~O_CREAT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (s->flags & (COPYFILE_PACK | COPYFILE_DATA))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_debug(4, "truncating existing file (%s)", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   oflags |= O_TRUNC;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case EACCES:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if(chmod(s->dst, (s->sb.st_mode | S_IWUSR) & ~S_IFMT) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * If we're trying to write to a directory to which we don't
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * have access, the create above would have failed, but chmod
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * here would have given us ENOENT.  But the real error is
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * still one of access, so we change the errno we're reporting.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * This could cause confusion with a race condition.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (errno == ENOENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           errno = EACCES;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case EISDIR:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_debug(3, "open failed because it is a directory (%s)", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (((s->flags & COPYFILE_EXCL) ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   (!isdir && (s->flags & COPYFILE_DATA)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   && !(s->flags & COPYFILE_UNPACK))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               oflags = (oflags & ~(O_WRONLY|O_CREAT|O_TRUNC)) | O_RDONLY;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("open on %s", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(2, "open successful on destination (%s)", s->dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->dst_fd < 0 || s->src_fd < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(1, "file descriptors not open (src: %d, dst: %d)",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->src_fd, s->dst_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyfile_check(), as described above, essentially tells you
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * what you'd have to copy, if you wanted it to copy the things
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * you asked it to copy.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * In other words, if you pass in COPYFILE_ALL, and the file in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * question had no extended attributes but did have an ACL, you'd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * get back COPYFILE_ACL.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static copyfile_flags_t copyfile_check(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    acl_t acl = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_flags_t ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int nofollow = (s->flags & COPYFILE_NOFOLLOW_SRC);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    qtn_file_t qinfo;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!s->src)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* check EAs */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_XATTR & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (listxattr(s->src, 0, 0, nofollow ? XATTR_NOFOLLOW : 0) > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret |= COPYFILE_XATTR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_ACL & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (COPYFILE_NOFOLLOW_SRC & s->flags ? lstatx_np : statx_np)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (s->src, &s->sb, s->fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret |= COPYFILE_ACL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_debug(2, "check result: %d (%s)", ret, s->src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (acl)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_free(acl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->qinfo) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* If the state has had quarantine info set already, we use that */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   qinfo = qtn_file_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * For quarantine information, we need to see if the source file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * has any.  Since it may be a symlink, however, and we may, or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * not be following, *and* there's no qtn* routine which can optionally
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * follow or not follow a symlink, we need to instead work around
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * this limitation.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (qinfo) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int qret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct stat sbuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * If we care about not following symlinks, *and* the file exists
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * (which is to say, lstat doesn't return an error), *and* the file
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * is a symlink, then we open it up (with O_SYMLINK), and use
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * qtn_file_init_with_fd(); if none of that is true, however, then
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * we can simply use qtn_file_init_with_path().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (nofollow
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   && lstat(s->src, &sbuf) == 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           && ((sbuf.st_mode & S_IFMT) == S_IFLNK)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   fd = open(s->src, O_RDONLY | O_SYMLINK);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (fd != -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (!qtn_file_init_with_fd(qinfo, fd)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           close(fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (!qtn_file_init_with_path(qinfo, s->src)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           qret |= ((s->flags & COPYFILE_XATTR) ? COPYFILE_XATTR : COPYFILE_ACL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           qtn_file_free(qinfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ret |= qret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Attempt to copy the data section of a file.  Using blockisize
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * is not necessarily the fastest -- it might be desirable to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * specify a blocksize, somehow.  But it's a size that should be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * guaranteed to work.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_data(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t blen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *bp = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t nread;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t iBlocksize = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t oBlocksize = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    const size_t onegig = 1 << 30;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct statfs sfs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_callback_t status = s->statuscb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Unless it's a normal file, we don't copy.  For now, anyway */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((s->sb.st_mode & S_IFMT) != S_IFREG)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (fstatfs(s->src_fd, &sfs) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   iBlocksize = s->sb.st_blksize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   iBlocksize = sfs.f_iosize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Work-around for 6453525, limit blocksize to 1G */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (iBlocksize > onegig) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   iBlocksize = onegig;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((bp = malloc(iBlocksize)) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (fstatfs(s->dst_fd, &sfs) == -1 || sfs.f_iosize == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   oBlocksize = iBlocksize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   oBlocksize = sfs.f_iosize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (oBlocksize > onegig)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       oBlocksize = onegig;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    blen = iBlocksize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    s->totalCopied = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* If supported, do preallocation for Xsan / HFS volumes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef F_PREALLOCATE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       fstore_t fst;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       fst.fst_flags = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       fst.fst_posmode = F_PEOFPOSMODE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       fst.fst_offset = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       fst.fst_length = s->sb.st_size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* Ignore errors; this is merely advisory. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       (void)fcntl(s->dst_fd, F_PREALLOCATE, &fst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    while ((nread = read(s->src_fd, bp, blen)) > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ssize_t nwritten;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t left = nread;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   void *ptr = bp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int loop = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   while (left > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           nwritten = write(s->dst_fd, ptr, MIN(left, oBlocksize));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           switch (nwritten) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case 0:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (++loop > 5) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           copyfile_warn("writing to output %d times resulted in 0 bytes written", loop);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           s->err = EAGAIN;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           case -1:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("writing to output file got error");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_SKIP) {      // Skip the data copy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if (rv == COPYFILE_CONTINUE) {  // Retry the write
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   left -= nwritten;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   ptr = ((char*)ptr) + nwritten;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   loop = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->totalCopied += nwritten;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (status) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   int rv = (*status)(COPYFILE_COPY_DATA, COPYFILE_PROGRESS,  s, s->src, s->dst, s->ctx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (rv == COPYFILE_QUIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           ret = -1; s->err = ECANCELED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (nread < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_warn("reading from %s", s->src ? s->src : "(null src)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ftruncate(s->dst_fd, s->sb.st_size) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->err = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    free(bp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyfile_security() will copy the ACL set, and the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * POSIX set.  Complexities come when dealing with
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * inheritied permissions, and when dealing with both
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * POSIX and ACL permissions.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_security(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int copied = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int has_uberace = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    acl_flagset_t flags;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct stat sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    acl_entry_t entry_src = NULL, entry_dst = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    acl_t acl_src = NULL, acl_dst = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_t tmp_fsec = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_t fsec_dst = filesec_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (fsec_dst == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_ACL & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (filesec_get_property(s->fsec, FILESEC_ACL, &acl_src))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (errno == ENOENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_src = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* grab the destination acl
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    cannot assume it's empty due to inheritance
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if(fstatx_np(s->dst_fd, &sb, fsec_dst))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (filesec_get_property(fsec_dst, FILESEC_ACL, &acl_dst))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (errno == ENOENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_dst = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_t tmp = acl_init(4);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_entry_t ace = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int count = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (tmp == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           for (; acl_get_entry(acl_dst,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   ace == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   &ace) == 0;)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (count++ == 0 && is_uberace(ace)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if ((ret = acl_create_entry(&tmp, &entry_dst)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if ((ret = acl_copy_entry(entry_dst, ace)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           has_uberace = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   acl_get_flagset_np(ace, &flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if ((ret = acl_create_entry(&tmp, &entry_dst)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           if ((ret = acl_copy_entry(entry_dst, ace)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_free(acl_dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_dst = tmp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (ret == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_src == NULL && acl_dst == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto no_acl;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (acl_src) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (acl_dst == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   acl_dst = acl_init(4);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           for (copied = 0;acl_get_entry(acl_src,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               entry_src == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               &entry_src) == 0;)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               acl_get_flagset_np(entry_src, &flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (!acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((ret = acl_create_entry(&acl_dst, &entry_dst)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((ret = acl_copy_entry(entry_dst, entry_src)) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_debug(2, "copied acl entry from %s to %s",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           s->src ? s->src : "(null src)",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           s->dst ? s->dst : "(null dst)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copied++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!has_uberace && (s->internal_flags & cfDelayAce)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (add_uberace(&acl_dst))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!filesec_set_property(s->fsec, FILESEC_ACL, &acl_dst))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(3, "altered acl");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+no_acl:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * The following code is attempting to ensure that only the requested
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * security information gets copied over to the destination file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * We essentially have four cases:  COPYFILE_ACL, COPYFILE_STAT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * COPYFILE_(STAT|ACL), and none (in which case, we wouldn't be in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * this function).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * If we have both flags, we copy everything; if we have ACL but not STAT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * we remove the POSIX information from the filesec object, and apply the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * ACL; if we have STAT but not ACL, then we just use fchmod(), and ignore
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * the extended version.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tmp_fsec = filesec_dup(s->fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (tmp_fsec == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto error_exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    switch (COPYFILE_SECURITY & s->flags) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_ACL:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_unset_posix_fsec(tmp_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* FALLTHROUGH */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_ACL | COPYFILE_STAT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (fchmodx_np(s->dst_fd, tmp_fsec) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_t acl = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * The call could have failed for a number of reasons, since
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * it does a number of things:  it changes the mode of the file,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * sets the owner and group, and applies an ACL (if one exists).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * The typical failure is going to be trying to set the group of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * the destination file to match the source file, when the process
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * doesn't have permission to put files in that group.  We try to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * work around this by breaking the steps out and doing them
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * discretely.  We don't care if the fchown fails, but we do care
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * if the mode or ACL can't be set.  For historical reasons, we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * simply log those failures, however.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NS(x)      ((x) ? (x) : "(null string)")
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (fchmod(s->dst_fd, s->sb.st_mode) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("could not change mode of destination file %s to match source file %s", NS(s->dst), NS(s->src));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (filesec_get_property(tmp_fsec, FILESEC_ACL, &acl) == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (acl_set_fd(s->dst_fd, acl) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           copyfile_warn("could not apply acl to destination file %s from source file %s", NS(s->dst), NS(s->src));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   acl_free(acl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STAT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       (void)fchmod(s->dst_fd, s->sb.st_mode);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_free(tmp_fsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filesec_free(fsec_dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (acl_src) acl_free(acl_src);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (acl_dst) acl_free(acl_dst);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+error_exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Attempt to set the destination file's stat information -- including
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * flags and time-related fields -- to the source's.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_stat(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    struct timeval tval[2];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * NFS doesn't support chflags; ignore errors unless there's reason
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * to believe we're losing bits.  (Note, this still won't be right
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * if the server supports flags and we were trying to *remove* flags
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * on a file that we copied, i.e., that we didn't create.)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (fchflags(s->dst_fd, (u_int)s->sb.st_flags))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (errno != EOPNOTSUPP || s->sb.st_flags != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("%s: set flags (was: 0%07o)", s->dst ? s->dst : "(null dst)", s->sb.st_flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* If this fails, we don't care */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* This may have already been done in copyfile_security() */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void)fchmod(s->dst_fd, s->sb.st_mode & ~S_IFMT);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tval[0].tv_sec = s->sb.st_atime;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tval[1].tv_sec = s->sb.st_mtime;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    tval[0].tv_usec = tval[1].tv_usec = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (futimes(s->dst_fd, tval))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Similar to copyfile_security() in some ways; this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * routine copies the extended attributes from the source,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * and sets them on the destination.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The procedure is pretty simple, even if it is verbose:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * for each named attribute on the destination, get its name, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * remove it.  We should have none after that.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * For each named attribute on the source, get its name, get its
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * data, and set it on the destination.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_xattr(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *namebuf, *end;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t xa_size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    void *xa_dataptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t bufsize = 4096;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t asize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t nsize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* delete EAs on destination */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((nsize = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((namebuf = (char *) malloc(nsize)) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       nsize = flistxattr(s->dst_fd, namebuf, nsize, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (nsize > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * With this, end points to the last byte of the allocated buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * This *should* be NUL, from flistxattr, but if it's not, we can
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * set it anyway -- it'll result in a truncated name, which then
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * shouldn't match when we get them later.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       end = namebuf + nsize - 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (*end != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           *end = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       for (name = namebuf; name <= end; name += strlen(name) + 1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /* If the quarantine information shows up as an EA, we skip over it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           fremovexattr(s->dst_fd, name,0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(namebuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (nsize < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (errno == ENOTSUP || errno == EPERM)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* get name list of EAs on source */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((nsize = flistxattr(s->src_fd, 0, 0, 0)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (errno == ENOTSUP || errno == EPERM)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (nsize == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((namebuf = (char *) malloc(nsize)) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   nsize = flistxattr(s->src_fd, namebuf, nsize, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (nsize <= 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(namebuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return (int)nsize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * With this, end points to the last byte of the allocated buffer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * This *should* be NUL, from flistxattr, but if it's not, we can
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * set it anyway -- it'll result in a truncated name, which then
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * shouldn't match when we get them later.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    end = namebuf + nsize - 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (*end != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   *end = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((xa_dataptr = (void *) malloc(bufsize)) == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(namebuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    for (name = namebuf; name <= end; name += strlen(name) + 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* If the quarantine information shows up as an EA, we skip over it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (strncmp(name, XATTR_QUARANTINE_NAME, end - name) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((xa_size = fgetxattr(s->src_fd, name, 0, 0, 0, 0)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (xa_size > bufsize)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       void *tdptr = xa_dataptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       bufsize = xa_size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if ((xa_dataptr =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (void *) realloc((void *) xa_dataptr, bufsize)) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(tdptr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((asize = fgetxattr(s->src_fd, name, xa_dataptr, xa_size, 0, 0)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (xa_size != asize)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       xa_size = asize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fsetxattr(s->dst_fd, name, xa_dataptr, xa_size, 0, 0) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (namebuf)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(namebuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    free((void *) xa_dataptr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * API interface into getting data from the opaque data type.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = EFAULT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    switch(flag)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_SRC_FD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(int*)ret = s->src_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_DST_FD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(int*)ret = s->dst_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_SRC_FILENAME:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(char**)ret = s->src;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_DST_FILENAME:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(char**)ret = s->dst;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_QUARANTINE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(qtn_file_t*)ret = s->qinfo;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_STATS:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret = s->stats.global;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_PROGRESS_CB:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret = s->callbacks.progress;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef     COPYFILE_STATE_STATUS_CB
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_STATUS_CB:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(copyfile_callback_t*)ret = s->statuscb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_STATUS_CTX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(void**)ret = s->ctx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_COPIED:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *(off_t*)ret = s->totalCopied;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Public API for setting state data (remember that the state is
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * an opaque data type).
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define copyfile_set_string(DST, SRC) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    do {                                   \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (SRC != NULL) {                      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       DST = strdup((char *)SRC);          \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {                                \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (DST != NULL) {                  \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           free(DST);                      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }                                   \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       DST = NULL;                         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (thing == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errno = EFAULT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return  -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    switch(flag)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_SRC_FD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       s->src_fd = *(int*)thing;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_DST_FD:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        s->dst_fd = *(int*)thing;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_SRC_FILENAME:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_set_string(s->src, thing);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_DST_FILENAME:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_set_string(s->dst, thing);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_QUARANTINE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (s->qinfo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           qtn_file_free(s->qinfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->qinfo = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (*(qtn_file_t*)thing)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->qinfo = qtn_file_clone(*(qtn_file_t*)thing);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_STATS:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        s->stats.global = thing;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_PROGRESS_CB:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        s->callbacks.progress = thing;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef COPYFILE_STATE_STATUS_CB
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_STATUS_CB:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       s->statuscb = (copyfile_callback_t)thing;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   case COPYFILE_STATE_STATUS_CTX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       s->ctx = (void*)thing;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       errno = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef copyfile_set_string
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Make this a standalone program for testing purposes by
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * defining _COPYFILE_TEST.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef _COPYFILE_TEST
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define COPYFILE_OPTION(x) { #x, COPYFILE_ ## x },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+struct {char *s; int v;} opts[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(ACL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(STAT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(XATTR)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(DATA)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(SECURITY)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(METADATA)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(ALL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(NOFOLLOW_SRC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(NOFOLLOW_DST)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(NOFOLLOW)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(EXCL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(MOVE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(UNLINK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(PACK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(UNPACK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(CHECK)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(VERBOSE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    COPYFILE_OPTION(DEBUG)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {NULL, 0}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int main(int c, char *v[])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int flags = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (c < 3)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   errx(1, "insufficient arguments");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    while(c-- > 3)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (i = 0; opts[i].s != NULL; ++i)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (strcasecmp(opts[i].s, v[c]) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf("option %d: %s <- %d\n", c, opts[i].s, opts[i].v);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           flags |= opts[i].v;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return copyfile(v[1], v[2], NULL, flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Apple Double Create
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Create an Apple Double "._" file from a file's extented attributes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define offsetof(type, member)     ((size_t)(&((type *)0)->member))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define    XATTR_MAXATTRLEN   (4*1024)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   Typical "._" AppleDouble Header File layout:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ------------------------------------------------------------
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         MAGIC          0x00051607
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         VERSION        0x00020000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         FILLER         0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         COUNT          2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     .-- AD ENTRY[0]    Finder Info Entry (must be first)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  .--+-- AD ENTRY[1]    Resource Fork Entry (must be last)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |  '-> FINDER INFO
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      /////////////  Fixed Size Data (32 bytes)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      EXT ATTR HDR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR ENTRY[0] --.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR ENTRY[1] --+--.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR ENTRY[2] --+--+--.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |         ...          |  |  |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR ENTRY[N] --+--+--+--.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR DATA 0   <-'  |  |  |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ////////////       |  |  |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR DATA 1   <----'  |  |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      /////////////         |  |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR DATA 2   <-------'  |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      /////////////            |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |         ...                   |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      ATTR DATA N   <----------'
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |      /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |                      Attribute Free Space
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  |
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  '----> RESOURCE FORK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /////////////   Variable Sized Data
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            ...
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /////////////
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  ------------------------------------------------------------
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   NOTE: The EXT ATTR HDR, ATTR ENTRY's and ATTR DATA's are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   stored as part of the Finder Info.  The length in the Finder
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   Info AppleDouble entry includes the length of the extended
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   attribute header, attribute entries, and attribute data.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * On Disk Data Structures
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Note: Motorola 68K alignment and big-endian.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * See RFC 1740 for additional information about the AppleDouble file format.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ADH_MAGIC     0x00051607
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ADH_VERSION   0x00020000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ADH_MACOSX    "Mac OS X        "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * AppleDouble Entry ID's
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_DATA          1   /* Data fork */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_RESOURCE      2   /* Resource fork */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_REALNAME      3   /* File's name on home file system */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_COMMENT       4   /* Standard Mac comment */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_ICONBW        5   /* Mac black & white icon */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_ICONCOLOR     6   /* Mac color icon */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_UNUSED        7   /* Not used */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_FILEDATES     8   /* File dates; create, modify, etc */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_FINDERINFO    9   /* Mac Finder info & extended info */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_MACINFO      10   /* Mac file info, attributes, etc */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_PRODOSINFO   11   /* Pro-DOS file info, attrib., etc */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_MSDOSINFO    12   /* MS-DOS file info, attributes, etc */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_AFPNAME      13   /* Short name on AFP server */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_AFPINFO      14   /* AFP file info, attrib., etc */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_AFPDIRID     15   /* AFP directory ID */ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define AD_ATTRIBUTES   AD_FINDERINFO
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_FILE_PREFIX   "._"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_HDR_MAGIC     0x41545452   /* 'ATTR' */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_BUF_SIZE      4096        /* default size of the attr file and how much we'll grow by */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Implementation Limits */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_MAX_SIZE      (128*1024)  /* 128K maximum attribute data size */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_MAX_NAME_LEN  128
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_MAX_HDR_SIZE  (65536+18)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Note: ATTR_MAX_HDR_SIZE is the largest attribute header
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * size supported (including the attribute entries). All of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the attribute entries must reside within this limit.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define FINDERINFOSIZE     32
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct apple_double_entry
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   type;     /* entry type: see list, 0 invalid */ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   offset;   /* entry data offset from the beginning of the file. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   length;   /* entry data length in bytes. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} __attribute__((aligned(2), packed)) apple_double_entry_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct apple_double_header
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   magic;         /* == ADH_MAGIC */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   version;       /* format version: 2 = 0x00020000 */ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   filler[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t   numEntries;    /* number of entries which follow */ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   apple_double_entry_t   entries[2];  /* 'finfo' & 'rsrc' always exist */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t    finfo[FINDERINFOSIZE];  /* Must start with Finder Info (32 bytes) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t    pad[2];        /* get better alignment inside attr_header */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} __attribute__((aligned(2), packed)) apple_double_header_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Entries are aligned on 4 byte boundaries */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct attr_entry
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   offset;    /* file offset to data */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   length;    /* size of attribute data */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t   flags;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t    namelen;   /* length of name including NULL termination char */ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t    name[1];   /* NULL-terminated UTF-8 name (up to 128 bytes max) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} __attribute__((aligned(2), packed)) attr_entry_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Header + entries must fit into 64K */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct attr_header
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   apple_double_header_t  appledouble;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   magic;        /* == ATTR_HDR_MAGIC */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   debug_tag;    /* for debugging == file id of owning file */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   total_size;   /* total size of attribute header + entries + data */ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   data_start;   /* file offset to attribute data area */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   data_length;  /* length of attribute data area */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t   reserved[3];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t   flags;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t   num_attrs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} __attribute__((aligned(2), packed)) attr_header_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Empty Resource Fork Header */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* This comes by way of xnu's vfs_xattr.c */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct rsrcfork_header {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       fh_DataOffset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       fh_MapOffset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       fh_DataLength;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       fh_MapLength;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t        systemData[112];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t        appData[128];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       mh_DataOffset; 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       mh_MapOffset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       mh_DataLength; 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       mh_MapLength;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int32_t       mh_Next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t       mh_RefNum;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t        mh_Attr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int8_t        mh_InMemoryAttr; 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t       mh_Types;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t       mh_Names;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   u_int16_t       typeCount;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} __attribute__((aligned(2), packed)) rsrcfork_header_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RF_FIRST_RESOURCE    256
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RF_NULL_MAP_LENGTH    30   
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RF_EMPTY_TAG  "This resource fork intentionally left blank   "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const rsrcfork_header_t empty_rsrcfork_header = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt32(RF_FIRST_RESOURCE),        // fh_DataOffset
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt32(RF_FIRST_RESOURCE),        // fh_MapOffset
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   0,                                              // fh_DataLength
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH),       // fh_MapLength
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { RF_EMPTY_TAG, },                              // systemData
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { 0 },                                          // appData
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt32(RF_FIRST_RESOURCE),        // mh_DataOffset
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt32(RF_FIRST_RESOURCE),        // mh_MapOffset
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   0,                                              // mh_DataLength
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt32(RF_NULL_MAP_LENGTH),       // mh_MapLength
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   0,                                              // mh_Next
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   0,                                              // mh_RefNum
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   0,                                              // mh_Attr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   0,                                              // mh_InMemoryAttr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH - 2),   // mh_Types
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt16(RF_NULL_MAP_LENGTH),       // mh_Names
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   OSSwapHostToBigInt16(-1),                       // typeCount
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SWAP16(x)  OSSwapBigToHostInt16(x)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SWAP32(x)  OSSwapBigToHostInt32(x)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SWAP64(x)  OSSwapBigToHostInt64(x)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_ALIGN 3L  /* Use four-byte alignment */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_ENTRY_LENGTH(namelen)  \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ((sizeof(attr_entry_t) - 1 + (namelen) + ATTR_ALIGN) & (~ATTR_ALIGN))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ATTR_NEXT(ae)  \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (attr_entry_t *)((u_int8_t *)(ae) + ATTR_ENTRY_LENGTH((ae)->namelen))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define    XATTR_SECURITY_NAME       "com.apple.acl.text"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Endian swap Apple Double header 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+swap_adhdr(apple_double_header_t *adh)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if BYTE_ORDER == LITTLE_ENDIAN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   count = (adh->magic == ADH_MAGIC) ? adh->numEntries : SWAP16(adh->numEntries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   adh->magic      = SWAP32 (adh->magic);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   adh->version    = SWAP32 (adh->version);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   adh->numEntries = SWAP16 (adh->numEntries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           adh->entries[i].type   = SWAP32 (adh->entries[i].type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           adh->entries[i].offset = SWAP32 (adh->entries[i].offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           adh->entries[i].length = SWAP32 (adh->entries[i].length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)adh;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Endian swap extended attributes header 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+swap_attrhdr(attr_header_t *ah)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if BYTE_ORDER == LITTLE_ENDIAN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   attr_entry_t *ae;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   count = (ah->magic == ATTR_HDR_MAGIC) ? ah->num_attrs : SWAP16(ah->num_attrs);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ah->magic       = SWAP32 (ah->magic);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ah->debug_tag   = SWAP32 (ah->debug_tag);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ah->total_size  = SWAP32 (ah->total_size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ah->data_start  = SWAP32 (ah->data_start);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ah->data_length = SWAP32 (ah->data_length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ah->flags       = SWAP16 (ah->flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ah->num_attrs   = SWAP16 (ah->num_attrs);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ae = (attr_entry_t *)(&ah[1]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attr_entry_t *next = ATTR_NEXT(ae);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ae->offset = SWAP32 (ae->offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ae->length = SWAP32 (ae->length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ae->flags  = SWAP16 (ae->flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ae = next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   (void)ah;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const u_int32_t emptyfinfo[8] = {0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Given an Apple Double file in src, turn it into a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * normal file (possibly with multiple forks, EAs, and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACLs) in dst.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_unpack(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t bytes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    void * buffer, * endptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    apple_double_header_t *adhdr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t hdrsize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int error = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->sb.st_size < ATTR_MAX_HDR_SIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   hdrsize = (ssize_t)s->sb.st_size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   hdrsize = ATTR_MAX_HDR_SIZE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    buffer = calloc(1, hdrsize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (buffer == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(1, "copyfile_unpack: calloc(1, %u) returned NULL",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                  (unsigned int) hdrsize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   endptr = (char*)buffer + hdrsize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    bytes = pread(s->src_fd, buffer, hdrsize, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (bytes < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(1, "pread returned: %d", (int) bytes);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (bytes < hdrsize)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       "pread couldn't read entire header: %d of %d",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       (int)bytes, (int)s->sb.st_size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    adhdr = (apple_double_header_t *)buffer;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Check for Apple Double file. 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((size_t)bytes < sizeof(apple_double_header_t) - 2 ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   SWAP32(adhdr->magic) != ADH_MAGIC ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   SWAP32(adhdr->version) != ADH_VERSION ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   SWAP16(adhdr->numEntries) != 2 ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   SWAP32(adhdr->entries[0].type) != AD_FINDERINFO)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("Not a valid Apple Double header");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    swap_adhdr(adhdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Remove any extended attributes on the target.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_XATTR & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((bytes = flistxattr(s->dst_fd, 0, 0, 0)) > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       char *namebuf, *name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if ((namebuf = (char*) malloc(bytes)) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = ENOMEM;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       bytes = flistxattr(s->dst_fd, namebuf, bytes, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (bytes > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           for (name = namebuf; name < namebuf + bytes; name += strlen(name) + 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               (void)fremovexattr(s->dst_fd, name, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       free(namebuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else if (bytes < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (errno != ENOTSUP && errno != EPERM)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Extract the extended attributes.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * >>>  WARNING <<<
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * This assumes that the data is already in memory (not
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * the case when there are lots of attributes or one of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * the attributes is very large.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (adhdr->entries[0].length > FINDERINFOSIZE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   attr_header_t *attrhdr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   attr_entry_t *entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if ((size_t)hdrsize < sizeof(attr_header_t)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("bad attribute header:  %u < %u",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                         (unsigned int) hdrsize,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                         (unsigned int) sizeof(attr_header_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   attrhdr = (attr_header_t *)buffer;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   swap_attrhdr(attrhdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (attrhdr->magic != ATTR_HDR_MAGIC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("bad attribute header");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   count = attrhdr->num_attrs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   entry = (attr_entry_t *)&attrhdr[1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       void * dataptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * First we do some simple sanity checking.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * +) See if entry is within the buffer's range;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * +) Check the attribute name length; if it's longer than the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * maximum, we truncate it down.  (We could error out as well;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * I'm not sure which is the better way to go here.)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * +) If, given the name length, it goes beyond the end of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * the buffer, error out.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * +) If the last byte isn't a NUL, make it a NUL.  (Since we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * truncated the name length above, we truncate the name here.)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * +) If entry->offset is so large that it causes dataptr to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * go beyond the end of the buffer -- or, worse, so large that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * it wraps around! -- we error out.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * +) If entry->length would cause the entry to go beyond the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * end of the buffer (or, worse, wrap around to before it),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * *or* if the length is larger than the hdrsize, we error out.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * (An explanation of that:  what we're checking for there is
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * the small range of values such that offset+length would cause
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * it to go beyond endptr, and then wrap around past buffer.  We
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * care about this because we are passing entry->length down to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * fgetxattr() below, and an erroneously large value could cause
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * problems there.  By making sure that it's less than hdrsize,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * which has already been sanity-checked above, we're safe.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        * That may mean that the check against < buffer is unnecessary.)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if ((void*)entry >= endptr || (void*)entry < buffer) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("Incomplete or corrupt attribute entry");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (((char*)entry + sizeof(*entry)) > (char*)endptr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("Incomplete or corrupt attribute entry");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (entry->namelen < 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("Corrupt attribute entry (only %d bytes)", entry->namelen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (entry->namelen > XATTR_MAXNAMELEN + 1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("Corrupt attribute entry (name length is %d bytes)", entry->namelen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if ((void*)(entry->name + entry->namelen) > endptr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("Incomplete or corrupt attribute entry");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* Because namelen includes the NUL, we check one byte back */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (entry->name[entry->namelen-1] != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("Corrupt attribute entry (name is not NUL-terminated)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           entry->name, entry->length, entry->offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       dataptr = (char *)attrhdr + entry->offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (dataptr > endptr || dataptr < buffer) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_debug(1, "Entry %d overflows:  offset = %u",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                          i, entry->offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = EINVAL;     /* Invalid buffer */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (((char*)dataptr + entry->length) > (char*)endptr ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (((char*)dataptr + entry->length) < (char*)buffer) ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (entry->length > (size_t)hdrsize)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("Incomplete or corrupt attribute entry");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_debug(1, "Entry %d length overflows:"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                             "  offset = %u, length = %u",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                          i, entry->offset, entry->length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           s->err = EINVAL;     /* Invalid buffer */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           qtn_file_t tqinfo = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (s->qinfo == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               tqinfo = qtn_file_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (tqinfo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   int x;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((x = qtn_file_init_with_data(tqinfo, dataptr, entry->length)) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       copyfile_warn("qtn_file_init_with_data failed: %s", qtn_error(x));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       qtn_file_free(tqinfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       tqinfo = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               tqinfo = s->qinfo;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (tqinfo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   int x;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   x = qtn_file_apply_to_fd(tqinfo, s->dst_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (x != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       copyfile_warn("qtn_file_apply_to_fd failed: %s", qtn_error(x));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (tqinfo && !s->qinfo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               qtn_file_free(tqinfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* Look for ACL data */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       else if (COPYFILE_ACL & s->flags && strcmp((char*)entry->name, XATTR_SECURITY_NAME) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           acl_t acl;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct stat sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           int retry = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           char *tcp = dataptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * acl_from_text() requires a NUL-terminated string.  The ACL EA,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * however, may not be NUL-terminated.  So in that case, we need to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            * copy it to a +1 sized buffer, to ensure it's got a terminated string.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (tcp[entry->length - 1] != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   char *tmpstr = malloc(entry->length + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (tmpstr == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   strlcpy(tmpstr, tcp, entry->length + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   acl = acl_from_text(tmpstr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   free(tmpstr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   acl = acl_from_text(tcp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (acl != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               filesec_t fsec_tmp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if ((fsec_tmp = filesec_init()) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               else if((error = fstatx_np(s->dst_fd, &sb, fsec_tmp)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               else if (filesec_set_property(fsec_tmp, FILESEC_ACL, &acl) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   while (fchmodx_np(s->dst_fd, fsec_tmp) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       if (errno == ENOTSUP)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                               if (retry && !copyfile_unset_acl(s))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                               {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   retry = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                   continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                               }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       copyfile_warn("setting security information");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               acl_free(acl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               filesec_free(fsec_tmp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (error == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* And, finally, everything else */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       else if (COPYFILE_XATTR & s->flags) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           copyfile_warn("error %d setting attribute %s", error, entry->name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       entry = ATTR_NEXT(entry);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Extract the Finder Info.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (adhdr->entries[0].offset > (hdrsize - sizeof(emptyfinfo))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (bcmp((u_int8_t*)buffer + adhdr->entries[0].offset, emptyfinfo, sizeof(emptyfinfo)) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(3, " extracting \"%s\" (32 bytes)", XATTR_FINDERINFO_NAME);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = fsetxattr(s->dst_fd, XATTR_FINDERINFO_NAME, (u_int8_t*)buffer + adhdr->entries[0].offset, sizeof(emptyfinfo), 0, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (error)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Extract the Resource Fork.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (adhdr->entries[1].type == AD_RESOURCE &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   adhdr->entries[1].length > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   void * rsrcforkdata = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t length;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   off_t offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct stat sb;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct timeval tval[2];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   length = adhdr->entries[1].length;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   offset = adhdr->entries[1].offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   rsrcforkdata = malloc(length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (rsrcforkdata == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_debug(1, "could not allocate %u bytes"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                             " for rsrcforkdata",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                          (unsigned int) length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto bad;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (fstat(s->dst_fd, &sb) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_debug(1, "couldn't stat destination file");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto bad;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   bytes = pread(s->src_fd, rsrcforkdata, length, offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (bytes < (ssize_t)length)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (bytes == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_debug(1, "couldn't read resource fork");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_debug(1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               "couldn't read resource fork (only read %d bytes of %d)",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               (int)bytes, (int)length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto bad;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = fsetxattr(s->dst_fd, XATTR_RESOURCEFORK_NAME, rsrcforkdata, bytes, 0, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (error)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * For filesystems that do not natively support named attributes,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * the kernel creates an AppleDouble file that -- for compatabilty
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * reasons -- has a resource fork containing nothing but a rsrcfork_header_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * structure that says there are no resources.  So, if fsetxattr has
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * failed, and the resource fork is that empty structure, *and* the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * target file is a directory, then we do nothing with it.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if ((bytes == sizeof(rsrcfork_header_t)) &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           ((sb.st_mode & S_IFMT) == S_IFDIR)  &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (memcmp(rsrcforkdata, &empty_rsrcfork_header, bytes) == 0)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_debug(2, "not setting empty resource fork on directory");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               error = errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               goto bad;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(1, "error %d setting resource fork attribute", error);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       goto bad;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(3, "extracting \"%s\" (%d bytes)",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               XATTR_RESOURCEFORK_NAME, (int)length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!(s->flags & COPYFILE_STAT))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       tval[0].tv_sec = sb.st_atime;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       tval[1].tv_sec = sb.st_mtime;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       tval[0].tv_usec = tval[1].tv_usec = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (futimes(s->dst_fd, tval))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("%s: set times", s->dst ? s->dst : "(null dst)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+bad:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (rsrcforkdata)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       free(rsrcforkdata);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_STAT & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = copyfile_stat(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (buffer) free(buffer);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return error;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_pack_quarantine(copyfile_state_t s, void **buf, ssize_t *len)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char qbuf[QTN_SERIALIZED_DATA_MAX];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t qlen = sizeof(qbuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->qinfo == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (qtn_file_to_data(s->qinfo, qbuf, &qlen) != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *buf = malloc(qlen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (*buf)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   memcpy(*buf, qbuf, qlen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   *len = qlen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+done:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_pack_acl(copyfile_state_t s, void **buf, ssize_t *len)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    acl_t acl = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *acl_text;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filesec_get_property(s->fsec, FILESEC_ACL, &acl) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (errno != ENOENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           copyfile_warn("getting acl");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   *len = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((acl_text = acl_to_text(acl, len)) != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * acl_to_text() doesn't include the NUL at the endo
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * in it's count (*len).  It does, however, promise to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * return a valid C string, so we need to up the count
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * by 1.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   *len = *len + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   *buf = malloc(*len);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (*buf)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       memcpy(*buf, acl_text, *len);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       *len = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_free(acl_text);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_debug(2, "copied acl (%ld) %p", *len, *buf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (acl)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_free(acl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_pack_rsrcfork(copyfile_state_t s, attr_header_t *filehdr)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t datasize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *databuf = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Get the resource fork size */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((datasize = fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, NULL, 0, 0, 0)) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("skipping attr \"%s\" due to error %d", XATTR_RESOURCEFORK_NAME, errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (datasize > INT_MAX) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   s->err = EINVAL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if ((databuf = malloc(datasize)) == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_warn("malloc");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (fgetxattr(s->src_fd, XATTR_RESOURCEFORK_NAME, databuf, datasize, 0, 0) != datasize)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("couldn't read entire resource fork");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Write the resource fork to disk. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (pwrite(s->dst_fd, databuf, datasize, filehdr->appledouble.entries[1].offset) != datasize)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("couldn't write resource fork");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    copyfile_debug(3, "copied %d bytes of \"%s\" data @ offset 0x%08x",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+              (int) datasize, XATTR_RESOURCEFORK_NAME,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+              filehdr->appledouble.entries[1].offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.entries[1].length = (u_int32_t)datasize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+done:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (databuf)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(databuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The opposite of copyfile_unpack(), obviously.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int copyfile_pack(copyfile_state_t s)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *attrnamebuf = NULL, *endnamebuf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    void *databuf = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    attr_header_t *filehdr, *endfilehdr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    attr_entry_t *entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t listsize = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char *nameptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t namelen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t entrylen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ssize_t datasize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    size_t offset = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int hasrsrcfork = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int error = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int seenq = 0; // Have we seen any quarantine info already?
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr = (attr_header_t *) calloc(1, ATTR_MAX_SIZE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filehdr == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_SIZE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (attrnamebuf == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   endnamebuf = ((char*)attrnamebuf) + ATTR_MAX_HDR_SIZE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Fill in the Apple Double Header defaults.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.magic              = ADH_MAGIC;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.version            = ADH_VERSION;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.numEntries         = 2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.entries[0].type    = AD_FINDERINFO;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.entries[0].offset  = (u_int32_t)offsetof(apple_double_header_t, finfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.entries[0].length  = FINDERINFOSIZE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.entries[1].type    = AD_RESOURCE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.entries[1].offset  = (u_int32_t)offsetof(apple_double_header_t, pad);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->appledouble.entries[1].length  = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    bcopy(ADH_MACOSX, filehdr->appledouble.filler, sizeof(filehdr->appledouble.filler));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Fill in the initial Attribute Header.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->magic       = ATTR_HDR_MAGIC;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->debug_tag   = (u_int32_t)s->sb.st_ino;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    filehdr->data_start  = (u_int32_t)sizeof(attr_header_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Collect the attribute names.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Test if there are acls to copy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_ACL & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   acl_t temp_acl = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (filesec_get_property(s->fsec, FILESEC_ACL, &temp_acl) < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(2, "no acl entries found (errno = %d)", errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       offset = strlen(XATTR_SECURITY_NAME) + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       strcpy(attrnamebuf, XATTR_SECURITY_NAME);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (temp_acl)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       acl_free(temp_acl);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (COPYFILE_XATTR & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ssize_t left = ATTR_MAX_HDR_SIZE - offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        if ((listsize = flistxattr(s->src_fd, attrnamebuf + offset, left, 0)) <= 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(2, "no extended attributes found (%d)", errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (listsize > left)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(1, "extended attribute list too long");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       listsize = left;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   listsize += offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   endnamebuf = attrnamebuf + listsize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (endnamebuf > (attrnamebuf + ATTR_MAX_HDR_SIZE)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (nameptr = attrnamebuf; nameptr < endnamebuf; nameptr += namelen)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       namelen = strlen(nameptr) + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* Skip over FinderInfo or Resource Fork names */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0 ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           seenq = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* The system should prevent this from happening, but... */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (namelen > XATTR_MAXNAMELEN + 1) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           namelen = XATTR_MAXNAMELEN + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       entry->namelen = namelen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       entry->flags = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (nameptr + namelen > endnamebuf) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       bcopy(nameptr, &entry->name[0], namelen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_debug(2, "copied name [%s]", entry->name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       entrylen = ATTR_ENTRY_LENGTH(namelen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       entry = (attr_entry_t *)(((char *)entry) + entrylen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if ((void*)entry >= (void*)endfilehdr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* Update the attributes header. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       filehdr->num_attrs++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       filehdr->data_start += (u_int32_t)entrylen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * If we have any quarantine data, we always pack it.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * But if we've already got it in the EA list, don't put it in again.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (s->qinfo && !seenq)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ssize_t left = ATTR_MAX_HDR_SIZE - offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* strlcpy returns number of bytes copied, but we need offset to point to the next byte */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   offset += strlcpy(attrnamebuf + offset, XATTR_QUARANTINE_NAME, left) + 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    seenq = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Collect the attribute data.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    entry = (attr_entry_t *)((char *)filehdr + sizeof(attr_header_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    for (nameptr = attrnamebuf; nameptr < attrnamebuf + listsize; nameptr += namelen + 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   namelen = strlen(nameptr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (strcmp(nameptr, XATTR_SECURITY_NAME) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_pack_acl(s, &databuf, &datasize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else if (s->qinfo && strcmp(nameptr, XATTR_QUARANTINE_NAME) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_pack_quarantine(s, &databuf, &datasize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* Check for Finder Info. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else if (strcmp(nameptr, XATTR_FINDERINFO_NAME) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       datasize = fgetxattr(s->src_fd, nameptr, (u_int8_t*)filehdr + filehdr->appledouble.entries[0].offset, 32, 0, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (datasize < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       } else if (datasize != 32)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn("unexpected size (%ld) for \"%s\"", datasize, nameptr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   copyfile_warn(" copied 32 bytes of \"%s\" data @ offset 0x%08x",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                       XATTR_FINDERINFO_NAME, filehdr->appledouble.entries[0].offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       continue;  /* finder info doesn't have an attribute entry */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* Check for Resource Fork. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   else if (strcmp(nameptr, XATTR_RESOURCEFORK_NAME) == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       hasrsrcfork = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       /* Just a normal attribute. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       datasize = fgetxattr(s->src_fd, nameptr, NULL, 0, 0, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (datasize == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (datasize < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("skipping attr \"%s\" due to error %d", nameptr, errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (datasize > XATTR_MAXATTRLEN)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+               copyfile_warn("skipping attr \"%s\" (too big)", nameptr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       databuf = malloc(datasize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       if (databuf == NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       datasize = fgetxattr(s->src_fd, nameptr, databuf, datasize, 0, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   entry->length = (u_int32_t)datasize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   entry->offset = filehdr->data_start + filehdr->data_length;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filehdr->data_length += (u_int32_t)datasize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * >>>  WARNING <<<
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * This assumes that the data is fits in memory (not
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * the case when there are lots of attributes or one of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * the attributes is very large.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (entry->offset > ATTR_MAX_SIZE ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (entry->offset + datasize > ATTR_MAX_SIZE)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           error = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           bcopy(databuf, (char*)filehdr + entry->offset, datasize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   free(databuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+next:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* bump to next entry */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   entrylen = ATTR_ENTRY_LENGTH(entry->namelen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   entry = (attr_entry_t *)((char *)entry + entrylen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filehdr->data_length > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* Now we know where the resource fork data starts. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* We also know the size of the "Finder Info entry. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filehdr->appledouble.entries[0].length =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   filehdr->total_size  = filehdr->appledouble.entries[1].offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Copy Resource Fork. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* Write the header to disk. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    datasize = filehdr->appledouble.entries[1].offset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    swap_adhdr(&filehdr->appledouble);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    swap_attrhdr(filehdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (pwrite(s->dst_fd, filehdr, datasize, 0) != datasize)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (COPYFILE_VERBOSE & s->flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       copyfile_warn("couldn't write file header");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   error = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto exit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+exit:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (filehdr) free(filehdr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (attrnamebuf) free(attrnamebuf);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (error)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return error;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return copyfile_stat(s);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* defined(_COPYFILE_TEST) || __MPLS_LIB_SUPPORT_COPYFILE_10_6__ */
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/quarantine.h b/src/quarantine.h
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..482f6c9
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/quarantine.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,70 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Building Apple's copyfile.c requires quarantine.h, which is not a published
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * header, and the "embedded" fallback appeared inappropriate.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This file (except this comment block) was taken from:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * https://github.com/samdmarshall/OSXPrivateSDK/blob/master/PrivateSDK10.10.sparse.sdk/usr/include/quarantine.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Other changes:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *   Removed inappropriate 'const' from _qtn_proc_to_data prototype.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifndef __quarantine_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __quarantine_h__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdint.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct _qtn_file_s *qtn_file_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct qtn_proc * qtn_proc_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define QTN_FLAG_SANDBOX 1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define QTN_FLAG_HARD 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern qtn_proc_t _qtn_proc_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern void _qtn_proc_set_identifier(qtn_proc_t qp, char *identifier);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern void _qtn_proc_set_flags(qtn_proc_t qp, int flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern void _qtn_proc_apply_to_self(qtn_proc_t qp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern void _qtn_proc_free(qtn_proc_t qp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern qtn_file_t _qtn_file_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern void _qtn_file_free(qtn_file_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern qtn_file_t _qtn_file_clone(qtn_file_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int _qtn_file_init_with_fd(qtn_file_t file, int fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int _qtn_file_apply_to_fd(qtn_file_t file, int fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int _qtn_file_init_with_path(qtn_file_t file, const char *path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int _qtn_file_init_with_data(qtn_file_t file, const void *, size_t);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int _qtn_file_to_data(qtn_file_t file, void *, size_t*);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int _qtn_file_apply_to_path(qtn_file_t qf, char *path);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern const char *_qtn_error(int err);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern const char *_qtn_xattr_name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int _qtn_proc_to_data(void * spawn_quarantine, char *qbuf,size_t *qbuf_sz);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define QTN_SERIALIZED_DATA_MAX 4096
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_alloc _qtn_file_alloc
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_free _qtn_file_free
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_clone _qtn_file_clone
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_init_with_fd _qtn_file_init_with_fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_apply_to_fd _qtn_file_apply_to_fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_init_with_path _qtn_file_init_with_path
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_init_with_data _qtn_file_init_with_data
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_file_to_data _qtn_file_to_data
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_error _qtn_error
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_xattr_name _qtn_xattr_name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define qtn_proc_to_data _qtn_proc_to_data
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span>\ No newline at end of file
</pre><pre style='margin:0'>

</pre>