diff --git a/src/core/file_sys/directories/base_directory.cpp b/src/core/file_sys/directories/base_directory.cpp index c709da6a2..75f67577c 100644 --- a/src/core/file_sys/directories/base_directory.cpp +++ b/src/core/file_sys/directories/base_directory.cpp @@ -5,6 +5,7 @@ #include "common/singleton.h" #include "core/file_sys/directories/base_directory.h" #include "core/file_sys/fs.h" +#include "core/libraries/kernel/orbis_error.h" namespace Core::Directories { @@ -12,4 +13,35 @@ BaseDirectory::BaseDirectory() = default; BaseDirectory::~BaseDirectory() = default; +s64 BaseDirectory::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) { + s64 bytes_read = 0; + for (s32 i = 0; i < iovcnt; i++) { + const s64 result = read(iov[i].iov_base, iov[i].iov_len); + if (result < 0) { + return result; + } + bytes_read += result; + } + return bytes_read; +} + +s64 BaseDirectory::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { + const u64 old_file_pointer = file_offset; + file_offset = offset; + const s64 bytes_read = readv(iov, iovcnt); + file_offset = old_file_pointer; + return bytes_read; +} + +s64 BaseDirectory::lseek(s64 offset, s32 whence) { + + s64 file_offset_new = ((0 == whence) * offset) + ((1 == whence) * (file_offset + offset)) + + ((2 == whence) * (directory_size + offset)); + if (file_offset_new < 0) + return ORBIS_KERNEL_ERROR_EINVAL; + + file_offset = file_offset_new; + return file_offset; +} + } // namespace Core::Directories \ No newline at end of file diff --git a/src/core/file_sys/directories/base_directory.h b/src/core/file_sys/directories/base_directory.h index b412865a2..832b8ac40 100644 --- a/src/core/file_sys/directories/base_directory.h +++ b/src/core/file_sys/directories/base_directory.h @@ -19,6 +19,17 @@ struct OrbisKernelDirent; namespace Core::Directories { class BaseDirectory { +protected: + static inline u32 fileno_pool{10}; + + static u32 next_fileno() { + return ++fileno_pool; + } + + s64 file_offset = 0; + u64 directory_size = 0; + std::vector dirent_cache_bin{}; + public: explicit BaseDirectory(); @@ -28,13 +39,8 @@ public: return ORBIS_KERNEL_ERROR_EBADF; } - virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) { - return ORBIS_KERNEL_ERROR_EBADF; - } - - virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { - return ORBIS_KERNEL_ERROR_EBADF; - } + virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt); + virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset); virtual s64 write(const void* buf, u64 nbytes) { return ORBIS_KERNEL_ERROR_EBADF; @@ -48,9 +54,7 @@ public: return ORBIS_KERNEL_ERROR_EBADF; } - virtual s64 lseek(s64 offset, s32 whence) { - return ORBIS_KERNEL_ERROR_EBADF; - } + virtual s64 lseek(s64 offset, s32 whence); virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* stat) { return ORBIS_KERNEL_ERROR_EBADF; diff --git a/src/core/file_sys/directories/normal_directory.cpp b/src/core/file_sys/directories/normal_directory.cpp index a7d76074a..3ed7c9492 100644 --- a/src/core/file_sys/directories/normal_directory.cpp +++ b/src/core/file_sys/directories/normal_directory.cpp @@ -15,111 +15,30 @@ std::shared_ptr NormalDirectory::Create(std::string_view guest_di std::make_shared(guest_directory)); } -NormalDirectory::NormalDirectory(std::string_view guest_directory) { - auto* mnt = Common::Singleton::Instance(); - - static s32 fileno = 0; - mnt->IterateDirectory(guest_directory, [this](const auto& ent_path, const auto ent_is_file) { - auto& dirent = dirents.emplace_back(); - dirent.d_fileno = ++fileno; - dirent.d_type = (ent_is_file ? 8 : 4); - strncpy(dirent.d_name, ent_path.filename().string().data(), MAX_LENGTH + 1); - dirent.d_namlen = ent_path.filename().string().size(); - - // Calculate the appropriate length for this dirent. - // Account for the null terminator in d_name too. - dirent.d_reclen = Common::AlignUp(sizeof(dirent.d_fileno) + sizeof(dirent.d_type) + - sizeof(dirent.d_namlen) + sizeof(dirent.d_reclen) + - (dirent.d_namlen + 1), - 4); - - directory_size += dirent.d_reclen; - }); - - // The last entry of a normal directory should have d_reclen covering the remaining data. - // Since the dirents of a folder are constant by this point, we can modify the last dirent - // before creating the emulated file buffer. - const u64 filler_count = Common::AlignUp(directory_size, DIRECTORY_ALIGNMENT) - directory_size; - dirents[dirents.size() - 1].d_reclen += filler_count; - - // Reading from standard directories seems to be based around file pointer logic. - // Keep an internal buffer representing the raw contents of this file descriptor, - // then emulate the various read functions with that. - directory_size = Common::AlignUp(directory_size, DIRECTORY_ALIGNMENT); - data_buffer.reserve(directory_size); - memset(data_buffer.data(), 0, directory_size); - - u8* current_dirent = data_buffer.data(); - for (const NormalDirectoryDirent& dirent : dirents) { - NormalDirectoryDirent* dirent_to_write = - reinterpret_cast(current_dirent); - dirent_to_write->d_fileno = dirent.d_fileno; - - // Using size d_namlen + 1 to account for null terminator. - strncpy(dirent_to_write->d_name, dirent.d_name, dirent.d_namlen + 1); - dirent_to_write->d_namlen = dirent.d_namlen; - dirent_to_write->d_reclen = dirent.d_reclen; - dirent_to_write->d_type = dirent.d_type; - - current_dirent += dirent.d_reclen; - } +NormalDirectory::NormalDirectory(std::string_view guest_directory) + : guest_directory(guest_directory) { + RebuildDirents(); } s64 NormalDirectory::read(void* buf, u64 nbytes) { - // Nothing left to read. - if (file_offset >= directory_size) { - return ORBIS_OK; - } + RebuildDirents(); - const s64 remaining_data = directory_size - file_offset; - const s64 bytes = nbytes > remaining_data ? remaining_data : nbytes; + // data is contiguous. read goes like any regular file would: start at offset, read n bytes + // output is always aligned up to 512 bytes with 0s + // offset - classic. however at the end of read any unused (exceeding dirent buffer size) buffer + // space will be left untouched + // reclen always sums up to end of current alignment - std::memcpy(buf, data_buffer.data() + file_offset, bytes); + s64 bytes_available = this->dirent_cache_bin.size() - file_offset; + if (bytes_available <= 0) + return 0; + bytes_available = std::min(bytes_available, static_cast(nbytes)); - file_offset += bytes; - return bytes; -} + // data + memcpy(buf, this->dirent_cache_bin.data() + file_offset, bytes_available); -s64 NormalDirectory::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) { - s64 bytes_read = 0; - for (s32 i = 0; i < iovcnt; i++) { - const s64 result = read(iov[i].iov_base, iov[i].iov_len); - if (result < 0) { - return result; - } - bytes_read += result; - } - return bytes_read; -} - -s64 NormalDirectory::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, - s64 offset) { - const u64 old_file_pointer = file_offset; - file_offset = offset; - const s64 bytes_read = readv(iov, iovcnt); - file_offset = old_file_pointer; - return bytes_read; -} - -s64 NormalDirectory::lseek(s64 offset, s32 whence) { - switch (whence) { - case 0: { - file_offset = offset; - break; - } - case 1: { - file_offset += offset; - break; - } - case 2: { - file_offset = directory_size + offset; - break; - } - default: { - UNREACHABLE_MSG("lseek with unknown whence {}", whence); - } - } - return file_offset; + file_offset += bytes_available; + return bytes_available; } s32 NormalDirectory::fstat(Libraries::Kernel::OrbisKernelStat* stat) { @@ -131,10 +50,110 @@ s32 NormalDirectory::fstat(Libraries::Kernel::OrbisKernelStat* stat) { } s64 NormalDirectory::getdents(void* buf, u64 nbytes, s64* basep) { - if (basep != nullptr) { + RebuildDirents(); + + if (basep) *basep = file_offset; + + // same as others, we just don't need a variable + if (file_offset >= directory_size) + return 0; + + s64 bytes_written = 0; + s64 working_offset = file_offset; + s64 dirent_buffer_offset = 0; + s64 aligned_count = Common::AlignDown(nbytes, 512); + + const u8* dirent_buffer = this->dirent_cache_bin.data(); + while (dirent_buffer_offset < this->dirent_cache_bin.size()) { + const u8* normal_dirent_ptr = dirent_buffer + dirent_buffer_offset; + const NormalDirectoryDirent* normal_dirent = + reinterpret_cast(normal_dirent_ptr); + auto d_reclen = normal_dirent->d_reclen; + + // bad, incomplete or OOB entry + if (normal_dirent->d_namlen == 0) + break; + + if (working_offset >= d_reclen) { + dirent_buffer_offset += d_reclen; + working_offset -= d_reclen; + continue; + } + + if ((bytes_written + d_reclen) > aligned_count) + // dirents are aligned to the last full one + break; + + memcpy(static_cast(buf) + bytes_written, normal_dirent_ptr + working_offset, + d_reclen - working_offset); + bytes_written += d_reclen - working_offset; + dirent_buffer_offset += d_reclen; + working_offset = 0; } - // read behaves identically to getdents for normal directories. - return read(buf, nbytes); + + file_offset += bytes_written; + return bytes_written; } + +void NormalDirectory::RebuildDirents() { + // regenerate only when target wants to read contents again + // no reason for testing - read is always raw and dirents get processed on the go + if (previous_file_offset == file_offset) + return; + previous_file_offset = file_offset; + + constexpr u32 dirent_meta_size = + sizeof(NormalDirectoryDirent::d_fileno) + sizeof(NormalDirectoryDirent::d_type) + + sizeof(NormalDirectoryDirent::d_namlen) + sizeof(NormalDirectoryDirent::d_reclen); + + u64 next_ceiling = 0; + u64 dirent_offset = 0; + u64 last_reclen_offset = 4; + dirent_cache_bin.clear(); + dirent_cache_bin.reserve(512); + + auto* mnt = Common::Singleton::Instance(); + + mnt->IterateDirectory( + guest_directory, [this, &next_ceiling, &dirent_offset, &last_reclen_offset]( + const std::filesystem::path& ent_path, const bool ent_is_file) { + NormalDirectoryDirent tmp{}; + std::string leaf(ent_path.filename().string()); + + // prepare dirent + tmp.d_fileno = BaseDirectory::next_fileno(); + tmp.d_namlen = leaf.size(); + strncpy(tmp.d_name, leaf.data(), tmp.d_namlen + 1); + tmp.d_type = (ent_is_file ? 0100000 : 0040000) >> 12; + tmp.d_reclen = Common::AlignUp(dirent_meta_size + tmp.d_namlen + 1, 4); + + // 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); + } + + // 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; + }); + + // 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 + directory_size = next_ceiling; +} + } // namespace Core::Directories \ No newline at end of file diff --git a/src/core/file_sys/directories/normal_directory.h b/src/core/file_sys/directories/normal_directory.h index 70e52f581..4fc84cd2a 100644 --- a/src/core/file_sys/directories/normal_directory.h +++ b/src/core/file_sys/directories/normal_directory.h @@ -19,27 +19,23 @@ public: ~NormalDirectory() override = default; virtual s64 read(void* buf, u64 nbytes) override; - virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override; - virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, - s64 offset) override; - virtual s64 lseek(s64 offset, s32 whence) override; virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* stat) override; virtual s64 getdents(void* buf, u64 nbytes, s64* basep) override; private: - static constexpr s32 MAX_LENGTH = 255; - static constexpr s64 DIRECTORY_ALIGNMENT = 0x200; +#pragma pack(push, 1) struct NormalDirectoryDirent { u32 d_fileno; u16 d_reclen; u8 d_type; u8 d_namlen; - char d_name[MAX_LENGTH + 1]; + char d_name[256]; }; +#pragma pack(pop) - u64 directory_size = 0; - s64 file_offset = 0; - std::vector data_buffer; - std::vector dirents; + std::string_view guest_directory{}; + s64 previous_file_offset = -1; + + void RebuildDirents(void); }; } // namespace Core::Directories diff --git a/src/core/file_sys/directories/pfs_directory.cpp b/src/core/file_sys/directories/pfs_directory.cpp index fbd97c019..38ceaf345 100644 --- a/src/core/file_sys/directories/pfs_directory.cpp +++ b/src/core/file_sys/directories/pfs_directory.cpp @@ -15,77 +15,49 @@ std::shared_ptr PfsDirectory::Create(std::string_view guest_direc } PfsDirectory::PfsDirectory(std::string_view guest_directory) { + constexpr u32 dirent_meta_size = + sizeof(PfsDirectoryDirent::d_fileno) + sizeof(PfsDirectoryDirent::d_type) + + sizeof(PfsDirectoryDirent::d_namlen) + sizeof(PfsDirectoryDirent::d_reclen); + + dirent_cache_bin.reserve(512); + auto* mnt = Common::Singleton::Instance(); - static s32 fileno = 0; - mnt->IterateDirectory(guest_directory, [this](const auto& ent_path, const auto ent_is_file) { - auto& dirent = dirents.emplace_back(); - dirent.d_fileno = ++fileno; - dirent.d_type = (ent_is_file ? 8 : 4); - strncpy(dirent.d_name, ent_path.filename().string().data(), MAX_LENGTH + 1); - dirent.d_namlen = ent_path.filename().string().size(); + mnt->IterateDirectory( + guest_directory, [this](const std::filesystem::path& ent_path, const bool ent_is_file) { + PfsDirectoryDirent tmp{}; + std::string leaf(ent_path.filename().string()); - // Calculate the appropriate length for this dirent. - // Account for the null terminator in d_name too. - dirent.d_reclen = Common::AlignUp(sizeof(dirent.d_fileno) + sizeof(dirent.d_type) + - sizeof(dirent.d_namlen) + sizeof(dirent.d_reclen) + - (dirent.d_namlen + 1), - 8); + tmp.d_fileno = BaseDirectory::next_fileno(); + tmp.d_namlen = leaf.size(); + strncpy(tmp.d_name, leaf.data(), tmp.d_namlen + 1); + tmp.d_type = ent_is_file ? 2 : 4; + tmp.d_reclen = Common::AlignUp(dirent_meta_size + tmp.d_namlen + 1, 8); + auto dirent_ptr = reinterpret_cast(&tmp); - // To handle some obscure dirents_index behavior, - // keep track of the "actual" length of this directory. - directory_content_size += dirent.d_reclen; - }); + dirent_cache_bin.insert(dirent_cache_bin.end(), dirent_ptr, dirent_ptr + tmp.d_reclen); + }); - directory_size = Common::AlignUp(directory_content_size, DIRECTORY_ALIGNMENT); + directory_size = Common::AlignUp(dirent_cache_bin.size(), 0x10000); } s64 PfsDirectory::read(void* buf, u64 nbytes) { - if (dirents_index >= dirents.size()) { - if (dirents_index < directory_content_size) { - // We need to find the appropriate dirents_index to start from. - s64 data_to_skip = dirents_index; - u64 corrected_index = 0; - while (data_to_skip > 0) { - const auto dirent = dirents[corrected_index++]; - data_to_skip -= dirent.d_reclen; - } - dirents_index = corrected_index; - } else { - // Nothing left to read. - return ORBIS_OK; - } + s64 bytes_available = this->dirent_cache_bin.size() - file_offset; + if (bytes_available <= 0) + return 0; + + bytes_available = std::min(bytes_available, static_cast(nbytes)); + memcpy(buf, this->dirent_cache_bin.data() + file_offset, bytes_available); + + s64 to_fill = + (std::min(directory_size, static_cast(nbytes))) - bytes_available - file_offset; + if (to_fill < 0) { + LOG_ERROR(Kernel_Fs, "Dirent may have leaked {} bytes", -to_fill); + return -to_fill + bytes_available; } - - s64 bytes_remaining = nbytes > directory_size ? directory_size : nbytes; - // read on PfsDirectories will always return the maximum possible value. - const u64 bytes_written = bytes_remaining; - memset(buf, 0, bytes_remaining); - - char* current_dirent = static_cast(buf); - PfsDirectoryDirent dirent = dirents[dirents_index]; - while (bytes_remaining > dirent.d_reclen) { - PfsDirectoryDirent* dirent_to_write = reinterpret_cast(current_dirent); - dirent_to_write->d_fileno = dirent.d_fileno; - - // Using size d_namlen + 1 to account for null terminator. - strncpy(dirent_to_write->d_name, dirent.d_name, dirent.d_namlen + 1); - dirent_to_write->d_namlen = dirent.d_namlen; - dirent_to_write->d_reclen = dirent.d_reclen; - dirent_to_write->d_type = dirent.d_type; - - current_dirent += dirent.d_reclen; - bytes_remaining -= dirent.d_reclen; - - if (dirents_index == dirents.size() - 1) { - // Currently at the last dirent, so break out of the loop. - dirents_index++; - break; - } - dirent = dirents[++dirents_index]; - } - - return bytes_written; + memset(static_cast(buf) + bytes_available, 0, to_fill); + file_offset += to_fill + bytes_available; + return to_fill + bytes_available; } s64 PfsDirectory::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) { @@ -101,62 +73,13 @@ s64 PfsDirectory::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovc } s64 PfsDirectory::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) { - const u64 old_dirent_index = dirents_index; - dirents_index = 0; - s64 data_to_skip = offset; - // If offset is part-way through one dirent, that dirent is skipped. - while (data_to_skip > 0) { - const auto dirent = dirents[dirents_index++]; - data_to_skip -= dirent.d_reclen; - if (dirents_index == dirents.size()) { - // We've reached the end of the dirents, nothing more can be skipped. - break; - } - } - + const u64 old_file_pointer = file_offset; + file_offset = offset; const s64 bytes_read = readv(iov, iovcnt); - dirents_index = old_dirent_index; + file_offset = old_file_pointer; return bytes_read; } -s64 PfsDirectory::lseek(s64 offset, s32 whence) { - switch (whence) { - // Seek start - case 0: { - dirents_index = 0; - } - case 1: { - // There aren't any dirents left to pass through. - if (dirents_index >= dirents.size()) { - dirents_index = dirents_index + offset; - break; - } - s64 data_to_skip = offset; - while (data_to_skip > 0) { - const auto dirent = dirents[dirents_index++]; - data_to_skip -= dirent.d_reclen; - if (dirents_index == dirents.size()) { - // We've passed through all file dirents. - // Set dirents_index to directory_size + remaining_offset instead. - dirents_index = directory_content_size + data_to_skip; - break; - } - } - break; - } - case 2: { - // Seems like real hardware gives up on tracking dirents_index if you go this route. - dirents_index = directory_size + offset; - break; - } - default: { - UNREACHABLE_MSG("lseek with unknown whence {}", whence); - } - } - - return dirents_index; -} - s32 PfsDirectory::fstat(Libraries::Kernel::OrbisKernelStat* stat) { stat->st_mode = 0000777u | 0040000u; stat->st_size = directory_size; @@ -166,55 +89,58 @@ s32 PfsDirectory::fstat(Libraries::Kernel::OrbisKernelStat* stat) { } s64 PfsDirectory::getdents(void* buf, u64 nbytes, s64* basep) { - // basep is set at the start of the function. - if (basep != nullptr) { - *basep = dirents_index; - } + if (basep) + *basep = file_offset; - if (dirents_index >= dirents.size()) { - if (dirents_index < directory_content_size) { - // We need to find the appropriate dirents_index to start from. - s64 data_to_skip = dirents_index; - u64 corrected_index = 0; - while (data_to_skip > 0) { - const auto dirent = dirents[corrected_index++]; - data_to_skip -= dirent.d_reclen; - } - dirents_index = corrected_index; - } else { - // Nothing left to read. - return ORBIS_OK; - } - } - - s64 bytes_remaining = nbytes > directory_size ? directory_size : nbytes; - memset(buf, 0, bytes_remaining); + // same as others, we just don't need a variable + if (file_offset >= directory_size) + return 0; u64 bytes_written = 0; - char* current_dirent = static_cast(buf); - // getdents has to convert pfs dirents to normal dirents - PfsDirectoryDirent dirent = dirents[dirents_index]; - while (bytes_remaining > dirent.d_reclen) { - NormalDirectoryDirent* dirent_to_write = - reinterpret_cast(current_dirent); - dirent_to_write->d_fileno = dirent.d_fileno; - strncpy(dirent_to_write->d_name, dirent.d_name, dirent.d_namlen + 1); - dirent_to_write->d_namlen = dirent.d_namlen; - dirent_to_write->d_reclen = dirent.d_reclen; - dirent_to_write->d_type = dirent.d_type; + u64 starting_offset = 0; + u64 buffer_position = 0; + while (buffer_position < this->dirent_cache_bin.size()) { + const PfsDirectoryDirent* pfs_dirent = + reinterpret_cast(this->dirent_cache_bin.data() + buffer_position); - current_dirent += dirent.d_reclen; - bytes_remaining -= dirent.d_reclen; - bytes_written += dirent.d_reclen; - - if (dirents_index == dirents.size() - 1) { - // Currently at the last dirent, so set dirents_index appropriately and break. - dirents_index = directory_size; + // bad, incomplete or OOB entry + if (pfs_dirent->d_namlen == 0) break; + + if (starting_offset < file_offset) { + // reading starts from the nearest full dirent + starting_offset += pfs_dirent->d_reclen; + buffer_position = bytes_written + starting_offset; + continue; } - dirent = dirents[++dirents_index]; + + if ((bytes_written + pfs_dirent->d_reclen) > nbytes) + // 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; + + // reclen for both is the same despite difference in var sizes, extra 0s are padded after + // the name + NormalDirectoryDirent 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 == 2) ? 8 : 4; + normal_dirent.d_namlen = pfs_dirent->d_namlen; + memcpy(normal_dirent.d_name, pfs_dirent->d_name, pfs_dirent->d_namlen); + + memcpy(static_cast(buf) + bytes_written, &normal_dirent, normal_dirent.d_reclen); + bytes_written += normal_dirent.d_reclen; + buffer_position = bytes_written + starting_offset; } + file_offset = (buffer_position >= this->dirent_cache_bin.size()) + ? directory_size + : (file_offset + bytes_written); return bytes_written; } } // namespace Core::Directories \ No newline at end of file diff --git a/src/core/file_sys/directories/pfs_directory.h b/src/core/file_sys/directories/pfs_directory.h index 8f3e8d1f5..23b7e1eb0 100644 --- a/src/core/file_sys/directories/pfs_directory.h +++ b/src/core/file_sys/directories/pfs_directory.h @@ -22,32 +22,28 @@ public: virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override; virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override; - virtual s64 lseek(s64 offset, s32 whence) override; virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* stat) override; virtual s64 getdents(void* buf, u64 nbytes, s64* basep) override; private: - static constexpr s32 MAX_LENGTH = 255; - static constexpr s32 DIRECTORY_ALIGNMENT = 0x10000; +#pragma pack(push, 1) struct PfsDirectoryDirent { u32 d_fileno; u32 d_type; u32 d_namlen; u32 d_reclen; - char d_name[MAX_LENGTH + 1]; + char d_name[256]; }; +#pragma pack(pop) +#pragma pack(push, 1) struct NormalDirectoryDirent { u32 d_fileno; u16 d_reclen; u8 d_type; u8 d_namlen; - char d_name[MAX_LENGTH + 1]; + char d_name[256]; }; - - u64 directory_size = 0; - u64 directory_content_size = 0; - s64 dirents_index = 0; - std::vector dirents; +#pragma pack(pop) }; } // namespace Core::Directories