1
Fork 0
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:
Andreas Kling 2018-10-24 12:43:52 +02:00
parent 0c5bbac86e
commit bca4b71bfa
19 changed files with 277 additions and 67 deletions

54
AK/BufferStream.h Normal file
View 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;

View file

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

View file

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

View file

@ -26,6 +26,7 @@ enum Function {
PosixWaitpid = 0x1994, PosixWaitpid = 0x1994,
PosixMmap = 0x1995, PosixMmap = 0x1995,
PosixMunmap = 0x1996, PosixMunmap = 0x1996,
GetDirEntries = 0x1997,
}; };
void initialize(); void initialize();

View file

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

View file

@ -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.

View file

@ -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
View 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
View 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
View 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
View file

@ -0,0 +1,11 @@
#pragma once
#include "types.h"
extern "C" {
void* malloc(size_t);
void free(void*);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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