Kernel: Rewrite directory listing so it can be integrated to libc

This commit is contained in:
Bananymous 2023-06-10 23:13:41 +03:00
parent ee8de77a90
commit e209ca7c82
9 changed files with 135 additions and 40 deletions

View File

@ -0,0 +1,21 @@
#pragma once
#include <dirent.h>
namespace Kernel::API
{
struct DirectoryEntry
{
size_t rec_len { 0 };
struct dirent dirent;
DirectoryEntry* next() const { return (DirectoryEntry*)((uintptr_t)this + rec_len); }
};
struct DirectoryEntryList
{
size_t entry_count { 0 };
DirectoryEntry array[];
};
}

View File

@ -34,7 +34,7 @@ namespace Kernel
virtual BAN::StringView name() const override { return "device-manager"; } virtual BAN::StringView name() const override { return "device-manager"; }
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) override; virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) override;
virtual BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(size_t) override; virtual BAN::ErrorOr<void> read_next_directory_entries(off_t, DirectoryEntryList*, size_t) override;
private: private:
DeviceManager() = default; DeviceManager() = default;

View File

@ -141,7 +141,7 @@ namespace Kernel
virtual BAN::ErrorOr<BAN::String> link_target() override; virtual BAN::ErrorOr<BAN::String> link_target() override;
virtual BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(size_t) override; virtual BAN::ErrorOr<void> read_next_directory_entries(off_t, DirectoryEntryList*, size_t) override;
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) override; virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) override;
virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override; virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override;

View File

@ -5,12 +5,16 @@
#include <BAN/StringView.h> #include <BAN/StringView.h>
#include <BAN/Vector.h> #include <BAN/Vector.h>
#include <kernel/API/DirectoryEntry.h>
#include <sys/types.h> #include <sys/types.h>
#include <time.h> #include <time.h>
namespace Kernel namespace Kernel
{ {
using namespace API;
class Inode : public BAN::RefCounted<Inode> class Inode : public BAN::RefCounted<Inode>
{ {
public: public:
@ -75,7 +79,7 @@ namespace Kernel
virtual BAN::ErrorOr<BAN::String> link_target() { ASSERT_NOT_REACHED(); } virtual BAN::ErrorOr<BAN::String> link_target() { ASSERT_NOT_REACHED(); }
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); } virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode(BAN::StringView) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); }
virtual BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(size_t) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); } virtual BAN::ErrorOr<void> read_next_directory_entries(off_t, DirectoryEntryList*, size_t) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); }
virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) { if (mode().ifdir()) return BAN::Error::from_errno(EISDIR); ASSERT_NOT_REACHED(); } virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) { if (mode().ifdir()) return BAN::Error::from_errno(EISDIR); ASSERT_NOT_REACHED(); }
virtual BAN::ErrorOr<size_t> write(size_t, const void*, size_t) { if (mode().ifdir()) return BAN::Error::from_errno(EISDIR); ASSERT_NOT_REACHED(); } virtual BAN::ErrorOr<size_t> write(size_t, const void*, size_t) { if (mode().ifdir()) return BAN::Error::from_errno(EISDIR); ASSERT_NOT_REACHED(); }

View File

@ -71,7 +71,7 @@ namespace Kernel
BAN::ErrorOr<void> mount(BAN::StringView source, BAN::StringView target); BAN::ErrorOr<void> mount(BAN::StringView source, BAN::StringView target);
BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries(int); BAN::ErrorOr<void> read_next_directory_entries(int fd, DirectoryEntryList* buffer, size_t buffer_size);
BAN::ErrorOr<BAN::String> working_directory() const; BAN::ErrorOr<BAN::String> working_directory() const;
BAN::ErrorOr<void> set_working_directory(BAN::StringView); BAN::ErrorOr<void> set_working_directory(BAN::StringView);

View File

@ -114,19 +114,49 @@ namespace Kernel
return BAN::Error::from_errno(ENOENT); return BAN::Error::from_errno(ENOENT);
} }
BAN::ErrorOr<BAN::Vector<BAN::String>> DeviceManager::read_directory_entries(size_t index) BAN::ErrorOr<void> DeviceManager::read_next_directory_entries(off_t offset, DirectoryEntryList* list, size_t list_size)
{ {
BAN::Vector<BAN::String> result; if (offset != 0)
if (index > 0) {
return result; list->entry_count = 0;
return {};
}
LockGuard _(m_lock); LockGuard _(m_lock);
TRY(result.reserve(m_devices.size() + 2));
MUST(result.emplace_back("."sv)); size_t needed_size = sizeof(DirectoryEntryList);
MUST(result.emplace_back(".."sv)); needed_size += sizeof(DirectoryEntry) + 2;
needed_size += sizeof(DirectoryEntry) + 3;
for (Device* device : m_devices) for (Device* device : m_devices)
MUST(result.emplace_back(device->name())); needed_size += sizeof(DirectoryEntry) + device->name().size() + 1;
return result; if (needed_size > list_size)
return BAN::Error::from_errno(EINVAL);
DirectoryEntry* ptr = list->array;
ptr->dirent.d_ino = ino();
ptr->rec_len = sizeof(DirectoryEntry) + 2;
memcpy(ptr->dirent.d_name, ".", 2);
ptr = ptr->next();
ptr->dirent.d_ino = 69; // FIXME: store parent inode number when we implement proper RAM fs
ptr->rec_len = sizeof(DirectoryEntry) + 3;
memcpy(ptr->dirent.d_name, "..", 3);
ptr = ptr->next();
for (Device* device : m_devices)
{
ptr->dirent.d_ino = device->ino();
ptr->rec_len = sizeof(DirectoryEntry) + device->name().size() + 1;
memcpy(ptr->dirent.d_name, device->name().data(), device->name().size());
ptr->dirent.d_name[device->name().size()] = '\0';
ptr = ptr->next();
}
list->entry_count = m_devices.size() + 2;
return {};
} }

View File

@ -291,24 +291,48 @@ namespace Kernel
return n_read; return n_read;
} }
BAN::ErrorOr<BAN::Vector<BAN::String>> Ext2Inode::read_directory_entries(size_t index) BAN::ErrorOr<void> Ext2Inode::read_next_directory_entries(off_t offset, DirectoryEntryList* list, size_t list_size)
{ {
if (!mode().ifdir()) if (!mode().ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
uint32_t data_block_count = blocks(); uint32_t data_block_count = blocks();
if (index >= data_block_count) if (offset >= data_block_count)
return BAN::Vector<BAN::String>(); {
list->entry_count = 0;
return {};
}
uint32_t block_size = blksize(); uint32_t block_size = blksize();
uint32_t block_index = TRY(data_block_index(index)); uint32_t block_index = TRY(data_block_index(offset));
BAN::Vector<uint8_t> block_buffer; BAN::Vector<uint8_t> block_buffer;
TRY(block_buffer.resize(block_size)); TRY(block_buffer.resize(block_size));
m_fs.read_block(block_index, block_buffer.span()); m_fs.read_block(block_index, block_buffer.span());
BAN::Vector<BAN::String> entries; // First determine if we have big enough list
{
const uint8_t* block_buffer_end = block_buffer.data() + block_size;
const uint8_t* entry_addr = block_buffer.data();
size_t needed_size = sizeof(DirectoryEntryList);
while (entry_addr < block_buffer_end)
{
auto& entry = *(Ext2::LinkedDirectoryEntry*)entry_addr;
if (entry.inode)
needed_size += sizeof(DirectoryEntry) + entry.name_len + 1;
entry_addr += entry.rec_len;
}
if (needed_size > list_size)
return BAN::Error::from_errno(EINVAL);
}
// Second fill the list
{
DirectoryEntry* ptr = list->array;
list->entry_count = 0;
const uint8_t* block_buffer_end = block_buffer.data() + block_size; const uint8_t* block_buffer_end = block_buffer.data() + block_size;
const uint8_t* entry_addr = block_buffer.data(); const uint8_t* entry_addr = block_buffer.data();
@ -316,11 +340,20 @@ namespace Kernel
{ {
auto& entry = *(Ext2::LinkedDirectoryEntry*)entry_addr; auto& entry = *(Ext2::LinkedDirectoryEntry*)entry_addr;
if (entry.inode) if (entry.inode)
TRY(entries.emplace_back(BAN::StringView(entry.name, entry.name_len))); {
ptr->dirent.d_ino = entry.inode;
ptr->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1;
memcpy(ptr->dirent.d_name, entry.name, entry.name_len);
ptr->dirent.d_name[entry.name_len] = '\0';
ptr = ptr->next();
list->entry_count++;
}
entry_addr += entry.rec_len; entry_addr += entry.rec_len;
} }
}
return entries; return {};
} }
BAN::ErrorOr<void> Ext2Inode::create_file(BAN::StringView name, mode_t mode) BAN::ErrorOr<void> Ext2Inode::create_file(BAN::StringView name, mode_t mode)

View File

@ -629,8 +629,7 @@ namespace Kernel
return ret; return ret;
} }
// FIXME: This whole API has to be rewritten BAN::ErrorOr<void> Process::read_next_directory_entries(int fd, DirectoryEntryList* list, size_t list_size)
BAN::ErrorOr<BAN::Vector<BAN::String>> Process::read_directory_entries(int fd)
{ {
OpenFileDescription open_fd_copy; OpenFileDescription open_fd_copy;
@ -640,7 +639,7 @@ namespace Kernel
open_fd_copy = open_file_description(fd); open_fd_copy = open_file_description(fd);
} }
auto result = TRY(open_fd_copy.inode->read_directory_entries(open_fd_copy.offset)); TRY(open_fd_copy.inode->read_next_directory_entries(open_fd_copy.offset, list, list_size));
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
@ -648,7 +647,7 @@ namespace Kernel
open_file_description(fd).offset = open_fd_copy.offset + 1; open_file_description(fd).offset = open_fd_copy.offset + 1;
} }
return result; return {};
} }
BAN::ErrorOr<BAN::String> Process::working_directory() const BAN::ErrorOr<BAN::String> Process::working_directory() const

View File

@ -516,12 +516,20 @@ argument_done:
BAN::Vector<BAN::String> all_entries; BAN::Vector<BAN::String> all_entries;
BAN::Vector<BAN::String> entries; DirectoryEntryList* directory_list = (DirectoryEntryList*)kmalloc(4096);
while (!(entries = TRY(Process::current().read_directory_entries(fd))).empty()) if (directory_list == nullptr)
return BAN::Error::from_errno(ENOMEM);
while (true)
{ {
TRY(all_entries.reserve(all_entries.size() + entries.size())); TRY(Process::current().read_next_directory_entries(fd, directory_list, 4096));
for (auto& entry : entries) if (directory_list->entry_count == 0)
TRY(all_entries.push_back(entry)); break;
DirectoryEntry* current = directory_list->array;
for (size_t i = 0; i < directory_list->entry_count; i++)
{
TRY(all_entries.emplace_back(current->dirent.d_name));
current = current->next();
}
} }
BAN::String entry_prefix; BAN::String entry_prefix;