Regular pread+dirents

PFS read (dirents WIP)
This commit is contained in:
Marek Ledworowski 2025-11-12 22:49:09 +01:00
parent dac56a3495
commit 7e4affaf8b
3 changed files with 39 additions and 64 deletions

View File

@ -31,7 +31,6 @@ protected:
void RebuildDirents(void);
time_t last_dirent_rebuild_time{0};
std::map<s64, dirent_t> dirent_cache{};
std::vector<u64> dirent_offset{};
std::vector<u8> dirent_cache_bin{};

View File

@ -46,6 +46,10 @@ s64 QuasiDirectory::getdents(void* buf, u32 count, s64 offset, s64* basep) {
RebuildDirents();
memset(buf, 0, count);
// Copies as many COMPLETE dirents as possible
// If they don't fit - fill with 0s
// Last dirent has its size adjusted to fill the rest of the buffer
if (offset >= this->st.st_size)
return 0;
@ -63,16 +67,8 @@ s64 QuasiDirectory::getdents(void* buf, u32 count, s64 offset, s64* basep) {
u8* dirent_data = static_cast<u8*>(dirent_cache_bin.data());
u8* buffer = static_cast<u8*>(buf);
for (; _start != dirent_offset.end(); _start++) {
if ((*reinterpret_cast<u16*>(dirent_data + 4) + *_start) < offset)
continue;
real_start = *_start;
}
u64 bytes_to_read = 0;
// track last reclen to update after writing
u64 reclen_offset = 0;
// there's always data left
for (auto _end_reverse = std::make_reverse_iterator(_end); _end_reverse != dirent_offset.rend();
@ -84,12 +80,10 @@ s64 QuasiDirectory::getdents(void* buf, u32 count, s64 offset, s64* basep) {
break;
}
std::copy(dirent_cache_bin.begin() + *_start,
dirent_cache_bin.begin() + *_start + bytes_to_read, reinterpret_cast<u8*>(buf));
memcpy(reinterpret_cast<u8*>(buf), dirent_cache_bin.data() + *_start, bytes_to_read);
u8* tmp = static_cast<u8*>(buf);
*(reinterpret_cast<u16*>(tmp + reclen_offset)) +=
Common::AlignUp(bytes_to_read, count) - bytes_to_read;
u8* tmp = static_cast<u8*>(buf) + reclen_offset - *_start;
*(reinterpret_cast<u16*>(tmp)) += count - bytes_to_read;
if (basep)
*basep = count;

View File

@ -19,33 +19,23 @@ s64 DirectoryPFS::pread(void* buf, u64 count, s64 offset) {
RebuildDirents();
memset(buf, 0, count);
auto it = dirent_cache.lower_bound(offset);
// 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
if (it == dirent_cache.end())
return 0;
if (offset >= this->dirent_cache_bin.size())
return count;
u64 cumulative_offset = 0;
u32* reclen_location = nullptr;
for (; it != dirent_cache.end(); it++) {
auto dirent = it->second;
if (dirent.d_reclen + cumulative_offset > count)
break;
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;
auto partial_base = static_cast<u8*>(buf) + cumulative_offset;
auto _fileno = reinterpret_cast<u32*>(partial_base);
auto _type = reinterpret_cast<u32*>(partial_base) + 1;
auto _namlen = reinterpret_cast<u32*>(partial_base) + 2;
reclen_location = reinterpret_cast<u32*>(partial_base) + 3;
*_fileno = dirent.d_fileno;
*_type = dirent.d_type;
*_namlen = dirent.d_namlen;
*reclen_location = dirent.d_reclen;
memcpy(reinterpret_cast<u8*>(reclen_location + 1), &dirent.d_name, dirent.d_namlen);
cumulative_offset += dirent.d_reclen;
}
memcpy(buf, this->dirent_cache_bin.data() + offset, bytes_available);
// always returns count
return count;
}
@ -58,10 +48,11 @@ s64 DirectoryPFS::lseek(s64 current, s64 offset, s32 whence) {
if ((current + offset) >= dirents_size)
return current + offset;
{
auto _tmp = dirent_cache.lower_bound(current + offset);
if (_tmp == dirent_cache.end())
auto _tmp =
std::lower_bound(dirent_offset.begin(), dirent_offset.end(), current + offset);
if (_tmp == dirent_offset.end())
return -QUASI_EINVAL;
return _tmp->first;
return *_tmp;
}
break;
case 2:
@ -76,29 +67,17 @@ s64 DirectoryPFS::getdents(void* buf, u32 count, s64 offset, s64* basep) {
RebuildDirents();
memset(buf, 0, count);
auto it = dirent_cache.lower_bound(offset);
// 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
if (it == dirent_cache.end())
return 0;
u64 cumulative_offset = 0;
for (; it != dirent_cache.end(); it++) {
auto dirent = it->second;
if (dirent.d_reclen + cumulative_offset > count)
break;
memcpy(static_cast<u8*>(buf) + cumulative_offset, &dirent, dirent.d_reclen);
cumulative_offset += dirent.d_reclen;
}
if (basep)
*basep = cumulative_offset;
return cumulative_offset;
return count;
}
void DirectoryPFS::RebuildDirents(void) {
// adding/removing entries changes mtime
if (this->st.st_mtim.tv_sec == this->last_dirent_rebuild_time)
return;
@ -109,10 +88,11 @@ void DirectoryPFS::RebuildDirents(void) {
sizeof(dirent_pfs_t::d_reclen);
u64 dirent_size = 0;
this->dirent_cache.clear();
this->dirent_cache_bin.clear();
this->dirent_offset.clear();
for (auto entry = entries.begin(); entry != entries.end(); ++entry) {
dirent_t tmp{};
dirent_pfs_t tmp{};
inode_ptr node = entry->second;
std::string name = entry->first;
@ -122,11 +102,13 @@ void DirectoryPFS::RebuildDirents(void) {
tmp.d_type = node->type() >> 12;
tmp.d_reclen = Common::AlignUp(dirent_meta_size + tmp.d_namlen + 1, 8);
dirent_cache[dirent_size] = tmp;
auto dirent_ptr = reinterpret_cast<const u8*>(&tmp);
dirent_cache_bin.insert(dirent_cache_bin.end(), dirent_ptr, dirent_ptr + tmp.d_reclen);
dirent_offset.push_back(dirent_size);
dirent_size += tmp.d_reclen;
}
this->dirents_size = dirent_size;
this->st.st_size = dirent_size;
return;
}