mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 22:47:47 +00:00
Kernel: Traverse ext2 directories blockwise.
Instead of reading in the entire contents of a directory into a large buffer, we can iterate block by block. This only requires a small buffer. Because directory entries are guaranteed to never span multiple blocks we do not have to handle any edge cases related to that.
This commit is contained in:
parent
49b132a92d
commit
e0deb46723
1 changed files with 23 additions and 11 deletions
|
@ -1071,20 +1071,32 @@ KResult Ext2FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
||||||
Locker locker(m_lock);
|
Locker locker(m_lock);
|
||||||
VERIFY(is_directory());
|
VERIFY(is_directory());
|
||||||
|
|
||||||
auto buffer_or = read_entire();
|
u8 buffer[max_block_size];
|
||||||
if (buffer_or.is_error())
|
auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer);
|
||||||
return buffer_or.error();
|
|
||||||
|
|
||||||
auto& buffer = *buffer_or.value();
|
auto block_size = fs().block_size();
|
||||||
auto* entry = reinterpret_cast<ext2_dir_entry_2*>(buffer.data());
|
bool allow_cache = true;
|
||||||
|
|
||||||
while (entry < buffer.end_pointer()) {
|
if (m_block_list.is_empty())
|
||||||
if (entry->inode != 0) {
|
m_block_list = compute_block_list();
|
||||||
dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::traverse_as_directory(): inode {}, name_len: {}, rec_len: {}, file_type: {}, name: {}", identifier(), entry->inode, entry->name_len, entry->rec_len, entry->file_type, StringView(entry->name, entry->name_len));
|
|
||||||
if (!callback({ { entry->name, entry->name_len }, { fsid(), entry->inode }, entry->file_type }))
|
// Directory entries are guaranteed not to span multiple blocks,
|
||||||
break;
|
// so we can iterate over blocks separately.
|
||||||
|
for (auto& block_index : m_block_list) {
|
||||||
|
VERIFY(block_index.value() != 0);
|
||||||
|
if (auto result = fs().read_block(block_index, &buf, block_size, 0, allow_cache); result.is_error()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
auto* entry = reinterpret_cast<ext2_dir_entry_2*>(buffer);
|
||||||
|
auto* entries_end = reinterpret_cast<ext2_dir_entry_2*>(buffer + block_size);
|
||||||
|
while (entry < entries_end) {
|
||||||
|
if (entry->inode != 0) {
|
||||||
|
dbgln_if(EXT2_DEBUG, "Ext2FSInode[{}]::traverse_as_directory(): inode {}, name_len: {}, rec_len: {}, file_type: {}, name: {}", identifier(), entry->inode, entry->name_len, entry->rec_len, entry->file_type, StringView(entry->name, entry->name_len));
|
||||||
|
if (!callback({ { entry->name, entry->name_len }, { fsid(), entry->inode }, entry->file_type }))
|
||||||
|
return KSuccess;
|
||||||
|
}
|
||||||
|
entry = (ext2_dir_entry_2*)((char*)entry + entry->rec_len);
|
||||||
}
|
}
|
||||||
entry = (ext2_dir_entry_2*)((char*)entry + entry->rec_len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue