#include "stdafx.h" #include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SC_FUNC.h" void sys_fs_init(); Module sys_fs(0x000e, sys_fs_init); 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; } int sdata_unpack(wxString packed_file, wxString unpacked_file) { vfsStream* packed_stream = Emu.GetVFS().Open(packed_file, vfsRead); vfsStream* unpacked_stream = Emu.GetVFS().Open(unpacked_file, vfsWrite); if(!packed_stream || !packed_stream->IsOpened()) { sys_fs.Error("'%s' not found! flags: 0x%08x", packed_file.mb_str(), vfsRead); delete packed_stream; return CELL_ENOENT; } if(!unpacked_stream || !unpacked_stream->IsOpened()) { sys_fs.Error("'%s' couldn't be created! flags: 0x%08x", unpacked_file.mb_str(), vfsWrite); delete unpacked_stream; return CELL_ENOENT; } char buffer [10200]; packed_stream->Read(buffer, 256); if (re32(*(u32*)&buffer[0]) != 0x4E504400) // "NPD\x00" { printf("ERROR: illegal format."); return CELL_EFSSPECIFIC; } u32 version = re32(*(u32*)&buffer[0x04]); u32 flags = re32(*(u32*)&buffer[0x80]); u32 blockSize = re32(*(u32*)&buffer[0x84]); u64 filesizeOutput = re64(*(u64*)&buffer[0x88]); u64 filesizeInput = packed_stream->GetSize(); u32 blockCount = (filesizeOutput + blockSize-1) / blockSize; // SDATA file is compressed if (flags & 0x1) { sys_fs.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)) { sys_fs.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(packed_stream->Tell() + t1); if (!(blockCount-i-1)) blockSize = filesizeOutput-i*blockSize; packed_stream->Read(buffer+256, blockSize); unpacked_stream->Write(buffer+256, blockSize); } } packed_stream->Close(); unpacked_stream->Close(); return CELL_OK; } int cellFsSdataOpen(u32 path_addr, int flags, mem32_t fd, mem32_t arg, u64 size) { const wxString& path = Memory.ReadString(path_addr); sys_fs.Warning("cellFsSdataOpen(path: %s, flags: 0x%x, fd_addr: 0x%x, arg_addr: 0x%x, size: 0x%llx)", path.mb_str(), flags, fd.GetAddr(), arg.GetAddr(), size); if (!fd.IsGood() || (!arg.IsGood() && size)) return CELL_EFAULT; if (flags != CELL_O_RDONLY) return CELL_EINVAL; if (!path.Lower().EndsWith(".sdat")) return CELL_ENOTSDATA; wxString unpacked_path = "/dev_hdd1/"+path.AfterLast('/')+".unpacked"; int ret = sdata_unpack(path, unpacked_path); if (ret) return ret; vfsStream* stream = Emu.GetVFS().Open(unpacked_path, vfsRead); fd = sys_fs.GetNewId(stream, flags); return CELL_OK; } /*struct CellFsAio { be_t fd; be_t offset; be_t buf_addr; be_t size; be_t user_data; }; int cellFsAioRead(mem_ptr_t aio, mem32_t id, mem32_t func_addr) { if(!aio.IsGood() || !id.IsGood() || !func_addr.IsGood()) return CELL_EFAULT; //CellFsAio *xaio, CellFsErrno error, int xid, uint64_t size; Callback callback; callback.SetAddr(func_addr); callback.SetName("cellFsAioReadCallback"); MemoryAllocator> nread; int error = cellFsRead(aio->fd, id.GetAddr(), aio->size, nread); callback.Handle(aio.GetAddr(), error, id, *nread); callback.Branch(true); return CELL_OK; }*/ std::atomic g_FsAioReadID = 0; int cellFsAioRead(mem_ptr_t aio, mem32_t aio_id, u32 func_addr) { ID id; u32 fd = (u32)aio->fd; if(!sys_fs.CheckId(fd, id)) return CELL_ESRCH; vfsFileBase& orig_file = *(vfsFileBase*)id.m_data; //open the file again (to prevent access conflicts roughly) vfsStream& file = vfsLocalFile(orig_file.GetPath().AfterFirst('/'), vfsRead); u64 nbytes = (u64)aio->size; const u32 buf_addr = (u32)aio->buf_addr; if(Memory.IsGoodAddr(buf_addr) && !Memory.IsGoodAddr(buf_addr, nbytes)) { MemoryBlock& block = Memory.GetMemByAddr(buf_addr); nbytes = block.GetSize() - (buf_addr - block.GetStartAddr()); } //read data immediately (actually it should be read in special thread) file.Seek((u64)aio->offset); const u64 res = nbytes ? file.Read(Memory.GetMemFromAddr(buf_addr), nbytes) : 0; file.Close(); //get a unique id for the callback const u32 xid = g_FsAioReadID++; aio_id = xid; sys_fs.Warning("cellFsAioRead(aio_addr: 0x%x[%s], id_addr: 0x%x, func_addr: 0x%x[res=%d, addr=0x%x])", aio.GetAddr(), orig_file.GetPath().c_str(), aio_id.GetAddr(), func_addr, res, (u32)aio->buf_addr); //TODO: init the callback CPUThread& new_thread = Emu.GetCPU().AddThread(CPU_THREAD_PPU); new_thread.SetEntry(func_addr); new_thread.SetPrio(1001); new_thread.SetStackSize(0x10000); new_thread.SetName("FsAioReadCallback"); new_thread.SetArg(0, aio.GetAddr()); //xaio new_thread.SetArg(1, CELL_OK); //error code new_thread.SetArg(2, xid); //xid (unique id) new_thread.SetArg(3, res); //size (bytes read) new_thread.Run(); new_thread.Exec(); return CELL_OK; } void sys_fs_init() { sys_fs.AddFunc(0x718bf5f8, cellFsOpen); sys_fs.AddFunc(0xb1840b53, cellFsSdataOpen); sys_fs.AddFunc(0x4d5ff8e2, cellFsRead); sys_fs.AddFunc(0xecdcf2ab, cellFsWrite); sys_fs.AddFunc(0x2cb51f0d, cellFsClose); sys_fs.AddFunc(0x3f61245c, cellFsOpendir); sys_fs.AddFunc(0x5c74903d, cellFsReaddir); sys_fs.AddFunc(0xff42dcc3, cellFsClosedir); sys_fs.AddFunc(0x7de6dced, cellFsStat); sys_fs.AddFunc(0xef3efa34, cellFsFstat); sys_fs.AddFunc(0xba901fe6, cellFsMkdir); sys_fs.AddFunc(0xf12eecc8, cellFsRename); sys_fs.AddFunc(0x2796fdf3, cellFsRmdir); sys_fs.AddFunc(0x7f4677a8, cellFsUnlink); sys_fs.AddFunc(0xa397d042, cellFsLseek); sys_fs.AddFunc(0x0e2939e5, cellFsFtruncate); sys_fs.AddFunc(0xc9dc3ac5, cellFsTruncate); sys_fs.AddFunc(0xcb588dba, cellFsFGetBlockSize); sys_fs.AddFunc(0xc1c507e7, cellFsAioRead); }