From e85f9ac6a135dd62ddd43fc4aa0c9aabcc6d71ff Mon Sep 17 00:00:00 2001 From: Bananymous Date: Wed, 25 Oct 2023 19:37:04 +0300 Subject: [PATCH] Kernel: Implement Ext2 directory creation --- kernel/include/kernel/FS/Ext2/Inode.h | 3 + kernel/kernel/FS/Ext2/Inode.cpp | 115 +++++++++++++++++++------- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/kernel/include/kernel/FS/Ext2/Inode.h b/kernel/include/kernel/FS/Ext2/Inode.h index 943eeb8132..14ba10ed24 100644 --- a/kernel/include/kernel/FS/Ext2/Inode.h +++ b/kernel/include/kernel/FS/Ext2/Inode.h @@ -31,6 +31,7 @@ namespace Kernel virtual BAN::ErrorOr> find_inode_impl(BAN::StringView) override; virtual BAN::ErrorOr list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override; virtual BAN::ErrorOr create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override; + virtual BAN::ErrorOr create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override; virtual BAN::ErrorOr link_target_impl() override; @@ -42,6 +43,8 @@ namespace Kernel private: uint32_t fs_block_of_data_block_index(uint32_t data_block_index); + BAN::ErrorOr link_inode_to_directory(Ext2Inode&, BAN::StringView name); + BAN::ErrorOr allocate_new_block(); BAN::ErrorOr sync(); diff --git a/kernel/kernel/FS/Ext2/Inode.cpp b/kernel/kernel/FS/Ext2/Inode.cpp index 13ad3e0529..332619ef27 100644 --- a/kernel/kernel/FS/Ext2/Inode.cpp +++ b/kernel/kernel/FS/Ext2/Inode.cpp @@ -317,7 +317,86 @@ namespace Kernel return {}; } + static bool mode_has_valid_type(mode_t mode) + { + switch (mode & Inode::Mode::TYPE_MASK) + { + case Inode::Mode::IFIFO: return true; + case Inode::Mode::IFCHR: return true; + case Inode::Mode::IFDIR: return true; + case Inode::Mode::IFBLK: return true; + case Inode::Mode::IFREG: return true; + case Inode::Mode::IFLNK: return true; + case Inode::Mode::IFSOCK: return true; + } + return false; + } + + static Ext2::Inode initialize_new_inode_info(mode_t mode, uid_t uid, gid_t gid) + { + ASSERT(mode_has_valid_type(mode)); + + timespec current_time = SystemTimer::get().real_time(); + return Ext2::Inode + { + .mode = (uint16_t)mode, + .uid = (uint16_t)uid, + .size = 0, + .atime = (uint32_t)current_time.tv_sec, + .ctime = (uint32_t)current_time.tv_sec, + .mtime = (uint32_t)current_time.tv_sec, + .dtime = 0, + .gid = (uint16_t)gid, + .links_count = 0, + .blocks = 0, + .flags = 0, + .osd1 = 0, + .block = {}, + .generation = 0, + .file_acl = 0, + .dir_acl = 0, + .faddr = 0, + .osd2 = {} + }; + } + BAN::ErrorOr Ext2Inode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid) + { + // FIXME: handle errors + + ASSERT(this->mode().ifdir()); + + if (!(Mode(mode).ifreg())) + return BAN::Error::from_errno(ENOTSUP); + + const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid))); + + auto inode = MUST(Ext2Inode::create(m_fs, new_ino)); + + MUST(link_inode_to_directory(*inode, name)); + + return {}; + } + + BAN::ErrorOr Ext2Inode::create_directory_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid) + { + // FIXME: handle errors + + ASSERT(this->mode().ifdir()); + ASSERT(Mode(mode).ifdir()); + + const uint32_t new_ino = TRY(m_fs.create_inode(initialize_new_inode_info(mode, uid, gid))); + + auto inode = MUST(Ext2Inode::create(m_fs, new_ino)); + MUST(inode->link_inode_to_directory(*inode, "."sv)); + MUST(inode->link_inode_to_directory(*this, ".."sv)); + + MUST(link_inode_to_directory(*inode, name)); + + return {}; + } + + BAN::ErrorOr Ext2Inode::link_inode_to_directory(Ext2Inode& inode, BAN::StringView name) { if (!this->mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); @@ -325,9 +404,6 @@ namespace Kernel if (name.size() > 255) return BAN::Error::from_errno(ENAMETOOLONG); - if (!(Mode(mode).ifreg())) - return BAN::Error::from_errno(EINVAL); - if (m_inode.flags & Ext2::Enum::INDEX_FL) { dwarnln("file creation to indexed directory not supported"); @@ -340,39 +416,13 @@ namespace Kernel if (error_or.error().get_error_code() != ENOENT) return error_or.error(); - timespec current_time = SystemTimer::get().real_time(); - - Ext2::Inode ext2_inode - { - .mode = (uint16_t)mode, - .uid = (uint16_t)uid, - .size = 0, - .atime = (uint32_t)current_time.tv_sec, - .ctime = (uint32_t)current_time.tv_sec, - .mtime = (uint32_t)current_time.tv_sec, - .dtime = 0, - .gid = (uint16_t)gid, - .links_count = 1, - .blocks = 0, - .flags = 0, - .osd1 = 0, - .block = {}, - .generation = 0, - .file_acl = 0, - .dir_acl = 0, - .faddr = 0, - .osd2 = {} - }; - - const uint32_t inode_index = TRY(m_fs.create_inode(ext2_inode)); - const uint32_t block_size = m_fs.block_size(); auto block_buffer = m_fs.get_block_buffer(); auto write_inode = [&](uint32_t entry_offset, uint32_t entry_rec_len) { - auto typed_mode = Mode(mode); + auto typed_mode = inode.mode(); uint8_t file_type = (m_fs.superblock().rev_level == Ext2::Enum::GOOD_OLD_REV) ? 0 : typed_mode.ifreg() ? Ext2::Enum::REG_FILE : typed_mode.ifdir() ? Ext2::Enum::DIR @@ -384,11 +434,14 @@ namespace Kernel : 0; auto& new_entry = *(Ext2::LinkedDirectoryEntry*)(block_buffer.data() + entry_offset); - new_entry.inode = inode_index; + new_entry.inode = inode.ino(); new_entry.rec_len = entry_rec_len; new_entry.name_len = name.size(); new_entry.file_type = file_type; memcpy(new_entry.name, name.data(), name.size()); + + inode.m_inode.links_count++; + MUST(inode.sync()); }; uint32_t block_index = 0;