From 618b37c8752c3ad13c3fa5762ae59be51bc85a2c Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 28 Aug 2014 21:33:35 +0000 Subject: [PATCH] copyfile-118.1.2.tar.gz --- copyfile.c | 78 +++++++++++--- copyfile.h | 13 +-- copyfile.xcodeproj/project.pbxproj | 54 +++++----- copyfile_private.h | 5 + xattr_properties.c => xattr_flags.c | 154 +++++++++++++++++++--------- xattr_flags.h | 149 +++++++++++++++++++++++++++ xattr_name_with_flags.3 | 123 ++++++++++++++++++++++ xattr_properties.h | 16 +-- xcodescripts/copyfile.xcconfig | 16 +++ xcodescripts/install_files.sh | 24 ++--- 10 files changed, 513 insertions(+), 119 deletions(-) rename xattr_properties.c => xattr_flags.c (65%) create mode 100644 xattr_flags.h create mode 100644 xattr_name_with_flags.3 create mode 100644 xcodescripts/copyfile.xcconfig diff --git a/copyfile.c b/copyfile.c index 09d6305..99f26fc 100644 --- a/copyfile.c +++ b/copyfile.c @@ -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; diff --git a/copyfile.h b/copyfile.h index 59c198a..91dfe87 100644 --- a/copyfile.h +++ b/copyfile.h @@ -24,14 +24,11 @@ #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 */ diff --git a/copyfile.xcodeproj/project.pbxproj b/copyfile.xcodeproj/project.pbxproj index 04b9858..c125959 100644 --- a/copyfile.xcodeproj/project.pbxproj +++ b/copyfile.xcodeproj/project.pbxproj @@ -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 = ""; }; + 3F1EFD4C185C4EB400D1C970 /* copyfile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = copyfile.xcconfig; path = xcodescripts/copyfile.xcconfig; sourceTree = ""; }; + 72406E621676C3C80099568B /* xattr_flags.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = xattr_flags.c; sourceTree = ""; }; 72B4C0F31676C47D00C13E05 /* copyfile_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = copyfile_private.h; sourceTree = ""; }; - 72EAA3AF16A72F4500833E98 /* xattr_properties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xattr_properties.h; sourceTree = ""; }; + 72EAA3AF16A72F4500833E98 /* xattr_flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xattr_flags.h; sourceTree = ""; }; + 861E1C14180F0AF900E65B9A /* xattr_name_with_flags.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = xattr_name_with_flags.3; sourceTree = ""; }; + 86EF9F091834018C00AAB3F3 /* xattr_properties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xattr_properties.h; sourceTree = ""; }; 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 = ""; }; FCCE17C1135A658F002CEE6D /* copyfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = copyfile.c; sourceTree = ""; }; FCCE17C2135A658F002CEE6D /* copyfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = copyfile.h; sourceTree = ""; }; - 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 */ @@ -39,13 +42,15 @@ 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 = ""; @@ -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; }; @@ -140,7 +146,7 @@ buildActionMask = 2147483647; files = ( FCCE17C3135A658F002CEE6D /* copyfile.c in Sources */, - 72406E631676C3C80099568B /* xattr_properties.c in Sources */, + 72406E631676C3C80099568B /* xattr_flags.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -149,7 +155,7 @@ /* 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; @@ -176,16 +182,9 @@ 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", @@ -199,6 +198,8 @@ "-lquarantine", "-lsystem_asl", "-lsystem_info", + "-lxpc", + "-ldispatch", ); "OTHER_LDFLAGS[sdk=iphoneos*]" = ( "-Wl,-umbrella,System", @@ -211,22 +212,23 @@ "-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", diff --git a/copyfile_private.h b/copyfile_private.h index 8f805d9..0111e0d 100644 --- a/copyfile_private.h +++ b/copyfile_private.h @@ -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_properties.c b/xattr_flags.c similarity index 65% rename from xattr_properties.c rename to xattr_flags.c index 78eccd0..8e8fd05 100644 --- a/xattr_properties.c +++ b/xattr_flags.c @@ -29,8 +29,13 @@ #include #include #include +#include +#include -#include +#include + +#define FLAG_DELIM_CHAR '#' +#define FLAG_DELIM_STR "#" /* * Some default propeteries for EAs we know about internally. @@ -43,17 +48,30 @@ struct defaultList { #define propFlagsPrefix 0x0001 // The name is a prefix, so only look at that part +static const struct defaultList *defaultPropertyTable = NULL; + 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 +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 @@ -63,19 +81,20 @@ defaultPropertyTable[] = { struct propertyListMapping { char enable; // Character to enable char disable; // Character to disable -- usually lower-case of enable - CopyOperationProperties_t value; + xattr_operation_intent_t value; }; static const struct propertyListMapping PropertyListMapTable[] = { - { 'C', 'c', kCopyOperationPropertyContentDependent }, - { 'P', 'p', kCopyOperationPropertyNoExport }, - { 'N', 'n', kCopyOperationPropertyNeverPreserve }, + { '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 - * CopyOperationProperties_t type), and an intent, determine if + * 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 @@ -84,24 +103,27 @@ PropertyListMapTable[] = { * as being exclusionary. */ static const struct divineIntent { - CopyOperationIntent_t intent; - int (^checker)(CopyOperationProperties_t); + xattr_operation_intent_t intent; + int (^checker)(xattr_flags_t); } intentTable[] = { - { CopyOperationIntentCopy, ^(CopyOperationProperties_t props) { - if (props & kCopyOperationPropertyNeverPreserve) + { XATTR_OPERATION_INTENT_COPY, ^(xattr_flags_t flags) { + if (flags & XATTR_FLAG_NEVER_PRESERVE) return 0; return 1; } }, - { CopyOperationIntentSave, ^(CopyOperationProperties_t props) { - if (props & (kCopyOperationPropertyContentDependent | kCopyOperationPropertyNeverPreserve)) + { XATTR_OPERATION_INTENT_SAVE, ^(xattr_flags_t flags) { + if (flags & (XATTR_FLAG_CONTENT_DEPENDENT | XATTR_FLAG_NEVER_PRESERVE)) return 0; return 1; } }, - { CopyOperationIntentShare, ^(CopyOperationProperties_t props) { - if ((props & (kCopyOperationPropertyNoExport | kCopyOperationPropertyNeverPreserve)) != 0) + { 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 }, }; @@ -114,6 +136,15 @@ 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 && @@ -143,12 +174,12 @@ findPropertyList(const char *eaname) /* * Convert a property list string (e.g., "pCd") into a - * CopyOperationProperties_t type. + * xattr_operation_intent_t type. */ -static CopyOperationProperties_t +static xattr_operation_intent_t stringToProperties(const char *proplist) { - CopyOperationProperties_t retval = 0; + xattr_operation_intent_t retval = 0; const char *ptr; // A switch would be more efficient, but less generic. @@ -167,7 +198,7 @@ stringToProperties(const char *proplist) /* * Given an EA name (e.g., "com.apple.lfs.hfs.test"), and a - * CopyOperationProperties_t value (it's currently an integral value, so + * 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". @@ -186,7 +217,7 @@ stringToProperties(const char *proplist) * for sanity checking. That would require having more than 64 bits to use.) */ char * -_xattrNameWithProperties(const char *orig, CopyOperationProperties_t propList) +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 @@ -233,15 +264,51 @@ _xattrNameWithProperties(const char *orig, CopyOperationProperties_t propList) return retval; } -CopyOperationProperties_t -_xattrPropertiesFromName(const char *eaname) +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) { - CopyOperationProperties_t retval = 0; + xattr_flags_t retval = 0; const char *propList; propList = findPropertyList(eaname); if (propList == NULL) { - propList = findPropertyList(eaname); + propList = nameInDefaultList(eaname); } if (propList != NULL) { retval = stringToProperties(propList); @@ -257,32 +324,17 @@ _xattrPropertiesFromName(const char *eaname) * 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 + * 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 -_PreserveEA(const char *eaname, CopyOperationIntent_t intent) +xattr_preserve_for_intent(const char *eaname, xattr_operation_intent_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 + xattr_flags_t flags = xattr_flags_from_name(eaname); - return 1; // Default to preserving everything + 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 index 0000000..032b6ad --- /dev/null +++ b/xattr_flags.h @@ -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 + +#include +#include + +__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 index 0000000..509f8b1 --- /dev/null +++ b/xattr_name_with_flags.3 @@ -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.h b/xattr_properties.h index e6eb457..21d9a29 100644 --- a/xattr_properties.h +++ b/xattr_properties.h @@ -27,7 +27,7 @@ #include #include - +#include __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 index 0000000..d451a2a --- /dev/null +++ b/xcodescripts/copyfile.xcconfig @@ -0,0 +1,16 @@ +#include "/Makefiles/CoreOS/Xcode/BSD.xcconfig" +#include "/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 diff --git a/xcodescripts/install_files.sh b/xcodescripts/install_files.sh index 50174fb..8aacf91 100644 --- a/xcodescripts/install_files.sh +++ b/xcodescripts/install_files.sh @@ -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 + -- 2.45.2