From aa65659bb84e33d77c35daaa2c652b8c99da6344 Mon Sep 17 00:00:00 2001 From: marecl Date: Fri, 14 Nov 2025 12:08:00 +0100 Subject: [PATCH] Regular dirents implemented (hopefully) --- src/core/file_sys/hostio/host_io_win32.h | 2 +- .../file_sys/hostio/src/host_io_win32.cpp | 2 +- src/core/file_sys/quasifs/quasifs_inode.h | 4 +- .../quasifs/quasifs_inode_quasi_directory.h | 1 - .../quasifs/quasifs_inode_quasi_file.h | 2 - .../src/quasifs_inode_quasi_directory.cpp | 82 +++++++++---------- .../src/quasifs_inode_quasi_directory_pfs.cpp | 19 +---- .../quasifs/src/quasifs_inode_quasi_file.cpp | 6 -- 8 files changed, 45 insertions(+), 73 deletions(-) diff --git a/src/core/file_sys/hostio/host_io_win32.h b/src/core/file_sys/hostio/host_io_win32.h index cf494605e..4138868aa 100644 --- a/src/core/file_sys/hostio/host_io_win32.h +++ b/src/core/file_sys/hostio/host_io_win32.h @@ -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; diff --git a/src/core/file_sys/hostio/src/host_io_win32.cpp b/src/core/file_sys/hostio/src/host_io_win32.cpp index 946f010d7..9dc4d2637 100644 --- a/src/core/file_sys/hostio/src/host_io_win32.cpp +++ b/src/core/file_sys/hostio/src/host_io_win32.cpp @@ -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; } diff --git a/src/core/file_sys/quasifs/quasifs_inode.h b/src/core/file_sys/quasifs/quasifs_inode.h index a954e5c82..689580cab 100644 --- a/src/core/file_sys/quasifs/quasifs_inode.h +++ b/src/core/file_sys/quasifs/quasifs_inode.h @@ -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) { diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h index 2ddf5d727..c7168820e 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_directory.h @@ -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; diff --git a/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h b/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h index f1eda818b..0d0c7c4d7 100644 --- a/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h +++ b/src/core/file_sys/quasifs/quasifs_inode_quasi_file.h @@ -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; }; diff --git a/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory.cpp b/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory.cpp index 47e3802f4..ba5f20110 100644 --- a/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory.cpp +++ b/src/core/file_sys/quasifs/src/quasifs_inode_quasi_directory.cpp @@ -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(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(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(&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(static_cast(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(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(static_cast(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; } 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 db032b410..5ef9e8ca2 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 @@ -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(&tmp); - + dirent_cache_bin.insert(dirent_cache_bin.end(), dirent_ptr, dirent_ptr + tmp.d_reclen); dirent_size += tmp.d_reclen; } diff --git a/src/core/file_sys/quasifs/src/quasifs_inode_quasi_file.cpp b/src/core/file_sys/quasifs/src/quasifs_inode_quasi_file.cpp index b06781f21..e3022a25b 100644 --- a/src/core/file_sys/quasifs/src/quasifs_inode_quasi_file.cpp +++ b/src/core/file_sys/quasifs/src/quasifs_inode_quasi_file.cpp @@ -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;