diff --git a/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory_pfs.cpp b/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory_pfs.cpp index 03f2711b4..4bb3bd8fd 100644 --- a/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory_pfs.cpp +++ b/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory_pfs.cpp @@ -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(this->dirent_cache_bin.data() + bytes_written); - dirent_t normal_dirent{}; + reinterpret_cast(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(buf) + bytes_written, &normal_dirent, to_write); - dirent_offset += pfs_dirent->d_reclen; - bytes_written += to_write; + memcpy(static_cast(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(&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