[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
This commit is contained in:
Herman S.
2026-01-10 23:16:32 +09:00
committed by Radosław Gliński
parent dce4d38c0a
commit 4b6ac45650
4 changed files with 27 additions and 16 deletions

View File

@@ -14,6 +14,7 @@
#include "xenia/base/mapped_memory.h" #include "xenia/base/mapped_memory.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/base/string.h" #include "xenia/base/string.h"
#include "xenia/base/utf8.h"
#include "xenia/vfs/device.h" #include "xenia/vfs/device.h"
#include "xenia/vfs/devices/host_path_device.h" #include "xenia/vfs/devices/host_path_device.h"
#include "xenia/vfs/devices/host_path_file.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<std::string_view>& path_parts) {
const std::string relative_path = xe::utf8::join_paths(path_parts);
const std::string new_host_path_ = xe::utf8::join_paths( const std::string new_host_path_ = xe::utf8::join_paths(
xe::path_to_utf8(((HostPathDevice*)device_)->host_path()), xe::path_to_utf8(static_cast<HostPathDevice*>(device_)->host_path()),
xe::path_to_utf8(file_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_; host_path_ = new_host_path_;
} }

View File

@@ -51,7 +51,8 @@ class HostPathEntry : public Entry {
std::unique_ptr<Entry> CreateEntryInternal(const std::string_view name, std::unique_ptr<Entry> CreateEntryInternal(const std::string_view name,
uint32_t attributes) override; uint32_t attributes) override;
bool DeleteEntryInternal(Entry* entry) override; bool DeleteEntryInternal(Entry* entry) override;
void RenameEntryInternal(const std::filesystem::path file_path) override; void RenameEntryInternal(
const std::vector<std::string_view>& path_parts) override;
std::filesystem::path host_path_; std::filesystem::path host_path_;
}; };

View File

@@ -135,19 +135,19 @@ void Entry::Touch() {
} }
void Entry::Rename(const std::filesystem::path file_path) { void Entry::Rename(const std::filesystem::path file_path) {
std::vector<std::string_view> splitted_path = // Store the string to ensure string_views from split_path remain valid
xe::utf8::split_path(xe::path_to_utf8(file_path)); const std::string path_str = xe::path_to_utf8(file_path);
std::vector<std::string_view> 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 = RenameEntryInternal(path_parts);
xe::utf8::join_guest_paths(splitted_path);
RenameEntryInternal(guest_path_without_root); const std::string guest_path = xe::utf8::join_guest_paths(path_parts);
absolute_path_ =
absolute_path_ = xe::utf8::join_guest_paths(device_->mount_path(), xe::utf8::join_guest_paths(device_->mount_path(), guest_path);
guest_path_without_root); path_ = guest_path;
path_ = guest_path_without_root;
name_ = xe::path_to_utf8(file_path.filename()); name_ = xe::path_to_utf8(file_path.filename());
} }

View File

@@ -141,7 +141,8 @@ class Entry {
return nullptr; return nullptr;
} }
virtual bool DeleteEntryInternal(Entry* entry) = 0; virtual bool DeleteEntryInternal(Entry* entry) = 0;
virtual void RenameEntryInternal(const std::filesystem::path file_path) {} virtual void RenameEntryInternal(
const std::vector<std::string_view>& path_parts) {}
xe::global_critical_region global_critical_region_; xe::global_critical_region global_critical_region_;
Device* device_; Device* device_;