#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Kernel { class FileBackedRegion; class FileSystem; struct SharedFileData; class Inode : public BAN::RefCounted { public: struct Mode { enum Mask : mode_t { IXOTH = 0x0001, IWOTH = 0x0002, IROTH = 0x0004, IXGRP = 0x0008, IWGRP = 0x0010, IRGRP = 0x0020, IXUSR = 0x0040, IWUSR = 0x0080, IRUSR = 0x0100, ISVTX = 0x0200, ISGID = 0x0400, ISUID = 0x0800, IFIFO = 0x1000, IFCHR = 0x2000, IFDIR = 0x4000, IFBLK = 0x6000, IFREG = 0x8000, IFLNK = 0xA000, IFSOCK = 0xC000, TYPE_MASK = 0xF000, }; bool ifchr() const { return (mode & Mask::TYPE_MASK) == Mask::IFCHR; } bool ifdir() const { return (mode & Mask::TYPE_MASK) == Mask::IFDIR; } bool ifblk() const { return (mode & Mask::TYPE_MASK) == Mask::IFBLK; } bool ifreg() const { return (mode & Mask::TYPE_MASK) == Mask::IFREG; } bool ififo() const { return (mode & Mask::TYPE_MASK) == Mask::IFIFO; } bool iflnk() const { return (mode & Mask::TYPE_MASK) == Mask::IFLNK; } bool ifsock() const { return (mode & Mask::TYPE_MASK) == Mask::IFSOCK; } mode_t mode; }; enum InodeKind : uint8_t { DEVICE = 0x01, EPOLL = 0x02, PIPE = 0x04, TTY = 0x08, PARTITION = 0x10, STORAGE = 0x20, }; enum class SyncType { General, Mode, UidGid, Times, }; public: virtual ~Inode() {} static bool can_access(uid_t uid, gid_t gid, mode_t mode, const Credentials& credentials, int); bool can_access(const Credentials&, int) const; bool operator==(const Inode& other) const { return dev() == other.dev() && ino() == other.ino(); } ino_t ino() const { return m_ino; } Mode mode() const { return Mode(m_mode); } nlink_t nlink() const { return m_nlink; } uid_t uid() const { return m_uid; } gid_t gid() const { return m_gid; } off_t size() const { return m_size; } timespec atime() const { return m_atime; } timespec mtime() const { return m_mtime; } timespec ctime() const { return m_ctime; } blksize_t blksize() const { return m_blksize; } blkcnt_t blocks() const { return m_blocks; } dev_t dev() const { return m_dev; } dev_t rdev() const { return m_rdev; } bool is_device() const { return m_kind & InodeKind::DEVICE; } bool is_epoll() const { return m_kind & InodeKind::EPOLL; } bool is_pipe() const { return m_kind & InodeKind::PIPE; } bool is_tty() const { return m_kind & InodeKind::TTY; } bool is_partition() const { return m_kind & InodeKind::PARTITION; } bool is_storage_device() const { return m_kind & InodeKind::STORAGE; } virtual const FileSystem* filesystem() const = 0; // Directory API BAN::ErrorOr> find_inode(BAN::StringView); BAN::ErrorOr list_next_inodes(off_t, struct dirent* list, size_t list_size); BAN::ErrorOr create_file(BAN::StringView, mode_t, uid_t, gid_t); BAN::ErrorOr create_directory(BAN::StringView, mode_t, uid_t, gid_t); BAN::ErrorOr link_inode(BAN::StringView, BAN::RefPtr); BAN::ErrorOr rename_inode(BAN::RefPtr, BAN::StringView, BAN::StringView); BAN::ErrorOr unlink(BAN::StringView); // Link API BAN::ErrorOr link_target(); BAN::ErrorOr set_link_target(BAN::StringView); // Socket API BAN::ErrorOr accept(sockaddr* address, socklen_t* address_len, int flags); BAN::ErrorOr bind(const sockaddr* address, socklen_t address_len); BAN::ErrorOr connect(const sockaddr* address, socklen_t address_len); BAN::ErrorOr listen(int backlog); BAN::ErrorOr sendmsg(const msghdr& message, int flags); BAN::ErrorOr recvmsg(msghdr& message, int flags); BAN::ErrorOr getsockname(sockaddr* address, socklen_t* address_len); BAN::ErrorOr getpeername(sockaddr* address, socklen_t* address_len); BAN::ErrorOr getsockopt(int level, int option, void* value, socklen_t* value_len); BAN::ErrorOr setsockopt(int level, int option, const void* value, socklen_t value_len); // General API BAN::ErrorOr read(off_t, BAN::ByteSpan buffer); BAN::ErrorOr write(off_t, BAN::ConstByteSpan buffer); BAN::ErrorOr truncate(size_t); BAN::ErrorOr chmod(mode_t); BAN::ErrorOr chown(uid_t, gid_t); BAN::ErrorOr utimens(const timespec[2]); BAN::ErrorOr fsync(); // Select/Non blocking API bool can_read() const { return can_read_impl(); } bool can_write() const { return can_write_impl(); } bool has_error() const { return has_error_impl(); } bool has_hungup() const { return has_hungup_impl(); } BAN::ErrorOr ioctl(unsigned long request, void* arg); BAN::ErrorOr add_epoll(class Epoll*); void del_epoll(class Epoll*); void epoll_notify(uint32_t event); virtual void on_close(int status_flags) { (void)status_flags; } virtual void on_clone(int status_flags) { (void)status_flags; } virtual BAN::ErrorOr sync_inode(SyncType) = 0; virtual BAN::ErrorOr sync_data() = 0; protected: // Directory API virtual BAN::ErrorOr> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr list_next_inodes_impl(off_t, struct dirent*, size_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr link_inode_impl(BAN::StringView, BAN::RefPtr) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr rename_inode_impl(BAN::RefPtr, BAN::StringView, BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } // Link API virtual BAN::ErrorOr link_target_impl() { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr set_link_target_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } // Socket API virtual BAN::ErrorOr accept_impl(sockaddr*, socklen_t*, int) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr connect_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr listen_impl(int) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr bind_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr recvmsg_impl(msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr sendmsg_impl(const msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr getsockopt_impl(int, int, void*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr setsockopt_impl(int, int, const void*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); } // General API virtual BAN::ErrorOr read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr truncate_impl(size_t) { return BAN::Error::from_errno(ENOTSUP); } // Select/Non blocking API virtual bool can_read_impl() const = 0; virtual bool can_write_impl() const = 0; virtual bool has_error_impl() const = 0; virtual bool has_hungup_impl() const = 0; virtual BAN::ErrorOr ioctl_impl(unsigned long, void*) { return BAN::Error::from_errno(ENOTSUP); } protected: // TODO: this is supposed to be const I guess? // But the thing is I would have to refactor a big chunk of the codebase // to add it as a parameter to Inode() soooooo yeah no, not doing that rn. uint8_t m_kind = 0; BAN::Atomic m_ino; BAN::Atomic m_mode; BAN::Atomic m_nlink; BAN::Atomic m_uid; BAN::Atomic m_gid; BAN::Atomic m_size; // TODO: make these guys atomic :) timespec m_atime; timespec m_mtime; timespec m_ctime; BAN::Atomic m_blksize; BAN::Atomic m_blocks; BAN::Atomic m_dev; BAN::Atomic m_rdev; private: SpinLock m_shared_region_lock; BAN::WeakPtr m_shared_region; SpinLock m_epoll_lock; BAN::LinkedList m_epolls; friend class Epoll; friend class FileBackedRegion; friend class OpenFileDescriptorSet; friend struct SharedFileData; friend class TTY; }; }