diff --git a/VirtualFileSystem/Ext2FileSystem.cpp b/VirtualFileSystem/Ext2FileSystem.cpp index d78388dc2a..0d265456ab 100644 --- a/VirtualFileSystem/Ext2FileSystem.cpp +++ b/VirtualFileSystem/Ext2FileSystem.cpp @@ -1152,3 +1152,27 @@ InodeIdentifier Ext2FileSystem::find_parent_of_inode(InodeIdentifier inode_id) c return foundParent; } + +InodeIdentifier Ext2Inode::lookup(const String& name) +{ + ASSERT(is_directory()); + + if (m_child_cache.isEmpty()) { + HashMap children; + + traverse_as_directory([&children] (auto& entry) { + children.set(String(entry.name, entry.name_length), entry.inode.index()); + return true; + }); + + LOCKER(m_lock); + m_child_cache = move(children); + } + + LOCKER(m_lock); + auto it = m_child_cache.find(name); + if (it != m_child_cache.end()) + return { fsid(), (*it).value }; + + return { }; +} diff --git a/VirtualFileSystem/Ext2FileSystem.h b/VirtualFileSystem/Ext2FileSystem.h index afaad0c40d..d35da38142 100644 --- a/VirtualFileSystem/Ext2FileSystem.h +++ b/VirtualFileSystem/Ext2FileSystem.h @@ -25,6 +25,7 @@ private: virtual Unix::ssize_t read_bytes(Unix::off_t, Unix::size_t, byte* buffer, FileDescriptor*) override; virtual void populate_metadata() const override; virtual bool traverse_as_directory(Function) override; + virtual InodeIdentifier lookup(const String& name) override; Ext2FileSystem& fs(); const Ext2FileSystem& fs() const; @@ -32,6 +33,7 @@ private: SpinLock m_lock; Vector m_block_list; + HashMap m_child_cache; ext2_inode m_raw_inode; }; diff --git a/VirtualFileSystem/FileSystem.cpp b/VirtualFileSystem/FileSystem.cpp index 3afaa12439..925c561333 100644 --- a/VirtualFileSystem/FileSystem.cpp +++ b/VirtualFileSystem/FileSystem.cpp @@ -37,19 +37,6 @@ FileSystem* FileSystem::fromID(dword id) return nullptr; } -InodeIdentifier FileSystem::child_of_directory_inode_with_name(InodeIdentifier inode, const String& name) const -{ - InodeIdentifier foundInode; - enumerateDirectoryInode(inode, [&] (const DirectoryEntry& entry) { - if (!strcmp(entry.name, name.characters())) { - foundInode = entry.inode; - return false; - } - return true; - }); - return foundInode; -} - String FileSystem::name_of_child_in_directory(InodeIdentifier parent, InodeIdentifier child) const { String name; diff --git a/VirtualFileSystem/FileSystem.h b/VirtualFileSystem/FileSystem.h index 6e6b68649d..80277c5ae2 100644 --- a/VirtualFileSystem/FileSystem.h +++ b/VirtualFileSystem/FileSystem.h @@ -53,7 +53,6 @@ public: virtual RetainPtr get_inode(InodeIdentifier) const = 0; - InodeIdentifier child_of_directory_inode_with_name(InodeIdentifier, const String& name) const; ByteBuffer readEntireInode(InodeIdentifier, FileDescriptor* = nullptr) const; String name_of_child_in_directory(InodeIdentifier parent, InodeIdentifier child) const; @@ -81,10 +80,12 @@ public: InodeIdentifier identifier() const { return { fsid(), index() }; } const InodeMetadata& metadata() const { if (!m_metadata.isValid()) { populate_metadata(); } return m_metadata; } + ByteBuffer read_entire(FileDescriptor* = nullptr); + virtual Unix::ssize_t read_bytes(Unix::off_t, Unix::size_t, byte* buffer, FileDescriptor*) = 0; virtual bool traverse_as_directory(Function) = 0; + virtual InodeIdentifier lookup(const String& name) = 0; - ByteBuffer read_entire(FileDescriptor* = nullptr); protected: CoreInode(FileSystem& fs, unsigned index) diff --git a/VirtualFileSystem/SyntheticFileSystem.cpp b/VirtualFileSystem/SyntheticFileSystem.cpp index a6f64acfb6..20f7a6d17d 100644 --- a/VirtualFileSystem/SyntheticFileSystem.cpp +++ b/VirtualFileSystem/SyntheticFileSystem.cpp @@ -320,3 +320,17 @@ bool SynthFSInode::traverse_as_directory(Functionm_name.characters(), child->m_name.length(), child->m_metadata.inode, child->m_metadata.isDirectory() ? (byte)2 : (byte)1 }); return true; } + +InodeIdentifier SynthFSInode::lookup(const String& name) +{ + ASSERT(is_directory()); + if (name == ".") + return identifier(); + if (name == "..") + return m_parent; + for (auto& child : m_children) { + if (child->m_name == name) + return child->identifier(); + } + return { }; +} diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index 1aadbc57d1..a1afc053d1 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -54,6 +54,7 @@ private: virtual Unix::ssize_t read_bytes(Unix::off_t, Unix::size_t, byte* buffer, FileDescriptor*) override; virtual void populate_metadata() const override; virtual bool traverse_as_directory(Function) override; + virtual InodeIdentifier lookup(const String& name) override; SyntheticFileSystem& fs(); const SyntheticFileSystem& fs() const; diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index c90941eb7b..e5dd3c60e9 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -525,7 +525,8 @@ InodeIdentifier VFS::resolve_path(const String& path, int& error, InodeIdentifie return { }; } auto parent = crumb_id; - crumb_id = crumb_id.fileSystem()->child_of_directory_inode_with_name(crumb_id, part); + auto dir_inode = get_inode(crumb_id); + crumb_id = dir_inode->lookup(part); if (!crumb_id.isValid()) { #ifdef VFS_DEBUG kprintf("child <%s>(%u) not found in directory, %02u:%08u\n", part.characters(), part.length(), parent.fsid(), parent.index()); @@ -547,8 +548,8 @@ InodeIdentifier VFS::resolve_path(const String& path, int& error, InodeIdentifie kprintf(" -- is guest\n"); #endif auto mount = find_mount_for_guest(crumb_id); - crumb_id = mount->host(); - crumb_id = crumb_id.fileSystem()->child_of_directory_inode_with_name(crumb_id, ".."); + auto dir_inode = get_inode(mount->host()); + crumb_id = dir_inode->lookup(".."); } metadata = crumb_id.metadata(); if (metadata.isSymbolicLink()) {