Skip to content

Commit

Permalink
Fix portable mode on macOS.
Browse files Browse the repository at this point in the history
  • Loading branch information
squidbus committed Mar 5, 2025
1 parent ce46aff commit 535741d
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 1 deletion.
5 changes: 5 additions & 0 deletions UnleashedRecomp/os/linux/process_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ std::filesystem::path os::process::GetExecutablePath()
}
}

std::filesystem::path os::process::GetExecutableRoot()
{
return GetExecutablePath().remove_filename();
}

std::filesystem::path os::process::GetWorkingDirectory()
{
char cwd[PATH_MAX] = {};
Expand Down
61 changes: 61 additions & 0 deletions UnleashedRecomp/os/macos/process_macos.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#include <os/process.h>

#include <CoreFoundation/CFBundle.h>
#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <signal.h>
#include <sys/param.h>
#include <unistd.h>

std::filesystem::path os::process::GetExecutablePath()
Expand All @@ -18,6 +21,64 @@ std::filesystem::path os::process::GetExecutablePath()
}
}

using IsTranslocatedURLFunc = Boolean (*)(CFURLRef path, bool* isTranslocated,
CFErrorRef* __nullable error);
using CreateOriginalPathForURLFunc = CFURLRef __nullable (*)(CFURLRef translocatedPath,
CFErrorRef* __nullable error);

static CFURLRef UntranslocateBundlePath(const CFURLRef bundlePath)
{
CFURLRef resultPath = nullptr;
if (void* securityHandle = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY))
{
const auto IsTranslocatedURL = reinterpret_cast<IsTranslocatedURLFunc>(
dlsym(securityHandle, "SecTranslocateIsTranslocatedURL"));
const auto CreateOriginalPathForURL = reinterpret_cast<CreateOriginalPathForURLFunc>(
dlsym(securityHandle, "SecTranslocateCreateOriginalPathForURL"));

bool translocated = false;
if (IsTranslocatedURL && CreateOriginalPathForURL &&
IsTranslocatedURL(bundlePath, &translocated, nullptr) && translocated)
{
resultPath = CreateOriginalPathForURL(bundlePath, nullptr);
}

dlclose(securityHandle);
}
return resultPath;
}

std::filesystem::path os::process::GetExecutableRoot()
{
std::filesystem::path appPath = GetExecutablePath();
if (CFBundleRef bundleRef = CFBundleGetMainBundle())
{
if (CFURLRef bundleUrlRef = CFBundleCopyBundleURL(bundleRef))
{
// The OS may relocate the app elsewhere for security reasons if,
// for example, it was downloaded and opened from the Downloads
// folder. In this case, we need to untranslocate the path to
// find out where the actual app bundle is.
CFURLRef untranslocatedUrlRef = UntranslocateBundlePath(bundleUrlRef);

char appBundlePath[MAXPATHLEN];
if (CFURLGetFileSystemRepresentation(
untranslocatedUrlRef ? untranslocatedUrlRef : bundleUrlRef, true,
reinterpret_cast<uint8_t*>(appBundlePath), sizeof(appBundlePath)))
{
appPath = std::filesystem::path(appBundlePath);
}

if (untranslocatedUrlRef)
{
CFRelease(untranslocatedUrlRef);
}
CFRelease(bundleUrlRef);
}
}
return appPath.remove_filename();
}

std::filesystem::path os::process::GetWorkingDirectory()
{
char cwd[PATH_MAX] = {};
Expand Down
1 change: 1 addition & 0 deletions UnleashedRecomp/os/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace os::process
inline bool g_consoleVisible;

std::filesystem::path GetExecutablePath();
std::filesystem::path GetExecutableRoot();
std::filesystem::path GetWorkingDirectory();
bool SetWorkingDirectory(const std::filesystem::path& path);
bool StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work = {});
Expand Down
5 changes: 5 additions & 0 deletions UnleashedRecomp/os/win32/process_win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ std::filesystem::path os::process::GetExecutablePath()
return std::filesystem::path(exePath);
}

std::filesystem::path os::process::GetExecutableRoot()
{
return GetExecutablePath().remove_filename();
}

std::filesystem::path os::process::GetWorkingDirectory()
{
WCHAR workPath[MAX_PATH];
Expand Down
2 changes: 1 addition & 1 deletion UnleashedRecomp/user/paths.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "paths.h"
#include <os/process.h>

std::filesystem::path g_executableRoot = os::process::GetExecutablePath().remove_filename();
std::filesystem::path g_executableRoot = os::process::GetExecutableRoot();
std::filesystem::path g_userPath = BuildUserPath();

bool CheckPortable()
Expand Down

0 comments on commit 535741d

Please sign in to comment.