From 42c86ac541f71ccac4bec618bd83a869dd6c2152 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Wed, 12 Jul 2023 21:33:13 +0300 Subject: [PATCH] Better FS::ReadDirectory --- include/fs/archive_base.hpp | 22 ++++++++- src/core/kernel/directory_operations.cpp | 63 +++++++++++++++++++++++- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/include/fs/archive_base.hpp b/include/fs/archive_base.hpp index e1b4caa0..4bd877f0 100644 --- a/include/fs/archive_base.hpp +++ b/include/fs/archive_base.hpp @@ -116,15 +116,35 @@ struct ArchiveSession { ArchiveSession(ArchiveBase* archive, const FSPath& filePath, bool isOpen = true) : archive(archive), path(filePath), isOpen(isOpen) {} }; +struct DirectoryEntry { + std::filesystem::path path; + bool isDirectory; +}; + struct DirectorySession { ArchiveBase* archive = nullptr; // For directories which are mirrored to a specific path on the disk, this contains that path // Otherwise this is a nullopt std::optional pathOnDisk; + + // Iterators for traversing the directory in Directory::Read + std::vector entries; + size_t currentEntry; + bool isOpen; DirectorySession(ArchiveBase* archive, std::filesystem::path path, bool isOpen = true) : archive(archive), pathOnDisk(path), - isOpen(isOpen) {} + isOpen(isOpen) { + currentEntry = 0; // Start from entry 0 + + // Read all directory entries, cache them + for (auto& e : std::filesystem::directory_iterator(path)) { + DirectoryEntry entry; + entry.path = e.path(); + entry.isDirectory = std::filesystem::is_directory(e); + entries.push_back(entry); + } + } }; // Represents a file descriptor obtained from OpenFile. If the optional is nullopt, opening the file failed. diff --git a/src/core/kernel/directory_operations.cpp b/src/core/kernel/directory_operations.cpp index fe4f58f4..a1204724 100644 --- a/src/core/kernel/directory_operations.cpp +++ b/src/core/kernel/directory_operations.cpp @@ -1,3 +1,5 @@ +#include + #include "kernel.hpp" namespace DirectoryOps { @@ -21,7 +23,7 @@ void Kernel::closeDirectory(u32 messagePointer, Handle directory) { const auto p = getObject(directory, KernelObjectType::Directory); if (p == nullptr) [[unlikely]] { - Helpers::panic("Called CloseFile on non-existent file"); + Helpers::panic("Called CloseDirectory on non-existent directory"); } p->getData()->isOpen = false; @@ -34,7 +36,64 @@ void Kernel::readDirectory(u32 messagePointer, Handle directory) { const u32 outPointer = mem.read32(messagePointer + 12); logFileIO("Directory::Read (handle = %X, entry count = %d, out pointer = %08X)\n", directory, entryCount, outPointer); Helpers::panicDev("Unimplemented FsDir::Read"); + + const auto p = getObject(directory, KernelObjectType::Directory); + if (p == nullptr) [[unlikely]] { + Helpers::panic("Called ReadDirectory on non-existent directory"); + } + + DirectorySession* session = p->getData(); + if (!session->pathOnDisk.has_value()) [[unlikely]] { + Helpers::panic("Called ReadDirectory on directory that doesn't have a path on disk"); + } + + std::filesystem::path dirPath = session->pathOnDisk.value(); + + int count = 0; + while (count < entryCount && session->currentEntry < session->entries.size()) { + const auto& entry = session->entries[session->currentEntry]; + std::filesystem::path path = entry.path; + std::filesystem::path extension = path.extension(); + std::filesystem::path relative = path.lexically_relative(dirPath); + bool isDirectory = std::filesystem::is_directory(relative); + std::cout << "Relative path: " << relative << "\nIs directory: " << isDirectory << "\n"; + + std::u16string nameU16 = relative.u16string(); + std::string nameString = relative.string(); + std::string extensionString = extension.string(); + + const u32 entryPointer = outPointer + (count * 0x228); // 0x228 is the size of a single entry + u32 utfPointer = entryPointer; + u32 namePointer = entryPointer + 0x20C; + u32 extensionPointer = entryPointer + 0x216; + u32 attributePointer = entryPointer + 0x21C; + u32 sizePointer = entryPointer + 0x220; + + for (auto c : nameU16) { + mem.write16(utfPointer, u16(c)); + utfPointer += sizeof(u16); + } + mem.write16(utfPointer, 0); // Null terminate the UTF16 name + + for (auto c : nameString) { + mem.write8(namePointer, u8(c)); + namePointer += sizeof(u8); + } + mem.write8(namePointer, 0); // Null terminate 8.3 name + + for (auto c : extensionString) { + mem.write8(extensionPointer, u8(c)); + extensionPointer += sizeof(u8); + } + mem.write8(extensionPointer, 0); // Null terminate 8.3 extension + mem.write8(outPointer + 0x21A, 1); // Always 1 according to 3DBrew + + mem.write8(attributePointer, entry.isDirectory ? 1 : 0); // "Is directory" attribute + + count++; // Increment number of read directories + session->currentEntry++; // Increment index of the entry currently being read + } mem.write32(messagePointer + 4, Result::Success); - mem.write32(messagePointer + 8, 0); + mem.write32(messagePointer + 8, count); } \ No newline at end of file