aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLukas Oesch <lukasoesch20@gmail.com>2026-06-07 21:11:00 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-07-14 21:25:10 +0200
commitb37c7a9203a669feb7eec3b694e1e6285a68b6ea (patch)
tree677e5e07e61ada73975a6eec61415af202e7021d /kernel
parent660e23151774411378799afb1a519f420ccda567 (diff)
downloadkernel-b37c7a9203a669feb7eec3b694e1e6285a68b6ea.tar.xz
kernel-b37c7a9203a669feb7eec3b694e1e6285a68b6ea.zip
first draft implementing init_directory
Diffstat (limited to 'kernel')
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.cpp134
-rw-r--r--kernel/kernel/filesystem/ext2/filesystem.hpp6
-rw-r--r--kernel/kernel/filesystem/ext2/inode.cpp5
-rw-r--r--kernel/kernel/filesystem/ext2/inode.hpp8
4 files changed, 113 insertions, 40 deletions
diff --git a/kernel/kernel/filesystem/ext2/filesystem.cpp b/kernel/kernel/filesystem/ext2/filesystem.cpp
index 89f25d42..bd1b99a2 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.cpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.cpp
@@ -167,6 +167,12 @@ namespace kernel::filesystem::ext2
return kstd::failure(vfs_errc::not_a_directory);
}
+ auto * ext2_parent = static_cast<inode *>(parent.get());
+ if (!ext2_parent)
+ {
+ return nullptr;
+ }
+
auto maybe_inode_number = allocate_inode();
if (!maybe_inode_number)
{
@@ -185,80 +191,85 @@ namespace kernel::filesystem::ext2
new_inode_data.blocks = 0;
new_inode_data.block.fill(0);
- if (auto write_result = write_inode(inode_number, new_inode_data); !write_result)
+ // TODO preallocate blocks depending on type and m_superblock.prealloc_dir_blocks or m_superblock.prealloc_blocks;
+
+ if (auto result = add_directory_entry(ext2_parent, name, inode_number, new_inode_data.mode); !result)
{
- return kstd::failure(write_result.error());
+ return kstd::failure(result.error());
}
- // add directory entry to parent
- if (auto * ext2_parent = static_cast<inode *>(parent.get()))
+ auto new_inode = kstd::make_shared<inode>(this, inode_number, new_inode_data);
+
+ bool is_directory = false; // TODO refactor
+ if (is_directory)
{
- if (auto result = add_directory_entry(ext2_parent, name, inode_number, new_inode_data.mode);
- !result) // TODO handle mode correctly
+ if (auto result = init_directory(new_inode, ext2_parent->number()); !result)
{
return kstd::failure(result.error());
}
- // TODO
+
+ // '..' inside the new dir counts as an extra hard link to the parent
+ auto & parent_inode_data = ext2_parent->data_mutable();
+ parent_inode_data.links_count++;
+
+ if (auto write_result = write_inode(ext2_parent->number(), parent_inode_data); !write_result)
+ {
+ return kstd::failure(write_result.error());
+ }
}
+
+ if (auto write_result = write_inode(inode_number, new_inode_data); !write_result)
+ {
+ return kstd::failure(write_result.error());
+ }
+
+ return new_inode;
}
auto filesystem::add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number,
[[maybe_unused]] uint16_t mode) -> kstd::result<void>
{
auto const last_block_index = inode_block_count(ext2_parent->data()) - 1;
- auto const global_block_number =
- map_inode_block_index_to_global_block_number(last_block_index, ext2_parent->data());
+ auto const global_block = map_inode_block_index_to_global_block_number(last_block_index, ext2_parent->data());
- if (!global_block_number)
+ if (!global_block)
{
- return kstd::failure(global_block_number.error());
+ return kstd::failure(global_block.error());
}
kstd::vector<uint8_t> buffer(block_size());
- if (auto read_result = read_block(*global_block_number, buffer.data()); !read_result)
+ if (auto read_result = read_block(*global_block, buffer.data()); !read_result)
{
return kstd::failure(read_result.error());
}
+ // TODO handle "gaps" in directory entries (e.g., after deletions) in the current implementation, we only
+ // add new entries at the end of the last block, but we could also reuse space from deleted entries
auto offset = 0uz;
while (true)
{
auto const * entry = reinterpret_cast<linked_directory_entry const *>(buffer.data() + offset);
-
if (offset + entry->rec_len >= block_size())
{
break;
}
-
offset += entry->rec_len;
}
- // auto const * last_entry = reinterpret_cast<linked_directory_entry const *>(buffer.data() + offset);
-
- // auto const last_entry_actual_len = static_cast<uint16_t>((8u + last_entry->name_len + 3u) & ~3u);
- // auto const free_space = last_entry->rec_len - last_entry_actual_len;
-
- // auto const last_entry_actual_length = 0; // TODO
+ auto const file_type = map_inode_mode_to_file_type(mode);
auto const name_len = static_cast<uint8_t>(name.size());
auto const needed_rec_len = static_cast<uint16_t>((8u + name_len + 3u) & ~3u);
auto * last_entry = reinterpret_cast<linked_directory_entry *>(buffer.data() + offset);
auto const last_entry_actual_len = static_cast<uint16_t>((8u + last_entry->name_len + 3u) & ~3u);
- auto const free_space = last_entry->rec_len - last_entry_actual_len;
- if (free_space >= needed_rec_len)
+ if (last_entry->rec_len - last_entry_actual_len >= needed_rec_len)
{
last_entry->rec_len = last_entry_actual_len;
- offset += last_entry_actual_len;
-
- auto * new_entry = reinterpret_cast<linked_directory_entry *>(buffer.data() + offset);
- new_entry->inode = child_inode_number;
- new_entry->rec_len = static_cast<uint16_t>(block_size() - offset);
- new_entry->name_len = name_len;
- new_entry->file_type = 0x01; // TODO handle mode correctly
- kstd::libc::memcpy(new_entry->name.data(), name.data(), name_len);
-
- return write_block(*global_block_number, buffer.data()).transform([](auto) {});
+ write_directory_entry_to_buffer(buffer.data(), offset + last_entry_actual_len, child_inode_number, name,
+ file_type);
+ return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer.data()); })
+ .transform([](auto) {});
}
if (!ext2_parent->append_blocks(1))
@@ -275,19 +286,47 @@ namespace kernel::filesystem::ext2
}
kstd::libc::memset(buffer.data(), 0, block_size());
-
- auto * entry = reinterpret_cast<linked_directory_entry *>(buffer.data());
- entry->inode = child_inode_number;
- entry->rec_len = static_cast<uint16_t>(block_size());
- entry->name_len = name_len;
- entry->file_type = 0x01; // TODO handle mode correctly
- kstd::libc::memcpy(entry->name.data(), name.data(), name_len);
+ write_directory_entry_to_buffer(buffer.data(), 0, child_inode_number, name, file_type);
return write_block(static_cast<uint32_t>(*new_global_block), buffer.data()).and_then([&](auto) {
return write_inode(ext2_parent->number(), ext2_parent->data());
});
}
+ auto filesystem::init_directory(kstd::shared_ptr<kernel::filesystem::ext2::inode> const & new_inode,
+ uint32_t parent_inode_number) -> kstd::result<void>
+ {
+ if (!new_inode->append_blocks(1))
+ {
+ return kstd::failure(ext2_errc::not_enough_free_blocks);
+ }
+
+ auto const global_block = map_inode_block_index_to_global_block_number(0, new_inode->data());
+ if (!global_block)
+ {
+ return kstd::failure(global_block.error());
+ }
+
+ kstd::vector<uint8_t> buffer(block_size(), 0);
+ write_directory_entry_to_buffer(buffer.data(), 0, new_inode->number(), ".", 2);
+ auto const dot_actual_len = static_cast<uint16_t>((8u + 1 + 3u) & ~3u);
+ write_directory_entry_to_buffer(buffer.data(), dot_actual_len, parent_inode_number, "..", 2);
+ return global_block.and_then([&](auto block_number) { return write_block(block_number, buffer.data()); })
+ .transform([](auto) {});
+ }
+
+ auto filesystem::write_directory_entry_to_buffer(uint8_t * block_buffer, size_t offset, uint32_t child_inode_number,
+ std::string_view name, uint8_t file_type) -> void
+ {
+ auto const name_len = static_cast<uint8_t>(name.size());
+ auto * entry = reinterpret_cast<linked_directory_entry *>(block_buffer + offset);
+ entry->inode = child_inode_number;
+ entry->rec_len = static_cast<uint16_t>(block_size() - offset);
+ entry->name_len = name_len;
+ entry->file_type = file_type;
+ kstd::libc::memcpy(entry->name.data(), name.data(), name_len);
+ }
+
auto filesystem::read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>>
{
if (auto inode_offset = calculate_inode_offset(inode_number))
@@ -671,6 +710,23 @@ namespace kernel::filesystem::ext2
.transform([](auto) {});
}
+ auto filesystem::map_inode_mode_to_file_type(uint16_t mode) -> uint8_t
+ {
+ {
+ switch (mode & constants::mode_mask)
+ {
+ case constants::mode_regular:
+ return 1;
+ case constants::mode_directory:
+ return 2;
+ case constants::mode_symbolic_link:
+ return 7;
+ default:
+ return 0;
+ }
+ }
+ }
+
auto filesystem::block_numbers_per_block() const -> size_t
{
return block_size() / sizeof(uint32_t);
diff --git a/kernel/kernel/filesystem/ext2/filesystem.hpp b/kernel/kernel/filesystem/ext2/filesystem.hpp
index b3279e09..f45bda97 100644
--- a/kernel/kernel/filesystem/ext2/filesystem.hpp
+++ b/kernel/kernel/filesystem/ext2/filesystem.hpp
@@ -168,6 +168,10 @@ namespace kernel::filesystem::ext2
auto allocate_inode() -> kstd::result<uint32_t>;
auto add_directory_entry(inode * ext2_parent, std::string_view name, uint32_t child_inode_number, uint16_t mode)
-> kstd::result<void>;
+ auto init_directory(kstd::shared_ptr<kernel::filesystem::ext2::inode> const & new_inode,
+ uint32_t parent_inode_number) -> kstd::result<void>;
+ auto write_directory_entry_to_buffer(uint8_t * block_buffer, size_t offset, uint32_t child_inode_number,
+ std::string_view name, uint8_t file_type) -> void;
[[nodiscard]] auto calculate_inode_offset(uint32_t inode_number) const -> kstd::result<size_t>;
[[nodiscard]] auto read_inode(uint32_t inode_number) const -> kstd::result<kstd::shared_ptr<inode>>;
@@ -186,6 +190,8 @@ namespace kernel::filesystem::ext2
size_t block_group_descriptor_index) const -> kstd::result<void>;
[[nodiscard]] auto write_superblock() const -> kstd::result<void>;
+ auto map_inode_mode_to_file_type(uint16_t mode) -> uint8_t;
+
superblock m_superblock{};
kstd::vector<block_group_descriptor> m_block_group_descriptors;
};
diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp
index 0c8da9d0..8af168b9 100644
--- a/kernel/kernel/filesystem/ext2/inode.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.cpp
@@ -176,6 +176,11 @@ namespace kernel::filesystem::ext2
return m_data;
}
+ [[nodiscard]] auto inode::data_mutable() -> inode_data &
+ {
+ return m_data;
+ }
+
auto inode::is_regular() const -> bool
{
return (m_data.mode & constants::mode_mask) == constants::mode_regular;
diff --git a/kernel/kernel/filesystem/ext2/inode.hpp b/kernel/kernel/filesystem/ext2/inode.hpp
index ac17e6ab..61542ef8 100644
--- a/kernel/kernel/filesystem/ext2/inode.hpp
+++ b/kernel/kernel/filesystem/ext2/inode.hpp
@@ -76,11 +76,17 @@ namespace kernel::filesystem::ext2
/**
@brief Get the data associated with this inode.
- @return A reference to the inode data.
+ @return A const reference to the inode data.
*/
[[nodiscard]] auto data() const -> inode_data const &;
/**
+ @brief Get the data associated with this inode.
+ @return A reference to the inode data.
+ */
+ [[nodiscard]] auto data_mutable() -> inode_data &;
+
+ /**
@brief Check if this inode represents a directory.
@return returns true if this inode represents a directory, false otherwise.
*/