summaryrefslogtreecommitdiff
path: root/Kernel/FileSystem
diff options
context:
space:
mode:
Diffstat (limited to 'Kernel/FileSystem')
-rw-r--r--Kernel/FileSystem/Ext2FileSystem.cpp52
-rw-r--r--Kernel/FileSystem/Ext2FileSystem.h2
2 files changed, 31 insertions, 23 deletions
diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp
index f672e4a8f9..9a1f182eb0 100644
--- a/Kernel/FileSystem/Ext2FileSystem.cpp
+++ b/Kernel/FileSystem/Ext2FileSystem.cpp
@@ -27,6 +27,7 @@ struct Ext2FSDirectoryEntry {
String name;
InodeIndex inode_index { 0 };
u8 file_type { 0 };
+ u16 record_length { 0 };
};
static u8 to_ext2_file_type(mode_t mode)
@@ -1089,45 +1090,52 @@ KResult Ext2FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
return KSuccess;
}
-KResult Ext2FSInode::write_directory(const Vector<Ext2FSDirectoryEntry>& entries)
+KResult Ext2FSInode::write_directory(Vector<Ext2FSDirectoryEntry>& entries)
{
Locker locker(m_lock);
-
- int directory_size = 0;
- for (auto& entry : entries)
- directory_size += EXT2_DIR_REC_LEN(entry.name.length());
-
auto block_size = fs().block_size();
- int blocks_needed = ceil_div(static_cast<size_t>(directory_size), block_size);
- int occupied_size = blocks_needed * block_size;
-
- dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::write_directory(): New directory contents to write (size {}, occupied {}):", identifier(), directory_size, occupied_size);
-
- auto directory_data = ByteBuffer::create_uninitialized(occupied_size);
- OutputMemoryStream stream { directory_data };
-
+ // Calculate directory size and record length of entries so that
+ // the following constraints are met:
+ // - All used blocks must be entirely filled.
+ // - Entries are aligned on a 4-byte boundary.
+ // - No entry may span multiple blocks.
+ size_t directory_size = 0;
+ size_t space_in_block = block_size;
for (size_t i = 0; i < entries.size(); ++i) {
auto& entry = entries[i];
+ entry.record_length = EXT2_DIR_REC_LEN(entry.name.length());
+ space_in_block -= entry.record_length;
+ if (i + 1 < entries.size()) {
+ if (EXT2_DIR_REC_LEN(entries[i + 1].name.length()) > space_in_block) {
+ entry.record_length += space_in_block;
+ space_in_block = block_size;
+ }
+ } else {
+ entry.record_length += space_in_block;
+ }
+ directory_size += entry.record_length;
+ }
- int record_length = EXT2_DIR_REC_LEN(entry.name.length());
- if (i == entries.size() - 1)
- record_length += occupied_size - directory_size;
+ dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::write_directory(): New directory contents to write (size {}):", identifier(), directory_size);
- dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::write_directory(): Writing inode: {}, name_len: {}, rec_len: {}, file_type: {}, name: {}", identifier(), entry.inode_index, u16(entry.name.length()), u16(record_length), u8(entry.file_type), entry.name);
+ auto directory_data = ByteBuffer::create_uninitialized(directory_size);
+ OutputMemoryStream stream { directory_data };
+
+ for (auto& entry : entries) {
+ dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::write_directory(): Writing inode: {}, name_len: {}, rec_len: {}, file_type: {}, name: {}", identifier(), entry.inode_index, u16(entry.name.length()), u16(entry.record_length), u8(entry.file_type), entry.name);
stream << u32(entry.inode_index.value());
- stream << u16(record_length);
+ stream << u16(entry.record_length);
stream << u8(entry.name.length());
stream << u8(entry.file_type);
stream << entry.name.bytes();
-
- int padding = record_length - entry.name.length() - 8;
+ int padding = entry.record_length - entry.name.length() - 8;
for (int j = 0; j < padding; ++j)
stream << u8(0);
}
- stream.fill_to_end(0);
+ VERIFY(stream.is_end());
if (auto result = resize(stream.size()); result.is_error())
return result;
diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h
index 6e666a4137..6027e28a12 100644
--- a/Kernel/FileSystem/Ext2FileSystem.h
+++ b/Kernel/FileSystem/Ext2FileSystem.h
@@ -58,7 +58,7 @@ private:
virtual KResult truncate(u64) override;
virtual KResultOr<int> get_block_address(int) override;
- KResult write_directory(const Vector<Ext2FSDirectoryEntry>&);
+ KResult write_directory(Vector<Ext2FSDirectoryEntry>&);
bool populate_lookup_cache() const;
KResult resize(u64);
KResult write_indirect_block(BlockBasedFS::BlockIndex, Span<BlockBasedFS::BlockIndex>);