Kernel: Rework filesystem reading

We now read from a filesystem to user provided buffer.

Read sizes are determined by read call.

You should now get file descriptors and do reading through Process::current()
This commit is contained in:
Bananymous 2023-03-17 21:16:22 +02:00
parent ceb53533be
commit 1a26a318a4
11 changed files with 359 additions and 113 deletions

View File

@ -131,12 +131,13 @@ namespace Kernel
virtual BAN::StringView name() const override { return m_name; } virtual BAN::StringView name() const override { return m_name; }
virtual BAN::ErrorOr<BAN::Vector<uint8_t>> read_all() override; virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override;
virtual BAN::ErrorOr<BAN::Vector<BAN::RefPtr<Inode>>> directory_inodes() override; virtual BAN::ErrorOr<BAN::Vector<BAN::RefPtr<Inode>>> directory_inodes() override;
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> directory_find(BAN::StringView) override; virtual BAN::ErrorOr<BAN::RefPtr<Inode>> directory_find(BAN::StringView) override;
private: private:
BAN::ErrorOr<void> for_each_block(BAN::Function<BAN::ErrorOr<bool>(const BAN::Vector<uint8_t>&)>&); using block_callback_t = BAN::ErrorOr<bool>(*)(const BAN::Vector<uint8_t>&, void*);
BAN::ErrorOr<void> for_each_block(block_callback_t, void*);
private: private:
Ext2Inode() {} Ext2Inode() {}

View File

@ -36,6 +36,8 @@ namespace Kernel
}; };
public: public:
virtual ~Inode() {}
bool ifdir() const { return mode().IFDIR; } bool ifdir() const { return mode().IFDIR; }
bool ifreg() const { return mode().IFREG; } bool ifreg() const { return mode().IFREG; }
@ -47,7 +49,7 @@ namespace Kernel
virtual BAN::StringView name() const = 0; virtual BAN::StringView name() const = 0;
virtual BAN::ErrorOr<BAN::Vector<uint8_t>> read_all() = 0; virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) = 0;
virtual BAN::ErrorOr<BAN::Vector<BAN::RefPtr<Inode>>> directory_inodes() = 0; virtual BAN::ErrorOr<BAN::Vector<BAN::RefPtr<Inode>>> directory_inodes() = 0;
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> directory_find(BAN::StringView) = 0; virtual BAN::ErrorOr<BAN::RefPtr<Inode>> directory_find(BAN::StringView) = 0;
}; };

View File

@ -15,19 +15,22 @@ namespace Kernel
static VirtualFileSystem& get(); static VirtualFileSystem& get();
virtual ~VirtualFileSystem() {}; virtual ~VirtualFileSystem() {};
virtual const BAN::RefPtr<Inode> root_inode() const override; virtual const BAN::RefPtr<Inode> root_inode() const override { return m_root_inode; }
void close_inode(BAN::StringView); struct File
{
BAN::ErrorOr<BAN::RefPtr<Inode>> from_absolute_path(BAN::StringView); BAN::RefPtr<Inode> inode;
BAN::String canonical_path;
};
BAN::ErrorOr<File> file_from_absolute_path(BAN::StringView);
private: private:
VirtualFileSystem() = default; VirtualFileSystem() = default;
BAN::ErrorOr<void> initialize_impl(); BAN::ErrorOr<void> initialize_impl();
private: private:
BAN::HashMap<BAN::String, BAN::RefPtr<Inode>> m_open_inodes; BAN::RefPtr<Inode> m_root_inode;
BAN::Vector<StorageController*> m_storage_controllers; BAN::Vector<StorageController*> m_storage_controllers;
}; };
} }

View File

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <BAN/String.h> #include <BAN/String.h>
#include <BAN/StringView.h>
#include <BAN/Vector.h> #include <BAN/Vector.h>
#include <kernel/FS/Inode.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
namespace Kernel namespace Kernel
@ -24,12 +26,39 @@ namespace Kernel
pid_t pid() const { return m_pid; } pid_t pid() const { return m_pid; }
BAN::ErrorOr<int> open(BAN::StringView, int);
BAN::ErrorOr<void> close(int);
BAN::ErrorOr<size_t> read(int, void*, size_t);
BAN::StringView working_directory() const { return m_working_directory; }
BAN::ErrorOr<void> set_working_directory(BAN::StringView);
Inode& inode_for_fd(int);
static BAN::RefPtr<Process> current() { return Thread::current()->process(); } static BAN::RefPtr<Process> current() { return Thread::current()->process(); }
private: private:
Process(pid_t pid) : m_pid(pid) {} Process(pid_t pid) : m_pid(pid) {}
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;
private: private:
struct OpenFileDescription
{
BAN::RefPtr<Inode> inode;
BAN::String path;
size_t offset = 0;
uint8_t flags = 0;
BAN::ErrorOr<size_t> read(void*, size_t);
};
BAN::ErrorOr<void> validate_fd(int);
OpenFileDescription& open_file_description(int);
BAN::ErrorOr<int> get_free_fd();
BAN::Vector<OpenFileDescription> m_open_files;
pid_t m_pid = 0; pid_t m_pid = 0;
BAN::String m_working_directory; BAN::String m_working_directory;
BAN::Vector<BAN::RefPtr<Thread>> m_threads; BAN::Vector<BAN::RefPtr<Thread>> m_threads;

View File

@ -13,7 +13,7 @@ namespace Kernel
public: public:
Shell(TTY*); Shell(TTY*);
Shell(const Shell&) = delete; Shell(const Shell&) = delete;
void set_prompt(BAN::StringView); BAN::ErrorOr<void> set_prompt(BAN::StringView);
void run(); void run();
private: private:
@ -21,11 +21,13 @@ namespace Kernel
BAN::Vector<BAN::String> parse_arguments(BAN::StringView) const; BAN::Vector<BAN::String> parse_arguments(BAN::StringView) const;
BAN::ErrorOr<void> process_command(const BAN::Vector<BAN::String>&); BAN::ErrorOr<void> process_command(const BAN::Vector<BAN::String>&);
void key_event_callback(Input::KeyEvent); void key_event_callback(Input::KeyEvent);
BAN::ErrorOr<void> update_prompt();
private: private:
TTY* m_tty; TTY* m_tty;
BAN::Vector<BAN::String> m_old_buffer; BAN::Vector<BAN::String> m_old_buffer;
BAN::Vector<BAN::String> m_buffer; BAN::Vector<BAN::String> m_buffer;
BAN::String m_prompt_string;
BAN::String m_prompt; BAN::String m_prompt;
uint32_t m_prompt_length = 0; uint32_t m_prompt_length = 0;

View File

@ -138,7 +138,7 @@ namespace Kernel
} }
BAN::ErrorOr<void> Ext2Inode::for_each_block(BAN::Function<BAN::ErrorOr<bool>(const BAN::Vector<uint8_t>&)>& func) BAN::ErrorOr<void> Ext2Inode::for_each_block(block_callback_t callback, void* callback_data)
{ {
uint32_t data_blocks_left = m_inode.blocks / (2 << m_fs->superblock().log_block_size); uint32_t data_blocks_left = m_inode.blocks / (2 << m_fs->superblock().log_block_size);
uint32_t block_array_block_count = (1024 << m_fs->superblock().log_block_size) / sizeof(uint32_t); uint32_t block_array_block_count = (1024 << m_fs->superblock().log_block_size) / sizeof(uint32_t);
@ -150,7 +150,7 @@ namespace Kernel
continue; continue;
auto block_data = TRY(m_fs->read_block(m_inode.block[i])); auto block_data = TRY(m_fs->read_block(m_inode.block[i]));
if (!TRY(func(block_data))) if (!TRY(callback(block_data, callback_data)))
return {}; return {};
if (--data_blocks_left == 0) if (--data_blocks_left == 0)
return {}; return {};
@ -166,7 +166,7 @@ namespace Kernel
if (block == 0) if (block == 0)
continue; continue;
auto block_data = TRY(m_fs->read_block(block)); auto block_data = TRY(m_fs->read_block(block));
if (!TRY(func(block_data))) if (!TRY(callback(block_data, callback_data)))
return {}; return {};
if (--data_blocks_left == 0) if (--data_blocks_left == 0)
return {}; return {};
@ -187,7 +187,7 @@ namespace Kernel
if (block == 0) if (block == 0)
continue; continue;
auto block_data = TRY(m_fs->read_block(block)); auto block_data = TRY(m_fs->read_block(block));
if (!TRY(func(block_data))) if (!TRY(callback(block_data, callback_data)))
return {}; return {};
if (--data_blocks_left == 0) if (--data_blocks_left == 0)
return {}; return {};
@ -213,7 +213,7 @@ namespace Kernel
if (block == 0) if (block == 0)
continue; continue;
auto block_data = TRY(m_fs->read_block(block)); auto block_data = TRY(m_fs->read_block(block));
if (!TRY(func(block_data))) if (!TRY(callback(block_data, callback_data)))
return {}; return {};
if (--data_blocks_left == 0) if (--data_blocks_left == 0)
return {}; return {};
@ -225,32 +225,63 @@ namespace Kernel
return BAN::Error::from_c_string("Inode did not contain enough blocks"); return BAN::Error::from_c_string("Inode did not contain enough blocks");
} }
BAN::ErrorOr<BAN::Vector<uint8_t>> Ext2Inode::read_all() BAN::ErrorOr<size_t> Ext2Inode::read(size_t offset, void* buffer, size_t count)
{ {
if (ifdir()) if (ifdir())
return BAN::Error::from_errno(EISDIR); return BAN::Error::from_errno(EISDIR);
BAN::Vector<uint8_t> data_buffer; struct read_info
TRY(data_buffer.resize(m_inode.size)); {
size_t file_current_offset;
size_t file_start_offset;
size_t file_bytes_left;
uint8_t* out_byte_buffer;
size_t out_bytes_read;
size_t out_byte_buffer_size;
};
uint32_t bytes_done = 0; read_info info;
uint32_t bytes_left = m_inode.size; info.file_current_offset = 0;
info.file_start_offset = offset;
info.file_bytes_left = m_inode.size;
info.out_byte_buffer = (uint8_t*)buffer;
info.out_bytes_read = 0;
info.out_byte_buffer_size = count;
BAN::Function<BAN::ErrorOr<bool>(const BAN::Vector<uint8_t>&)> read_func( block_callback_t read_func =
[&](const BAN::Vector<uint8_t>& block_data) [](const BAN::Vector<uint8_t>& block_data, void* info_) -> BAN::ErrorOr<bool>
{ {
uint32_t to_copy = BAN::Math::min<uint32_t>(block_data.size(), bytes_left); read_info& info = *(read_info*)info_;
memcpy(data_buffer.data() + bytes_done, block_data.data(), to_copy);
bytes_done += to_copy;
bytes_left -= to_copy;
return bytes_left > 0;
}
);
TRY(for_each_block(read_func)); size_t block_size = BAN::Math::min<size_t>(block_data.size(), info.file_bytes_left);
ASSERT(bytes_left == 0);
return data_buffer; // Skip blocks before 'offset'
if (info.file_current_offset + block_size <= info.file_start_offset)
{
info.file_current_offset += block_size;
info.file_bytes_left -= block_size;
return info.file_bytes_left > 0;
}
size_t read_offset = 0;
if (info.file_current_offset < info.file_start_offset)
read_offset = info.file_start_offset - info.file_current_offset;
size_t to_read = BAN::Math::min<size_t>(block_size - read_offset, info.out_byte_buffer_size - info.out_bytes_read);
memcpy(info.out_byte_buffer + info.out_bytes_read, block_data.data() + read_offset, to_read);
info.out_bytes_read += to_read;
if (info.out_bytes_read >= info.out_byte_buffer_size)
return false;
info.file_current_offset += block_size;
info.file_bytes_left -= block_size;
return info.file_bytes_left > 0;
};
TRY(for_each_block(read_func, &info));
return info.out_bytes_read;
} }
BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::directory_find(BAN::StringView file_name) BAN::ErrorOr<BAN::RefPtr<Inode>> Ext2Inode::directory_find(BAN::StringView file_name)
@ -258,33 +289,45 @@ namespace Kernel
if (!ifdir()) if (!ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
BAN::RefPtr<Inode> result; struct search_info
BAN::Function<BAN::ErrorOr<bool>(const BAN::Vector<uint8_t>&)> function( {
[&](const BAN::Vector<uint8_t>& block_data) -> BAN::ErrorOr<bool> BAN::StringView file_name;
BAN::RefPtr<Inode> result;
Ext2FS* fs;
};
search_info info;
info.file_name = file_name;
info.result = {};
info.fs = m_fs;
block_callback_t function =
[](const BAN::Vector<uint8_t>& block_data, void* info_) -> BAN::ErrorOr<bool>
{ {
search_info& info = *(search_info*)info_;
uintptr_t block_data_end = (uintptr_t)block_data.data() + block_data.size(); uintptr_t block_data_end = (uintptr_t)block_data.data() + block_data.size();
uintptr_t entry_addr = (uintptr_t)block_data.data(); uintptr_t entry_addr = (uintptr_t)block_data.data();
while (entry_addr < block_data_end) while (entry_addr < block_data_end)
{ {
Ext2::LinkedDirectoryEntry* entry = (Ext2::LinkedDirectoryEntry*)entry_addr; Ext2::LinkedDirectoryEntry* entry = (Ext2::LinkedDirectoryEntry*)entry_addr;
BAN::StringView entry_name = BAN::StringView(entry->name, entry->name_len); BAN::StringView entry_name = BAN::StringView(entry->name, entry->name_len);
if (entry->inode && file_name == entry_name) if (entry->inode && info.file_name == entry_name)
{ {
Ext2Inode* inode = new Ext2Inode(m_fs, TRY(m_fs->read_inode(entry->inode)), entry_name); Ext2Inode* inode = new Ext2Inode(info.fs, TRY(info.fs->read_inode(entry->inode)), entry_name);
if (inode == nullptr) if (inode == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
result = BAN::RefPtr<Inode>::adopt(inode); info.result = BAN::RefPtr<Inode>::adopt(inode);
return false; return false;
} }
entry_addr += entry->rec_len; entry_addr += entry->rec_len;
} }
return true; return true;
} };
);
TRY(for_each_block(function)); TRY(for_each_block(function, &info));
if (result) if (info.result)
return result; return info.result;
return BAN::Error::from_errno(ENOENT); return BAN::Error::from_errno(ENOENT);
} }
@ -293,10 +336,21 @@ namespace Kernel
if (!ifdir()) if (!ifdir())
return BAN::Error::from_errno(ENOTDIR); return BAN::Error::from_errno(ENOTDIR);
BAN::Vector<BAN::RefPtr<Inode>> inodes; struct directory_info
BAN::Function<BAN::ErrorOr<bool>(const BAN::Vector<uint8_t>&)> function( {
[&](const BAN::Vector<uint8_t>& block_data) -> BAN::ErrorOr<bool> BAN::Vector<BAN::RefPtr<Inode>> inodes;
Ext2FS* fs;
};
directory_info info;
info.inodes = {};
info.fs = m_fs;
block_callback_t function =
[](const BAN::Vector<uint8_t>& block_data, void* info_) -> BAN::ErrorOr<bool>
{ {
directory_info& info = *(directory_info*)info_;
uintptr_t block_data_end = (uintptr_t)block_data.data() + block_data.size(); uintptr_t block_data_end = (uintptr_t)block_data.data() + block_data.size();
uintptr_t entry_addr = (uintptr_t)block_data.data(); uintptr_t entry_addr = (uintptr_t)block_data.data();
while (entry_addr < block_data_end) while (entry_addr < block_data_end)
@ -305,22 +359,21 @@ namespace Kernel
if (entry->inode) if (entry->inode)
{ {
BAN::StringView entry_name = BAN::StringView(entry->name, entry->name_len); BAN::StringView entry_name = BAN::StringView(entry->name, entry->name_len);
Ext2::Inode current_inode = TRY(m_fs->read_inode(entry->inode)); Ext2::Inode current_inode = TRY(info.fs->read_inode(entry->inode));
Ext2Inode* inode = new Ext2Inode(m_fs, BAN::move(current_inode), entry_name); Ext2Inode* inode = new Ext2Inode(info.fs, BAN::move(current_inode), entry_name);
if (inode == nullptr) if (inode == nullptr)
return BAN::Error::from_errno(ENOMEM); return BAN::Error::from_errno(ENOMEM);
TRY(inodes.push_back(BAN::RefPtr<Inode>::adopt(inode))); TRY(info.inodes.push_back(BAN::RefPtr<Inode>::adopt(inode)));
} }
entry_addr += entry->rec_len; entry_addr += entry->rec_len;
} }
return true; return true;
} };
);
TRY(for_each_block(function)); TRY(for_each_block(function, &info));
return inodes; return info.inodes;
} }
BAN::ErrorOr<Ext2FS*> Ext2FS::create(StorageDevice::Partition& partition) BAN::ErrorOr<Ext2FS*> Ext2FS::create(StorageDevice::Partition& partition)

View File

@ -103,7 +103,7 @@ namespace Kernel
else else
// FIXME: We leave a dangling pointer to ext2fs. This might be okay since // FIXME: We leave a dangling pointer to ext2fs. This might be okay since
// root fs sould probably be always mounted // root fs sould probably be always mounted
TRY(m_open_inodes.insert("/"sv, ext2fs_or_error.release_value()->root_inode())); m_root_inode = ext2fs_or_error.value()->root_inode();
} }
} }
} }
@ -115,40 +115,52 @@ namespace Kernel
return {}; return {};
} }
const BAN::RefPtr<Inode> VirtualFileSystem::root_inode() const BAN::ErrorOr<VirtualFileSystem::File> VirtualFileSystem::file_from_absolute_path(BAN::StringView path)
{
if (!m_open_inodes.contains("/"sv))
return nullptr;
return m_open_inodes["/"sv];
}
void VirtualFileSystem::close_inode(BAN::StringView path)
{
ASSERT(m_open_inodes.contains(path));
// Delete the cached inode, if we are the only one holding a reference to it
if (m_open_inodes[path]->ref_count() == 1)
m_open_inodes.remove(path);
}
BAN::ErrorOr<BAN::RefPtr<Inode>> VirtualFileSystem::from_absolute_path(BAN::StringView path)
{ {
ASSERT(path.front() == '/'); ASSERT(path.front() == '/');
if (m_open_inodes.contains(path))
return m_open_inodes[path];
auto inode = root_inode(); auto inode = root_inode();
if (!inode) if (!inode)
return BAN::Error::from_c_string("No root inode available"); return BAN::Error::from_c_string("No root inode available");
auto path_parts = TRY(path.split('/')); auto path_parts = TRY(path.split('/'));
for (BAN::StringView part : path_parts)
inode = TRY(inode->directory_find(part));
TRY(m_open_inodes.insert(path, inode));
return inode; for (size_t i = 0; i < path_parts.size();)
{
if (path_parts[i] == "."sv)
{
path_parts.remove(i);
}
else if (path_parts[i] == ".."sv)
{
inode = TRY(inode->directory_find(path_parts[i]));
path_parts.remove(i);
if (i > 0)
{
path_parts.remove(i - 1);
i--;
}
}
else
{
inode = TRY(inode->directory_find(path_parts[i]));
i++;
}
}
File file;
file.inode = inode;
for (const auto& part : path_parts)
{
TRY(file.canonical_path.push_back('/'));
TRY(file.canonical_path.append(part));
}
if (file.canonical_path.empty())
TRY(file.canonical_path.push_back('/'));
return file;
} }
} }

View File

@ -1,6 +1,9 @@
#include <BAN/UTF8.h> #include <BAN/UTF8.h>
#include <BAN/ScopeGuard.h>
#include <kernel/Font.h> #include <kernel/Font.h>
#include <kernel/FS/VirtualFileSystem.h> #include <kernel/Process.h>
#include <fcntl.h>
#define PSF1_MODE_512 0x01 #define PSF1_MODE_512 0x01
#define PSF1_MODE_HASTAB 0x02 #define PSF1_MODE_HASTAB 0x02
@ -25,9 +28,13 @@ namespace Kernel
BAN::ErrorOr<Font> Font::load(BAN::StringView path) BAN::ErrorOr<Font> Font::load(BAN::StringView path)
{ {
auto inode = TRY(VirtualFileSystem::get().from_absolute_path(path)); int fd = TRY(Process::current()->open(path, O_RDONLY));
BAN::ScopeGuard _([fd] { MUST(Process::current()->close(fd)); });
auto file_data = TRY(inode->read_all()); size_t file_size = Process::current()->inode_for_fd(fd).size();
BAN::Vector<uint8_t> file_data;
TRY(file_data.resize(file_size));
TRY(Process::current()->read(fd, file_data.data(), file_size));
if (file_data.size() < 4) if (file_data.size() < 4)
return BAN::Error::from_c_string("Font file is too small"); return BAN::Error::from_c_string("Font file is too small");

View File

@ -1,6 +1,9 @@
#include <BAN/StringView.h> #include <BAN/StringView.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
#include <kernel/FS/VirtualFileSystem.h>
#include <fcntl.h>
namespace Kernel namespace Kernel
{ {
@ -9,8 +12,8 @@ namespace Kernel
{ {
static pid_t next_pid = 1; static pid_t next_pid = 1;
auto process = TRY(BAN::RefPtr<Process>::create(next_pid++)); auto process = TRY(BAN::RefPtr<Process>::create(next_pid++));
TRY(process->m_working_directory.push_back('/'));
TRY(process->add_thread(entry, data)); TRY(process->add_thread(entry, data));
TRY(process->m_working_directory.append("/"sv));
return process; return process;
} }
@ -24,14 +27,112 @@ namespace Kernel
return res; return res;
} }
dprintln("add thread {} to process {}", thread->tid(), pid());
return {}; return {};
} }
void Process::on_thread_exit(Thread& thread) void Process::on_thread_exit(Thread& thread)
{ {
dprintln("thread {} exited from process", thread.tid(), pid()); (void)thread;
}
BAN::ErrorOr<int> Process::open(BAN::StringView path, int flags)
{
if (flags != O_RDONLY)
return BAN::Error::from_errno(ENOTSUP);
BAN::String absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
int fd = TRY(get_free_fd());
auto& open_file_description = m_open_files[fd];
open_file_description.inode = file.inode;
open_file_description.path = BAN::move(file.canonical_path);
open_file_description.offset = 0;
open_file_description.flags = flags;
return fd;
}
BAN::ErrorOr<void> Process::close(int fd)
{
TRY(validate_fd(fd));
auto& open_file_description = this->open_file_description(fd);
open_file_description.inode = nullptr;
return {};
}
BAN::ErrorOr<size_t> Process::read(int fd, void* buffer, size_t count)
{
TRY(validate_fd(fd));
auto& open_file_description = this->open_file_description(fd);
if (open_file_description.offset >= open_file_description.inode->size())
return 0;
size_t n_read = TRY(open_file_description.read(buffer, count));
return n_read;
}
Inode& Process::inode_for_fd(int fd)
{
MUST(validate_fd(fd));
return *open_file_description(fd).inode;
}
BAN::ErrorOr<void> Process::set_working_directory(BAN::StringView path)
{
BAN::String absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(absolute_path));
if (!file.inode->ifdir())
return BAN::Error::from_errno(ENOTDIR);
m_working_directory = BAN::move(file.canonical_path);
return {};
}
BAN::ErrorOr<BAN::String> Process::absolute_path_of(BAN::StringView path) const
{
if (path.empty())
return m_working_directory;
BAN::String absolute_path;
if (path.front() != '/')
{
TRY(absolute_path.append(m_working_directory));
if (m_working_directory.sv().back() != '/')
TRY(absolute_path.push_back('/'));
}
TRY(absolute_path.append(path));
return absolute_path;
}
BAN::ErrorOr<size_t> Process::OpenFileDescription::read(void* buffer, size_t count)
{
size_t n_read = TRY(inode->read(offset, buffer, count));
offset += n_read;
return n_read;
}
BAN::ErrorOr<void> Process::validate_fd(int fd)
{
if (fd < 0 || m_open_files.size() <= (size_t)fd || !m_open_files[fd].inode)
return BAN::Error::from_errno(EBADF);
return {};
}
Process::OpenFileDescription& Process::open_file_description(int fd)
{
MUST(validate_fd(fd));
return m_open_files[fd];
}
BAN::ErrorOr<int> Process::get_free_fd()
{
for (size_t fd = 0; fd < m_open_files.size(); fd++)
if (!m_open_files[fd].inode)
return fd;
TRY(m_open_files.push_back({}));
return m_open_files.size() - 1;
} }
} }

View File

@ -1,16 +1,17 @@
#include <BAN/Math.h> #include <BAN/Math.h>
#include <BAN/ScopeGuard.h>
#include <BAN/StringView.h> #include <BAN/StringView.h>
#include <BAN/Vector.h> #include <BAN/Vector.h>
#include <kernel/CPUID.h> #include <kernel/CPUID.h>
#include <kernel/Input.h> #include <kernel/Input.h>
#include <kernel/IO.h> #include <kernel/IO.h>
#include <kernel/PIT.h> #include <kernel/PIT.h>
#include <kernel/PCI.h>
#include <kernel/Process.h> #include <kernel/Process.h>
#include <kernel/RTC.h> #include <kernel/RTC.h>
#include <kernel/Shell.h> #include <kernel/Shell.h>
#include <kernel/FS/VirtualFileSystem.h> #include <fcntl.h>
#include <ctype.h> #include <ctype.h>
#define TTY_PRINT(...) Formatter::print([this](char c) { m_tty->putchar(c); }, __VA_ARGS__) #define TTY_PRINT(...) Formatter::print([this](char c) { m_tty->putchar(c); }, __VA_ARGS__)
@ -20,38 +21,62 @@ namespace Kernel
{ {
using namespace BAN; using namespace BAN;
static auto s_default_prompt = "\\[\e[32m\\]user\\[\e[m\\]# "sv; static auto s_default_prompt = "\\[\e[32m\\]user\\[\e[m\\]:\\[\e[34m\\]\\w\\[\e[m\\]# "sv;
Shell::Shell(TTY* tty) Shell::Shell(TTY* tty)
: m_tty(tty) : m_tty(tty)
{ {
Input::register_key_event_callback({ &Shell::key_event_callback, this }); Input::register_key_event_callback({ &Shell::key_event_callback, this });
set_prompt(s_default_prompt); MUST(set_prompt(s_default_prompt));
MUST(m_buffer.push_back(""sv)); MUST(m_buffer.push_back(""sv));
} }
void Shell::set_prompt(StringView prompt) BAN::ErrorOr<void> Shell::set_prompt(StringView prompt)
{
m_prompt_string = prompt;
TRY(update_prompt());
return {};
}
BAN::ErrorOr<void> Shell::update_prompt()
{ {
m_prompt_length = 0; m_prompt_length = 0;
m_prompt = String(); m_prompt = String();
bool skipping = false; bool skipping = false;
for (size_t i = 0; i < prompt.size(); i++) for (size_t i = 0; i < m_prompt_string.size(); i++)
{ {
if (i < prompt.size() - 1 && prompt[i] == '\\') if (i < m_prompt_string.size() - 1 && m_prompt_string[i] == '\\')
{ {
if (prompt[i + 1] == '[') switch (m_prompt_string[i + 1])
skipping = true; {
if (prompt[i + 1] == ']') case '[':
skipping = false; skipping = true;
break;
case ']':
skipping = false;
break;
case 'w':
{
auto working_directory = Process::current()->working_directory();
TRY(m_prompt.append(working_directory));
m_prompt_length += working_directory.size();
break;
}
default:
dprintln("unknown escape character '{}' in shell prompt", m_prompt_string[i + 1]);
break;
}
i++; i++;
continue; continue;
} }
MUST(m_prompt.push_back(prompt[i])); TRY(m_prompt.push_back(m_prompt_string[i]));
if (!skipping) if (!skipping)
m_prompt_length++; m_prompt_length++;
} }
return {};
} }
void Shell::run() void Shell::run()
@ -276,12 +301,13 @@ argument_done:
if (arguments.size() > 2) if (arguments.size() > 2)
return BAN::Error::from_c_string("usage: 'ls [path]'"); return BAN::Error::from_c_string("usage: 'ls [path]'");
BAN::StringView path = (arguments.size() == 2) ? arguments[1].sv() : "/"; BAN::StringView path = (arguments.size() == 2) ? arguments[1].sv() : Process::current()->working_directory();
if (path.front() != '/')
return BAN::Error::from_c_string("ls currently works only with absolute paths");
auto directory = TRY(VirtualFileSystem::get().from_absolute_path(path)); int fd = TRY(Process::current()->open(path, O_RDONLY));
auto inodes = TRY(directory->directory_inodes()); BAN::ScopeGuard _([fd] { MUST(Process::current()->close(fd)); });
auto& directory = Process::current()->inode_for_fd(fd);
auto inodes = TRY(directory.directory_inodes());
auto mode_string = [](Inode::Mode mode) auto mode_string = [](Inode::Mode mode)
{ {
@ -299,7 +325,6 @@ argument_done:
return (const char*)buffer; return (const char*)buffer;
}; };
TTY_PRINTLN("{}", path);
for (auto& inode : inodes) for (auto& inode : inodes)
if (inode->ifdir()) if (inode->ifdir())
TTY_PRINTLN(" {} {7} \e[34m{}\e[m", mode_string(inode->mode()), inode->size(), inode->name()); TTY_PRINTLN(" {} {7} \e[34m{}\e[m", mode_string(inode->mode()), inode->size(), inode->name());
@ -312,9 +337,26 @@ argument_done:
if (arguments.size() != 2) if (arguments.size() != 2)
return BAN::Error::from_c_string("usage: 'cat path'"); return BAN::Error::from_c_string("usage: 'cat path'");
auto file = TRY(VirtualFileSystem::get().from_absolute_path(arguments[1])); int fd = TRY(Process::current()->open(arguments[1], O_RDONLY));
auto data = TRY(file->read_all()); BAN::ScopeGuard _([fd] { MUST(Process::current()->close(fd)); });
TTY_PRINTLN("{}", BAN::StringView((const char*)data.data(), data.size()));
char buffer[1024] {};
while (true)
{
size_t n_read = TRY(Process::current()->read(fd, buffer, sizeof(buffer)));
if (n_read == 0)
break;
TTY_PRINT("{}", BAN::StringView(buffer, n_read));
}
TTY_PRINTLN("");
}
else if (arguments.front() == "cd")
{
if (arguments.size() > 2)
return BAN::Error::from_c_string("usage 'cd path'");
BAN::StringView path = arguments.size() == 2 ? arguments[1].sv() : "/"sv;
TRY(Process::current()->set_working_directory(path));
TRY(update_prompt());
} }
else if (arguments.front() == "loadfont") else if (arguments.front() == "loadfont")
{ {

View File

@ -196,12 +196,6 @@ void init2(void* tty1_ptr)
MUST(VirtualFileSystem::initialize()); MUST(VirtualFileSystem::initialize());
auto font_or_error = Font::load("/usr/share/fonts/zap-ext-vga16.psf");
if (font_or_error.is_error())
dprintln("{}", font_or_error.error());
else
tty1->set_font(font_or_error.release_value());
MUST(Process::create_kernel( MUST(Process::create_kernel(
[](void* tty1) [](void* tty1)
{ {