Make gamedata installation atomic as real PS3

This commit is contained in:
Eladash 2021-03-12 16:25:03 +02:00 committed by Ivan
parent a9b0d25c01
commit d7b4753007
6 changed files with 123 additions and 11 deletions

View File

@ -907,19 +907,16 @@ struct fs_aio_thread : ppu_thread
const auto func = cmd2.arg2<fs_aio_cb_t>();
cmd_pop(1);
s32 error = CELL_OK;
s32 error = CELL_EBADF;
u64 result = 0;
const auto file = idm::get<lv2_fs_object, lv2_file>(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);

View File

@ -81,7 +81,7 @@ struct syscache_info
{
idm::select<lv2_fs_object, lv2_file>([](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;
}

View File

@ -603,6 +603,11 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> 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<void> 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<lv2_fs_object, lv2_file>(fd, [](lv2_file& file)
const auto file = idm::get<lv2_fs_object, lv2_file>(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<lv2_fs_object, lv2_file>(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<loaded_npdrm_keys>().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<CellFsStat> 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<void> _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<void> _arg, u32
std::lock_guard lock(file->mp->mutex);
if (!file->file)
{
return CELL_EBADF;
}
auto sdata_file = std::make_unique<EDATADecrypter>(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<fs::seek_mode>(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;

View File

@ -101,6 +101,13 @@ error_code sys_overlay_load_module_by_fd(vm::ptr<u32> 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));
}

View File

@ -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));
}

View File

@ -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)
{