Kernel: Rewrite directory listing so it can be integrated to libc
This commit is contained in:
@@ -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 {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user