mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:28:12 +00:00
Kernel: Add DirectoryEntryView for VFS directory traversal
Unlike DirectoryEntry (which is used when constructing directories), DirectoryEntryView does not manage storage for file names. Names are just StringViews. This is much more suited to the directory traversal API and makes it easier to implement this in file system classes since they no longer need to create temporary name copies while traversing.
This commit is contained in:
parent
8abf5048b8
commit
eeaba41d13
16 changed files with 61 additions and 53 deletions
|
@ -136,18 +136,18 @@ InodeMetadata DevPtsFSInode::metadata() const
|
|||
return m_metadata;
|
||||
}
|
||||
|
||||
KResult DevPtsFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const
|
||||
KResult DevPtsFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)> callback) const
|
||||
{
|
||||
if (identifier().index() > 1)
|
||||
return KResult(-ENOTDIR);
|
||||
|
||||
callback({ ".", 1, identifier(), 0 });
|
||||
callback({ "..", 2, identifier(), 0 });
|
||||
callback({ ".", identifier(), 0 });
|
||||
callback({ "..", identifier(), 0 });
|
||||
|
||||
for (unsigned pty_index : *ptys) {
|
||||
String name = String::number(pty_index);
|
||||
InodeIdentifier identifier = { fsid(), pty_index_to_inode_index(pty_index) };
|
||||
callback({ name.characters(), name.length(), identifier, 0 });
|
||||
callback({ name, identifier, 0 });
|
||||
}
|
||||
|
||||
return KSuccess;
|
||||
|
|
|
@ -69,7 +69,7 @@ private:
|
|||
// ^Inode
|
||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||
virtual void flush_metadata() override;
|
||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
|
||||
|
|
|
@ -849,7 +849,7 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi
|
|||
return nwritten;
|
||||
}
|
||||
|
||||
KResult Ext2FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const
|
||||
KResult Ext2FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)> callback) const
|
||||
{
|
||||
LOCKER(m_lock);
|
||||
ASSERT(is_directory());
|
||||
|
@ -871,7 +871,7 @@ KResult Ext2FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
#ifdef EXT2_DEBUG
|
||||
dbg() << "Ext2Inode::traverse_as_directory: " << entry->inode << ", name_len: " << entry->name_len << ", rec_len: " << entry->rec_len << ", file_type: " << entry->file_type << ", name: " << String(entry->name, entry->name_len);
|
||||
#endif
|
||||
if (!callback({ entry->name, entry->name_len, { fsid(), entry->inode }, entry->file_type }))
|
||||
if (!callback({ { entry->name, entry->name_len }, { fsid(), entry->inode }, entry->file_type }))
|
||||
break;
|
||||
}
|
||||
entry = (ext2_dir_entry_2*)((char*)entry + entry->rec_len);
|
||||
|
@ -961,7 +961,7 @@ KResult Ext2FSInode::add_child(Inode& child, const StringView& name, mode_t mode
|
|||
name_already_exists = true;
|
||||
return false;
|
||||
}
|
||||
entries.append(entry);
|
||||
entries.append({ entry.name.characters_without_null_termination(), entry.name.length(), entry.inode, entry.file_type });
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -1008,7 +1008,7 @@ KResult Ext2FSInode::remove_child(const StringView& name)
|
|||
Vector<FS::DirectoryEntry> entries;
|
||||
KResult result = traverse_as_directory([&](auto& entry) {
|
||||
if (name != entry.name)
|
||||
entries.append(entry);
|
||||
entries.append({ entry.name.characters_without_null_termination(), entry.name.length(), entry.inode, entry.file_type });
|
||||
return true;
|
||||
});
|
||||
if (result.is_error())
|
||||
|
@ -1478,7 +1478,7 @@ void Ext2FSInode::populate_lookup_cache() const
|
|||
HashMap<String, unsigned> children;
|
||||
|
||||
KResult result = traverse_as_directory([&children](auto& entry) {
|
||||
children.set(String(entry.name, entry.name_length), entry.inode.index());
|
||||
children.set(entry.name, entry.inode.index());
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ private:
|
|||
// ^Inode
|
||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||
virtual void flush_metadata() override;
|
||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override;
|
||||
|
|
|
@ -191,7 +191,7 @@ ssize_t FileDescription::get_dir_entries(u8* buffer, ssize_t size)
|
|||
KResult result = VFS::the().traverse_directory_inode(*m_inode, [&stream](auto& entry) {
|
||||
stream << (u32)entry.inode.index();
|
||||
stream << (u8)entry.file_type;
|
||||
stream << (u32)entry.name_length;
|
||||
stream << (u32)entry.name.length();
|
||||
stream << entry.name;
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -85,6 +85,13 @@ FS::DirectoryEntry::DirectoryEntry(const char* n, size_t nl, InodeIdentifier i,
|
|||
name[nl] = '\0';
|
||||
}
|
||||
|
||||
FS::DirectoryEntryView::DirectoryEntryView(const StringView& n, InodeIdentifier i, u8 ft)
|
||||
: name(n)
|
||||
, inode(i)
|
||||
, file_type(ft)
|
||||
{
|
||||
}
|
||||
|
||||
void FS::sync()
|
||||
{
|
||||
Inode::sync();
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <AK/RefCounted.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/StringView.h>
|
||||
#include <Kernel/FileSystem/InodeIdentifier.h>
|
||||
#include <Kernel/KResult.h>
|
||||
#include <Kernel/Lock.h>
|
||||
|
@ -78,6 +79,14 @@ public:
|
|||
u8 file_type { 0 };
|
||||
};
|
||||
|
||||
struct DirectoryEntryView {
|
||||
DirectoryEntryView(const StringView& name, InodeIdentifier, u8 file_type);
|
||||
|
||||
StringView name;
|
||||
InodeIdentifier inode;
|
||||
u8 file_type { 0 };
|
||||
};
|
||||
|
||||
virtual void flush_writes() { }
|
||||
|
||||
size_t block_size() const { return m_block_size; }
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
KResultOr<KBuffer> read_entire(FileDescription* = nullptr) const;
|
||||
|
||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const = 0;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const = 0;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const = 0;
|
||||
virtual RefPtr<Inode> lookup(StringView name) = 0;
|
||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) = 0;
|
||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) = 0;
|
||||
|
|
|
@ -798,7 +798,7 @@ void Plan9FSInode::flush_metadata()
|
|||
KResultOr<size_t> Plan9FSInode::directory_entry_count() const
|
||||
{
|
||||
size_t count = 0;
|
||||
KResult result = traverse_as_directory([&count](const FS::DirectoryEntry&) {
|
||||
KResult result = traverse_as_directory([&count](auto&) {
|
||||
count++;
|
||||
return true;
|
||||
});
|
||||
|
@ -809,7 +809,7 @@ KResultOr<size_t> Plan9FSInode::directory_entry_count() const
|
|||
return count;
|
||||
}
|
||||
|
||||
KResult Plan9FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const
|
||||
KResult Plan9FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)> callback) const
|
||||
{
|
||||
KResult result = KSuccess;
|
||||
|
||||
|
@ -857,17 +857,7 @@ KResult Plan9FSInode::traverse_as_directory(Function<bool(const FS::DirectoryEnt
|
|||
u8 type;
|
||||
StringView name;
|
||||
decoder >> qid >> offset >> type >> name;
|
||||
|
||||
FS::DirectoryEntry entry {
|
||||
"",
|
||||
name.length(),
|
||||
{ fsid(), fs().allocate_fid() },
|
||||
0
|
||||
};
|
||||
size_t size_to_copy = min(sizeof(entry.name) - 1, name.length());
|
||||
memcpy(entry.name, name.characters_without_null_termination(), size_to_copy);
|
||||
entry.name[size_to_copy] = 0;
|
||||
callback(entry);
|
||||
callback({ name, { fsid(), fs().allocate_fid() }, 0 });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -126,7 +126,7 @@ public:
|
|||
virtual void flush_metadata() override;
|
||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||
virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override;
|
||||
virtual KResult add_child(Inode&, const StringView& name, mode_t) override;
|
||||
|
|
|
@ -1246,7 +1246,7 @@ InodeIdentifier ProcFS::ProcFSDirectoryEntry::identifier(unsigned fsid) const
|
|||
return to_identifier(fsid, PDI_Root, 0, (ProcFileType)proc_file_type);
|
||||
}
|
||||
|
||||
KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const
|
||||
KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)> callback) const
|
||||
{
|
||||
#ifdef PROCFS_DEBUG
|
||||
dbg() << "ProcFS: traverse_as_directory " << index();
|
||||
|
@ -1258,8 +1258,8 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
auto proc_file_type = to_proc_file_type(identifier());
|
||||
auto parent_id = to_parent_id(identifier());
|
||||
|
||||
callback({ ".", 1, identifier(), 2 });
|
||||
callback({ "..", 2, parent_id, 2 });
|
||||
callback({ ".", identifier(), 2 });
|
||||
callback({ "..", parent_id, 2 });
|
||||
|
||||
switch (proc_file_type) {
|
||||
case FI_Root:
|
||||
|
@ -1268,28 +1268,28 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
if (!entry.name)
|
||||
continue;
|
||||
if (entry.proc_file_type > __FI_Root_Start && entry.proc_file_type < __FI_Root_End)
|
||||
callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type), 0 });
|
||||
callback({ { entry.name, strlen(entry.name) }, to_identifier(fsid(), PDI_Root, 0, (ProcFileType)entry.proc_file_type), 0 });
|
||||
}
|
||||
for (auto pid_child : Process::all_pids()) {
|
||||
char name[16];
|
||||
size_t name_length = (size_t)sprintf(name, "%d", pid_child.value());
|
||||
callback({ name, name_length, to_identifier(fsid(), PDI_Root, pid_child, FI_PID), 0 });
|
||||
callback({ { name, name_length }, to_identifier(fsid(), PDI_Root, pid_child, FI_PID), 0 });
|
||||
}
|
||||
break;
|
||||
|
||||
case FI_Root_sys:
|
||||
for (size_t i = 1; i < sys_variables().size(); ++i) {
|
||||
auto& variable = sys_variables()[i];
|
||||
callback({ variable.name.characters(), variable.name.length(), sys_var_to_identifier(fsid(), i), 0 });
|
||||
callback({ variable.name, sys_var_to_identifier(fsid(), i), 0 });
|
||||
}
|
||||
break;
|
||||
|
||||
case FI_Root_net:
|
||||
callback({ "adapters", 8, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_adapters), 0 });
|
||||
callback({ "arp", 3, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_arp), 0 });
|
||||
callback({ "tcp", 3, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_tcp), 0 });
|
||||
callback({ "udp", 3, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_udp), 0 });
|
||||
callback({ "local", 5, to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_local), 0 });
|
||||
callback({ "adapters", to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_adapters), 0 });
|
||||
callback({ "arp", to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_arp), 0 });
|
||||
callback({ "tcp", to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_tcp), 0 });
|
||||
callback({ "udp", to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_udp), 0 });
|
||||
callback({ "local", to_identifier(fsid(), PDI_Root_net, 0, FI_Root_net_local), 0 });
|
||||
break;
|
||||
|
||||
case FI_PID: {
|
||||
|
@ -1302,7 +1302,7 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
if (entry.proc_file_type == FI_PID_exe && !process->executable())
|
||||
continue;
|
||||
// FIXME: strlen() here is sad.
|
||||
callback({ entry.name, strlen(entry.name), to_identifier(fsid(), PDI_PID, pid, (ProcFileType)entry.proc_file_type), 0 });
|
||||
callback({ { entry.name, strlen(entry.name) }, to_identifier(fsid(), PDI_PID, pid, (ProcFileType)entry.proc_file_type), 0 });
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -1318,7 +1318,7 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
continue;
|
||||
char name[16];
|
||||
size_t name_length = (size_t)sprintf(name, "%d", i);
|
||||
callback({ name, name_length, to_identifier_with_fd(fsid(), pid, i), 0 });
|
||||
callback({ { name, name_length }, to_identifier_with_fd(fsid(), pid, i), 0 });
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -1331,7 +1331,7 @@ KResult ProcFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntr
|
|||
int tid = thread.tid().value();
|
||||
char name[16];
|
||||
size_t name_length = (size_t)sprintf(name, "%d", tid);
|
||||
callback({ name, name_length, to_identifier_with_stack(fsid(), tid), 0 });
|
||||
callback({ { name, name_length }, to_identifier_with_stack(fsid(), tid), 0 });
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
} break;
|
||||
|
@ -1635,7 +1635,7 @@ KResultOr<size_t> ProcFSInode::directory_entry_count() const
|
|||
{
|
||||
ASSERT(is_directory());
|
||||
size_t count = 0;
|
||||
KResult result = traverse_as_directory([&count](const FS::DirectoryEntry&) {
|
||||
KResult result = traverse_as_directory([&count](auto&) {
|
||||
++count;
|
||||
return true;
|
||||
});
|
||||
|
|
|
@ -98,7 +98,7 @@ private:
|
|||
// ^Inode
|
||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||
virtual void flush_metadata() override;
|
||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
|
||||
|
@ -125,7 +125,7 @@ private:
|
|||
// ^Inode
|
||||
virtual ssize_t read_bytes(off_t, ssize_t, u8*, FileDescription*) const override { ASSERT_NOT_REACHED(); }
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override { ASSERT_NOT_REACHED(); }
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { ASSERT_NOT_REACHED(); }
|
||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||
virtual void flush_metadata() override {};
|
||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8*, FileDescription*) override { ASSERT_NOT_REACHED(); }
|
||||
|
|
|
@ -124,7 +124,7 @@ InodeMetadata TmpFSInode::metadata() const
|
|||
return m_metadata;
|
||||
}
|
||||
|
||||
KResult TmpFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback) const
|
||||
KResult TmpFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)> callback) const
|
||||
{
|
||||
LOCKER(m_lock, Lock::Mode::Shared);
|
||||
|
||||
|
@ -134,8 +134,10 @@ KResult TmpFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry
|
|||
callback({ ".", identifier(), 0 });
|
||||
callback({ "..", m_parent, 0 });
|
||||
|
||||
for (auto& it : m_children)
|
||||
callback(it.value.entry);
|
||||
for (auto& it : m_children) {
|
||||
auto& entry = it.value.entry;
|
||||
callback({ { entry.name, entry.name_length }, entry.inode, entry.file_type });
|
||||
}
|
||||
return KSuccess;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
// ^Inode
|
||||
virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override;
|
||||
virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override;
|
||||
virtual RefPtr<Inode> lookup(StringView name) override;
|
||||
virtual void flush_metadata() override;
|
||||
virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
|
||||
|
|
|
@ -191,9 +191,9 @@ bool VFS::is_vfs_root(InodeIdentifier inode) const
|
|||
return inode == root_inode_id();
|
||||
}
|
||||
|
||||
KResult VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::DirectoryEntry&)> callback)
|
||||
KResult VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::DirectoryEntryView&)> callback)
|
||||
{
|
||||
return dir_inode.traverse_as_directory([&](const FS::DirectoryEntry& entry) {
|
||||
return dir_inode.traverse_as_directory([&](auto& entry) {
|
||||
InodeIdentifier resolved_inode;
|
||||
if (auto mount = find_mount_for_host(entry.inode))
|
||||
resolved_inode = mount->guest().identifier();
|
||||
|
@ -202,13 +202,13 @@ KResult VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::
|
|||
|
||||
// FIXME: This is now broken considering chroot and bind mounts.
|
||||
bool is_root_inode = dir_inode.identifier() == dir_inode.fs().root_inode()->identifier();
|
||||
if (is_root_inode && !is_vfs_root(dir_inode.identifier()) && !strcmp(entry.name, "..")) {
|
||||
if (is_root_inode && !is_vfs_root(dir_inode.identifier()) && entry.name == "..") {
|
||||
auto mount = find_mount_for_guest(dir_inode);
|
||||
ASSERT(mount);
|
||||
ASSERT(mount->host());
|
||||
resolved_inode = mount->host()->identifier();
|
||||
}
|
||||
callback(FS::DirectoryEntry(entry.name, entry.name_length, resolved_inode, entry.file_type));
|
||||
callback({ entry.name, resolved_inode, entry.file_type });
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -126,7 +126,7 @@ private:
|
|||
|
||||
bool is_vfs_root(InodeIdentifier) const;
|
||||
|
||||
KResult traverse_directory_inode(Inode&, Function<bool(const FS::DirectoryEntry&)>);
|
||||
KResult traverse_directory_inode(Inode&, Function<bool(const FS::DirectoryEntryView&)>);
|
||||
|
||||
Mount* find_mount_for_host(Inode&);
|
||||
Mount* find_mount_for_host(InodeIdentifier);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue