From c735c56e4cdc6b3a7f292fdf78eb6c04b417afcd Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 13 Nov 2018 23:44:54 +0100 Subject: [PATCH] More work on CoreInode. --- Kernel/ProcFileSystem.cpp | 44 ++--- Kernel/Process.cpp | 13 +- Kernel/Process.h | 4 +- VirtualFileSystem/Ext2FileSystem.cpp | 56 ++++-- VirtualFileSystem/Ext2FileSystem.h | 3 +- VirtualFileSystem/FileDescriptor.cpp | 8 +- VirtualFileSystem/FileDescriptor.h | 2 +- VirtualFileSystem/FileSystem.cpp | 32 ++++ VirtualFileSystem/FileSystem.h | 70 ++++---- VirtualFileSystem/SyntheticFileSystem.cpp | 200 ++++++++++++++-------- VirtualFileSystem/SyntheticFileSystem.h | 44 +++-- VirtualFileSystem/VirtualFileSystem.cpp | 33 ++-- VirtualFileSystem/VirtualFileSystem.h | 5 +- 13 files changed, 342 insertions(+), 172 deletions(-) diff --git a/Kernel/ProcFileSystem.cpp b/Kernel/ProcFileSystem.cpp index 350897774e..4b0afc4aa7 100644 --- a/Kernel/ProcFileSystem.cpp +++ b/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; } diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 85f51032e8..308ea9382d 100644 --- a/Kernel/Process.cpp +++ b/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()) diff --git a/Kernel/Process.h b/Kernel/Process.h index f7915883cb..6a6586dee0 100644 --- a/Kernel/Process.h +++ b/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; } diff --git a/VirtualFileSystem/Ext2FileSystem.cpp b/VirtualFileSystem/Ext2FileSystem.cpp index 4af91e7a87..9707c7ad43 100644 --- a/VirtualFileSystem/Ext2FileSystem.cpp +++ b/VirtualFileSystem/Ext2FileSystem.cpp @@ -342,7 +342,7 @@ void Ext2Inode::populate_metadata() const } } -RetainPtr Ext2FileSystem::get_inode(InodeIdentifier inode) +RetainPtr Ext2FileSystem::get_inode(InodeIdentifier inode) const { ASSERT(inode.fileSystemID() == id()); { @@ -358,7 +358,7 @@ RetainPtr 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(*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 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(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 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 directoriesInGroup; + Vector> 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; diff --git a/VirtualFileSystem/Ext2FileSystem.h b/VirtualFileSystem/Ext2FileSystem.h index d7423cca95..9883774986 100644 --- a/VirtualFileSystem/Ext2FileSystem.h +++ b/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) 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 get_inode(InodeIdentifier) override; + virtual RetainPtr get_inode(InodeIdentifier) const override; bool isDirectoryInode(unsigned) const; unsigned allocateInode(unsigned preferredGroup, unsigned expectedSize); diff --git a/VirtualFileSystem/FileDescriptor.cpp b/VirtualFileSystem/FileDescriptor.cpp index df2ffcfd6c..db5fd24fa1 100644 --- a/VirtualFileSystem/FileDescriptor.cpp +++ b/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) diff --git a/VirtualFileSystem/FileDescriptor.h b/VirtualFileSystem/FileDescriptor.h index 66ebb9f15b..ff81801051 100644 --- a/VirtualFileSystem/FileDescriptor.h +++ b/VirtualFileSystem/FileDescriptor.h @@ -34,7 +34,7 @@ public: ByteBuffer readEntireFile(); - String absolute_path() const; + String absolute_path(); bool isDirectory() const; diff --git a/VirtualFileSystem/FileSystem.cpp b/VirtualFileSystem/FileSystem.cpp index a5aed9be0b..0bedab4f9c 100644 --- a/VirtualFileSystem/FileSystem.cpp +++ b/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()); diff --git a/VirtualFileSystem/FileSystem.h b/VirtualFileSystem/FileSystem.h index 25532e8935..d826ca7ef7 100644 --- a/VirtualFileSystem/FileSystem.h +++ b/VirtualFileSystem/FileSystem.h @@ -16,37 +16,8 @@ static const dword mepoch = 476763780; +class CoreInode; class FileDescriptor; -class FileSystem; - -class CoreInode : public Retainable { -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 { public: @@ -80,7 +51,7 @@ public: virtual InodeIdentifier findParentOfInode(InodeIdentifier) const = 0; - virtual RetainPtr get_inode(InodeIdentifier) = 0; + virtual RetainPtr 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 { + 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) = 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); diff --git a/VirtualFileSystem/SyntheticFileSystem.cpp b/VirtualFileSystem/SyntheticFileSystem.cpp index 8343ffb438..2a4d47b949 100644 --- a/VirtualFileSystem/SyntheticFileSystem.cpp +++ b/VirtualFileSystem/SyntheticFileSystem.cpp @@ -26,15 +26,14 @@ bool SyntheticFileSystem::initialize() { // Add a File for the root directory. // FIXME: This needs work. - auto rootDir = make(); - 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 +RetainPtr SyntheticFileSystem::create_directory(String&& name) { - auto file = make(); - 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 +RetainPtr SyntheticFileSystem::create_text_file(String&& name, ByteBuffer&& contents, Unix::mode_t mode) { - auto file = make(); - 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&& generator, Unix::mode_t mode) -> OwnPtr +RetainPtr SyntheticFileSystem::create_generated_file(String&& name, Function&& generator, Unix::mode_t mode) { - auto file = make(); - 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, InodeIndex parent) +InodeIdentifier SyntheticFileSystem::addFile(RetainPtr&& 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(data->size() - offset), static_cast(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 SyntheticFileSystem::get_inode(InodeIdentifier) +RetainPtr SyntheticFileSystem::get_inode(InodeIdentifier inode) const { - return nullptr; + 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(data->size() - offset), static_cast(count)); + memcpy(buffer, data->pointer() + offset, nread); + if (nread == 0 && descriptor && descriptor->generatorCache()) + descriptor->generatorCache().clear(); + return nread; +} + +bool SynthFSInode::traverse_as_directory(Function callback) +{ + 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; } diff --git a/VirtualFileSystem/SyntheticFileSystem.h b/VirtualFileSystem/SyntheticFileSystem.h index acfe6eefb3..d3854c018c 100644 --- a/VirtualFileSystem/SyntheticFileSystem.h +++ b/VirtualFileSystem/SyntheticFileSystem.h @@ -4,6 +4,8 @@ #include "UnixTypes.h" #include +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 get_inode(InodeIdentifier) override; + virtual RetainPtr 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 generator; - Vector children; - }; + RetainPtr create_directory(String&& name); + RetainPtr create_text_file(String&& name, ByteBuffer&&, Unix::mode_t = 0010644); + RetainPtr create_generated_file(String&& name, Function&&, Unix::mode_t = 0100644); - OwnPtr createDirectory(String&& name); - OwnPtr createTextFile(String&& name, ByteBuffer&&, Unix::mode_t = 0010644); - OwnPtr createGeneratedFile(String&& name, Function&&, Unix::mode_t = 0100644); - - InodeIdentifier addFile(OwnPtr&&, InodeIndex parent = RootInodeIndex); + InodeIdentifier addFile(RetainPtr&&, InodeIndex parent = RootInodeIndex); bool removeFile(InodeIndex); private: InodeIndex m_nextInodeIndex { 2 }; - HashMap> m_inodes; + HashMap> 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) override; + + SyntheticFileSystem& fs(); + const SyntheticFileSystem& fs() const; + SynthFSInode(SyntheticFileSystem&, unsigned index); + + String m_name; + InodeIdentifier m_parent; + ByteBuffer m_data; + Function m_generator; + Vector m_children; +}; diff --git a/VirtualFileSystem/VirtualFileSystem.cpp b/VirtualFileSystem/VirtualFileSystem.cpp index 25bb8bdc29..f5572078fd 100644 --- a/VirtualFileSystem/VirtualFileSystem.cpp +++ b/VirtualFileSystem/VirtualFileSystem.cpp @@ -55,6 +55,8 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr 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 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 lineage; - while (inode != m_rootNode->inode) { - if (auto* mount = findMountForGuest(inode)) + RetainPtr 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 "/"; diff --git a/VirtualFileSystem/VirtualFileSystem.h b/VirtualFileSystem/VirtualFileSystem.h index ebc7c3e779..286506798b 100644 --- a/VirtualFileSystem/VirtualFileSystem.h +++ b/VirtualFileSystem/VirtualFileSystem.h @@ -122,12 +122,15 @@ public: size_t mountCount() const { return m_mounts.size(); } void forEachMount(Function) const; - String absolutePath(InodeIdentifier); + String absolute_path(CoreInode&); private: friend class FileDescriptor; + RetainPtr get_inode(InodeIdentifier); + void enumerateDirectoryInode(InodeIdentifier, Function); + 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);