MBR (Master Boot Record) partition table: C++/STL parsing library

MBR (Master Boot Record) partition table is a traditional way of MS-DOS to partition larger hard disc drives into distinct partitions.

This table is stored in the end of the boot sector (first sector) of the drive, after the bootstrap code. Original DOS 2.0 specification allowed only 4 partitions per disc, but DOS 3.2 introduced concept of "extended partitions", which work as nested extra "boot records" which are pointed to by original ("primary") partitions in MBR.

KS implementation details

License: CC0-1.0

This page hosts a formal specification of MBR (Master Boot Record) partition table using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Usage

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 a stream for reading from a local file:
      #include <fstream>
      
      std::ifstream is("path/to/local/file.mbr_partition_table", std::ifstream::binary);
    • Or one can prepare a stream for reading from existing std::string str:
      #include <sstream>
      
      std::istringstream is(str);
    • Or one can parse arbitrary char* buffer in memory, given that we know its size:
      #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:
    mbr_partition_table_t data(&ks);

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

data.bootstrap_code() // => get bootstrap code

C++/STL source code to parse MBR (Master Boot Record) partition table

mbr_partition_table.h

#ifndef MBR_PARTITION_TABLE_H_
#define MBR_PARTITION_TABLE_H_

// 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 <vector>

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

/**
 * MBR (Master Boot Record) partition table is a traditional way of
 * MS-DOS to partition larger hard disc drives into distinct
 * partitions.
 * 
 * This table is stored in the end of the boot sector (first sector) of
 * the drive, after the bootstrap code. Original DOS 2.0 specification
 * allowed only 4 partitions per disc, but DOS 3.2 introduced concept
 * of "extended partitions", which work as nested extra "boot records"
 * which are pointed to by original ("primary") partitions in MBR.
 */

class mbr_partition_table_t : public kaitai::kstruct {

public:
    class partition_entry_t;
    class chs_t;

    mbr_partition_table_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent = 0, mbr_partition_table_t* p__root = 0);

private:
    void _read();

public:
    ~mbr_partition_table_t();

    class partition_entry_t : public kaitai::kstruct {

    public:

        partition_entry_t(kaitai::kstream* p__io, mbr_partition_table_t* p__parent = 0, mbr_partition_table_t* p__root = 0);

    private:
        void _read();

    public:
        ~partition_entry_t();

    private:
        uint8_t m_status;
        chs_t* m_chs_start;
        uint8_t m_partition_type;
        chs_t* m_chs_end;
        uint32_t m_lba_start;
        uint32_t m_num_sectors;
        mbr_partition_table_t* m__root;
        mbr_partition_table_t* m__parent;

    public:
        uint8_t status() const { return m_status; }
        chs_t* chs_start() const { return m_chs_start; }
        uint8_t partition_type() const { return m_partition_type; }
        chs_t* chs_end() const { return m_chs_end; }
        uint32_t lba_start() const { return m_lba_start; }
        uint32_t num_sectors() const { return m_num_sectors; }
        mbr_partition_table_t* _root() const { return m__root; }
        mbr_partition_table_t* _parent() const { return m__parent; }
    };

    class chs_t : public kaitai::kstruct {

    public:

        chs_t(kaitai::kstream* p__io, mbr_partition_table_t::partition_entry_t* p__parent = 0, mbr_partition_table_t* p__root = 0);

    private:
        void _read();

    public:
        ~chs_t();

    private:
        bool f_sector;
        int32_t m_sector;

    public:
        int32_t sector();

    private:
        bool f_cylinder;
        int32_t m_cylinder;

    public:
        int32_t cylinder();

    private:
        uint8_t m_head;
        uint8_t m_b2;
        uint8_t m_b3;
        mbr_partition_table_t* m__root;
        mbr_partition_table_t::partition_entry_t* m__parent;

    public:
        uint8_t head() const { return m_head; }
        uint8_t b2() const { return m_b2; }
        uint8_t b3() const { return m_b3; }
        mbr_partition_table_t* _root() const { return m__root; }
        mbr_partition_table_t::partition_entry_t* _parent() const { return m__parent; }
    };

private:
    std::string m_bootstrap_code;
    std::vector<partition_entry_t*>* m_partitions;
    std::string m_boot_signature;
    mbr_partition_table_t* m__root;
    kaitai::kstruct* m__parent;

public:
    std::string bootstrap_code() const { return m_bootstrap_code; }
    std::vector<partition_entry_t*>* partitions() const { return m_partitions; }
    std::string boot_signature() const { return m_boot_signature; }
    mbr_partition_table_t* _root() const { return m__root; }
    kaitai::kstruct* _parent() const { return m__parent; }
};

#endif  // MBR_PARTITION_TABLE_H_

mbr_partition_table.cpp

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

#include "mbr_partition_table.h"



mbr_partition_table_t::mbr_partition_table_t(kaitai::kstream* p__io, kaitai::kstruct* p__parent, mbr_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = this;
    _read();
}

void mbr_partition_table_t::_read() {
    m_bootstrap_code = m__io->read_bytes(446);
    int l_partitions = 4;
    m_partitions = new std::vector<partition_entry_t*>();
    m_partitions->reserve(l_partitions);
    for (int i = 0; i < l_partitions; i++) {
        m_partitions->push_back(new partition_entry_t(m__io, this, m__root));
    }
    m_boot_signature = m__io->ensure_fixed_contents(std::string("\x55\xAA", 2));
}

mbr_partition_table_t::~mbr_partition_table_t() {
    for (std::vector<partition_entry_t*>::iterator it = m_partitions->begin(); it != m_partitions->end(); ++it) {
        delete *it;
    }
    delete m_partitions;
}

mbr_partition_table_t::partition_entry_t::partition_entry_t(kaitai::kstream* p__io, mbr_partition_table_t* p__parent, mbr_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    _read();
}

void mbr_partition_table_t::partition_entry_t::_read() {
    m_status = m__io->read_u1();
    m_chs_start = new chs_t(m__io, this, m__root);
    m_partition_type = m__io->read_u1();
    m_chs_end = new chs_t(m__io, this, m__root);
    m_lba_start = m__io->read_u4le();
    m_num_sectors = m__io->read_u4le();
}

mbr_partition_table_t::partition_entry_t::~partition_entry_t() {
    delete m_chs_start;
    delete m_chs_end;
}

mbr_partition_table_t::chs_t::chs_t(kaitai::kstream* p__io, mbr_partition_table_t::partition_entry_t* p__parent, mbr_partition_table_t* p__root) : kaitai::kstruct(p__io) {
    m__parent = p__parent;
    m__root = p__root;
    f_sector = false;
    f_cylinder = false;
    _read();
}

void mbr_partition_table_t::chs_t::_read() {
    m_head = m__io->read_u1();
    m_b2 = m__io->read_u1();
    m_b3 = m__io->read_u1();
}

mbr_partition_table_t::chs_t::~chs_t() {
}

int32_t mbr_partition_table_t::chs_t::sector() {
    if (f_sector)
        return m_sector;
    m_sector = (b2() & 63);
    f_sector = true;
    return m_sector;
}

int32_t mbr_partition_table_t::chs_t::cylinder() {
    if (f_cylinder)
        return m_cylinder;
    m_cylinder = (b3() + ((b2() & 192) << 2));
    f_cylinder = true;
    return m_cylinder;
}