diff options
Diffstat (limited to 'kernel/kernel/filesystem/ext2/inode.cpp')
| -rw-r--r-- | kernel/kernel/filesystem/ext2/inode.cpp | 116 |
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 |
