[orbis-kernel] Impl sys_getdirentries/sys_getdents

This commit is contained in:
Ivan Chikish 2023-08-14 23:58:28 +03:00
parent 8179a638ad
commit 8f0a90d24b
5 changed files with 89 additions and 4 deletions

View file

@ -1,6 +1,8 @@
#pragma once
#include "KernelAllocator.hpp"
#include "error/ErrorCode.hpp"
#include "stat.hpp"
#include "utils/Rc.hpp"
#include "utils/SharedMutex.hpp"
#include <cstdint>
@ -43,5 +45,6 @@ struct File : RcBase {
const FileOps *ops = nullptr;
Ref<RcBase> device;
std::uint64_t nextOff = 0;
utils::kvector<Dirent> dirEntries;
};
} // namespace orbis

View file

@ -23,4 +23,25 @@ struct Stat {
int32_t lspare;
timespec birthtim; // time of file creation
};
struct Dirent {
uint32_t fileno;
uint16_t reclen;
uint8_t type;
uint8_t namlen;
char name[256];
};
enum {
kDtUnknown = 0,
kDtFifo = 1,
kDtChr = 2,
kDtDir = 4,
kDtBlk = 6,
kDtReg = 8,
kDtLnk = 10,
kDtSock = 12,
kDtWht = 14,
};
} // namespace orbis

View file

@ -304,13 +304,36 @@ orbis::SysResult orbis::sys_rmdir(Thread *thread, ptr<char> path) {
orbis::SysResult orbis::sys_getdirentries(Thread *thread, sint fd,
ptr<char> buf, uint count,
ptr<slong> basep) {
ORBIS_LOG_ERROR(__FUNCTION__, fd, (void *)buf, count, basep);
thread->where();
ORBIS_LOG_WARNING(__FUNCTION__, fd, (void *)buf, count, basep);
Ref<File> file = thread->tproc->fileDescriptors.get(fd);
if (file == nullptr) {
return ErrorCode::BADF;
}
std::lock_guard lock(file->mtx);
const orbis::Dirent *entries = file->dirEntries.data();
auto pos = file->nextOff / sizeof(orbis::Dirent); // TODO
auto rmax = count / sizeof(orbis::Dirent);
auto next = std::min<uint64_t>(file->dirEntries.size(), pos + rmax);
file->nextOff = next * sizeof(orbis::Dirent);
SysResult result{};
result = uwrite((orbis::Dirent *)buf, entries + pos, next - pos);
if (result.isError())
return result;
if (basep) {
result = uwrite(basep, slong(file->nextOff));
if (result.isError())
return result;
}
thread->retval[0] = (next - pos) * sizeof(orbis::Dirent);
return {};
}
orbis::SysResult orbis::sys_getdents(Thread *thread, sint fd, ptr<char> buf,
size_t count) {
return ErrorCode::NOSYS;
ORBIS_LOG_WARNING(__FUNCTION__, fd, (void *)buf, count);
return orbis::sys_getdirentries(thread, fd, buf, count, nullptr);
}
orbis::SysResult orbis::sys_umask(Thread *thread, sint newmask) {
return ErrorCode::NOSYS;

View file

@ -6,6 +6,7 @@
#include "orbis/utils/Logs.hpp"
#include "vm.hpp"
#include <cerrno>
#include <dirent.h>
#include <fcntl.h>
#include <span>
#include <string>
@ -87,6 +88,9 @@ static orbis::ErrorCode convertErrno() {
static orbis::ErrorCode host_read(orbis::File *file, orbis::Uio *uio,
orbis::Thread *) {
auto hostFile = static_cast<HostFile *>(file);
if (!hostFile->dirEntries.empty())
return orbis::ErrorCode::ISDIR;
std::vector<iovec> vec;
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
@ -116,6 +120,9 @@ static orbis::ErrorCode host_read(orbis::File *file, orbis::Uio *uio,
static orbis::ErrorCode host_write(orbis::File *file, orbis::Uio *uio,
orbis::Thread *) {
auto hostFile = static_cast<HostFile *>(file);
if (!hostFile->dirEntries.empty())
return orbis::ErrorCode::ISDIR;
std::vector<iovec> vec;
for (auto entry : std::span(uio->iov, uio->iovcnt)) {
vec.push_back({.iov_base = entry.base, .iov_len = entry.len});
@ -147,6 +154,8 @@ static orbis::ErrorCode host_mmap(orbis::File *file, void **address,
std::int32_t flags, std::int64_t offset,
orbis::Thread *thread) {
auto hostFile = static_cast<HostFile *>(file);
if (!hostFile->dirEntries.empty())
return orbis::ErrorCode::ISDIR;
auto result =
rx::vm::map(*address, size, prot, flags, rx::vm::kMapInternalReserveOnly);
@ -210,6 +219,9 @@ static orbis::ErrorCode host_stat(orbis::File *file, orbis::Stat *sb,
static orbis::ErrorCode host_truncate(orbis::File *file, std::uint64_t len,
orbis::Thread *thread) {
auto hostFile = static_cast<HostFile *>(file);
if (!hostFile->dirEntries.empty())
return orbis::ErrorCode::ISDIR;
// hack for audio control shared memory
std::uint64_t realLen = len;
if (len == 3880) {
@ -321,8 +333,33 @@ orbis::ErrorCode HostFsDevice::open(orbis::Ref<orbis::File> *file,
return error;
}
// Assume the file is a directory and try to read direntries
orbis::utils::kvector<orbis::Dirent> dirEntries;
while (true) {
::dirent64 hostEntry{};
auto r = getdents64(hostFd, &hostEntry, sizeof(hostEntry));
if (r <= 0)
break;
auto &entry = dirEntries.emplace_back();
entry.fileno = dirEntries.size(); // TODO
entry.reclen = sizeof(entry);
entry.namlen = std::strlen(hostEntry.d_name);
std::strncpy(entry.name, hostEntry.d_name, sizeof(entry.name));
if (hostEntry.d_type == DT_REG)
entry.type = orbis::kDtReg;
else if (hostEntry.d_type == DT_DIR || hostEntry.d_type == DT_LNK)
entry.type = orbis::kDtDir; // Assume symlinks to be dirs
else {
ORBIS_LOG_ERROR("host_open: unknown directory entry d_type", realPath,
hostEntry.d_name, hostEntry.d_type);
dirEntries.pop_back();
}
}
auto newFile = orbis::knew<HostFile>();
newFile->hostFd = hostFd;
newFile->dirEntries = std::move(dirEntries);
newFile->ops = &hostOps;
newFile->device = this;
*file = newFile;

View file

@ -95,7 +95,8 @@ template <typename T>
}
template <typename T>
[[nodiscard]] ErrorCode uwrite(ptr<T> pointer, T *data, std::size_t count) {
[[nodiscard]] ErrorCode uwrite(ptr<T> pointer, const T *data,
std::size_t count) {
return uwriteRaw(pointer, &data, sizeof(T) * count);
}