mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +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 {
|
class DoublyLinkedList {
|
||||||
private:
|
private:
|
||||||
struct Node {
|
struct Node {
|
||||||
explicit Node(T&& v) : value(v) { }
|
explicit Node(T&& v) : value(move(v)) { }
|
||||||
T value;
|
T value;
|
||||||
Node* next { nullptr };
|
Node* next { nullptr };
|
||||||
Node* prev { nullptr };
|
Node* prev { nullptr };
|
||||||
|
@ -62,7 +62,8 @@ public:
|
||||||
|
|
||||||
class Iterator {
|
class Iterator {
|
||||||
public:
|
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; }
|
Iterator& operator++() { m_node = m_node->next; return *this; }
|
||||||
T& operator*() { return m_node->value; }
|
T& operator*() { return m_node->value; }
|
||||||
bool isEnd() const { return !m_node; }
|
bool isEnd() const { return !m_node; }
|
||||||
|
@ -78,7 +79,8 @@ public:
|
||||||
|
|
||||||
class ConstIterator {
|
class ConstIterator {
|
||||||
public:
|
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; }
|
ConstIterator& operator++() { m_node = m_node->next; return *this; }
|
||||||
const T& operator*() const { return m_node->value; }
|
const T& operator*() const { return m_node->value; }
|
||||||
bool isEnd() const { return !m_node; }
|
bool isEnd() const { return !m_node; }
|
||||||
|
|
|
@ -56,7 +56,7 @@ public:
|
||||||
|
|
||||||
class Iterator {
|
class Iterator {
|
||||||
public:
|
public:
|
||||||
bool operator!=(const Iterator& other)
|
bool operator!=(const Iterator& other) const
|
||||||
{
|
{
|
||||||
if (m_isEnd && other.m_isEnd)
|
if (m_isEnd && other.m_isEnd)
|
||||||
return false;
|
return false;
|
||||||
|
@ -65,6 +65,7 @@ public:
|
||||||
|| m_bucketIndex != other.m_bucketIndex
|
|| m_bucketIndex != other.m_bucketIndex
|
||||||
|| m_bucketIterator != other.m_bucketIterator;
|
|| m_bucketIterator != other.m_bucketIterator;
|
||||||
}
|
}
|
||||||
|
bool operator==(const Iterator& other) const { return !(*this != other); }
|
||||||
T& operator*()
|
T& operator*()
|
||||||
{
|
{
|
||||||
#ifdef HASHTABLE_DEBUG
|
#ifdef HASHTABLE_DEBUG
|
||||||
|
@ -126,12 +127,12 @@ public:
|
||||||
typename DoublyLinkedList<T>::Iterator m_bucketIterator;
|
typename DoublyLinkedList<T>::Iterator m_bucketIterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
Iterator begin() { return Iterator(*this, false); }
|
Iterator begin() { return Iterator(*this, isEmpty()); }
|
||||||
Iterator end() { return Iterator(*this, true); }
|
Iterator end() { return Iterator(*this, true); }
|
||||||
|
|
||||||
class ConstIterator {
|
class ConstIterator {
|
||||||
public:
|
public:
|
||||||
bool operator!=(const ConstIterator& other)
|
bool operator!=(const ConstIterator& other) const
|
||||||
{
|
{
|
||||||
if (m_isEnd && other.m_isEnd)
|
if (m_isEnd && other.m_isEnd)
|
||||||
return false;
|
return false;
|
||||||
|
@ -140,6 +141,7 @@ public:
|
||||||
|| m_bucketIndex != other.m_bucketIndex
|
|| m_bucketIndex != other.m_bucketIndex
|
||||||
|| m_bucketIterator != other.m_bucketIterator;
|
|| m_bucketIterator != other.m_bucketIterator;
|
||||||
}
|
}
|
||||||
|
bool operator==(const ConstIterator& other) const { return !(*this != other); }
|
||||||
const T& operator*() const
|
const T& operator*() const
|
||||||
{
|
{
|
||||||
#ifdef HASHTABLE_DEBUG
|
#ifdef HASHTABLE_DEBUG
|
||||||
|
@ -203,7 +205,7 @@ public:
|
||||||
typename DoublyLinkedList<T>::ConstIterator m_bucketIterator;
|
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); }
|
ConstIterator end() const { return ConstIterator(*this, true); }
|
||||||
|
|
||||||
Iterator find(const T&);
|
Iterator find(const T&);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "StdLib.h"
|
#include "StdLib.h"
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
#include "Traits.h"
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
|
@ -96,6 +97,12 @@ make(Args&&... args)
|
||||||
return OwnPtr<T>(new T(forward<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;
|
using AK::OwnPtr;
|
||||||
|
|
20
AK/Vector.h
20
AK/Vector.h
|
@ -12,11 +12,12 @@ template<typename T>
|
||||||
class VectorImpl {
|
class VectorImpl {
|
||||||
public:
|
public:
|
||||||
~VectorImpl() { }
|
~VectorImpl() { }
|
||||||
static OwnPtr<VectorImpl> create(size_t capacity)
|
static VectorImpl* create(size_t capacity)
|
||||||
{
|
{
|
||||||
size_t size = sizeof(VectorImpl) + sizeof(T) * capacity;
|
size_t size = sizeof(VectorImpl) + sizeof(T) * capacity;
|
||||||
void* slot = kmalloc(size);
|
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; }
|
size_t size() const { return m_size; }
|
||||||
|
@ -59,14 +60,17 @@ public:
|
||||||
~Vector() { clear(); }
|
~Vector() { clear(); }
|
||||||
|
|
||||||
Vector(Vector&& other)
|
Vector(Vector&& other)
|
||||||
: m_impl(move(other.m_impl))
|
: m_impl(other.m_impl)
|
||||||
{
|
{
|
||||||
|
other.m_impl = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector& operator=(Vector&& other)
|
Vector& operator=(Vector&& other)
|
||||||
{
|
{
|
||||||
if (this != &other)
|
if (this != &other) {
|
||||||
m_impl = move(other.m_impl);
|
m_impl = other.m_impl;
|
||||||
|
other.m_impl = nullptr;
|
||||||
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +79,7 @@ public:
|
||||||
for (size_t i = 0; i < size(); ++i) {
|
for (size_t i = 0; i < size(); ++i) {
|
||||||
at(i).~T();
|
at(i).~T();
|
||||||
}
|
}
|
||||||
|
kfree(m_impl);
|
||||||
m_impl = nullptr;
|
m_impl = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,8 +139,9 @@ public:
|
||||||
new (newImpl->slot(i)) T(move(m_impl->at(i)));
|
new (newImpl->slot(i)) T(move(m_impl->at(i)));
|
||||||
m_impl->at(i).~T();
|
m_impl->at(i).~T();
|
||||||
}
|
}
|
||||||
|
kfree(m_impl);
|
||||||
}
|
}
|
||||||
m_impl = move(newImpl);
|
m_impl = newImpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Iterator {
|
class Iterator {
|
||||||
|
@ -174,7 +180,7 @@ private:
|
||||||
return max(size_t(4), capacity + (capacity / 4) + 4);
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "Compiler.h"
|
||||||
|
|
||||||
#ifdef SERENITY
|
#ifdef SERENITY
|
||||||
#ifdef USERLAND
|
#ifdef USERLAND
|
||||||
#include <LibC/stdlib.h>
|
#include <LibC/stdlib.h>
|
||||||
|
|
20
AK/test.cpp
20
AK/test.cpp
|
@ -16,6 +16,26 @@ static void testWeakPtr();
|
||||||
int main(int, char**)
|
int main(int, char**)
|
||||||
{
|
{
|
||||||
StringImpl::initializeGlobals();
|
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;
|
CircularQueue<int, 4> queue;
|
||||||
queue.dump();
|
queue.dump();
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
#include "ProcFileSystem.h"
|
#include "ProcFileSystem.h"
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
|
|
||||||
|
static ProcFileSystem* s_the;
|
||||||
|
|
||||||
|
ProcFileSystem& ProcFileSystem::the()
|
||||||
|
{
|
||||||
|
ASSERT(s_the);
|
||||||
|
return *s_the;
|
||||||
|
}
|
||||||
|
|
||||||
RetainPtr<ProcFileSystem> ProcFileSystem::create()
|
RetainPtr<ProcFileSystem> ProcFileSystem::create()
|
||||||
{
|
{
|
||||||
return adopt(*new ProcFileSystem);
|
return adopt(*new ProcFileSystem);
|
||||||
|
@ -8,15 +16,56 @@ RetainPtr<ProcFileSystem> ProcFileSystem::create()
|
||||||
|
|
||||||
ProcFileSystem::ProcFileSystem()
|
ProcFileSystem::ProcFileSystem()
|
||||||
{
|
{
|
||||||
|
s_the = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcFileSystem::~ProcFileSystem()
|
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()
|
bool ProcFileSystem::initialize()
|
||||||
{
|
{
|
||||||
SyntheticFileSystem::initialize();
|
SyntheticFileSystem::initialize();
|
||||||
|
|
||||||
|
auto d = addFile(createDirectory("sys"));
|
||||||
|
|
||||||
addFile(createGeneratedFile("summary", [] {
|
addFile(createGeneratedFile("summary", [] {
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
auto tasks = Task::allTasks();
|
auto tasks = Task::allTasks();
|
||||||
|
|
|
@ -3,15 +3,24 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <VirtualFileSystem/SyntheticFileSystem.h>
|
#include <VirtualFileSystem/SyntheticFileSystem.h>
|
||||||
|
|
||||||
|
class Task;
|
||||||
|
|
||||||
class ProcFileSystem final : public SyntheticFileSystem {
|
class ProcFileSystem final : public SyntheticFileSystem {
|
||||||
public:
|
public:
|
||||||
|
static ProcFileSystem& the();
|
||||||
|
|
||||||
virtual ~ProcFileSystem() override;
|
virtual ~ProcFileSystem() override;
|
||||||
static RetainPtr<ProcFileSystem> create();
|
static RetainPtr<ProcFileSystem> create();
|
||||||
|
|
||||||
virtual bool initialize() override;
|
virtual bool initialize() override;
|
||||||
virtual const char* className() const override;
|
virtual const char* className() const override;
|
||||||
|
|
||||||
|
void addProcess(Task&);
|
||||||
|
void removeProcess(Task&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProcFileSystem();
|
ProcFileSystem();
|
||||||
|
|
||||||
|
HashMap<pid_t, InodeIndex> m_pid2inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "errno.h"
|
#include "errno.h"
|
||||||
#include "i8253.h"
|
#include "i8253.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
|
#include "ProcFileSystem.h"
|
||||||
|
|
||||||
//#define DEBUG_IO
|
//#define DEBUG_IO
|
||||||
//#define TASK_DEBUG
|
//#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.
|
// HACK: Ring2 SS in the TSS is the current PID.
|
||||||
m_tss.ss2 = m_pid;
|
m_tss.ss2 = m_pid;
|
||||||
m_farPtr.offset = 0x98765432;
|
m_farPtr.offset = 0x98765432;
|
||||||
|
|
||||||
|
ProcFileSystem::the().addProcess(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Task::~Task()
|
Task::~Task()
|
||||||
{
|
{
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
|
ProcFileSystem::the().removeProcess(*this);
|
||||||
system.nprocess--;
|
system.nprocess--;
|
||||||
delete [] m_ldtEntries;
|
delete [] m_ldtEntries;
|
||||||
m_ldtEntries = nullptr;
|
m_ldtEntries = nullptr;
|
||||||
|
|
|
@ -15,6 +15,7 @@ class Zone;
|
||||||
|
|
||||||
class Task : public InlineLinkedListNode<Task> {
|
class Task : public InlineLinkedListNode<Task> {
|
||||||
friend class InlineLinkedListNode<Task>;
|
friend class InlineLinkedListNode<Task>;
|
||||||
|
class Region;
|
||||||
public:
|
public:
|
||||||
static Task* createKernelTask(void (*entry)(), String&& name);
|
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);
|
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*);
|
static void taskDidCrash(Task*);
|
||||||
|
|
||||||
|
size_t regionCount() const { return m_regions.size(); }
|
||||||
|
const Vector<OwnPtr<Region>>& regions() const { return m_regions; }
|
||||||
void dumpRegions();
|
void dumpRegions();
|
||||||
|
|
||||||
void didSchedule() { ++m_timesScheduled; }
|
void didSchedule() { ++m_timesScheduled; }
|
||||||
|
|
|
@ -108,9 +108,7 @@ static void init_stage2()
|
||||||
|
|
||||||
vfs->mountRoot(e2fs.copyRef());
|
vfs->mountRoot(e2fs.copyRef());
|
||||||
|
|
||||||
auto procfs = ProcFileSystem::create();
|
vfs->mount(ProcFileSystem::the(), "/proc");
|
||||||
procfs->initialize();
|
|
||||||
vfs->mount(procfs.copyRef(), "/proc");
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -200,6 +198,9 @@ void init()
|
||||||
kprintf("%u kB base memory\n", base_memory);
|
kprintf("%u kB base memory\n", base_memory);
|
||||||
kprintf("%u kB extended memory\n", ext_memory);
|
kprintf("%u kB extended memory\n", ext_memory);
|
||||||
|
|
||||||
|
auto procfs = ProcFileSystem::create();
|
||||||
|
procfs->initialize();
|
||||||
|
|
||||||
Task::initialize();
|
Task::initialize();
|
||||||
|
|
||||||
Task::createKernelTask(undertaker_main, "undertaker");
|
Task::createKernelTask(undertaker_main, "undertaker");
|
||||||
|
|
|
@ -133,7 +133,7 @@ bool FileHandle::isDirectory() const
|
||||||
return m_vnode->metadata().isDirectory();
|
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());
|
Locker locker(VirtualFileSystem::lock());
|
||||||
|
|
||||||
|
|
|
@ -21,21 +21,36 @@ bool SyntheticFileSystem::initialize()
|
||||||
// Add a File for the root directory.
|
// Add a File for the root directory.
|
||||||
// FIXME: This needs work.
|
// FIXME: This needs work.
|
||||||
auto rootDir = make<File>();
|
auto rootDir = make<File>();
|
||||||
rootDir->metadata.inode = { id(), 1 };
|
rootDir->metadata.inode = { id(), RootInodeIndex };
|
||||||
|
rootDir->parent = { id(), RootInodeIndex };
|
||||||
rootDir->metadata.mode = 0040555;
|
rootDir->metadata.mode = 0040555;
|
||||||
rootDir->metadata.uid = 0;
|
rootDir->metadata.uid = 0;
|
||||||
rootDir->metadata.gid = 0;
|
rootDir->metadata.gid = 0;
|
||||||
rootDir->metadata.size = 0;
|
rootDir->metadata.size = 0;
|
||||||
rootDir->metadata.mtime = mepoch;
|
rootDir->metadata.mtime = mepoch;
|
||||||
m_files.append(move(rootDir));
|
m_inodes.set(RootInodeIndex, move(rootDir));
|
||||||
|
|
||||||
|
#if 0
|
||||||
#ifndef SERENITY
|
#ifndef SERENITY
|
||||||
addFile(createTextFile("file", "I'm a synthetic file!\n"));
|
addFile(createTextFile("file", "I'm a synthetic file!\n"));
|
||||||
addFile(createTextFile("message", "Hey! This isn't my bottle!\n"));
|
addFile(createTextFile("message", "Hey! This isn't my bottle!\n"));
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
return true;
|
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 SyntheticFileSystem::createTextFile(String&& name, String&& text) -> OwnPtr<File>
|
||||||
{
|
{
|
||||||
auto file = make<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.size = file->data.size();
|
||||||
file->metadata.uid = 100;
|
file->metadata.uid = 100;
|
||||||
file->metadata.gid = 200;
|
file->metadata.gid = 200;
|
||||||
file->metadata.mode = 0100644;
|
file->metadata.mode = 04;
|
||||||
file->metadata.mtime = mepoch;
|
file->metadata.mtime = mepoch;
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
@ -62,11 +77,42 @@ auto SyntheticFileSystem::createGeneratedFile(String&& name, Function<ByteBuffer
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SyntheticFileSystem::addFile(OwnPtr<File>&& file)
|
InodeIdentifier SyntheticFileSystem::addFile(OwnPtr<File>&& file, InodeIndex parent)
|
||||||
{
|
{
|
||||||
ASSERT(file);
|
ASSERT(file);
|
||||||
file->metadata.inode = { id(), m_files.size() + 1 };
|
auto it = m_inodes.find(parent);
|
||||||
m_files.append(move(file));
|
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
|
const char* SyntheticFileSystem::className() const
|
||||||
|
@ -85,14 +131,20 @@ bool SyntheticFileSystem::enumerateDirectoryInode(InodeIdentifier inode, Functio
|
||||||
#ifdef SYNTHFS_DEBUG
|
#ifdef SYNTHFS_DEBUG
|
||||||
kprintf("[synthfs] enumerateDirectoryInode %u\n", inode.index());
|
kprintf("[synthfs] enumerateDirectoryInode %u\n", inode.index());
|
||||||
#endif
|
#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;
|
return false;
|
||||||
|
|
||||||
callback({ ".", m_files[0]->metadata.inode });
|
callback({ ".", synInode.metadata.inode });
|
||||||
callback({ "..", m_files[0]->metadata.inode });
|
callback({ "..", synInode.parent });
|
||||||
|
|
||||||
for (unsigned i = 1; i < m_files.size(); ++i)
|
for (auto& child : synInode.children) {
|
||||||
callback({ m_files[i]->name, m_files[i]->metadata.inode });
|
callback({ child->name, child->metadata.inode });
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,10 +154,11 @@ InodeMetadata SyntheticFileSystem::inodeMetadata(InodeIdentifier inode) const
|
||||||
#ifdef SYNTHFS_DEBUG
|
#ifdef SYNTHFS_DEBUG
|
||||||
kprintf("[synthfs] inodeMetadata(%u)\n", inode.index());
|
kprintf("[synthfs] inodeMetadata(%u)\n", inode.index());
|
||||||
#endif
|
#endif
|
||||||
if (inode.index() == 0 || inode.index() > m_files.size())
|
|
||||||
return InodeMetadata();
|
auto it = m_inodes.find(inode.index());
|
||||||
auto& file = *m_files[inode.index() - 1];
|
if (it == m_inodes.end())
|
||||||
return file.metadata;
|
return { };
|
||||||
|
return (*it).value->metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SyntheticFileSystem::setModificationTime(InodeIdentifier, dword timestamp)
|
bool SyntheticFileSystem::setModificationTime(InodeIdentifier, dword timestamp)
|
||||||
|
@ -120,6 +173,7 @@ InodeIdentifier SyntheticFileSystem::createInode(InodeIdentifier parentInode, co
|
||||||
(void) parentInode;
|
(void) parentInode;
|
||||||
(void) name;
|
(void) name;
|
||||||
(void) mode;
|
(void) mode;
|
||||||
|
(void) size;
|
||||||
kprintf("FIXME: Implement SyntheticFileSystem::createDirectoryInode().\n");
|
kprintf("FIXME: Implement SyntheticFileSystem::createDirectoryInode().\n");
|
||||||
return { };
|
return { };
|
||||||
}
|
}
|
||||||
|
@ -136,12 +190,13 @@ Unix::ssize_t SyntheticFileSystem::readInodeBytes(InodeIdentifier inode, Unix::o
|
||||||
#ifdef SYNTHFS_DEBUG
|
#ifdef SYNTHFS_DEBUG
|
||||||
kprintf("[synthfs] readInode %u\n", inode.index());
|
kprintf("[synthfs] readInode %u\n", inode.index());
|
||||||
#endif
|
#endif
|
||||||
ASSERT(inode.index() != 1);
|
|
||||||
ASSERT(inode.index() <= m_files.size());
|
|
||||||
ASSERT(offset >= 0);
|
ASSERT(offset >= 0);
|
||||||
ASSERT(buffer);
|
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;
|
ByteBuffer generatedData;
|
||||||
if (file.generator)
|
if (file.generator)
|
||||||
generatedData = 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)
|
InodeIdentifier SyntheticFileSystem::makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t)
|
||||||
{
|
{
|
||||||
|
(void) parentInode;
|
||||||
|
(void) name;
|
||||||
kprintf("FIXME: Implement SyntheticFileSystem::makeDirectory().\n");
|
kprintf("FIXME: Implement SyntheticFileSystem::makeDirectory().\n");
|
||||||
return { };
|
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;
|
virtual InodeIdentifier makeDirectory(InodeIdentifier parentInode, const String& name, Unix::mode_t) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
typedef unsigned InodeIndex;
|
||||||
|
|
||||||
|
InodeIndex generateInodeIndex();
|
||||||
|
static constexpr InodeIndex RootInodeIndex = 1;
|
||||||
|
|
||||||
SyntheticFileSystem();
|
SyntheticFileSystem();
|
||||||
|
|
||||||
struct File {
|
struct File {
|
||||||
String name;
|
String name;
|
||||||
InodeMetadata metadata;
|
InodeMetadata metadata;
|
||||||
|
InodeIdentifier parent;
|
||||||
ByteBuffer data;
|
ByteBuffer data;
|
||||||
Function<ByteBuffer()> generator;
|
Function<ByteBuffer()> generator;
|
||||||
|
Vector<File*> children;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
OwnPtr<File> createDirectory(String&& name);
|
||||||
OwnPtr<File> createTextFile(String&& name, String&& text);
|
OwnPtr<File> createTextFile(String&& name, String&& text);
|
||||||
OwnPtr<File> createGeneratedFile(String&& name, Function<ByteBuffer()>&&);
|
OwnPtr<File> createGeneratedFile(String&& name, Function<ByteBuffer()>&&);
|
||||||
|
|
||||||
void addFile(OwnPtr<File>&&);
|
InodeIdentifier addFile(OwnPtr<File>&&, InodeIndex parent = RootInodeIndex);
|
||||||
|
bool removeFile(InodeIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vector<OwnPtr<File>> m_files;
|
InodeIndex m_nextInodeIndex { 2 };
|
||||||
|
HashMap<InodeIndex, OwnPtr<File>> m_inodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ VirtualFileSystem::VirtualFileSystem()
|
||||||
VirtualFileSystem::~VirtualFileSystem()
|
VirtualFileSystem::~VirtualFileSystem()
|
||||||
{
|
{
|
||||||
kprintf("[VFS] ~VirtualFileSystem with %u nodes allocated\n", allocatedNodeCount());
|
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>
|
auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
|
||||||
|
|
Loading…
Reference in a new issue