summaryrefslogtreecommitdiff
path: root/Kernel
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-05-30 17:46:08 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-05-30 17:46:08 +0200
commit4cb87b17536d64656e3f842a408d00c4072afc9b (patch)
tree14695838d4b101faec37286a8dee46a43d12f1a9 /Kernel
parent3a1d5fa112611b76c34d3dbd17346f1e714a7896 (diff)
downloadserenity-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.cpp27
-rw-r--r--Kernel/FileSystem/Custody.h32
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.cpp75
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.h6
-rw-r--r--Kernel/Makefile1
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 = \