From 9c354ee269779c5b473b39d313cbe1305040d138 Mon Sep 17 00:00:00 2001 From: Steveice10 <1269164+Steveice10@users.noreply.github.com> Date: Sat, 20 Jan 2024 00:04:25 -0800 Subject: [PATCH] Utilities: Add support for portable user directory. (#15064) --- Utilities/File.cpp | 74 ++++++++++++++++++++++++++++++++ Utilities/File.h | 6 +++ rpcs3/Emu/system_utils.cpp | 62 -------------------------- rpcs3/Emu/system_utils.hpp | 8 ---- rpcs3/rpcs3qt/shortcut_utils.cpp | 7 +-- rpcs3/rpcs3qt/update_manager.cpp | 4 +- 6 files changed, 86 insertions(+), 75 deletions(-) diff --git a/Utilities/File.cpp b/Utilities/File.cpp index f0e514f636..6b0a5f7c55 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "util/asm.hpp" #include "util/coro.hpp" @@ -137,6 +138,7 @@ static fs::error to_error(DWORD e) #if defined(__APPLE__) #include #include +#include #elif defined(__linux__) || defined(__sun) #include #include @@ -1898,6 +1900,71 @@ bool fs::file::strict_read_check(u64 _size, u64 type_size) const return true; } +std::string fs::get_executable_path() +{ + // Use magic static + static const std::string s_exe_path = [] + { +#if defined(_WIN32) + std::vector buffer(32767); + GetModuleFileNameW(nullptr, buffer.data(), buffer.size()); + return wchar_to_utf8(buffer.data()); +#elif defined(__APPLE__) + char bin_path[PATH_MAX]; + uint32_t bin_path_size = sizeof(bin_path); + if (_NSGetExecutablePath(bin_path, &bin_path_size) != 0) + { + std::cerr << "Failed to find app binary path" << std::endl; + return std::string{}; + } + + // App bundle directory is three levels up from the binary. + return get_parent_dir(bin_path, 3); +#else + if (const char* appimage_path = ::getenv("APPIMAGE")) + { + std::cout << "Found AppImage path: " << appimage_path << std::endl; + return std::string(appimage_path); + } + + std::cout << "No AppImage path found, checking for executable" << std::endl; + + char exe_path[PATH_MAX]; + const ssize_t len = ::readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + + if (len == -1) + { + std::cerr << "Failed to find executable path" << std::endl; + return std::string{}; + } + + exe_path[len] = '\0'; + std::cout << "Found exec path: " << exe_path << std::endl; + + return std::string(exe_path); +#endif + }(); + + return s_exe_path; +} + +std::string fs::get_executable_dir() +{ + // Use magic static + static const std::string s_exe_dir = [] + { + std::string exe_path = get_executable_path(); + if (exe_path.empty()) + { + return exe_path; + } + + return get_parent_dir(exe_path); + }(); + + return s_exe_dir; +} + const std::string& fs::get_config_dir() { // Use magic static @@ -1905,6 +1972,13 @@ const std::string& fs::get_config_dir() { std::string dir; + // Check if a portable directory exists. + std::string portable_dir = get_executable_dir() + "/portable/"; + if (is_dir(portable_dir)) + { + return portable_dir; + } + #ifdef _WIN32 std::vector buf; diff --git a/Utilities/File.h b/Utilities/File.h index 4718236f12..07607bea2d 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -660,6 +660,12 @@ namespace fs } }; + // Get executable path + std::string get_executable_path(); + + // Get executable containing directory + std::string get_executable_dir(); + // Get configuration directory const std::string& get_config_dir(); diff --git a/rpcs3/Emu/system_utils.cpp b/rpcs3/Emu/system_utils.cpp index 75f4c199da..448addc4a5 100644 --- a/rpcs3/Emu/system_utils.cpp +++ b/rpcs3/Emu/system_utils.cpp @@ -14,18 +14,6 @@ #include #include -#ifdef _WIN32 -#include -#else -#include -#endif - -#ifdef __APPLE__ -#include -#include -#include -#endif - LOG_CHANNEL(sys_log, "SYS"); namespace rpcs3::utils @@ -112,56 +100,6 @@ namespace rpcs3::utils return worker(); } -#ifdef _WIN32 - std::string get_exe_dir() - { - wchar_t buffer[32767]; - GetModuleFileNameW(nullptr, buffer, sizeof(buffer) / 2); - - const std::string path_to_exe = wchar_to_utf8(buffer); - const usz last = path_to_exe.find_last_of('\\'); - return last == std::string::npos ? std::string("") : path_to_exe.substr(0, last + 1); - } -#elif defined(__APPLE__) - std::string get_app_bundle_path() - { - char bin_path[PATH_MAX]; - uint32_t bin_path_size = sizeof(bin_path); - if (_NSGetExecutablePath(bin_path, &bin_path_size) != 0) - { - sys_log.error("Failed to find app binary path"); - return {}; - } - - return std::filesystem::path(bin_path).parent_path().parent_path().parent_path(); - } -#else - std::string get_executable_path() - { - if (const char* appimage_path = ::getenv("APPIMAGE")) - { - sys_log.notice("Found AppImage path: %s", appimage_path); - return std::string(appimage_path); - } - - sys_log.warning("Failed to find AppImage path"); - - char exe_path[PATH_MAX]; - const ssize_t len = ::readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); - - if (len == -1) - { - sys_log.error("Failed to find executable path"); - return {}; - } - - exe_path[len] = '\0'; - sys_log.trace("Found exec path: %s", exe_path); - - return std::string(exe_path); - } -#endif - std::string get_emu_dir() { const std::string& emu_dir_ = g_cfg_vfs.emulator_dir; diff --git a/rpcs3/Emu/system_utils.hpp b/rpcs3/Emu/system_utils.hpp index 42297c7b4e..57ea098cc3 100644 --- a/rpcs3/Emu/system_utils.hpp +++ b/rpcs3/Emu/system_utils.hpp @@ -13,14 +13,6 @@ namespace rpcs3::utils bool install_pkg(const std::string& path); -#ifdef _WIN32 - std::string get_exe_dir(); -#elif defined(__APPLE__) - std::string get_app_bundle_path(); -#else - std::string get_executable_path(); -#endif - std::string get_emu_dir(); std::string get_hdd0_dir(); std::string get_hdd1_dir(); diff --git a/rpcs3/rpcs3qt/shortcut_utils.cpp b/rpcs3/rpcs3qt/shortcut_utils.cpp index 2d5d4bb733..712a98200e 100644 --- a/rpcs3/rpcs3qt/shortcut_utils.cpp +++ b/rpcs3/rpcs3qt/shortcut_utils.cpp @@ -4,6 +4,7 @@ #include "Emu/system_utils.hpp" #include "Emu/VFS.h" #include "Emu/vfs_config.h" +#include "Utilities/File.h" #include "Utilities/StrUtil.h" #ifdef _WIN32 @@ -154,7 +155,7 @@ namespace gui::utils if (FAILED(res)) return cleanup(false, "CoCreateInstance failed"); - const std::string working_dir{ rpcs3::utils::get_exe_dir() }; + const std::string working_dir{ fs::get_executable_dir() }; const std::string rpcs3_path{ working_dir + "rpcs3.exe" }; const std::wstring w_target_file = utf8_to_wchar(rpcs3_path); @@ -219,7 +220,7 @@ namespace gui::utils #elif defined(__APPLE__) - const std::string app_bundle_path = rpcs3::utils::get_app_bundle_path(); + const std::string app_bundle_path = fs::get_executable_path(); if (app_bundle_path.empty()) { sys_log.error("Failed to create shortcut. App bundle path empty."); @@ -307,7 +308,7 @@ namespace gui::utils #else - const std::string exe_path = rpcs3::utils::get_executable_path(); + const std::string exe_path = fs::get_executable_path(); if (exe_path.empty()) { sys_log.error("Failed to create shortcut. Executable path empty."); diff --git a/rpcs3/rpcs3qt/update_manager.cpp b/rpcs3/rpcs3qt/update_manager.cpp index c01dfe613d..75f23f7dd0 100644 --- a/rpcs3/rpcs3qt/update_manager.cpp +++ b/rpcs3/rpcs3qt/update_manager.cpp @@ -393,7 +393,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept) #ifdef _WIN32 // Get executable path - const std::string exe_dir = rpcs3::utils::get_exe_dir(); + const std::string exe_dir = fs::get_executable_dir(); const std::string orig_path = exe_dir + "rpcs3.exe"; const std::wstring wchar_orig_path = utf8_to_wchar(orig_path); const std::string tmpfile_path = fs::get_temp_dir() + "\\rpcs3_update.7z"; @@ -583,7 +583,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept) #else - std::string replace_path = rpcs3::utils::get_executable_path(); + std::string replace_path = fs::get_executable_path(); if (replace_path.empty()) { return false;