#pragma once #include "fs/VFS.h" #include "fs/devices/DeviceRegistry.h" #include #define EXT2_MAGIC 0xef53 namespace Ext2 { struct [[gnu::packed]] Superblock { u32 nr_inodes; u32 nr_blocks; u32 nr_reserved_blocks; u32 nr_free_blocks; u32 nr_free_inodes; u32 first_data_block; u32 log_block_size; u32 log_fragment_size; u32 blocks_per_block_group; u32 fragments_per_block_group; u32 inodes_per_block_group; u32 last_mount_time; u32 last_write_time; u16 mounts_since_last_fsck; u16 mounts_allowed_before_fsck; u16 signature; u16 fs_state; u16 error_action; u16 minor_version; u32 last_fsck_time; u32 fsck_time_interval; u32 os_id; u32 major_version; u16 reserved_block_uid; u16 reserved_block_gid; // TODO: Add extended superblock fields. u8 padding[1024 - 84]; }; struct [[gnu::packed]] BlockGroupDescriptor { u32 block_usage_addr; u32 inode_usage_addr; u32 inode_table_start; u16 nr_free_blocks; u16 nr_free_inodes; u16 nr_directories; u8 padding[32 - 18]; }; struct [[gnu::packed]] RawInode { u16 mode; u16 uid; u32 size_low; u32 atime; u32 create_time; u32 mtime; u32 delete_time; u16 gid; u16 nlinks; u32 sectors_used; u32 flags; u32 os_specific_1; u32 direct_pointers[12]; u32 singly_indirect_ptr; u32 doubly_indirect_ptr; u32 triply_indirect_ptr; u32 gen_number; u32 extended_attrs; u32 size_high; u32 frag_addr; u32 os_specific_2[3]; }; static_assert(sizeof(Superblock) == 1024); static_assert(sizeof(BlockGroupDescriptor) == 32); static_assert(sizeof(RawInode) == 128); class Inode; class FileSystem : public VFS::FileSystem { public: SharedPtr root_inode() const override { return m_root_inode; } Result> create_file_inode() override { return err(EROFS); } Result> create_dir_inode(SharedPtr) override { return err(EROFS); } Result> create_device_inode(u32, u32) override { return err(EROFS); } Result> create_symlink_inode(StringView) override { return err(EROFS); } Result set_mount_dir(SharedPtr) override { return {}; } bool is_readonly() const override { return true; } static Result> create(SharedPtr host_device); dev_t host_device_id() const override { return m_host_device_id; } Result> find_inode_by_number(ino_t inode); Result find_block_group_descriptor(u32 index); virtual ~FileSystem() = default; private: FileSystem(); SharedPtr m_root_inode; SharedPtr m_host_device; dev_t m_host_device_id; Superblock m_superblock; u64 m_block_size; u64 m_block_groups; // FIXME: This inode cache will keep all inodes in it alive despite having no other references to it, but we're // not worrying about that as for now the filesystem implementation is read-only. HashMap> m_inode_cache; HashMap m_block_group_descriptor_cache; friend class Inode; }; }