<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>