#pragma once #include "arch/Timer.h" #include #include #include #include #include #include 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 root_inode() const = 0; virtual Result> create_file_inode(mode_t mode) = 0; virtual Result> create_dir_inode(SharedPtr parent, mode_t mode) = 0; virtual Result> create_device_inode(u32 major, u32 minor, mode_t mode) = 0; virtual Result> create_symlink_inode(StringView link) = 0; virtual Result allocate_inode_number() { return err(ENOTSUP); } virtual Result set_mount_dir(SharedPtr parent) = 0; virtual Result 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; StaticString<128> name; }; class Inode : public Shareable { public: virtual Result ioctl(int, void*) { return err(ENOTTY); } virtual Result isatty() const { return err(ENOTTY); } virtual void did_close() { } virtual Result query_shared_memory(off_t, usize) { return err(EACCES); } // Directory-specific methods virtual Result> find(const char* name) const = 0; virtual Option get(usize index) const = 0; virtual Result> create_file(const char* name, mode_t mode) = 0; virtual Result> create_subdirectory(const char* name, mode_t mode) = 0; virtual Result add_entry(SharedPtr inode, const char* name) = 0; virtual Result remove_entry(const char* name) = 0; virtual Result replace_entry(SharedPtr inode, const char* name) = 0; virtual usize entries() const = 0; // File-specific methods virtual Result read(u8* buf, usize offset, usize length) const = 0; virtual Result write(const u8* buf, usize offset, usize length) = 0; virtual Result truncate(usize size) = 0; virtual bool will_block_if_read() const = 0; // Symlink-specific methods virtual Result readlink() { return StringView {}; } virtual const InodeMetadata& metadata() const { return m_metadata; } virtual Result 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 m_shmid {}; }; class FileInode : public Inode { public: Result> find(const char*) const override { return err(ENOTDIR); } Option get(usize) const override { return {}; } Result> create_file(const char*, mode_t) override { return err(ENOTDIR); } Result> create_subdirectory(const char*, mode_t) override { return err(ENOTDIR); } Result add_entry(SharedPtr, const char*) override { return err(ENOTDIR); } Result replace_entry(SharedPtr, const char*) override { return err(ENOTDIR); } Result 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> find(const char*) const override { return err(ENOTDIR); } Option get(usize) const override { return {}; } Result> create_file(const char*, mode_t) override { return err(ENOTDIR); } Result> create_subdirectory(const char*, mode_t) override { return err(ENOTDIR); } Result add_entry(SharedPtr, const char*) override { return err(ENOTDIR); } Result replace_entry(SharedPtr, const char*) override { return err(ENOTDIR); } Result 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> resolve_path(const char* path, Credentials auth, SharedPtr working_directory = {}, bool follow_last_symlink = true); Result> create_directory(const char* path, mode_t mode, Credentials auth, SharedPtr working_directory = {}); Result> create_file(const char* path, mode_t mode, Credentials auth, SharedPtr working_directory = {}); Result validate_filename(StringView name); bool can_execute(SharedPtr inode, Credentials auth); bool can_read(SharedPtr inode, Credentials auth); bool can_write(SharedPtr inode, Credentials auth); bool is_setuid(SharedPtr inode); bool is_setgid(SharedPtr inode); bool is_sticky(SharedPtr inode); bool is_seekable(SharedPtr inode); Inode& root_inode(); Result mount_root(SharedPtr fs); Result pivot_root(const char* new_root, const char* put_old, SharedPtr working_directory); Result mount(const char* path, SharedPtr fs, Credentials auth, SharedPtr working_directory = {}); Result umount(const char* path, Credentials auth, SharedPtr working_directory = {}); }