#pragma once #include "arch/Timer.h" #include <bits/makedev.h> #include <bits/timespec.h> #include <luna/SharedPtr.h> #include <luna/StaticString.h> #include <luna/StringView.h> #include <sys/types.h> struct Credentials; namespace VFS { enum class InodeType { RegularFile, Directory, CharacterDevice, BlockDevice, Symlink, FIFO, Socket, }; struct InodeMetadata { ino_t inum; size_t size { 0 }; mode_t mode; nlink_t nlinks { 1 }; uid_t uid { 0 }; gid_t gid { 0 }; dev_t devid { 0 }; struct timespec atime; struct timespec mtime; struct timespec ctime; }; class Inode; class FileSystem : public Shareable { public: virtual SharedPtr<Inode> root_inode() const = 0; virtual Result<SharedPtr<Inode>> create_file_inode(mode_t mode) = 0; virtual Result<SharedPtr<Inode>> create_dir_inode(SharedPtr<Inode> parent, mode_t mode) = 0; virtual Result<SharedPtr<Inode>> create_device_inode(u32 major, u32 minor, mode_t mode) = 0; virtual Result<SharedPtr<Inode>> create_symlink_inode(StringView link) = 0; virtual Result<u64> allocate_inode_number() { return err(ENOTSUP); } virtual Result<void> set_mount_dir(SharedPtr<Inode> parent) = 0; virtual Result<void> reset_mount_dir() = 0; virtual bool is_readonly() const { return false; } virtual u64 handles() const { return m_handles; } virtual void add_handle() { m_handles++; } virtual void remove_handle() { m_handles--; } virtual dev_t host_device_id() const = 0; virtual ~FileSystem() = default; protected: u64 m_handles { 0 }; }; struct DirectoryEntry { public: SharedPtr<Inode> inode; StaticString<128> name; }; class Inode : public Shareable { public: virtual Result<u64> ioctl(int, void*) { return err(ENOTTY); } virtual Result<u64> isatty() const { return err(ENOTTY); } virtual void did_close() { } virtual Result<u64> query_shared_memory(off_t, usize) { return err(EACCES); } // Directory-specific methods virtual Result<SharedPtr<Inode>> find(const char* name) const = 0; virtual Option<DirectoryEntry> get(usize index) const = 0; virtual Result<SharedPtr<Inode>> create_file(const char* name, mode_t mode) = 0; virtual Result<SharedPtr<Inode>> create_subdirectory(const char* name, mode_t mode) = 0; virtual Result<void> add_entry(SharedPtr<Inode> inode, const char* name) = 0; virtual Result<void> remove_entry(const char* name) = 0; virtual Result<void> replace_entry(SharedPtr<Inode> inode, const char* name) = 0; virtual usize entries() const = 0; // File-specific methods virtual Result<usize> read(u8* buf, usize offset, usize length) const = 0; virtual Result<usize> write(const u8* buf, usize offset, usize length) = 0; virtual Result<void> truncate(usize size) = 0; virtual bool will_block_if_read() const = 0; // Symlink-specific methods virtual Result<StringView> readlink() { return StringView {}; } virtual const InodeMetadata& metadata() const { return m_metadata; } virtual Result<void> set_metadata(const InodeMetadata& metadata) { m_metadata = metadata; m_metadata.ctime = *Timer::realtime_clock(); return {}; } virtual bool is_mountpoint() const { return false; } virtual void did_link() = 0; virtual void did_unlink() = 0; // Generic VFS-related methods virtual FileSystem* fs() const = 0; virtual ~Inode() = default; virtual InodeType type() const = 0; virtual void add_handle() { auto* f = fs(); if (f) f->add_handle(); } virtual void remove_handle() { auto* f = fs(); if (f) f->remove_handle(); } protected: mutable InodeMetadata m_metadata; Option<u64> m_shmid {}; }; class FileInode : public Inode { public: Result<SharedPtr<Inode>> find(const char*) const override { return err(ENOTDIR); } Option<DirectoryEntry> get(usize) const override { return {}; } Result<SharedPtr<Inode>> create_file(const char*, mode_t) override { return err(ENOTDIR); } Result<SharedPtr<Inode>> create_subdirectory(const char*, mode_t) override { return err(ENOTDIR); } Result<void> add_entry(SharedPtr<Inode>, const char*) override { return err(ENOTDIR); } Result<void> replace_entry(SharedPtr<Inode>, const char*) override { return err(ENOTDIR); } Result<void> remove_entry(const char*) override { return err(ENOTDIR); } usize entries() const override { return 0; } bool will_block_if_read() const override { return false; } InodeType type() const override { return InodeType::RegularFile; } virtual ~FileInode() = default; }; class DeviceInode : public Inode { public: Result<SharedPtr<Inode>> find(const char*) const override { return err(ENOTDIR); } Option<DirectoryEntry> get(usize) const override { return {}; } Result<SharedPtr<Inode>> create_file(const char*, mode_t) override { return err(ENOTDIR); } Result<SharedPtr<Inode>> create_subdirectory(const char*, mode_t) override { return err(ENOTDIR); } Result<void> add_entry(SharedPtr<Inode>, const char*) override { return err(ENOTDIR); } Result<void> replace_entry(SharedPtr<Inode>, const char*) override { return err(ENOTDIR); } Result<void> remove_entry(const char*) override { return err(ENOTDIR); } usize entries() const override { return 0; } InodeType type() const override { return InodeType::CharacterDevice; } virtual ~DeviceInode() = default; }; Result<SharedPtr<Inode>> resolve_path(const char* path, Credentials auth, SharedPtr<VFS::Inode> working_directory = {}, bool follow_last_symlink = true); Result<SharedPtr<Inode>> create_directory(const char* path, mode_t mode, Credentials auth, SharedPtr<VFS::Inode> working_directory = {}); Result<SharedPtr<Inode>> create_file(const char* path, mode_t mode, Credentials auth, SharedPtr<VFS::Inode> working_directory = {}); Result<void> validate_filename(StringView name); bool can_execute(SharedPtr<Inode> inode, Credentials auth); bool can_read(SharedPtr<Inode> inode, Credentials auth); bool can_write(SharedPtr<Inode> inode, Credentials auth); bool is_setuid(SharedPtr<Inode> inode); bool is_setgid(SharedPtr<Inode> inode); bool is_sticky(SharedPtr<Inode> inode); bool is_seekable(SharedPtr<Inode> inode); Inode& root_inode(); Result<void> mount_root(SharedPtr<VFS::FileSystem> fs); Result<void> pivot_root(const char* new_root, const char* put_old, SharedPtr<VFS::Inode> working_directory); Result<void> mount(const char* path, SharedPtr<VFS::FileSystem> fs, Credentials auth, SharedPtr<Inode> working_directory = {}); Result<void> umount(const char* path, Credentials auth, SharedPtr<Inode> working_directory = {}); }