mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-26 04:35:24 -06:00
Finished dirents (hopefully)
This commit is contained in:
parent
9eed4385f2
commit
26fc2a54ea
@ -62,6 +62,7 @@ public:
|
||||
|
||||
virtual s64 pread(void* buf, u64 count, s64 offset) override;
|
||||
// s64 pwrite(const void* buf, size_t count, u64 offset) override;
|
||||
s64 lseek(s64 current, s64 offset, s32 whence) override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 ftruncate(s64 length) final override;
|
||||
|
||||
|
||||
@ -45,8 +45,8 @@ public:
|
||||
}
|
||||
|
||||
s64 pread(void* buf, u64 count, s64 offset) override;
|
||||
s64 lseek(s64 current, s64 offset, s32 whence) override;
|
||||
|
||||
// s64 lseek(s64 current, s64 offset, s32 whence) override;
|
||||
s64 getdents(void* buf, u32 count, s64 offset, s64* basep) override;
|
||||
};
|
||||
|
||||
|
||||
@ -24,6 +24,11 @@ s64 QuasiDirectory::pread(void* buf, u64 count, s64 offset) {
|
||||
return getdents(buf, count, offset, nullptr);
|
||||
}
|
||||
|
||||
s64 QuasiDirectory::lseek(s64 current, s64 offset, s32 whence) {
|
||||
RebuildDirents();
|
||||
return Inode::lseek(current, offset, whence);
|
||||
}
|
||||
|
||||
s32 QuasiDirectory::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
RebuildDirents();
|
||||
*sb = st;
|
||||
@ -42,20 +47,15 @@ s64 QuasiDirectory::getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
// return always alignd final fptr to 512 bytes
|
||||
// doesn't zero-out remaining space in buffer
|
||||
|
||||
// we're assuming this is always aligned, no check here
|
||||
s64 bytes_available = this->dirent_cache_bin.size() - offset;
|
||||
if (bytes_available <= 0)
|
||||
return 0;
|
||||
|
||||
if (count > 512)
|
||||
count = 512;
|
||||
u64 apparent_end = count + offset;
|
||||
// offset might push it too far so read count becomes misaligned
|
||||
u64 apparent_end = offset + count;
|
||||
u64 minimum_read = Common::AlignDown(apparent_end, 512) - offset;
|
||||
u64 maximum_read = Common::AlignUp(apparent_end, 512) - offset;
|
||||
|
||||
u64 to_read = std::min(minimum_read, maximum_read);
|
||||
|
||||
if (to_read > bytes_available)
|
||||
UNREACHABLE_MSG("Buffer read/write misaligned from 512 bytes");
|
||||
u64 to_read = bytes_available > minimum_read ? minimum_read : bytes_available;
|
||||
|
||||
std::copy(dirent_cache_bin.data() + offset, dirent_cache_bin.data() + offset + to_read,
|
||||
static_cast<u8*>(buf));
|
||||
|
||||
@ -7,41 +7,65 @@
|
||||
#include "core/file_sys/quasifs/quasi_errno.h"
|
||||
#include "core/file_sys/quasifs/quasifs_inode_quasi_directory_pfs.h"
|
||||
|
||||
// PFS is a bit different from regular dirents, see comments below
|
||||
// Although it's pretty simple, every tested game (sample size: 1) reads it exclusively with
|
||||
// count=65536, so it doesn't need much mumbo-jambo like regular dirents
|
||||
// I'll worry if a game uses something different than that count and offset=0
|
||||
|
||||
namespace QuasiFS {
|
||||
|
||||
DirectoryPFS::DirectoryPFS() {
|
||||
this->st.st_size = 65536;
|
||||
this->st.st_size = 65536; // pro forma, gets erased on sync. TODO: fixme
|
||||
}
|
||||
|
||||
DirectoryPFS::~DirectoryPFS() = default;
|
||||
|
||||
s64 DirectoryPFS::pread(void* buf, u64 count, s64 offset) {
|
||||
RebuildDirents();
|
||||
memset(buf, 0, count);
|
||||
|
||||
// data is contiguous. i think that's how it's said
|
||||
// anyway, everything goes raw
|
||||
// always returns count
|
||||
// always zeroes buffer
|
||||
// no cut-off, will just spew out data whenever you ask for it
|
||||
// aligned to 65536 bytes, everything is zeroed-out in that range
|
||||
// currently not testing for anything higher than that
|
||||
|
||||
if (offset >= this->dirent_cache_bin.size())
|
||||
return count;
|
||||
s64 apparent_end = offset + count;
|
||||
|
||||
if (apparent_end > 65536) {
|
||||
// i really don't want to do this yet
|
||||
LOG_CRITICAL(Kernel_Fs,
|
||||
"PFS directory size larger than 65536 bytes is not implemented yet");
|
||||
if (offset > 65536)
|
||||
return 0;
|
||||
count = 65536 - offset;
|
||||
}
|
||||
|
||||
s64 bytes_available = this->dirent_cache_bin.size() - offset;
|
||||
// bytes_to_read but retains the same variable lmao
|
||||
if (bytes_available >= count)
|
||||
bytes_available = count;
|
||||
if (0 >= bytes_available)
|
||||
return 0;
|
||||
bytes_available = bytes_available > count ? count : bytes_available;
|
||||
|
||||
// data
|
||||
memcpy(buf, this->dirent_cache_bin.data() + offset, bytes_available);
|
||||
// remainders
|
||||
s64 filler = count - bytes_available;
|
||||
if (filler > 0)
|
||||
memset(static_cast<u8*>(buf) + bytes_available, 0, filler);
|
||||
|
||||
// always returns count
|
||||
return count;
|
||||
}
|
||||
|
||||
s64 DirectoryPFS::lseek(s64 current, s64 offset, s32 whence) {
|
||||
RebuildDirents();
|
||||
return Inode::lseek(current, offset, whence);
|
||||
}
|
||||
|
||||
s64 DirectoryPFS::getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
RebuildDirents();
|
||||
memset(buf, 0, count);
|
||||
|
||||
if (count != 65536)
|
||||
LOG_CRITICAL(Kernel_Fs, "PFS dirents read with count={} (which is not 65536) (report this)",
|
||||
count);
|
||||
|
||||
// honestly i have no idea on how to implement this
|
||||
// buffer behaves like a regular directory
|
||||
@ -50,7 +74,52 @@ s64 DirectoryPFS::getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
// for some reason, subsequent calls return 0
|
||||
// doesn't zero-out memory after last dirent
|
||||
|
||||
return count;
|
||||
s64 apparent_end = offset + count;
|
||||
|
||||
if (apparent_end > 65536) {
|
||||
// i really don't want to do this yet
|
||||
LOG_CRITICAL(Kernel_Fs,
|
||||
"PFS directory size larger than 65536 bytes is not implemented yet");
|
||||
if (offset > 65536)
|
||||
return 0;
|
||||
count = 65536 - offset;
|
||||
}
|
||||
|
||||
s64 bytes_available = this->dirent_cache_bin.size() - offset;
|
||||
if (0 >= bytes_available)
|
||||
return 0;
|
||||
bytes_available = bytes_available > count ? count : bytes_available;
|
||||
|
||||
u64 bytes_written = 0;
|
||||
u64 dirent_offset = 0;
|
||||
while (dirent_offset < bytes_available) {
|
||||
const dirent_pfs_t* pfs_dirent =
|
||||
reinterpret_cast<dirent_pfs_t*>(this->dirent_cache_bin.data() + bytes_written);
|
||||
dirent_t normal_dirent{};
|
||||
|
||||
// we're transposing u32 into smaller types, so there miiight be some issues
|
||||
normal_dirent.d_fileno = pfs_dirent->d_fileno;
|
||||
normal_dirent.d_reclen = pfs_dirent->d_reclen;
|
||||
normal_dirent.d_type = pfs_dirent->d_type;
|
||||
normal_dirent.d_namlen = pfs_dirent->d_namlen;
|
||||
memcpy(normal_dirent.d_name, pfs_dirent->d_name, pfs_dirent->d_namlen);
|
||||
|
||||
s64 bytes_remaining = bytes_available - bytes_written;
|
||||
u64 to_write = 0;
|
||||
|
||||
if (bytes_remaining > normal_dirent.d_reclen)
|
||||
to_write = normal_dirent.d_reclen;
|
||||
else if (bytes_remaining > 0) {
|
||||
to_write = bytes_remaining;
|
||||
}
|
||||
|
||||
memcpy(static_cast<u8*>(buf) + bytes_written, &normal_dirent, to_write);
|
||||
dirent_offset += pfs_dirent->d_reclen;
|
||||
bytes_written += to_write;
|
||||
}
|
||||
|
||||
// always returns count
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
void DirectoryPFS::RebuildDirents(void) {
|
||||
@ -84,6 +153,9 @@ void DirectoryPFS::RebuildDirents(void) {
|
||||
}
|
||||
|
||||
// directory size is always 65536 bytes
|
||||
// it gets erased on FS sync in QFS, but this fn is rarely called,
|
||||
// especially for PFS which is RO
|
||||
this->st.st_size = 65536;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user