#include "copyfile.h"
#include "copyfile_private.h"
-#include "xattr_properties.h"
+#include "xattr_flags.h"
enum cfInternalFlags {
cfDelayAce = 1 << 0,
off_t totalCopied;
int err;
char *xattr_name;
- CopyOperationIntent_t copyIntent;
+ xattr_operation_intent_t copyIntent;
};
struct acl_entry {
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
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);
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;
}
// 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);
#endif
#ifdef COPYFILE_STATE_INTENT
case COPYFILE_STATE_INTENT:
- *(CopyOperationIntent_t*)ret = s->copyIntent;
+ *(xattr_operation_intent_t*)ret = s->copyIntent;
break;
#endif
default:
#endif
#ifdef COPYFILE_STATE_INTENT
case COPYFILE_STATE_INTENT:
- s->copyIntent = *(CopyOperationIntent_t*)thing;
+ s->copyIntent = *(xattr_operation_intent_t*)thing;
break;
#endif
default:
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);
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);
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;
#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 */
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>";
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",
*/
# 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 */
--- /dev/null
+/*
+ * 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"
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+.\"
+.\" 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.
+++ /dev/null
-/*
- * 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
-}
#include <stdint.h>
#include <sys/cdefs.h>
-
+#include <Availability.h>
__BEGIN_DECLS
*/
#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;
* 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
* 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
--- /dev/null
+#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
#!/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
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
+