From cf4ae38699af83e8b62d2ea257c30e657d71e86b Mon Sep 17 00:00:00 2001 From: brian218 Date: Sun, 25 Jun 2023 10:09:08 +0800 Subject: [PATCH] sys_fs: Implemented get_normalized_path() --- Utilities/File.cpp | 1 - rpcs3/Emu/Cell/lv2/sys_fs.cpp | 52 ++++++++++++++++++++++------------- rpcs3/Emu/Cell/lv2/sys_fs.h | 6 +++- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/Utilities/File.cpp b/Utilities/File.cpp index c8e4622811..9b78a573ab 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -3,7 +3,6 @@ #include "StrFmt.h" #include "Crypto/sha1.h" -#include #include #include #include diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 47cb6e06c6..9ffdee3f23 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -14,6 +14,7 @@ #include "Emu/system_utils.hpp" #include "Emu/Cell/lv2/sys_process.h" +#include #include LOG_CHANNEL(sys_fs); @@ -163,13 +164,14 @@ const lv2_fs_mount_info& lv2_fs_mount_info_map::lookup(std::string_view path, bo if (path.starts_with("/"sv)) { constexpr std::string_view cell_fs_path = "CELL_FS_PATH:"sv; - std::string path_dir; + const std::string normalized_path = lv2_fs_object::get_normalized_path(path); + std::string_view parent_dir; u32 parent_level = 0; do { - path_dir = fs::get_parent_dir(path, parent_level++); - if (const auto iterator = map.find(path_dir); iterator != map.end()) + parent_dir = fs::get_parent_dir_view(normalized_path, parent_level++); + if (const auto iterator = map.find(parent_dir); iterator != map.end()) { if (iterator->second == &g_mp_sys_dev_root && parent_level > 1) break; @@ -177,7 +179,7 @@ const lv2_fs_mount_info& lv2_fs_mount_info_map::lookup(std::string_view path, bo return lookup(iterator->second.device.substr(cell_fs_path.size()), no_cell_fs_path); // Recursively look up the parent mount info return iterator->second; } - } while (path_dir.length() > 1); // Exit the loop when path_dir == "/" or empty + } while (parent_dir.length() > 1); // Exit the loop when parent_dir == "/" or empty } return g_mi_sys_not_found; @@ -247,22 +249,34 @@ bool lv2_fs_mount_info_map::vfs_unmount(std::string_view vpath, bool remove_from return result; } -std::string lv2_fs_object::get_device_root(std::string_view filename) +std::string lv2_fs_object::get_normalized_path(std::string_view path) { - if (filename.starts_with("/"sv)) - { - std::string path_dir; - u32 parent_level = 0; + std::string normalized_path = std::filesystem::u8path(path).lexically_normal().string(); - do - { - path_dir = fs::get_parent_dir(filename, parent_level++); - if (path_dir.find_last_of("/") == 0) - return path_dir; - } while (path_dir.length() > 1); // Exit the loop when path_dir == "/" or empty +#ifdef _WIN32 + std::replace(normalized_path.begin(), normalized_path.end(), '\\', '/'); +#endif + + if (normalized_path.ends_with('/')) + normalized_path.pop_back(); + + return normalized_path.empty() ? "/" : normalized_path; +} + +std::string_view lv2_fs_object::get_device_root(std::string_view path) +{ + if (const auto first = path.find_first_not_of("/"sv); first != umax) + { + if (const auto pos = path.substr(first).find_first_of("/"sv); pos != umax) + path = path.substr(0, first + pos); + path.remove_prefix(std::max(0, first - 1)); // Remove duplicate leading '/' while keeping only one + } + else + { + path = path.substr(0, 1); } - return std::string(filename); + return path; } lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename, std::string* vfs_path) @@ -273,8 +287,8 @@ lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename, std::string if (is_cell_fs_path) filename.remove_prefix(cell_fs_path.size()); - const bool is_path = filename.starts_with('/'); - std::string mp_name = get_device_root(filename); + const bool is_path = filename.starts_with("/"sv); + std::string mp_name = std::string(is_path ? get_device_root(filename) : filename); const auto check_mp = [&]() { @@ -3115,7 +3129,7 @@ error_code sys_fs_mount(ppu_thread& ppu, vm::cptr dev_name, vm::cptr return {path_error, path_sv}; } - const std::string vpath = fs::get_parent_dir(path_sv, 0); // Just normalize the path + const std::string vpath = lv2_fs_object::get_normalized_path(path_sv); std::string vfs_path; const auto mp = lv2_fs_object::get_mp(device_name, &vfs_path); diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index 5fb75f3d38..0f5c9a3be3 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -245,7 +245,11 @@ public: lv2_fs_object& operator=(const lv2_fs_object&) = delete; - static std::string get_device_root(std::string_view filename); + // Normalize a virtual path + static std::string get_normalized_path(std::string_view path); + + // Get the device's root path (e.g. "/dev_hdd0") from a given path + static std::string_view get_device_root(std::string_view path); // Filename can be either a path starting with '/' or a CELL_FS device name // This should be used only when handling devices that are not mounted