:github_url: https://github.com/nyx-org/gaia .. _program_listing_file_fs_vfs.hpp: Program Listing for File vfs.hpp ================================ |exhale_lsh| :ref:`Return to documentation for file ` (``fs/vfs.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp /* SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include "lib/stream.hpp" #include #include #include #include #include #include #include #define __USE_MISC #include 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 lookup(Vnode *dir, frg::string_view path) = 0; // FIXME (hack): Use type or something instead of checking whether dev_t != -1 virtual Result create(Vnode *dir, frg::string_view path, VnodeAttr attr = DefaultVnodeAttr, dev_t dev = -1) = 0; virtual Result mkdir(Vnode *dir, frg::string_view path, VnodeAttr attr = DefaultVnodeAttr) = 0; virtual Result link(Vnode *dir, frg::string_view path, frg::string_view link, VnodeAttr attr = DefaultVnodeAttr) = 0; virtual Result getattr(Vnode *node) = 0; virtual Result read(Vnode *vn, frg::span buf, off_t off) = 0; virtual Result write(Vnode *vn, frg::span buf, off_t off) = 0; virtual Result ioctl(Vnode *vn, uint64_t request, void *arg) = 0; virtual Vm::String get_absolute_path(Vnode *vn) = 0; virtual Result 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 vfs_read(Vnode *vn, frg::span buf, off_t off); Result vfs_readdir(Vnode *vn, void *buf, size_t max_size, off_t off); Result vfs_write(Vnode *vn, frg::span buf, off_t off); Result vfs_create_file(Vnode *cwd, frg::string_view name, VnodeAttr attr = DefaultVnodeAttr, dev_t dev = -1); Result vfs_mkdir(Vnode *cwd, frg::string_view name, VnodeAttr attr = DefaultVnodeAttr); Result vfs_find(frg::string_view pathname, Vnode *cwd = nullptr); Result 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 Result vfs_find_and(frg::string_view pathname, F function, Vnode *cwd = nullptr, VnodeAttr attr = DefaultVnodeAttr) { Path 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 Result vfs_find_and(frg::string_view pathname, dev_t dev, F function, Vnode *cwd = nullptr, VnodeAttr attr = DefaultVnodeAttr) { Path 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 Result vfs_find_and(frg::string_view pathname, frg::string_view linkpath, F function, Vnode *cwd = nullptr, VnodeAttr attr = DefaultVnodeAttr) { Path 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 read(void *buf, size_t size) override { auto ret = TRY(vfs_read(vnode, {(uint8_t *)buf, size}, position)); position += ret; return Ok(ret); } Result write(void *buf, size_t size) override { auto ret = TRY(vfs_write(vnode, {(uint8_t *)buf, size}, position)); position += ret; return Ok(ret); } Result 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