Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: file path fixes #15043

Merged
merged 3 commits into from
Jan 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
74 changes: 42 additions & 32 deletions Utilities/File.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "File.h"
#include "mutex.h"
#include "StrFmt.h"
#include "StrUtil.h"
#include "Crypto/sha1.h"

#include <unordered_map>
Expand Down Expand Up @@ -49,23 +50,6 @@ static std::unique_ptr<wchar_t[]> to_wchar(const std::string& source)
return buffer;
}

static void to_utf8(std::string& out, const wchar_t* source)
{
// String size
const usz length = std::wcslen(source);

// Safe buffer size for max possible output length (including null terminator)
const int buf_size = narrow<int>(length * 3 + 1);

// Resize buffer
out.resize(buf_size - 1);

const int result = WideCharToMultiByte(CP_UTF8, 0, source, static_cast<int>(length) + 1, &out.front(), buf_size, nullptr, nullptr);

// Fix the size
out.resize(ensure(result) - 1);
}

static time_t to_time(const ULARGE_INTEGER& ft)
{
return ft.QuadPart / 10000000ULL - 11644473600ULL;
Expand Down Expand Up @@ -531,7 +515,7 @@ bool fs::get_stat(const std::string& path, stat_t& info)
// Handle drives specially
if (epath.find_first_of(delim) == umax && epath.ends_with(':'))
{
WIN32_FILE_ATTRIBUTE_DATA attrs;
WIN32_FILE_ATTRIBUTE_DATA attrs{};

// Must end with a delimiter
if (!GetFileAttributesExW(to_wchar(std::string(epath) + '/').get(), GetFileExInfoStandard, &attrs))
Expand All @@ -553,15 +537,15 @@ bool fs::get_stat(const std::string& path, stat_t& info)
return true;
}

WIN32_FIND_DATA attrs;

// Allowed by FindFirstFileExW but we should not allow it
if (epath.ends_with("*"))
{
g_tls_error = fs::error::noent;
return false;
}

WIN32_FIND_DATA attrs{};

const auto wchar_ptr = to_wchar(std::string(epath));
const std::wstring_view wpath_view = wchar_ptr.get();

Expand Down Expand Up @@ -797,17 +781,15 @@ bool fs::remove_dir(const std::string& path)
g_tls_error = to_error(GetLastError());
return false;
}

return true;
#else
if (::rmdir(path.c_str()) != 0)
{
g_tls_error = to_error(errno);
return false;
}
#endif

return true;
#endif
}

bool fs::rename(const std::string& from, const std::string& to, bool overwrite)
Expand Down Expand Up @@ -1789,7 +1771,7 @@ bool fs::dir::open(const std::string& path)
{
dir_entry info;

to_utf8(info.name, found.cFileName);
info.name = wchar_to_utf8(found.cFileName);
info.is_directory = (found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
info.is_writable = (found.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
info.size = (static_cast<u64>(found.nFileSizeHigh) << 32) | static_cast<u64>(found.nFileSizeLow);
Expand Down Expand Up @@ -1924,16 +1906,44 @@ const std::string& fs::get_config_dir()
std::string dir;

#ifdef _WIN32
wchar_t buf[32768];
constexpr DWORD size = static_cast<DWORD>(std::size(buf));
if (GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", buf, size) - 1 >= size - 1 &&
GetModuleFileName(nullptr, buf, size) - 1 >= size - 1)
std::vector<wchar_t> buf;

// Check if RPCS3_CONFIG_DIR is set and get the required buffer size
DWORD size = GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", nullptr, 0);
if (size > 0)
{
MessageBoxA(nullptr, fmt::format("GetModuleFileName() failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
return dir; // empty
// Resize buffer and fetch RPCS3_CONFIG_DIR
buf.resize(size);

if (GetEnvironmentVariable(L"RPCS3_CONFIG_DIR", buf.data(), size) != (size - 1))
{
// Clear buffer on failure and notify user
MessageBoxA(nullptr, fmt::format("GetEnvironmentVariable(RPCS3_CONFIG_DIR) failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
buf.clear();
}
}

// Fallback to executable path if needed
for (DWORD buf_size = MAX_PATH; size == 0; buf_size += MAX_PATH)
{
buf.resize(buf_size);
size = GetModuleFileName(nullptr, buf.data(), buf_size);

if (size == 0)
{
MessageBoxA(nullptr, fmt::format("GetModuleFileName() failed: error: %s", fmt::win_error{GetLastError(), nullptr}).c_str(), "fs::get_config_dir()", MB_ICONERROR);
return dir; // empty
}

if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
// Try again with increased buffer size
size = 0;
continue;
}
}

to_utf8(dir, buf); // Convert to UTF-8
dir = wchar_to_utf8(buf.data());

std::replace(dir.begin(), dir.end(), '\\', '/');

Expand Down Expand Up @@ -2018,7 +2028,7 @@ const std::string& fs::get_temp_dir()
return dir; // empty
}

to_utf8(dir, buf);
dir = wchar_to_utf8(buf);
#else
// TODO
dir = get_cache_dir();
Expand Down
7 changes: 1 addition & 6 deletions rpcs3/rpcs3qt/update_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,12 +396,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
const std::string exe_dir = rpcs3::utils::get_exe_dir();
const std::string orig_path = exe_dir + "rpcs3.exe";
const std::wstring wchar_orig_path = utf8_to_wchar(orig_path);

wchar_t wide_temp_path[MAX_PATH + 1]{};
GetTempPathW(sizeof(wide_temp_path), wide_temp_path);

std::string tmpfile_path = wchar_to_utf8(wide_temp_path);
tmpfile_path += "\\rpcs3_update.7z";
const std::string tmpfile_path = fs::get_temp_dir() + "\\rpcs3_update.7z";

fs::file tmpfile(tmpfile_path, fs::read + fs::write + fs::create + fs::trunc);
if (!tmpfile)
Expand Down