From 40142420c17f9cf796e00922109a495a761dbea7 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Mon, 8 Apr 2019 00:53:56 +0300 Subject: [PATCH] Implement vfs::host::unlink Emulate POSIX behaviour in sys_fs_unlink. This should allow to delete opened files transparently on Windows. --- rpcs3/Emu/Cell/lv2/sys_fs.cpp | 2 +- rpcs3/Emu/VFS.cpp | 39 +++++++++++++++++++++++++++++++++++ rpcs3/Emu/VFS.h | 3 +++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 02054e0504..6bb66463ca 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -852,7 +852,7 @@ error_code sys_fs_unlink(vm::cptr path) return {CELL_ENOTMOUNTED, path}; } - if (!fs::remove_file(local_path)) + if (!vfs::host::unlink(local_path)) { switch (auto error = fs::g_tls_error) { diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index 4535a3158d..d4114ca36f 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -385,6 +385,17 @@ std::string vfs::unescape(std::string_view path) result += '*'; break; } + case char{u8"$"[2]}: + { + if (i == 0) + { + // Special case: filename starts with full-width $ likely created by vfs::host::unlink + result.resize(1, '.'); + return result; + } + + [[fallthrough]]; + } default: { // Unrecognized character (ignored) @@ -462,3 +473,31 @@ bool vfs::host::rename(const std::string& from, const std::string& to, bool over return true; } + +bool vfs::host::unlink(const std::string& path) +{ +#ifdef _WIN32 + if (path.size() < 2 || reinterpret_cast(path.front()) != "//"_u16) + { + // 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", fs::get_parent_dir(path), fmt::base57(std::hash()(path)), fmt::base57(__rdtsc())); + + if (!fs::rename(path, dummy, true)) + { + return false; + } + + if (fs::file f{dummy, fs::read + fs::write}) + { + // Set to delete on close on last handle + f.set_delete(); + return true; + } + + // TODO: what could cause this and how to handle it + return true; + } +#endif + + return fs::remove_file(path); +} diff --git a/rpcs3/Emu/VFS.h b/rpcs3/Emu/VFS.h index bb546c097b..e3e12ede1b 100644 --- a/rpcs3/Emu/VFS.h +++ b/rpcs3/Emu/VFS.h @@ -23,5 +23,8 @@ namespace vfs { // Call fs::rename with retry on access error bool rename(const std::string& from, const std::string& to, bool overwrite); + + // Delete file without deleting its contents, emulated with MoveFileEx on Windows + bool unlink(const std::string&); } }