HOPEFULLY finished PFS dirent

This commit is contained in:
Marek Ledworowski 2025-11-16 17:14:23 +01:00
parent 1d18d97b50
commit 748d81b647

View File

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