mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-08 07:51:28 +12:00
Win32 FS: Rewrite (fix) vfs::host::rename
This commit is contained in:
parent
22269ca0d7
commit
b8fa6fb4c4
16 changed files with 329 additions and 108 deletions
|
@ -3,6 +3,8 @@
|
|||
#include "System.h"
|
||||
#include "VFS.h"
|
||||
|
||||
#include "Cell/lv2/sys_fs.h"
|
||||
|
||||
#include "Utilities/mutex.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
|
@ -10,6 +12,8 @@
|
|||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
|
||||
struct vfs_directory
|
||||
{
|
||||
// Real path (empty if root or not exists)
|
||||
|
@ -706,18 +710,77 @@ std::string vfs::host::hash_path(const std::string& path, const std::string& dev
|
|||
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)
|
||||
bool vfs::host::rename(const std::string& from, const std::string& to, const lv2_fs_mount_point* mp, bool overwrite)
|
||||
{
|
||||
while (!fs::rename(from, to, overwrite))
|
||||
#ifdef _WIN32
|
||||
constexpr auto& delim = "/\\";
|
||||
#else
|
||||
constexpr auto& delim = "/";
|
||||
#endif
|
||||
|
||||
// Lock mount point, close file descriptors, retry
|
||||
const auto from0 = std::string_view(from).substr(0, from.find_last_not_of(delim) + 1);
|
||||
const auto escaped_from = fs::escape_path(from);
|
||||
|
||||
// Lock app_home as well because it could be in the same drive as current mount point (TODO)
|
||||
std::scoped_lock lock(mp->mutex, g_mp_sys_app_home.mutex);
|
||||
|
||||
auto check_path = [&](std::string_view path)
|
||||
{
|
||||
// Try to ignore access error in order to prevent spurious failure
|
||||
return path.starts_with(from) && (path.size() == from.size() || path[from.size()] == delim[0] || path[from.size()] == delim[1]);
|
||||
};
|
||||
|
||||
idm::select<lv2_fs_object, lv2_file>([&](u32 id, lv2_file& file)
|
||||
{
|
||||
if (check_path(fs::escape_path(file.real_path)))
|
||||
{
|
||||
verify(HERE), file.mp == mp || file.mp == &g_mp_sys_app_home;
|
||||
file.restore_data.seek_pos = file.file.pos();
|
||||
file.file.close(); // Actually close it!
|
||||
}
|
||||
});
|
||||
|
||||
bool res = false;
|
||||
|
||||
for (;; std::this_thread::yield())
|
||||
{
|
||||
if (fs::rename(from, to, overwrite))
|
||||
{
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Emu.IsStopped() || fs::g_tls_error != fs::error::acces)
|
||||
{
|
||||
return false;
|
||||
res = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
const auto fs_error = fs::g_tls_error;
|
||||
|
||||
idm::select<lv2_fs_object, lv2_file>([&](u32 id, lv2_file& file)
|
||||
{
|
||||
const auto escaped_real = fs::escape_path(file.real_path);
|
||||
|
||||
if (check_path(escaped_real))
|
||||
{
|
||||
// Update internal path
|
||||
if (res)
|
||||
{
|
||||
file.real_path = to + (escaped_real != escaped_from ? '/' + file.real_path.substr(from0.size()) : ""s);
|
||||
}
|
||||
|
||||
// Reopen with ignored TRUNC, APPEND, CREATE and EXCL flags
|
||||
auto res0 = lv2_file::open_raw(file.real_path, file.flags & CELL_FS_O_ACCMODE, file.mode, file.type, file.mp);
|
||||
file.file = std::move(res0.file);
|
||||
verify(HERE), file.file.operator bool();
|
||||
file.file.seek(file.restore_data.seek_pos);
|
||||
}
|
||||
});
|
||||
|
||||
fs::g_tls_error = fs_error;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool vfs::host::unlink(const std::string& path, const std::string& dev_root)
|
||||
|
@ -754,7 +817,7 @@ bool vfs::host::unlink(const std::string& path, const std::string& dev_root)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool vfs::host::remove_all(const std::string& path, const std::string& dev_root, bool remove_root)
|
||||
bool vfs::host::remove_all(const std::string& path, const std::string& dev_root, const lv2_fs_mount_point* mp, bool remove_root)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (remove_root)
|
||||
|
@ -762,12 +825,12 @@ bool vfs::host::remove_all(const std::string& path, const std::string& dev_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 = hash_path(path, dev_root);
|
||||
|
||||
if (!vfs::host::rename(path, dummy, false))
|
||||
if (!vfs::host::rename(path, dummy, mp, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!vfs::host::remove_all(dummy, dev_root, false))
|
||||
if (!vfs::host::remove_all(dummy, dev_root, mp, false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -802,7 +865,7 @@ bool vfs::host::remove_all(const std::string& path, const std::string& dev_root,
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!vfs::host::remove_all(path + '/' + entry.name, dev_root))
|
||||
if (!vfs::host::remove_all(path + '/' + entry.name, dev_root, mp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue