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 <cstring>
#include <map>
#include <iostream>
#include "util/asm.hpp"
#include "util/coro.hpp"
@ -137,6 +138,7 @@ static fs::error to_error(DWORD e)
#if defined(__APPLE__)
#include <copyfile.h>
#include <mach-o/dyld.h>
#include <limits.h>
#elif defined(__linux__) || defined(__sun)
#include <sys/sendfile.h>
#include <sys/syscall.h>
@ -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<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()
{
// 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<wchar_t> buf;