MBR (Master Boot Record) partition table: C# 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.

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

Runtime library

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

The C# runtime library is available in the NuGet Gallery. Installation instructions can also be found there.

Code

Parse a local file and get structure in memory:

var data = MbrPartitionTable.FromFile("path/to/local/file.bin");

Or parse structure from a byte array:

byte[] someArray = new byte[] { ... };
var data = new MbrPartitionTable(new KaitaiStream(someArray));

After that, one can get various attributes from the structure by accessing properties like:

data.BootstrapCode // => get bootstrap code

C# source code to parse MBR (Master Boot Record) partition table

MbrPartitionTable.cs

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

using System.Collections.Generic;

namespace Kaitai
{

    /// <summary>
    /// 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 &quot;extended partitions&quot;, which work as nested extra &quot;boot records&quot;
    /// which are pointed to by original (&quot;primary&quot;) partitions in MBR.
    /// </summary>
    public partial class MbrPartitionTable : KaitaiStruct
    {
        public static MbrPartitionTable FromFile(string fileName)
        {
            return new MbrPartitionTable(new KaitaiStream(fileName));
        }

        public MbrPartitionTable(KaitaiStream p__io, KaitaiStruct p__parent = null, MbrPartitionTable p__root = null) : base(p__io)
        {
            m_parent = p__parent;
            m_root = p__root ?? this;
            _read();
        }
        private void _read()
        {
            _bootstrapCode = m_io.ReadBytes(446);
            _partitions = new List<PartitionEntry>();
            for (var i = 0; i < 4; i++)
            {
                _partitions.Add(new PartitionEntry(m_io, this, m_root));
            }
            _bootSignature = m_io.ReadBytes(2);
            if (!((KaitaiStream.ByteArrayCompare(BootSignature, new byte[] { 85, 170 }) == 0)))
            {
                throw new ValidationNotEqualError(new byte[] { 85, 170 }, BootSignature, M_Io, "/seq/2");
            }
        }
        public partial class PartitionEntry : KaitaiStruct
        {
            public static PartitionEntry FromFile(string fileName)
            {
                return new PartitionEntry(new KaitaiStream(fileName));
            }

            public PartitionEntry(KaitaiStream p__io, MbrPartitionTable p__parent = null, MbrPartitionTable p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                _read();
            }
            private void _read()
            {
                _status = m_io.ReadU1();
                _chsStart = new Chs(m_io, this, m_root);
                _partitionType = m_io.ReadU1();
                _chsEnd = new Chs(m_io, this, m_root);
                _lbaStart = m_io.ReadU4le();
                _numSectors = m_io.ReadU4le();
            }
            private byte _status;
            private Chs _chsStart;
            private byte _partitionType;
            private Chs _chsEnd;
            private uint _lbaStart;
            private uint _numSectors;
            private MbrPartitionTable m_root;
            private MbrPartitionTable m_parent;
            public byte Status { get { return _status; } }
            public Chs ChsStart { get { return _chsStart; } }
            public byte PartitionType { get { return _partitionType; } }
            public Chs ChsEnd { get { return _chsEnd; } }
            public uint LbaStart { get { return _lbaStart; } }
            public uint NumSectors { get { return _numSectors; } }
            public MbrPartitionTable M_Root { get { return m_root; } }
            public MbrPartitionTable M_Parent { get { return m_parent; } }
        }
        public partial class Chs : KaitaiStruct
        {
            public static Chs FromFile(string fileName)
            {
                return new Chs(new KaitaiStream(fileName));
            }

            public Chs(KaitaiStream p__io, MbrPartitionTable.PartitionEntry p__parent = null, MbrPartitionTable p__root = null) : base(p__io)
            {
                m_parent = p__parent;
                m_root = p__root;
                f_sector = false;
                f_cylinder = false;
                _read();
            }
            private void _read()
            {
                _head = m_io.ReadU1();
                _b2 = m_io.ReadU1();
                _b3 = m_io.ReadU1();
            }
            private bool f_sector;
            private int _sector;
            public int Sector
            {
                get
                {
                    if (f_sector)
                        return _sector;
                    _sector = (int) ((B2 & 63));
                    f_sector = true;
                    return _sector;
                }
            }
            private bool f_cylinder;
            private int _cylinder;
            public int Cylinder
            {
                get
                {
                    if (f_cylinder)
                        return _cylinder;
                    _cylinder = (int) ((B3 + ((B2 & 192) << 2)));
                    f_cylinder = true;
                    return _cylinder;
                }
            }
            private byte _head;
            private byte _b2;
            private byte _b3;
            private MbrPartitionTable m_root;
            private MbrPartitionTable.PartitionEntry m_parent;
            public byte Head { get { return _head; } }
            public byte B2 { get { return _b2; } }
            public byte B3 { get { return _b3; } }
            public MbrPartitionTable M_Root { get { return m_root; } }
            public MbrPartitionTable.PartitionEntry M_Parent { get { return m_parent; } }
        }
        private byte[] _bootstrapCode;
        private List<PartitionEntry> _partitions;
        private byte[] _bootSignature;
        private MbrPartitionTable m_root;
        private KaitaiStruct m_parent;
        public byte[] BootstrapCode { get { return _bootstrapCode; } }
        public List<PartitionEntry> Partitions { get { return _partitions; } }
        public byte[] BootSignature { get { return _bootSignature; } }
        public MbrPartitionTable M_Root { get { return m_root; } }
        public KaitaiStruct M_Parent { get { return m_parent; } }
    }
}