Regular dirents implemented (hopefully)

This commit is contained in:
marecl 2025-11-14 12:08:00 +01:00
parent 6505d451f5
commit aa65659bb8
8 changed files with 45 additions and 73 deletions

View File

@ -23,7 +23,7 @@ public:
// Conversion helpers
//
static constexpr s32 ToWIN32SeekOrigin(QuasiFS::SeekOrigin origin) {
static constexpr s32 ToWIN32SeekOrigin(s32 origin) {
switch (origin) {
case QuasiFS::SeekOrigin::ORIGIN:
return SEEK_SET;

View File

@ -60,7 +60,7 @@ s32 HostIO_Win32::FSync(const s32 fd) {
s64 HostIO_Win32::LSeek(const s32 fd, s64 offset, s32 whence) {
errno = 0;
s32 status = _lseeki64(fd, offset, ToWIN32SeekOrigin(origin));
s32 status = _lseeki64(fd, offset, ToWIN32SeekOrigin(whence));
return status >= 0 ? status : -errno;
}

View File

@ -73,7 +73,9 @@ public:
}
virtual s64 lseek(s64 current, s64 offset, s32 whence) {
return -QUASI_EBADF;
return ((SeekOrigin::ORIGIN == whence) * offset) +
((SeekOrigin::CURRENT == whence) * (current + offset)) +
((SeekOrigin::END == whence) * (this->st.st_size + offset));
}
virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) {

View File

@ -62,7 +62,6 @@ 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;

View File

@ -25,8 +25,6 @@ public:
s64 pread(void* buf, size_t count, s64 offset) override;
s64 pwrite(const void* buf, size_t count, s64 offset) override;
s64 lseek(s64 current, s64 offset, s32 whence) override;
s32 ftruncate(s64 length) override;
};

View File

@ -24,23 +24,6 @@ s64 QuasiDirectory::pread(void* buf, u64 count, s64 offset) {
return getdents(buf, count, offset, nullptr);
}
s64 QuasiDirectory::lseek(s64 current, s64 offset, s32 whence) {
LOG_ERROR(Kernel_Fs, "(STUB)");
// TBD, most likely acts like a file would
switch (whence) {
case 0:
return offset;
case 1:
return current + offset;
case 2:
return this->st.st_size + offset;
}
UNREACHABLE_MSG("lseek with unknown whence {}", whence);
return -QUASI_ENOSYS;
}
s32 QuasiDirectory::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
RebuildDirents();
*sb = st;
@ -54,22 +37,28 @@ s32 QuasiDirectory::ftruncate(s64 length) {
s64 QuasiDirectory::getdents(void* buf, u32 count, s64 offset, s64* basep) {
RebuildDirents();
// always returns 512 bytes
// forces handle ptr to increment in multiples of 512
// returns each memory-aligned segment
// at this point count is ALWAYS >512 (checked in VIO Driver)
// always returns up to 512 bytes
// return always alignd final fptr to 512 bytes
// doesn't zero-out remaining space in buffer
s64 bytes_available = this->dirent_cache_bin.size() - offset;
s64 true_end = Common::AlignUp(static_cast<u64>(offset) + count, 512);
s64 to_read = true_end - offset;
if (bytes_available <= 0)
return 0;
to_read = to_read > 512 ? 512 : to_read;
to_read = to_read > bytes_available ? bytes_available : to_read;
if (count > 512)
count = 512;
u64 apparent_end = count + offset;
u64 minimum_read = Common::AlignDown(apparent_end, 512) - offset;
u64 maximum_read = Common::AlignUp(apparent_end, 512) - offset;
memcpy(this->dirent_cache_bin.data() + offset, buf, to_read);
u64 to_read = std::min(minimum_read, maximum_read);
if (to_read > bytes_available)
UNREACHABLE_MSG("Buffer read/write misaligned from 512 bytes");
std::copy(dirent_cache_bin.data() + offset, dirent_cache_bin.data() + offset + to_read,
static_cast<u8*>(buf));
if (basep)
*basep = to_read;
@ -141,10 +130,11 @@ void QuasiDirectory::RebuildDirents(void) {
constexpr u32 dirent_meta_size = sizeof(dirent_t::d_fileno) + sizeof(dirent_t::d_type) +
sizeof(dirent_t::d_namlen) + sizeof(dirent_t::d_reclen);
u64 next_ceiling = 512;
u64 dirent_size = 0;
u64 next_ceiling = 0;
u64 dirent_offset = 0;
u64 last_reclen_offset = 4;
this->dirent_cache_bin.clear();
for (auto entry = entries.begin(); entry != entries.end(); ++entry) {
dirent_t tmp{};
inode_ptr node = entry->second;
@ -155,27 +145,33 @@ void QuasiDirectory::RebuildDirents(void) {
tmp.d_namlen = name.size();
strncpy(tmp.d_name, name.data(), tmp.d_namlen + 1);
tmp.d_type = node->type() >> 12;
tmp.d_reclen = Common::AlignUp(dirent_meta_size + tmp.d_namlen + 1, 8);
auto dirent_ptr = reinterpret_cast<const u8*>(&tmp);
tmp.d_reclen = Common::AlignUp(dirent_meta_size + tmp.d_namlen + 1, 4);
if (dirent_size + tmp.d_reclen > next_ceiling) {
// fill rest of the sector with 0s
std::fill(dirent_cache_bin.begin() + dirent_size,
// next element may break 512 byte alignment
if (tmp.d_reclen + dirent_offset > next_ceiling) {
// align previous dirent's size to the current ceiling
*reinterpret_cast<u16*>(static_cast<u8*>(dirent_cache_bin.data()) +
last_reclen_offset) += next_ceiling - dirent_offset;
// set writing pointer to the aligned start position (current ceiling)
dirent_offset = next_ceiling;
// move the ceiling up and zero-out the buffer
next_ceiling += 512;
dirent_cache_bin.resize(next_ceiling);
std::fill(dirent_cache_bin.begin() + dirent_offset,
dirent_cache_bin.begin() + next_ceiling, 0);
// last reclen size to fill the void
*reinterpret_cast<u16*>(dirent_cache_bin.data() + last_reclen_offset) +=
next_ceiling - dirent_size;
dirent_size = next_ceiling;
}
last_reclen_offset = dirent_size + 4;
dirent_cache_bin.insert(dirent_cache_bin.end(), dirent_ptr, dirent_ptr + tmp.d_reclen);
dirent_size += tmp.d_reclen;
next_ceiling = Common::AlignUp(dirent_size, 512);
// current dirent's reclen position
last_reclen_offset = dirent_offset + 4;
memcpy(dirent_cache_bin.data() + dirent_offset, &tmp, tmp.d_reclen);
dirent_offset += tmp.d_reclen;
}
std::fill(dirent_cache_bin.begin() + dirent_size,
dirent_cache_bin.begin() + Common::AlignUp(dirent_size, 512), 0);
// last reclen, as before
*reinterpret_cast<u16*>(static_cast<u8*>(dirent_cache_bin.data()) + last_reclen_offset) +=
next_ceiling - dirent_offset;
// i have no idea if this is the case, but lseek returns size aligned to 512
this->st.st_size = next_ceiling;
}

View File

@ -39,23 +39,6 @@ s64 DirectoryPFS::pread(void* buf, u64 count, s64 offset) {
return count;
}
// s64 DirectoryPFS::lseek(s64 current, s64 offset, s32 whence) {
// LOG_ERROR(Kernel_Fs, "(PFS STUB)");
// // TBD, most likely acts like a file would
// switch (whence) {
// case 0:
// return offset;
// case 1:
// return current + offset;
// case 2:
// return this->st.st_size + offset;
// }
// UNREACHABLE_MSG("lseek with unknown whence {}", whence);
// return -QUASI_ENOSYS;
// }
s64 DirectoryPFS::getdents(void* buf, u32 count, s64 offset, s64* basep) {
RebuildDirents();
memset(buf, 0, count);
@ -95,7 +78,7 @@ void DirectoryPFS::RebuildDirents(void) {
tmp.d_type = node->type() >> 12;
tmp.d_reclen = Common::AlignUp(dirent_meta_size + tmp.d_namlen + 1, 8);
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;
}

View File

@ -25,12 +25,6 @@ s64 QuasiFile::pwrite(const void* buf, size_t count, s64 offset) {
return count;
}
s64 QuasiFile::lseek(s64 current, s64 offset, s32 whence) {
return ((SeekOrigin::ORIGIN == whence) * offset) +
((SeekOrigin::CURRENT == whence) * (current + offset)) +
((SeekOrigin::END == whence) * (this->st.st_size + offset));
}
s32 QuasiFile::ftruncate(s64 length) {
if (length < 0)
return -QUASI_EINVAL;