[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/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<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(
xe::path_to_utf8(((HostPathDevice*)device_)->host_path()),
xe::path_to_utf8(file_path));
xe::path_to_utf8(static_cast<HostPathDevice*>(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_;
}

View File

@@ -51,7 +51,8 @@ class HostPathEntry : public Entry {
std::unique_ptr<Entry> 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<std::string_view>& path_parts) override;
std::filesystem::path host_path_;
};

View File

@@ -135,19 +135,19 @@ void Entry::Touch() {
}
void Entry::Rename(const std::filesystem::path file_path) {
std::vector<std::string_view> 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<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 =
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());
}

View File

@@ -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<std::string_view>& path_parts) {}
xe::global_critical_region global_critical_region_;
Device* device_;