mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 03:25:16 +00:00
cellFsSdataOpenByFd draft
LLE-compatible implementation lv2_file::make_view implemented
This commit is contained in:
parent
67ac8bf070
commit
8e4a09d9e5
3 changed files with 173 additions and 128 deletions
|
@ -551,113 +551,6 @@ s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr<void(s32 xfd, u64 xsize)>
|
|||
return CELL_OK;
|
||||
}
|
||||
|
||||
bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp)
|
||||
{
|
||||
if (version > 4 || flags & 0x7EFFFFC0){
|
||||
printf("ERROR: unknown version");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((version == 1 && (flags & 0x7FFFFFFE)) ||
|
||||
(version == 2 && (flags & 0x7EFFFFC0))){
|
||||
printf("ERROR: unknown or unsupported type");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (filesizeTmp > filesizeInput){
|
||||
printf("ERROR: input file size is too short.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(flags & 0x80000000)){
|
||||
printf("ERROR: cannot extract finalized edata.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_file)
|
||||
{
|
||||
fs::file packed_stream(vfs::get(packed_file));
|
||||
fs::file unpacked_stream(vfs::get(unpacked_file), fs::rewrite);
|
||||
|
||||
if (!packed_stream)
|
||||
{
|
||||
cellFs.error("File '%s' not found!", packed_file);
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
if (!unpacked_stream)
|
||||
{
|
||||
cellFs.error("File '%s' couldn't be created!", unpacked_file);
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
char buffer[10200];
|
||||
packed_stream.read(buffer, 256);
|
||||
u32 format = *(be_t<u32>*)&buffer[0];
|
||||
if (format != 0x4E504400) // "NPD\x00"
|
||||
{
|
||||
cellFs.error("Illegal format. Expected 0x4E504400, but got 0x%08x", format);
|
||||
return CELL_EFSSPECIFIC;
|
||||
}
|
||||
|
||||
u32 version = *(be_t<u32>*)&buffer[0x04];
|
||||
u32 flags = *(be_t<u32>*)&buffer[0x80];
|
||||
u32 blockSize = *(be_t<u32>*)&buffer[0x84];
|
||||
u64 filesizeOutput = *(be_t<u64>*)&buffer[0x88];
|
||||
u64 filesizeInput = packed_stream.size();
|
||||
u32 blockCount = (u32)((filesizeOutput + blockSize - 1) / blockSize);
|
||||
|
||||
// SDATA file is compressed
|
||||
if (flags & 0x1)
|
||||
{
|
||||
cellFs.warning("cellFsSdataOpen: Compressed SDATA files are not supported yet.");
|
||||
return CELL_EFSSPECIFIC;
|
||||
}
|
||||
// SDATA file is NOT compressed
|
||||
else
|
||||
{
|
||||
u32 t1 = (flags & 0x20) ? 0x20 : 0x10;
|
||||
u32 startOffset = (blockCount * t1) + 0x100;
|
||||
u64 filesizeTmp = (filesizeOutput + 0xF) & 0xFFFFFFF0 + startOffset;
|
||||
|
||||
if (!sdata_check(version, flags, filesizeInput, filesizeTmp))
|
||||
{
|
||||
cellFs.error("cellFsSdataOpen: Wrong header information.");
|
||||
return CELL_EFSSPECIFIC;
|
||||
}
|
||||
|
||||
if (flags & 0x20)
|
||||
{
|
||||
packed_stream.seek(0x100);
|
||||
}
|
||||
else
|
||||
{
|
||||
packed_stream.seek(startOffset);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < blockCount; i++)
|
||||
{
|
||||
if (flags & 0x20)
|
||||
{
|
||||
packed_stream.seek(t1, fs::seek_cur);
|
||||
}
|
||||
|
||||
if (!(blockCount - i - 1))
|
||||
{
|
||||
blockSize = (u32)(filesizeOutput - i * blockSize);
|
||||
}
|
||||
|
||||
packed_stream.read(buffer + 256, blockSize);
|
||||
unpacked_stream.write(buffer + 256, blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsSdataOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size)
|
||||
{
|
||||
cellFs.notice("cellFsSdataOpen(path=%s, flags=%#o, fd=*0x%x, arg=*0x%x, size=0x%llx)", path, flags, fd, arg, size);
|
||||
|
@ -667,33 +560,52 @@ s32 cellFsSdataOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<vo
|
|||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
return cellFsOpen(path, CELL_FS_O_RDONLY, fd, vm::make_var<be_t<u32>[2]>({ 0x180, 0x10 }), 8);
|
||||
|
||||
// Don't implement sdata decryption in this function, it should be done in sys_fs_open() syscall or somewhere else
|
||||
|
||||
/*
|
||||
std::string suffix = path.substr(path.length() - 5, 5);
|
||||
if (suffix != ".sdat" && suffix != ".SDAT")
|
||||
return CELL_ENOTSDATA;
|
||||
|
||||
std::string::size_type last_slash = path.rfind('/'); //TODO: use a filesystem library to solve this more robustly
|
||||
last_slash = last_slash == std::string::npos ? 0 : last_slash+1;
|
||||
std::string unpacked_path = "/dev_hdd1/"+path.substr(last_slash,path.length()-last_slash)+".unpacked";
|
||||
s32 ret = sdata_unpack(path, unpacked_path);
|
||||
if (ret) return ret;
|
||||
|
||||
fd = idm::GetNewID(Emu.GetVFS().OpenFile(unpacked_path, vfsRead), TYPE_FS_FILE);
|
||||
|
||||
return CELL_OK;
|
||||
*/
|
||||
return cellFsOpen(path, CELL_FS_O_RDONLY, fd, vm::make_var<be_t<u32>[2]>({0x180, 0x10}), 8);
|
||||
}
|
||||
|
||||
s32 cellFsSdataOpenByFd(u32 mself_fd, s32 flags, vm::ptr<u32> sdata_fd, u64 offset, vm::cptr<void> arg, u64 size)
|
||||
{
|
||||
cellFs.todo("cellFsSdataOpenByFd(mself_fd=0x%x, flags=%#o, sdata_fd=*0x%x, offset=0x%llx, arg=*0x%x, size=0x%llx)", mself_fd, flags, sdata_fd, offset, arg, size);
|
||||
cellFs.notice("cellFsSdataOpenByFd(mself_fd=0x%x, flags=%#o, sdata_fd=*0x%x, offset=0x%llx, arg=*0x%x, size=0x%llx)", mself_fd, flags, sdata_fd, offset, arg, size);
|
||||
|
||||
// TODO:
|
||||
if (!sdata_fd)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
*sdata_fd = -1;
|
||||
|
||||
if (mself_fd < 3 || mself_fd > 255)
|
||||
{
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
if (flags)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
vm::var<lv2_file_op_09> ctrl;
|
||||
ctrl->_vtable = vm::cast(0xfa880000); // Intentionally wrong (provide correct vtable if necessary)
|
||||
ctrl->op = 0x80000009;
|
||||
ctrl->fd = mself_fd;
|
||||
ctrl->offset = offset;
|
||||
ctrl->_vtabl2 = vm::cast(0xfa880020);
|
||||
ctrl->arg1 = 0x180;
|
||||
ctrl->arg2 = 0x10;
|
||||
ctrl->arg_ptr = arg.addr();
|
||||
ctrl->arg_size = u32(size);
|
||||
|
||||
if (const s32 rc = sys_fs_fcntl(mself_fd, 0x80000009, ctrl, 0x40))
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (const s32 rc = ctrl->out_code)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
|
||||
*sdata_fd = ctrl->out_fd;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,73 @@ u64 lv2_file::op_write(vm::ps3::cptr<void> buf, u64 size)
|
|||
return file.write(local_buf.get(), size);
|
||||
}
|
||||
|
||||
struct lv2_file::file_view : fs::file_base
|
||||
{
|
||||
const std::shared_ptr<lv2_file> m_file;
|
||||
const u64 m_off;
|
||||
u64 m_pos;
|
||||
|
||||
explicit file_view(const std::shared_ptr<lv2_file>& _file, u64 offset)
|
||||
: m_file(_file)
|
||||
, m_off(offset)
|
||||
, m_pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
~file_view() override
|
||||
{
|
||||
}
|
||||
|
||||
fs::stat_t stat() override
|
||||
{
|
||||
return m_file->file.stat();
|
||||
}
|
||||
|
||||
bool trunc(u64 length) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 read(void* buffer, u64 size) override
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_file->mp->mutex);
|
||||
|
||||
const u64 old_pos = m_file->file.pos();
|
||||
const u64 new_pos = m_file->file.seek(m_off + m_pos);
|
||||
const u64 result = m_file->file.read(buffer, size);
|
||||
verify(HERE), old_pos == m_file->file.seek(old_pos);
|
||||
|
||||
m_pos += result;
|
||||
return result;
|
||||
}
|
||||
|
||||
u64 write(const void* buffer, u64 size) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 seek(s64 offset, fs::seek_mode whence) override
|
||||
{
|
||||
return
|
||||
whence == fs::seek_set ? m_pos = offset :
|
||||
whence == fs::seek_cur ? m_pos = offset + m_pos :
|
||||
whence == fs::seek_end ? m_pos = offset + size() :
|
||||
(fmt::raw_error("lv2_file::file_view::seek(): invalid whence"), 0);
|
||||
}
|
||||
|
||||
u64 size() override
|
||||
{
|
||||
return m_off + m_file->file.size();
|
||||
}
|
||||
};
|
||||
|
||||
fs::file lv2_file::make_view(const std::shared_ptr<lv2_file>& _file, u64 offset)
|
||||
{
|
||||
fs::file result;
|
||||
result.reset(std::make_unique<lv2_file::file_view>(_file, offset));
|
||||
return result;
|
||||
}
|
||||
|
||||
error_code sys_fs_test(u32 arg1, u32 arg2, vm::ptr<u32> arg3, u32 arg4, vm::ptr<char> arg5, u32 arg6)
|
||||
{
|
||||
sys_fs.todo("sys_fs_test(arg1=0x%x, arg2=0x%x, arg3=*0x%x, arg4=0x%x, arg5=*0x%x, arg6=0x%x) -> CELL_OK", arg1, arg2, arg3, arg4, arg5, arg6);
|
||||
|
@ -475,6 +542,35 @@ error_code sys_fs_fcntl(u32 fd, u32 op, vm::ptr<void> _arg, u32 _size)
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x80000009: // cellFsSdataOpenByFd
|
||||
{
|
||||
const auto arg = vm::static_ptr_cast<lv2_file_op_09>(_arg);
|
||||
|
||||
if (_size < arg.size())
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
|
||||
|
||||
if (!file)
|
||||
{
|
||||
return CELL_EBADF;
|
||||
}
|
||||
|
||||
// TODO
|
||||
if (const u32 id = idm::make<lv2_fs_object, lv2_file>(file->mp, lv2_file::make_view(file, arg->offset), file->mode, file->flags))
|
||||
{
|
||||
arg->out_code = CELL_OK;
|
||||
arg->out_fd = id;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// Out of file descriptors
|
||||
return CELL_EMFILE;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
sys_fs.todo("sys_fs_fcntl(): Unknown operation 0x%08x (fd=%d, arg=*0x%x, size=0x%x)", op, fd, _arg, _size);
|
||||
|
|
|
@ -126,11 +126,25 @@ struct lv2_file final : lv2_fs_object
|
|||
{
|
||||
}
|
||||
|
||||
lv2_file(lv2_fs_mount_point* mp, fs::file&& file, s32 mode, s32 flags)
|
||||
: lv2_fs_object(mp)
|
||||
, file(std::move(file))
|
||||
, mode(mode)
|
||||
, flags(flags)
|
||||
{
|
||||
}
|
||||
|
||||
// File reading with intermediate buffer
|
||||
u64 op_read(vm::ps3::ptr<void> buf, u64 size);
|
||||
|
||||
// File writing with intermediate buffer
|
||||
u64 op_write(vm::ps3::cptr<void> buf, u64 size);
|
||||
|
||||
// For MSELF support
|
||||
struct file_view;
|
||||
|
||||
// Make file view from lv2_file object (for MSELF support)
|
||||
static fs::file make_view(const std::shared_ptr<lv2_file>& _file, u64 offset);
|
||||
};
|
||||
|
||||
struct lv2_dir final : lv2_fs_object
|
||||
|
@ -181,6 +195,29 @@ struct lv2_file_op_rw : lv2_file_op
|
|||
|
||||
CHECK_SIZE(lv2_file_op_rw, 0x38);
|
||||
|
||||
// sys_fs_fcntl: cellFsSdataOpenByFd
|
||||
struct lv2_file_op_09 : lv2_file_op
|
||||
{
|
||||
vm::bptrb<vtable::lv2_file_op> _vtable;
|
||||
|
||||
be_t<u32> op;
|
||||
be_t<u32> _x8;
|
||||
be_t<u32> _xc;
|
||||
|
||||
be_t<u32> fd;
|
||||
be_t<u64> offset;
|
||||
be_t<u32> _vtabl2;
|
||||
be_t<u32> arg1; // 0x180
|
||||
be_t<u32> arg2; // 0x10
|
||||
be_t<u32> arg_size; // 6th arg
|
||||
be_t<u32> arg_ptr; // 5th arg
|
||||
|
||||
be_t<s32> out_code;
|
||||
be_t<u32> out_fd;
|
||||
};
|
||||
|
||||
CHECK_SIZE(lv2_file_op_09, 0x40);
|
||||
|
||||
// Syscalls
|
||||
|
||||
error_code sys_fs_test(u32 arg1, u32 arg2, vm::ps3::ptr<u32> arg3, u32 arg4, vm::ps3::ptr<char> arg5, u32 arg6);
|
||||
|
|
Loading…
Add table
Reference in a new issue