From 71b433a6f9a013ba62559c187ca6f473f9882334 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Wed, 17 Mar 2021 18:35:42 +0100 Subject: [PATCH] Kernel: Add 64 bit file size support to Ext2FS --- Kernel/FileSystem/Ext2FileSystem.cpp | 30 +++++++++++++++++++++++----- Kernel/FileSystem/Ext2FileSystem.h | 9 ++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index f08bc1ad3c..c743724515 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -428,7 +428,7 @@ KResult Ext2FSInode::flush_block_list() } // NOTE: There is a mismatch between i_blocks and blocks.size() since i_blocks includes meta blocks and blocks.size() does not. - const auto old_block_count = ceil_div(static_cast(m_raw_inode.i_size), fs().block_size()); + const auto old_block_count = ceil_div(size(), static_cast(fs().block_size())); auto old_shape = fs().compute_block_list_shape(old_block_count); const auto new_shape = fs().compute_block_list_shape(m_block_list.size()); @@ -572,7 +572,7 @@ Vector Ext2FSInode::compute_block_list_impl_internal(const e { unsigned entries_per_block = EXT2_ADDR_PER_BLOCK(&fs().super_block()); - unsigned block_count = ceil_div(static_cast(e2inode.i_size), fs().block_size()); + unsigned block_count = ceil_div(size(), static_cast(fs().block_size())); // If we are handling a symbolic link, the path is stored in the 60 bytes in // the inode that are used for the 12 direct and 3 indirect block pointers, @@ -765,12 +765,19 @@ Ext2FSInode::~Ext2FSInode() fs().free_inode(*this); } +u64 Ext2FSInode::size() const +{ + if (Kernel::is_regular_file(m_raw_inode.i_mode) && ((u32)fs().get_features_readonly() & (u32)Ext2FS::FeaturesReadOnly::FileSize64bits)) + return static_cast(m_raw_inode.i_dir_acl) << 32 | m_raw_inode.i_size; + return m_raw_inode.i_size; +} + InodeMetadata Ext2FSInode::metadata() const { LOCKER(m_lock); InodeMetadata metadata; metadata.inode = identifier(); - metadata.size = m_raw_inode.i_size; + metadata.size = size(); metadata.mode = m_raw_inode.i_mode; metadata.uid = m_raw_inode.i_uid; metadata.gid = m_raw_inode.i_gid; @@ -908,6 +915,9 @@ KResult Ext2FSInode::resize(u64 new_size) if (old_size == new_size) return KSuccess; + if (!((u32)fs().get_features_readonly() & (u32)Ext2FS::FeaturesReadOnly::FileSize64bits) && (new_size >= static_cast(-1))) + return ENOSPC; + u64 block_size = fs().block_size(); size_t blocks_needed_before = ceil_div(old_size, block_size); size_t blocks_needed_after = ceil_div(new_size, block_size); @@ -955,6 +965,9 @@ KResult Ext2FSInode::resize(u64 new_size) return result; m_raw_inode.i_size = new_size; + if (Kernel::is_regular_file(m_raw_inode.i_mode)) + m_raw_inode.i_dir_acl = new_size >> 32; + set_metadata_dirty(true); if (new_size > old_size) { @@ -1003,7 +1016,7 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const UserOrKernel bool allow_cache = !description || !description->is_direct(); const size_t block_size = fs().block_size(); - u64 new_size = max(static_cast(offset) + count, (u64)size()); + u64 new_size = max(static_cast(offset) + count, size()); auto resize_result = resize(new_size); if (resize_result.is_error()) @@ -1042,7 +1055,7 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const UserOrKernel nwritten += num_bytes_to_copy; } - dbgln_if(EXT2_VERY_DEBUG, "Ext2FSInode[{}]::write_bytes(): After write, i_size={}, i_blocks={} ({} blocks in list)", identifier(), m_raw_inode.i_size, m_raw_inode.i_blocks, m_block_list.size()); + dbgln_if(EXT2_VERY_DEBUG, "Ext2FSInode[{}]::write_bytes(): After write, i_size={}, i_blocks={} ({} blocks in list)", identifier(), size(), m_raw_inode.i_blocks, m_block_list.size()); return nwritten; } @@ -1068,6 +1081,13 @@ u8 Ext2FS::internal_file_type_to_directory_entry_type(const DirectoryEntryView& } } +Ext2FS::FeaturesReadOnly Ext2FS::get_features_readonly() const +{ + if (m_super_block.s_rev_level > 0) + return static_cast(m_super_block.s_feature_ro_compat); + return Ext2FS::FeaturesReadOnly::None; +} + KResult Ext2FSInode::traverse_as_directory(Function callback) const { LOCKER(m_lock); diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h index 714dbb96e5..b66ce64f1a 100644 --- a/Kernel/FileSystem/Ext2FileSystem.h +++ b/Kernel/FileSystem/Ext2FileSystem.h @@ -49,7 +49,7 @@ class Ext2FSInode final : public Inode { public: virtual ~Ext2FSInode() override; - size_t size() const { return m_raw_inode.i_size; } + u64 size() const; bool is_symlink() const { return Kernel::is_symlink(m_raw_inode.i_mode); } bool is_directory() const { return Kernel::is_directory(m_raw_inode.i_mode); } @@ -105,6 +105,11 @@ class Ext2FS final : public BlockBasedFS { friend class Ext2FSInode; public: + enum class FeaturesReadOnly : u32 { + None = 0, + FileSize64bits = 1 << 1, + }; + static NonnullRefPtr create(FileDescription&); virtual ~Ext2FS() override; @@ -121,6 +126,8 @@ public: virtual u8 internal_file_type_to_directory_entry_type(const DirectoryEntryView& entry) const override; + FeaturesReadOnly get_features_readonly() const; + private: TYPEDEF_DISTINCT_ORDERED_ID(unsigned, GroupIndex);