mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 09:00:22 +00:00
Implement /proc/PID/vm.
Refactored SyntheticFileSystem to maintain an arbitrary directory structure. ProcFileSystem creates a directory entry in /proc for each new process.
This commit is contained in:
parent
10347b9ae8
commit
a32b3a3ddf
Notes:
sideshowbarker
2024-07-19 18:38:09 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/a32b3a3ddfc
15 changed files with 217 additions and 39 deletions
|
@ -8,7 +8,7 @@ template<typename T>
|
|||
class DoublyLinkedList {
|
||||
private:
|
||||
struct Node {
|
||||
explicit Node(T&& v) : value(v) { }
|
||||
explicit Node(T&& v) : value(move(v)) { }
|
||||
T value;
|
||||
Node* next { nullptr };
|
||||
Node* prev { nullptr };
|
||||
|
@ -62,7 +62,8 @@ public:
|
|||
|
||||
class Iterator {
|
||||
public:
|
||||
bool operator!=(const Iterator& other) { return m_node != other.m_node; }
|
||||
bool operator!=(const Iterator& other) const { return m_node != other.m_node; }
|
||||
bool operator==(const Iterator& other) const { return m_node == other.m_node; }
|
||||
Iterator& operator++() { m_node = m_node->next; return *this; }
|
||||
T& operator*() { return m_node->value; }
|
||||
bool isEnd() const { return !m_node; }
|
||||
|
@ -78,7 +79,8 @@ public:
|
|||
|
||||
class ConstIterator {
|
||||
public:
|
||||
bool operator!=(const ConstIterator& other) { return m_node != other.m_node; }
|
||||
bool operator!=(const ConstIterator& other) const { return m_node != other.m_node; }
|
||||
bool operator==(const ConstIterator& other) const { return m_node == other.m_node; }
|
||||
ConstIterator& operator++() { m_node = m_node->next; return *this; }
|
||||
const T& operator*() const { return m_node->value; }
|
||||
bool isEnd() const { return !m_node; }
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
|
||||
class Iterator {
|
||||
public:
|
||||
bool operator!=(const Iterator& other)
|
||||
bool operator!=(const Iterator& other) const
|
||||
{
|
||||
if (m_isEnd && other.m_isEnd)
|
||||
return false;
|
||||
|
@ -65,6 +65,7 @@ public:
|
|||
|| m_bucketIndex != other.m_bucketIndex
|
||||
|| m_bucketIterator != other.m_bucketIterator;
|
||||
}
|
||||
bool operator==(const Iterator& other) const { return !(*this != other); }
|
||||
T& operator*()
|
||||
{
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
|
@ -126,12 +127,12 @@ public:
|
|||
typename DoublyLinkedList<T>::Iterator m_bucketIterator;
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(*this, false); }
|
||||
Iterator begin() { return Iterator(*this, isEmpty()); }
|
||||
Iterator end() { return Iterator(*this, true); }
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
bool operator!=(const ConstIterator& other)
|
||||
bool operator!=(const ConstIterator& other) const
|
||||
{
|
||||
if (m_isEnd && other.m_isEnd)
|
||||
return false;
|
||||
|
@ -140,6 +141,7 @@ public:
|
|||
|| m_bucketIndex != other.m_bucketIndex
|
||||
|| m_bucketIterator != other.m_bucketIterator;
|
||||
}
|
||||
bool operator==(const ConstIterator& other) const { return !(*this != other); }
|
||||
const T& operator*() const
|
||||
{
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
|
@ -203,7 +205,7 @@ public:
|
|||
typename DoublyLinkedList<T>::ConstIterator m_bucketIterator;
|
||||
};
|
||||
|
||||
ConstIterator begin() const { return ConstIterator(*this, false); }
|
||||
ConstIterator begin() const { return ConstIterator(*this, isEmpty()); }
|
||||
ConstIterator end() const { return ConstIterator(*this, true); }
|
||||
|
||||
Iterator find(const T&);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "StdLib.h"
|
||||
#include "Types.h"
|
||||
#include "Traits.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
|
@ -96,6 +97,12 @@ make(Args&&... args)
|
|||
return OwnPtr<T>(new T(forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct Traits<OwnPtr<T>> {
|
||||
static unsigned hash(const OwnPtr<T>& p) { return (unsigned)p.ptr(); }
|
||||
static void dump(const OwnPtr<T>& p) { kprintf("%p", p.ptr()); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::OwnPtr;
|
||||
|
|
20
AK/Vector.h
20
AK/Vector.h
|
@ -12,11 +12,12 @@ template<typename T>
|
|||
class VectorImpl {
|
||||
public:
|
||||
~VectorImpl() { }
|
||||
static OwnPtr<VectorImpl> create(size_t capacity)
|
||||
static VectorImpl* create(size_t capacity)
|
||||
{
|
||||
size_t size = sizeof(VectorImpl) + sizeof(T) * capacity;
|
||||
void* slot = kmalloc(size);
|
||||
return OwnPtr<VectorImpl>(new (slot) VectorImpl(capacity));
|
||||
new (slot) VectorImpl(capacity);
|
||||
return (VectorImpl*)slot;
|
||||
}
|
||||
|
||||
size_t size() const { return m_size; }
|
||||
|
@ -59,14 +60,17 @@ public:
|
|||
~Vector() { clear(); }
|
||||
|
||||
Vector(Vector&& other)
|
||||
: m_impl(move(other.m_impl))
|
||||
: m_impl(other.m_impl)
|
||||
{
|
||||
other.m_impl = nullptr;
|
||||
}
|
||||
|
||||
Vector& operator=(Vector&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
m_impl = move(other.m_impl);
|
||||
if (this != &other) {
|
||||
m_impl = other.m_impl;
|
||||
other.m_impl = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -75,6 +79,7 @@ public:
|
|||
for (size_t i = 0; i < size(); ++i) {
|
||||
at(i).~T();
|
||||
}
|
||||
kfree(m_impl);
|
||||
m_impl = nullptr;
|
||||
}
|
||||
|
||||
|
@ -134,8 +139,9 @@ public:
|
|||
new (newImpl->slot(i)) T(move(m_impl->at(i)));
|
||||
m_impl->at(i).~T();
|
||||
}
|
||||
kfree(m_impl);
|
||||
}
|
||||
m_impl = move(newImpl);
|
||||
m_impl = newImpl;
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
|
@ -174,7 +180,7 @@ private:
|
|||
return max(size_t(4), capacity + (capacity / 4) + 4);
|
||||
}
|
||||
|
||||
OwnPtr<VectorImpl<T>> m_impl;
|
||||
VectorImpl<T>* m_impl { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
#ifdef SERENITY
|
||||
#ifdef USERLAND
|
||||
#include <LibC/stdlib.h>
|
||||
|
|
20
AK/test.cpp
20
AK/test.cpp
|
@ -16,6 +16,26 @@ static void testWeakPtr();
|
|||
int main(int, char**)
|
||||
{
|
||||
StringImpl::initializeGlobals();
|
||||
|
||||
{
|
||||
struct entry {
|
||||
String s;
|
||||
};
|
||||
|
||||
HashMap<unsigned, entry> tab;
|
||||
tab.set(1, { "one" });
|
||||
tab.set(2, { "two" });
|
||||
tab.set(3, { "three" });
|
||||
tab.set(4, { "four" });
|
||||
tab.remove(1);
|
||||
tab.remove(2);
|
||||
tab.remove(3);
|
||||
for (auto& it : tab) {
|
||||
printf("%s\n", it.value.s.characters());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
{
|
||||
CircularQueue<int, 4> queue;
|
||||
queue.dump();
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
#include "ProcFileSystem.h"
|
||||
#include "Task.h"
|
||||
|
||||
static ProcFileSystem* s_the;
|
||||
|
||||
ProcFileSystem& ProcFileSystem::the()
|
||||
{
|
||||
ASSERT(s_the);
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
RetainPtr<ProcFileSystem> ProcFileSystem::create()
|
||||
{
|
||||
return adopt(*new ProcFileSystem);
|
||||
|
@ -8,15 +16,56 @@ RetainPtr<ProcFileSystem> ProcFileSystem::create()
|
|||
|
||||
ProcFileSystem::ProcFileSystem()
|
||||
{
|
||||
s_the = this;
|
||||
}
|
||||
|
||||
ProcFileSystem::~ProcFileSystem()
|
||||
{
|
||||
}
|
||||
|
||||
void ProcFileSystem::addProcess(Task& task)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
char buf[16];
|
||||
ksprintf(buf, "%d", task.pid());
|
||||
auto dir = addFile(createDirectory(buf));
|
||||
m_pid2inode.set(task.pid(), dir.index());
|
||||
addFile(createGeneratedFile("vm", [&task] {
|
||||
InterruptDisabler disabler;
|
||||
char* buffer;
|
||||
auto stringImpl = StringImpl::createUninitialized(80 + task.regionCount() * 80, buffer);
|
||||
memset(buffer, 0, stringImpl->length());
|
||||
char* ptr = buffer;
|
||||
ptr += ksprintf(ptr, "BEGIN END SIZE NAME\n");
|
||||
for (auto& region : task.regions()) {
|
||||
ptr += ksprintf(ptr, "%x -- %x %x %s\n",
|
||||
region->linearAddress.get(),
|
||||
region->linearAddress.offset(region->size - 1).get(),
|
||||
region->size,
|
||||
region->name.characters());
|
||||
}
|
||||
*ptr = '\0';
|
||||
return ByteBuffer::copy((byte*)buffer, ptr - buffer);
|
||||
}), dir.index());
|
||||
}
|
||||
|
||||
void ProcFileSystem::removeProcess(Task& task)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
auto pid = task.pid();
|
||||
auto it = m_pid2inode.find(pid);
|
||||
ASSERT(it != m_pid2inode.end());
|
||||
bool success = removeFile((*it).value);
|
||||
ASSERT(success);
|
||||
m_pid2inode.remove(pid);
|
||||
}
|
||||
|
||||
bool ProcFileSystem::initialize()
|
||||
{
|
||||
SyntheticFileSystem::initialize();
|
||||
|
||||
auto d = addFile(createDirectory("sys"));
|
||||
|
||||
addFile(createGeneratedFile("summary", [] {
|
||||
InterruptDisabler disabler;
|
||||
auto tasks = Task::allTasks();
|
||||
|
|
|
@ -3,15 +3,24 @@
|
|||
#include <AK/Types.h>
|
||||
#include <VirtualFileSystem/SyntheticFileSystem.h>
|
||||
|
||||
class Task;
|
||||
|
||||
class ProcFileSystem final : public SyntheticFileSystem {
|
||||
public:
|
||||
static ProcFileSystem& the();
|
||||
|
||||
virtual ~ProcFileSystem() override;
|
||||
static RetainPtr<ProcFileSystem> create();
|
||||
|
||||
virtual bool initialize() override;
|
||||
virtual const char* className() const override;
|
||||
|
||||
void addProcess(Task&);
|
||||
void removeProcess(Task&);
|
||||
|
||||
private:
|
||||
ProcFileSystem();
|
||||
|
||||
HashMap<pid_t, InodeIndex> m_pid2inode;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "errno.h"
|
||||
#include "i8253.h"
|
||||
#include "RTC.h"
|
||||
#include "ProcFileSystem.h"
|
||||
|
||||
//#define DEBUG_IO
|
||||
//#define TASK_DEBUG
|
||||
|
@ -397,11 +398,14 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring)
|
|||
// HACK: Ring2 SS in the TSS is the current PID.
|
||||
m_tss.ss2 = m_pid;
|
||||
m_farPtr.offset = 0x98765432;
|
||||
|
||||
ProcFileSystem::the().addProcess(*this);
|
||||
}
|
||||
|
||||
Task::~Task()
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
ProcFileSystem::the().removeProcess(*this);
|
||||
system.nprocess--;
|
||||
delete [] m_ldtEntries;
|
||||
m_ldtEntries = nullptr;
|
||||
|
|
|
@ -15,6 +15,7 @@ class Zone;
|
|||
|
||||
class Task : public InlineLinkedListNode<Task> {
|
||||
friend class InlineLinkedListNode<Task>;
|
||||
class Region;
|
||||
public:
|
||||
static Task* createKernelTask(void (*entry)(), String&& name);
|
||||
static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr);
|
||||
|
@ -110,6 +111,8 @@ public:
|
|||
|
||||
static void taskDidCrash(Task*);
|
||||
|
||||
size_t regionCount() const { return m_regions.size(); }
|
||||
const Vector<OwnPtr<Region>>& regions() const { return m_regions; }
|
||||
void dumpRegions();
|
||||
|
||||
void didSchedule() { ++m_timesScheduled; }
|
||||
|
|
|
@ -108,9 +108,7 @@ static void init_stage2()
|
|||
|
||||
vfs->mountRoot(e2fs.copyRef());
|
||||
|
||||
auto procfs = ProcFileSystem::create();
|
||||
procfs->initialize();
|
||||
vfs->mount(procfs.copyRef(), "/proc");
|
||||
vfs->mount(ProcFileSystem::the(), "/proc");
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -200,6 +198,9 @@ void init()
|
|||
kprintf("%u kB base memory\n", base_memory);
|
||||
kprintf("%u kB extended memory\n", ext_memory);
|
||||
|
||||
auto procfs = ProcFileSystem::create();
|
||||
procfs->initialize();
|
||||
|
||||
Task::initialize();
|
||||
|
||||
Task::createKernelTask(undertaker_main, "undertaker");
|
||||
|
|
|
@ -133,7 +133,7 @@ bool FileHandle::isDirectory() const
|
|||
return m_vnode->metadata().isDirectory();
|
||||
}
|
||||
|
||||
ssize_t FileHandle::get_dir_entries(byte* buffer, size_t size)
|
||||
ssize_t FileHandle::get_dir_entries(byte* buffer, Unix::size_t size)
|
||||
{
|
||||
Locker locker(VirtualFileSystem::lock());
|
||||
|
||||
|
|
|
@ -21,21 +21,36 @@ bool SyntheticFileSystem::initialize()
|
|||
// Add a File for the root directory.
|
||||
// FIXME: This needs work.
|
||||
auto rootDir = make<File>();
|
||||
rootDir->metadata.inode = { id(), 1 };
|
||||
rootDir->metadata.inode = { id(), RootInodeIndex };
|
||||
rootDir->parent = { id(), RootInodeIndex };
|
||||
rootDir->metadata.mode = 0040555;
|
||||
rootDir->metadata.uid = 0;
|
||||
rootDir->metadata.gid = 0;
|
||||
rootDir->metadata.size = 0;
|
||||
rootDir->metadata.mtime = mepoch;
|
||||
m_files.append(move(rootDir));
|
||||
m_inodes.set(RootInodeIndex, move(rootDir));
|
||||
|
||||
#if 0
|
||||
#ifndef SERENITY
|
||||
addFile(createTextFile("file", "I'm a synthetic file!\n"));
|
||||
addFile(createTextFile("message", "Hey! This isn't my bottle!\n"));
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
auto SyntheticFileSystem::createDirectory(String&& name) -> OwnPtr<File>
|
||||
{
|
||||
auto file = make<File>();
|
||||
file->name = move(name);
|
||||
file->metadata.size = 0;
|
||||
file->metadata.uid = 0;
|
||||
file->metadata.gid = 0;
|
||||
file->metadata.mode = 0040555;
|
||||
file->metadata.mtime = mepoch;
|
||||
return file;
|
||||
}
|
||||
|
||||
auto SyntheticFileSystem::createTextFile(String&& name, String&& text) -> OwnPtr<File>
|
||||
{
|
||||
auto file = make<File>();
|
||||
|
@ -44,7 +59,7 @@ auto SyntheticFileSystem::createTextFile(String&& name, String&& text) -> OwnPtr
|
|||
file->metadata.size = file->data.size();
|
||||
file->metadata.uid = 100;
|
||||
file->metadata.gid = 200;
|
||||
file->metadata.mode = 0100644;
|
||||
file->metadata.mode = 04;
|
||||
file->metadata.mtime = mepoch;
|
||||
return file;
|
||||
}
|
||||
|
@ -62,11 +77,42 @@ auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer
|
|||
return file;
|
||||
}
|
||||
|
||||
void SyntheticFileSystem::addFile(OwnPtr<File>&& file)
|
||||
InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex parent)
|
||||
{
|
||||
ASSERT(file);
|
||||
file->metadata.inode = { id(), m_files.size() + 1 };
|
||||
m_files.append(move(file));
|
||||
auto it = m_inodes.find(parent);
|
||||
ASSERT(it != m_inodes.end());
|
||||
InodeIdentifier newInode { id(), generateInodeIndex() };
|
||||
file->metadata.inode = newInode;
|
||||
file->parent = { id(), parent };
|
||||
(*it).value->children.append(file.ptr());
|
||||
m_inodes.set(newInode.index(), move(file));
|
||||
return newInode;
|
||||
}
|
||||
|
||||
bool SyntheticFileSystem::removeFile(InodeIndex inode)
|
||||
{
|
||||
auto it = m_inodes.find(inode);
|
||||
if (it == m_inodes.end())
|
||||
return false;
|
||||
auto& file = *(*it).value;
|
||||
|
||||
auto pit = m_inodes.find(file.parent.index());
|
||||
if (pit == m_inodes.end())
|
||||
return false;
|
||||
auto& parent = *(*pit).value;
|
||||
for (size_t i = 0; i < parent.children.size(); ++i) {
|
||||
if (parent.children[i]->metadata.inode.index() != inode) {
|
||||
continue;
|
||||
}
|
||||
parent.children.remove(i);
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto& child : file.children)
|
||||
removeFile(child->metadata.inode.index());
|
||||
m_inodes.remove(inode);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* SyntheticFileSystem::className() const
|
||||
|
@ -85,14 +131,20 @@ bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Functio
|
|||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("[synthfs] enumerateDirectoryInode %u\n", inode.index());
|
||||
#endif
|
||||
if (inode.index() != 1)
|
||||
|
||||
auto it = m_inodes.find(inode.index());
|
||||
if (it == m_inodes.end())
|
||||
return false;
|
||||
const File& synInode = *(*it).value;
|
||||
if (!synInode.metadata.isDirectory())
|
||||
return false;
|
||||
|
||||
callback({ ".", m_files[0]->metadata.inode });
|
||||
callback({ "..", m_files[0]->metadata.inode });
|
||||
callback({ ".", synInode.metadata.inode });
|
||||
callback({ "..", synInode.parent });
|
||||
|
||||
for (unsigned i = 1; i < m_files.size(); ++i)
|
||||
callback({ m_files[i]->name, m_files[i]->metadata.inode });
|
||||
for (auto& child : synInode.children) {
|
||||
callback({ child->name, child->metadata.inode });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -102,10 +154,11 @@ InodeMetadata SyntheticFileSystem::inodeMetadata(InodeIdentifier inode) const
|
|||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("[synthfs] inodeMetadata(%u)\n", inode.index());
|
||||
#endif
|
||||
if (inode.index() == 0 || inode.index() > m_files.size())
|
||||
return InodeMetadata();
|
||||
auto& file = *m_files[inode.index() - 1];
|
||||
return file.metadata;
|
||||
|
||||
auto it = m_inodes.find(inode.index());
|
||||
if (it == m_inodes.end())
|
||||
return { };
|
||||
return (*it).value->metadata;
|
||||
}
|
||||
|
||||
bool SyntheticFileSystem::setModificationTime(InodeIdentifier, dword timestamp)
|
||||
|
@ -120,6 +173,7 @@ InodeIdentifier SyntheticFileSystem::createInode(InodeIdentifier parentInode, co
|
|||
(void) parentInode;
|
||||
(void) name;
|
||||
(void) mode;
|
||||
(void) size;
|
||||
kprintf("FIXME: Implement SyntheticFileSystem::createDirectoryInode().\n");
|
||||
return { };
|
||||
}
|
||||
|
@ -136,12 +190,13 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o
|
|||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("[synthfs] readInode %u\n", inode.index());
|
||||
#endif
|
||||
ASSERT(inode.index() != 1);
|
||||
ASSERT(inode.index() <= m_files.size());
|
||||
ASSERT(offset >= 0);
|
||||
ASSERT(buffer);
|
||||
|
||||
auto& file = *m_files[inode.index() - 1];
|
||||
\
|
||||
auto it = m_inodes.find(inode.index());
|
||||
if (it == m_inodes.end())
|
||||
return false;
|
||||
const File& file = *(*it).value;
|
||||
ByteBuffer generatedData;
|
||||
if (file.generator)
|
||||
generatedData = file.generator();
|
||||
|
@ -154,6 +209,13 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o
|
|||
|
||||
InodeIdentifier SyntheticFileSystem::makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t)
|
||||
{
|
||||
(void) parentInode;
|
||||
(void) name;
|
||||
kprintf("FIXME: Implement SyntheticFileSystem::makeDirectory().\n");
|
||||
return { };
|
||||
}
|
||||
|
||||
auto SyntheticFileSystem::generateInodeIndex() -> InodeIndex
|
||||
{
|
||||
return m_nextInodeIndex++;
|
||||
}
|
||||
|
|
|
@ -21,21 +21,31 @@ public:
|
|||
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
|
||||
|
||||
protected:
|
||||
typedef unsigned InodeIndex;
|
||||
|
||||
InodeIndex generateInodeIndex();
|
||||
static constexpr InodeIndex RootInodeIndex = 1;
|
||||
|
||||
SyntheticFileSystem();
|
||||
|
||||
struct File {
|
||||
String name;
|
||||
InodeMetadata metadata;
|
||||
InodeIdentifier parent;
|
||||
ByteBuffer data;
|
||||
Function<ByteBuffer()> generator;
|
||||
Vector<File*> children;
|
||||
};
|
||||
|
||||
OwnPtr<File> createDirectory(String&& name);
|
||||
OwnPtr<File> createTextFile(String&& name, String&& text);
|
||||
OwnPtr<File> createGeneratedFile(String&& name, Function<ByteBuffer()>&&);
|
||||
|
||||
void addFile(OwnPtr<File>&&);
|
||||
InodeIdentifier addFile(OwnPtr<File>&&, InodeIndex parent = RootInodeIndex);
|
||||
bool removeFile(InodeIndex);
|
||||
|
||||
private:
|
||||
Vector<OwnPtr<File>> m_files;
|
||||
InodeIndex m_nextInodeIndex { 2 };
|
||||
HashMap<InodeIndex, OwnPtr<File>> m_inodes;
|
||||
};
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ VirtualFileSystem::VirtualFileSystem()
|
|||
VirtualFileSystem::~VirtualFileSystem()
|
||||
{
|
||||
kprintf("[VFS] ~VirtualFileSystem with %u nodes allocated\n", allocatedNodeCount());
|
||||
// FIXME: m_nodes is never freed. Does it matter though?
|
||||
}
|
||||
|
||||
auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
|
||||
|
|
Loading…
Reference in a new issue