mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-26 04:35:24 -06:00
HOPEFULLY finished PFS dirent
This commit is contained in:
parent
1d18d97b50
commit
748d81b647
@ -25,13 +25,14 @@ s64 DirectoryPFS::pread(void* buf, u64 count, s64 offset) {
|
||||
|
||||
// data is contiguous. i think that's how it's said
|
||||
// anyway, everything goes raw
|
||||
// aligned to 65536 bytes, everything is zeroed-out in that range
|
||||
// currently not testing for anything higher than that
|
||||
// aligned to 65536 bytes, everything is zeroed-out in that range,
|
||||
// above that - no touchies
|
||||
|
||||
s64 apparent_end = offset + count;
|
||||
|
||||
if (apparent_end > 65536) {
|
||||
// i really don't want to do this yet
|
||||
// no idea if it's even supported on og hw
|
||||
LOG_CRITICAL(Kernel_Fs,
|
||||
"PFS directory size larger than 65536 bytes is not implemented yet");
|
||||
if (offset > 65536)
|
||||
@ -60,6 +61,10 @@ s64 DirectoryPFS::lseek(s64 current, s64 offset, s32 whence) {
|
||||
return Inode::lseek(current, offset, whence);
|
||||
}
|
||||
|
||||
// FIXME: this fn sets file pointer to 65536 so far no issues in testing
|
||||
// it could be just a pointer, but I don't have energy to poke around this
|
||||
// find a key, notify logs when this value should be set and pray nothing breaks in forseeable
|
||||
// future
|
||||
s64 DirectoryPFS::getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
RebuildDirents();
|
||||
|
||||
@ -67,58 +72,53 @@ s64 DirectoryPFS::getdents(void* buf, u32 count, s64 offset, s64* basep) {
|
||||
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
|
||||
// variable sizes are same as dirent_t, but data is still aligned to 8 bytes
|
||||
// initial call pulls all COMPLETE dirents (like base), but returns real amount of bytes
|
||||
// for some reason, subsequent calls return 0
|
||||
// doesn't zero-out memory after last dirent
|
||||
|
||||
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;
|
||||
if (basep)
|
||||
*basep = offset;
|
||||
|
||||
u64 bytes_written = 0;
|
||||
u64 dirent_offset = 0;
|
||||
while (dirent_offset < bytes_available) {
|
||||
u64 starting_offset = 0;
|
||||
u64 buffer_position = 0;
|
||||
while (buffer_position < this->dirent_cache_bin.size()) {
|
||||
|
||||
const dirent_pfs_t* pfs_dirent =
|
||||
reinterpret_cast<dirent_pfs_t*>(this->dirent_cache_bin.data() + bytes_written);
|
||||
dirent_t normal_dirent{};
|
||||
reinterpret_cast<dirent_pfs_t*>(this->dirent_cache_bin.data() + buffer_position);
|
||||
|
||||
// bad, incomplete or OOB entry
|
||||
if (pfs_dirent->d_namlen == 0)
|
||||
break;
|
||||
|
||||
if (starting_offset < offset) {
|
||||
// reading starts from the nearest full dirent
|
||||
starting_offset += pfs_dirent->d_reclen;
|
||||
buffer_position = bytes_written + starting_offset;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((bytes_written + pfs_dirent->d_reclen) > count)
|
||||
// dirents are aligned to the last full one
|
||||
break;
|
||||
|
||||
// if this dirent breaks alignment, skip
|
||||
// dirents are count-aligned here, excess data is simply not written
|
||||
if (Common::AlignUp(buffer_position, count) !=
|
||||
Common::AlignUp(buffer_position + pfs_dirent->d_reclen, count))
|
||||
break;
|
||||
|
||||
// we're transposing u32 into smaller types, so there miiight be some issues
|
||||
// reclen for both is the same despite difference in var sizes, extra 0s are padded after
|
||||
// the name
|
||||
dirent_t normal_dirent{};
|
||||
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;
|
||||
memcpy(static_cast<u8*>(buf) + bytes_written, &normal_dirent, normal_dirent.d_reclen);
|
||||
bytes_written += normal_dirent.d_reclen;
|
||||
buffer_position = bytes_written + starting_offset;
|
||||
}
|
||||
|
||||
// always returns count
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
@ -133,7 +133,6 @@ void DirectoryPFS::RebuildDirents(void) {
|
||||
sizeof(dirent_pfs_t::d_namlen) +
|
||||
sizeof(dirent_pfs_t::d_reclen);
|
||||
|
||||
u64 dirent_size = 0;
|
||||
this->dirent_cache_bin.clear();
|
||||
|
||||
for (auto entry = entries.begin(); entry != entries.end(); ++entry) {
|
||||
@ -149,7 +148,6 @@ void DirectoryPFS::RebuildDirents(void) {
|
||||
auto dirent_ptr = reinterpret_cast<const u8*>(&tmp);
|
||||
|
||||
dirent_cache_bin.insert(dirent_cache_bin.end(), dirent_ptr, dirent_ptr + tmp.d_reclen);
|
||||
dirent_size += tmp.d_reclen;
|
||||
}
|
||||
|
||||
// directory size is always 65536 bytes
|
||||
|
||||
Loading…
Reference in New Issue
Block a user