From 7c57d736c640c2c08319878cd8d5b4bb6a2fdb87 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 28 Jan 2025 17:15:11 +0200 Subject: [PATCH] Kernel/LibC: Fix dirent functions dirent functions used to fail if a directory contained more than 128 files :D --- kernel/kernel/OpenFileDescriptorSet.cpp | 7 ++++-- userspace/libraries/LibC/dirent.cpp | 30 ++++++++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index 81486da0..d246148a 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -330,8 +330,11 @@ namespace Kernel return BAN::Error::from_errno(EACCES); for (;;) { - auto ret = open_file.inode()->list_next_inodes(open_file.offset()++, list, list_len); - if (ret.is_error() && ret.error().get_error_code() == ENODATA) + auto ret = open_file.inode()->list_next_inodes(open_file.offset(), list, list_len); + if (ret.is_error() && ret.error().get_error_code() != ENODATA) + return ret; + open_file.offset()++; + if (ret.is_error()) continue; return ret; } diff --git a/userspace/libraries/LibC/dirent.cpp b/userspace/libraries/LibC/dirent.cpp index d3c43299..339a6157 100644 --- a/userspace/libraries/LibC/dirent.cpp +++ b/userspace/libraries/LibC/dirent.cpp @@ -10,9 +10,10 @@ struct __DIR int fd { -1 }; size_t entry_count { 0 }; size_t entry_index { 0 }; - // FIXME: we should probably allocate entries dynamically - // based if syscall returns ENOBUFS - dirent entries[128]; + size_t entries_size { 0 }; + dirent* entries { nullptr }; + + static constexpr size_t default_entries_size { 128 }; }; int closedir(DIR* dirp) @@ -42,10 +43,18 @@ int dirfd(DIR* dirp) DIR* fdopendir(int fd) { - DIR* dirp = (DIR*)malloc(sizeof(DIR)); + DIR* dirp = static_cast(malloc(sizeof(DIR))); if (dirp == nullptr) return nullptr; + dirp->entries = static_cast(malloc(DIR::default_entries_size * sizeof(dirent))); + dirp->entries_size = DIR::default_entries_size; + if (dirp->entries == nullptr) + { + free(dirp); + return nullptr; + } + dirp->fd = fd; dirp->entry_count = 0; dirp->entry_index = 0; @@ -73,7 +82,18 @@ struct dirent* readdir(DIR* dirp) if (dirp->entry_index < dirp->entry_count) return &dirp->entries[dirp->entry_index]; - long entry_count = syscall(SYS_READ_DIR, dirp->fd, dirp->entries, sizeof(dirp->entries) / sizeof(dirp->entries[0])); +readdir_do_syscall: + long entry_count = syscall(SYS_READ_DIR, dirp->fd, dirp->entries, dirp->entries_size); + if (entry_count == -1 && errno == ENOBUFS) + { + const size_t new_entries_size = dirp->entries_size * 2; + dirent* new_entries = static_cast(malloc(new_entries_size * sizeof(dirent))); + if (new_entries == nullptr) + return nullptr; + dirp->entries = new_entries; + dirp->entries_size = new_entries_size; + goto readdir_do_syscall; + } if (entry_count <= 0) return nullptr;