diff --git a/rpcs3/Emu/Cell/Modules/cellFs.cpp b/rpcs3/Emu/Cell/Modules/cellFs.cpp index 42a1bd538e..b72da97cf2 100644 --- a/rpcs3/Emu/Cell/Modules/cellFs.cpp +++ b/rpcs3/Emu/Cell/Modules/cellFs.cpp @@ -907,19 +907,16 @@ struct fs_aio_thread : ppu_thread const auto func = cmd2.arg2(); cmd_pop(1); - s32 error = CELL_OK; + s32 error = CELL_EBADF; u64 result = 0; const auto file = idm::get(aio->fd); if (!file || (type == 1 && file->flags & CELL_FS_O_WRONLY) || (type == 2 && !(file->flags & CELL_FS_O_ACCMODE))) { - error = CELL_EBADF; } - else + else if (std::lock_guard lock(file->mp->mutex); file->file) { - std::lock_guard lock(file->mp->mutex); - const auto old_pos = file->file.pos(); file->file.seek(aio->offset); result = type == 2 @@ -927,6 +924,7 @@ struct fs_aio_thread : ppu_thread : file->op_read(aio->buf, aio->size); file->file.seek(old_pos); + error = CELL_OK; } func(*this, aio, error, xid, result); diff --git a/rpcs3/Emu/Cell/Modules/cellSysCache.cpp b/rpcs3/Emu/Cell/Modules/cellSysCache.cpp index 3a2cad779c..d14d8d70ef 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysCache.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysCache.cpp @@ -81,7 +81,7 @@ struct syscache_info { idm::select([](u32 /*id*/, lv2_file& file) { - if (std::memcmp("/dev_hdd1", file.name.data(), 9) == 0) + if (file.file && std::memcmp("/dev_hdd1/", file.name.data(), 10) == 0) { file.lock = 2; } diff --git a/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 4cfc046074..d3b887bae7 100644 --- a/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -603,6 +603,11 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr buf, u64 nbytes, v std::lock_guard lock(file->mp->mutex); + if (!file->file) + { + return CELL_EBADF; + } + if (file->lock == 2) { nread.try_write(0); @@ -648,6 +653,11 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr buf, u64 nbytes, std::lock_guard lock(file->mp->mutex); + if (!file->file) + { + return CELL_EBADF; + } + if (file->lock) { if (file->lock == 2) @@ -677,15 +687,49 @@ error_code sys_fs_close(ppu_thread& ppu, u32 fd) sys_fs.trace("sys_fs_close(fd=%d)", fd); - const auto file = idm::withdraw(fd, [](lv2_file& file) + const auto file = idm::get(fd); + + if (!file) { - if (file.type >= lv2_file_type::sdata) + return CELL_EBADF; + } + + { + std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + + if (std::memcmp(file->name.data(), "/dev_hdd1/", 10) != 0 + && !(file->mp->flags & lv2_mp_flag::read_only) && file->flags & CELL_FS_O_ACCMODE) + { + // Special: Ensure temporary directory for gamedata writes will remain on disk before final gamedata commitment + file->file.sync(); // For cellGameContentPermit atomicity + } + + // Ensure Host file handle won't be kept open after this syscall + file->file.close(); + } + + const auto ret = idm::withdraw(fd, [&](lv2_file& _file) -> CellError + { + if (file.get() != std::addressof(_file)) + { + // Other thread destroyed the object inbetween + return CELL_EBADF; + } + + if (_file.type >= lv2_file_type::sdata) { g_fxo->get().npdrm_fds--; } + + return {}; }); - if (!file) + if (!ret || ret.ret == CELL_EBADF) { return CELL_EBADF; } @@ -980,6 +1024,11 @@ error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr sb) std::lock_guard lock(file->mp->mutex); + if (!file->file) + { + return CELL_EBADF; + } + if (file->lock == 2) { return CELL_EIO; @@ -1296,6 +1345,11 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 std::lock_guard lock(file->mp->mutex); + if (!file->file) + { + return CELL_EBADF; + } + if (file->lock == 2) { return CELL_EIO; @@ -1339,6 +1393,11 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr _arg, u32 std::lock_guard lock(file->mp->mutex); + if (!file->file) + { + return CELL_EBADF; + } + auto sdata_file = std::make_unique(lv2_file::make_view(file, arg->offset)); if (!sdata_file->ReadHeader()) @@ -1668,13 +1727,18 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr return CELL_EBADF; } + std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + if (whence + 0u >= 3) { return {CELL_EINVAL, whence}; } - std::lock_guard lock(file->mp->mutex); - const u64 result = file->file.seek(offset, static_cast(whence)); if (result == umax) @@ -1707,6 +1771,12 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd) } std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + file->file.sync(); return CELL_OK; } @@ -1726,6 +1796,12 @@ error_code sys_fs_fsync(ppu_thread& ppu, u32 fd) } std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + file->file.sync(); return CELL_OK; } @@ -1880,6 +1956,11 @@ error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size) std::lock_guard lock(file->mp->mutex); + if (!file->file) + { + return CELL_EBADF; + } + if (file->lock == 2) { return CELL_EIO; diff --git a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp index 590385ed9d..857e35ab37 100644 --- a/rpcs3/Emu/Cell/lv2/sys_overlay.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_overlay.cpp @@ -101,6 +101,13 @@ error_code sys_overlay_load_module_by_fd(vm::ptr ovlmid, u32 fd, u64 offset return CELL_EBADF; } + std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + return overlay_load_module(ovlmid, fmt::format("%s_x%x", file->name.data(), offset), flags, entry, lv2_file::make_view(file, offset)); } diff --git a/rpcs3/Emu/Cell/lv2/sys_prx.cpp b/rpcs3/Emu/Cell/lv2/sys_prx.cpp index cab860cdae..7addd60516 100644 --- a/rpcs3/Emu/Cell/lv2/sys_prx.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_prx.cpp @@ -311,6 +311,13 @@ error_code _sys_prx_load_module_by_fd(ppu_thread& ppu, s32 fd, u64 offset, u64 f return CELL_EBADF; } + std::lock_guard lock(file->mp->mutex); + + if (!file->file) + { + return CELL_EBADF; + } + return prx_load_module(fmt::format("%s_x%x", file->name.data(), offset), flags, pOpt, lv2_file::make_view(file, offset)); } diff --git a/rpcs3/Emu/VFS.cpp b/rpcs3/Emu/VFS.cpp index 482873c215..904852afbe 100644 --- a/rpcs3/Emu/VFS.cpp +++ b/rpcs3/Emu/VFS.cpp @@ -749,7 +749,21 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2 if (check_path(fs::escape_path(file.real_path))) { ensure(file.mp == mp); + + if (!file.file) + { + file.restore_data.seek_pos = -1; + return; + } + file.restore_data.seek_pos = file.file.pos(); + + if (std::memcmp(file.name.data(), "/dev_hdd1/", 10) != 0 + && !(file.mp->flags & lv2_mp_flag::read_only) && file.flags & CELL_FS_O_ACCMODE) + { + file.file.sync(); // For cellGameContentPermit atomicity + } + file.file.close(); // Actually close it! } }); @@ -779,6 +793,11 @@ bool vfs::host::rename(const std::string& from, const std::string& to, const lv2 if (check_path(escaped_real)) { + if (file.restore_data.seek_pos == umax) + { + return; + } + // Update internal path if (res) {