From 4b6ac456509f43f872d02d715cec056c4263a598 Mon Sep 17 00:00:00 2001 From: "Herman S." <429230+has207@users.noreply.github.com> Date: Sat, 10 Jan 2026 23:16:32 +0900 Subject: [PATCH] [VFS/Posix] Fix Rename to properly handle guest paths And ensure string_views aren't pointing at freed memory by saving a reference to the result of path_to_utf8 --- src/xenia/vfs/devices/host_path_entry.cc | 17 +++++++++++++---- src/xenia/vfs/devices/host_path_entry.h | 3 ++- src/xenia/vfs/entry.cc | 20 ++++++++++---------- src/xenia/vfs/entry.h | 3 ++- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/xenia/vfs/devices/host_path_entry.cc b/src/xenia/vfs/devices/host_path_entry.cc index a7da81c50..41f74df69 100644 --- a/src/xenia/vfs/devices/host_path_entry.cc +++ b/src/xenia/vfs/devices/host_path_entry.cc @@ -14,6 +14,7 @@ #include "xenia/base/mapped_memory.h" #include "xenia/base/math.h" #include "xenia/base/string.h" +#include "xenia/base/utf8.h" #include "xenia/vfs/device.h" #include "xenia/vfs/devices/host_path_device.h" #include "xenia/vfs/devices/host_path_file.h" @@ -121,12 +122,20 @@ bool HostPathEntry::DeleteEntryInternal(Entry* entry) { } } -void HostPathEntry::RenameEntryInternal(const std::filesystem::path file_path) { +void HostPathEntry::RenameEntryInternal( + const std::vector& path_parts) { + const std::string relative_path = xe::utf8::join_paths(path_parts); const std::string new_host_path_ = xe::utf8::join_paths( - xe::path_to_utf8(((HostPathDevice*)device_)->host_path()), - xe::path_to_utf8(file_path)); + xe::path_to_utf8(static_cast(device_)->host_path()), + relative_path); - std::filesystem::rename(host_path_, new_host_path_); + std::error_code ec; + std::filesystem::rename(host_path_, new_host_path_, ec); + if (ec) { + XELOGE("RenameEntryInternal: Failed to rename '{}' to '{}': {}", + xe::path_to_utf8(host_path_), new_host_path_, ec.message()); + return; + } host_path_ = new_host_path_; } diff --git a/src/xenia/vfs/devices/host_path_entry.h b/src/xenia/vfs/devices/host_path_entry.h index 85ce94d8b..eb0ae1012 100644 --- a/src/xenia/vfs/devices/host_path_entry.h +++ b/src/xenia/vfs/devices/host_path_entry.h @@ -51,7 +51,8 @@ class HostPathEntry : public Entry { std::unique_ptr CreateEntryInternal(const std::string_view name, uint32_t attributes) override; bool DeleteEntryInternal(Entry* entry) override; - void RenameEntryInternal(const std::filesystem::path file_path) override; + void RenameEntryInternal( + const std::vector& path_parts) override; std::filesystem::path host_path_; }; diff --git a/src/xenia/vfs/entry.cc b/src/xenia/vfs/entry.cc index da2a7b939..59de6af08 100644 --- a/src/xenia/vfs/entry.cc +++ b/src/xenia/vfs/entry.cc @@ -135,19 +135,19 @@ void Entry::Touch() { } void Entry::Rename(const std::filesystem::path file_path) { - std::vector splitted_path = - xe::utf8::split_path(xe::path_to_utf8(file_path)); + // Store the string to ensure string_views from split_path remain valid + const std::string path_str = xe::path_to_utf8(file_path); + std::vector path_parts = xe::utf8::split_path(path_str); - splitted_path.erase(splitted_path.begin()); + // Remove the root (e.g., "cache:") + path_parts.erase(path_parts.begin()); - const std::string guest_path_without_root = - xe::utf8::join_guest_paths(splitted_path); + RenameEntryInternal(path_parts); - RenameEntryInternal(guest_path_without_root); - - absolute_path_ = xe::utf8::join_guest_paths(device_->mount_path(), - guest_path_without_root); - path_ = guest_path_without_root; + const std::string guest_path = xe::utf8::join_guest_paths(path_parts); + absolute_path_ = + xe::utf8::join_guest_paths(device_->mount_path(), guest_path); + path_ = guest_path; name_ = xe::path_to_utf8(file_path.filename()); } diff --git a/src/xenia/vfs/entry.h b/src/xenia/vfs/entry.h index 4346663ec..c0f454197 100644 --- a/src/xenia/vfs/entry.h +++ b/src/xenia/vfs/entry.h @@ -141,7 +141,8 @@ class Entry { return nullptr; } virtual bool DeleteEntryInternal(Entry* entry) = 0; - virtual void RenameEntryInternal(const std::filesystem::path file_path) {} + virtual void RenameEntryInternal( + const std::vector& path_parts) {} xe::global_critical_region global_critical_region_; Device* device_;