Logical Volume Manager version 2: C++11/STL parsing library

Building a test file

dd if=/dev/zero of=image.img bs=512 count=$(( 4 * 1024 * 2 ))
sudo losetup /dev/loop1 image.img
sudo pvcreate /dev/loop1
sudo vgcreate vg_test /dev/loop1
sudo lvcreate --name lv_test1 vg_test
sudo losetup -d /dev/loop1

Application

["linux", "grub2", "lvm tools", "libvslvm"]

KS implementation details

References

This page hosts a formal specification of Logical Volume Manager version 2 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:
    lvm2_t data(&ks);
    

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

data.pv() // => Physical volume

C++11/STL source code to parse Logical Volume Manager version 2

lvm2.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

/**
 * ### Building a test file
 * 
 * ```
 * dd if=/dev/zero of=image.img bs=512 count=$(( 4 * 1024 * 2 ))
 * sudo losetup /dev/loop1 image.img
 * sudo pvcreate /dev/loop1
 * sudo vgcreate vg_test /dev/loop1
 * sudo lvcreate --name lv_test1 vg_test
 * sudo losetup -d /dev/loop1
 * ```
 * \sa https://github.com/libyal/libvslvm/blob/main/documentation/Logical%20Volume%20Manager%20(LVM)%20format.asciidoc Source
 */

class lvm2_t : public kaitai::kstruct {

public:
    class physical_volume_t;

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

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

public:
    ~lvm2_t();

    class physical_volume_t : public kaitai::kstruct {

    public:
        class label_t;

        physical_volume_t(kaitai::kstream* p__io, lvm2_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

    public:
        ~physical_volume_t();

        class label_t : public kaitai::kstruct {

        public:
            class label_header_t;
            class volume_header_t;

            label_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

        public:
            ~label_t();

            class label_header_t : public kaitai::kstruct {

            public:
                class label_header__t;

                label_header_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

            public:
                ~label_header_t();

                class label_header__t : public kaitai::kstruct {

                public:

                    label_header__t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::label_header_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

                public:
                    ~label_header__t();

                private:
                    uint32_t m_data_offset;
                    std::string m_type_indicator;
                    lvm2_t* m__root;
                    lvm2_t::physical_volume_t::label_t::label_header_t* m__parent;

                public:

                    /**
                     * The offset, in bytes, relative from the start of the physical volume label header where data is stored
                     */
                    uint32_t data_offset() const { return m_data_offset; }
                    std::string type_indicator() const { return m_type_indicator; }
                    lvm2_t* _root() const { return m__root; }
                    lvm2_t::physical_volume_t::label_t::label_header_t* _parent() const { return m__parent; }
                };

            private:
                std::string m_signature;
                uint64_t m_sector_number;
                uint32_t m_checksum;
                std::unique_ptr<label_header__t> m_label_header_;
                lvm2_t* m__root;
                lvm2_t::physical_volume_t::label_t* m__parent;

            public:
                std::string signature() const { return m_signature; }

                /**
                 * The sector number of the physical volume label header
                 */
                uint64_t sector_number() const { return m_sector_number; }

                /**
                 * CRC-32 for offset 20 to end of the physical volume label sector
                 */
                uint32_t checksum() const { return m_checksum; }
                label_header__t* label_header_() const { return m_label_header_.get(); }
                lvm2_t* _root() const { return m__root; }
                lvm2_t::physical_volume_t::label_t* _parent() const { return m__parent; }
            };

            class volume_header_t : public kaitai::kstruct {

            public:
                class data_area_descriptor_t;
                class metadata_area_descriptor_t;
                class metadata_area_t;

                volume_header_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

            public:
                ~volume_header_t();

                class data_area_descriptor_t : public kaitai::kstruct {

                public:

                    data_area_descriptor_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

                public:
                    ~data_area_descriptor_t();

                private:
                    bool f_data;
                    std::string m_data;
                    bool n_data;

                public:
                    bool _is_null_data() { data(); return n_data; };

                private:

                public:
                    std::string data();

                private:
                    uint64_t m_offset;
                    uint64_t m_size;
                    lvm2_t* m__root;
                    lvm2_t::physical_volume_t::label_t::volume_header_t* m__parent;

                public:

                    /**
                     * The offset, in bytes, relative from the start of the physical volume
                     */
                    uint64_t offset() const { return m_offset; }

                    /**
                     * Value in bytes. Can be 0. [yellow-background]*Does this represent all remaining available space?*
                     */
                    uint64_t size() const { return m_size; }
                    lvm2_t* _root() const { return m__root; }
                    lvm2_t::physical_volume_t::label_t::volume_header_t* _parent() const { return m__parent; }
                };

                class metadata_area_descriptor_t : public kaitai::kstruct {

                public:

                    metadata_area_descriptor_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

                public:
                    ~metadata_area_descriptor_t();

                private:
                    bool f_data;
                    std::unique_ptr<metadata_area_t> m_data;
                    bool n_data;

                public:
                    bool _is_null_data() { data(); return n_data; };

                private:

                public:
                    metadata_area_t* data();

                private:
                    uint64_t m_offset;
                    uint64_t m_size;
                    lvm2_t* m__root;
                    lvm2_t::physical_volume_t::label_t::volume_header_t* m__parent;
                    std::string m__raw_data;
                    bool n__raw_data;

                public:
                    bool _is_null__raw_data() { _raw_data(); return n__raw_data; };

                private:
                    std::unique_ptr<kaitai::kstream> m__io__raw_data;

                public:

                    /**
                     * The offset, in bytes, relative from the start of the physical volume
                     */
                    uint64_t offset() const { return m_offset; }

                    /**
                     * Value in bytes
                     */
                    uint64_t size() const { return m_size; }
                    lvm2_t* _root() const { return m__root; }
                    lvm2_t::physical_volume_t::label_t::volume_header_t* _parent() const { return m__parent; }
                    std::string _raw_data() const { return m__raw_data; }
                    kaitai::kstream* _io__raw_data() const { return m__io__raw_data.get(); }
                };

                /**
                 * According to `[REDHAT]` the metadata area is a circular buffer. New metadata is appended to the old metadata and then the pointer to the start of it is updated. The metadata area, therefore, can contain copies of older versions of the metadata.
                 */

                class metadata_area_t : public kaitai::kstruct {

                public:
                    class metadata_area_header_t;

                    metadata_area_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

                public:
                    ~metadata_area_t();

                    class metadata_area_header_t : public kaitai::kstruct {

                    public:
                        class raw_location_descriptor_t;

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

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

                    public:
                        ~metadata_area_header_t();

                        /**
                         * The data area size can be 0. It is assumed it represents the remaining  available data.
                         */

                        class raw_location_descriptor_t : public kaitai::kstruct {

                        public:

                            enum raw_location_descriptor_flags_t {
                                RAW_LOCATION_DESCRIPTOR_FLAGS_RAW_LOCATION_IGNORED = 1
                            };

                            raw_location_descriptor_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t* p__parent = nullptr, lvm2_t* p__root = nullptr);

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

                        public:
                            ~raw_location_descriptor_t();

                        private:
                            uint64_t m_offset;
                            uint64_t m_size;
                            uint32_t m_checksum;
                            raw_location_descriptor_flags_t m_flags;
                            lvm2_t* m__root;
                            lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t* m__parent;

                        public:

                            /**
                             * The data area offset, in bytes, relative from the start of the metadata area
                             */
                            uint64_t offset() const { return m_offset; }

                            /**
                             * data area size in bytes
                             */
                            uint64_t size() const { return m_size; }

                            /**
                             * CRC-32 of *TODO (metadata?)*
                             */
                            uint32_t checksum() const { return m_checksum; }
                            raw_location_descriptor_flags_t flags() const { return m_flags; }
                            lvm2_t* _root() const { return m__root; }
                            lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t* _parent() const { return m__parent; }
                        };

                    private:
                        bool f_metadata;
                        std::string m_metadata;

                    public:
                        std::string metadata();

                    private:
                        std::unique_ptr<metadata_area_header_t> m_checksum;
                        std::string m_signature;
                        uint32_t m_version;
                        uint64_t m_metadata_area_offset;
                        uint64_t m_metadata_area_size;
                        std::unique_ptr<std::vector<std::unique_ptr<raw_location_descriptor_t>>> m_raw_location_descriptors;
                        lvm2_t* m__root;
                        kaitai::kstruct* m__parent;

                    public:

                        /**
                         * CRC-32 for offset 4 to end of the metadata area header
                         */
                        metadata_area_header_t* checksum() const { return m_checksum.get(); }
                        std::string signature() const { return m_signature; }
                        uint32_t version() const { return m_version; }

                        /**
                         * The offset, in bytes, of the metadata area relative from the start of the physical volume
                         */
                        uint64_t metadata_area_offset() const { return m_metadata_area_offset; }
                        uint64_t metadata_area_size() const { return m_metadata_area_size; }

                        /**
                         * The last descriptor in the list is terminator and consists of 0-byte values.
                         */
                        std::vector<std::unique_ptr<raw_location_descriptor_t>>* raw_location_descriptors() const { return m_raw_location_descriptors.get(); }
                        lvm2_t* _root() const { return m__root; }
                        kaitai::kstruct* _parent() const { return m__parent; }
                    };

                private:
                    std::unique_ptr<metadata_area_header_t> m_header;
                    lvm2_t* m__root;
                    lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t* m__parent;

                public:
                    metadata_area_header_t* header() const { return m_header.get(); }
                    lvm2_t* _root() const { return m__root; }
                    lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t* _parent() const { return m__parent; }
                };

            private:
                std::string m_id;
                uint64_t m_size;
                std::unique_ptr<std::vector<std::unique_ptr<data_area_descriptor_t>>> m_data_area_descriptors;
                std::unique_ptr<std::vector<std::unique_ptr<metadata_area_descriptor_t>>> m_metadata_area_descriptors;
                lvm2_t* m__root;
                lvm2_t::physical_volume_t::label_t* m__parent;

            public:

                /**
                 * Contains a UUID stored as an ASCII string. The physical volume identifier can be used to uniquely identify a physical volume. The physical volume identifier is stored as: 9LBcEB7PQTGIlLI0KxrtzrynjuSL983W but is equivalent to its formatted variant: 9LBcEB-7PQT-GIlL-I0Kx-rtzr-ynju-SL983W, which is used in the metadata.
                 */
                std::string id() const { return m_id; }

                /**
                 * Physical Volume size. Value in bytes
                 */
                uint64_t size() const { return m_size; }

                /**
                 * The last descriptor in the list is terminator and consists of 0-byte values.
                 */
                std::vector<std::unique_ptr<data_area_descriptor_t>>* data_area_descriptors() const { return m_data_area_descriptors.get(); }
                std::vector<std::unique_ptr<metadata_area_descriptor_t>>* metadata_area_descriptors() const { return m_metadata_area_descriptors.get(); }
                lvm2_t* _root() const { return m__root; }
                lvm2_t::physical_volume_t::label_t* _parent() const { return m__parent; }
            };

        private:
            std::unique_ptr<label_header_t> m_label_header;
            std::unique_ptr<volume_header_t> m_volume_header;
            lvm2_t* m__root;
            lvm2_t::physical_volume_t* m__parent;

        public:
            label_header_t* label_header() const { return m_label_header.get(); }
            volume_header_t* volume_header() const { return m_volume_header.get(); }
            lvm2_t* _root() const { return m__root; }
            lvm2_t::physical_volume_t* _parent() const { return m__parent; }
        };

    private:
        std::string m_empty_sector;
        std::unique_ptr<label_t> m_label;
        lvm2_t* m__root;
        lvm2_t* m__parent;

    public:
        std::string empty_sector() const { return m_empty_sector; }
        label_t* label() const { return m_label.get(); }
        lvm2_t* _root() const { return m__root; }
        lvm2_t* _parent() const { return m__parent; }
    };

private:
    bool f_sector_size;
    int32_t m_sector_size;

public:
    int32_t sector_size();

private:
    std::unique_ptr<physical_volume_t> m_pv;
    lvm2_t* m__root;
    kaitai::kstruct* m__parent;

public:

    /**
     * Physical volume
     */
    physical_volume_t* pv() const { return m_pv.get(); }
    lvm2_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

lvm2.cpp

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

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

lvm2_t::lvm2_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    m_pv = nullptr;
    f_sector_size = false;
    _read();
}

void lvm2_t::_read() {
    m_pv = std::unique_ptr<physical_volume_t>(new physical_volume_t(m__io, this, m__root));
}

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

void lvm2_t::_clean_up() {
}

lvm2_t::physical_volume_t::physical_volume_t(kaitai::kstream* p__io, lvm2_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_label = nullptr;
    _read();
}

void lvm2_t::physical_volume_t::_read() {
    m_empty_sector = m__io->read_bytes(_root()->sector_size());
    m_label = std::unique_ptr<label_t>(new label_t(m__io, this, m__root));
}

lvm2_t::physical_volume_t::~physical_volume_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::_clean_up() {
}

lvm2_t::physical_volume_t::label_t::label_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_label_header = nullptr;
    m_volume_header = nullptr;
    _read();
}

void lvm2_t::physical_volume_t::label_t::_read() {
    m_label_header = std::unique_ptr<label_header_t>(new label_header_t(m__io, this, m__root));
    m_volume_header = std::unique_ptr<volume_header_t>(new volume_header_t(m__io, this, m__root));
}

lvm2_t::physical_volume_t::label_t::~label_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::_clean_up() {
}

lvm2_t::physical_volume_t::label_t::label_header_t::label_header_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_label_header_ = nullptr;
    _read();
}

void lvm2_t::physical_volume_t::label_t::label_header_t::_read() {
    m_signature = m__io->read_bytes(8);
    if (!(signature() == std::string("\x4C\x41\x42\x45\x4C\x4F\x4E\x45", 8))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x4C\x41\x42\x45\x4C\x4F\x4E\x45", 8), signature(), _io(), std::string("/types/physical_volume/types/label/types/label_header/seq/0"));
    }
    m_sector_number = m__io->read_u8le();
    m_checksum = m__io->read_u4le();
    m_label_header_ = std::unique_ptr<label_header__t>(new label_header__t(m__io, this, m__root));
}

lvm2_t::physical_volume_t::label_t::label_header_t::~label_header_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::label_header_t::_clean_up() {
}

lvm2_t::physical_volume_t::label_t::label_header_t::label_header__t::label_header__t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::label_header_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void lvm2_t::physical_volume_t::label_t::label_header_t::label_header__t::_read() {
    m_data_offset = m__io->read_u4le();
    m_type_indicator = m__io->read_bytes(8);
    if (!(type_indicator() == std::string("\x4C\x56\x4D\x32\x20\x30\x30\x31", 8))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x4C\x56\x4D\x32\x20\x30\x30\x31", 8), type_indicator(), _io(), std::string("/types/physical_volume/types/label/types/label_header/types/label_header_/seq/1"));
    }
}

lvm2_t::physical_volume_t::label_t::label_header_t::label_header__t::~label_header__t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::label_header_t::label_header__t::_clean_up() {
}

lvm2_t::physical_volume_t::label_t::volume_header_t::volume_header_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_data_area_descriptors = nullptr;
    m_metadata_area_descriptors = nullptr;
    _read();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::_read() {
    m_id = kaitai::kstream::bytes_to_str(m__io->read_bytes(32), std::string("ascii"));
    m_size = m__io->read_u8le();
    m_data_area_descriptors = std::unique_ptr<std::vector<std::unique_ptr<data_area_descriptor_t>>>(new std::vector<std::unique_ptr<data_area_descriptor_t>>());
    {
        int i = 0;
        data_area_descriptor_t* _;
        do {
            _ = new data_area_descriptor_t(m__io, this, m__root);
            m_data_area_descriptors->push_back(std::move(std::unique_ptr<data_area_descriptor_t>(_)));
            i++;
        } while (!( ((_->size() != 0) && (_->offset() != 0)) ));
    }
    m_metadata_area_descriptors = std::unique_ptr<std::vector<std::unique_ptr<metadata_area_descriptor_t>>>(new std::vector<std::unique_ptr<metadata_area_descriptor_t>>());
    {
        int i = 0;
        metadata_area_descriptor_t* _;
        do {
            _ = new metadata_area_descriptor_t(m__io, this, m__root);
            m_metadata_area_descriptors->push_back(std::move(std::unique_ptr<metadata_area_descriptor_t>(_)));
            i++;
        } while (!( ((_->size() != 0) && (_->offset() != 0)) ));
    }
}

lvm2_t::physical_volume_t::label_t::volume_header_t::~volume_header_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::_clean_up() {
}

lvm2_t::physical_volume_t::label_t::volume_header_t::data_area_descriptor_t::data_area_descriptor_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_data = false;
    _read();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::data_area_descriptor_t::_read() {
    m_offset = m__io->read_u8le();
    m_size = m__io->read_u8le();
}

lvm2_t::physical_volume_t::label_t::volume_header_t::data_area_descriptor_t::~data_area_descriptor_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::data_area_descriptor_t::_clean_up() {
    if (f_data && !n_data) {
    }
}

std::string lvm2_t::physical_volume_t::label_t::volume_header_t::data_area_descriptor_t::data() {
    if (f_data)
        return m_data;
    n_data = true;
    if (size() != 0) {
        n_data = false;
        std::streampos _pos = m__io->pos();
        m__io->seek(offset());
        m_data = kaitai::kstream::bytes_to_str(m__io->read_bytes(size()), std::string("ascii"));
        m__io->seek(_pos);
        f_data = true;
    }
    return m_data;
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t::metadata_area_descriptor_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_data = nullptr;
    m__io__raw_data = nullptr;
    f_data = false;
    _read();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t::_read() {
    m_offset = m__io->read_u8le();
    m_size = m__io->read_u8le();
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t::~metadata_area_descriptor_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t::_clean_up() {
    if (f_data && !n_data) {
    }
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t* lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t::data() {
    if (f_data)
        return m_data.get();
    n_data = true;
    if (size() != 0) {
        n_data = false;
        std::streampos _pos = m__io->pos();
        m__io->seek(offset());
        m__raw_data = m__io->read_bytes(size());
        m__io__raw_data = std::unique_ptr<kaitai::kstream>(new kaitai::kstream(m__raw_data));
        m_data = std::unique_ptr<metadata_area_t>(new metadata_area_t(m__io__raw_data.get(), this, m__root));
        m__io->seek(_pos);
        f_data = true;
    }
    return m_data.get();
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_descriptor_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_header = nullptr;
    _read();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::_read() {
    m_header = std::unique_ptr<metadata_area_header_t>(new metadata_area_header_t(m__io, this, m__root));
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::~metadata_area_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::_clean_up() {
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::metadata_area_header_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    m_checksum = nullptr;
    m_raw_location_descriptors = nullptr;
    f_metadata = false;
    _read();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::_read() {
    m_checksum = std::unique_ptr<metadata_area_header_t>(new metadata_area_header_t(m__io, this, m__root));
    m_signature = m__io->read_bytes(16);
    if (!(signature() == std::string("\x20\x4C\x56\x4D\x32\x20\x78\x5B\x35\x41\x25\x72\x30\x4E\x2A\x3E", 16))) {
        throw kaitai::validation_not_equal_error<std::string>(std::string("\x20\x4C\x56\x4D\x32\x20\x78\x5B\x35\x41\x25\x72\x30\x4E\x2A\x3E", 16), signature(), _io(), std::string("/types/physical_volume/types/label/types/volume_header/types/metadata_area/types/metadata_area_header/seq/1"));
    }
    m_version = m__io->read_u4le();
    m_metadata_area_offset = m__io->read_u8le();
    m_metadata_area_size = m__io->read_u8le();
    m_raw_location_descriptors = std::unique_ptr<std::vector<std::unique_ptr<raw_location_descriptor_t>>>(new std::vector<std::unique_ptr<raw_location_descriptor_t>>());
    {
        int i = 0;
        raw_location_descriptor_t* _;
        do {
            _ = new raw_location_descriptor_t(m__io, this, m__root);
            m_raw_location_descriptors->push_back(std::move(std::unique_ptr<raw_location_descriptor_t>(_)));
            i++;
        } while (!( ((_->offset() != 0) && (_->size() != 0) && (_->checksum() != 0)) ));
    }
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::~metadata_area_header_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::_clean_up() {
    if (f_metadata) {
    }
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::raw_location_descriptor_t::raw_location_descriptor_t(kaitai::kstream* p__io, lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t* p__parent, lvm2_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::raw_location_descriptor_t::_read() {
    m_offset = m__io->read_u8le();
    m_size = m__io->read_u8le();
    m_checksum = m__io->read_u4le();
    m_flags = static_cast<lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::raw_location_descriptor_t::raw_location_descriptor_flags_t>(m__io->read_u4le());
}

lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::raw_location_descriptor_t::~raw_location_descriptor_t() {
    _clean_up();
}

void lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::raw_location_descriptor_t::_clean_up() {
}

std::string lvm2_t::physical_volume_t::label_t::volume_header_t::metadata_area_t::metadata_area_header_t::metadata() {
    if (f_metadata)
        return m_metadata;
    std::streampos _pos = m__io->pos();
    m__io->seek(metadata_area_offset());
    m_metadata = m__io->read_bytes(metadata_area_size());
    m__io->seek(_pos);
    f_metadata = true;
    return m_metadata;
}

int32_t lvm2_t::sector_size() {
    if (f_sector_size)
        return m_sector_size;
    m_sector_size = 512;
    f_sector_size = true;
    return m_sector_size;
}