Blender V4.3
storage_apple.mm
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#import <Foundation/Foundation.h>
12#include <string>
13#include <sys/xattr.h>
14
15#include "BLI_fileops.h"
16#include "BLI_path_utils.hh"
17#include "BLI_string.h"
18
19/* Extended file attribute used by OneDrive to mark placeholder files. */
20static const char *ONEDRIVE_RECALLONOPEN_ATTRIBUTE = "com.microsoft.OneDrive.RecallOnOpen";
21
26/* False alarm by clang-tidy: #getFileSystemRepresentation changes the return value argument. */
27/* NOLINTNEXTLINE: readability-non-const-parameter. */
28bool BLI_file_alias_target(const char *filepath, char r_targetpath[FILE_MAXDIR])
29{
30 /* clang-format off */
31 @autoreleasepool {
32 /* clang-format on */
33 NSError *error = nil;
34 NSURL *shortcutURL = [[NSURL alloc] initFileURLWithFileSystemRepresentation:filepath
35 isDirectory:NO
36 relativeToURL:nil];
37
38 /* Note, NSURLBookmarkResolutionWithoutMounting keeps blender from crashing when an alias can't
39 * be mounted */
40 NSURL *targetURL = [NSURL URLByResolvingAliasFileAtURL:shortcutURL
41 options:NSURLBookmarkResolutionWithoutUI |
42 NSURLBookmarkResolutionWithoutMounting
43 error:&error];
44 const BOOL isSame = [shortcutURL isEqual:targetURL] and
45 ([[[shortcutURL path] stringByStandardizingPath]
46 isEqualToString:[[targetURL path] stringByStandardizingPath]]);
47
48 if (targetURL == nil) {
49 return false;
50 }
51 if (isSame) {
52 [targetURL getFileSystemRepresentation:r_targetpath maxLength:FILE_MAXDIR];
53 return false;
54 }
55 /* Note that the if-condition may also change the value of `r_targetpath`. */
56 if (![targetURL getFileSystemRepresentation:r_targetpath maxLength:FILE_MAXDIR]) {
57 return false;
58 }
59 }
60
61 return true;
62}
63
71static bool find_attribute(const std::string &attributes, const char *search_attribute)
72{
73 /* Attributes is a list of consecutive null-terminated strings. */
74 const char *end = attributes.data() + attributes.size();
75 for (const char *item = attributes.data(); item < end; item += strlen(item) + 1) {
76 if (STREQ(item, search_attribute)) {
77 return true;
78 }
79 }
80
81 return false;
82}
83
90static bool test_onedrive_file_is_placeholder(const char *path)
91{
92 /* NOTE: Currently only checking for the "com.microsoft.OneDrive.RecallOnOpen" extended file
93 * attribute. In theory this attribute can also be set on files that aren't located inside a
94 * OneDrive folder. Maybe additional checks are required? */
95
96 /* Get extended file attributes */
97 ssize_t size = listxattr(path, nullptr, 0, XATTR_NOFOLLOW);
98 if (size < 1) {
99 return false;
100 }
101
102 std::string attributes(size, '\0');
103 size = listxattr(path, attributes.data(), size, XATTR_NOFOLLOW);
104 /* In case listxattr() has failed the second time it's called. */
105 if (size < 1) {
106 return false;
107 }
108
109 /* Check for presence of 'com.microsoft.OneDrive.RecallOnOpen' attribute. */
111}
112
119static bool test_file_is_offline(const char *path)
120{
121 /* Logic for additional cloud storage providers could be added in the future. */
123}
124
126{
127 int ret = 0;
128
129 /* clang-format off */
130 @autoreleasepool {
131 /* clang-format on */
132 NSURL *fileURL = [[[NSURL alloc] initFileURLWithFileSystemRepresentation:path
133 isDirectory:NO
134 relativeToURL:nil] autorelease];
135
136 /* Querying NSURLIsReadableKey and NSURLIsWritableKey keys for OneDrive placeholder files
137 * triggers their unwanted download. */
138 NSArray *resourceKeys = nullptr;
139 const bool is_offline = test_file_is_offline(path);
140
141 if (is_offline) {
142 resourceKeys = @[ NSURLIsAliasFileKey, NSURLIsHiddenKey ];
143 }
144 else {
145 resourceKeys =
146 @[ NSURLIsAliasFileKey, NSURLIsHiddenKey, NSURLIsReadableKey, NSURLIsWritableKey ];
147 }
148
149 NSDictionary *resourceKeyValues = [fileURL resourceValuesForKeys:resourceKeys error:nil];
150
151 const bool is_alias = [resourceKeyValues[(void)(@"@%"), NSURLIsAliasFileKey] boolValue];
152 const bool is_hidden = [resourceKeyValues[(void)(@"@%"), NSURLIsHiddenKey] boolValue];
153 const bool is_readable = is_offline ||
154 [resourceKeyValues[(void)(@"@%"), NSURLIsReadableKey] boolValue];
155 const bool is_writable = is_offline ||
156 [resourceKeyValues[(void)(@"@%"), NSURLIsWritableKey] boolValue];
157
158 if (is_alias) {
160 }
161 if (is_hidden) {
163 }
164 if (is_readable && !is_writable) {
166 }
167 if (!is_readable) {
169 }
170 if (is_offline) {
172 }
173 }
174
175 return (eFileAttributes)ret;
176}
177
178const char *BLI_expand_tilde(const char *path_with_tilde)
179{
180 static char path_expanded[FILE_MAX];
181 @autoreleasepool {
182 NSString *str_with_tilde = [[NSString alloc] initWithCString:path_with_tilde
183 encoding:NSUTF8StringEncoding];
184 if (!str_with_tilde) {
185 return nullptr;
186 }
187 NSString *str_expanded = [str_with_tilde stringByExpandingTildeInPath];
188 [str_expanded getCString:path_expanded
189 maxLength:sizeof(path_expanded)
190 encoding:NSUTF8StringEncoding];
191 }
192 return path_expanded;
193}
194
195char *BLI_current_working_dir(char *dir, const size_t maxncpy)
196{
197 /* Can't just copy to the *dir pointer, as [path getCString gets grumpy. */
198 char path_expanded[PATH_MAX];
199 @autoreleasepool {
200 NSString *path = [[NSFileManager defaultManager] currentDirectoryPath];
201 const size_t length = maxncpy > PATH_MAX ? PATH_MAX : maxncpy;
202 [path getCString:path_expanded maxLength:length encoding:NSUTF8StringEncoding];
203 BLI_strncpy(dir, path_expanded, maxncpy);
204 return dir;
205 }
206}
207
208bool BLI_change_working_dir(const char *dir)
209{
210 @autoreleasepool {
211 NSString *path = [[NSString alloc] initWithUTF8String:dir];
212 if ([[NSFileManager defaultManager] changeCurrentDirectoryPath:path] == YES) {
213 return true;
214 }
215 return false;
216 }
217}
File and directory operations.
eFileAttributes
@ FILE_ATTR_ALIAS
@ FILE_ATTR_HIDDEN
@ FILE_ATTR_READONLY
@ FILE_ATTR_SYSTEM
@ FILE_ATTR_OFFLINE
#define PATH_MAX
Definition BLI_fileops.h:30
#define FILE_MAX
#define FILE_MAXDIR
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STREQ(a, b)
CCL_NAMESPACE_BEGIN struct Options options
static void error(const char *str)
return ret
bool BLI_change_working_dir(const char *dir)
eFileAttributes BLI_file_attributes(const char *path)
static const char * ONEDRIVE_RECALLONOPEN_ATTRIBUTE
bool BLI_file_alias_target(const char *filepath, char r_targetpath[FILE_MAXDIR])
static bool test_onedrive_file_is_placeholder(const char *path)
static bool test_file_is_offline(const char *path)
char * BLI_current_working_dir(char *dir, const size_t maxncpy)
const char * BLI_expand_tilde(const char *path_with_tilde)
static bool find_attribute(const std::string &attributes, const char *search_attribute)