#include #include #include #include #include #include #include #include #include #include #include #include #include namespace kernel::filesystem::ext2 { auto filesystem::mount(kstd::shared_ptr const & backing_inode) -> operation_result { kernel::filesystem::filesystem::mount(backing_inode); m_backing_inode->read(&m_superblock, constants::superblock_offset, sizeof(m_superblock)); if (m_superblock.magic != constants::magic_number) { return operation_result::invalid_magic_number; } auto const blocks_per_group = m_superblock.blocks_per_group; auto const num_block_groups = (m_superblock.blocks_count + blocks_per_group - 1) / blocks_per_group; m_block_group_descriptors = kstd::vector(num_block_groups); m_backing_inode->read(m_block_group_descriptors.data(), block_group_descriptor_table_offset(), num_block_groups * sizeof(block_group_descriptor)); m_root_inode = read_inode(constants::root_inode_number); if (!m_root_inode || !m_root_inode->is_directory()) { return operation_result::invalid_root_inode; } return operation_result::success; } auto filesystem::lookup(kstd::shared_ptr const & parent, std::string_view name) const -> kstd::shared_ptr { if (!parent || !parent->is_directory()) { return nullptr; } auto * ext2_parent = static_cast(parent.get()); if (!ext2_parent) { return nullptr; } auto const & inode_data = ext2_parent->data(); kstd::vector buffer(block_size()); for (auto i = 0uz; i < inode_block_count(inode_data); ++i) { auto const global_block_number = map_inode_block_index_to_global_block_number(i, inode_data); auto const block_offset = global_block_number * block_size(); m_backing_inode->read(buffer.data(), block_offset, block_size()); auto const * entry = reinterpret_cast(buffer.data()); auto bytes_read = 0uz; while (bytes_read < block_size() && entry->inode != 0) { auto const entry_name = std::string_view{entry->name.data(), entry->name_len}; if (entry_name == name) { return read_inode(entry->inode); } bytes_read += entry->rec_len; entry = reinterpret_cast(buffer.data() + bytes_read); } } return nullptr; } auto filesystem::read_inode(size_t inode_number) const -> kstd::shared_ptr { auto const inodes_per_group = m_superblock.inodes_per_group; auto const block_group_index = (inode_number - 1) / inodes_per_group; auto const inode_index_within_group = (inode_number - 1) % inodes_per_group; if (block_group_index >= m_block_group_descriptors.size()) { return nullptr; } auto const & block_group_descriptor = m_block_group_descriptors.at(block_group_index); auto const inode_table_start_block = block_group_descriptor.inode_table; auto const inode_table_offset = static_cast(inode_table_start_block) * block_size(); auto const inode_offset = inode_table_offset + inode_index_within_group * inode_size(); auto new_inode_data = inode_data{}; m_backing_inode->read(&new_inode_data, inode_offset, sizeof(inode_data)); return kstd::make_shared(this, new_inode_data); } auto filesystem::map_inode_block_index_to_global_block_number(size_t inode_block_index, inode_data data) const -> ssize_t { if (inode_block_index < constants::direct_block_count) { return data.block.at(inode_block_index); } inode_block_index -= constants::direct_block_count; if (inode_block_index < block_numbers_per_singly_indirect_block()) { auto const singly_indirect_block_number = data.block.at(constants::singly_indirect_block_index); return read_singly_indirect_block_number(singly_indirect_block_number, inode_block_index); } inode_block_index -= block_numbers_per_singly_indirect_block(); if (inode_block_index < block_numbers_per_doubly_indirect_block()) { auto const doubly_indirect_block_number = data.block.at(constants::doubly_indirect_block_index); return read_doubly_indirect_block_number(doubly_indirect_block_number, inode_block_index); } inode_block_index -= block_numbers_per_doubly_indirect_block(); if (inode_block_index < block_numbers_per_triply_indirect_block()) { auto const triply_indirect_block_number = data.block.at(constants::triply_indirect_block_index); return read_triply_indirect_block_number(triply_indirect_block_number, inode_block_index); } return -1; } auto filesystem::read_singly_indirect_block_number(size_t singly_indirect_block_number, size_t block_index_in_singly_indirect_block) const -> size_t { if (singly_indirect_block_number == 0) { return 0; } return read_block_number_at_index(singly_indirect_block_number, block_index_in_singly_indirect_block); } auto filesystem::read_doubly_indirect_block_number(size_t doubly_indirect_block_number, size_t block_index_in_doubly_indirect_block) const -> size_t { if (doubly_indirect_block_number == 0) { return 0; } auto const singly_indirect_block_index_in_doubly_indirect_block = block_index_in_doubly_indirect_block / block_numbers_per_singly_indirect_block(); auto const block_index_in_singly_indirect_block = block_index_in_doubly_indirect_block % block_numbers_per_singly_indirect_block(); auto const singly_indirect_block_number = read_block_number_at_index(doubly_indirect_block_number, singly_indirect_block_index_in_doubly_indirect_block); return read_singly_indirect_block_number(singly_indirect_block_number, block_index_in_singly_indirect_block); } auto filesystem::read_triply_indirect_block_number(size_t triply_indirect_block_number, size_t block_index_in_triply_indirect_block) const -> size_t { if (triply_indirect_block_number == 0) { return 0; } auto const doubly_indirect_block_index_in_triply_indirect_block = block_index_in_triply_indirect_block / block_numbers_per_doubly_indirect_block(); auto const block_index_in_doubly_indirect_block = block_index_in_triply_indirect_block % block_numbers_per_doubly_indirect_block(); auto const doubly_indirect_block_number = read_block_number_at_index(triply_indirect_block_number, doubly_indirect_block_index_in_triply_indirect_block); return read_doubly_indirect_block_number(doubly_indirect_block_number, block_index_in_doubly_indirect_block); } auto filesystem::read_block_number_at_index(size_t block_number, size_t index) const -> size_t { auto block_number_buffer = 0uz; auto const block_start_offset = block_number * block_size(); auto const number_start_address = block_start_offset + index * sizeof(uint32_t); m_backing_inode->read(&block_number_buffer, number_start_address, sizeof(uint32_t)); return block_number_buffer; } auto filesystem::block_numbers_per_block() const -> size_t { return block_size() / sizeof(uint32_t); } auto filesystem::block_numbers_per_singly_indirect_block() const -> size_t { return block_numbers_per_block(); } auto filesystem::block_numbers_per_doubly_indirect_block() const -> size_t { return block_numbers_per_singly_indirect_block() * block_numbers_per_block(); } auto filesystem::block_numbers_per_triply_indirect_block() const -> size_t { return block_numbers_per_doubly_indirect_block() * block_numbers_per_block(); } auto filesystem::block_size() const -> size_t { return constants::base_block_size << m_superblock.log_block_size; } auto filesystem::revision_level() const -> size_t { return m_superblock.rev_level; } auto filesystem::inode_size() const -> size_t { return revision_level() == constants::good_old_revision ? 128 : m_superblock.inode_size; } auto filesystem::inode_block_count(inode_data const & data) const -> size_t { return data.blocks / (2 << m_superblock.log_block_size); } auto filesystem::block_group_descriptor_table_offset() const -> size_t { return block_size() == 1024 ? 2 * block_size() : block_size(); } } // namespace kernel::filesystem::ext2