diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-05-30 17:46:08 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-05-30 17:46:08 +0200 |
commit | 4cb87b17536d64656e3f842a408d00c4072afc9b (patch) | |
tree | 14695838d4b101faec37286a8dee46a43d12f1a9 /Kernel | |
parent | 3a1d5fa112611b76c34d3dbd17346f1e714a7896 (diff) | |
download | serenity-4cb87b17536d64656e3f842a408d00c4072afc9b.zip |
FileSystem: Add a Custody class that represents a parent/child guardianship.
A custody is kind of a directory entry abstraction that represents a single
entry in a parent directory that tells us the name of a child inode.
The idea here is for path resolution to produce a chain of custody objects.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/FileSystem/Custody.cpp | 27 | ||||
-rw-r--r-- | Kernel/FileSystem/Custody.h | 32 | ||||
-rw-r--r-- | Kernel/FileSystem/VirtualFileSystem.cpp | 75 | ||||
-rw-r--r-- | Kernel/FileSystem/VirtualFileSystem.h | 6 | ||||
-rw-r--r-- | Kernel/Makefile | 1 |
5 files changed, 141 insertions, 0 deletions
diff --git a/Kernel/FileSystem/Custody.cpp b/Kernel/FileSystem/Custody.cpp new file mode 100644 index 0000000000..39c9761808 --- /dev/null +++ b/Kernel/FileSystem/Custody.cpp @@ -0,0 +1,27 @@ +#include <AK/HashTable.h> +#include <Kernel/FileSystem/Custody.h> +#include <Kernel/FileSystem/Inode.h> +#include <Kernel/Lock.h> + +static Lockable<HashTable<Custody*>>& all_custodies() +{ + static Lockable<HashTable<Custody*>>* table; + if (!table) + table = new Lockable<HashTable<Custody*>>; + 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 0000000000..06cf20b69e --- /dev/null +++ b/Kernel/FileSystem/Custody.h @@ -0,0 +1,32 @@ +#pragma once + +#include <AK/AKString.h> +#include <AK/RetainPtr.h> +#include <AK/Retainable.h> + +class Inode; + +class Custody : public Retainable<Custody> { +public: + static Retained<Custody> 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<Custody> m_parent; + String m_name; + Retained<Inode> m_inode; +}; diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index ec8b32ef15..dfe1c56a3d 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -6,6 +6,7 @@ #include <Kernel/Devices/CharacterDevice.h> #include <LibC/errno_numbers.h> #include <Kernel/Process.h> +#include <Kernel/FileSystem/Custody.h> //#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<Retained<Custody>> 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<Retained<Custody>, 32> custody_chain; + + if (path[0] == '/') { + custody_chain.append(Retained<Custody>(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 04ef61a432..0dbef2bb36 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<Retained<Custody>> resolve_path_to_custody(StringView path, Custody& base, int options = 0); + private: friend class FileDescriptor; @@ -115,4 +119,6 @@ private: RetainPtr<Inode> m_root_inode; Vector<OwnPtr<Mount>> m_mounts; HashMap<dword, Device*> m_devices; + + RetainPtr<Custody> m_root_custody; }; diff --git a/Kernel/Makefile b/Kernel/Makefile index 660f18fe7c..1593bfc41c 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 = \ |