forked from Bananymous/banan-os
Kernel: Rewrite directory listing so it can be integrated to libc
This commit is contained in:
parent
ee8de77a90
commit
e209ca7c82
|
@ -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[];
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(); }
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue