]> git.saurik.com Git - apple/copyfile.git/commitdiff
copyfile-118.1.2.tar.gz os-x-1010 os-x-10101 os-x-10102 os-x-10103 os-x-10104 os-x-10105 v118.1.2
authorApple <opensource@apple.com>
Thu, 28 Aug 2014 21:33:35 +0000 (21:33 +0000)
committerApple <opensource@apple.com>
Thu, 28 Aug 2014 21:33:35 +0000 (21:33 +0000)
copyfile.c
copyfile.h
copyfile.xcodeproj/project.pbxproj
copyfile_private.h
xattr_flags.c [new file with mode: 0644]
xattr_flags.h [new file with mode: 0644]
xattr_name_with_flags.3 [new file with mode: 0644]
xattr_properties.c [deleted file]
xattr_properties.h
xcodescripts/copyfile.xcconfig [new file with mode: 0644]
xcodescripts/install_files.sh

index 09d6305a597aaa3c28e27b72e9e475a072d2d587..99f26fcdb7b545ee77cb72182842d586c7c358c3 100644 (file)
@@ -72,7 +72,7 @@ static void *qtn_file_clone(void *x) { return NULL; }
 
 #include "copyfile.h"
 #include "copyfile_private.h"
-#include "xattr_properties.h"
+#include "xattr_flags.h"
 
 enum cfInternalFlags {
        cfDelayAce = 1 << 0,
@@ -109,7 +109,7 @@ struct _copyfile_state
     off_t totalCopied;
     int err;
     char *xattr_name;
-    CopyOperationIntent_t copyIntent;
+    xattr_operation_intent_t copyIntent;
 };
 
 struct acl_entry {
@@ -2105,7 +2105,8 @@ goto exit;
 static int copyfile_stat(copyfile_state_t s)
 {
     struct timeval tval[2];
-    unsigned int added_flags = 0;
+    unsigned int added_flags = 0, dst_flags = 0;
+    struct stat dst_sb;
 
     /*
      * NFS doesn't support chflags; ignore errors as a result, since
@@ -2114,7 +2115,18 @@ static int copyfile_stat(copyfile_state_t s)
     if (s->internal_flags & cfMakeFileInvisible)
        added_flags |= UF_HIDDEN;
 
-    (void)fchflags(s->dst_fd, (u_int)s->sb.st_flags | added_flags);
+    /*
+    * We need to check if SF_RESTRICTED was set on the destination
+    * by the kernel.  If it was, don't drop it.
+    */
+    if (fstat(s->dst_fd, &dst_sb))
+       return -1;
+    if (dst_sb.st_flags & SF_RESTRICTED)
+       added_flags |= SF_RESTRICTED;
+
+    /* Copy file flags, masking out any we don't want to preserve */
+    dst_flags = (s->sb.st_flags & ~COPYFILE_OMIT_FLAGS) | added_flags;
+    (void)fchflags(s->dst_fd, dst_flags);
 
     /* If this fails, we don't care */
     (void)fchown(s->dst_fd, s->sb.st_uid, s->sb.st_gid);
@@ -2288,9 +2300,49 @@ static int copyfile_xattr(copyfile_state_t s)
            if (OSSwapLittleToHostInt32(hdr->compression_magic) != DECMPFS_MAGIC) {
                continue;
            }
-           if (OSSwapLittleToHostInt32(hdr->compression_type) != 3 &&
-               OSSwapLittleToHostInt32(hdr->compression_type) != 4) {
-               continue;
+           /*
+            * From AppleFSCompression documentation:
+            * "It is incumbent on the aware copy engine to identify
+            *  the type of compression being used, and to perform an
+            *  unaware copy of any file it does not recognize."
+            *
+            * Compression Types are defined in:
+            * "AppleFSCompression/Common/compressorCommon.h"
+            *
+            * Unfortunately, they don't provide a way to dynamically
+            * determine what possible compression_type values exist,
+            * so we have to update this every time a new compression_type
+            * is added (Types 7->10 were added in Yosemite)
+            *
+            * Ubiquity faulting file compression type 0x80000001 are
+            * deprecated as of Yosemite, per rdar://17714998 don't copy the
+            * decmpfs xattr on these files, zero byte files are safer
+            * than a fault nobody knows how to handle.
+            */
+           switch (OSSwapLittleToHostInt32(hdr->compression_type)) {
+               case 3: /* zlib-compressed data in xattr */
+               case 4: /* 64k chunked zlib-compressed data in resource fork */
+
+               case 7: /* LZVN-compressed data in xattr */
+               case 8: /* 64k chunked LZVN-compressed data in resource fork */
+
+               case 9: /* uncompressed data in xattr (similar to but not identical to CMP_Type1) */
+               case 10: /* 64k chunked uncompressed data in resource fork */
+
+                       /* valid compression type, we want to copy. */
+                       break;
+                
+               case 5: /* specifies de-dup within the generation store. Don't copy decmpfs xattr. */
+                       copyfile_debug(3, "compression_type <5> on attribute com.apple.decmpfs for src file %s is not copied.",
+                                     s->src ? s->src : "(null string)");
+                       continue;
+
+               case 6: /* unused */
+               case 0x80000001: /* faulting files are deprecated, don't copy decmpfs xattr */
+               default:
+                       copyfile_warn("Invalid compression_type <%d> on attribute %s for src file %s",
+                                     OSSwapLittleToHostInt32(hdr->compression_type), name, s->src ? s->src : "(null string)");
+                       continue;
            }
            s->internal_flags |= cfSawDecmpEA;
        }
@@ -2298,7 +2350,7 @@ static int copyfile_xattr(copyfile_state_t s)
 
        // If we have a copy intention stated, and the EA is to be ignored, we ignore it
        if (s->copyIntent
-           && _PreserveEA(name, s->copyIntent) == 0)
+           && xattr_preserve_for_intent(name, s->copyIntent) == 0)
                continue;
 
        s->xattr_name = strdup(name);
@@ -2412,7 +2464,7 @@ int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
 #endif
 #ifdef COPYFILE_STATE_INTENT
        case COPYFILE_STATE_INTENT:
-           *(CopyOperationIntent_t*)ret = s->copyIntent;
+           *(xattr_operation_intent_t*)ret = s->copyIntent;
           break;
 #endif
        default:
@@ -2488,7 +2540,7 @@ int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
 #endif
 #ifdef COPYFILE_STATE_INTENT
        case COPYFILE_STATE_INTENT:
-           s->copyIntent = *(CopyOperationIntent_t*)thing;
+           s->copyIntent = *(xattr_operation_intent_t*)thing;
           break;
 #endif
        default:
@@ -3238,7 +3290,7 @@ acl_done:
            else
            {
                if (s->copyIntent ||
-                   _PreserveEA((char*)entry->name, s->copyIntent) == 1) {
+                   xattr_preserve_for_intent((char*)entry->name, s->copyIntent) == 1) {
                        if (s->statuscb) {
                                int rv;
                                s->xattr_name = strdup((char*)entry->name);
@@ -3793,7 +3845,7 @@ static int copyfile_pack(copyfile_state_t s)
                namelen = XATTR_MAXNAMELEN + 1;
            }
            if (s->copyIntent &&
-               _PreserveEA(nameptr, s->copyIntent) == 0) {
+               xattr_preserve_for_intent(nameptr, s->copyIntent) == 0) {
                    // Skip it
                    size_t amt = endnamebuf - (nameptr + namelen);
                    memmove(nameptr, nameptr + namelen, amt);
@@ -3807,7 +3859,7 @@ static int copyfile_pack(copyfile_state_t s)
                int rv;
                char eaname[namelen];
                bcopy(nameptr, eaname, namelen);
-               eaname[namelen] = 0; // Just to be sure!
+               eaname[namelen - 1] = 0; // Just to be sure!
                s->xattr_name = eaname;
                rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
                s->xattr_name = NULL;
index 59c198a5b4ca79dcef24bb1b24fbfcfedc88c7ab..91dfe87aac2ce51f699f17a6ca91e87e00cbfb3d 100644 (file)
 #define _COPYFILE_H_
 
 /*
- * this is an API to faciliatate copying of files and their
- * associated metadata.  There are several open source projects that
- * need modifications to support preserving extended attributes and
- * acls and this API collapses several hundred lines of modifications
- * into one or two calls.
- *
- * This implementation is incomplete and the interface may change in a 
- * future release.
+ * This API facilitates the copying of files and their associated
+ * metadata.  There are several open source projects that need
+ * modifications to support preserving extended attributes and ACLs
+ * and this API collapses several hundred lines of modifications into
+ * one or two calls.
  */
 
 /* private */
index 04b9858d9cc5e5f94bd92a8d003f8e1123e3debc..c125959761378e5ff7488d11f658b27eff713c94 100644 (file)
@@ -7,22 +7,25 @@
        objects = {
 
 /* Begin PBXBuildFile section */
-               72406E631676C3C80099568B /* xattr_properties.c in Sources */ = {isa = PBXBuildFile; fileRef = 72406E621676C3C80099568B /* xattr_properties.c */; };
+               72406E631676C3C80099568B /* xattr_flags.c in Sources */ = {isa = PBXBuildFile; fileRef = 72406E621676C3C80099568B /* xattr_flags.c */; };
                72B4C0F41676C47D00C13E05 /* copyfile_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B4C0F31676C47D00C13E05 /* copyfile_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               72EAA3B016A72F4500833E98 /* xattr_properties.h in Headers */ = {isa = PBXBuildFile; fileRef = 72EAA3AF16A72F4500833E98 /* xattr_properties.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               72EAA3B016A72F4500833E98 /* xattr_flags.h in Headers */ = {isa = PBXBuildFile; fileRef = 72EAA3AF16A72F4500833E98 /* xattr_flags.h */; settings = {ATTRIBUTES = (Public, ); }; };
+               86EF9F0A1834018C00AAB3F3 /* xattr_properties.h in Headers */ = {isa = PBXBuildFile; fileRef = 86EF9F091834018C00AAB3F3 /* xattr_properties.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FCCE17C3135A658F002CEE6D /* copyfile.c in Sources */ = {isa = PBXBuildFile; fileRef = FCCE17C1135A658F002CEE6D /* copyfile.c */; };
                FCCE17C4135A658F002CEE6D /* copyfile.h in Headers */ = {isa = PBXBuildFile; fileRef = FCCE17C2135A658F002CEE6D /* copyfile.h */; settings = {ATTRIBUTES = (Public, ); }; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
-               72406E621676C3C80099568B /* xattr_properties.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xattr_properties.c; sourceTree = "<group>"; };
+               3F1EFD4C185C4EB400D1C970 /* copyfile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = copyfile.xcconfig; path = xcodescripts/copyfile.xcconfig; sourceTree = "<group>"; };
+               72406E621676C3C80099568B /* xattr_flags.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xattr_flags.c; sourceTree = "<group>"; };
                72B4C0F31676C47D00C13E05 /* copyfile_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = copyfile_private.h; sourceTree = "<group>"; };
-               72EAA3AF16A72F4500833E98 /* xattr_properties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xattr_properties.h; sourceTree = "<group>"; };
+               72EAA3AF16A72F4500833E98 /* xattr_flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xattr_flags.h; sourceTree = "<group>"; };
+               861E1C14180F0AF900E65B9A /* xattr_name_with_flags.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = xattr_name_with_flags.3; sourceTree = "<group>"; };
+               86EF9F091834018C00AAB3F3 /* xattr_properties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xattr_properties.h; sourceTree = "<group>"; };
                FCCE17BB135A6444002CEE6D /* libcopyfile.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcopyfile.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                FCCE17C0135A658F002CEE6D /* copyfile.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = copyfile.3; sourceTree = "<group>"; };
                FCCE17C1135A658F002CEE6D /* copyfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = copyfile.c; sourceTree = "<group>"; };
                FCCE17C2135A658F002CEE6D /* copyfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = copyfile.h; sourceTree = "<group>"; };
-               FCCE17C5135A659B002CEE6D /* BSD.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = BSD.xcconfig; path = Makefiles/CoreOS/Xcode/BSD.xcconfig; sourceTree = DEVELOPER_DIR; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                FCCE17AB135A5FFB002CEE6D = {
                        isa = PBXGroup;
                        children = (
+                               3F1EFD4C185C4EB400D1C970 /* copyfile.xcconfig */,
+                               861E1C14180F0AF900E65B9A /* xattr_name_with_flags.3 */,
                                72B4C0F31676C47D00C13E05 /* copyfile_private.h */,
-                               72EAA3AF16A72F4500833E98 /* xattr_properties.h */,
-                               72406E621676C3C80099568B /* xattr_properties.c */,
+                               72EAA3AF16A72F4500833E98 /* xattr_flags.h */,
+                               72406E621676C3C80099568B /* xattr_flags.c */,
                                FCCE17C0135A658F002CEE6D /* copyfile.3 */,
                                FCCE17C1135A658F002CEE6D /* copyfile.c */,
+                               86EF9F091834018C00AAB3F3 /* xattr_properties.h */,
                                FCCE17C2135A658F002CEE6D /* copyfile.h */,
-                               FCCE17C5135A659B002CEE6D /* BSD.xcconfig */,
                                FCCE17BC135A6444002CEE6D /* Products */,
                        );
                        sourceTree = "<group>";
@@ -66,8 +71,9 @@
                        buildActionMask = 2147483647;
                        files = (
                                FCCE17C4135A658F002CEE6D /* copyfile.h in Headers */,
+                               72EAA3B016A72F4500833E98 /* xattr_flags.h in Headers */,
                                72B4C0F41676C47D00C13E05 /* copyfile_private.h in Headers */,
-                               72EAA3B016A72F4500833E98 /* xattr_properties.h in Headers */,
+                               86EF9F0A1834018C00AAB3F3 /* xattr_properties.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                FCCE17C3135A658F002CEE6D /* copyfile.c in Sources */,
-                               72406E631676C3C80099568B /* xattr_properties.c in Sources */,
+                               72406E631676C3C80099568B /* xattr_flags.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
 /* Begin XCBuildConfiguration section */
                FCCE17B3135A5FFB002CEE6D /* Release */ = {
                        isa = XCBuildConfiguration;
-                       baseConfigurationReference = FCCE17C5135A659B002CEE6D /* BSD.xcconfig */;
+                       baseConfigurationReference = 3F1EFD4C185C4EB400D1C970 /* copyfile.xcconfig */;
                        buildSettings = {
                                GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                                GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
                FCCE17BD135A6444002CEE6D /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               BUILD_VARIANTS = (
-                                       normal,
-                                       debug,
-                               );
-                               DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)";
                                EXECUTABLE_PREFIX = lib;
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = "__DARWIN_NOW_CANCELABLE=1";
-                               INSTALL_PATH = /usr/lib/system;
-                               "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/lib/system";
                                LINK_WITH_STANDARD_LIBRARIES = NO;
                                OTHER_LDFLAGS = (
                                        "-Wl,-umbrella,System",
                                        "-lquarantine",
                                        "-lsystem_asl",
                                        "-lsystem_info",
+                                       "-lxpc",
+                                       "-ldispatch",
                                );
                                "OTHER_LDFLAGS[sdk=iphoneos*]" = (
                                        "-Wl,-umbrella,System",
                                        "-lsystem_blocks",
                                        "-lsystem_asl",
                                        "-lsystem_info",
+                                       "-ldispatch",
+                                       "-lxpc",
                                );
                                "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
                                        "-Wl,-umbrella,System",
                                        "-L/usr/lib/system",
-                                       "-ldyld_sim",
-                                       "-lcompiler_rt_sim",
+                                       "-ldyld",
+                                       "-lcompiler_rt",
+                                       "-lsystem_sim_kernel",
+                                       "-lsystem_malloc",
                                        "-lsystem_sim_c",
                                        "-lsystem_sim_blocks",
+                                       "-lsystem_sim_asl",
                                        "-lsystem_sim_info",
-                                       "-Wl,-upward-lSystem",
+                                       "-ldispatch",
+                                       "-lxpc",
                                );
-                               "PRIVATE_HEADERS_FOLDER_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/local/include";
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               "PRODUCT_NAME[sdk=iphonesimulator*]" = copyfile_sim;
-                               PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
-                               "PUBLIC_HEADERS_FOLDER_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/include";
                                WARNING_CFLAGS = (
                                        "-Wall",
                                        "-Wextra",
index 8f805d9981ebd365f6cb3f0b9eb3fbdee68316dc..0111e0d750bc82cafb3cbc60ab9dc1ef5e2e2ca5 100644 (file)
@@ -30,4 +30,9 @@
  */
 # define COPYFILE_STATE_INTENT 256
 
+/*
+ * File flags that are not preserved when copying stat information.
+ */
+#define COPYFILE_OMIT_FLAGS    (UF_TRACKED | SF_RESTRICTED)
+
 #endif /* _COPYFILE_PRIVATE_H */
diff --git a/xattr_flags.c b/xattr_flags.c
new file mode 100644 (file)
index 0000000..8e8fd05
--- /dev/null
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2013 Apple, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <dispatch/dispatch.h>
+#include <xpc/private.h>
+
+#include <xattr_flags.h>
+
+#define FLAG_DELIM_CHAR        '#'
+#define FLAG_DELIM_STR "#"
+
+/*
+ * Some default propeteries for EAs we know about internally.
+ */
+struct defaultList {
+       const char *eaName;
+       const char *propList;
+       int flags;      // See below
+};
+
+#define propFlagsPrefix        0x0001  // The name is a prefix, so only look at that part
+
+static const struct defaultList *defaultPropertyTable = NULL;
+
+static const struct defaultList
+defaultUnboxedPropertyTable[] = {
+       { "com.apple.quarantine", "PCS", 0 },   // not public
+       { "com.apple.TextEncoding", "CS", 0 },  // Content-dependent, public
+       { "com.apple.metadata:", "PS", propFlagsPrefix },       // Don't export, keep for copy & safe save
+       { "com.apple.security.", "S", propFlagsPrefix },
+       { XATTR_RESOURCEFORK_NAME, "PCS", 0 },  // Don't keep for safe save
+       { XATTR_FINDERINFO_NAME, "PCS", 0 },    // Same as ResourceFork
+       { 0, 0, 0 },
+};
+
+static const struct defaultList
+defaultSandboxedPropertyTable[] = {
+    { "com.apple.quarantine", "PCS", 0 },      // not public
+    { "com.apple.TextEncoding", "CS", 0 },     // Content-dependent, public
+    { "com.apple.metadata:", "PS", propFlagsPrefix },  // Don't export, keep for copy & safe save
+    { "com.apple.security.", "N", propFlagsPrefix },
+    { XATTR_RESOURCEFORK_NAME, "PCS", 0 },     // Don't keep for safe save
+    { XATTR_FINDERINFO_NAME, "PCS", 0 },       // Same as ResourceFork
+    { 0, 0, 0 },
+};
+
+/*
+ * The property lists on an EA are set by having a suffix character,
+ * and then a list of characters.  In general, we're choosing upper-case
+ * to indicate the property is set, and lower-case to indicate it's to be
+ * cleared.
+ */
+struct propertyListMapping {
+       char enable;    // Character to enable
+       char disable;   // Character to disable -- usually lower-case of enable
+       xattr_operation_intent_t        value;
+};
+static const struct propertyListMapping
+PropertyListMapTable[] = {
+       { 'C', 'c', XATTR_FLAG_CONTENT_DEPENDENT },
+       { 'P', 'p', XATTR_FLAG_NO_EXPORT },
+       { 'N', 'n', XATTR_FLAG_NEVER_PRESERVE },
+       { 'S', 's', XATTR_FLAG_SYNCABLE },
+       { 0, 0, 0 },
+};
+       
+/*
+ * Given a converted property list (that is, converted to the
+ * xattr_operation_intent_t type), and an intent, determine if
+ * it should be preserved or not.
+ *
+ * I've chosen to use a block instead of a simple mask on the belief
+ * that the question may be moderately complex.  If it ends up not being
+ * so, then this can simply be turned into a mask of which bits to check
+ * as being exclusionary.
+ */
+static const struct divineIntent {
+       xattr_operation_intent_t intent;
+       int (^checker)(xattr_flags_t);
+} intentTable[] = {
+       { XATTR_OPERATION_INTENT_COPY, ^(xattr_flags_t flags) {
+                       if (flags & XATTR_FLAG_NEVER_PRESERVE)
+                               return 0;
+                       return 1;
+               } },
+       { XATTR_OPERATION_INTENT_SAVE, ^(xattr_flags_t flags) {
+                       if (flags & (XATTR_FLAG_CONTENT_DEPENDENT | XATTR_FLAG_NEVER_PRESERVE))
+                               return 0;
+                       return 1;
+               } },
+       { XATTR_OPERATION_INTENT_SHARE, ^(xattr_flags_t flags) {
+                       if ((flags & (XATTR_FLAG_NO_EXPORT | XATTR_FLAG_NEVER_PRESERVE)) != 0)
+                               return 0;
+                       return 1;
+               } },
+       { XATTR_OPERATION_INTENT_SYNC, ^(xattr_flags_t flags) {
+                       return (flags & (XATTR_FLAG_SYNCABLE | XATTR_FLAG_NEVER_PRESERVE)) == XATTR_FLAG_SYNCABLE;
+               } },
+       { 0, 0 },
+};
+
+
+/*
+ * If an EA name is in the default list, find it, and return the property
+ * list string for it.
+ */
+static const char *
+nameInDefaultList(const char *eaname)
+{
+       const struct defaultList *retval;
+       static dispatch_once_t onceToken;
+    
+       dispatch_once(&onceToken, ^{
+               if (_xpc_runtime_is_app_sandboxed()) {
+                       defaultPropertyTable = defaultSandboxedPropertyTable;
+               } else {
+                       defaultPropertyTable = defaultUnboxedPropertyTable;
+               }
+       });
+
+       for (retval = defaultPropertyTable; retval->eaName; retval++) {
+               if ((retval->flags & propFlagsPrefix) != 0 &&
+                   strncmp(retval->eaName, eaname, strlen(retval->eaName)) == 0)
+                       return retval->propList;
+               if (strcmp(retval->eaName, eaname) == 0)
+                       return retval->propList;
+       }
+       return NULL;
+}
+
+/*
+ * Given an EA name, see if it has a property list in it, and
+ * return a pointer to it.  All this is doing is looking for
+ * the delimiter, and returning the string after that.  Returns
+ * NULL if the delimiter isn't found.  Note that an empty string
+ * is a valid property list, as far as we're concerned.
+ */
+static const char *
+findPropertyList(const char *eaname)
+{
+       const char *ptr = strrchr(eaname, '#');
+       if (ptr)
+               return ptr+1;
+       return NULL;
+}
+
+/*
+ * Convert a property list string (e.g., "pCd") into a
+ * xattr_operation_intent_t type.
+ */
+static xattr_operation_intent_t
+stringToProperties(const char *proplist)
+{
+       xattr_operation_intent_t retval = 0;
+       const char *ptr;
+
+       // A switch would be more efficient, but less generic.
+       for (ptr = proplist; *ptr; ptr++) {
+               const struct propertyListMapping *mapPtr;
+               for (mapPtr = PropertyListMapTable; mapPtr->enable; mapPtr++) {
+                       if (*ptr == mapPtr->enable) {
+                               retval |= mapPtr->value;
+                       } else if (*ptr == mapPtr->disable) {
+                               retval &= ~mapPtr->value;
+                       }
+               }
+       }
+       return retval;
+}
+
+/*
+ * Given an EA name (e.g., "com.apple.lfs.hfs.test"), and a
+ * xattr_operation_intent_t value (it's currently an integral value, so
+ * just a bitmask), cycle through the list of known properties, and return
+ * a string with the EA name, and the property list appended.  E.g., we
+ * might return "com.apple.lfs.hfs.test#pD".
+ *
+ * The tricky part of this funciton is that it will not append any letters
+ * if the value is only the default properites.  In that case, it will copy
+ * the EA name, and return that.
+ *
+ * It returns NULL if there was an error.  The two errors right now are
+ * no memory (strdup failed), in which case it will set errno to ENOMEM; and
+ * the resulting EA name is longer than XATTR_MAXNAMELEN, in which case it
+ * sets errno to ENAMETOOLONG.
+ *
+ * (Note that it also uses ENAMETOOLONG if the buffer it's trying to set
+ * gets too large.  I honestly can't see how that would happen, but it's there
+ * for sanity checking.  That would require having more than 64 bits to use.)
+ */
+char *
+xattr_name_with_flags(const char *orig, xattr_flags_t propList)
+{
+       char *retval = NULL;
+       char suffix[66] = { 0 }; // 66:  uint64_t for property types, plus '#', plus NUL
+       char *cur = suffix;
+       const struct propertyListMapping *mapPtr;
+
+       *cur++ = '#';
+       for (mapPtr = PropertyListMapTable; mapPtr->enable; mapPtr++) {
+               if ((propList & mapPtr->value) != 0) {
+                       *cur++ = mapPtr->enable;
+               }
+               if (cur >= (suffix + sizeof(suffix))) {
+                       errno = ENAMETOOLONG;
+                       return NULL;
+               }
+
+       }
+       
+               
+       if (cur == suffix + 1) {
+               // No changes made
+               retval = strdup(orig);
+               if (retval == NULL)
+                       errno = ENOMEM;
+       } else {
+               const char *defaultEntry = NULL;
+               if ((defaultEntry = nameInDefaultList(orig)) != NULL &&
+                   strcmp(defaultEntry, suffix + 1) == 0) {
+                       // Just use the name passed in
+                       retval = strdup(orig);
+               } else {
+                       asprintf(&retval, "%s%s", orig, suffix);
+               }
+               if (retval == NULL) {
+                       errno = ENOMEM;
+               } else {
+                       if (strlen(retval) > XATTR_MAXNAMELEN) {
+                               free(retval);
+                               retval = NULL;
+                               errno = ENAMETOOLONG;
+                       }
+               }
+       }
+       return retval;
+}
+
+char *
+xattr_name_without_flags(const char *eaname)
+{
+       char *retval = NULL;
+       char *tmp;
+
+       if ((tmp = strrchr(eaname, FLAG_DELIM_CHAR)) == NULL) {
+               retval = strdup(eaname);
+       } else {
+               retval = calloc(tmp - eaname + 1, 1);
+               if (retval) {
+                       strlcpy(retval, eaname, tmp - eaname + 1);
+               }
+       }
+       if (retval == NULL) {
+               errno = ENOMEM;
+       }
+       return retval;
+}
+
+int
+xattr_intent_with_flags(xattr_operation_intent_t intent, xattr_flags_t flags)
+{
+       const struct divineIntent *ip;
+
+       for (ip = intentTable; ip->intent; ip++) {
+               if (ip->intent == intent) {
+                       return ip->checker(flags);
+               }
+       }
+       if ((flags & XATTR_FLAG_NEVER_PRESERVE) != 0)
+               return 0;       // Special case, don't try to copy this one
+
+       return 1;       // Default
+}
+
+xattr_flags_t
+xattr_flags_from_name(const char *eaname)
+{
+       xattr_flags_t retval = 0;
+       const char *propList;
+
+       propList = findPropertyList(eaname);
+       if (propList == NULL) {
+               propList = nameInDefaultList(eaname);
+       }
+       if (propList != NULL) {
+               retval = stringToProperties(propList);
+       }
+       
+       return retval;
+}
+
+/*
+ * Indicate whether an EA should be preserved, when using the
+ * given intent.
+ * 
+ * This returns 0 if it should not be preserved, and 1 if it should.
+ * 
+ * It simply looks through the tables we have above, and compares the
+ * xattr_operation_intent_t for the EA with the intent.  If the
+ * EA doesn't have any properties, and it's not on the default list, the
+ * default is to preserve it.
+ */
+
+int
+xattr_preserve_for_intent(const char *eaname, xattr_operation_intent_t intent)
+{
+       xattr_flags_t flags = xattr_flags_from_name(eaname);
+
+       return xattr_intent_with_flags(intent, flags);
+}
+
+#include "xattr_properties.h"
diff --git a/xattr_flags.h b/xattr_flags.h
new file mode 100644 (file)
index 0000000..032b6ad
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013 Apple, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _XATTR_FLAGS_H
+#define _XATTR_FLAGS_H
+
+#include <stdint.h>
+
+#include <sys/cdefs.h>
+#include <Availability.h>
+
+__BEGIN_DECLS
+
+/*
+ * xattr_operation_intent_t is used to declare what the intent of the copy is.
+ * Not a bit-field (for now, at least).
+ *
+ * XATTR_OPERATION_INTENT_COPY indicates that the EA is attached to an object
+ * that is simply being copied.  E.g., cp src dst
+ *
+ * XATTR_OPERATION_INTENT_SAVE indicates that the EA is attached to an object
+ * being saved; as in a "safe save," the destination is being replaced by
+ * the source, so the question is whether the EA should be applied to the
+ * destination, or generated anew.
+ *
+ * XATTR_OPERATION_INTENT_SHARE  indicates that the EA is attached to an object that
+ * is being given out to other people.  For example, saving to a public folder,
+ * or attaching to an email message.
+ *
+ * XATTR_OPERATION_INTENT_SYNC  indicates that the EA is attached to an object that
+ * is being synced to other storages for the same user.  For example synced to
+ * iCloud.
+ */
+
+#define XATTR_OPERATION_INTENT_COPY    1
+#define XATTR_OPERATION_INTENT_SAVE    2
+#define XATTR_OPERATION_INTENT_SHARE   3
+#define XATTR_OPERATION_INTENT_SYNC    4
+
+typedef unsigned int xattr_operation_intent_t;
+
+typedef uint64_t xattr_flags_t;
+
+/*
+ * Various properties used to determine how to handle the xattr during
+ * copying.  The intent is that the default is reasonable for most xattrs.
+ */
+
+/*
+ * XATTR_FLAG_NO_EXPORT
+ * Declare that the extended property should not be exported; this is
+ * deliberately a bit vague, but this is used by XATTR_OPERATION_INTENT_SHARE
+ * to indicate not to preserve the xattr.
+ */
+#define XATTR_FLAG_NO_EXPORT   ((xattr_flags_t)0x0001)
+
+/*
+ * XATTR_FLAG_CONTENT_DEPENDENT
+ * Declares the extended attribute to be tied to the contents of the file (or
+ * vice versa), such that it should be re-created when the contents of the
+ * file change.  Examples might include cryptographic keys, checksums, saved
+ * position or search information, and text encoding.
+ *
+ * This property causes the EA to be preserved for copy and share, but not for
+ * safe save.  (In a safe save, the EA exists on the original, and will not
+ * be copied to the new version.)
+ */
+#define        XATTR_FLAG_CONTENT_DEPENDENT    ((xattr_flags_t)0x0002)
+
+/*
+ * XATTR_FLAG_NEVER_PRESERVE
+ * Declares that the extended attribute is never to be copied, for any
+ * intention type.
+ */
+#define XATTR_FLAG_NEVER_PRESERVE      ((xattr_flags_t)0x0004)
+
+/*
+ * XATTR_FLAG_SYNCABLE
+ * Declares that the extended attribute is to be synced, used by the
+ * XATTR_OPERATION_ITENT_SYNC intention.  Syncing tends to want to minimize the
+ * amount of metadata synced around, hence the default behavior is for the EA
+ * NOT to be synced, even if it would else be preserved for the
+ * XATTR_OPERATION_ITENT_COPY intention.
+ */
+#define XATTR_FLAG_SYNCABLE    ((xattr_flags_t)0x0008)
+
+/* Given a named extended attribute, and a copy intent, should the EA be preserved? */
+extern int xattr_preserve_for_intent(const char *, xattr_operation_intent_t) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0);
+
+/*
+ * Given an extended attribute name, and a set of properties, return an
+ *  allocated C string with the name.  This will return NULL on error;
+ * errno may be set to ENOMEM if the new name cannot be allocated, or
+ * ENAMETOOLONG if the new name is longer than the maximum for EAs (127 UTF8
+ * characters).  The caller must deallocate the return value otherwise.
+ *
+ * If no properties are set, it returns a copy of the EA name.
+ *
+ * If the EA name is in the internal list, and the properties are the same as
+ * defined there, then it will also return an unmodified copy of the EA name.
+ */
+extern char *xattr_name_with_flags(const char *, xattr_flags_t) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0);
+
+/*
+ * Given an extended attribute name, which may or may not have properties encoded
+ * as a suffix, return just the name of the attribute.  E.g., com.example.mine#P
+ * would return "com.example.mine".  The return value will be NULL on error;
+ * errno will be set to ENOMEM if it cannot be allocated.  The caller must deallocate
+ * the return value.
+ */
+extern char *xattr_name_without_flags(const char *) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0);
+
+/*
+ * Given an EA name, return the properties.  If the name is in the internal list,
+ * those properties will be returned.  Unknown property encodings are ignored.
+ */
+extern xattr_flags_t xattr_flags_from_name(const char *) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0);
+
+/*
+ * Given an xattr_operation_intent_t and an xattr_flags_t, return whether it should
+ * be preserved.  The default (in case either flags or intent is 0, or unknown
+ * values) is to return 1; it only returns 0 if the flags and intent indicate it
+ * should not be preserved.
+ */
+extern int xattr_intent_with_flags(xattr_operation_intent_t, xattr_flags_t) __OSX_AVAILABLE_STARTING( __MAC_10_10, __IPHONE_8_0);
+
+__END_DECLS
+
+#endif /* _XATTR_FLAGS_H */
diff --git a/xattr_name_with_flags.3 b/xattr_name_with_flags.3
new file mode 100644 (file)
index 0000000..509f8b1
--- /dev/null
@@ -0,0 +1,123 @@
+.\"
+.\" Copyright (c) 2013 Apple Computer, Inc.  All rights reserved.
+.\"
+.Dd October 7, 2013
+.Dt XATTR_NAME_WITH_FLAGS 3
+.Os
+.Sh NAME
+.Nm xattr_preserve_for_intent , xattr_name_with_flags , xattr_name_without_flags ,
+.Nm xattr_flags_from_name , xattr_intent_with_flags
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In xattr_properties.h
+.Ft int
+.Fn xattr_preserve_for_intent "const char *" "xattr_operation_intent_t"
+.Ft char *
+.Fn xattr_name_with_flags "const char *" "xattr_flags_t"
+.Ft char *
+.Fn xattr_name_without_flags "const char *"
+.Ft xattr_flags_t
+.Fn xattr_flags_from_name "const char *"
+.Ft int
+.Fn xattr_intent_with_flags "xattr_operation_intent_t" "xattr_flags_t"
+.Sh DESCRIPTION
+These functions are used in conjunction with copying extended attributes from
+one file to another.  Various types of copying (an "intent") check flags to
+determine which is allowed or not.
+.Pp
+The
+.Fn xattr_name_with_flags
+function returns an extended attribute name with the appropriate flags encoded
+as a string; the
+.Fn xattr_name_without_flags
+undoes this, giving the name of the extended attribute without the flags
+encoding.  The slight inverse of that is
+.Fn xattr_flags_from_name ,
+which will return the flags encoded in a name.
+.Pp
+The values returned by
+.Fn xattr_name_with_flags
+and
+.Fn xattr_name_without_flags
+are allocated using
+.Xr malloc 3 ,
+and should be released by the caller, using
+.Xr free 3 .
+.Pp
+These functions also have an internal table of pre-defined names, maintained
+by the operating system.
+.Pp
+The function
+.Fn xattr_intent_with_flags
+will return 0 if the
+.Ar flags
+argument indicates it should not be preserved for the given
+intent, or 1 if it should.
+.Pp
+The function
+.Fn xattr_presere_for_intent
+combines the functions above, and will return zero if the
+named extended attribute should be preserved during a copy for
+the given intent.
+.Sh INTENT
+The type
+.Dt xattr_operation_intent_t
+is an integral type, which is used to indicate what the intent for the operation
+is.  The following intent values are defined:
+.Bl -tag -width XATTR_OPERATION_INTENT_SHARE
+.It Dv XATTR_OPERATION_INTENT_COPY
+Indicates that the intent is to simply copy from the source to the destination.
+E.g., with cp.  Most extended attributes should generally be preserved in this
+case.
+.It Dv XATTR_OPERATION_INTENT_SAVE
+Indicates that intent is to perform a save (perhaps as in a "safe save").
+This differs from a copy in that the content may be changing; the destination
+may be over-writing or replacing the source, and som extended attributes should
+not be preserved during this process.
+.It Dv XATTR_OPERATION_INTENT_SHARE
+Indicates that the intent is to share, or export, the object.  For example,
+saving as an attachment in an email message, or placing in a public folder.
+Sensitive information should probably not be preserved in this case.
+.It Dv XATTR_OPERATION_INTENT_SYNC
+Indicates that the intent is to sync the object to a service like iCloud.
+.El
+.Sh FLAGS
+Various flags are defined by the type
+.Dt xattr_flags_t ;
+the currently-defined values for this are
+.Bl -tag -width XATTR_FLAG_CONTENT_DEPENDENT
+.It Dv XATTR_FLAG_NO_EXPORT
+This indicates that the extended attribute should not be exported, or shared.
+This is used with
+.Dv XATTR_OPERATION_INTENT_SHARE .
+.It Dv XATTR_FLAG_CONTENT_DEPENDENT
+This indicates that the extended attribute is tied to the contents of the
+file (or vice versa), such that it should be re-created when the contents
+are changed.  A checksum, for example, should not be copied, and would thus
+be marked with this flag.
+.It Dv XATTR_FLAG_NEVER_PRESERVE
+This indicates that the extended attribute should never be copied from a
+source object to a destination, no matter what the given intent is.
+.It Dv XATTR_FLAG_SYNCABLE
+This indicates that the extended attribute should be copied when the file
+is synced on services like iCloud. Sync services tends to want the metadata
+synced to be kept to a bare minimum, and may enforce additional restrictions
+on the acceptable size and number of extended attributes.
+.El
+.Sh EXAMPLE
+The following example is a simple function that, given an extended attribute
+name and an operation intent, will return whether or not the extended attribute
+should be copied.  (This essentially does what
+.Fn xattr_preserve_for_intent
+does.)
+.Bd -literal -offset indent
+int
+ShouldCopyEA(const char *eaName, xattr_operation_intent_t intent)
+{
+       xattr_flags_t flags = xattr_flags_from_name(eaName);
+       return xattr_intent_with_flags(intent, flags);
+}
+.Ed
+.Sh HISTORY
+These functions first appeared in Mac OS in 2013.
diff --git a/xattr_properties.c b/xattr_properties.c
deleted file mode 100644 (file)
index 78eccd0..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (c) 2013 Apple, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <err.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/xattr.h>
-
-#include <xattr_properties.h>
-
-/*
- * Some default propeteries for EAs we know about internally.
- */
-struct defaultList {
-       const char *eaName;
-       const char *propList;
-       int flags;      // See below
-};
-
-#define propFlagsPrefix        0x0001  // The name is a prefix, so only look at that part
-
-static const struct defaultList
-defaultPropertyTable[] = {
-       { "com.apple.quarantine", "PC", 0 },    // not public
-       { "com.apple.TextEncoding", "PC", 0 },  // Content-dependent, public
-       { "com.apple.metadata:", "P", propFlagsPrefix },        // Don't export, keep for copy & safe save
-       { "com.apple.security.", "N", propFlagsPrefix },
-       { XATTR_RESOURCEFORK_NAME, "PC", 0 },   // Don't keep for safe save
-       { XATTR_FINDERINFO_NAME, "PC", 0 },     // Same as ResourceFork
-       { 0, 0, 0 },
-};
-
-/*
- * The property lists on an EA are set by having a suffix character,
- * and then a list of characters.  In general, we're choosing upper-case
- * to indicate the property is set, and lower-case to indicate it's to be
- * cleared.
- */
-struct propertyListMapping {
-       char enable;    // Character to enable
-       char disable;   // Character to disable -- usually lower-case of enable
-       CopyOperationProperties_t       value;
-};
-static const struct propertyListMapping
-PropertyListMapTable[] = {
-       { 'C', 'c', kCopyOperationPropertyContentDependent },
-       { 'P', 'p', kCopyOperationPropertyNoExport },
-       { 'N', 'n', kCopyOperationPropertyNeverPreserve },
-       { 0, 0, 0 },
-};
-       
-/*
- * Given a converted property list (that is, converted to the
- * CopyOperationProperties_t type), and an intent, determine if
- * it should be preserved or not.
- *
- * I've chosen to use a block instead of a simple mask on the belief
- * that the question may be moderately complex.  If it ends up not being
- * so, then this can simply be turned into a mask of which bits to check
- * as being exclusionary.
- */
-static const struct divineIntent {
-       CopyOperationIntent_t intent;
-       int (^checker)(CopyOperationProperties_t);
-} intentTable[] = {
-       { CopyOperationIntentCopy, ^(CopyOperationProperties_t props) {
-                       if (props & kCopyOperationPropertyNeverPreserve)
-                               return 0;
-                       return 1;
-               } },
-       { CopyOperationIntentSave, ^(CopyOperationProperties_t props) {
-                       if (props & (kCopyOperationPropertyContentDependent | kCopyOperationPropertyNeverPreserve))
-                               return 0;
-                       return 1;
-               } },
-       { CopyOperationIntentShare, ^(CopyOperationProperties_t props) {
-                       if ((props & (kCopyOperationPropertyNoExport | kCopyOperationPropertyNeverPreserve)) != 0)
-                               return 0;
-                       return 1;
-               } },
-       { 0, 0 },
-};
-
-
-/*
- * If an EA name is in the default list, find it, and return the property
- * list string for it.
- */
-static const char *
-nameInDefaultList(const char *eaname)
-{
-       const struct defaultList *retval;
-
-       for (retval = defaultPropertyTable; retval->eaName; retval++) {
-               if ((retval->flags & propFlagsPrefix) != 0 &&
-                   strncmp(retval->eaName, eaname, strlen(retval->eaName)) == 0)
-                       return retval->propList;
-               if (strcmp(retval->eaName, eaname) == 0)
-                       return retval->propList;
-       }
-       return NULL;
-}
-
-/*
- * Given an EA name, see if it has a property list in it, and
- * return a pointer to it.  All this is doing is looking for
- * the delimiter, and returning the string after that.  Returns
- * NULL if the delimiter isn't found.  Note that an empty string
- * is a valid property list, as far as we're concerned.
- */
-static const char *
-findPropertyList(const char *eaname)
-{
-       const char *ptr = strrchr(eaname, '#');
-       if (ptr)
-               return ptr+1;
-       return NULL;
-}
-
-/*
- * Convert a property list string (e.g., "pCd") into a
- * CopyOperationProperties_t type.
- */
-static CopyOperationProperties_t
-stringToProperties(const char *proplist)
-{
-       CopyOperationProperties_t retval = 0;
-       const char *ptr;
-
-       // A switch would be more efficient, but less generic.
-       for (ptr = proplist; *ptr; ptr++) {
-               const struct propertyListMapping *mapPtr;
-               for (mapPtr = PropertyListMapTable; mapPtr->enable; mapPtr++) {
-                       if (*ptr == mapPtr->enable) {
-                               retval |= mapPtr->value;
-                       } else if (*ptr == mapPtr->disable) {
-                               retval &= ~mapPtr->value;
-                       }
-               }
-       }
-       return retval;
-}
-
-/*
- * Given an EA name (e.g., "com.apple.lfs.hfs.test"), and a
- * CopyOperationProperties_t value (it's currently an integral value, so
- * just a bitmask), cycle through the list of known properties, and return
- * a string with the EA name, and the property list appended.  E.g., we
- * might return "com.apple.lfs.hfs.test#pD".
- *
- * The tricky part of this funciton is that it will not append any letters
- * if the value is only the default properites.  In that case, it will copy
- * the EA name, and return that.
- *
- * It returns NULL if there was an error.  The two errors right now are
- * no memory (strdup failed), in which case it will set errno to ENOMEM; and
- * the resulting EA name is longer than XATTR_MAXNAMELEN, in which case it
- * sets errno to ENAMETOOLONG.
- *
- * (Note that it also uses ENAMETOOLONG if the buffer it's trying to set
- * gets too large.  I honestly can't see how that would happen, but it's there
- * for sanity checking.  That would require having more than 64 bits to use.)
- */
-char *
-_xattrNameWithProperties(const char *orig, CopyOperationProperties_t propList)
-{
-       char *retval = NULL;
-       char suffix[66] = { 0 }; // 66:  uint64_t for property types, plus '#', plus NUL
-       char *cur = suffix;
-       const struct propertyListMapping *mapPtr;
-
-       *cur++ = '#';
-       for (mapPtr = PropertyListMapTable; mapPtr->enable; mapPtr++) {
-               if ((propList & mapPtr->value) != 0) {
-                       *cur++ = mapPtr->enable;
-               }
-               if (cur >= (suffix + sizeof(suffix))) {
-                       errno = ENAMETOOLONG;
-                       return NULL;
-               }
-
-       }
-       
-               
-       if (cur == suffix + 1) {
-               // No changes made
-               retval = strdup(orig);
-               if (retval == NULL)
-                       errno = ENOMEM;
-       } else {
-               const char *defaultEntry = NULL;
-               if ((defaultEntry = nameInDefaultList(orig)) != NULL &&
-                   strcmp(defaultEntry, suffix + 1) == 0) {
-                       // Just use the name passed in
-                       retval = strdup(orig);
-               } else {
-                       asprintf(&retval, "%s%s", orig, suffix);
-               }
-               if (retval == NULL) {
-                       errno = ENOMEM;
-               } else {
-                       if (strlen(retval) > XATTR_MAXNAMELEN) {
-                               free(retval);
-                               retval = NULL;
-                               errno = ENAMETOOLONG;
-                       }
-               }
-       }
-       return retval;
-}
-
-CopyOperationProperties_t
-_xattrPropertiesFromName(const char *eaname)
-{
-       CopyOperationProperties_t retval = 0;
-       const char *propList;
-
-       propList = findPropertyList(eaname);
-       if (propList == NULL) {
-               propList = findPropertyList(eaname);
-       }
-       if (propList != NULL) {
-               retval = stringToProperties(propList);
-       }
-       
-       return retval;
-}
-
-/*
- * Indicate whether an EA should be preserved, when using the
- * given intent.
- * 
- * This returns 0 if it should not be preserved, and 1 if it should.
- * 
- * It simply looks through the tables we have above, and compares the
- * CopyOperationProperties_t for the EA with the intent.  If the
- * EA doesn't have any properties, and it's not on the default list, the
- * default is to preserve it.
- */
-
-int
-_PreserveEA(const char *eaname, CopyOperationIntent_t intent)
-{
-       const struct divineIntent *ip;
-       CopyOperationProperties_t props;
-       const char *propList;
-
-       if ((propList = findPropertyList(eaname)) == NULL &&
-           (propList = nameInDefaultList(eaname)) == NULL)
-               props = 0;
-       else
-               props = stringToProperties(propList);
-
-       for (ip = intentTable; ip->intent; ip++) {
-               if (ip->intent == intent) {
-                       return ip->checker(props);
-               }
-       }
-       
-       if ((props & kCopyOperationPropertyNeverPreserve) != 0)
-               return 0;       // Special case, don't try to preserve this one
-
-       return 1;       // Default to preserving everything
-}
index e6eb457b268cc5d22a8e9299c9b4d9de0def1ffe..21d9a29eb73215f6836818ca02d9a9a06034d372 100644 (file)
@@ -27,7 +27,7 @@
 #include <stdint.h>
 
 #include <sys/cdefs.h>
-
+#include <Availability.h>
 
 __BEGIN_DECLS
 
@@ -89,9 +89,10 @@ typedef uint64_t CopyOperationProperties_t;
  */
 #define kCopyOperationPropertyNeverPreserve    ((CopyOperationProperties_t)0x0004)
 
-// Given a named extended attribute, and a copy intent, should the EA be preserved?
-extern int _PreserveEA(const char *, CopyOperationIntent_t);
-
+#if 0
+/*
+ * These are all going to be removed, and I don't believe anyone used them.
+ */
 /*
  * Given an extended attribute name, and a set of properties, return an
  *  allocated C string with the name.  This will return NULL on error;
@@ -104,7 +105,7 @@ extern int _PreserveEA(const char *, CopyOperationIntent_t);
  * If the EA name is in the internal list, and the properties are the same as
  * defined there, then it will also return an unmodified copy of the EA name.
  */
-extern char *_xattrNameWithProperties(const char *, CopyOperationProperties_t);
+extern char *_xattrNameWithProperties(const char *, CopyOperationProperties_t) DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER;
 
 /*
  * Given an extended attribute name, which may or may not have properties encoded
@@ -113,13 +114,14 @@ extern char *_xattrNameWithProperties(const char *, CopyOperationProperties_t);
  * errno will be set to ENOMEM if it cannot be allocated.  The caller must deallocate
  * the return value.
  */
-extern char *_xattrNameWithoutProperties(const char *);
+extern char *_xattrNameWithoutProperties(const char *) DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER;
 
 /*
  * Given an EA name, return the properties.  If the name is in the internal list,
  * those properties will be returned.  Unknown property encodings are ignored.
  */
-extern CopyOperationProperties_t _xattrPropertiesFromName(const char *);
+extern CopyOperationProperties_t _xattrPropertiesFromName(const char *) DEPRECATED_IN_MAC_OS_X_VERSION_10_10_AND_LATER;
+#endif /* 0 */
 
 __END_DECLS
 
diff --git a/xcodescripts/copyfile.xcconfig b/xcodescripts/copyfile.xcconfig
new file mode 100644 (file)
index 0000000..d451a2a
--- /dev/null
@@ -0,0 +1,16 @@
+#include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
+#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig"
+
+// Set INSTALL_PATH_ACTUAL to whatever INSTALL_PATH would normally be
+INSTALL_PATH_ACTUAL = /usr/lib/system
+
+// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable
+INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL)
+
+// Use $(INSTALL_PATH_PREFIX) instead of $(SDKROOT) as an unconditional prefix
+PUBLIC_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/include
+PRIVATE_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/local/include
+
+BUILD_VARIANTS = normal debug
+
+PRODUCT_NAME = copyfile
index 50174fba22d1e0ee49ae103f891caf40cf27ce73..8aacf911ad54fbca9dcdf0cf8f5840fe3e2b0d41 100644 (file)
@@ -1,20 +1,9 @@
 #!/bin/sh
 set -e -x
 
-# check if we're building for the simulator
-if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ] ; then
-        if [ -d ${DSTROOT}${SDKROOT}/usr/lib/system ] ; then
-                for lib in ${DSTROOT}${SDKROOT}/usr/lib/system/*.dylib ; do
-                        install_name_tool -id "${lib#${DSTROOT}${SDKROOT}}" "${lib}"
-                done
-        fi
-       exit 0
-fi
-
-# don't install files for installhdrs or simulator builds
-if [ "$ACTION" == "installhdrs" -o ] ; then
-       exit 0
-fi
+# don't install man pages for installhdrs or iOS builds
+if [ "$ACTION" = installhdrs ]; then exit 0; fi
+if [ "${PLATFORM_NAME/iphone/}" != "${PLATFORM_NAME}" ]; then exit 0; fi
 
 function InstallManPages() {
        for MANPAGE in "$@"; do
@@ -42,3 +31,10 @@ LinkManPages copyfile.3 \
        copyfile_state_free.3 \
        copyfile_state_get.3 \
        copyfile_state_set.3
+
+InstallManPages xattr_name_with_flags.3
+LinkManPages    xattr_name_with_flags.3 \
+       xattr_name_without_flags.3 \
+       xattr_flags_from_name.3 \
+       xattr_intent_with_flags.3
+