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::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:
DeviceManager() = default;

View File

@ -141,7 +141,7 @@ namespace Kernel
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<size_t> read(size_t, void*, size_t) override;

View File

@ -5,12 +5,16 @@
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <kernel/API/DirectoryEntry.h>
#include <sys/types.h>
#include <time.h>
namespace Kernel
{
using namespace API;
class Inode : public BAN::RefCounted<Inode>
{
public:
@ -74,13 +78,13 @@ namespace Kernel
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::Vector<BAN::String>> read_directory_entries(size_t) { 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<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> write(size_t, const 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<void> create_file(BAN::StringView, mode_t) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); }
virtual BAN::ErrorOr<void> create_file(BAN::StringView, mode_t) { if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); ASSERT_NOT_REACHED(); }
};
}

View File

@ -71,7 +71,7 @@ namespace Kernel
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<void> set_working_directory(BAN::StringView);

View File

@ -114,19 +114,49 @@ namespace Kernel
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 (index > 0)
return result;
if (offset != 0)
{
list->entry_count = 0;
return {};
}
LockGuard _(m_lock);
TRY(result.reserve(m_devices.size() + 2));
MUST(result.emplace_back("."sv));
MUST(result.emplace_back(".."sv));
size_t needed_size = sizeof(DirectoryEntryList);
needed_size += sizeof(DirectoryEntry) + 2;
needed_size += sizeof(DirectoryEntry) + 3;
for (Device* device : m_devices)
MUST(result.emplace_back(device->name()));
return result;
needed_size += sizeof(DirectoryEntry) + device->name().size() + 1;
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,36 +291,69 @@ namespace Kernel
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())
return BAN::Error::from_errno(ENOTDIR);
uint32_t data_block_count = blocks();
if (index >= data_block_count)
return BAN::Vector<BAN::String>();
if (offset >= data_block_count)
{
list->entry_count = 0;
return {};
}
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;
TRY(block_buffer.resize(block_size));
m_fs.read_block(block_index, block_buffer.span());
BAN::Vector<BAN::String> entries;
const uint8_t* block_buffer_end = block_buffer.data() + block_size;
const uint8_t* entry_addr = block_buffer.data();
while (entry_addr < block_buffer_end)
// First determine if we have big enough list
{
auto& entry = *(Ext2::LinkedDirectoryEntry*)entry_addr;
if (entry.inode)
TRY(entries.emplace_back(BAN::StringView(entry.name, entry.name_len)));
entry_addr += entry.rec_len;
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);
}
return entries;
// 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* entry_addr = block_buffer.data();
while (entry_addr < block_buffer_end)
{
auto& entry = *(Ext2::LinkedDirectoryEntry*)entry_addr;
if (entry.inode)
{
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;
}
}
return {};
}
BAN::ErrorOr<void> Ext2Inode::create_file(BAN::StringView name, mode_t mode)

View File

@ -629,8 +629,7 @@ namespace Kernel
return ret;
}
// FIXME: This whole API has to be rewritten
BAN::ErrorOr<BAN::Vector<BAN::String>> Process::read_directory_entries(int fd)
BAN::ErrorOr<void> Process::read_next_directory_entries(int fd, DirectoryEntryList* list, size_t list_size)
{
OpenFileDescription open_fd_copy;
@ -640,7 +639,7 @@ namespace Kernel
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);
@ -648,7 +647,7 @@ namespace Kernel
open_file_description(fd).offset = open_fd_copy.offset + 1;
}
return result;
return {};
}
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> entries;
while (!(entries = TRY(Process::current().read_directory_entries(fd))).empty())
DirectoryEntryList* directory_list = (DirectoryEntryList*)kmalloc(4096);
if (directory_list == nullptr)
return BAN::Error::from_errno(ENOMEM);
while (true)
{
TRY(all_entries.reserve(all_entries.size() + entries.size()));
for (auto& entry : entries)
TRY(all_entries.push_back(entry));
TRY(Process::current().read_next_directory_entries(fd, directory_list, 4096));
if (directory_list->entry_count == 0)
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;