Luna/kernel/src/sys/dirent.cpp
apio 78d72c2f0c Kernel, libc: Add a getdents() system call
This is meant to be a low-level interface to implement dirent.h on top of.
2022-10-23 14:03:46 +02:00

61 lines
1.4 KiB
C++

#define MODULE "dir"
#include "luna/dirent.h"
#include "fs/VFS.h"
#include "interrupts/Context.h"
#include "std/errno.h"
#include "std/string.h"
#include "sys/UserMemory.h"
#include "thread/Scheduler.h"
void sys_getdents(Context* context, int fd, struct luna_dirent* buf, size_t count)
{
if (fd < 0 || fd > TASK_MAX_FDS)
{
context->rax = -EBADF;
return;
}
Task* current_task = Scheduler::current_task();
if (!current_task->files[fd].is_open())
{
context->rax = -EBADF;
return;
}
Descriptor& dir = current_task->files[fd];
VFS::Node* node = dir.node();
if (node->type != VFS_DIRECTORY)
{
context->rax = -ENOTDIR;
return;
}
size_t nread = 0;
while (count)
{
VFS::Node* entry = VFS::readdir(node, dir.offset());
if (!entry)
{
context->rax = nread;
return;
}
auto* kdirent = obtain_user_ref(buf);
if (!kdirent)
{
context->rax = -EFAULT;
return;
}
kdirent->total = node->length;
kdirent->offset = dir.offset();
kdirent->inode = entry->inode;
strlcpy(kdirent->name, entry->name, sizeof(kdirent->name));
release_user_ref(kdirent);
dir.seek(dir.offset() + 1);
buf++;
nread++;
count--;
}
context->rax = nread;
}