ext2 filesystem: C++11/STL parsing library

This page hosts a formal specification of ext2 filesystem using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

Runtime library

All parsing code for C++11/STL generated by Kaitai Struct depends on the C++/STL runtime library. You have to install it before you can parse data.

For C++, the easiest way is to clone the runtime library sources and build them along with your project.

Code

Using Kaitai Struct in C++/STL usually consists of 3 steps.

  1. We need to create an STL input stream (std::istream). One can open local file for that, or use existing std::string or char* buffer.
    #include <fstream>
    
    std::ifstream is("path/to/local/file.bin", std::ifstream::binary);
    
    #include <sstream>
    
    std::istringstream is(str);
    
    #include <sstream>
    
    const char buf[] = { ... };
    std::string str(buf, sizeof buf);
    std::istringstream is(str);
    
  2. We need to wrap our input stream into Kaitai stream:
    #include "kaitai/kaitaistream.h"
    
    kaitai::kstream ks(&is);
    
  3. And finally, we can invoke the parsing:
    ext2_t data(&ks);
    

After that, one can get various attributes from the structure by invoking getter methods like:

data.bg1() // => get bg1

C++11/STL source code to parse ext2 filesystem

ext2.h

#pragma once

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "kaitai/kaitaistruct.h"
#include <stdint.h>
#include <memory>
#include <vector>

#if KAITAI_STRUCT_VERSION < 9000L
#error "Incompatible Kaitai Struct C++/STL API: version 0.9 or later is required"
#endif

class ext2_t : public kaitai::kstruct {

public:
    class super_block_struct_t;
    class dir_entry_t;
    class inode_t;
    class block_ptr_t;
    class dir_t;
    class block_group_t;
    class bgd_t;
    class raw_block_t;

    ext2_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = nullptr, ext2_t* p__root = nullptr);

private:
    void _read();
    void _clean_up();

public:
    ~ext2_t();

    class super_block_struct_t : public kaitai::kstruct {

    public:

        enum state_enum_t {
            STATE_ENUM_VALID_FS = 1,
            STATE_ENUM_ERROR_FS = 2
        };

        enum errors_enum_t {
            ERRORS_ENUM_ACT_CONTINUE = 1,
            ERRORS_ENUM_ACT_RO = 2,
            ERRORS_ENUM_ACT_PANIC = 3
        };

        super_block_struct_t(kaitai::kstream* p__io, ext2_t::block_group_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~super_block_struct_t();

    private:
        bool f_block_size;
        int32_t m_block_size;

    public:
        int32_t block_size();

    private:
        bool f_block_group_count;
        int32_t m_block_group_count;

    public:
        int32_t block_group_count();

    private:
        uint32_t m_inodes_count;
        uint32_t m_blocks_count;
        uint32_t m_r_blocks_count;
        uint32_t m_free_blocks_count;
        uint32_t m_free_inodes_count;
        uint32_t m_first_data_block;
        uint32_t m_log_block_size;
        uint32_t m_log_frag_size;
        uint32_t m_blocks_per_group;
        uint32_t m_frags_per_group;
        uint32_t m_inodes_per_group;
        uint32_t m_mtime;
        uint32_t m_wtime;
        uint16_t m_mnt_count;
        uint16_t m_max_mnt_count;
        std::string m_magic;
        state_enum_t m_state;
        errors_enum_t m_errors;
        uint16_t m_minor_rev_level;
        uint32_t m_lastcheck;
        uint32_t m_checkinterval;
        uint32_t m_creator_os;
        uint32_t m_rev_level;
        uint16_t m_def_resuid;
        uint16_t m_def_resgid;
        uint32_t m_first_ino;
        uint16_t m_inode_size;
        uint16_t m_block_group_nr;
        uint32_t m_feature_compat;
        uint32_t m_feature_incompat;
        uint32_t m_feature_ro_compat;
        std::string m_uuid;
        std::string m_volume_name;
        std::string m_last_mounted;
        uint32_t m_algo_bitmap;
        uint8_t m_prealloc_blocks;
        uint8_t m_prealloc_dir_blocks;
        std::string m_padding1;
        std::string m_journal_uuid;
        uint32_t m_journal_inum;
        uint32_t m_journal_dev;
        uint32_t m_last_orphan;
        std::unique_ptr<std::vector<uint32_t>> m_hash_seed;
        uint8_t m_def_hash_version;
        ext2_t* m__root;
        ext2_t::block_group_t* m__parent;

    public:
        uint32_t inodes_count() const { return m_inodes_count; }
        uint32_t blocks_count() const { return m_blocks_count; }
        uint32_t r_blocks_count() const { return m_r_blocks_count; }
        uint32_t free_blocks_count() const { return m_free_blocks_count; }
        uint32_t free_inodes_count() const { return m_free_inodes_count; }
        uint32_t first_data_block() const { return m_first_data_block; }
        uint32_t log_block_size() const { return m_log_block_size; }
        uint32_t log_frag_size() const { return m_log_frag_size; }
        uint32_t blocks_per_group() const { return m_blocks_per_group; }
        uint32_t frags_per_group() const { return m_frags_per_group; }
        uint32_t inodes_per_group() const { return m_inodes_per_group; }
        uint32_t mtime() const { return m_mtime; }
        uint32_t wtime() const { return m_wtime; }
        uint16_t mnt_count() const { return m_mnt_count; }
        uint16_t max_mnt_count() const { return m_max_mnt_count; }
        std::string magic() const { return m_magic; }
        state_enum_t state() const { return m_state; }
        errors_enum_t errors() const { return m_errors; }
        uint16_t minor_rev_level() const { return m_minor_rev_level; }
        uint32_t lastcheck() const { return m_lastcheck; }
        uint32_t checkinterval() const { return m_checkinterval; }
        uint32_t creator_os() const { return m_creator_os; }
        uint32_t rev_level() const { return m_rev_level; }
        uint16_t def_resuid() const { return m_def_resuid; }
        uint16_t def_resgid() const { return m_def_resgid; }
        uint32_t first_ino() const { return m_first_ino; }
        uint16_t inode_size() const { return m_inode_size; }
        uint16_t block_group_nr() const { return m_block_group_nr; }
        uint32_t feature_compat() const { return m_feature_compat; }
        uint32_t feature_incompat() const { return m_feature_incompat; }
        uint32_t feature_ro_compat() const { return m_feature_ro_compat; }
        std::string uuid() const { return m_uuid; }
        std::string volume_name() const { return m_volume_name; }
        std::string last_mounted() const { return m_last_mounted; }
        uint32_t algo_bitmap() const { return m_algo_bitmap; }
        uint8_t prealloc_blocks() const { return m_prealloc_blocks; }
        uint8_t prealloc_dir_blocks() const { return m_prealloc_dir_blocks; }
        std::string padding1() const { return m_padding1; }
        std::string journal_uuid() const { return m_journal_uuid; }
        uint32_t journal_inum() const { return m_journal_inum; }
        uint32_t journal_dev() const { return m_journal_dev; }
        uint32_t last_orphan() const { return m_last_orphan; }
        std::vector<uint32_t>* hash_seed() const { return m_hash_seed.get(); }
        uint8_t def_hash_version() const { return m_def_hash_version; }
        ext2_t* _root() const { return m__root; }
        ext2_t::block_group_t* _parent() const { return m__parent; }
    };

    class dir_entry_t : public kaitai::kstruct {

    public:

        enum file_type_enum_t {
            FILE_TYPE_ENUM_UNKNOWN = 0,
            FILE_TYPE_ENUM_REG_FILE = 1,
            FILE_TYPE_ENUM_DIR = 2,
            FILE_TYPE_ENUM_CHRDEV = 3,
            FILE_TYPE_ENUM_BLKDEV = 4,
            FILE_TYPE_ENUM_FIFO = 5,
            FILE_TYPE_ENUM_SOCK = 6,
            FILE_TYPE_ENUM_SYMLINK = 7
        };

        dir_entry_t(kaitai::kstream* p__io, ext2_t::dir_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~dir_entry_t();

    private:
        bool f_inode;
        inode_t* m_inode;

    public:
        inode_t* inode();

    private:
        uint32_t m_inode_ptr;
        uint16_t m_rec_len;
        uint8_t m_name_len;
        file_type_enum_t m_file_type;
        std::string m_name;
        std::string m_padding;
        ext2_t* m__root;
        ext2_t::dir_t* m__parent;

    public:
        uint32_t inode_ptr() const { return m_inode_ptr; }
        uint16_t rec_len() const { return m_rec_len; }
        uint8_t name_len() const { return m_name_len; }
        file_type_enum_t file_type() const { return m_file_type; }
        std::string name() const { return m_name; }
        std::string padding() const { return m_padding; }
        ext2_t* _root() const { return m__root; }
        ext2_t::dir_t* _parent() const { return m__parent; }
    };

    class inode_t : public kaitai::kstruct {

    public:

        inode_t(kaitai::kstream* p__io, ext2_t::bgd_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~inode_t();

    private:
        bool f_as_dir;
        std::unique_ptr<dir_t> m_as_dir;

    public:
        dir_t* as_dir();

    private:
        uint16_t m_mode;
        uint16_t m_uid;
        uint32_t m_size;
        uint32_t m_atime;
        uint32_t m_ctime;
        uint32_t m_mtime;
        uint32_t m_dtime;
        uint16_t m_gid;
        uint16_t m_links_count;
        uint32_t m_blocks;
        uint32_t m_flags;
        uint32_t m_osd1;
        std::unique_ptr<std::vector<std::unique_ptr<block_ptr_t>>> m_block;
        uint32_t m_generation;
        uint32_t m_file_acl;
        uint32_t m_dir_acl;
        uint32_t m_faddr;
        std::string m_osd2;
        ext2_t* m__root;
        ext2_t::bgd_t* m__parent;

    public:
        uint16_t mode() const { return m_mode; }
        uint16_t uid() const { return m_uid; }
        uint32_t size() const { return m_size; }
        uint32_t atime() const { return m_atime; }
        uint32_t ctime() const { return m_ctime; }
        uint32_t mtime() const { return m_mtime; }
        uint32_t dtime() const { return m_dtime; }
        uint16_t gid() const { return m_gid; }
        uint16_t links_count() const { return m_links_count; }
        uint32_t blocks() const { return m_blocks; }
        uint32_t flags() const { return m_flags; }
        uint32_t osd1() const { return m_osd1; }
        std::vector<std::unique_ptr<block_ptr_t>>* block() const { return m_block.get(); }
        uint32_t generation() const { return m_generation; }
        uint32_t file_acl() const { return m_file_acl; }
        uint32_t dir_acl() const { return m_dir_acl; }
        uint32_t faddr() const { return m_faddr; }
        std::string osd2() const { return m_osd2; }
        ext2_t* _root() const { return m__root; }
        ext2_t::bgd_t* _parent() const { return m__parent; }
    };

    class block_ptr_t : public kaitai::kstruct {

    public:

        block_ptr_t(kaitai::kstream* p__io, ext2_t::inode_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~block_ptr_t();

    private:
        bool f_body;
        std::unique_ptr<raw_block_t> m_body;

    public:
        raw_block_t* body();

    private:
        uint32_t m_ptr;
        ext2_t* m__root;
        ext2_t::inode_t* m__parent;
        std::string m__raw_body;
        std::unique_ptr<kaitai::kstream> m__io__raw_body;

    public:
        uint32_t ptr() const { return m_ptr; }
        ext2_t* _root() const { return m__root; }
        ext2_t::inode_t* _parent() const { return m__parent; }
        std::string _raw_body() const { return m__raw_body; }
        kaitai::kstream* _io__raw_body() const { return m__io__raw_body.get(); }
    };

    class dir_t : public kaitai::kstruct {

    public:

        dir_t(kaitai::kstream* p__io, ext2_t::inode_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~dir_t();

    private:
        std::unique_ptr<std::vector<std::unique_ptr<dir_entry_t>>> m_entries;
        ext2_t* m__root;
        ext2_t::inode_t* m__parent;

    public:
        std::vector<std::unique_ptr<dir_entry_t>>* entries() const { return m_entries.get(); }
        ext2_t* _root() const { return m__root; }
        ext2_t::inode_t* _parent() const { return m__parent; }
    };

    class block_group_t : public kaitai::kstruct {

    public:

        block_group_t(kaitai::kstream* p__io, ext2_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~block_group_t();

    private:
        std::unique_ptr<super_block_struct_t> m_super_block;
        std::unique_ptr<std::vector<std::unique_ptr<bgd_t>>> m_block_groups;
        ext2_t* m__root;
        ext2_t* m__parent;
        std::string m__raw_super_block;
        std::unique_ptr<kaitai::kstream> m__io__raw_super_block;

    public:
        super_block_struct_t* super_block() const { return m_super_block.get(); }
        std::vector<std::unique_ptr<bgd_t>>* block_groups() const { return m_block_groups.get(); }
        ext2_t* _root() const { return m__root; }
        ext2_t* _parent() const { return m__parent; }
        std::string _raw_super_block() const { return m__raw_super_block; }
        kaitai::kstream* _io__raw_super_block() const { return m__io__raw_super_block.get(); }
    };

    class bgd_t : public kaitai::kstruct {

    public:

        bgd_t(kaitai::kstream* p__io, ext2_t::block_group_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~bgd_t();

    private:
        bool f_block_bitmap;
        std::string m_block_bitmap;

    public:
        std::string block_bitmap();

    private:
        bool f_inode_bitmap;
        std::string m_inode_bitmap;

    public:
        std::string inode_bitmap();

    private:
        bool f_inodes;
        std::unique_ptr<std::vector<std::unique_ptr<inode_t>>> m_inodes;

    public:
        std::vector<std::unique_ptr<inode_t>>* inodes();

    private:
        uint32_t m_block_bitmap_block;
        uint32_t m_inode_bitmap_block;
        uint32_t m_inode_table_block;
        uint16_t m_free_blocks_count;
        uint16_t m_free_inodes_count;
        uint16_t m_used_dirs_count;
        std::string m_pad_reserved;
        ext2_t* m__root;
        ext2_t::block_group_t* m__parent;

    public:
        uint32_t block_bitmap_block() const { return m_block_bitmap_block; }
        uint32_t inode_bitmap_block() const { return m_inode_bitmap_block; }
        uint32_t inode_table_block() const { return m_inode_table_block; }
        uint16_t free_blocks_count() const { return m_free_blocks_count; }
        uint16_t free_inodes_count() const { return m_free_inodes_count; }
        uint16_t used_dirs_count() const { return m_used_dirs_count; }
        std::string pad_reserved() const { return m_pad_reserved; }
        ext2_t* _root() const { return m__root; }
        ext2_t::block_group_t* _parent() const { return m__parent; }
    };

    class raw_block_t : public kaitai::kstruct {

    public:

        raw_block_t(kaitai::kstream* p__io, ext2_t::block_ptr_t* p__parent = nullptr, ext2_t* p__root = nullptr);

    private:
        void _read();
        void _clean_up();

    public:
        ~raw_block_t();

    private:
        std::string m_body;
        ext2_t* m__root;
        ext2_t::block_ptr_t* m__parent;

    public:
        std::string body() const { return m_body; }
        ext2_t* _root() const { return m__root; }
        ext2_t::block_ptr_t* _parent() const { return m__parent; }
    };

private:
    bool f_bg1;
    std::unique_ptr<block_group_t> m_bg1;

public:
    block_group_t* bg1();

private:
    bool f_root_dir;
    dir_t* m_root_dir;

public:
    dir_t* root_dir();

private:
    ext2_t* m__root;
    kaitai::kstruct* m__parent;

public:
    ext2_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

ext2.cpp

// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild

#include "ext2.h"
#include "kaitai/exceptions.h"

ext2_t::ext2_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_bg1 = nullptr;
    f_bg1 = false;
    f_root_dir = false;
    _read();
}

void ext2_t::_read() {
}

ext2_t::~ext2_t() {
    _clean_up();
}

void ext2_t::_clean_up() {
    if (f_bg1) {
    }
}

ext2_t::super_block_struct_t::super_block_struct_t(kaitai::kstream* p__io, ext2_t::block_group_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_hash_seed = nullptr;
    f_block_size = false;
    f_block_group_count = false;
    _read();
}

void ext2_t::super_block_struct_t::_read() {
    m_inodes_count = m__io->read_u4le();
    m_blocks_count = m__io->read_u4le();
    m_r_blocks_count = m__io->read_u4le();
    m_free_blocks_count = m__io->read_u4le();
    m_free_inodes_count = m__io->read_u4le();
    m_first_data_block = m__io->read_u4le();
    m_log_block_size = m__io->read_u4le();
    m_log_frag_size = m__io->read_u4le();
    m_blocks_per_group = m__io->read_u4le();
    m_frags_per_group = m__io->read_u4le();
    m_inodes_per_group = m__io->read_u4le();
    m_mtime = m__io->read_u4le();
    m_wtime = m__io->read_u4le();
    m_mnt_count = m__io->read_u2le();
    m_max_mnt_count = m__io->read_u2le();
    m_magic = m__io->read_bytes(2);
    if (!(magic() == std::string("\x53\xEF", 2))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x53\xEF", 2), magic(), _io(), std::string("/types/super_block_struct/seq/15"));
    }
    m_state = static_cast<ext2_t::super_block_struct_t::state_enum_t>(m__io->read_u2le());
    m_errors = static_cast<ext2_t::super_block_struct_t::errors_enum_t>(m__io->read_u2le());
    m_minor_rev_level = m__io->read_u2le();
    m_lastcheck = m__io->read_u4le();
    m_checkinterval = m__io->read_u4le();
    m_creator_os = m__io->read_u4le();
    m_rev_level = m__io->read_u4le();
    m_def_resuid = m__io->read_u2le();
    m_def_resgid = m__io->read_u2le();
    m_first_ino = m__io->read_u4le();
    m_inode_size = m__io->read_u2le();
    m_block_group_nr = m__io->read_u2le();
    m_feature_compat = m__io->read_u4le();
    m_feature_incompat = m__io->read_u4le();
    m_feature_ro_compat = m__io->read_u4le();
    m_uuid = m__io->read_bytes(16);
    m_volume_name = m__io->read_bytes(16);
    m_last_mounted = m__io->read_bytes(64);
    m_algo_bitmap = m__io->read_u4le();
    m_prealloc_blocks = m__io->read_u1();
    m_prealloc_dir_blocks = m__io->read_u1();
    m_padding1 = m__io->read_bytes(2);
    m_journal_uuid = m__io->read_bytes(16);
    m_journal_inum = m__io->read_u4le();
    m_journal_dev = m__io->read_u4le();
    m_last_orphan = m__io->read_u4le();
    m_hash_seed = std::unique_ptr<std::vector<uint32_t>>(new std::vector<uint32_t>());
    const int l_hash_seed = 4;
    for (int i = 0; i < l_hash_seed; i++) {
        m_hash_seed->push_back(std::move(m__io->read_u4le()));
    }
    m_def_hash_version = m__io->read_u1();
}

ext2_t::super_block_struct_t::~super_block_struct_t() {
    _clean_up();
}

void ext2_t::super_block_struct_t::_clean_up() {
}

int32_t ext2_t::super_block_struct_t::block_size() {
    if (f_block_size)
        return m_block_size;
    m_block_size = (1024 << log_block_size());
    f_block_size = true;
    return m_block_size;
}

int32_t ext2_t::super_block_struct_t::block_group_count() {
    if (f_block_group_count)
        return m_block_group_count;
    m_block_group_count = (blocks_count() / blocks_per_group());
    f_block_group_count = true;
    return m_block_group_count;
}

ext2_t::dir_entry_t::dir_entry_t(kaitai::kstream* p__io, ext2_t::dir_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_inode = false;
    _read();
}

void ext2_t::dir_entry_t::_read() {
    m_inode_ptr = m__io->read_u4le();
    m_rec_len = m__io->read_u2le();
    m_name_len = m__io->read_u1();
    m_file_type = static_cast<ext2_t::dir_entry_t::file_type_enum_t>(m__io->read_u1());
    m_name = kaitai::kstream::bytes_to_str(m__io->read_bytes(name_len()), std::string("UTF-8"));
    m_padding = m__io->read_bytes(((rec_len() - name_len()) - 8));
}

ext2_t::dir_entry_t::~dir_entry_t() {
    _clean_up();
}

void ext2_t::dir_entry_t::_clean_up() {
}

ext2_t::inode_t* ext2_t::dir_entry_t::inode() {
    if (f_inode)
        return m_inode;
    m_inode = _root()->bg1()->block_groups()->at(((inode_ptr() - 1) / _root()->bg1()->super_block()->inodes_per_group()))->inodes()->at(kaitai::kstream::mod((inode_ptr() - 1), _root()->bg1()->super_block()->inodes_per_group()));
    f_inode = true;
    return m_inode;
}

ext2_t::inode_t::inode_t(kaitai::kstream* p__io, ext2_t::bgd_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_block = nullptr;
    m_as_dir = nullptr;
    f_as_dir = false;
    _read();
}

void ext2_t::inode_t::_read() {
    m_mode = m__io->read_u2le();
    m_uid = m__io->read_u2le();
    m_size = m__io->read_u4le();
    m_atime = m__io->read_u4le();
    m_ctime = m__io->read_u4le();
    m_mtime = m__io->read_u4le();
    m_dtime = m__io->read_u4le();
    m_gid = m__io->read_u2le();
    m_links_count = m__io->read_u2le();
    m_blocks = m__io->read_u4le();
    m_flags = m__io->read_u4le();
    m_osd1 = m__io->read_u4le();
    m_block = std::unique_ptr<std::vector<std::unique_ptr<block_ptr_t>>>(new std::vector<std::unique_ptr<block_ptr_t>>());
    const int l_block = 15;
    for (int i = 0; i < l_block; i++) {
        m_block->push_back(std::move(std::unique_ptr<block_ptr_t>(new block_ptr_t(m__io, this, m__root))));
    }
    m_generation = m__io->read_u4le();
    m_file_acl = m__io->read_u4le();
    m_dir_acl = m__io->read_u4le();
    m_faddr = m__io->read_u4le();
    m_osd2 = m__io->read_bytes(12);
}

ext2_t::inode_t::~inode_t() {
    _clean_up();
}

void ext2_t::inode_t::_clean_up() {
    if (f_as_dir) {
    }
}

ext2_t::dir_t* ext2_t::inode_t::as_dir() {
    if (f_as_dir)
        return m_as_dir.get();
    kaitai::kstream *io = block()->at(0)->body()->_io();
    std::streampos _pos = io->pos();
    io->seek(0);
    m_as_dir = std::unique_ptr<dir_t>(new dir_t(io, this, m__root));
    io->seek(_pos);
    f_as_dir = true;
    return m_as_dir.get();
}

ext2_t::block_ptr_t::block_ptr_t(kaitai::kstream* p__io, ext2_t::inode_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_body = nullptr;
    m__io__raw_body = nullptr;
    f_body = false;
    _read();
}

void ext2_t::block_ptr_t::_read() {
    m_ptr = m__io->read_u4le();
}

ext2_t::block_ptr_t::~block_ptr_t() {
    _clean_up();
}

void ext2_t::block_ptr_t::_clean_up() {
    if (f_body) {
    }
}

ext2_t::raw_block_t* ext2_t::block_ptr_t::body() {
    if (f_body)
        return m_body.get();
    std::streampos _pos = m__io->pos();
    m__io->seek((ptr() * _root()->bg1()->super_block()->block_size()));
    m__raw_body = m__io->read_bytes(_root()->bg1()->super_block()->block_size());
    m__io__raw_body = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_body));
    m_body = std::unique_ptr<raw_block_t>(new raw_block_t(m__io__raw_body.get(), this, m__root));
    m__io->seek(_pos);
    f_body = true;
    return m_body.get();
}

ext2_t::dir_t::dir_t(kaitai::kstream* p__io, ext2_t::inode_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_entries = nullptr;
    _read();
}

void ext2_t::dir_t::_read() {
    m_entries = std::unique_ptr<std::vector<std::unique_ptr<dir_entry_t>>>(new std::vector<std::unique_ptr<dir_entry_t>>());
    {
        int i = 0;
        while (!m__io->is_eof()) {
            m_entries->push_back(std::move(std::unique_ptr<dir_entry_t>(new dir_entry_t(m__io, this, m__root))));
            i++;
        }
    }
}

ext2_t::dir_t::~dir_t() {
    _clean_up();
}

void ext2_t::dir_t::_clean_up() {
}

ext2_t::block_group_t::block_group_t(kaitai::kstream* p__io, ext2_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_super_block = nullptr;
    m__io__raw_super_block = nullptr;
    m_block_groups = nullptr;
    _read();
}

void ext2_t::block_group_t::_read() {
    m__raw_super_block = m__io->read_bytes(1024);
    m__io__raw_super_block = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_super_block));
    m_super_block = std::unique_ptr<super_block_struct_t>(new super_block_struct_t(m__io__raw_super_block.get(), this, m__root));
    m_block_groups = std::unique_ptr<std::vector<std::unique_ptr<bgd_t>>>(new std::vector<std::unique_ptr<bgd_t>>());
    const int l_block_groups = super_block()->block_group_count();
    for (int i = 0; i < l_block_groups; i++) {
        m_block_groups->push_back(std::move(std::unique_ptr<bgd_t>(new bgd_t(m__io, this, m__root))));
    }
}

ext2_t::block_group_t::~block_group_t() {
    _clean_up();
}

void ext2_t::block_group_t::_clean_up() {
}

ext2_t::bgd_t::bgd_t(kaitai::kstream* p__io, ext2_t::block_group_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_inodes = nullptr;
    f_block_bitmap = false;
    f_inode_bitmap = false;
    f_inodes = false;
    _read();
}

void ext2_t::bgd_t::_read() {
    m_block_bitmap_block = m__io->read_u4le();
    m_inode_bitmap_block = m__io->read_u4le();
    m_inode_table_block = m__io->read_u4le();
    m_free_blocks_count = m__io->read_u2le();
    m_free_inodes_count = m__io->read_u2le();
    m_used_dirs_count = m__io->read_u2le();
    m_pad_reserved = m__io->read_bytes((2 + 12));
}

ext2_t::bgd_t::~bgd_t() {
    _clean_up();
}

void ext2_t::bgd_t::_clean_up() {
    if (f_block_bitmap) {
    }
    if (f_inode_bitmap) {
    }
    if (f_inodes) {
    }
}

std::string ext2_t::bgd_t::block_bitmap() {
    if (f_block_bitmap)
        return m_block_bitmap;
    std::streampos _pos = m__io->pos();
    m__io->seek((block_bitmap_block() * _root()->bg1()->super_block()->block_size()));
    m_block_bitmap = m__io->read_bytes(1024);
    m__io->seek(_pos);
    f_block_bitmap = true;
    return m_block_bitmap;
}

std::string ext2_t::bgd_t::inode_bitmap() {
    if (f_inode_bitmap)
        return m_inode_bitmap;
    std::streampos _pos = m__io->pos();
    m__io->seek((inode_bitmap_block() * _root()->bg1()->super_block()->block_size()));
    m_inode_bitmap = m__io->read_bytes(1024);
    m__io->seek(_pos);
    f_inode_bitmap = true;
    return m_inode_bitmap;
}

std::vector<std::unique_ptr<ext2_t::inode_t>>* ext2_t::bgd_t::inodes() {
    if (f_inodes)
        return m_inodes.get();
    std::streampos _pos = m__io->pos();
    m__io->seek((inode_table_block() * _root()->bg1()->super_block()->block_size()));
    m_inodes = std::unique_ptr<std::vector<std::unique_ptr<inode_t>>>(new std::vector<std::unique_ptr<inode_t>>());
    const int l_inodes = _root()->bg1()->super_block()->inodes_per_group();
    for (int i = 0; i < l_inodes; i++) {
        m_inodes->push_back(std::move(std::unique_ptr<inode_t>(new inode_t(m__io, this, m__root))));
    }
    m__io->seek(_pos);
    f_inodes = true;
    return m_inodes.get();
}

ext2_t::raw_block_t::raw_block_t(kaitai::kstream* p__io, ext2_t::block_ptr_t* p__parent, ext2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void ext2_t::raw_block_t::_read() {
    m_body = m__io->read_bytes(_root()->bg1()->super_block()->block_size());
}

ext2_t::raw_block_t::~raw_block_t() {
    _clean_up();
}

void ext2_t::raw_block_t::_clean_up() {
}

ext2_t::block_group_t* ext2_t::bg1() {
    if (f_bg1)
        return m_bg1.get();
    std::streampos _pos = m__io->pos();
    m__io->seek(1024);
    m_bg1 = std::unique_ptr<block_group_t>(new block_group_t(m__io, this, m__root));
    m__io->seek(_pos);
    f_bg1 = true;
    return m_bg1.get();
}

ext2_t::dir_t* ext2_t::root_dir() {
    if (f_root_dir)
        return m_root_dir;
    m_root_dir = bg1()->block_groups()->at(0)->inodes()->at(1)->as_dir();
    f_root_dir = true;
    return m_root_dir;
}