1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2025-01-31 20:41:45 +01:00

sceNpTrophyRegisterContext: Atomically create trophy data

This commit is contained in:
Eladash 2020-09-20 09:27:08 +03:00 committed by Ivan
parent a50ea09053
commit 3a96d99187
4 changed files with 46 additions and 6 deletions

View File

@ -628,7 +628,8 @@ namespace fs
template <typename... Args>
bool write_file(const std::string& path, bs_t<fs::open_mode> mode, const Args&... args)
{
if (fs::file f{path, mode})
// Always use write flag, remove read flag
if (fs::file f{path, mode + fs::write - fs::read})
{
// Write args sequentially
(f.write(args), ...);

View File

@ -701,6 +701,11 @@ std::string vfs::unescape(std::string_view name)
return result;
}
std::string vfs::host::hash_path(const std::string& path, const std::string& dev_root)
{
return fmt::format(u8"%s/%s%s", dev_root, fmt::base57(std::hash<std::string>()(path)), fmt::base57(__rdtsc()));
}
bool vfs::host::rename(const std::string& from, const std::string& to, bool overwrite)
{
while (!fs::rename(from, to, overwrite))
@ -725,7 +730,7 @@ bool vfs::host::unlink(const std::string& path, const std::string& dev_root)
else
{
// Rename to special dummy name which will be ignored by VFS (but opened file handles can still read or write it)
const std::string dummy = fmt::format(u8"%s/%s%s", dev_root, fmt::base57(std::hash<std::string>()(path)), fmt::base57(__rdtsc()));
const std::string dummy = hash_path(path, dev_root);
if (!fs::rename(path, dummy, true))
{
@ -755,7 +760,7 @@ bool vfs::host::remove_all(const std::string& path, const std::string& dev_root,
if (remove_root)
{
// Rename to special dummy folder which will be ignored by VFS (but opened file handles can still read or write it)
const std::string dummy = fmt::format(u8"%s/%s%s", dev_root, fmt::base57(std::hash<std::string>()(path)), fmt::base57(__rdtsc()));
const std::string dummy = hash_path(path, dev_root);
if (!vfs::host::rename(path, dummy, false))
{

View File

@ -21,6 +21,8 @@ namespace vfs
// Functions in this namespace operate on host filepaths, similar to fs::
namespace host
{
std::string hash_path(const std::string& path, const std::string& dev_root);
// Call fs::rename with retry on access error
bool rename(const std::string& from, const std::string& to, bool overwrite);

View File

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Emu/VFS.h"
#include "Emu/System.h"
#include "TRP.h"
#include "Crypto/sha1.h"
#include "Utilities/StrUtil.h"
@ -15,27 +16,58 @@ bool TRPLoader::Install(const std::string& dest, bool show)
{
if (!trp_f)
{
fs::g_tls_error = fs::error::noent;
return false;
}
fs::g_tls_error = {};
const std::string& local_path = vfs::get(dest);
if (!fs::is_dir(local_path) && !fs::create_dir(local_path))
const auto temp = vfs::host::hash_path(local_path, Emu.GetHddDir()) + '/';
if (!fs::create_dir(temp))
{
return false;
}
std::vector<char> buffer(65536);
bool success = true;
for (const TRPEntry& entry : m_entries)
{
trp_f.seek(entry.offset);
buffer.resize(entry.size);
if (!trp_f.read(buffer)) continue; // ???
fs::file(local_path + '/' + entry.name, fs::rewrite).write(buffer);
// Create the file in the temporary directory
success = fs::write_file(temp + vfs::escape(entry.name), fs::create + fs::excl, buffer);
if (!success)
{
break;
}
}
return true;
if (success)
{
success = vfs::host::remove_all(local_path, Emu.GetHddDir(), true);
if (success)
{
// Atomically create trophy data (overwrite existing data)
success = fs::rename(temp, local_path, false);
}
}
if (!success)
{
// Remove temporary directory manually on failure (removed automatically on success)
auto old_error = fs::g_tls_error;
fs::remove_all(temp);
fs::g_tls_error = old_error;
}
return success;
}
bool TRPLoader::LoadHeader(bool show)