aboutsummaryrefslogtreecommitdiff
path: root/kernel/kernel/filesystem/ext2/inode.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kernel/filesystem/ext2/inode.cpp')
-rw-r--r--kernel/kernel/filesystem/ext2/inode.cpp116
1 files changed, 112 insertions, 4 deletions
diff --git a/kernel/kernel/filesystem/ext2/inode.cpp b/kernel/kernel/filesystem/ext2/inode.cpp
index 6dadbec5..8af168b9 100644
--- a/kernel/kernel/filesystem/ext2/inode.cpp
+++ b/kernel/kernel/filesystem/ext2/inode.cpp
@@ -14,8 +14,9 @@
namespace kernel::filesystem::ext2
{
- inode::inode(filesystem const * fs, inode_data const & data)
+ inode::inode(filesystem * fs, uint32_t inode_number, inode_data const & data)
: m_filesystem(fs)
+ , m_inode_number(inode_number)
, m_data(data)
{
if (!m_filesystem)
@@ -76,10 +77,98 @@ namespace kernel::filesystem::ext2
return bytes_read;
}
- auto inode::write(void const *, size_t, size_t) -> kstd::result<size_t>
+ auto inode::write(void const * buffer, size_t offset, size_t size) -> kstd::result<size_t>
{
- kapi::system::panic("[EXT2] inode::write is not implemented yet");
- return 0;
+ if (!is_regular())
+ {
+ kapi::system::panic("[EXT2] ext2::inode write called on inode that is not of type regular");
+ }
+
+ // TODO check maximum file size of filesystem
+ // TODO handle sparse files
+
+ auto const new_inode_size = std::max(this->size(), offset + size);
+
+ auto const current_block_count = m_filesystem->inode_block_count(m_data);
+ auto const max_new_inode_size_without_new_blocks = current_block_count * m_filesystem->block_size();
+
+ if (new_inode_size > max_new_inode_size_without_new_blocks)
+ {
+ auto const additional_blocks_needed =
+ (new_inode_size - max_new_inode_size_without_new_blocks + m_filesystem->block_size() - 1) /
+ m_filesystem->block_size();
+
+ if (!append_blocks(additional_blocks_needed))
+ {
+ // TODO handle out of space
+ kapi::system::panic("[EXT2] Failed to allocate blocks for inode write");
+ }
+ }
+
+ auto block_index = offset / m_filesystem->block_size();
+ auto in_block_offset = offset % m_filesystem->block_size();
+
+ auto bytes_written = 0uz;
+
+ while (bytes_written < size)
+ {
+ auto const block_number = m_filesystem->map_inode_block_index_to_global_block_number(block_index, m_data);
+ // TODO BA-FS26 if blocknumber == 0 --> handle sparse file
+ if (!block_number)
+ {
+ kstd::failure(block_number.error());
+ }
+
+ auto const bytes_to_write = std::min(size - bytes_written, m_filesystem->block_size() - in_block_offset);
+
+ auto const block_start_offset = block_number.value() * m_filesystem->block_size();
+ auto const write_offset = block_start_offset + in_block_offset;
+
+ auto const write_result = m_filesystem->backing_inode()->write(
+ static_cast<uint8_t const *>(buffer) + bytes_written, write_offset, bytes_to_write);
+ if (!write_result)
+ {
+ return kstd::failure(write_result.error());
+ }
+
+ bytes_written += write_result.value();
+
+ block_index++;
+ in_block_offset = 0;
+ }
+
+ set_size(std::max(this->size(), offset + bytes_written));
+ if (auto write_result = m_filesystem->write_inode(m_inode_number, m_data); !write_result)
+ {
+ return kstd::failure(write_result.error());
+ }
+
+ return bytes_written;
+ }
+
+ auto inode::append_blocks(size_t count) -> bool
+ {
+ auto new_blocks = m_filesystem->allocate_blocks(count);
+ if (!new_blocks)
+ {
+ return false;
+ }
+
+ for (auto i = 0uz; i < new_blocks->size(); ++i)
+ {
+ auto const block_index = m_filesystem->inode_block_count(m_data) + i;
+ auto const global_block_number = new_blocks->at(i);
+
+ if (auto write_result =
+ m_filesystem->write_global_block_number_to_inode_block_index(block_index, m_data, global_block_number);
+ !write_result)
+ {
+ return false;
+ }
+ }
+
+ m_filesystem->update_inode_block_count(m_data, count);
+ return true;
}
[[nodiscard]] auto inode::data() const -> inode_data const &
@@ -87,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;
@@ -114,4 +208,18 @@ namespace kernel::filesystem::ext2
return size;
}
+ auto inode::set_size(uint64_t new_size) -> void
+ {
+ if (m_filesystem->revision_level() > constants::good_old_revision && is_regular())
+ {
+ m_data.dir_acl = static_cast<uint32_t>(new_size >> 32);
+ }
+ m_data.size = static_cast<uint32_t>(new_size);
+ }
+
+ [[nodiscard]] auto inode::number() const -> uint32_t
+ {
+ return m_inode_number;
+ }
+
} // namespace kernel::filesystem::ext2