From 3a4ebb1413cb4767bb03cd11263eb188ea2d97f0 Mon Sep 17 00:00:00 2001
From: Steveice10 <1269164+Steveice10@users.noreply.github.com>
Date: Sun, 18 Feb 2024 15:21:53 -0800
Subject: [PATCH] file_util: Make sure portable user path is absolute. (#7448)

---
 src/citra_qt/main.cpp     |  6 ++--
 src/common/common_paths.h |  1 -
 src/common/file_util.cpp  | 63 ++++++++++++++++++++++-----------------
 src/common/file_util.h    |  5 +---
 4 files changed, 41 insertions(+), 34 deletions(-)

diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 4f179a35c4..5d8b4204be 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -3197,8 +3197,10 @@ int main(int argc, char* argv[]) {
     QApplication::setHighDpiScaleFactorRoundingPolicy(rounding_policy);
 
 #ifdef __APPLE__
-    std::string bin_path = FileUtil::GetBundleDirectory() + DIR_SEP + "..";
-    chdir(bin_path.c_str());
+    auto bundle_dir = FileUtil::GetBundleDirectory();
+    if (bundle_dir) {
+        FileUtil::SetCurrentDir(bundle_dir.value() + "..");
+    }
 #endif
 
 #ifdef ENABLE_OPENGL
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index da9c04f2f1..f12eedb0c3 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -13,7 +13,6 @@
 #endif
 
 // The user data dir
-#define ROOT_DIR "."
 #define USERDATA_DIR "user"
 #ifdef USER_DIR
 #define EMU_DATA_DIR USER_DIR
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 1acbb27240..cda752e5f0 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -634,6 +634,10 @@ std::optional<std::string> GetCurrentDir() {
     std::string strDir = dir;
 #endif
     free(dir);
+
+    if (!strDir.ends_with(DIR_SEP)) {
+        strDir += DIR_SEP;
+    }
     return strDir;
 } // namespace FileUtil
 
@@ -646,17 +650,36 @@ bool SetCurrentDir(const std::string& directory) {
 }
 
 #if defined(__APPLE__)
-std::string GetBundleDirectory() {
-    CFURLRef BundleRef;
-    char AppBundlePath[MAXPATHLEN];
+std::optional<std::string> GetBundleDirectory() {
     // Get the main bundle for the app
-    BundleRef = CFBundleCopyBundleURL(CFBundleGetMainBundle());
-    CFStringRef BundlePath = CFURLCopyFileSystemPath(BundleRef, kCFURLPOSIXPathStyle);
-    CFStringGetFileSystemRepresentation(BundlePath, AppBundlePath, sizeof(AppBundlePath));
-    CFRelease(BundleRef);
-    CFRelease(BundlePath);
+    CFBundleRef bundle_ref = CFBundleGetMainBundle();
+    if (!bundle_ref) {
+        return {};
+    }
 
-    return AppBundlePath;
+    CFURLRef bundle_url_ref = CFBundleCopyBundleURL(bundle_ref);
+    if (!bundle_url_ref) {
+        return {};
+    }
+    SCOPE_EXIT({ CFRelease(bundle_url_ref); });
+
+    CFStringRef bundle_path_ref = CFURLCopyFileSystemPath(bundle_url_ref, kCFURLPOSIXPathStyle);
+    if (!bundle_path_ref) {
+        return {};
+    }
+    SCOPE_EXIT({ CFRelease(bundle_path_ref); });
+
+    char app_bundle_path[MAXPATHLEN];
+    if (!CFStringGetFileSystemRepresentation(bundle_path_ref, app_bundle_path,
+                                             sizeof(app_bundle_path))) {
+        return {};
+    }
+
+    std::string path_str(app_bundle_path);
+    if (!path_str.ends_with(DIR_SEP)) {
+        path_str += DIR_SEP;
+    }
+    return path_str;
 }
 #endif
 
@@ -732,22 +755,6 @@ static const std::string& GetHomeDirectory() {
 }
 #endif
 
-std::string GetSysDirectory() {
-    std::string sysDir;
-
-#if defined(__APPLE__)
-    sysDir = GetBundleDirectory();
-    sysDir += DIR_SEP;
-    sysDir += SYSDATA_DIR;
-#else
-    sysDir = SYSDATA_DIR;
-#endif
-    sysDir += DIR_SEP;
-
-    LOG_DEBUG(Common_Filesystem, "Setting to {}:", sysDir);
-    return sysDir;
-}
-
 namespace {
 std::unordered_map<UserPath, std::string> g_paths;
 std::unordered_map<UserPath, std::string> g_default_paths;
@@ -777,8 +784,10 @@ void SetUserPath(const std::string& path) {
         g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
         g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
 #else
-        if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) {
-            user_path = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
+        auto current_dir = FileUtil::GetCurrentDir();
+        if (current_dir.has_value() &&
+            FileUtil::Exists(current_dir.value() + USERDATA_DIR DIR_SEP)) {
+            user_path = current_dir.value() + USERDATA_DIR DIR_SEP;
             g_paths.emplace(UserPath::ConfigDir, user_path + CONFIG_DIR DIR_SEP);
             g_paths.emplace(UserPath::CacheDir, user_path + CACHE_DIR DIR_SEP);
         } else {
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 2a4cc70efd..6595fead90 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -193,11 +193,8 @@ void SetCurrentRomPath(const std::string& path);
 // Update the Global Path with the new value
 void UpdateUserPath(UserPath path, const std::string& filename);
 
-// Returns the path to where the sys file are
-[[nodiscard]] std::string GetSysDirectory();
-
 #ifdef __APPLE__
-[[nodiscard]] std::string GetBundleDirectory();
+[[nodiscard]] std::optional<std::string> GetBundleDirectory();
 #endif
 
 #ifdef _WIN32