mirror of
https://github.com/RGBCube/serenity
synced 2025-05-24 18:35:07 +00:00
Lots of hacking to make a very simple "ls" utility.
I added a dead-simple malloc that only allows allocations < 4096 bytes. It just forwards the request to mmap() every time. I also added simplified versions of opendir() and readdir().
This commit is contained in:
parent
0c5bbac86e
commit
bca4b71bfa
19 changed files with 277 additions and 67 deletions
54
AK/BufferStream.h
Normal file
54
AK/BufferStream.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ByteBuffer.h"
|
||||||
|
|
||||||
|
namespace AK {
|
||||||
|
|
||||||
|
class BufferStream {
|
||||||
|
public:
|
||||||
|
explicit BufferStream(ByteBuffer& buffer)
|
||||||
|
: m_buffer(buffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator<<(byte value)
|
||||||
|
{
|
||||||
|
m_buffer[m_offset++] = value & 0xffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator<<(word value)
|
||||||
|
{
|
||||||
|
m_buffer[m_offset++] = value & 0xffu;
|
||||||
|
m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator<<(dword value)
|
||||||
|
{
|
||||||
|
m_buffer[m_offset++] = value & 0xffu;
|
||||||
|
m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu;
|
||||||
|
m_buffer[m_offset++] = (byte)(value >> 16) & 0xffu;
|
||||||
|
m_buffer[m_offset++] = (byte)(value >> 24) & 0xffu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator<<(const String& value)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < value.length(); ++i)
|
||||||
|
m_buffer[m_offset++] = value[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void fillToEnd(byte ch)
|
||||||
|
{
|
||||||
|
while (m_offset < m_buffer.size())
|
||||||
|
m_buffer[m_offset++] = ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unix::size_t offset() const { return m_offset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ByteBuffer& m_buffer;
|
||||||
|
Unix::size_t m_offset { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using AK::BufferStream;
|
|
@ -21,17 +21,18 @@ bool ProcFileSystem::initialize()
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
auto tasks = Task::allTasks();
|
auto tasks = Task::allTasks();
|
||||||
char* buffer;
|
char* buffer;
|
||||||
auto stringImpl = StringImpl::createUninitialized(tasks.size() * 128, buffer);
|
auto stringImpl = StringImpl::createUninitialized(tasks.size() * 256, buffer);
|
||||||
memset(buffer, 0, stringImpl->length());
|
memset(buffer, 0, stringImpl->length());
|
||||||
char* ptr = buffer;
|
char* ptr = buffer;
|
||||||
ptr += ksprintf(ptr, "PID OWNER STATE NSCHED NAME\n");
|
ptr += ksprintf(ptr, "PID OWNER STATE NSCHED FDS NAME\n");
|
||||||
for (auto* task : tasks) {
|
for (auto* task : tasks) {
|
||||||
ptr += ksprintf(ptr, "%w %w:%w %b %w %s\n",
|
ptr += ksprintf(ptr, "%w %w:%w %b %w %w %s\n",
|
||||||
task->pid(),
|
task->pid(),
|
||||||
task->uid(),
|
task->uid(),
|
||||||
task->gid(),
|
task->gid(),
|
||||||
task->state(),
|
task->state(),
|
||||||
task->timesScheduled(),
|
task->timesScheduled(),
|
||||||
|
task->fileHandleCount(),
|
||||||
task->name().characters());
|
task->name().characters());
|
||||||
}
|
}
|
||||||
ptr += ksprintf(ptr, "kmalloc: alloc: %u / free: %u\n", sum_alloc, sum_free);
|
ptr += ksprintf(ptr, "kmalloc: alloc: %u / free: %u\n", sum_alloc, sum_free);
|
||||||
|
|
|
@ -66,6 +66,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
||||||
break;
|
break;
|
||||||
case Syscall::Spawn:
|
case Syscall::Spawn:
|
||||||
return current->sys$spawn((const char*)arg1);
|
return current->sys$spawn((const char*)arg1);
|
||||||
|
case Syscall::GetDirEntries:
|
||||||
|
return current->sys$get_dir_entries((int)arg1, (void*)arg2, (size_t)arg3);
|
||||||
case Syscall::PosixOpen:
|
case Syscall::PosixOpen:
|
||||||
//kprintf("syscall: open('%s', %u)\n", arg1, arg2);
|
//kprintf("syscall: open('%s', %u)\n", arg1, arg2);
|
||||||
return current->sys$open((const char*)arg1, (size_t)arg2);
|
return current->sys$open((const char*)arg1, (size_t)arg2);
|
||||||
|
|
|
@ -26,6 +26,7 @@ enum Function {
|
||||||
PosixWaitpid = 0x1994,
|
PosixWaitpid = 0x1994,
|
||||||
PosixMmap = 0x1995,
|
PosixMmap = 0x1995,
|
||||||
PosixMunmap = 0x1996,
|
PosixMunmap = 0x1996,
|
||||||
|
GetDirEntries = 0x1997,
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
|
@ -230,6 +230,10 @@ Task::Task(String&& name, uid_t uid, gid_t gid)
|
||||||
, m_state(Runnable)
|
, m_state(Runnable)
|
||||||
, m_ring(Ring3)
|
, m_ring(Ring3)
|
||||||
{
|
{
|
||||||
|
m_fileHandles.append(nullptr);
|
||||||
|
m_fileHandles.append(nullptr);
|
||||||
|
m_fileHandles.append(nullptr);
|
||||||
|
|
||||||
m_nextRegion = LinearAddress(0x600000);
|
m_nextRegion = LinearAddress(0x600000);
|
||||||
|
|
||||||
memset(&m_tss, 0, sizeof(m_tss));
|
memset(&m_tss, 0, sizeof(m_tss));
|
||||||
|
@ -280,6 +284,10 @@ Task::Task(void (*e)(), const char* n, IPC::Handle h, RingLevel ring)
|
||||||
, m_state(Runnable)
|
, m_state(Runnable)
|
||||||
, m_ring(ring)
|
, m_ring(ring)
|
||||||
{
|
{
|
||||||
|
m_fileHandles.append(nullptr);
|
||||||
|
m_fileHandles.append(nullptr);
|
||||||
|
m_fileHandles.append(nullptr);
|
||||||
|
|
||||||
m_nextRegion = LinearAddress(0x600000);
|
m_nextRegion = LinearAddress(0x600000);
|
||||||
|
|
||||||
Region* codeRegion = nullptr;
|
Region* codeRegion = nullptr;
|
||||||
|
@ -643,6 +651,14 @@ FileHandle* Task::fileHandleIfExists(int fd)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Task::sys$get_dir_entries(int fd, void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
auto* handle = fileHandleIfExists(fd);
|
||||||
|
if (!handle)
|
||||||
|
return -1;
|
||||||
|
return handle->get_dir_entries((byte*)buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
int Task::sys$seek(int fd, int offset)
|
int Task::sys$seek(int fd, int offset)
|
||||||
{
|
{
|
||||||
auto* handle = fileHandleIfExists(fd);
|
auto* handle = fileHandleIfExists(fd);
|
||||||
|
|
|
@ -101,6 +101,7 @@ public:
|
||||||
pid_t sys$waitpid(pid_t);
|
pid_t sys$waitpid(pid_t);
|
||||||
void* sys$mmap(void*, size_t size);
|
void* sys$mmap(void*, size_t size);
|
||||||
int sys$munmap(void*, size_t size);
|
int sys$munmap(void*, size_t size);
|
||||||
|
int sys$get_dir_entries(int fd, void*, size_t);
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -122,6 +123,8 @@ public:
|
||||||
|
|
||||||
pid_t waitee() const { return m_waitee; }
|
pid_t waitee() const { return m_waitee; }
|
||||||
|
|
||||||
|
size_t fileHandleCount() const { return m_fileHandles.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MemoryManager;
|
friend class MemoryManager;
|
||||||
|
|
||||||
|
|
Binary file not shown.
|
@ -4,6 +4,8 @@ OBJS = \
|
||||||
string.o \
|
string.o \
|
||||||
process.o \
|
process.o \
|
||||||
mman.o \
|
mman.o \
|
||||||
|
dirent.o \
|
||||||
|
stdlib.o \
|
||||||
entry.o
|
entry.o
|
||||||
|
|
||||||
LIBRARY = LibC.a
|
LIBRARY = LibC.a
|
||||||
|
|
67
LibC/dirent.cpp
Normal file
67
LibC/dirent.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "dirent.h"
|
||||||
|
#include "unistd.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include <Kernel/Syscall.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
DIR* opendir(const char* name)
|
||||||
|
{
|
||||||
|
// FIXME: Should fail if it's not a directory!
|
||||||
|
int fd = open(name);
|
||||||
|
if (fd == -1)
|
||||||
|
return nullptr;
|
||||||
|
DIR* dirp = (DIR*)malloc(sizeof(dirp));
|
||||||
|
dirp->fd = fd;
|
||||||
|
dirp->buffer = nullptr;
|
||||||
|
dirp->buffer_size = 0;
|
||||||
|
dirp->nextptr = nullptr;
|
||||||
|
return dirp;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sys_dirent {
|
||||||
|
ino_t ino;
|
||||||
|
byte file_type;
|
||||||
|
size_t namelen;
|
||||||
|
char name[];
|
||||||
|
size_t total_size()
|
||||||
|
{
|
||||||
|
return sizeof(ino_t) + sizeof(byte) + sizeof(size_t) + sizeof(char) * namelen;
|
||||||
|
}
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
dirent* readdir(DIR* dirp)
|
||||||
|
{
|
||||||
|
if (!dirp)
|
||||||
|
return nullptr;
|
||||||
|
if (dirp->fd == -1)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!dirp->buffer) {
|
||||||
|
// FIXME: Figure out how much to actually allocate.
|
||||||
|
dirp->buffer = (char*)malloc(4096);
|
||||||
|
ssize_t nread = Syscall::invoke(Syscall::GetDirEntries, (dword)dirp->fd, (dword)dirp->buffer, 4096);
|
||||||
|
dirp->buffer_size = nread;
|
||||||
|
dirp->nextptr = dirp->buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirp->nextptr > (dirp->buffer + dirp->buffer_size))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
auto* sys_ent = (sys_dirent*)dirp->nextptr;
|
||||||
|
dirp->cur_ent.d_ino = sys_ent->ino;
|
||||||
|
dirp->cur_ent.d_type = sys_ent->file_type;
|
||||||
|
dirp->cur_ent.d_off = 0;
|
||||||
|
dirp->cur_ent.d_reclen = sys_ent->total_size();
|
||||||
|
for (size_t i = 0; i < sys_ent->namelen; ++i)
|
||||||
|
dirp->cur_ent.d_name[i] = sys_ent->name[i];
|
||||||
|
// FIXME: I think this null termination behavior is not supposed to be here.
|
||||||
|
dirp->cur_ent.d_name[sys_ent->namelen] = '\0';
|
||||||
|
|
||||||
|
dirp->nextptr += sys_ent->total_size();
|
||||||
|
return &dirp->cur_ent;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
27
LibC/dirent.h
Normal file
27
LibC/dirent.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
struct dirent {
|
||||||
|
ino_t d_ino;
|
||||||
|
off_t d_off;
|
||||||
|
unsigned short d_reclen;
|
||||||
|
unsigned char d_type;
|
||||||
|
char d_name[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DIR {
|
||||||
|
int fd;
|
||||||
|
dirent cur_ent;
|
||||||
|
char* buffer;
|
||||||
|
size_t buffer_size;
|
||||||
|
char* nextptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
DIR* opendir(const char* name);
|
||||||
|
dirent* readdir(DIR* dirp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
24
LibC/stdlib.cpp
Normal file
24
LibC/stdlib.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "mman.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void* malloc(size_t size)
|
||||||
|
{
|
||||||
|
if (size > 4096) {
|
||||||
|
volatile char* crashme = (char*)0xc007d00d;
|
||||||
|
*crashme = 0;
|
||||||
|
}
|
||||||
|
void* ptr = mmap(nullptr, 4096);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* ptr)
|
||||||
|
{
|
||||||
|
if (!ptr)
|
||||||
|
return;
|
||||||
|
munmap(ptr, 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
11
LibC/stdlib.h
Normal file
11
LibC/stdlib.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void* malloc(size_t);
|
||||||
|
void free(void*);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -17,5 +17,8 @@ typedef dword pid_t;
|
||||||
typedef dword size_t;
|
typedef dword size_t;
|
||||||
typedef signed_dword ssize_t;
|
typedef signed_dword ssize_t;
|
||||||
|
|
||||||
|
typedef dword ino_t;
|
||||||
|
typedef signed_dword off_t;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
#include <LibC/stdio.h>
|
#include <LibC/stdio.h>
|
||||||
#include <LibC/unistd.h>
|
#include <LibC/unistd.h>
|
||||||
#include <LibC/mman.h>
|
#include <LibC/dirent.h>
|
||||||
|
|
||||||
int main(int c, char** v)
|
int main(int c, char** v)
|
||||||
{
|
{
|
||||||
int fd = open("/");
|
DIR* dirp = opendir("/");
|
||||||
if (fd == -1) {
|
if (!dirp) {
|
||||||
printf("failed to open / :(\n");
|
printf("opendir failed :(\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
while (auto* de = readdir(dirp)) {
|
||||||
|
printf("%s\n", de->d_name);
|
||||||
|
|
||||||
byte* memory = (byte*)mmap(nullptr, 16384);
|
}
|
||||||
printf("%p\n", memory);
|
|
||||||
memory[0] = 'H';
|
|
||||||
memory[1] = 'i';
|
|
||||||
memory[2] = '!';
|
|
||||||
memory[3] = '\0';
|
|
||||||
printf("%p : %s\n", memory, memory);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <AK/kmalloc.h>
|
#include <AK/kmalloc.h>
|
||||||
#include <AK/ktime.h>
|
#include <AK/ktime.h>
|
||||||
#include <AK/kstdio.h>
|
#include <AK/kstdio.h>
|
||||||
|
#include <AK/BufferStream.h>
|
||||||
#include "sys-errno.h"
|
#include "sys-errno.h"
|
||||||
|
|
||||||
//#define EXT2_DEBUG
|
//#define EXT2_DEBUG
|
||||||
|
@ -431,49 +432,6 @@ bool Ext2FileSystem::addInodeToDirectory(unsigned directoryInode, unsigned inode
|
||||||
return writeDirectoryInode(directoryInode, move(entries));
|
return writeDirectoryInode(directoryInode, move(entries));
|
||||||
}
|
}
|
||||||
|
|
||||||
class BufferStream {
|
|
||||||
public:
|
|
||||||
explicit BufferStream(ByteBuffer& buffer)
|
|
||||||
: m_buffer(buffer)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator<<(byte value)
|
|
||||||
{
|
|
||||||
m_buffer[m_offset++] = value & 0xffu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator<<(word value)
|
|
||||||
{
|
|
||||||
m_buffer[m_offset++] = value & 0xffu;
|
|
||||||
m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator<<(dword value)
|
|
||||||
{
|
|
||||||
m_buffer[m_offset++] = value & 0xffu;
|
|
||||||
m_buffer[m_offset++] = (byte)(value >> 8) & 0xffu;
|
|
||||||
m_buffer[m_offset++] = (byte)(value >> 16) & 0xffu;
|
|
||||||
m_buffer[m_offset++] = (byte)(value >> 24) & 0xffu;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator<<(const String& value)
|
|
||||||
{
|
|
||||||
for (unsigned i = 0; i < value.length(); ++i)
|
|
||||||
m_buffer[m_offset++] = value[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void fillToEnd(byte ch)
|
|
||||||
{
|
|
||||||
while (m_offset < m_buffer.size())
|
|
||||||
m_buffer[m_offset++] = ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ByteBuffer& m_buffer;
|
|
||||||
Unix::size_t m_offset { 0 };
|
|
||||||
};
|
|
||||||
|
|
||||||
bool Ext2FileSystem::writeDirectoryInode(unsigned directoryInode, Vector<DirectoryEntry>&& entries)
|
bool Ext2FileSystem::writeDirectoryInode(unsigned directoryInode, Vector<DirectoryEntry>&& entries)
|
||||||
{
|
{
|
||||||
kprintf("[ext2fs] New directory inode %u contents to write:\n", directoryInode);
|
kprintf("[ext2fs] New directory inode %u contents to write:\n", directoryInode);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "CharacterDevice.h"
|
#include "CharacterDevice.h"
|
||||||
#include "sys-errno.h"
|
#include "sys-errno.h"
|
||||||
#include "UnixTypes.h"
|
#include "UnixTypes.h"
|
||||||
|
#include <AK/BufferStream.h>
|
||||||
|
|
||||||
FileHandle::FileHandle(RetainPtr<VirtualFileSystem::Node>&& vnode)
|
FileHandle::FileHandle(RetainPtr<VirtualFileSystem::Node>&& vnode)
|
||||||
: m_vnode(move(vnode))
|
: m_vnode(move(vnode))
|
||||||
|
@ -29,7 +30,7 @@ int FileHandle::stat(Unix::stat* buffer)
|
||||||
if (!m_vnode)
|
if (!m_vnode)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
auto metadata = m_vnode->inode.metadata();
|
auto metadata = m_vnode->metadata();
|
||||||
if (!metadata.isValid())
|
if (!metadata.isValid())
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ Unix::off_t FileHandle::seek(Unix::off_t offset, int whence)
|
||||||
|
|
||||||
// FIXME: The file type should be cached on the vnode.
|
// FIXME: The file type should be cached on the vnode.
|
||||||
// It's silly that we have to do a full metadata lookup here.
|
// It's silly that we have to do a full metadata lookup here.
|
||||||
auto metadata = m_vnode->inode.metadata();
|
auto metadata = m_vnode->metadata();
|
||||||
if (!metadata.isValid())
|
if (!metadata.isValid())
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
|
@ -120,3 +121,27 @@ ByteBuffer FileHandle::readEntireFile()
|
||||||
return m_vnode->fileSystem()->readEntireInode(m_vnode->inode);
|
return m_vnode->fileSystem()->readEntireInode(m_vnode->inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t FileHandle::get_dir_entries(byte* buffer, size_t size)
|
||||||
|
{
|
||||||
|
Locker locker(VirtualFileSystem::lock());
|
||||||
|
|
||||||
|
auto metadata = m_vnode->metadata();
|
||||||
|
if (!metadata.isValid())
|
||||||
|
return -EIO;
|
||||||
|
if (!metadata.isDirectory())
|
||||||
|
return -ENOTDIR;
|
||||||
|
|
||||||
|
// FIXME: Compute the actual size needed.
|
||||||
|
auto tempBuffer = ByteBuffer::createUninitialized(2048);
|
||||||
|
BufferStream stream(tempBuffer);
|
||||||
|
m_vnode->vfs()->enumerateDirectoryInode(m_vnode->inode, [&stream] (const FileSystem::DirectoryEntry& entry) {
|
||||||
|
stream << (dword)entry.inode.index();
|
||||||
|
stream << (byte)entry.fileType;
|
||||||
|
stream << (dword)entry.name.length();
|
||||||
|
stream << entry.name;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
memcpy(buffer, tempBuffer.pointer(), stream.offset());
|
||||||
|
return stream.offset();
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ public:
|
||||||
Unix::ssize_t read(byte* buffer, Unix::size_t count);
|
Unix::ssize_t read(byte* buffer, Unix::size_t count);
|
||||||
int stat(Unix::stat*);
|
int stat(Unix::stat*);
|
||||||
|
|
||||||
|
ssize_t get_dir_entries(byte* buffer, Unix::size_t);
|
||||||
|
|
||||||
ByteBuffer readEntireFile();
|
ByteBuffer readEntireFile();
|
||||||
|
|
||||||
#ifdef SERENITY
|
#ifdef SERENITY
|
||||||
|
|
|
@ -78,6 +78,7 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
|
||||||
fileSystem->retain();
|
fileSystem->retain();
|
||||||
|
|
||||||
vnode->inode = inode;
|
vnode->inode = inode;
|
||||||
|
vnode->m_cachedMetadata = { };
|
||||||
|
|
||||||
#ifdef VFS_DEBUG
|
#ifdef VFS_DEBUG
|
||||||
kprintf("makeNode: inode=%u, size=%u, mode=%o, uid=%u, gid=%u\n", inode.index(), metadata.size, metadata.mode, metadata.uid, metadata.gid);
|
kprintf("makeNode: inode=%u, size=%u, mode=%o, uid=%u, gid=%u\n", inode.index(), metadata.size, metadata.mode, metadata.uid, metadata.gid);
|
||||||
|
@ -85,6 +86,7 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
|
||||||
|
|
||||||
m_inode2vnode.set(inode, vnode.ptr());
|
m_inode2vnode.set(inode, vnode.ptr());
|
||||||
vnode->m_characterDevice = characterDevice;
|
vnode->m_characterDevice = characterDevice;
|
||||||
|
|
||||||
return vnode;
|
return vnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +153,7 @@ auto VirtualFileSystem::allocateNode() -> RetainPtr<Node>
|
||||||
auto* node = m_nodeFreeList.takeLast();
|
auto* node = m_nodeFreeList.takeLast();
|
||||||
ASSERT(node->retainCount == 0);
|
ASSERT(node->retainCount == 0);
|
||||||
node->retainCount = 1;
|
node->retainCount = 1;
|
||||||
node->vfs = this;
|
node->m_vfs = this;
|
||||||
return adopt(*node);
|
return adopt(*node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,8 +200,7 @@ bool VirtualFileSystem::isRoot(InodeIdentifier inode) const
|
||||||
return inode == m_rootNode->inode;
|
return inode == m_rootNode->inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode, Function<bool(const FileSystem::DirectoryEntry&)> callback)
|
||||||
void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode, F func)
|
|
||||||
{
|
{
|
||||||
if (!directoryInode.isValid())
|
if (!directoryInode.isValid())
|
||||||
return;
|
return;
|
||||||
|
@ -216,7 +217,7 @@ void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode,
|
||||||
ASSERT(mount);
|
ASSERT(mount);
|
||||||
resolvedInode = mount->host();
|
resolvedInode = mount->host();
|
||||||
}
|
}
|
||||||
func({ entry.name, resolvedInode });
|
callback({ entry.name, resolvedInode });
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -340,6 +341,7 @@ void VirtualFileSystem::listDirectoryRecursively(const String& path)
|
||||||
} else {
|
} else {
|
||||||
kprintf("%s/%s\n", path.characters(), entry.name.characters());
|
kprintf("%s/%s\n", path.characters(), entry.name.characters());
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -467,10 +469,17 @@ void VirtualFileSystem::Node::release()
|
||||||
{
|
{
|
||||||
ASSERT(retainCount);
|
ASSERT(retainCount);
|
||||||
if (--retainCount == 0) {
|
if (--retainCount == 0) {
|
||||||
vfs->freeNode(this);
|
m_vfs->freeNode(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const InodeMetadata& VirtualFileSystem::Node::metadata() const
|
||||||
|
{
|
||||||
|
if (!m_cachedMetadata.isValid())
|
||||||
|
m_cachedMetadata = inode.metadata();
|
||||||
|
return m_cachedMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
VirtualFileSystem::Mount::Mount(InodeIdentifier host, RetainPtr<FileSystem>&& guestFileSystem)
|
VirtualFileSystem::Mount::Mount(InodeIdentifier host, RetainPtr<FileSystem>&& guestFileSystem)
|
||||||
: m_host(host)
|
: m_host(host)
|
||||||
, m_guest(guestFileSystem->rootInode())
|
, m_guest(guestFileSystem->rootInode())
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <AK/Lock.h>
|
#include <AK/Lock.h>
|
||||||
|
#include <AK/Function.h>
|
||||||
#include "InodeIdentifier.h"
|
#include "InodeIdentifier.h"
|
||||||
|
#include "InodeMetadata.h"
|
||||||
#include "Limits.h"
|
#include "Limits.h"
|
||||||
|
#include "FileSystem.h"
|
||||||
|
|
||||||
class CharacterDevice;
|
class CharacterDevice;
|
||||||
class FileHandle;
|
class FileHandle;
|
||||||
class FileSystem;
|
|
||||||
|
|
||||||
class VirtualFileSystem {
|
class VirtualFileSystem {
|
||||||
public:
|
public:
|
||||||
|
@ -20,6 +22,7 @@ public:
|
||||||
|
|
||||||
struct Node {
|
struct Node {
|
||||||
InodeIdentifier inode;
|
InodeIdentifier inode;
|
||||||
|
const InodeMetadata& metadata() const;
|
||||||
|
|
||||||
bool inUse() const { return inode.isValid(); }
|
bool inUse() const { return inode.isValid(); }
|
||||||
|
|
||||||
|
@ -32,11 +35,15 @@ public:
|
||||||
FileSystem* fileSystem() { return inode.fileSystem(); }
|
FileSystem* fileSystem() { return inode.fileSystem(); }
|
||||||
const FileSystem* fileSystem() const { return inode.fileSystem(); }
|
const FileSystem* fileSystem() const { return inode.fileSystem(); }
|
||||||
|
|
||||||
|
VirtualFileSystem* vfs() { return m_vfs; }
|
||||||
|
const VirtualFileSystem* vfs() const { return m_vfs; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class VirtualFileSystem;
|
friend class VirtualFileSystem;
|
||||||
VirtualFileSystem* vfs { nullptr };
|
VirtualFileSystem* m_vfs { nullptr };
|
||||||
unsigned retainCount { 0 };
|
unsigned retainCount { 0 };
|
||||||
CharacterDevice* m_characterDevice { nullptr };
|
CharacterDevice* m_characterDevice { nullptr };
|
||||||
|
mutable InodeMetadata m_cachedMetadata;
|
||||||
};
|
};
|
||||||
|
|
||||||
static VirtualFileSystem& the();
|
static VirtualFileSystem& the();
|
||||||
|
@ -68,7 +75,9 @@ public:
|
||||||
void registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice&);
|
void registerCharacterDevice(unsigned major, unsigned minor, CharacterDevice&);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename F> void enumerateDirectoryInode(InodeIdentifier, F func);
|
friend class FileHandle;
|
||||||
|
|
||||||
|
void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>);
|
||||||
InodeIdentifier resolvePath(const String& path);
|
InodeIdentifier resolvePath(const String& path);
|
||||||
InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode);
|
InodeIdentifier resolveSymbolicLink(const String& basePath, InodeIdentifier symlinkInode);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue