[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 sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker beginFolderAccess:url];
|
const void *sbHandle = [sandboxBroker beginFolderAccess:url];
|
||||||
|
|
||||||
fex_t *fex;
|
fex_t *fex;
|
||||||
fex_err_t error = fex_open(&fex, [[url path] UTF8String]);
|
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);
|
fex_close(fex);
|
||||||
|
|
||||||
[sandboxBroker endFolderAccess:url];
|
[sandboxBroker endFolderAccess:sbHandle];
|
||||||
|
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@
|
||||||
NSUInteger size;
|
NSUInteger size;
|
||||||
|
|
||||||
NSURL *_url;
|
NSURL *_url;
|
||||||
NSURL *fileURL;
|
|
||||||
|
const void *sbHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -85,12 +85,10 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi
|
||||||
if(![type isEqualToString:@"fex"])
|
if(![type isEqualToString:@"fex"])
|
||||||
return NO;
|
return NO;
|
||||||
|
|
||||||
fileURL = [NSURL fileURLWithPath:archive];
|
|
||||||
|
|
||||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker beginFolderAccess:fileURL];
|
sbHandle = [sandboxBroker beginFolderAccess:[NSURL fileURLWithPath:archive]];
|
||||||
|
|
||||||
fex_err_t error;
|
fex_err_t error;
|
||||||
|
|
||||||
|
@ -161,11 +159,12 @@ static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **fi
|
||||||
fex = NULL;
|
fex = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fileURL) {
|
if(sbHandle) {
|
||||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker endFolderAccess:fileURL];
|
[sandboxBroker endFolderAccess:sbHandle];
|
||||||
|
sbHandle = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
FILE *_fd;
|
FILE *_fd;
|
||||||
|
|
||||||
NSURL *_url;
|
NSURL *_url;
|
||||||
|
|
||||||
|
const void *sbHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker beginFolderAccess:url];
|
sbHandle = [sandboxBroker beginFolderAccess:url];
|
||||||
|
|
||||||
NSString *path = [url path];
|
NSString *path = [url path];
|
||||||
|
|
||||||
|
@ -131,10 +131,13 @@
|
||||||
fex = NULL;
|
fex = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
if(sbHandle) {
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker endFolderAccess:_url];
|
[sandboxBroker endFolderAccess:sbHandle];
|
||||||
|
sbHandle = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURL *)url {
|
- (NSURL *)url {
|
||||||
|
|
|
@ -24,7 +24,7 @@ class BMPlayer;
|
||||||
MIDIPlayer* player;
|
MIDIPlayer* player;
|
||||||
midi_container midi_file;
|
midi_container midi_file;
|
||||||
|
|
||||||
NSURL* sandboxURL;
|
const void* sbHandle;
|
||||||
|
|
||||||
NSString* globalSoundFontPath;
|
NSString* globalSoundFontPath;
|
||||||
BOOL soundFontsAssigned;
|
BOOL soundFontsAssigned;
|
||||||
|
|
|
@ -168,12 +168,14 @@ static OSType getOSType(const char *in_) {
|
||||||
globalSoundFontPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"soundFontPath"];
|
globalSoundFontPath = [[NSUserDefaults standardUserDefaults] stringForKey:@"soundFontPath"];
|
||||||
|
|
||||||
if(globalSoundFontPath && [globalSoundFontPath length] > 0) {
|
if(globalSoundFontPath && [globalSoundFontPath length] > 0) {
|
||||||
sandboxURL = [NSURL fileURLWithPath:[globalSoundFontPath stringByDeletingLastPathComponent]];
|
NSURL *sandboxURL = [NSURL fileURLWithPath:[globalSoundFontPath stringByDeletingLastPathComponent]];
|
||||||
|
|
||||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker beginFolderAccess:sandboxURL];
|
sbHandle = [sandboxBroker beginFolderAccess:sandboxURL];
|
||||||
|
} else {
|
||||||
|
sbHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First detect if soundfont has gone AWOL
|
// First detect if soundfont has gone AWOL
|
||||||
|
@ -345,13 +347,12 @@ static OSType getOSType(const char *in_) {
|
||||||
delete player;
|
delete player;
|
||||||
player = NULL;
|
player = NULL;
|
||||||
|
|
||||||
if(sandboxURL) {
|
if(sbHandle) {
|
||||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker endFolderAccess:sandboxURL];
|
[sandboxBroker endFolderAccess:sbHandle];
|
||||||
|
sbHandle = NULL;
|
||||||
sandboxURL = nil;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
|
||||||
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
|
||||||
|
|
||||||
[sandboxBroker beginFolderAccess:url];
|
const void *sbHandle = [sandboxBroker beginFolderAccess:url];
|
||||||
|
|
||||||
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[sandboxBroker endFolderAccess:url];
|
[sandboxBroker endFolderAccess:sbHandle];
|
||||||
|
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
- (id)init;
|
- (id)init;
|
||||||
- (void)shutdown;
|
- (void)shutdown;
|
||||||
|
|
||||||
- (void)beginFolderAccess:(NSURL *)fileUrl;
|
- (const void *)beginFolderAccess:(NSURL *)fileUrl;
|
||||||
- (void)endFolderAccess:(NSURL *)fileUrl;
|
- (void)endFolderAccess:(const void *)handle;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -125,112 +125,102 @@ static NSURL *urlWithoutFragment(NSURL *u) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)recursivePathTest:(NSURL *)url removing:(BOOL)removing {
|
+ (BOOL)isPath:(NSURL *)path aSubdirectoryOf:(NSURL *)directory {
|
||||||
NSArray *pathComponents = [url pathComponents];
|
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) {
|
for(size_t i = 0; i < [directoryComponents count]; ++i) {
|
||||||
NSArray *partialComponents = [pathComponents subarrayWithRange:NSMakeRange(0, i)];
|
if(![pathComponents[i] isEqualToString:directoryComponents[i]])
|
||||||
NSURL *partialUrl = [NSURL fileURLWithPathComponents:partialComponents];
|
return NO;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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];
|
NSPersistentContainer *pc = [NSApp sharedPersistentContainer];
|
||||||
|
|
||||||
for(size_t i = [pathComponents count]; i > 0; --i) {
|
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"path.length" ascending:NO];
|
||||||
NSArray *partialComponents = [pathComponents subarrayWithRange:NSMakeRange(0, i)];
|
|
||||||
NSURL *partialUrl = [NSURL fileURLWithPathComponents:partialComponents];
|
|
||||||
NSString *matchString = [[partialUrl path] stringByAppendingString:@"*"];
|
|
||||||
|
|
||||||
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"path like %@", matchString];
|
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
|
||||||
|
request.sortDescriptors = @[sortDescriptor];
|
||||||
|
|
||||||
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"SandboxToken"];
|
NSError *error = nil;
|
||||||
request.predicate = predicate;
|
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
|
||||||
request.sortDescriptors = @[sortDescriptor];
|
|
||||||
|
|
||||||
NSError *error = nil;
|
if(results && [results count] > 0) {
|
||||||
NSArray *results = [pc.viewContext executeFetchRequest:request error:&error];
|
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) {
|
[storage addObject:entry];
|
||||||
for(SandboxToken *token in results) {
|
|
||||||
if([token.path isEqualToString:[partialUrl path]]) {
|
|
||||||
SandboxEntry *entry = [[SandboxEntry alloc] initWithToken:token];
|
|
||||||
|
|
||||||
[storage addObject:entry];
|
BOOL isStale;
|
||||||
|
NSError *err = nil;
|
||||||
BOOL isStale;
|
NSURL *secureUrl = [NSURL URLByResolvingBookmarkData:token.bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&err];
|
||||||
NSError *err = nil;
|
if(!secureUrl && err) {
|
||||||
NSURL *secureUrl = [NSURL URLByResolvingBookmarkData:token.bookmark options:NSURLBookmarkResolutionWithSecurityScope relativeToURL:nil bookmarkDataIsStale:&isStale error:&err];
|
ALog(@"Failed to access bookmark for URL: %@, error: %@", token.path, [err localizedDescription]);
|
||||||
if(!secureUrl && err) {
|
return nil;
|
||||||
ALog(@"Failed to access bookmark for URL: %@, error: %@", token.path, [err localizedDescription]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.secureUrl = secureUrl;
|
|
||||||
|
|
||||||
[secureUrl startAccessingSecurityScopedResource];
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry.secureUrl = secureUrl;
|
||||||
|
|
||||||
|
[secureUrl startAccessingSecurityScopedResource];
|
||||||
|
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)beginFolderAccess:(NSURL *)fileUrl {
|
- (const void *)beginFolderAccess:(NSURL *)fileUrl {
|
||||||
NSURL *folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
|
NSURL *folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
|
||||||
if(![folderUrl isFileURL]) return;
|
if(![folderUrl isFileURL]) return NULL;
|
||||||
if(![NSApp respondsToSelector:@selector(sharedPersistentContainer)]) return;
|
if(![NSApp respondsToSelector:@selector(sharedPersistentContainer)]) return NULL;
|
||||||
|
|
||||||
|
SandboxEntry *entry;
|
||||||
|
|
||||||
@synchronized(self) {
|
@synchronized(self) {
|
||||||
[self recursivePathTest:folderUrl removing:NO];
|
entry = [self recursivePathTest:folderUrl];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(entry) {
|
||||||
|
return CFBridgingRetain(entry);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)endFolderAccess:(NSURL *)fileUrl {
|
- (void)endFolderAccess:(const void *)handle {
|
||||||
NSURL *folderUrl = [urlWithoutFragment(fileUrl) URLByDeletingLastPathComponent];
|
if(!handle) return;
|
||||||
if(![folderUrl isFileURL]) return;
|
SandboxEntry *entry = CFBridgingRelease(handle);
|
||||||
|
if(!entry) return;
|
||||||
|
|
||||||
@synchronized(self) {
|
@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