소스 검색

Add a VFS::absolutePath(InodeIdentifier).

This is pretty inefficient for ext2fs. We walk the entire block group
containing the inode, searching through every directory for an entry
referencing this inode.

It might be a good idea to cache this information somehow. I'm not sure
how often we'll be searching for it.

Obviously there are multiple caching layers missing in the file system.
Andreas Kling 6 년 전
부모
커밋
1d4af51250

+ 2 - 1
Kernel/Makefile

@@ -43,7 +43,8 @@ ELFLOADER_OBJS = \
 
 AK_OBJS = \
     ../AK/String.o \
-    ../AK/StringImpl.o
+    ../AK/StringImpl.o \
+    ../AK/StringBuilder.o
 
 OBJS = $(KERNEL_OBJS) $(VFS_OBJS) $(AK_OBJS) $(ELFLOADER_OBJS)
 

+ 4 - 4
Kernel/Task.cpp

@@ -234,7 +234,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren
             cwd = parentTask->m_cwd.copyRef();
     }
 
-    auto handle = VirtualFileSystem::the().open(path, cwd.ptr());
+    auto handle = VirtualFileSystem::the().open(path, cwd ? cwd->inode : InodeIdentifier());
     if (!handle) {
         error = -ENOENT; // FIXME: Get a more detailed error from VFS.
         return nullptr;
@@ -785,7 +785,7 @@ int Task::sys$close(int fd)
 int Task::sys$lstat(const char* path, Unix::stat* statbuf)
 {
     VALIDATE_USER_BUFFER(statbuf, sizeof(Unix::stat));
-    auto handle = VirtualFileSystem::the().open(move(path), m_cwd.ptr());
+    auto handle = VirtualFileSystem::the().open(move(path), cwdInode());
     if (!handle)
         return -1;
     handle->stat(statbuf);
@@ -795,7 +795,7 @@ int Task::sys$lstat(const char* path, Unix::stat* statbuf)
 int Task::sys$chdir(const char* path)
 {
     VALIDATE_USER_BUFFER(path, strlen(path));
-    auto handle = VirtualFileSystem::the().open(path, m_cwd.ptr());
+    auto handle = VirtualFileSystem::the().open(path, cwdInode());
     if (!handle)
         return -ENOENT; // FIXME: More detailed error.
     if (!handle->isDirectory())
@@ -819,7 +819,7 @@ int Task::sys$open(const char* path, size_t pathLength)
     VALIDATE_USER_BUFFER(path, pathLength);
     if (m_fileHandles.size() >= m_maxFileHandles)
         return -EMFILE;
-    auto handle = VirtualFileSystem::the().open(String(path, pathLength), m_cwd.ptr());
+    auto handle = VirtualFileSystem::the().open(String(path, pathLength), cwdInode());
     if (!handle)
         return -ENOENT; // FIXME: Detailed error.
     int fd = m_fileHandles.size();

+ 2 - 0
Kernel/Task.h

@@ -133,6 +133,8 @@ public:
     bool isValidAddressForKernel(LinearAddress) const;
     bool isValidAddressForUser(LinearAddress) const;
 
+    InodeIdentifier cwdInode() const { return m_cwd ? m_cwd->inode : InodeIdentifier(); }
+
 private:
     friend class MemoryManager;
     friend bool scheduleNewTask();

+ 32 - 0
VirtualFileSystem/Ext2FileSystem.cpp

@@ -943,3 +943,35 @@ InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const S
     return { id(), inode };
 }
 
+InodeIdentifier Ext2FileSystem::findParentOfInode(InodeIdentifier inode) const
+{
+    ASSERT(inode.fileSystemID() == id());
+    unsigned groupIndex = groupIndexFromInode(inode.index());
+    unsigned firstInodeInGroup = inodesPerGroup() * (groupIndex - 1);
+
+    Vector<InodeIdentifier> directoriesInGroup;
+
+    for (unsigned i = 0; i < inodesPerGroup(); ++i) {
+        auto e2inode = lookupExt2Inode(firstInodeInGroup + i);
+        if (!e2inode)
+            continue;
+        if (isDirectory(e2inode->i_mode)) {
+            directoriesInGroup.append({ id(), firstInodeInGroup + i });
+        }
+    }
+
+    InodeIdentifier foundParent;
+    for (auto& directory : directoriesInGroup) {
+        enumerateDirectoryInode(directory, [inode, directory, &foundParent] (auto& entry) {
+            if (entry.inode == inode) {
+                foundParent = directory;
+                return false;
+            }
+            return true;
+        });
+        if (foundParent.isValid())
+            break;
+    }
+
+    return foundParent;
+}

+ 1 - 0
VirtualFileSystem/Ext2FileSystem.h

@@ -46,6 +46,7 @@ private:
     virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
     virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileHandle*) const override;
     virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
+    virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override;
 
     bool isDirectoryInode(unsigned) const;
     unsigned allocateInode(unsigned preferredGroup, unsigned expectedSize);

+ 14 - 0
VirtualFileSystem/FileSystem.cpp

@@ -50,6 +50,20 @@ InodeIdentifier FileSystem::childOfDirectoryInodeWithName(InodeIdentifier inode,
     return foundInode;
 }
 
+String FileSystem::nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifier child) const
+{
+    String name;
+    bool success = enumerateDirectoryInode(parent, [&] (auto& entry) {
+        if (entry.inode == child) {
+            name = entry.name;
+            return false;
+        }
+        return true;
+    });
+    ASSERT(success);
+    return name;
+}
+
 ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileHandle* handle) const
 {
     ASSERT(inode.fileSystemID() == id());

+ 3 - 0
VirtualFileSystem/FileSystem.h

@@ -45,8 +45,11 @@ public:
     virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) = 0;
     virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) = 0;
 
+    virtual InodeIdentifier findParentOfInode(InodeIdentifier) const = 0;
+
     InodeIdentifier childOfDirectoryInodeWithName(InodeIdentifier, const String& name) const;
     ByteBuffer readEntireInode(InodeIdentifier, FileHandle* = nullptr) const;
+    String nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifier child) const;
 
 protected:
     FileSystem();

+ 9 - 1
VirtualFileSystem/SyntheticFileSystem.cpp

@@ -199,7 +199,7 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o
 #endif
     ASSERT(offset >= 0);
     ASSERT(buffer);
-\
+
     auto it = m_inodes.find(inode.index());
     if (it == m_inodes.end())
         return false;
@@ -235,3 +235,11 @@ auto SyntheticFileSystem::generateInodeIndex() -> InodeIndex
 {
     return m_nextInodeIndex++;
 }
+
+InodeIdentifier SyntheticFileSystem::findParentOfInode(InodeIdentifier inode) const
+{
+    auto it = m_inodes.find(inode.index());
+    if (it == m_inodes.end())
+        return { };
+    return (*it).value->parent;
+}

+ 1 - 0
VirtualFileSystem/SyntheticFileSystem.h

@@ -19,6 +19,7 @@ public:
     virtual InodeIdentifier createInode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size) override;
     virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileHandle*) const override;
     virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
+    virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override;
 
 protected:
     typedef unsigned InodeIndex;

+ 41 - 6
VirtualFileSystem/VirtualFileSystem.cpp

@@ -1,6 +1,7 @@
 #include "VirtualFileSystem.h"
 #include "FileHandle.h"
 #include "FileSystem.h"
+#include <AK/StringBuilder.h>
 #include <AK/kmalloc.h>
 #include <AK/kstdio.h>
 #include <AK/ktime.h>
@@ -169,7 +170,7 @@ void VirtualFileSystem::freeNode(Node* node)
     m_nodeFreeList.append(move(node));
 }
 
-bool VirtualFileSystem::isDirectory(const String& path, Node* base)
+bool VirtualFileSystem::isDirectory(const String& path, InodeIdentifier base)
 {
     auto inode = resolvePath(path, base);
     if (!inode.isValid())
@@ -356,7 +357,7 @@ bool VirtualFileSystem::touch(const String& path)
     return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
 }
 
-OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, Node* base)
+OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, InodeIdentifier base)
 {
     Locker locker(VirtualFileSystem::lock());
 
@@ -369,7 +370,7 @@ OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, Node* base)
     return make<FileHandle>(move(vnode));
 }
 
-OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, Node* base)
+OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, InodeIdentifier base)
 {
     Locker locker(VirtualFileSystem::lock());
 
@@ -379,7 +380,7 @@ OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, Node* base)
     return nullptr;
 }
 
-OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path, Node* base)
+OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path, InodeIdentifier base)
 {
     Locker locker(VirtualFileSystem::lock());
 
@@ -399,7 +400,41 @@ InodeIdentifier VirtualFileSystem::resolveSymbolicLink(const String& basePath, I
     return resolvePath(buf);
 }
 
-InodeIdentifier VirtualFileSystem::resolvePath(const String& path, Node* base)
+String VirtualFileSystem::absolutePath(InodeIdentifier inode)
+{
+    Locker locker(VirtualFileSystem::lock());
+
+    if (!inode.isValid())
+        return String();
+
+    Vector<InodeIdentifier> lineage;
+    while (inode != m_rootNode->inode) {
+        if (auto* mount = findMountForGuest(inode))
+            lineage.append(mount->host());
+        else
+            lineage.append(inode);
+        if (inode.metadata().isDirectory()) {
+            inode = resolvePath("..", inode);
+        } else
+            inode = inode.fileSystem()->findParentOfInode(inode);
+        ASSERT(inode.isValid());
+    }
+    if (lineage.isEmpty())
+        return "/";
+    lineage.append(m_rootNode->inode);
+    StringBuilder builder;
+    for (size_t i = lineage.size() - 1; i >= 1; --i) {
+        auto& child = lineage[i - 1];
+        auto parent = lineage[i];
+        if (auto* mount = findMountForHost(parent))
+            parent = mount->guest();
+        builder.append('/');
+        builder.append(parent.fileSystem()->nameOfChildInDirectory(parent, child));
+    }
+    return builder.build();
+}
+
+InodeIdentifier VirtualFileSystem::resolvePath(const String& path, InodeIdentifier base)
 {
     if (path.isEmpty())
         return { };
@@ -410,7 +445,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, Node* base)
     if (path[0] == '/')
         inode = m_rootNode->inode;
     else
-        inode = base ? base->inode : m_rootNode->inode;
+        inode = base.isValid() ? base : m_rootNode->inode;
 
     for (unsigned i = 0; i < parts.size(); ++i) {
         bool wasRootInodeAtHeadOfLoop = inode.isRootInode();

+ 7 - 6
VirtualFileSystem/VirtualFileSystem.h

@@ -66,7 +66,7 @@ public:
     VirtualFileSystem();
     ~VirtualFileSystem();
 
-    bool isDirectory(const String& path, Node* base = nullptr);
+    bool isDirectory(const String& path, InodeIdentifier base = InodeIdentifier());
     void listDirectory(const String& path);
     void listDirectoryRecursively(const String& path);
 
@@ -79,9 +79,9 @@ public:
     bool mountRoot(RetainPtr<FileSystem>&&);
     bool mount(RetainPtr<FileSystem>&&, const String& path);
 
-    OwnPtr<FileHandle> open(const String& path, Node* base = nullptr);
-    OwnPtr<FileHandle> create(const String& path, Node* base = nullptr);
-    OwnPtr<FileHandle> mkdir(const String& path, Node* base = nullptr);
+    OwnPtr<FileHandle> open(const String& path, InodeIdentifier base = InodeIdentifier());
+    OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier());
+    OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier());
 
     bool isRoot(InodeIdentifier) const;
 
@@ -92,12 +92,13 @@ public:
     size_t mountCount() const { return m_mounts.size(); }
     void forEachMount(Function<void(const Mount&)>) const;
 
+    String absolutePath(InodeIdentifier);
+
 private:
     friend class FileHandle;
 
     void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>);
-    String absolutePath(InodeIdentifier);
-    InodeIdentifier resolvePath(const String& path, Node* base = nullptr);
+    InodeIdentifier resolvePath(const String& path, InodeIdentifier base = InodeIdentifier());
     InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode);
 
     RetainPtr<Node> allocateNode();