diff --git a/Kernel/FileSystem/Custody.cpp b/Kernel/FileSystem/Custody.cpp new file mode 100644 index 00000000000..39c97618087 --- /dev/null +++ b/Kernel/FileSystem/Custody.cpp @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +static Lockable>& all_custodies() +{ + static Lockable>* table; + if (!table) + table = new Lockable>; + return *table; +} + +Custody::Custody(Custody* parent, const String& name, Inode& inode) + : m_parent(parent) + , m_name(name) + , m_inode(inode) +{ + LOCKER(all_custodies().lock()); + all_custodies().resource().set(this); +} + +Custody::~Custody() +{ + LOCKER(all_custodies().lock()); + all_custodies().resource().remove(this); +} diff --git a/Kernel/FileSystem/Custody.h b/Kernel/FileSystem/Custody.h new file mode 100644 index 00000000000..06cf20b69ee --- /dev/null +++ b/Kernel/FileSystem/Custody.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +class Inode; + +class Custody : public Retainable { +public: + static Retained create(Custody* parent, const String& name, Inode& inode) + { + return adopt(*new Custody(parent, name, inode)); + } + + ~Custody(); + + Custody* parent() { return m_parent.ptr(); } + const Custody* parent() const { return m_parent.ptr(); } + + Inode& inode() { return *m_inode; } + const Inode& inode() const { return *m_inode; } + + const String& name() const { return m_name; } + +private: + Custody(Custody* parent, const String& name, Inode&); + + RetainPtr m_parent; + String m_name; + Retained m_inode; +}; diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index ec8b32ef159..dfe1c56a3de 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -6,6 +6,7 @@ #include #include #include +#include //#define VFS_DEBUG @@ -739,3 +740,77 @@ void VFS::sync() { FS::sync(); } + +Custody& VFS::root_custody() +{ + if (!m_root_custody) + m_root_custody = Custody::create(nullptr, "", *root_inode()); + return *m_root_custody; +} + +KResultOr> VFS::resolve_path_to_custody(StringView path, Custody& base, int options) +{ + if (path.is_empty()) + return KResult(-EINVAL); + + auto parts = path.split_view('/'); + InodeIdentifier crumb_id; + + Vector, 32> custody_chain; + + if (path[0] == '/') { + custody_chain.append(Retained(base)); + crumb_id = root_inode_id(); + } else { + for (auto* custody = &base; custody; custody = custody->parent()) { + // FIXME: Prepending here is not efficient! Fix this. + custody_chain.prepend(*custody); + } + crumb_id = base.inode().identifier(); + } + + for (int i = 0; i < parts.size(); ++i) { + bool inode_was_root_at_head_of_loop = crumb_id.is_root_inode(); + auto& part = parts[i]; + if (part.is_empty()) + break; + auto crumb_inode = get_inode(crumb_id); + if (!crumb_inode) + return KResult(-EIO); + auto metadata = crumb_inode->metadata(); + if (!metadata.is_directory()) + return KResult(-ENOTDIR); + if (!metadata.may_execute(current->process())) + return KResult(-EACCES); + auto parent = crumb_id; + crumb_id = crumb_inode->lookup(part); + if (!crumb_id.is_valid()) + return KResult(-ENOENT); + if (auto mount = find_mount_for_host(crumb_id)) + crumb_id = mount->guest(); + if (inode_was_root_at_head_of_loop && crumb_id.is_root_inode() && !is_vfs_root(crumb_id) && part == "..") { + auto mount = find_mount_for_guest(crumb_id); + auto dir_inode = get_inode(mount->host()); + ASSERT(dir_inode); + crumb_id = dir_inode->lookup(".."); + } + crumb_inode = get_inode(crumb_id); + ASSERT(crumb_inode); + custody_chain.append(Custody::create(custody_chain.last().ptr(), part, *crumb_inode)); + metadata = crumb_inode->metadata(); + if (metadata.is_symlink()) { + if (i == parts.size() - 1) { + if (options & O_NOFOLLOW) + return KResult(-ELOOP); + if (options & O_NOFOLLOW_NOERROR) + return custody_chain.last(); + } + auto result = resolve_symbolic_link(parent, *crumb_inode); + if (result.is_error()) + return KResult(-ENOENT); + crumb_id = result.value(); + ASSERT(crumb_id.is_valid()); + } + } + return custody_chain.last(); +} diff --git a/Kernel/FileSystem/VirtualFileSystem.h b/Kernel/FileSystem/VirtualFileSystem.h index 04ef61a432b..0dbef2bb36b 100644 --- a/Kernel/FileSystem/VirtualFileSystem.h +++ b/Kernel/FileSystem/VirtualFileSystem.h @@ -25,6 +25,7 @@ #define O_CLOEXEC 02000000 #define O_NOFOLLOW_NOERROR 0x4000000 +class Custody; class Device; class FileDescriptor; @@ -96,6 +97,9 @@ public: Device* get_device(unsigned major, unsigned minor); + Custody& root_custody(); + KResultOr> resolve_path_to_custody(StringView path, Custody& base, int options = 0); + private: friend class FileDescriptor; @@ -115,4 +119,6 @@ private: RetainPtr m_root_inode; Vector> m_mounts; HashMap m_devices; + + RetainPtr m_root_custody; }; diff --git a/Kernel/Makefile b/Kernel/Makefile index 660f18fe7c7..1593bfc41cc 100644 --- a/Kernel/Makefile +++ b/Kernel/Makefile @@ -50,6 +50,7 @@ KERNEL_OBJS = \ ProcessTracer.o \ Devices/PCSpeaker.o \ FileSystem/InodeFile.o \ + FileSystem/Custody.o \ File.o VFS_OBJS = \