Program Listing for File vfs.hpp¶
↰ Return to documentation for file (fs/vfs.hpp
)
/* SPDX-License-Identifier: BSD-2-Clause */
#pragma once
#include "lib/stream.hpp"
#include <frg/span.hpp>
#include <lib/base.hpp>
#include <lib/error.hpp>
#include <lib/path.hpp>
#include <lib/result.hpp>
#include <sys/types.h>
#include <vm/heap.hpp>
#define __USE_MISC
#include <sys/stat.h>
namespace Gaia::Fs {
struct Vnode;
struct VnodeAttr {
size_t size;
mode_t mode;
uid_t uid;
gid_t gid;
time_t time;
};
constexpr VnodeAttr DefaultVnodeAttr = {
.size = 0,
.mode = 0,
.uid = 0,
.gid = 0,
.time = 0,
};
struct VnodeOps {
virtual Result<Vnode *, Error> lookup(Vnode *dir, frg::string_view path) = 0;
// FIXME (hack): Use type or something instead of checking whether dev_t != -1
virtual Result<Vnode *, Error> create(Vnode *dir, frg::string_view path,
VnodeAttr attr = DefaultVnodeAttr,
dev_t dev = -1) = 0;
virtual Result<Vnode *, Error> mkdir(Vnode *dir, frg::string_view path,
VnodeAttr attr = DefaultVnodeAttr) = 0;
virtual Result<Vnode *, Error> link(Vnode *dir, frg::string_view path,
frg::string_view link,
VnodeAttr attr = DefaultVnodeAttr) = 0;
virtual Result<VnodeAttr, Error> getattr(Vnode *node) = 0;
virtual Result<size_t, Error> read(Vnode *vn, frg::span<uint8_t> buf,
off_t off) = 0;
virtual Result<size_t, Error> write(Vnode *vn, frg::span<uint8_t> buf,
off_t off) = 0;
virtual Result<uint64_t, Error> ioctl(Vnode *vn, uint64_t request,
void *arg) = 0;
virtual Vm::String get_absolute_path(Vnode *vn) = 0;
virtual Result<size_t, Error> readdir(Vnode *vn, void *buf, size_t max_size,
off_t offset) = 0;
};
struct Vnode {
enum class Type {
NONE,
REG,
DIR,
CHR,
LNK,
};
Type type;
void *data;
dev_t dev;
VnodeOps *ops;
Vnode(Type type, void *data, VnodeOps *ops)
: type(type), data(data), ops(ops) {}
};
Result<size_t, Error> vfs_read(Vnode *vn, frg::span<uint8_t> buf, off_t off);
Result<size_t, Error> vfs_readdir(Vnode *vn, void *buf, size_t max_size,
off_t off);
Result<size_t, Error> vfs_write(Vnode *vn, frg::span<uint8_t> buf, off_t off);
Result<Vnode *, Error> vfs_create_file(Vnode *cwd, frg::string_view name,
VnodeAttr attr = DefaultVnodeAttr,
dev_t dev = -1);
Result<Vnode *, Error> vfs_mkdir(Vnode *cwd, frg::string_view name,
VnodeAttr attr = DefaultVnodeAttr);
Result<Vnode *, Error> vfs_find(frg::string_view pathname,
Vnode *cwd = nullptr);
Result<Vnode *, Error> vfs_link(Vnode *cwd, frg::string_view path,
frg::string_view link,
VnodeAttr attr = DefaultVnodeAttr);
Vm::String vfs_get_absolute_path(Vnode *node);
extern Vnode *root_vnode;
template <typename F>
Result<Vnode *, Error> vfs_find_and(frg::string_view pathname, F function,
Vnode *cwd = nullptr,
VnodeAttr attr = DefaultVnodeAttr) {
Path<Gaia::Vm::HeapAllocator> path{pathname};
auto segments = path.parse();
Vnode *vn = nullptr;
bool root = false;
if (pathname[0] == '/') {
vn = root_vnode;
root = true;
} else {
vn = cwd ? cwd : root_vnode;
}
for (size_t i = root; i < segments.size(); i++) {
if (i != segments.size() - 1) {
vn = TRY(vn->ops->lookup(vn, segments[i]));
} else {
vn = TRY(function(vn, segments[i], attr));
}
}
return Ok(vn);
}
template <typename F>
Result<Vnode *, Error> vfs_find_and(frg::string_view pathname, dev_t dev,
F function, Vnode *cwd = nullptr,
VnodeAttr attr = DefaultVnodeAttr) {
Path<Gaia::Vm::HeapAllocator> path{pathname};
auto segments = path.parse();
Vnode *vn;
bool root = false;
if (pathname[0] == '/') {
vn = root_vnode;
root = true;
} else {
vn = cwd ? cwd : root_vnode;
}
for (size_t i = root; i < segments.size(); i++) {
if (i != segments.size() - 1) {
vn = TRY(vn->ops->lookup(vn, segments[i]));
} else {
vn = TRY(function(vn, segments[i], attr, dev));
}
}
return Ok(vn);
}
template <typename F>
Result<Vnode *, Error>
vfs_find_and(frg::string_view pathname, frg::string_view linkpath, F function,
Vnode *cwd = nullptr, VnodeAttr attr = DefaultVnodeAttr) {
Path<Gaia::Vm::HeapAllocator> path{pathname};
auto segments = path.parse();
Vnode *vn;
bool root = false;
if (pathname[0] == '/') {
vn = root_vnode;
root = true;
} else {
vn = cwd ? cwd : root_vnode;
}
for (size_t i = root; i < segments.size(); i++) {
if (i != segments.size() - 1) {
vn = TRY(vn->ops->lookup(vn, segments[i]));
} else {
vn = TRY(function(vn, segments[i], linkpath, attr));
}
}
return Ok(vn);
}
class VnodeStream : public Stream {
public:
VnodeStream(Vnode *vnode) : position(0), vnode(vnode) {}
Result<size_t, Error> read(void *buf, size_t size) override {
auto ret = TRY(vfs_read(vnode, {(uint8_t *)buf, size}, position));
position += ret;
return Ok(ret);
}
Result<size_t, Error> write(void *buf, size_t size) override {
auto ret = TRY(vfs_write(vnode, {(uint8_t *)buf, size}, position));
position += ret;
return Ok(ret);
}
Result<off_t, Error> seek(off_t offset, Whence whence) override {
switch (whence) {
case Whence::CURRENT:
position += offset;
break;
case Whence::SET:
position = offset;
break;
case Whence::END:
position = TRY(vnode->ops->getattr(vnode)).size + offset;
break;
default:
return Err(Error::INVALID_PARAMETERS);
}
return Ok(position);
}
private:
off_t position;
Vnode *vnode;
};
} // namespace Gaia::Fs