From e55860eb6b773c255855302cd5564ace46e4c563 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Sun, 26 Mar 2023 04:30:57 +0300 Subject: [PATCH] Kernel: Rework processes and VFS so we don't expose inodes Everything is now done through a file descriptor. --- kernel/include/kernel/FS/Ext2.h | 16 +++-- kernel/include/kernel/FS/Inode.h | 22 ++++--- kernel/include/kernel/Process.h | 11 ++-- kernel/kernel/FS/Ext2.cpp | 85 ++++++++++++++------------ kernel/kernel/FS/Inode.cpp | 25 ++++---- kernel/kernel/FS/VirtualFileSystem.cpp | 8 +-- kernel/kernel/Font.cpp | 8 ++- kernel/kernel/Process.cpp | 68 ++++++++++++++------- kernel/kernel/Shell.cpp | 48 ++++++++++----- 9 files changed, 179 insertions(+), 112 deletions(-) diff --git a/kernel/include/kernel/FS/Ext2.h b/kernel/include/kernel/FS/Ext2.h index 44b54990..08608ef2 100644 --- a/kernel/include/kernel/FS/Ext2.h +++ b/kernel/include/kernel/FS/Ext2.h @@ -123,15 +123,22 @@ namespace Kernel class Ext2Inode : public Inode { public: + virtual ino_t ino() const override { return m_index; }; + virtual mode_t mode() const override { return m_inode.mode; } + virtual nlink_t nlink() const override { return m_inode.links_count; } virtual uid_t uid() const override { return m_inode.uid; } virtual gid_t gid() const override { return m_inode.gid; } - virtual size_t size() const override { return m_inode.size; } - - virtual mode_t mode() const override { return m_inode.mode; } + virtual off_t size() const override { return m_inode.size; } + virtual timespec atime() const override { return timespec { .tv_sec = m_inode.atime, .tv_nsec = 0 }; } + virtual timespec mtime() const override { return timespec { .tv_sec = m_inode.mtime, .tv_nsec = 0 }; } + virtual timespec ctime() const override { return timespec { .tv_sec = m_inode.ctime, .tv_nsec = 0 }; } + virtual blksize_t blksize() const override; + virtual blkcnt_t blocks() const override; virtual BAN::StringView name() const override { return m_name; } virtual BAN::ErrorOr read(size_t, void*, size_t) override; + virtual BAN::ErrorOr> read_directory_entries_impl(size_t) override; virtual BAN::ErrorOr create_file(BAN::StringView, mode_t) override; @@ -139,8 +146,7 @@ namespace Kernel virtual bool operator==(const Inode& other) const override; protected: - virtual BAN::ErrorOr>> directory_inodes_impl() override; - virtual BAN::ErrorOr> directory_find_impl(BAN::StringView) override; + virtual BAN::ErrorOr> read_directory_inode_impl(BAN::StringView) override; private: BAN::ErrorOr data_block_index(uint32_t); diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index f0001649..9b40b37f 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -5,6 +5,7 @@ #include #include +#include namespace Kernel { @@ -43,27 +44,32 @@ namespace Kernel bool ifdir() const { return mode() & Mode::IFDIR; } bool ifreg() const { return mode() & Mode::IFREG; } + virtual ino_t ino() const = 0; + virtual mode_t mode() const = 0; + virtual nlink_t nlink() const = 0; virtual uid_t uid() const = 0; virtual gid_t gid() const = 0; - virtual size_t size() const = 0; - - virtual mode_t mode() const = 0; + virtual off_t size() const = 0; + virtual timespec atime() const = 0; + virtual timespec mtime() const = 0; + virtual timespec ctime() const = 0; + virtual blksize_t blksize() const = 0; + virtual blkcnt_t blocks() const = 0; virtual BAN::StringView name() const = 0; - BAN::ErrorOr>> directory_inodes(); - BAN::ErrorOr> directory_find(BAN::StringView); + BAN::ErrorOr> read_directory_inode(BAN::StringView); + BAN::ErrorOr> read_directory_entries(size_t); virtual BAN::ErrorOr read(size_t, void*, size_t) = 0; - virtual BAN::ErrorOr create_file(BAN::StringView, mode_t) = 0; virtual Type type() const = 0; virtual bool operator==(const Inode&) const = 0; protected: - virtual BAN::ErrorOr>> directory_inodes_impl() = 0; - virtual BAN::ErrorOr> directory_find_impl(BAN::StringView) = 0; + virtual BAN::ErrorOr> read_directory_inode_impl(BAN::StringView) = 0; + virtual BAN::ErrorOr> read_directory_entries_impl(size_t) = 0; }; } \ No newline at end of file diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index e3ffe061..047b92bf 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -7,6 +7,8 @@ #include #include +#include + namespace Kernel { @@ -32,11 +34,14 @@ namespace Kernel BAN::ErrorOr read(int, void*, size_t); BAN::ErrorOr creat(BAN::StringView, mode_t); + BAN::ErrorOr fstat(int, stat*); + BAN::ErrorOr stat(BAN::StringView, stat*); + + BAN::ErrorOr> read_directory_entries(int); + BAN::String working_directory() const; BAN::ErrorOr set_working_directory(BAN::StringView); - Inode& inode_for_fd(int); - static BAN::RefPtr current() { return Thread::current()->process(); } private: @@ -51,8 +56,6 @@ namespace Kernel BAN::String path; size_t offset = 0; uint8_t flags = 0; - - BAN::ErrorOr read(void*, size_t); }; BAN::ErrorOr validate_fd(int); diff --git a/kernel/kernel/FS/Ext2.cpp b/kernel/kernel/FS/Ext2.cpp index e7d8b230..6e9f2de9 100644 --- a/kernel/kernel/FS/Ext2.cpp +++ b/kernel/kernel/FS/Ext2.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #define EXT2_DEBUG_PRINT 0 @@ -150,6 +151,16 @@ namespace Kernel } + blksize_t Ext2Inode::blksize() const + { + return m_fs.block_size(); + } + + blkcnt_t Ext2Inode::blocks() const + { + return m_inode.blocks / (2 << m_fs.superblock().log_block_size); + } + BAN::ErrorOr> Ext2Inode::create(Ext2FS& fs, uint32_t inode_inode, BAN::StringView name) { BAN::Vector block_buffer; @@ -273,6 +284,38 @@ namespace Kernel return n_read; } + BAN::ErrorOr> Ext2Inode::read_directory_entries_impl(size_t index) + { + if (!ifdir()) + return BAN::Error::from_errno(ENOTDIR); + + uint32_t data_block_count = blocks(); + if (index >= data_block_count) + return BAN::Vector(); + + uint32_t block_size = blksize(); + uint32_t block_index = TRY(data_block_index(index)); + + BAN::Vector block_buffer; + TRY(block_buffer.resize(block_size)); + + m_fs.read_block(block_index, block_buffer.span()); + + BAN::Vector 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) + { + 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; + } + + return entries; + } + BAN::ErrorOr Ext2Inode::create_file(BAN::StringView name, mode_t mode) { if (!ifdir()) @@ -285,7 +328,7 @@ namespace Kernel BAN::Vector block_buffer; TRY(block_buffer.resize(block_size)); - auto error_or = directory_find_impl(name); + auto error_or = read_directory_inode_impl(name); if (!error_or.is_error()) return BAN::Error::from_errno(EEXISTS); if (error_or.error().get_error_code() != ENOENT) @@ -358,7 +401,7 @@ namespace Kernel return {}; } - BAN::ErrorOr> Ext2Inode::directory_find_impl(BAN::StringView file_name) + BAN::ErrorOr> Ext2Inode::read_directory_inode_impl(BAN::StringView file_name) { if (!ifdir()) return BAN::Error::from_errno(ENOTDIR); @@ -367,7 +410,7 @@ namespace Kernel BAN::Vector block_buffer; TRY(block_buffer.resize(block_size)); - uint32_t data_block_count = m_inode.blocks / (2 << m_fs.superblock().log_block_size); + uint32_t data_block_count = blocks(); for (uint32_t i = 0; i < data_block_count; i++) { @@ -390,42 +433,6 @@ namespace Kernel return BAN::Error::from_errno(ENOENT); } - BAN::ErrorOr>> Ext2Inode::directory_inodes_impl() - { - if (!ifdir()) - return BAN::Error::from_errno(ENOTDIR); - - uint32_t block_size = m_fs.block_size(); - BAN::Vector block_buffer; - TRY(block_buffer.resize(block_size)); - - uint32_t data_block_count = m_inode.blocks / (2 << m_fs.superblock().log_block_size); - - BAN::Vector> inodes; - - for (uint32_t i = 0; i < data_block_count; i++) - { - uint32_t block_index = TRY(data_block_index(i)); - m_fs.read_block(block_index, block_buffer.span()); - - 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) - { - const auto& entry = *(const Ext2::LinkedDirectoryEntry*)entry_addr; - if (entry.inode) - { - BAN::StringView entry_name(entry.name, entry.name_len); - auto inode = TRY(Ext2Inode::create(m_fs, entry.inode, entry_name)); - TRY(inodes.push_back(inode)); - } - entry_addr += entry.rec_len; - } - } - - return inodes; - } - bool Ext2Inode::operator==(const Inode& other) const { if (type() != other.type()) diff --git a/kernel/kernel/FS/Inode.cpp b/kernel/kernel/FS/Inode.cpp index 361891b0..bbe01a99 100644 --- a/kernel/kernel/FS/Inode.cpp +++ b/kernel/kernel/FS/Inode.cpp @@ -5,23 +5,22 @@ namespace Kernel { - - BAN::ErrorOr>> Inode::directory_inodes() - { - for (const auto& mount : VirtualFileSystem::get().mount_points()) - if (*mount.inode == *this) - return mount.target->root_inode()->directory_inodes_impl(); - return directory_inodes_impl(); - } - - BAN::ErrorOr> Inode::directory_find(BAN::StringView name) + BAN::ErrorOr> Inode::read_directory_inode(BAN::StringView name) { if (name == ".."sv) - return directory_find_impl(name); + return read_directory_inode_impl(name); for (const auto& mount : VirtualFileSystem::get().mount_points()) if (*mount.inode == *this) - return mount.target->root_inode()->directory_find_impl(name); - return directory_find_impl(name); + return mount.target->root_inode()->read_directory_inode_impl(name); + return read_directory_inode_impl(name); + } + + BAN::ErrorOr> Inode::read_directory_entries(size_t index) + { + for (const auto& mount : VirtualFileSystem::get().mount_points()) + if (*mount.inode == *this) + return mount.target->root_inode()->read_directory_entries_impl(index); + return read_directory_entries_impl(index); } } \ No newline at end of file diff --git a/kernel/kernel/FS/VirtualFileSystem.cpp b/kernel/kernel/FS/VirtualFileSystem.cpp index 95d35b61..22a0f5ea 100644 --- a/kernel/kernel/FS/VirtualFileSystem.cpp +++ b/kernel/kernel/FS/VirtualFileSystem.cpp @@ -117,11 +117,9 @@ namespace Kernel BAN::ErrorOr VirtualFileSystem::mount_test() { - auto mount = TRY(root_inode()->directory_find("mnt"sv)); + auto mount = TRY(root_inode()->read_directory_inode("mnt"sv)); if (!mount->ifdir()) return BAN::Error::from_errno(ENOTDIR); - if (TRY(mount->directory_inodes()).size() > 2) - return BAN::Error::from_errno(ENOTEMPTY); for (auto* controller : m_storage_controllers) { @@ -159,7 +157,7 @@ namespace Kernel } else if (path_parts[i] == ".."sv) { - inode = TRY(inode->directory_find(path_parts[i])); + inode = TRY(inode->read_directory_inode(path_parts[i])); path_parts.remove(i); if (i > 0) { @@ -169,7 +167,7 @@ namespace Kernel } else { - inode = TRY(inode->directory_find(path_parts[i])); + inode = TRY(inode->read_directory_inode(path_parts[i])); i++; } } diff --git a/kernel/kernel/Font.cpp b/kernel/kernel/Font.cpp index c8ee092c..c165c6d5 100644 --- a/kernel/kernel/Font.cpp +++ b/kernel/kernel/Font.cpp @@ -40,10 +40,12 @@ namespace Kernel int fd = TRY(Process::current()->open(path, O_RDONLY)); BAN::ScopeGuard _([fd] { MUST(Process::current()->close(fd)); }); - size_t file_size = Process::current()->inode_for_fd(fd).size(); + stat st; + TRY(Process::current()->fstat(fd, &st)); + BAN::Vector file_data; - TRY(file_data.resize(file_size)); - TRY(Process::current()->read(fd, file_data.data(), file_size)); + TRY(file_data.resize(st.st_size)); + TRY(Process::current()->read(fd, file_data.data(), st.st_size)); if (file_data.size() < 4) return BAN::Error::from_c_string("Font file is too small"); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index e28827a6..3af306f6 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -36,7 +36,10 @@ namespace Kernel void Process::on_thread_exit(Thread& thread) { LockGuard _(m_lock); - (void)thread; + dprintln("thread {} exit", thread.tid()); + for (size_t i = 0; i < m_threads.size(); i++) + if (m_threads[i].ptr() == &thread) + m_threads.remove(i); } BAN::ErrorOr Process::open(BAN::StringView path, int flags) @@ -63,7 +66,6 @@ namespace Kernel BAN::ErrorOr Process::close(int fd) { LockGuard _(m_lock); - TRY(validate_fd(fd)); auto& open_file_description = this->open_file_description(fd); open_file_description.inode = nullptr; @@ -73,19 +75,18 @@ namespace Kernel BAN::ErrorOr Process::read(int fd, void* buffer, size_t count) { LockGuard _(m_lock); - 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)); + auto& open_fd = open_file_description(fd); + if (!(open_fd.flags & O_RDONLY)) + return BAN::Error::from_errno(EBADF); + size_t n_read = TRY(open_fd.inode->read(open_fd.offset, buffer, count)); + open_fd.offset += n_read; return n_read; } BAN::ErrorOr Process::creat(BAN::StringView path, mode_t mode) { LockGuard _(m_lock); - auto absolute_path = TRY(absolute_path_of(path)); while (absolute_path.sv().back() != '/') absolute_path.pop_back(); @@ -96,12 +97,47 @@ namespace Kernel return {}; } - Inode& Process::inode_for_fd(int fd) + BAN::ErrorOr Process::fstat(int fd, struct stat* out) { LockGuard _(m_lock); - MUST(validate_fd(fd)); - return *open_file_description(fd).inode; + TRY(validate_fd(fd)); + const auto& open_fd = open_file_description(fd); + + out->st_dev = 0; + out->st_ino = open_fd.inode->ino(); + out->st_mode = open_fd.inode->mode(); + out->st_nlink = open_fd.inode->nlink(); + out->st_uid = open_fd.inode->uid(); + out->st_gid = open_fd.inode->gid(); + out->st_rdev = 0; + out->st_size = open_fd.inode->size(); + out->st_atim = open_fd.inode->atime(); + out->st_mtim = open_fd.inode->mtime(); + out->st_ctim = open_fd.inode->ctime(); + out->st_blksize = open_fd.inode->blksize(); + out->st_blocks = open_fd.inode->blocks(); + + return {}; + } + + BAN::ErrorOr Process::stat(BAN::StringView path, struct stat* out) + { + LockGuard _(m_lock); + int fd = TRY(open(path, O_RDONLY)); + auto ret = fstat(fd, out); + MUST(close(fd)); + return ret; + } + + BAN::ErrorOr> Process::read_directory_entries(int fd) + { + LockGuard _(m_lock); + TRY(validate_fd(fd)); + auto& open_fd = open_file_description(fd); + auto result = TRY(open_fd.inode->read_directory_entries(open_fd.offset)); + open_fd.offset++; + return result; } BAN::String Process::working_directory() const @@ -142,19 +178,9 @@ namespace Kernel return absolute_path; } - BAN::ErrorOr Process::OpenFileDescription::read(void* buffer, size_t count) - { - if (!(flags & O_RDONLY)) - return BAN::Error::from_errno(EBADF); - size_t n_read = TRY(inode->read(offset, buffer, count)); - offset += n_read; - return n_read; - } - BAN::ErrorOr Process::validate_fd(int fd) { LockGuard _(m_lock); - if (fd < 0 || m_open_files.size() <= (size_t)fd || !m_open_files[fd].inode) return BAN::Error::from_errno(EBADF); return {}; diff --git a/kernel/kernel/Shell.cpp b/kernel/kernel/Shell.cpp index 17550dd4..9b707adb 100644 --- a/kernel/kernel/Shell.cpp +++ b/kernel/kernel/Shell.cpp @@ -356,14 +356,6 @@ argument_done: if (arguments.size() > 2) return BAN::Error::from_c_string("usage: 'ls [path]'"); - BAN::String path = (arguments.size() == 2) ? arguments[1] : Process::current()->working_directory(); - - int fd = TRY(Process::current()->open(path, O_RDONLY)); - 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 = [](mode_t mode) { static char buffer[11] {}; @@ -380,12 +372,40 @@ argument_done: return (const char*)buffer; }; - for (auto& inode : inodes) - if (inode->ifdir()) - TTY_PRINTLN(" {} {7} \e[34m{}\e[m", mode_string(inode->mode()), inode->size(), inode->name()); - for (auto& inode : inodes) - if (!inode->ifdir()) - TTY_PRINTLN(" {} {7} {}", mode_string(inode->mode()), inode->size(), inode->name()); + BAN::String path = (arguments.size() == 2) ? arguments[1] : Process::current()->working_directory(); + + int fd = TRY(Process::current()->open(path, O_RDONLY)); + BAN::ScopeGuard _([fd] { MUST(Process::current()->close(fd)); }); + + BAN::Vector all_entries; + + BAN::Vector entries; + while (!(entries = TRY(Process::current()->read_directory_entries(fd))).empty()) + { + TRY(all_entries.reserve(all_entries.size() + entries.size())); + for (auto& entry : entries) + TRY(all_entries.push_back(entry)); + } + + BAN::String entry_prefix; + TRY(entry_prefix.append(path)); + TRY(entry_prefix.push_back('/')); + for (const auto& entry : all_entries) + { + stat st; + + BAN::String entry_path; + TRY(entry_path.append(entry_prefix)); + TRY(entry_path.append(entry)); + TRY(Process::current()->stat(entry_path, &st)); + + const char* color = + (st.st_mode & Inode::Mode::IFDIR) ? "34" : + (st.st_mode & Inode::Mode::IXUSR) ? "32" : + ""; + + TTY_PRINTLN(" {} {7} \e[{}m{}\e[m", mode_string(st.st_mode), st.st_size, color, entry); + } } else if (arguments.front() == "cat") {