diff --git a/PFMoveApplication.m b/PFMoveApplication.m index 12e84c1..5583454 100644 --- a/PFMoveApplication.m +++ b/PFMoveApplication.m @@ -42,6 +42,7 @@ // Helper functions +static NSURL * GetOriginalBundleURL(void); static NSString *PreferredInstallLocation(BOOL *isUserDirectory); static BOOL IsInApplicationsFolder(NSString *path); static BOOL IsInDownloadsFolder(NSString *path); @@ -61,7 +62,7 @@ void PFMoveToApplicationsFolderIfNecessary(void) { if ([[NSUserDefaults standardUserDefaults] boolForKey:AlertSuppressKey]) return; // Path of the bundle - NSString *bundlePath = [[NSBundle mainBundle] bundlePath]; + NSString *bundlePath = GetOriginalBundleURL().path; // Check if the bundle is embedded in another application BOOL isNestedApplication = IsApplicationAtPathNested(bundlePath); @@ -210,6 +211,51 @@ void PFMoveToApplicationsFolderIfNecessary(void) { #pragma mark - #pragma mark Helper Functions +/// Gets the real bundle path of the application, not the Translocated one if applicable +static NSURL * GetOriginalBundleURL(void) { + + NSURL * bundleURL = [NSBundle mainBundle].bundleURL; + NSLog(@"%s: Foundation says bundle URL is %@", __FUNCTION__, bundleURL); + + // #define NSAppKitVersionNumber10_11 1404 + if (floor(NSAppKitVersionNumber) <= 1404) { + return bundleURL; + } + + void * handle = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY); + if (handle == NULL) { + return bundleURL; + } + + bool isTranslocated = false; + + // Get (undocumented?) function symbols for looking up app translocation info + // Note: was available in the macOS 10.12 beta SDKs but seems to have been removed as of Xcode 8.1 + Boolean(*mySecTranslocateIsTranslocatedURL)(CFURLRef path, bool *isTranslocated, CFErrorRef * __nullable error) = dlsym(handle, "SecTranslocateIsTranslocatedURL"); + CFURLRef __nullable(*mySecTranslocateCreateOriginalPathForURL)(CFURLRef translocatedPath, CFErrorRef * __nullable error) = dlsym(handle, "SecTranslocateCreateOriginalPathForURL"); + + dlclose(handle); + + if (mySecTranslocateIsTranslocatedURL == NULL || mySecTranslocateCreateOriginalPathForURL == NULL) { + NSLog(@"%s: We're running on macOS >= 10.12 but the SecTranslocate functions are not available", __FUNCTION__); + return bundleURL; + } + + if (mySecTranslocateIsTranslocatedURL((__bridge CFURLRef)bundleURL, &isTranslocated, NULL) && isTranslocated) + { + CFURLRef originalURL = mySecTranslocateCreateOriginalPathForURL((__bridge CFURLRef)bundleURL, NULL); + if (originalURL != NULL) + { + NSURL * result = CFBridgingRelease(originalURL); + NSLog(@"%s: Security says bundle is Translocated from %@", __FUNCTION__, result); + return result; + } + } + + NSLog(@"%s: Translocation not in effect", __FUNCTION__); + return bundleURL; +} + static NSString *PreferredInstallLocation(BOOL *isUserDirectory) { // Return the preferred install location. // Assume that if the user has a ~/Applications folder, they'd prefer their