]> git.saurik.com Git - apple/copyfile.git/commitdiff
copyfile-103.tar.gz os-x-109 os-x-1091 os-x-1092 os-x-1093 v103
authorApple <opensource@apple.com>
Tue, 7 May 2013 23:09:28 +0000 (23:09 +0000)
committerApple <opensource@apple.com>
Tue, 7 May 2013 23:09:28 +0000 (23:09 +0000)
copyfile.c
copyfile.h
copyfile.xcodeproj/project.pbxproj
copyfile_private.h [new file with mode: 0644]
xattr_properties.c [new file with mode: 0644]
xattr_properties.h [new file with mode: 0644]
xcodescripts/install_files.sh

index a1861ea2f4dbf992a660be6cd22c434272a11ed3..8a1351438c6adc3caf229845a67fcd1495e931be 100644 (file)
 #endif
 
 #include <TargetConditionals.h>
-#if !TARGET_OS_EMBEDDED
+#if !TARGET_OS_IPHONE
 #include <quarantine.h>
 
 #define        XATTR_QUARANTINE_NAME qtn_xattr_name
-#else /* TARGET_OS_EMBEDDED */
+#else /* TARGET_OS_IPHONE */
 #define qtn_file_t void *
 #define QTN_SERIALIZED_DATA_MAX 0
 static void * qtn_file_alloc(void) { return NULL; }
 static int qtn_file_init_with_fd(void *x, int y) { return -1; }
+static int qtn_file_init_with_path(void *x, const char *path) { return -1; }
+static int qtn_file_init_with_data(void *x, const void *data, size_t len) { return -1; }
 static void qtn_file_free(void *x) { return; }
 static int qtn_file_apply_to_fd(void *x, int y) { return 0; }
 static char *qtn_error(int x) { return NULL; }
 static int qtn_file_to_data(void *x, char *y, size_t z) { return -1; }
 static void *qtn_file_clone(void *x) { return NULL; }
 #define        XATTR_QUARANTINE_NAME "figgledidiggledy"
-#endif /* TARGET_OS_EMBEDDED */
+#endif /* TARGET_OS_IPHONE */
 
 #include "copyfile.h"
+#include "copyfile_private.h"
+#include "xattr_properties.h"
 
 enum cfInternalFlags {
        cfDelayAce = 1 << 0,
@@ -105,6 +109,7 @@ struct _copyfile_state
     off_t totalCopied;
     int err;
     char *xattr_name;
+    CopyOperationIntent_t copyIntent;
 };
 
 struct acl_entry {
@@ -1050,6 +1055,9 @@ int copyfile(const char *src, const char *dst, copyfile_state_t state, copyfile_
 
     (void)fcntl(s->src_fd, F_NOCACHE, 1);
     (void)fcntl(s->dst_fd, F_NOCACHE, 1);
+#ifdef F_SINGLE_WRITER
+    (void)fcntl(s->dst_fd, F_SINGLE_WRITER, 1);
+#endif
 
     ret = copyfile_internal(s, flags);
     if (ret == -1)
@@ -2288,6 +2296,11 @@ static int copyfile_xattr(copyfile_state_t s)
        }
 #endif
 
+       // 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)
+               continue;
+
        s->xattr_name = strdup(name);
        
        if (s->statuscb) {
@@ -2396,6 +2409,11 @@ int copyfile_state_get(copyfile_state_t s, uint32_t flag, void *ret)
        case COPYFILE_STATE_XATTRNAME:
                *(char**)ret = s->xattr_name;
                break;
+#endif
+#ifdef COPYFILE_STATE_INTENT
+       case COPYFILE_STATE_INTENT:
+           *(CopyOperationIntent_t*)ret = s->copyIntent;
+          break;
 #endif
        default:
            errno = EINVAL;
@@ -2467,6 +2485,11 @@ int copyfile_state_set(copyfile_state_t s, uint32_t flag, const void * thing)
        case COPYFILE_STATE_STATUS_CTX:
            s->ctx = (void*)thing;
            break;
+#endif
+#ifdef COPYFILE_STATE_INTENT
+       case COPYFILE_STATE_INTENT:
+           s->copyIntent = *(CopyOperationIntent_t*)thing;
+          break;
 #endif
        default:
            errno = EINVAL;
@@ -2541,7 +2564,7 @@ int main(int c, char *v[])
 
 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
 
-#define        XATTR_MAXATTRLEN   (32*1024)
+#define        XATTR_MAXATTRLEN   (16*1024*1024)
 
 
 /*
@@ -2632,7 +2655,7 @@ int main(int c, char *v[])
 #define ATTR_BUF_SIZE      4096        /* default size of the attr file and how much we'll grow by */
 
 /* Implementation Limits */
-#define ATTR_MAX_SIZE      (128*1024)  /* 128K maximum attribute data size */
+#define ATTR_MAX_SIZE      (16*1024*1024)      /* 16 megabyte maximum attribute data size */
 #define ATTR_MAX_NAME_LEN  128
 #define ATTR_MAX_HDR_SIZE  (65536+18)
 
@@ -2822,7 +2845,7 @@ static const u_int32_t emptyfinfo[8] = {0};
 static int copyfile_unpack(copyfile_state_t s)
 {
     ssize_t bytes;
-    void * buffer, * endptr;
+    void * buffer, * endptr, * dataptr = NULL;
     apple_double_header_t *adhdr;
     ssize_t hdrsize;
     int error = 0;
@@ -2936,7 +2959,6 @@ static int copyfile_unpack(copyfile_state_t s)
 
        for (i = 0; i < count; i++)
        {
-           void * dataptr;
 
            /*
             * First we do some simple sanity checking.
@@ -3020,6 +3042,7 @@ static int copyfile_unpack(copyfile_state_t s)
            copyfile_debug(3, "extracting \"%s\" (%d bytes) at offset %u",
                entry->name, entry->length, entry->offset);
 
+#if 0
            dataptr = (char *)attrhdr + entry->offset;
 
            if (dataptr > endptr || dataptr < buffer) {
@@ -3028,6 +3051,7 @@ static int copyfile_unpack(copyfile_state_t s)
                s->err = EINVAL;        /* Invalid buffer */
                goto exit;
            }
+
            if (((char*)dataptr + entry->length) > (char*)endptr ||
                (((char*)dataptr + entry->length) < (char*)buffer) ||
                (entry->length > (size_t)hdrsize)) {
@@ -3040,6 +3064,22 @@ static int copyfile_unpack(copyfile_state_t s)
                goto exit;
            }
 
+#else
+           dataptr = malloc(entry->length);
+           if (dataptr == NULL) {
+                   copyfile_debug(1, "no memory for %u bytes\n", entry->length);
+                   error = -1;
+                   s->err = ENOMEM;
+                   goto exit;
+           }
+           if (pread(s->src_fd, dataptr, entry->length, entry->offset) != (ssize_t)entry->length) {
+                   copyfile_debug(1, "failed to read %u bytes at offset %u\n", entry->length, entry->offset);
+                   error = -1;
+                   s->err = EINVAL;
+                   goto exit;
+           }
+#endif     
+
            if (strcmp((char*)entry->name, XATTR_QUARANTINE_NAME) == 0)
            {
                qtn_file_t tqinfo = NULL;
@@ -3160,57 +3200,64 @@ acl_done:
            /* And, finally, everything else */
            else
            {
-               if (s->statuscb) {
-                       int rv;
-                       s->xattr_name = strdup((char*)entry->name);
-                       s->totalCopied = 0;
-                       rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
-                       if (s->xattr_name) {
-                               free(s->xattr_name);
-                               s->xattr_name = NULL;
-                       }
-                       if (rv == COPYFILE_QUIT) {
-                               s->err = ECANCELED;
-                               error = -1;
-                               goto exit;
-                       }
-               }
-               if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
-                       if (COPYFILE_VERBOSE & s->flags)
-                               copyfile_warn("error %d setting attribute %s", error, entry->name);
+               if (s->copyIntent ||
+                   _PreserveEA((char*)entry->name, s->copyIntent) == 1) {
                        if (s->statuscb) {
                                int rv;
-
                                s->xattr_name = strdup((char*)entry->name);
-                               rv = (s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
+                               s->totalCopied = 0;
+                               rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
                                if (s->xattr_name) {
                                        free(s->xattr_name);
                                        s->xattr_name = NULL;
                                }
                                if (rv == COPYFILE_QUIT) {
+                                       s->err = ECANCELED;
                                        error = -1;
                                        goto exit;
                                }
-                       } else {
-                               error = -1;
-                               goto exit;
-                       }
-               } else if (s->statuscb) {
-                       int rv;
-                       s->xattr_name = strdup((char*)entry->name);
-                       s->totalCopied = entry->length;
-                       rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
-                       if (s->xattr_name) {
-                               free(s->xattr_name);
-                               s->xattr_name = NULL;
                        }
-                       if (rv == COPYFILE_QUIT) {
-                               error = -1;
-                               s->err = ECANCELED;
-                               goto exit;
+                       if (fsetxattr(s->dst_fd, (char *)entry->name, dataptr, entry->length, 0, 0) == -1) {
+                               if (COPYFILE_VERBOSE & s->flags)
+                                       copyfile_warn("error %d setting attribute %s", errno, entry->name);
+                               if (s->statuscb) {
+                                       int rv;
+                                       
+                                       s->xattr_name = strdup((char*)entry->name);
+                                       rv = (s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
+                                       if (s->xattr_name) {
+                                               free(s->xattr_name);
+                                               s->xattr_name = NULL;
+                                       }
+                                       if (rv == COPYFILE_QUIT) {
+                                               error = -1;
+                                               goto exit;
+                                       }
+                               } else {
+                                       error = -1;
+                                       goto exit;
+                               }
+                       } else if (s->statuscb) {
+                               int rv;
+                               s->xattr_name = strdup((char*)entry->name);
+                               s->totalCopied = entry->length;
+                               rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
+                               if (s->xattr_name) {
+                                       free(s->xattr_name);
+                                       s->xattr_name = NULL;
+                               }
+                               if (rv == COPYFILE_QUIT) {
+                                       error = -1;
+                                       s->err = ECANCELED;
+                                       goto exit;
+                               }
                        }
                }
            }
+           if (dataptr) {
+                   free(dataptr);
+                   dataptr = NULL;
+           }
            entry = ATTR_NEXT(entry);
        }
     }
@@ -3249,7 +3296,7 @@ acl_done:
        if (error) {
                if (s->statuscb) {
                        int rv;
-                       s->xattr_name = XATTR_FINDERINFO_NAME;
+                       s->xattr_name = (char *)XATTR_FINDERINFO_NAME;
                        rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
                        s->xattr_name = NULL;
                        if (rv == COPYFILE_QUIT) {
@@ -3261,7 +3308,7 @@ acl_done:
            goto exit;
        } else if (s->statuscb) {
                int rv;
-               s->xattr_name = XATTR_FINDERINFO_NAME;
+               s->xattr_name = (char *)XATTR_FINDERINFO_NAME;
                rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
                s->xattr_name = NULL;
                if (rv == COPYFILE_QUIT) {
@@ -3323,7 +3370,7 @@ skip_fi:
        }
        if (s->statuscb) {
                int rv;
-               s->xattr_name = XATTR_RESOURCEFORK_NAME;
+               s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
                rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_START, s, s->src, s->dst, s->ctx);
                s->xattr_name = NULL;
                if (rv == COPYFILE_QUIT) {
@@ -3356,7 +3403,7 @@ skip_fi:
            }
            if (s->statuscb) {
                int rv;
-               s->xattr_name = XATTR_RESOURCEFORK_NAME;
+               s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
                rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_ERR, s, s->src, s->dst, s->ctx);
                s->xattr_name = NULL;
                if (rv == COPYFILE_CONTINUE) {
@@ -3369,7 +3416,7 @@ skip_fi:
            goto bad;
        } else if (s->statuscb) {
                int rv;
-               s->xattr_name = XATTR_RESOURCEFORK_NAME;
+               s->xattr_name = (char *)XATTR_RESOURCEFORK_NAME;
                rv = (*s->statuscb)(COPYFILE_COPY_XATTR, COPYFILE_FINISH, s, s->src, s->dst, s->ctx);
                s->xattr_name = NULL;
                if (rv == COPYFILE_QUIT) {
@@ -3403,6 +3450,7 @@ bad:
     }
 exit:
     if (buffer) free(buffer);
+    if (dataptr) free(dataptr);
     return error;
 }
 
@@ -3607,12 +3655,13 @@ static int copyfile_pack(copyfile_state_t s)
     int error = 0;
     int seenq = 0;     // Have we seen any quarantine info already?
 
-    filehdr = (attr_header_t *) calloc(1, ATTR_MAX_SIZE);
+    filehdr = (attr_header_t *) calloc(1, ATTR_MAX_HDR_SIZE);
+
     if (filehdr == NULL) {
        error = -1;
        goto exit;
     } else {
-           endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_SIZE);
+           endfilehdr = (attr_header_t*)(((char*)filehdr) + ATTR_MAX_HDR_SIZE);
     }
 
     attrnamebuf = calloc(1, ATTR_MAX_HDR_SIZE);
@@ -3706,6 +3755,17 @@ static int copyfile_pack(copyfile_state_t s)
            if (namelen > XATTR_MAXNAMELEN + 1) {
                namelen = XATTR_MAXNAMELEN + 1;
            }
+           if (s->copyIntent &&
+               _PreserveEA(nameptr, s->copyIntent) == 0) {
+                   // Skip it
+                   size_t amt = endnamebuf - (nameptr + namelen);
+                   memmove(nameptr, nameptr + namelen, amt);
+                   endnamebuf -= namelen;
+                   /* Set namelen to 0 so continue doesn't miss names */
+                   namelen = 0;
+                   continue;
+           }
+                   
            if (s->statuscb) {
                int rv;
                char eaname[namelen];
@@ -3937,6 +3997,7 @@ static int copyfile_pack(copyfile_state_t s)
        entry->offset = filehdr->data_start + filehdr->data_length;
 
        filehdr->data_length += (u_int32_t)datasize;
+#if 0
        /*
         * >>>  WARNING <<<
         * This assumes that the data is fits in memory (not
@@ -3949,6 +4010,11 @@ static int copyfile_pack(copyfile_state_t s)
        } else {
                bcopy(databuf, (char*)filehdr + entry->offset, datasize);
        }
+#else
+       if (pwrite(s->dst_fd, databuf, datasize, entry->offset) != datasize) {
+               error = 1;
+       }
+#endif
        free(databuf);
 
        copyfile_debug(3, "copied %ld bytes of \"%s\" data @ offset 0x%08x", datasize, nameptr, entry->offset);
@@ -3958,24 +4024,21 @@ next:
        entry = (attr_entry_t *)((char *)entry + entrylen);
     }
 
-    if (filehdr->data_length > 0)
-    {
-       /* Now we know where the resource fork data starts. */
-       filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
-
-       /* We also know the size of the "Finder Info entry. */
-       filehdr->appledouble.entries[0].length =
+    /* Now we know where the resource fork data starts. */
+    filehdr->appledouble.entries[1].offset = (filehdr->data_start + filehdr->data_length);
+    
+    /* We also know the size of the "Finder Info entry. */
+    filehdr->appledouble.entries[0].length =
            filehdr->appledouble.entries[1].offset - filehdr->appledouble.entries[0].offset;
-
-       filehdr->total_size  = filehdr->appledouble.entries[1].offset;
-    }
-
+    
+    filehdr->total_size  = filehdr->appledouble.entries[1].offset;
+    
     /* Copy Resource Fork. */
     if (hasrsrcfork && (error = copyfile_pack_rsrcfork(s, filehdr)))
        goto exit;
 
     /* Write the header to disk. */
-    datasize = filehdr->appledouble.entries[1].offset;
+    datasize = filehdr->data_start;
 
     swap_adhdr(&filehdr->appledouble);
     swap_attrhdr(filehdr);
index 4029d217bf6e08fb7f0822ba66a7ee0b0625dca3..59c198a5b4ca79dcef24bb1b24fbfcfedc88c7ab 100644 (file)
@@ -77,6 +77,7 @@ typedef int (*copyfile_callback_t)(int, int, copyfile_state_t, const char *, con
 #define        COPYFILE_STATE_COPIED           8
 #define        COPYFILE_STATE_XATTRNAME        9
 
+
 #define        COPYFILE_DISABLE_VAR    "COPYFILE_DISABLE"
 
 /* flags for copyfile */
index 181f09c751775f469f0d771cdbc195b653a12c2b..04b9858d9cc5e5f94bd92a8d003f8e1123e3debc 100644 (file)
@@ -7,11 +7,17 @@
        objects = {
 
 /* Begin PBXBuildFile section */
+               72406E631676C3C80099568B /* xattr_properties.c in Sources */ = {isa = PBXBuildFile; fileRef = 72406E621676C3C80099568B /* xattr_properties.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, ); }; };
                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>"; };
+               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>"; };
                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>"; };
@@ -33,6 +39,9 @@
                FCCE17AB135A5FFB002CEE6D = {
                        isa = PBXGroup;
                        children = (
+                               72B4C0F31676C47D00C13E05 /* copyfile_private.h */,
+                               72EAA3AF16A72F4500833E98 /* xattr_properties.h */,
+                               72406E621676C3C80099568B /* xattr_properties.c */,
                                FCCE17C0135A658F002CEE6D /* copyfile.3 */,
                                FCCE17C1135A658F002CEE6D /* copyfile.c */,
                                FCCE17C2135A658F002CEE6D /* copyfile.h */,
@@ -57,6 +66,8 @@
                        buildActionMask = 2147483647;
                        files = (
                                FCCE17C4135A658F002CEE6D /* copyfile.h in Headers */,
+                               72B4C0F41676C47D00C13E05 /* copyfile_private.h in Headers */,
+                               72EAA3B016A72F4500833E98 /* xattr_properties.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        buildActionMask = 2147483647;
                        files = (
                                FCCE17C3135A658F002CEE6D /* copyfile.c in Sources */,
+                               72406E631676C3C80099568B /* xattr_properties.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                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 = (
-                                       "-umbrella",
-                                       System,
+                                       "-Wl,-umbrella,System",
+                                       "-L/usr/lib/system",
+                                       "-ldyld",
+                                       "-lcompiler_rt",
+                                       "-lsystem_kernel",
+                                       "-lsystem_malloc",
+                                       "-lsystem_c",
+                                       "-lsystem_blocks",
+                                       "-lquarantine",
+                                       "-lsystem_asl",
+                                       "-lsystem_info",
                                );
+                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
+                                       "-Wl,-umbrella,System",
+                                       "-L/usr/lib/system",
+                                       "-ldyld",
+                                       "-lcompiler_rt",
+                                       "-lsystem_kernel",
+                                       "-lsystem_malloc",
+                                       "-lsystem_c",
+                                       "-lsystem_blocks",
+                                       "-lsystem_asl",
+                                       "-lsystem_info",
+                               );
+                               "OTHER_LDFLAGS[sdk=iphonesimulator*]" = (
+                                       "-Wl,-umbrella,System",
+                                       "-L/usr/lib/system",
+                                       "-ldyld_sim",
+                                       "-lcompiler_rt_sim",
+                                       "-lsystem_sim_c",
+                                       "-lsystem_sim_blocks",
+                                       "-lsystem_sim_info",
+                                       "-Wl,-upward-lSystem",
+                               );
+                               "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",
diff --git a/copyfile_private.h b/copyfile_private.h
new file mode 100644 (file)
index 0000000..8f805d9
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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 _COPYFILE_PRIVATE_H
+# define _COPYFILE_PRIVATE_H
+
+/*
+ * Set (or get) the intent type; see xattr_properties.h for details.
+ * This command uses a pointer to CopyOperationIntent_t as the parameter.
+ */
+# define COPYFILE_STATE_INTENT 256
+
+#endif /* _COPYFILE_PRIVATE_H */
diff --git a/xattr_properties.c b/xattr_properties.c
new file mode 100644 (file)
index 0000000..78eccd0
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * 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
+}
diff --git a/xattr_properties.h b/xattr_properties.h
new file mode 100644 (file)
index 0000000..e6eb457
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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_PROPERTIES_H
+#define _XATTR_PROPERTIES_H
+
+#include <stdint.h>
+
+#include <sys/cdefs.h>
+
+
+__BEGIN_DECLS
+
+/*
+ * CopyOperationIntent_t is used to declare what the intent of the copy is.
+ * Not a bit-field (for now, at least).
+ *
+ * CopyOperationIntentCopy indicates that the EA is attached to an object
+ * that is simply being copied.  E.g., cp src dst
+ *
+ * CopyOperationIntentSave 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.
+ *
+ * CopyOperationIntentShare 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.
+ */
+
+typedef enum {
+       CopyOperationIntentCopy = 1,
+       CopyOperationIntentSave,
+       CopyOperationIntentShare,
+} CopyOperationIntent_t;
+
+typedef uint64_t CopyOperationProperties_t;
+
+/*
+ * Various properties used to determine how to handle the xattr during
+ * copying.  The intent is that the default is reasonable for most xattrs.
+ */
+
+/*
+ * kCopyOperationPropertyNoExport
+ * Declare that the extended property should not be exported; this is
+ * deliberately a bit vague, but this is used by CopyOperationIntentShare
+ * to indicate not to preserve the xattr.
+ */
+#define kCopyOperationPropertyNoExport ((CopyOperationProperties_t)0x0001)
+
+/*
+ * kCopyOperationPropertyContentDependent
+ * 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        kCopyOperationPropertyContentDependent  ((CopyOperationProperties_t)0x0002)
+
+/*
+ * kCopyOperationPropertyNeverPreserve
+ * Declares that the extended attribute is never to be copied, for any
+ * intention type.
+ */
+#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);
+
+/*
+ * 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 *_xattrNameWithProperties(const char *, CopyOperationProperties_t);
+
+/*
+ * 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 *_xattrNameWithoutProperties(const char *);
+
+/*
+ * 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 *);
+
+__END_DECLS
+
+#endif /* _XATTR_PROPERTIES_H */
index 7f2e58feb6866d39ecc593b4157b47e203711670..50174fba22d1e0ee49ae103f891caf40cf27ce73 100644 (file)
@@ -1,9 +1,18 @@
 #!/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 \
-     "${RC_ProjectName%_Sim}" != "$RC_ProjectName" ]; then
+if [ "$ACTION" == "installhdrs" -o ] ; then
        exit 0
 fi