From 13ca1a7f09e8a66f6337881ee1824fa8935a1fdc Mon Sep 17 00:00:00 2001 From: brian218 Date: Sun, 13 Nov 2022 22:15:46 +0800 Subject: [PATCH] Further implemented sys_fs_get_mount_info() and sys_fs_get_mount_info_size() --- rpcs3/Emu/Cell/lv2/sys_fs.cpp | 197 +++++++++++++++++++--------------- rpcs3/Emu/Cell/lv2/sys_fs.h | 13 ++- rpcs3/Emu/VFS.cpp | 11 ++ 3 files changed, 132 insertions(+), 89 deletions(-) diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index b95456f521..e6d3ab477f 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -20,17 +20,32 @@ LOG_CHANNEL(sys_fs); -lv2_fs_mount_point g_mp_sys_dev_root; lv2_fs_mount_point g_mp_sys_no_device; -lv2_fs_mount_point g_mp_sys_dev_hdd0{"/dev_hdd0", 512, 0x24FAEA98}; -lv2_fs_mount_point g_mp_sys_dev_hdd1{"/dev_hdd1", 512, 0x3FFFF8, 32768, lv2_mp_flag::no_uid_gid + lv2_mp_flag::cache}; -lv2_fs_mount_point g_mp_sys_dev_usb{"", 512, 0x100, 4096, lv2_mp_flag::no_uid_gid}; -lv2_fs_mount_point g_mp_sys_dev_bdvd{"", 2048, 0x4D955, 65536, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; -lv2_fs_mount_point g_mp_sys_dev_dvd{"", 2048, 0x100, 32768, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; -lv2_fs_mount_point g_mp_sys_host_root{"", 512, 0x100, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid}; -lv2_fs_mount_point g_mp_sys_dev_flash{"", 512, 0x63E00, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; -lv2_fs_mount_point g_mp_sys_dev_flash2{"", 512, 0x8000, 8192, lv2_mp_flag::no_uid_gid}; // TODO confirm -lv2_fs_mount_point g_mp_sys_dev_flash3{"", 512, 0x400, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; // TODO confirm +lv2_fs_mount_point g_mp_sys_dev_root{"/", "CELL_FS_ADMINFS", "CELL_FS_ADMINFS:"}; +lv2_fs_mount_point g_mp_sys_app_home{"/app_home", "CELL_FS_DUMMYFS", "CELL_FS_DUMMY:", 512, 0x100, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid}; +lv2_fs_mount_point g_mp_sys_host_root{"/host_root", "CELL_FS_DUMMYFS", "CELL_FS_DUMMY:/", 512, 0x100, 512, lv2_mp_flag::strict_get_block_size + lv2_mp_flag::no_uid_gid}; +lv2_fs_mount_point g_mp_sys_dev_flash{"/dev_flash", "CELL_FS_FAT", "CELL_FS_IOS:BUILTIN_FLSH1", 512, 0x63E00, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; +lv2_fs_mount_point g_mp_sys_dev_flash2{"/dev_flash2", "CELL_FS_FAT", "CELL_FS_IOS:BUILTIN_FLSH2", 512, 0x8000, 8192, lv2_mp_flag::no_uid_gid}; // TODO confirm +lv2_fs_mount_point g_mp_sys_dev_flash3{"/dev_flash3", "CELL_FS_FAT", "CELL_FS_IOS:BUILTIN_FLSH3", 512, 0x400, 8192, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; // TODO confirm +lv2_fs_mount_point g_mp_sys_dev_hdd0{"/dev_hdd0", "CELL_FS_UFS", "CELL_FS_UTILITY:HDD0", 512, 0x24FAEA98}; +lv2_fs_mount_point g_mp_sys_dev_hdd1{"/dev_hdd1", "CELL_FS_FAT", "CELL_FS_UTILITY:HDD1", 512, 0x3FFFF8, 32768, lv2_mp_flag::no_uid_gid + lv2_mp_flag::cache}; +lv2_fs_mount_point g_mp_sys_dev_bdvd{"/dev_bdvd", "CELL_FS_ISO9660", "CELL_FS_IOS:PATA0_BDVD_DRIVE", 2048, 0x4D955, 65536, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; +lv2_fs_mount_point g_mp_sys_dev_dvd{"/dev_ps2disc", "CELL_FS_ISO9660", "CELL_FS_IOS:PATA0_BDVD_DRIVE", 2048, 0x100, 32768, lv2_mp_flag::read_only + lv2_mp_flag::no_uid_gid}; +lv2_fs_mount_point g_mp_sys_dev_usb{"/dev_usb", "CELL_FS_FAT", "CELL_FS_IOS:USB_MASS_STORAGE", 512, 0x100, 4096, lv2_mp_flag::no_uid_gid}; +constexpr lv2_fs_mount_point* mp_array[] +{ + &g_mp_sys_dev_root, + &g_mp_sys_app_home, + &g_mp_sys_host_root, + &g_mp_sys_dev_flash, + &g_mp_sys_dev_flash2, + &g_mp_sys_dev_flash3, + &g_mp_sys_dev_hdd0, + &g_mp_sys_dev_hdd1, + &g_mp_sys_dev_bdvd, + &g_mp_sys_dev_dvd, + &g_mp_sys_dev_usb, +}; template<> void fmt_class_string::format(std::string& out, u64 arg) @@ -178,72 +193,65 @@ lv2_fs_mount_point* lv2_fs_object::get_mp(std::string_view filename) { const auto mp_name = get_device_path(filename); - 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 == "dev_ps2disc"sv) - return &g_mp_sys_dev_dvd; - 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; - if (mp_name == "dev_flash2"sv) - return &g_mp_sys_dev_flash2; - if (mp_name == "dev_flash3"sv) - return &g_mp_sys_dev_flash3; - - // Default + 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 == "dev_ps2disc"sv) + return &g_mp_sys_dev_dvd; + if (mp_name == "app_home"sv) + return &g_mp_sys_app_home; + if (mp_name == "host_root"sv) + return &g_mp_sys_host_root; + if (mp_name == "dev_flash"sv) + return &g_mp_sys_dev_flash; + if (mp_name == "dev_flash2"sv) + return &g_mp_sys_dev_flash2; + if (mp_name == "dev_flash3"sv) + return &g_mp_sys_dev_flash3; // Default fallback - return &g_mp_sys_dev_root; + return &g_mp_sys_no_device; } std::string lv2_fs_object::get_vfs(std::string_view filename) { const auto mp_name = get_device_path(filename); - if (!mp_name.empty()) - { - if (mp_name == "dev_hdd0"sv) - return g_cfg_vfs.get(g_cfg_vfs.dev_hdd0, rpcs3::utils::get_emu_dir()); - if (mp_name == "dev_hdd1"sv) - return g_cfg_vfs.get(g_cfg_vfs.dev_hdd1, rpcs3::utils::get_emu_dir()); - if (mp_name.starts_with("dev_usb"sv)) - return g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, fmt::format("/%s", mp_name), rpcs3::utils::get_emu_dir()).path; - if (mp_name == "dev_bdvd"sv) - return g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, rpcs3::utils::get_emu_dir()); - if (mp_name == "dev_ps2disc"sv) - return {}; // Unsupported in VFS - if (mp_name == "app_home"sv && filename.data() != Emu.argv[0].data()) - return lv2_fs_object::get_vfs(Emu.argv[0]); - if (mp_name == "host_root"sv) - return g_cfg.vfs.host_root ? "/" : std::string(); - if (mp_name == "dev_flash"sv) - return g_cfg_vfs.get_dev_flash(); - if (mp_name == "dev_flash2"sv) - return g_cfg_vfs.get_dev_flash2(); - if (mp_name == "dev_flash3"sv) - return g_cfg_vfs.get_dev_flash3(); - - // Default + if (mp_name == "dev_hdd0"sv) return g_cfg_vfs.get(g_cfg_vfs.dev_hdd0, rpcs3::utils::get_emu_dir()); - } + if (mp_name == "dev_hdd1"sv) + return g_cfg_vfs.get(g_cfg_vfs.dev_hdd1, rpcs3::utils::get_emu_dir()); + if (mp_name.starts_with("dev_usb"sv)) + return g_cfg_vfs.get_device(g_cfg_vfs.dev_usb, fmt::format("/%s", mp_name), rpcs3::utils::get_emu_dir()).path; + if (mp_name == "dev_bdvd"sv) + return g_cfg_vfs.get(g_cfg_vfs.dev_bdvd, rpcs3::utils::get_emu_dir()); + if (mp_name == "dev_ps2disc"sv) + return {}; // Unsupported in VFS + if (mp_name == "app_home"sv) + return g_cfg_vfs.get(g_cfg_vfs.app_home, rpcs3::utils::get_emu_dir()); + if (mp_name == "host_root"sv) + return g_cfg.vfs.host_root ? "/" : std::string(); + if (mp_name == "dev_flash"sv) + return g_cfg_vfs.get_dev_flash(); + if (mp_name == "dev_flash2"sv) + return g_cfg_vfs.get_dev_flash2(); + if (mp_name == "dev_flash3"sv) + return g_cfg_vfs.get_dev_flash3(); // Default fallback return {}; } +s32 lv2_fs_object::get_mount_count() +{ + return std::count_if(std::begin(mp_array), std::end(mp_array), [](lv2_fs_mount_point* mp){return mp != &g_mp_sys_dev_usb && mp->is_mounted == 1U;}) + std::popcount(g_mp_sys_dev_usb.is_mounted); +} + lv2_fs_object::lv2_fs_object(utils::serial& ar, bool) : name(ar) , mp(get_mp(name.data())) @@ -2932,54 +2940,62 @@ error_code sys_fs_truncate2(ppu_thread&, u32 fd, u64 size) error_code sys_fs_get_mount_info_size(ppu_thread&, vm::ptr len) { - sys_fs.todo("sys_fs_get_mount_info_size(len=*0x%x)", len); + sys_fs.trace("sys_fs_get_mount_info_size(len=*0x%x)", len); if (!len) { return CELL_EFAULT; } - *len = 0x9; + *len = lv2_fs_object::get_mount_count(); return CELL_OK; } error_code sys_fs_get_mount_info(ppu_thread&, vm::ptr info, u32 len, vm::ptr out_len) { - sys_fs.todo("sys_fs_get_mount_info(info=*0x%x, len=0x%x, out_len=*0x%x)", info, len, out_len); + sys_fs.trace("sys_fs_get_mount_info(info=*0x%x, len=0x%x, out_len=*0x%x)", info, len, out_len); - if (!out_len) + if (!info || !out_len) { return CELL_EFAULT; } - // TODO there is a case where 'something' happens if !info or len == 0 - if (!info || len == 0) - { - sys_fs.todo("sys_fs_get_mount_info special case TODO"); - } - - const u32 max_len = std::min(len, 9); + const u32 max_len = std::min(len, lv2_fs_object::get_mount_count()); *out_len = max_len; struct mount_info { - std::string_view path, filesystem, dev_name; + std::string path, filesystem, dev_name; be_t unk1 = 0, unk2 = 0, unk3 = 0, unk4 = 0, unk5 = 0; }; - static constexpr std::array data + std::vector data; + + for (auto mp : mp_array) { - mount_info{.path = "/", .filesystem = "CELL_FS_ADMINFS", .dev_name = "CELL_FS_ADMINFS:", .unk5 = 0x10000000}, - mount_info{.path = "/app_home", .filesystem = "CELL_FS_DUMMY", .dev_name = "CELL_FS_DUMMY:"}, - mount_info{.path = "/host_root", .filesystem = "CELL_FS_DUMMY", .dev_name = "CELL_FS_DUMMY:"}, - mount_info{.path = "/dev_flash", .filesystem = "CELL_FS_FAT", .dev_name = "CELL_FS_IOS:BUILTIN_FLSH1:", .unk5 = 0x10000000}, - mount_info{.path = "/dev_flash2", .filesystem = "CELL_FS_FAT", .dev_name = "CELL_FS_IOS:BUILTIN_FLSH2:"}, - mount_info{.path = "/dev_flash3", .filesystem = "CELL_FS_FAT", .dev_name = "CELL_FS_IOS:BUILTIN_FLSH3:"}, - mount_info{.path = "/dev_hdd0", .filesystem = "CELL_FS_UFS", .dev_name = "CELL_FS_UTILITY:HDD0:"}, - mount_info{.path = "/dev_hdd1", .filesystem = "CELL_FS_FAT", .dev_name = "CELL_FS_UTILITY:HDD1:"}, - mount_info{.path = "/dev_bdvd", .filesystem = "CELL_FS_ISO9660", .dev_name = "CELL_FS_IOS:PATA0_BDVD_DRIVE"}, - }; + if (mp->is_mounted == 0U) + continue; + + if (mp == &g_mp_sys_dev_usb) + { + for (int i = 0; i < 8; i++) + { + if ((mp->is_mounted >> i) & 1U) + { + data.push_back(mount_info{.path = fmt::format("%s%03d", mp->root, i), .filesystem = mp->file_system.data(), .dev_name = fmt::format("%s%03d", mp->device, i)}); + } + } + } + else if (mp == &g_mp_sys_dev_root || mp == &g_mp_sys_dev_flash) + { + data.push_back(mount_info{.path = mp->root.data(), .filesystem = mp->file_system.data(), .dev_name = mp->device.data(), .unk5 = 0x10000000}); + } + else + { + data.push_back(mount_info{.path = mp->root.data(), .filesystem = mp->file_system.data(), .dev_name = mp->device.data()}); + } + } for (u32 i = 0; i < max_len; info++, i++) { @@ -2992,7 +3008,7 @@ error_code sys_fs_get_mount_info(ppu_thread&, vm::ptr info, u32 return CELL_OK; } -error_code sys_fs_newfs(ppu_thread& ppu, vm::cptr dev_name, vm::cptr file_system, s32 unk1, vm::cptr str1) +error_code sys_fs_newfs(ppu_thread&, vm::cptr dev_name, vm::cptr file_system, s32 unk1, vm::cptr str1) { sys_fs.todo("sys_fs_newfs(dev_name=%s, file_system=%s, unk1=0x%x, str1=%s)", dev_name, file_system, unk1, str1); @@ -3032,6 +3048,12 @@ error_code sys_fs_mount(ppu_thread&, vm::cptr dev_name, vm::cptr fil auto vfs_mount = [&vpath = vpath, &filesystem = filesystem, &mp = mp](std::string mount_path) { + const std::string local_path = vfs::get(vpath); + if (!local_path.empty()) + { + sys_fs.error("\"%s\" has already been mounted to \"%s\"", vpath, local_path); + return false; + } if (!mount_path.ends_with('/')) mount_path += '/'; if (!fs::is_dir(mount_path) && !fs::create_dir(mount_path)) @@ -3097,6 +3119,11 @@ error_code sys_fs_unmount(ppu_thread&, vm::cptr path, s32 unk1, s32 unk2) auto vfs_unmount = [&vpath = vpath]() { const std::string local_path = vfs::get(vpath); + if (local_path.empty()) + { + sys_fs.error("\"%s\" is not mounted!", vpath); + return false; + } if (fs::is_file(local_path)) { if (fs::remove_file(local_path)) diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index 3faddd9c07..f555fc241c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -148,16 +148,20 @@ enum class lv2_file_type struct lv2_fs_mount_point { const std::string_view root; + const std::string_view file_system; + const std::string_view device; const u32 sector_size = 512; const u64 sector_count = 256; const u32 block_size = 4096; const bs_t flags{}; + u8 is_mounted = 0U; mutable std::recursive_mutex mutex; }; 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; struct lv2_fs_object { @@ -190,6 +194,7 @@ public: static std::string_view get_device_path(std::string_view filename); static lv2_fs_mount_point* get_mp(std::string_view filename); static std::string get_vfs(std::string_view filename); + static s32 get_mount_count(); static std::array get_name(std::string_view filename) { @@ -617,8 +622,8 @@ error_code sys_fs_lsn_write(ppu_thread& ppu, u32 fd, vm::cptr, u64); error_code sys_fs_mapped_allocate(ppu_thread& ppu, u32 fd, u64, vm::pptr out_ptr); error_code sys_fs_mapped_free(ppu_thread& ppu, u32 fd, vm::ptr ptr); error_code sys_fs_truncate2(ppu_thread& ppu, u32 fd, u64 size); -error_code sys_fs_newfs(ppu_thread& ppu, vm::cptr dev_name, vm::cptr file_system, s32 unk1, vm::cptr str1); -error_code sys_fs_mount(ppu_thread& ppu, vm::cptr dev_name, vm::cptr file_system, vm::cptr path, s32 unk1, s32 prot, s32 unk3, vm::cptr str1, u32 str_len); +error_code sys_fs_newfs(ppu_thread&, vm::cptr dev_name, vm::cptr file_system, s32 unk1, vm::cptr str1); +error_code sys_fs_mount(ppu_thread&, vm::cptr dev_name, vm::cptr file_system, vm::cptr path, s32 unk1, s32 prot, s32 unk3, vm::cptr str1, u32 str_len); error_code sys_fs_unmount(ppu_thread&, vm::cptr path, s32 unk1, s32 unk2); -error_code sys_fs_get_mount_info_size(ppu_thread& ppu, vm::ptr len); -error_code sys_fs_get_mount_info(ppu_thread& ppu, vm::ptr info, u32 len, vm::ptr out_len); +error_code sys_fs_get_mount_info_size(ppu_thread&, vm::ptr len); +error_code sys_fs_get_mount_info(ppu_thread&, vm::ptr info, u32 len, vm::ptr out_len); diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index 3e472793f8..d88d949379 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -73,6 +73,11 @@ bool vfs::mount(std::string_view vpath, std::string_view path, bool is_dir) list.back()->path += '/'; if (!is_dir && list.back()->path.ends_with('/')) vfs_log.error("File mounted with trailing /."); + const auto mp = lv2_fs_object::get_mp(vpath_backup); + if (mp == &g_mp_sys_dev_usb) + mp->is_mounted |= (1U << vpath_backup.back() - '0'); + else + mp->is_mounted = 1U; vfs_log.notice("Mounted path \"%s\" to \"%s\"", vpath_backup, list.back()->path); return true; } @@ -180,6 +185,12 @@ bool vfs::unmount(std::string_view vpath) }; unmount_children(table.root, 0); + const auto mp = lv2_fs_object::get_mp(vpath); + if (mp == &g_mp_sys_dev_usb) + mp->is_mounted &= ~(1U << vpath.back() - '0'); + else + mp->is_mounted = 0U; + return true; }