From 9b22661c19fd44dcdc34ef053b3ae01d33dc08e5 Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 1 Oct 2020 22:07:38 +0300 Subject: [PATCH] fs: improve mountpoint detection Properly handle . and .. path components in mountpoint detection. Remove app_home mountpoint and use mountpoint from argv[0] instead. Add dev_root mountpoint for special purposes. --- rpcs3/Emu/Cell/lv2/sys_fs.cpp | 67 ++++++++++++++++++++++++++++++----- rpcs3/Emu/Cell/lv2/sys_fs.h | 5 --- rpcs3/Emu/VFS.cpp | 7 ++-- 3 files changed, 61 insertions(+), 18 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 5b948da74d..ddb00cd0cc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -10,11 +10,11 @@ LOG_CHANNEL(sys_fs); +lv2_fs_mount_point g_mp_sys_dev_root; lv2_fs_mount_point g_mp_sys_dev_hdd0; lv2_fs_mount_point g_mp_sys_dev_hdd1{512, 32768, lv2_mp_flag::no_uid_gid}; lv2_fs_mount_point g_mp_sys_dev_usb{512, 4096, lv2_mp_flag::no_uid_gid}; lv2_fs_mount_point g_mp_sys_dev_bdvd{2048, 65536, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; -lv2_fs_mount_point g_mp_sys_app_home{512, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid}; lv2_fs_mount_point g_mp_sys_host_root{512, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid}; lv2_fs_mount_point g_mp_sys_dev_flash{512, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; @@ -53,28 +53,77 @@ bool verify_mself(const fs::file& mself_file) lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename) { - const auto mp_begin = filename.find_first_not_of('/'); + std::string_view mp_name, vpath = filename; - if (mp_begin + 1) + for (std::size_t depth = 0;;) { - const auto mp_name = filename.substr(mp_begin, filename.find_first_of('/', mp_begin) - mp_begin); + // Skip one or more '/' + const auto pos = vpath.find_first_not_of('/'); + if (pos == 0) + { + // Relative path (TODO) + break; + } + + if (pos == umax) + { + break; + } + + // Get fragment name + const auto name = vpath.substr(pos, vpath.find_first_of('/', pos) - pos); + vpath.remove_prefix(name.size() + pos); + + // Process special directories + if (name == "."sv) + { + // Keep current + continue; + } + + if (name == ".."sv) + { + // Root parent is root + if (depth == 0) + { + continue; + } + + depth--; + continue; + } + + if (depth++ == 0) + { + // Save mountpoint name + mp_name = name; + } + } + + if (!mp_name.empty()) + { + if (mp_name == "dev_hdd0"sv) + return &g_mp_sys_dev_hdd0; if (mp_name == "dev_hdd1"sv) return &g_mp_sys_dev_hdd1; if (mp_name.starts_with("dev_usb"sv)) return &g_mp_sys_dev_usb; if (mp_name == "dev_bdvd"sv) return &g_mp_sys_dev_bdvd; - if (mp_name == "app_home"sv) - return &g_mp_sys_app_home; + if (mp_name == "app_home"sv && filename.data() != Emu.argv[0].data()) + return lv2_fs_object::get_mp(Emu.argv[0]); if (mp_name == "host_root"sv) return &g_mp_sys_host_root; if (mp_name == "dev_flash"sv) return &g_mp_sys_dev_flash; + + // Default + return &g_mp_sys_dev_hdd0; } - // Default - return &g_mp_sys_dev_hdd0; + // Default fallback + return &g_mp_sys_dev_root; } u64 lv2_file::op_read(const fs::file& file, vm::ptr buf, u64 size) @@ -1902,7 +1951,7 @@ error_code sys_fs_disk_free(ppu_thread& ppu, vm::cptr path, vm::ptr t } // HACK: Hopefully nothing uses this value or once at max because its hacked here: - // The total size can change based on the size of the directory + // The total size can change based on the size of the directory *total_free = *avail_free + fs::get_dir_size(local_path, mp->sector_size); return CELL_OK; diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index 1d389d00ae..b290922476 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -149,11 +149,6 @@ struct lv2_fs_mount_point extern lv2_fs_mount_point g_mp_sys_dev_hdd0; extern lv2_fs_mount_point g_mp_sys_dev_hdd1; -extern lv2_fs_mount_point g_mp_sys_dev_usb; -extern lv2_fs_mount_point g_mp_sys_dev_bdvd; -extern lv2_fs_mount_point g_mp_sys_app_home; -extern lv2_fs_mount_point g_mp_sys_host_root; -extern lv2_fs_mount_point g_mp_sys_dev_flash; struct lv2_fs_object { diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index cb8544a37a..8120d6585b 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -712,12 +712,11 @@ std::string vfs::host::hash_path(const std::string& path, const std::string& dev bool vfs::host::rename(const std::string& from, const std::string& to, const lv2_fs_mount_point* mp, bool overwrite) { - // Lock mount point, close file descriptors, retry + // Lock mount point, close file descriptors, retry const auto from0 = std::string_view(from).substr(0, from.find_last_not_of(fs::delim) + 1); const auto escaped_from = fs::escape_path(from); - // Lock app_home as well because it could be in the same drive as current mount point (TODO) - std::scoped_lock lock(mp->mutex, g_mp_sys_app_home.mutex); + std::lock_guard lock(mp->mutex); auto check_path = [&](std::string_view path) { @@ -728,7 +727,7 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2 { if (check_path(fs::escape_path(file.real_path))) { - verify(HERE), file.mp == mp || file.mp == &g_mp_sys_app_home; + verify(HERE), file.mp == mp; file.restore_data.seek_pos = file.file.pos(); file.file.close(); // Actually close it! }