Ver Fonte

More work on CoreInode.

Andreas Kling há 6 anos atrás
pai
commit
c735c56e4c

+ 24 - 20
Kernel/ProcFileSystem.cpp

@@ -134,15 +134,17 @@ ByteBuffer procfs$pid_regs(Process& process)
 ByteBuffer procfs$pid_exe(Process& process)
 {
     ProcessInspectionHandle handle(process);
-    auto inode = process.executableInode();
-    return VirtualFileSystem::the().absolutePath(inode).toByteBuffer();
+    auto inode = process.executable_inode();
+    ASSERT(inode);
+    return VirtualFileSystem::the().absolute_path(*inode).toByteBuffer();
 }
 
 ByteBuffer procfs$pid_cwd(Process& process)
 {
     ProcessInspectionHandle handle(process);
-    auto inode = process.cwdInode();
-    return VirtualFileSystem::the().absolutePath(inode).toByteBuffer();
+    auto inode = process.cwd_inode();
+    ASSERT(inode);
+    return VirtualFileSystem::the().absolute_path(*inode).toByteBuffer();
 }
 
 void ProcFileSystem::addProcess(Process& process)
@@ -150,15 +152,15 @@ void ProcFileSystem::addProcess(Process& process)
     InterruptDisabler disabler;
     char buf[16];
     ksprintf(buf, "%d", process.pid());
-    auto dir = addFile(createDirectory(buf));
+    auto dir = addFile(create_directory(buf));
     m_pid2inode.set(process.pid(), dir.index());
-    addFile(createGeneratedFile("vm", [&process] { return procfs$pid_vm(process); }), dir.index());
-    addFile(createGeneratedFile("stack", [&process] { return procfs$pid_stack(process); }), dir.index());
-    addFile(createGeneratedFile("regs", [&process] { return procfs$pid_regs(process); }), dir.index());
-    addFile(createGeneratedFile("fds", [&process] { return procfs$pid_fds(process); }), dir.index());
-    if (process.executableInode().isValid())
-        addFile(createGeneratedFile("exe", [&process] { return procfs$pid_exe(process); }, 00120777), dir.index());
-    addFile(createGeneratedFile("cwd", [&process] { return procfs$pid_cwd(process); }, 00120777), dir.index());
+    addFile(create_generated_file("vm", [&process] { return procfs$pid_vm(process); }), dir.index());
+    addFile(create_generated_file("stack", [&process] { return procfs$pid_stack(process); }), dir.index());
+    addFile(create_generated_file("regs", [&process] { return procfs$pid_regs(process); }), dir.index());
+    addFile(create_generated_file("fds", [&process] { return procfs$pid_fds(process); }), dir.index());
+    if (process.executable_inode())
+        addFile(create_generated_file("exe", [&process] { return procfs$pid_exe(process); }, 00120777), dir.index());
+    addFile(create_generated_file("cwd", [&process] { return procfs$pid_cwd(process); }, 00120777), dir.index());
 }
 
 void ProcFileSystem::removeProcess(Process& process)
@@ -336,7 +338,9 @@ ByteBuffer procfs$vnodes()
         // FIXME: Retain the vnode while inspecting it.
         if (!vnode.inUse())
             continue;
-        auto path = vfs.absolutePath(vnode.inode);
+        String path;
+        if (vnode.core_inode())
+            path = vfs.absolute_path(*vnode.core_inode());
         if (path.isEmpty()) {
             if (auto* dev = vnode.characterDevice()) {
                 if (dev->isTTY())
@@ -353,13 +357,13 @@ ByteBuffer procfs$vnodes()
 bool ProcFileSystem::initialize()
 {
     SyntheticFileSystem::initialize();
-    addFile(createGeneratedFile("mm", procfs$mm));
-    addFile(createGeneratedFile("regions", procfs$regions));
-    addFile(createGeneratedFile("mounts", procfs$mounts));
-    addFile(createGeneratedFile("kmalloc", procfs$kmalloc));
-    addFile(createGeneratedFile("summary", procfs$summary));
-    addFile(createGeneratedFile("cpuinfo", procfs$cpuinfo));
-    addFile(createGeneratedFile("vnodes", procfs$vnodes));
+    addFile(create_generated_file("mm", procfs$mm));
+    addFile(create_generated_file("regions", procfs$regions));
+    addFile(create_generated_file("mounts", procfs$mounts));
+    addFile(create_generated_file("kmalloc", procfs$kmalloc));
+    addFile(create_generated_file("summary", procfs$summary));
+    addFile(create_generated_file("cpuinfo", procfs$cpuinfo));
+    addFile(create_generated_file("vnodes", procfs$vnodes));
     return true;
 }
 

+ 7 - 6
Kernel/Process.cpp

@@ -1124,7 +1124,7 @@ int Process::sys$lstat(const char* path, Unix::stat* statbuf)
 {
     VALIDATE_USER_WRITE(statbuf, sizeof(Unix::stat));
     int error;
-    auto descriptor = VirtualFileSystem::the().open(move(path), error, O_NOFOLLOW_NOERROR, cwdInode());
+    auto descriptor = VirtualFileSystem::the().open(move(path), error, O_NOFOLLOW_NOERROR, cwd_inode()->identifier());
     if (!descriptor)
         return error;
     descriptor->stat(statbuf);
@@ -1135,7 +1135,7 @@ int Process::sys$stat(const char* path, Unix::stat* statbuf)
 {
     VALIDATE_USER_WRITE(statbuf, sizeof(Unix::stat));
     int error;
-    auto descriptor = VirtualFileSystem::the().open(move(path), error, 0, cwdInode());
+    auto descriptor = VirtualFileSystem::the().open(move(path), error, 0, cwd_inode()->identifier());
     if (!descriptor)
         return error;
     descriptor->stat(statbuf);
@@ -1148,7 +1148,7 @@ int Process::sys$readlink(const char* path, char* buffer, size_t size)
     VALIDATE_USER_WRITE(buffer, size);
 
     int error;
-    auto descriptor = VirtualFileSystem::the().open(path, error, O_RDONLY | O_NOFOLLOW_NOERROR, cwdInode());
+    auto descriptor = VirtualFileSystem::the().open(path, error, O_RDONLY | O_NOFOLLOW_NOERROR, cwd_inode()->identifier());
     if (!descriptor)
         return error;
 
@@ -1169,7 +1169,7 @@ int Process::sys$chdir(const char* path)
 {
     VALIDATE_USER_READ(path, strlen(path));
     int error;
-    auto descriptor = VirtualFileSystem::the().open(path, error, 0, cwdInode());
+    auto descriptor = VirtualFileSystem::the().open(path, error, 0, cwd_inode()->identifier());
     if (!descriptor)
         return error;
     if (!descriptor->isDirectory())
@@ -1181,7 +1181,8 @@ int Process::sys$chdir(const char* path)
 int Process::sys$getcwd(char* buffer, size_t size)
 {
     VALIDATE_USER_WRITE(buffer, size);
-    auto path = VirtualFileSystem::the().absolutePath(cwdInode());
+    ASSERT(cwd_inode());
+    auto path = VirtualFileSystem::the().absolute_path(*cwd_inode());
     if (path.isNull())
         return -EINVAL;
     if (size < path.length() + 1)
@@ -1209,7 +1210,7 @@ int Process::sys$open(const char* path, int options)
     if (number_of_open_file_descriptors() >= m_max_open_file_descriptors)
         return -EMFILE;
     int error;
-    auto descriptor = VirtualFileSystem::the().open(path, error, options, cwdInode());
+    auto descriptor = VirtualFileSystem::the().open(path, error, options, cwd_inode()->identifier());
     if (!descriptor)
         return error;
     if (options & O_DIRECTORY && !descriptor->isDirectory())

+ 2 - 2
Kernel/Process.h

@@ -200,8 +200,8 @@ public:
     bool validate_user_read(LinearAddress) const;
     bool validate_user_write(LinearAddress) const;
 
-    InodeIdentifier cwdInode() const { return m_cwd ? m_cwd->inode : InodeIdentifier(); }
-    InodeIdentifier executableInode() const { return m_executable ? m_executable->inode : InodeIdentifier(); }
+    CoreInode* cwd_inode() { return m_cwd ? m_cwd->core_inode() : nullptr; }
+    CoreInode* executable_inode() { return m_executable ? m_executable->core_inode() : nullptr; }
 
     size_t number_of_open_file_descriptors() const;
     size_t max_open_file_descriptors() const { return m_max_open_file_descriptors; }

+ 41 - 15
VirtualFileSystem/Ext2FileSystem.cpp

@@ -342,7 +342,7 @@ void Ext2Inode::populate_metadata() const
     }
 }
 
-RetainPtr<CoreInode> Ext2FileSystem::get_inode(InodeIdentifier inode)
+RetainPtr<CoreInode> Ext2FileSystem::get_inode(InodeIdentifier inode) const
 {
     ASSERT(inode.fileSystemID() == id());
     {
@@ -358,7 +358,7 @@ RetainPtr<CoreInode> Ext2FileSystem::get_inode(InodeIdentifier inode)
     auto it = m_inode_cache.find(inode.index());
     if (it != m_inode_cache.end())
         return (*it).value;
-    auto new_inode = adopt(*new Ext2Inode(*this, inode.index(), *raw_inode));
+    auto new_inode = adopt(*new Ext2Inode(const_cast<Ext2FileSystem&>(*this), inode.index(), *raw_inode));
     m_inode_cache.set(inode.index(), new_inode.copyRef());
     return new_inode;
 }
@@ -536,6 +536,31 @@ bool Ext2FileSystem::writeInode(InodeIdentifier inode, const ByteBuffer& data)
     return true;
 }
 
+bool Ext2Inode::traverse_as_directory(Function<bool(const FileSystem::DirectoryEntry&)> callback)
+{
+    ASSERT(metadata().isDirectory());
+
+#ifdef EXT2_DEBUG
+    kprintf("Ext2Inode::traverse_as_directory: inode=%u:\n", index());
+#endif
+
+    auto buffer = read_entire();
+    ASSERT(buffer);
+    auto* entry = reinterpret_cast<ext2_dir_entry_2*>(buffer.pointer());
+
+    while (entry < buffer.endPointer()) {
+        if (entry->inode != 0) {
+#ifdef EXT2_DEBUG
+            kprintf("Ext2Inode::traverse_as_directory: %u, name_len: %u, rec_len: %u, file_type: %u, name: %s\n", entry->inode, entry->name_len, entry->rec_len, entry->file_type, namebuf);
+#endif
+            if (!callback({ entry->name, entry->name_len, { fsid(), entry->inode }, entry->file_type }))
+                break;
+        }
+        entry = (ext2_dir_entry_2*)((char*)entry + entry->rec_len);
+    }
+    return true;
+}
+
 bool Ext2FileSystem::enumerateDirectoryInode(InodeIdentifier inode, Function<bool(const DirectoryEntry&)> callback) const
 {
     ASSERT(inode.fileSystemID() == id());
@@ -1094,28 +1119,29 @@ InodeIdentifier Ext2FileSystem::createInode(InodeIdentifier parentInode, const S
     return { id(), inode };
 }
 
-InodeIdentifier Ext2FileSystem::findParentOfInode(InodeIdentifier inode) const
+InodeIdentifier Ext2FileSystem::findParentOfInode(InodeIdentifier inode_id) const
 {
-    ASSERT(inode.fileSystemID() == id());
-    unsigned groupIndex = groupIndexFromInode(inode.index());
+    auto inode = get_inode(inode_id);
+    ASSERT(inode);
+
+    unsigned groupIndex = groupIndexFromInode(inode->index());
     unsigned firstInodeInGroup = inodesPerGroup() * (groupIndex - 1);
 
-    Vector<InodeIdentifier> directoriesInGroup;
+    Vector<RetainPtr<Ext2Inode>> directories_in_group;
 
     for (unsigned i = 0; i < inodesPerGroup(); ++i) {
-        auto e2inode = lookupExt2Inode(firstInodeInGroup + i);
-        if (!e2inode)
+        auto group_member = get_inode({ id(), firstInodeInGroup + i });
+        if (!group_member)
             continue;
-        if (isDirectory(e2inode->i_mode)) {
-            directoriesInGroup.append({ id(), firstInodeInGroup + i });
-        }
+        if (group_member->is_directory())
+            directories_in_group.append(move(group_member));
     }
 
     InodeIdentifier foundParent;
-    for (auto& directory : directoriesInGroup) {
-        enumerateDirectoryInode(directory, [inode, directory, &foundParent] (auto& entry) {
-            if (entry.inode == inode) {
-                foundParent = directory;
+    for (auto& directory : directories_in_group) {
+        directory->traverse_as_directory([inode, directory, &foundParent] (auto& entry) {
+            if (entry.inode == inode->identifier()) {
+                foundParent = directory->identifier();
                 return false;
             }
             return true;

+ 2 - 1
VirtualFileSystem/Ext2FileSystem.h

@@ -24,6 +24,7 @@ private:
     // ^CoreInode
     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<bool(const FileSystem::DirectoryEntry&)>) override;
 
     Ext2FileSystem& fs();
     const Ext2FileSystem& fs() const;
@@ -75,7 +76,7 @@ private:
     virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override;
     virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
     virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override;
-    virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) override;
+    virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) const override;
 
     bool isDirectoryInode(unsigned) const;
     unsigned allocateInode(unsigned preferredGroup, unsigned expectedSize);

+ 6 - 2
VirtualFileSystem/FileDescriptor.cpp

@@ -194,6 +194,8 @@ ByteBuffer FileDescriptor::readEntireFile()
         return buffer;
     }
 
+    if (m_vnode->core_inode())
+        return m_vnode->core_inode()->read_entire(this);
     return m_vnode->fileSystem()->readEntireInode(m_vnode->inode, this);
 }
 
@@ -263,8 +265,9 @@ int FileDescriptor::close()
     return 0;
 }
 
-String FileDescriptor::absolute_path() const
+String FileDescriptor::absolute_path()
 {
+    Stopwatch sw("absolute_path");
 #ifdef SERENITY
     if (isTTY())
         return tty()->ttyName();
@@ -274,7 +277,8 @@ String FileDescriptor::absolute_path() const
         ksprintf(buf, "fifo:%x", m_fifo.ptr());
         return buf;
     }
-    return VirtualFileSystem::the().absolutePath(m_vnode->inode);
+    ASSERT(m_vnode->core_inode());
+    return VirtualFileSystem::the().absolute_path(*m_vnode->core_inode());
 }
 
 FileDescriptor::FileDescriptor(FIFO& fifo, FIFO::Direction direction)

+ 1 - 1
VirtualFileSystem/FileDescriptor.h

@@ -34,7 +34,7 @@ public:
 
     ByteBuffer readEntireFile();
 
-    String absolute_path() const;
+    String absolute_path();
 
     bool isDirectory() const;
 

+ 32 - 0
VirtualFileSystem/FileSystem.cpp

@@ -64,6 +64,38 @@ String FileSystem::nameOfChildInDirectory(InodeIdentifier parent, InodeIdentifie
     return name;
 }
 
+ByteBuffer CoreInode::read_entire(FileDescriptor* descriptor)
+{
+    return fs().readEntireInode(identifier(), descriptor);
+/*
+    size_t initial_size = metadata().size ? metadata().size : 4096;
+    auto contents = ByteBuffer::createUninitialized(initial_size);
+
+    Unix::ssize_t nread;
+    byte buffer[4096];
+    byte* out = contents.pointer();
+    Unix::off_t offset = 0;
+    for (;;) {
+        nread = read_bytes(offset, sizeof(buffer), buffer, descriptor);
+        //kprintf("nread: %u, bufsiz: %u, initial_size: %u\n", nread, sizeof(buffer), initial_size);
+        ASSERT(nread <= (Unix::ssize_t)sizeof(buffer));
+        if (nread <= 0)
+            break;
+        memcpy(out, buffer, nread);
+        out += nread;
+        offset += nread;
+        ASSERT(offset <= (Unix::ssize_t)initial_size); // FIXME: Support dynamically growing the buffer.
+    }
+    if (nread < 0) {
+        kprintf("CoreInode::read_entire: ERROR: %d\n", nread);
+        return nullptr;
+    }
+
+    contents.trim(offset);
+    return contents;
+    */
+}
+
 ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileDescriptor* handle) const
 {
     ASSERT(inode.fileSystemID() == id());

+ 39 - 31
VirtualFileSystem/FileSystem.h

@@ -16,37 +16,8 @@
 
 static const dword mepoch = 476763780;
 
+class CoreInode;
 class FileDescriptor;
-class FileSystem;
-
-class CoreInode : public Retainable<CoreInode> {
-public:
-    virtual ~CoreInode();
-
-    FileSystem& fs() { return m_fs; }
-    const FileSystem& fs() const { return m_fs; }
-    unsigned fsid() const;
-    unsigned index() const { return m_index; }
-
-    InodeIdentifier identifier() const { return { fsid(), index() }; }
-    const InodeMetadata& metadata() const { if (!m_metadata.isValid()) { populate_metadata(); } return m_metadata; }
-
-    virtual Unix::ssize_t read_bytes(Unix::off_t, Unix::size_t, byte* buffer, FileDescriptor*) = 0;
-
-protected:
-    CoreInode(FileSystem& fs, unsigned index)
-        : m_fs(fs)
-        , m_index(index)
-    {
-    }
-
-    virtual void populate_metadata() const = 0;
-
-    mutable InodeMetadata m_metadata;
-private:
-    FileSystem& m_fs;
-    unsigned m_index { 0 };
-};
 
 class FileSystem : public Retainable<FileSystem> {
 public:
@@ -80,7 +51,7 @@ public:
 
     virtual InodeIdentifier findParentOfInode(InodeIdentifier) const = 0;
 
-    virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) = 0;
+    virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) const = 0;
 
     InodeIdentifier childOfDirectoryInodeWithName(InodeIdentifier, const String& name) const;
     ByteBuffer readEntireInode(InodeIdentifier, FileDescriptor* = nullptr) const;
@@ -93,6 +64,43 @@ private:
     dword m_id { 0 };
 };
 
+class CoreInode : public Retainable<CoreInode> {
+    friend class VirtualFileSystem;
+public:
+    virtual ~CoreInode();
+
+    FileSystem& fs() { return m_fs; }
+    const FileSystem& fs() const { return m_fs; }
+    unsigned fsid() const;
+    unsigned index() const { return m_index; }
+
+    size_t size() const { return metadata().size; }
+    bool is_symlink() const { return metadata().isSymbolicLink(); }
+    bool is_directory() const { return metadata().isDirectory(); }
+
+    InodeIdentifier identifier() const { return { fsid(), index() }; }
+    const InodeMetadata& metadata() const { if (!m_metadata.isValid()) { populate_metadata(); } return m_metadata; }
+
+    virtual Unix::ssize_t read_bytes(Unix::off_t, Unix::size_t, byte* buffer, FileDescriptor*) = 0;
+    virtual bool traverse_as_directory(Function<bool(const FileSystem::DirectoryEntry&)>) = 0;
+
+    ByteBuffer read_entire(FileDescriptor* = nullptr);
+
+protected:
+    CoreInode(FileSystem& fs, unsigned index)
+        : m_fs(fs)
+        , m_index(index)
+    {
+    }
+
+    virtual void populate_metadata() const = 0;
+
+    mutable InodeMetadata m_metadata;
+private:
+    FileSystem& m_fs;
+    unsigned m_index { 0 };
+};
+
 inline FileSystem* InodeIdentifier::fileSystem()
 {
     return FileSystem::fromID(m_fileSystemID);

+ 133 - 67
VirtualFileSystem/SyntheticFileSystem.cpp

@@ -26,15 +26,14 @@ bool SyntheticFileSystem::initialize()
 {
     // Add a File for the root directory.
     // FIXME: This needs work.
-    auto rootDir = make<File>();
-    rootDir->metadata.inode = { id(), RootInodeIndex };
-    rootDir->parent = { id(), RootInodeIndex };
-    rootDir->metadata.mode = 0040555;
-    rootDir->metadata.uid = 0;
-    rootDir->metadata.gid = 0;
-    rootDir->metadata.size = 0;
-    rootDir->metadata.mtime = mepoch;
-    m_inodes.set(RootInodeIndex, move(rootDir));
+    auto root = adopt(*new SynthFSInode(*this, RootInodeIndex));
+    root->m_parent = { id(), RootInodeIndex };
+    root->m_metadata.mode = 0040555;
+    root->m_metadata.uid = 0;
+    root->m_metadata.gid = 0;
+    root->m_metadata.size = 0;
+    root->m_metadata.mtime = mepoch;
+    m_inodes.set(RootInodeIndex, move(root));
 
 #ifndef SERENITY
     addFile(createTextFile("file", String("I'm a synthetic file!\n").toByteBuffer(), 0100644));
@@ -44,56 +43,56 @@ bool SyntheticFileSystem::initialize()
     return true;
 }
 
-auto SyntheticFileSystem::createDirectory(String&& name) -> OwnPtr<File>
+RetainPtr<SynthFSInode> SyntheticFileSystem::create_directory(String&& name)
 {
-    auto file = make<File>();
-    file->name = move(name);
-    file->metadata.size = 0;
-    file->metadata.uid = 0;
-    file->metadata.gid = 0;
-    file->metadata.mode = 0040555;
-    file->metadata.mtime = mepoch;
+    auto file = adopt(*new SynthFSInode(*this, generateInodeIndex()));
+    file->m_name = move(name);
+    file->m_metadata.size = 0;
+    file->m_metadata.uid = 0;
+    file->m_metadata.gid = 0;
+    file->m_metadata.mode = 0040555;
+    file->m_metadata.mtime = mepoch;
     return file;
 }
 
-auto SyntheticFileSystem::createTextFile(String&& name, ByteBuffer&& contents, Unix::mode_t mode) -> OwnPtr<File>
+RetainPtr<SynthFSInode> SyntheticFileSystem::create_text_file(String&& name, ByteBuffer&& contents, Unix::mode_t mode)
 {
-    auto file = make<File>();
-    file->data = contents;
-    file->name = move(name);
-    file->metadata.size = file->data.size();
-    file->metadata.uid = 100;
-    file->metadata.gid = 200;
-    file->metadata.mode = mode;
-    file->metadata.mtime = mepoch;
+    auto file = adopt(*new SynthFSInode(*this, generateInodeIndex()));
+    file->m_data = contents;
+    file->m_name = move(name);
+    file->m_metadata.size = file->m_data.size();
+    file->m_metadata.uid = 100;
+    file->m_metadata.gid = 200;
+    file->m_metadata.mode = mode;
+    file->m_metadata.mtime = mepoch;
     return file;
 }
 
-auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer()>&& generator, Unix::mode_t mode) -> OwnPtr<File>
+RetainPtr<SynthFSInode> SyntheticFileSystem::create_generated_file(String&& name, Function<ByteBuffer()>&& generator, Unix::mode_t mode)
 {
-    auto file = make<File>();
-    file->generator = move(generator);
-    file->name = move(name);
-    file->metadata.size = 0;
-    file->metadata.uid = 0;
-    file->metadata.gid = 0;
-    file->metadata.mode = mode;
-    file->metadata.mtime = mepoch;
+    auto file = adopt(*new SynthFSInode(*this, generateInodeIndex()));
+    file->m_generator = move(generator);
+    file->m_name = move(name);
+    file->m_metadata.size = 0;
+    file->m_metadata.uid = 0;
+    file->m_metadata.gid = 0;
+    file->m_metadata.mode = mode;
+    file->m_metadata.mtime = mepoch;
     return file;
 }
 
-InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex parent)
+InodeIdentifier SyntheticFileSystem::addFile(RetainPtr<SynthFSInode>&& file, InodeIndex parent)
 {
     ASSERT_INTERRUPTS_DISABLED();
     ASSERT(file);
     auto it = m_inodes.find(parent);
     ASSERT(it != m_inodes.end());
-    InodeIdentifier newInode { id(), generateInodeIndex() };
-    file->metadata.inode = newInode;
-    file->parent = { id(), parent };
-    (*it).value->children.append(file.ptr());
-    m_inodes.set(newInode.index(), move(file));
-    return newInode;
+    auto new_inode_id = file->identifier();
+    file->m_metadata.inode = new_inode_id;
+    file->m_parent = { id(), parent };
+    (*it).value->m_children.append(file.ptr());
+    m_inodes.set(new_inode_id.index(), move(file));
+    return new_inode_id;
 }
 
 bool SyntheticFileSystem::removeFile(InodeIndex inode)
@@ -104,20 +103,20 @@ bool SyntheticFileSystem::removeFile(InodeIndex inode)
         return false;
     auto& file = *(*it).value;
 
-    auto pit = m_inodes.find(file.parent.index());
+    auto pit = m_inodes.find(file.m_parent.index());
     if (pit == m_inodes.end())
         return false;
     auto& parent = *(*pit).value;
-    for (size_t i = 0; i < parent.children.size(); ++i) {
-        if (parent.children[i]->metadata.inode.index() != inode) {
+    for (size_t i = 0; i < parent.m_children.size(); ++i) {
+        if (parent.m_children[i]->m_metadata.inode.index() != inode) {
             continue;
         }
-        parent.children.remove(i);
+        parent.m_children.remove(i);
         break;
     }
 
-    for (auto& child : file.children)
-        removeFile(child->metadata.inode.index());
+    for (auto& child : file.m_children)
+        removeFile(child->m_metadata.inode.index());
     m_inodes.remove(inode);
     return true;
 }
@@ -141,17 +140,21 @@ bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Functio
 #endif
 
     auto it = m_inodes.find(inode.index());
-    if (it == m_inodes.end())
+    if (it == m_inodes.end()) {
+        kprintf("SynthFS: enumerateDirectoryInode with invalid inode %u\n", inode.index());
         return false;
-    const File& synInode = *(*it).value;
-    if (!synInode.metadata.isDirectory())
+    }
+    const auto& synthfs_inode = *(*it).value;
+    if (!synthfs_inode.m_metadata.isDirectory()) {
+        kprintf("SynthFS: enumerateDirectoryInode with non-directory inode %u\n", inode.index());
         return false;
+    }
 
-    callback({ ".", 1, synInode.metadata.inode, 2 });
-    callback({ "..", 2, synInode.parent, 2 });
+    callback({ ".", 1, synthfs_inode.m_metadata.inode, 2 });
+    callback({ "..", 2, synthfs_inode.m_parent, 2 });
 
-    for (auto& child : synInode.children)
-        callback({ child->name.characters(), child->name.length(), child->metadata.inode, child->metadata.isDirectory() ? (byte)2 : (byte)1 });
+    for (auto& child : synthfs_inode.m_children)
+        callback({ child->m_name.characters(), child->m_name.length(), child->m_metadata.inode, child->m_metadata.isDirectory() ? (byte)2 : (byte)1 });
     return true;
 }
 
@@ -160,13 +163,13 @@ InodeMetadata SyntheticFileSystem::inodeMetadata(InodeIdentifier inode) const
     InterruptDisabler disabler;
     ASSERT(inode.fileSystemID() == id());
 #ifdef SYNTHFS_DEBUG
-    kprintf("synthfs: inodeMetadata(%u)\n", inode.index());
+    kprintf("SynthFS: inodeMetadata(%u)\n", inode.index());
 #endif
 
     auto it = m_inodes.find(inode.index());
     if (it == m_inodes.end())
         return { };
-    return (*it).value->metadata;
+    return (*it).value->m_metadata;
 }
 
 bool SyntheticFileSystem::setModificationTime(InodeIdentifier, dword timestamp)
@@ -196,12 +199,12 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o
 {
     ASSERT(inode.fileSystemID() == id());
 #ifdef SYNTHFS_DEBUG
-    kprintf("synthfs: readInode %u\n", inode.index());
+    kprintf("SynthFS: readInode %u\n", inode.index());
 #endif
     ASSERT(offset >= 0);
     ASSERT(buffer);
 
-    const File* found_file;
+    const SynthFSInode* found_file;
     {
         InterruptDisabler disabler;
         auto it = m_inodes.find(inode.index());
@@ -209,19 +212,19 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o
             return false;
         found_file = (*it).value.ptr();
     }
-    const File& file = *found_file;
+    const SynthFSInode& file = *found_file;
     ByteBuffer generatedData;
-    if (file.generator) {
+    if (file.m_generator) {
         if (!handle) {
-            generatedData = file.generator();
+            generatedData = file.m_generator();
         } else {
             if (!handle->generatorCache())
-                handle->generatorCache() = file.generator();
+                handle->generatorCache() = file.m_generator();
             generatedData = handle->generatorCache();
         }
     }
 
-    auto* data = generatedData ? &generatedData : &file.data;
+    auto* data = generatedData ? &generatedData : &file.m_data;
     Unix::ssize_t nread = min(static_cast<Unix::off_t>(data->size() - offset), static_cast<Unix::off_t>(count));
     memcpy(buffer, data->pointer() + offset, nread);
     if (nread == 0 && handle && handle->generatorCache())
@@ -247,10 +250,73 @@ InodeIdentifier SyntheticFileSystem::findParentOfInode(InodeIdentifier inode) co
     auto it = m_inodes.find(inode.index());
     if (it == m_inodes.end())
         return { };
-    return (*it).value->parent;
+    return (*it).value->m_parent;
+}
+
+RetainPtr<CoreInode> SyntheticFileSystem::get_inode(InodeIdentifier inode) const
+{
+    auto it = m_inodes.find(inode.index());
+    if (it == m_inodes.end())
+        return { };
+    return (*it).value;
+}
+
+SynthFSInode::SynthFSInode(SyntheticFileSystem& fs, unsigned index)
+    : CoreInode(fs, index)
+{
+    m_metadata.inode = { fs.id(), index };
+}
+
+SynthFSInode::~SynthFSInode()
+{
+}
+
+void SynthFSInode::populate_metadata() const
+{
+    // Already done when SynthFS created the file.
+}
+
+Unix::ssize_t SynthFSInode::read_bytes(Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor* descriptor)
+{
+#ifdef SYNTHFS_DEBUG
+    kprintf("SynthFS: read_bytes %u\n", index());
+#endif
+    ASSERT(offset >= 0);
+    ASSERT(buffer);
+
+    ByteBuffer generatedData;
+    if (m_generator) {
+        if (!descriptor) {
+            generatedData = m_generator();
+        } else {
+            if (!descriptor->generatorCache())
+                descriptor->generatorCache() = m_generator();
+            generatedData = descriptor->generatorCache();
+        }
+    }
+
+    auto* data = generatedData ? &generatedData : &m_data;
+    Unix::ssize_t nread = min(static_cast<Unix::off_t>(data->size() - offset), static_cast<Unix::off_t>(count));
+    memcpy(buffer, data->pointer() + offset, nread);
+    if (nread == 0 && descriptor && descriptor->generatorCache())
+        descriptor->generatorCache().clear();
+    return nread;
 }
 
-RetainPtr<CoreInode> SyntheticFileSystem::get_inode(InodeIdentifier)
+bool SynthFSInode::traverse_as_directory(Function<bool(const FileSystem::DirectoryEntry&)> callback)
 {
-    return nullptr;
+    InterruptDisabler disabler;
+#ifdef SYNTHFS_DEBUG
+    kprintf("SynthFS: traverse_as_directory %u\n", index());
+#endif
+
+    if (!m_metadata.isDirectory())
+        return false;
+
+    callback({ ".", 1, m_metadata.inode, 2 });
+    callback({ "..", 2, m_parent, 2 });
+
+    for (auto& child : m_children)
+        callback({ child->m_name.characters(), child->m_name.length(), child->m_metadata.inode, child->m_metadata.isDirectory() ? (byte)2 : (byte)1 });
+    return true;
 }

+ 29 - 15
VirtualFileSystem/SyntheticFileSystem.h

@@ -4,6 +4,8 @@
 #include "UnixTypes.h"
 #include <AK/HashMap.h>
 
+class SynthFSInode;
+
 class SyntheticFileSystem : public FileSystem {
 public:
     virtual ~SyntheticFileSystem() override;
@@ -20,7 +22,7 @@ public:
     virtual Unix::ssize_t readInodeBytes(InodeIdentifier, Unix::off_t offset, Unix::size_t count, byte* buffer, FileDescriptor*) const override;
     virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
     virtual InodeIdentifier findParentOfInode(InodeIdentifier) const override;
-    virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) override;
+    virtual RetainPtr<CoreInode> get_inode(InodeIdentifier) const override;
 
 protected:
     typedef unsigned InodeIndex;
@@ -30,24 +32,36 @@ protected:
 
     SyntheticFileSystem();
 
-    struct File {
-        String name;
-        InodeMetadata metadata;
-        InodeIdentifier parent;
-        ByteBuffer data;
-        Function<ByteBuffer()> generator;
-        Vector<File*> children;
-    };
-
-    OwnPtr<File> createDirectory(String&& name);
-    OwnPtr<File> createTextFile(String&& name, ByteBuffer&&, Unix::mode_t = 0010644);
-    OwnPtr<File> createGeneratedFile(String&& name, Function<ByteBuffer()>&&, Unix::mode_t = 0100644);
+    RetainPtr<SynthFSInode> create_directory(String&& name);
+    RetainPtr<SynthFSInode> create_text_file(String&& name, ByteBuffer&&, Unix::mode_t = 0010644);
+    RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer()>&&, Unix::mode_t = 0100644);
 
-    InodeIdentifier addFile(OwnPtr<File>&&, InodeIndex parent = RootInodeIndex);
+    InodeIdentifier addFile(RetainPtr<SynthFSInode>&&, InodeIndex parent = RootInodeIndex);
     bool removeFile(InodeIndex);
 
 private:
     InodeIndex m_nextInodeIndex { 2 };
-    HashMap<InodeIndex, OwnPtr<File>> m_inodes;
+    HashMap<InodeIndex, RetainPtr<SynthFSInode>> m_inodes;
 };
 
+class SynthFSInode final : public CoreInode {
+    friend class SyntheticFileSystem;
+public:
+    virtual ~SynthFSInode() override;
+
+private:
+    // ^CoreInode
+    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<bool(const FileSystem::DirectoryEntry&)>) override;
+
+    SyntheticFileSystem& fs();
+    const SyntheticFileSystem& fs() const;
+    SynthFSInode(SyntheticFileSystem&, unsigned index);
+
+    String m_name;
+    InodeIdentifier m_parent;
+    ByteBuffer m_data;
+    Function<ByteBuffer()> m_generator;
+    Vector<SynthFSInode*> m_children;
+};

+ 22 - 11
VirtualFileSystem/VirtualFileSystem.cpp

@@ -55,6 +55,8 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
         return nullptr;
 
     auto core_inode = inode.fileSystem()->get_inode(inode);
+    if (core_inode)
+        core_inode->m_metadata = metadata;
 
     InterruptDisabler disabler;
 
@@ -450,23 +452,32 @@ InodeIdentifier VirtualFileSystem::resolveSymbolicLink(InodeIdentifier base, Ino
     return resolvePath(linkee, error, base);
 }
 
-String VirtualFileSystem::absolutePath(InodeIdentifier inode)
+RetainPtr<CoreInode> VirtualFileSystem::get_inode(InodeIdentifier inode_id)
 {
-    if (!inode.isValid())
-        return String();
+    if (!inode_id.isValid())
+        return nullptr;
+    return inode_id.fileSystem()->get_inode(inode_id);
+}
 
+String VirtualFileSystem::absolute_path(CoreInode& core_inode)
+{
     int error;
     Vector<InodeIdentifier> lineage;
-    while (inode != m_rootNode->inode) {
-        if (auto* mount = findMountForGuest(inode))
+    RetainPtr<CoreInode> inode = &core_inode;
+    while (inode->identifier() != m_rootNode->inode) {
+        if (auto* mount = findMountForGuest(inode->identifier()))
             lineage.append(mount->host());
         else
-            lineage.append(inode);
-        if (inode.metadata().isDirectory()) {
-            inode = resolvePath("..", error, inode);
-        } else
-            inode = inode.fileSystem()->findParentOfInode(inode);
-        ASSERT(inode.isValid());
+            lineage.append(inode->identifier());
+
+        InodeIdentifier parent_id;
+        if (inode->is_directory()) {
+            parent_id = resolvePath("..", error, inode->identifier());
+        } else {
+            parent_id = inode->fs().findParentOfInode(inode->identifier());
+        }
+        ASSERT(parent_id.isValid());
+        inode = get_inode(parent_id);
     }
     if (lineage.isEmpty())
         return "/";

+ 4 - 1
VirtualFileSystem/VirtualFileSystem.h

@@ -122,12 +122,15 @@ public:
     size_t mountCount() const { return m_mounts.size(); }
     void forEachMount(Function<void(const Mount&)>) const;
 
-    String absolutePath(InodeIdentifier);
+    String absolute_path(CoreInode&);
 
 private:
     friend class FileDescriptor;
 
+    RetainPtr<CoreInode> get_inode(InodeIdentifier);
+
     void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>);
+    InodeIdentifier resolve_path(const String& path, int& error, CoreInode& base, int options = 0);
     InodeIdentifier resolvePath(const String& path, int& error, InodeIdentifier base = InodeIdentifier(), int options = 0);
     InodeIdentifier resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error);