diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 16ee89e30b..f592b3647b 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -2,6 +2,7 @@ #include "sys_sync.h" #include "sys_fs.h" +#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUThread.h" #include "Crypto/unedat.h" #include "Emu/System.h" @@ -1709,9 +1710,53 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 break; } - case 0x00000025: // cellFsSdataOpenWithVersion + case 0xe0000025: // cellFsSdataOpenWithVersion { - break; + const auto arg = vm::static_ptr_cast(_arg); + + if (arg->size != 0x30u) + { + sys_fs.error("sys_fs_fcntl(0xe0000025): invalid size (0x%x)", arg->size); + break; + } + + if (arg->_x4 != 0x10u || arg->_x8 != 0x28u) + { + sys_fs.error("sys_fs_fcntl(0xe0000025): invalid args (0x%x, 0x%x)", arg->_x4, arg->_x8); + break; + } + + std::string_view vpath{ arg->name.get_ptr(), arg->name_size }; + vpath = vpath.substr(0, vpath.find_first_of('\0')); + + sys_fs.notice("sys_fs_fcntl(0xe0000025): %s", vpath); + + be_t sdata_identifier = 0x18000000010; + + lv2_file::open_result_t result = lv2_file::open(vpath, 0, 0, &sdata_identifier, 8); + + if (result.error) + { + return result.error; + } + + if (const u32 id = idm::import([&]() -> std::shared_ptr + { + if (!g_fxo->get().npdrm_fds.try_inc(16)) + { + return nullptr; + } + + return std::make_shared(result.ppath, std::move(result.file), 0, 0, std::move(result.real_path), lv2_file_type::sdata); + })) + { + arg->out_code = CELL_OK; + arg->fd = id; + return CELL_OK; + } + + // Out of file descriptors + return CELL_EMFILE; } } diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.h b/rpcs3/Emu/Cell/lv2/sys_fs.h index cc0e12fc98..08b4f2d04c 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.h +++ b/rpcs3/Emu/Cell/lv2/sys_fs.h @@ -382,6 +382,24 @@ struct lv2_file_op_09 : lv2_file_op CHECK_SIZE(lv2_file_op_09, 0x40); +struct lv2_file_e0000025 : lv2_file_op +{ + be_t size; // 0x30 + be_t _x4; // 0x10 + be_t _x8; // 0x28 - offset of out_code + be_t name_size; + vm::bcptr name; + be_t _x14; + be_t _x18; // 0 + be_t _x1c; // 0 + be_t _x20; // 16 + be_t _x24; // unk, seems to be memory location + be_t out_code; // out_code + be_t fd; // 0xffffffff - likely fd out +}; + +CHECK_SIZE(lv2_file_e0000025, 0x30); + // sys_fs_fnctl: cellFsGetDirectoryEntries struct lv2_file_op_dir : lv2_file_op {