#pragma once #include "block_device.hpp" #include "types.hpp" #include #include #include #include #include #include #include namespace vc5::filesys { constexpr u16 block_size = 0x200; constexpr u16 name_max_len = 256; struct DirEntry { u16 inode; u16 next; u16 name_len; std::array name; template void write(Writer& w) const { w << inode << next << name_len << name; } template auto read(Reader& r) { r >> inode >> next >> name_len >> name; } }; constexpr u16 inode_size = 32; constexpr u16 inodes_per_block = block_size / inode_size; enum class INodeType : u16 { File = 0, Dir = 1, Link = 2, }; constexpr u16 inode_type_bitoffset = 0; constexpr u16 inode_type_bitmask = 0b11; constexpr u16 inode_ndir_blocks = 8; constexpr u16 inode_ind_block = inode_ndir_blocks; constexpr u16 inode_dind_block = inode_ind_block + 1; constexpr u16 inode_blocks_count = inode_dind_block + 1; struct INode { u16 mode; u16 blocks_count; u16 links_count; u16 last_block_size; u32 size; std::array blocks; template void write(Writer& w) const { w << mode << blocks_count << links_count << last_block_size << size << blocks; } template auto read(Reader& r) { r >> mode >> blocks_count >> links_count >> last_block_size >> size >> blocks; } }; static_assert(sizeof(INode) <= inode_size); constexpr u16 sb_loc = 3; constexpr u16 blocks_bitmap_loc = 4; constexpr u16 blocks_max_count = block_size * 8; constexpr u16 iblocks_max_count = 32; constexpr u16 inodes_max_count = block_size / inode_size * iblocks_max_count; struct Superblock { u16 volume_id; u16 fs_version; u16 blocks_count; u16 blocks_free; u16 root_inode; u16 inode_blocks_count; std::array iblocks; std::bitset inode_bitmap; template void write(Writer& w) const { w << volume_id << fs_version << blocks_count << blocks_free << root_inode << inode_blocks_count << iblocks << inode_bitmap; } template auto read(Reader& r) { r >> volume_id >> fs_version >> blocks_count >> blocks_free >> root_inode >> inode_blocks_count >> iblocks >> inode_bitmap; } }; static_assert(sizeof(Superblock) <= block_size); struct BlocksBitmap { std::bitset bitmap; template void write(Writer& w) const { w << bitmap; } template auto read(Reader& r) { r >> bitmap; } }; template requires std::is_integral_v struct IntBlock { std::array data; template void write(Writer& w) const { w << data; } template auto read(Reader& r) { r >> data; } }; static_assert(sizeof(BlocksBitmap) <= block_size); class Fs { public: explicit Fs(BlockDevice& disk) : m_disk(&disk) { } template using Result = std::expected; static auto init_new(BlockDevice& disk, u16 volume_id, u16 block_count) -> Result { auto fs = Fs(disk); if (auto result = fs.init_new(volume_id, block_count); not result) return std::unexpected(result.error()); return fs; } static auto load(BlockDevice& disk) -> Result { auto fs = Fs(disk); if (auto result = fs.init_from_existing(); not result) return std::unexpected(result.error()); return fs; } auto root_inode_id() const -> Result { return m_superblock.root_inode; } auto make_file(u16 dir_inode_id, std::string_view name) -> Result; private: auto init_new(u16 volume_id, u16 block_count) -> Result; auto init_from_existing() -> Result; auto append_to_directory(INode& dir_inode, const DirEntry& entry) -> Result; auto make_directory_inode() -> Result; auto inode_last_block_id(const INode& inode) -> Result; auto write_inode(u16 inode_id, const INode& inode) -> Result; auto read_inode(u16 inode_id) -> Result; auto allocate_inode() -> Result; auto allocate_block() -> Result; auto sync_from_disk() -> Result; auto sync_to_disk() -> Result; // templates declared here to get private access template requires(sizeof(Data) <= block_size) auto read_block_part(u16 block_id, u16 offset) -> Result; template requires(sizeof(Data) <= block_size) auto write_block_part(u16 block_id, const Data& data, u16 offset) -> Result; template requires(sizeof(Data) <= block_size) auto read_block(u16 block_id) -> Result; template requires(sizeof(Data) <= block_size) auto write_block(const Data& data, u16 block_id) -> Result; BlockDevice* m_disk; Superblock m_superblock = {}; BlocksBitmap m_blocks_bitmap = {}; }; }