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.
This commit is contained in:
Andreas Kling 2019-05-30 17:46:08 +02:00
parent 3a1d5fa112
commit 4cb87b1753
Notes: sideshowbarker 2024-07-19 13:50:03 +09:00
5 changed files with 141 additions and 0 deletions

View file

@ -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);
}

View file

@ -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;
};

View file

@ -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();
}

View file

@ -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;
};

View file

@ -50,6 +50,7 @@ KERNEL_OBJS = \
ProcessTracer.o \
Devices/PCSpeaker.o \
FileSystem/InodeFile.o \
FileSystem/Custody.o \
File.o
VFS_OBJS = \