Commit: cab23264f25f96556ea0ee659214c6ca320f9a74 Author: Leon Zandman Date: Mon Jun 14 11:16:42 2021 +0200 Branches: override-recursive-resync https://developer.blender.org/rBcab23264f25f96556ea0ee659214c6ca320f9a74
Fix T87867: file open dialog triggers OneDrive file downloads on macOS Until OneDrive supports macOS's native placeholder file implementation, detect the com.microsoft.OneDrive.RecallOnOpen extended file attribute. Differential Revision: https://developer.blender.org/D11466 =================================================================== M source/blender/blenlib/intern/storage_apple.mm =================================================================== diff --git a/source/blender/blenlib/intern/storage_apple.mm b/source/blender/blenlib/intern/storage_apple.mm index 2a4bbffa60e..8af98d61ecb 100644 --- a/source/blender/blenlib/intern/storage_apple.mm +++ b/source/blender/blenlib/intern/storage_apple.mm @@ -24,10 +24,15 @@ */ #import <Foundation/Foundation.h> +#include <string> +#include <sys/xattr.h> #include "BLI_fileops.h" #include "BLI_path_util.h" +/* Extended file attribute used by OneDrive to mark placeholder files. */ +static const char *ONEDRIVE_RECALLONOPEN_ATTRIBUTE = "com.microsoft.OneDrive.RecallOnOpen"; + /** * \param r_targetpath: Buffer for the target path an alias points to. * \return Whether the file at the input path is an alias. @@ -66,6 +71,67 @@ bool BLI_file_alias_target(const char *filepath, char r_targetpath[FILE_MAXDIR]) return true; } +/** + * Checks if the given string of listxattr() attributes contains a specific attribute. + * + * \param attributes: a string of null-terminated listxattr() attributes. + * \param search_attribute: the attribute to search for. + * \return 'true' when the attribute is found, otherwise 'false'. + */ +static bool find_attribute(const std::string &attributes, const char *search_attribute) +{ + /* Attributes is a list of consecutive null-terminated strings. */ + const char *end = attributes.data() + attributes.size(); + for (const char *item = attributes.data(); item < end; item += strlen(item) + 1) { + if (STREQ(item, search_attribute)) { + return true; + } + } + + return false; +} + +/** + * Checks if the file is merely a placeholder for a OneDrive file that hasn't yet been downloaded. + * + * \param path: the path of the file. + * \return 'true' when the file is a OneDrive placeholder, otherwise 'false'. + */ +static bool test_onedrive_file_is_placeholder(const char *path) +{ + /* Note: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file + * attribute. In theory this attribute can also be set on files that aren't located inside a + * OneDrive folder. Maybe additional checks are required? */ + + /* Get extended file attributes */ + ssize_t size = listxattr(path, nullptr, 0, XATTR_NOFOLLOW); + if (size < 1) { + return false; + } + + std::string attributes(size, '\0'); + size = listxattr(path, attributes.data(), size, XATTR_NOFOLLOW); + /* In case listxattr() has failed the second time it's called. */ + if (size < 1) { + return false; + } + + /* Check for presence of 'com.microsoft.OneDrive.RecallOnOpen' attribute. */ + return find_attribute(attributes, ONEDRIVE_RECALLONOPEN_ATTRIBUTE); +} + +/** + * Checks if the file is marked as offline and not immediately available. + * + * \param path: the path of the file. + * \return 'true' when the file is a placeholder, otherwise 'false'. + */ +static bool test_file_is_offline(const char *path) +{ + /* Logic for additional cloud storage providers could be added in the future. */ + return test_onedrive_file_is_placeholder(path); +} + eFileAttributes BLI_file_attributes(const char *path) { int ret = 0; @@ -76,15 +142,28 @@ eFileAttributes BLI_file_attributes(const char *path) const NSURL *fileURL = [[NSURL alloc] initFileURLWithFileSystemRepresentation:path isDirectory:NO relativeToURL:nil]; - NSArray *resourceKeys = - @[ NSURLIsAliasFileKey, NSURLIsHiddenKey, NSURLIsReadableKey, NSURLIsWritableKey ]; + + /* Querying NSURLIsReadableKey and NSURLIsWritableKey keys for OneDrive placeholder files + * triggers their unwanted download. */ + NSArray *resourceKeys = nullptr; + const bool is_offline = test_file_is_offline(path); + + if (is_offline) { + resourceKeys = @[ NSURLIsAliasFileKey, NSURLIsHiddenKey ]; + } + else { + resourceKeys = + @[ NSURLIsAliasFileKey, NSURLIsHiddenKey, NSURLIsReadableKey, NSURLIsWritableKey ]; + } const NSDictionary *resourceKeyValues = [fileURL resourceValuesForKeys:resourceKeys error:nil]; const bool is_alias = [resourceKeyValues[(void)(@"@%"), NSURLIsAliasFileKey] boolValue]; const bool is_hidden = [resourceKeyValues[(void)(@"@%"), NSURLIsHiddenKey] boolValue]; - const bool is_readable = [resourceKeyValues[(void)(@"@%"), NSURLIsReadableKey] boolValue]; - const bool is_writable = [resourceKeyValues[(void)(@"@%"), NSURLIsWritableKey] boolValue]; + const bool is_readable = is_offline || + [resourceKeyValues[(void)(@"@%"), NSURLIsReadableKey] boolValue]; + const bool is_writable = is_offline || + [resourceKeyValues[(void)(@"@%"), NSURLIsWritableKey] boolValue]; if (is_alias) { ret |= FILE_ATTR_ALIAS; @@ -98,6 +177,9 @@ eFileAttributes BLI_file_attributes(const char *path) if (!is_readable) { ret |= FILE_ATTR_SYSTEM; } + if (is_offline) { + ret |= FILE_ATTR_OFFLINE; + } } return (eFileAttributes)ret; _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs