1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 02:32:36 +01:00

Utilities: Add support for portable user directory. (#15064)

This commit is contained in:
Steveice10 2024-01-20 00:04:25 -08:00 committed by GitHub
parent 96d880839a
commit 9c354ee269
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 86 additions and 75 deletions

View File

@ -8,6 +8,7 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <map> #include <map>
#include <iostream>
#include "util/asm.hpp" #include "util/asm.hpp"
#include "util/coro.hpp" #include "util/coro.hpp"
@ -137,6 +138,7 @@ static fs::error to_error(DWORD e)
#if defined(__APPLE__) #if defined(__APPLE__)
#include <copyfile.h> #include <copyfile.h>
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
#include <limits.h>
#elif defined(__linux__) || defined(__sun) #elif defined(__linux__) || defined(__sun)
#include <sys/sendfile.h> #include <sys/sendfile.h>
#include <sys/syscall.h> #include <sys/syscall.h>
@ -1898,6 +1900,71 @@ bool fs::file::strict_read_check(u64 _size, u64 type_size) const
return true; return true;
} }
std::string fs::get_executable_path()
{
// Use magic static
static const std::string s_exe_path = []
{
#if defined(_WIN32)
std::vector<wchar_t> 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() const std::string& fs::get_config_dir()
{ {
// Use magic static // Use magic static
@ -1905,6 +1972,13 @@ const std::string& fs::get_config_dir()
{ {
std::string 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 #ifdef _WIN32
std::vector<wchar_t> buf; std::vector<wchar_t> buf;

View File

@ -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 // Get configuration directory
const std::string& get_config_dir(); const std::string& get_config_dir();

View File

@ -14,18 +14,6 @@
#include <charconv> #include <charconv>
#include <thread> #include <thread>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#include <limits.h>
#include <filesystem>
#endif
LOG_CHANNEL(sys_log, "SYS"); LOG_CHANNEL(sys_log, "SYS");
namespace rpcs3::utils namespace rpcs3::utils
@ -112,56 +100,6 @@ namespace rpcs3::utils
return worker(); 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() std::string get_emu_dir()
{ {
const std::string& emu_dir_ = g_cfg_vfs.emulator_dir; const std::string& emu_dir_ = g_cfg_vfs.emulator_dir;

View File

@ -13,14 +13,6 @@ namespace rpcs3::utils
bool install_pkg(const std::string& path); 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_emu_dir();
std::string get_hdd0_dir(); std::string get_hdd0_dir();
std::string get_hdd1_dir(); std::string get_hdd1_dir();

View File

@ -4,6 +4,7 @@
#include "Emu/system_utils.hpp" #include "Emu/system_utils.hpp"
#include "Emu/VFS.h" #include "Emu/VFS.h"
#include "Emu/vfs_config.h" #include "Emu/vfs_config.h"
#include "Utilities/File.h"
#include "Utilities/StrUtil.h" #include "Utilities/StrUtil.h"
#ifdef _WIN32 #ifdef _WIN32
@ -154,7 +155,7 @@ namespace gui::utils
if (FAILED(res)) if (FAILED(res))
return cleanup(false, "CoCreateInstance failed"); 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::string rpcs3_path{ working_dir + "rpcs3.exe" };
const std::wstring w_target_file = utf8_to_wchar(rpcs3_path); const std::wstring w_target_file = utf8_to_wchar(rpcs3_path);
@ -219,7 +220,7 @@ namespace gui::utils
#elif defined(__APPLE__) #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()) if (app_bundle_path.empty())
{ {
sys_log.error("Failed to create shortcut. App bundle path empty."); sys_log.error("Failed to create shortcut. App bundle path empty.");
@ -307,7 +308,7 @@ namespace gui::utils
#else #else
const std::string exe_path = rpcs3::utils::get_executable_path(); const std::string exe_path = fs::get_executable_path();
if (exe_path.empty()) if (exe_path.empty())
{ {
sys_log.error("Failed to create shortcut. Executable path empty."); sys_log.error("Failed to create shortcut. Executable path empty.");

View File

@ -393,7 +393,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
#ifdef _WIN32 #ifdef _WIN32
// Get executable path // 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::string orig_path = exe_dir + "rpcs3.exe";
const std::wstring wchar_orig_path = utf8_to_wchar(orig_path); const std::wstring wchar_orig_path = utf8_to_wchar(orig_path);
const std::string tmpfile_path = fs::get_temp_dir() + "\\rpcs3_update.7z"; 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 #else
std::string replace_path = rpcs3::utils::get_executable_path(); std::string replace_path = fs::get_executable_path();
if (replace_path.empty()) if (replace_path.empty())
{ {
return false; return false;