[Sandbox] Refine broker to return handle to token
Sandbox Broker now returns a handle to the exact path object that was retained by the caller, so it will be released correctly, regardless of what happens to the list of bookmarked paths. Also refined the bookmark path comparison function. For existing paths, it will find the first match. For new paths, it will prefer the longest path instead, to try to find the deepest matching bookmark. Signed-off-by: Christopher Snowhill <kode54@gmail.com>swiftingly
parent
dbdcad6c04
commit
8dddf6a115
|
@ -48,7 +48,7 @@ static NSString *g_make_unpack_path(NSString *archive, NSString *file, NSString
|
|||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker beginFolderAccess:url];
|
||||
const void *sbHandle = [sandboxBroker beginFolderAccess:url];
|
||||
|
||||
fex_t *fex;
|
||||
fex_err_t error = fex_open(&fex, [[url path] UTF8String]);
|
||||
|
@ -68,7 +68,7 @@ static NSString *g_make_unpack_path(NSString *archive, NSString *file, NSString
|
|||
|
||||
fex_close(fex);
|
||||
|
||||
[sandboxBroker endFolderAccess:url];
|
||||
[sandboxBroker endFolderAccess:sbHandle];
|
||||
|
||||
return files;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
NSUInteger size;
|
||||
|
||||
NSURL *_url;
|
||||
NSURL *fileURL;
|
||||
|
||||
const void *sbHandle;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -85,12 +85,10 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi
|
|||
if(![type isEqualToString:@"fex"])
|
||||
return NO;
|
||||
|
||||
fileURL = [NSURL fileURLWithPath:archive];
|
||||
|
||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker beginFolderAccess:fileURL];
|
||||
sbHandle = [sandboxBroker beginFolderAccess:[NSURL fileURLWithPath:archive]];
|
||||
|
||||
fex_err_t error;
|
||||
|
||||
|
@ -161,11 +159,12 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi
|
|||
fex = NULL;
|
||||
}
|
||||
|
||||
if(fileURL) {
|
||||
if(sbHandle) {
|
||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker endFolderAccess:fileURL];
|
||||
[sandboxBroker endFolderAccess:sbHandle];
|
||||
sbHandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
FILE *_fd;
|
||||
|
||||
NSURL *_url;
|
||||
|
||||
const void *sbHandle;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker beginFolderAccess:url];
|
||||
sbHandle = [sandboxBroker beginFolderAccess:url];
|
||||
|
||||
NSString *path = [url path];
|
||||
|
||||
|
@ -131,10 +131,13 @@
|
|||
fex = NULL;
|
||||
}
|
||||
|
||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
if(sbHandle) {
|
||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker endFolderAccess:_url];
|
||||
[sandboxBroker endFolderAccess:sbHandle];
|
||||
sbHandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSURL *)url {
|
||||
|
|
|
@ -24,7 +24,7 @@ class BMPlayer;
|
|||
MIDIPlayer* player;
|
||||
midi_container midi_file;
|
||||
|
||||
NSURL* sandboxURL;
|
||||
const void* sbHandle;
|
||||
|
||||
NSString* globalSoundFontPath;
|
||||
BOOL soundFontsAssigned;
|
||||
|
|
|
@ -168,12 +168,14 @@ static OSType getOSType(const char *in_) {
|
|||
globalSoundFontPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"soundFontPath"];
|
||||
|
||||
if(globalSoundFontPath && [globalSoundFontPath length] > 0) {
|
||||
sandboxURL = [NSURL fileURLWithPath:[globalSoundFontPath stringByDeletingLastPathComponent]];
|
||||
NSURL *sandboxURL = [NSURL fileURLWithPath:[globalSoundFontPath stringByDeletingLastPathComponent]];
|
||||
|
||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker beginFolderAccess:sandboxURL];
|
||||
sbHandle = [sandboxBroker beginFolderAccess:sandboxURL];
|
||||
} else {
|
||||
sbHandle = NULL;
|
||||
}
|
||||
|
||||
// First detect if soundfont has gone AWOL
|
||||
|
@ -345,13 +347,12 @@ static OSType getOSType(const char *in_) {
|
|||
delete player;
|
||||
player = NULL;
|
||||
|
||||
if(sandboxURL) {
|
||||
if(sbHandle) {
|
||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker endFolderAccess:sandboxURL];
|
||||
|
||||
sandboxURL = nil;
|
||||
[sandboxBroker endFolderAccess:sbHandle];
|
||||
sbHandle = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||
|
||||
[sandboxBroker beginFolderAccess:url];
|
||||
const void *sbHandle = [sandboxBroker beginFolderAccess:url];
|
||||
|
||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||
|
||||
|
@ -237,7 +237,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
[sandboxBroker endFolderAccess:url];
|
||||
[sandboxBroker endFolderAccess:sbHandle];
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (id)init;
|
||||
- (void)shutdown;
|
||||
|
||||
- (void)beginFolderAccess:(NSURL *)fileUrl;
|
||||
- (void)endFolderAccess:(NSURL *)fileUrl;
|
||||
- (const void *)beginFolderAccess:(NSURL *)fileUrl;
|
||||
- (void)endFolderAccess:(const void *)handle;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -125,112 +125,102 @@ static NSURL *urlWithoutFragment(NSURL *u) {
|
|||
}
|
||||
}
|
||||
|
||||
- (void)recursivePathTest:(NSURL *)url removing:(BOOL)removing {
|
||||
NSArray *pathComponents = [url pathComponents];
|
||||
+ (BOOL)isPath:(NSURL *)path aSubdirectoryOf:(NSURL *)directory {
|
||||
NSArray *pathComponents = [path pathComponents];
|
||||
NSArray *directoryComponents = [directory pathComponents];
|
||||
|
||||
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"path" ascending:NO];
|
||||
if([pathComponents count] < [directoryComponents count])
|
||||
return NO;
|
||||
|
||||
for(size_t i = [pathComponents count]; i > 0; --i) {
|
||||
NSArray *partialComponents = [pathComponents subarrayWithRange:NSMakeRange(0, i)];
|
||||
NSURL *partialUrl = [NSURL fileURLWithPathComponents:partialComponents];
|
||||
NSString *matchString = [[partialUrl path] stringByAppendingString:@"*"];
|
||||
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"path like %@", matchString];
|
||||
|
||||
NSArray *matchingObjects = [storage filteredArrayUsingPredicate:predicate];
|
||||
|
||||
if(matchingObjects && [matchingObjects count] > 0) {
|
||||
if([matchingObjects count] > 1) {
|
||||
matchingObjects = [matchingObjects sortedArrayUsingDescriptors:@[sortDescriptor]];
|
||||
}
|
||||
|
||||
for(SandboxEntry *entry in matchingObjects) {
|
||||
if([entry.path isEqualToString:[partialUrl path]]) {
|
||||
if(!removing) {
|
||||
entry.refCount += 1;
|
||||
return;
|
||||
} else {
|
||||
if(entry.refCount > 1) {
|
||||
entry.refCount -= 1;
|
||||
return;
|
||||
} else {
|
||||
if(entry.secureUrl) {
|
||||
[entry.secureUrl stopAccessingSecurityScopedResource];
|
||||
entry.secureUrl = nil;
|
||||
}
|
||||
entry.refCount = 0;
|
||||
|
||||
[storage removeObject:entry];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(size_t i = 0; i < [directoryComponents count]; ++i) {
|
||||
if(![pathComponents[i] isEqualToString:directoryComponents[i]])
|
||||
return NO;
|
||||
}
|
||||
|
||||
if(removing) return;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (SandboxEntry *)recursivePathTest:(NSURL *)url {
|
||||
for(SandboxEntry *entry in storage) {
|
||||
if([SandboxBroker isPath:url aSubdirectoryOf:[NSURL fileURLWithPath:entry.path]]) {
|
||||
entry.refCount += 1;
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
NSPersistentContainer *pc = [NSApp sharedPersistentContainer];
|
||||
|
||||
for(size_t i = [pathComponents count]; i > 0; --i) {
|
||||
NSArray *partialComponents = [pathComponents subarrayWithRange:NSMakeRange(0, i)];
|
||||
NSURL *partialUrl = [NSURL fileURLWithPathComponents:partialComponents];
|
||||
NSString *matchString = [[partialUrl path] stringByAppendingString:@"*"];
|
||||
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"path.length" ascending:NO];
|
||||
|
||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"path like %@", matchString];
|
||||
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
|
||||
request.sortDescriptors = @[sortDescriptor];
|
||||
|
||||
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
|
||||
request.predicate = predicate;
|
||||
request.sortDescriptors = @[sortDescriptor];
|
||||
NSError *error = nil;
|
||||
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
|
||||
|
||||
NSError *error = nil;
|
||||
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
|
||||
if(results && [results count] > 0) {
|
||||
for(SandboxToken *token in results) {
|
||||
if([SandboxBroker isPath:url aSubdirectoryOf:[NSURL fileURLWithPath:token.path]]) {
|
||||
SandboxEntry *entry = [[SandboxEntry alloc] initWithToken:token];
|
||||
|
||||
if(results && [results count] > 0) {
|
||||
for(SandboxToken *token in results) {
|
||||
if([token.path isEqualToString:[partialUrl path]]) {
|
||||
SandboxEntry *entry = [[SandboxEntry alloc] initWithToken:token];
|
||||
[storage addObject:entry];
|
||||
|
||||
[storage addObject:entry];
|
||||
|
||||
BOOL isStale;
|
||||
NSError *err = nil;
|
||||
NSURL *secureUrl = [NSURL URLByResolvingBookmarkData:token.bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&err];
|
||||
if(!secureUrl && err) {
|
||||
ALog(@"Failed to access bookmark for URL: %@, error: %@", token.path, [err localizedDescription]);
|
||||
return;
|
||||
}
|
||||
|
||||
entry.secureUrl = secureUrl;
|
||||
|
||||
[secureUrl startAccessingSecurityScopedResource];
|
||||
|
||||
return;
|
||||
BOOL isStale;
|
||||
NSError *err = nil;
|
||||
NSURL *secureUrl = [NSURL URLByResolvingBookmarkData:token.bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&err];
|
||||
if(!secureUrl && err) {
|
||||
ALog(@"Failed to access bookmark for URL: %@, error: %@", token.path, [err localizedDescription]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
entry.secureUrl = secureUrl;
|
||||
|
||||
[secureUrl startAccessingSecurityScopedResource];
|
||||
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)beginFolderAccess:(NSURL *)fileUrl {
|
||||
- (const void *)beginFolderAccess:(NSURL *)fileUrl {
|
||||
NSURL *folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
|
||||
if(![folderUrl isFileURL]) return;
|
||||
if(![NSApp respondsToSelector:@selector(sharedPersistentContainer)]) return;
|
||||
if(![folderUrl isFileURL]) return NULL;
|
||||
if(![NSApp respondsToSelector:@selector(sharedPersistentContainer)]) return NULL;
|
||||
|
||||
SandboxEntry *entry;
|
||||
|
||||
@synchronized(self) {
|
||||
[self recursivePathTest:folderUrl removing:NO];
|
||||
entry = [self recursivePathTest:folderUrl];
|
||||
}
|
||||
|
||||
if(entry) {
|
||||
return CFBridgingRetain(entry);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)endFolderAccess:(NSURL *)fileUrl {
|
||||
NSURL *folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
|
||||
if(![folderUrl isFileURL]) return;
|
||||
- (void)endFolderAccess:(const void *)handle {
|
||||
if(!handle) return;
|
||||
SandboxEntry *entry = CFBridgingRelease(handle);
|
||||
if(!entry) return;
|
||||
|
||||
@synchronized(self) {
|
||||
[self recursivePathTest:folderUrl removing:YES];
|
||||
if(entry.refCount > 1) {
|
||||
entry.refCount -= 1;
|
||||
return;
|
||||
} else {
|
||||
if(entry.secureUrl) {
|
||||
[entry.secureUrl stopAccessingSecurityScopedResource];
|
||||
entry.secureUrl = nil;
|
||||
}
|
||||
entry.refCount = 0;
|
||||
|
||||
[storage removeObject:entry];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue