def read_mbr(image):
"""Read an MBR with ctypes and return it. Not for general use. Works
with the MBRs in the Raspbian images we test, not tested with anything
else. Mostly used as a fun second opinion to parted which is used in
the tool under testing.
"""
class Partition(LittleEndianStructure):
"""https://en.wikipedia.org/wiki/Master_boot_record#Partition_table_entries"""
SECTOR_SIZE = 512
_pack_ = 1
_fields_ = [("status", c_ubyte),
("chs_begin", c_ubyte * 3),
("type", c_ubyte),
("chs_end", c_ubyte * 3),
("lba_begin", c_uint),
("lba_size", c_uint),
]
@property
def begin(self):
"""Convenience function for returning begin in bytes."""
return self.lba_begin * self.SECTOR_SIZE
@property
def size(self):
"""Convenience function for returning size in bytes."""
return self.lba_size * self.SECTOR_SIZE
assert sizeof(Partition) == 16, "Partition definition error"
class MBR(LittleEndianStructure):
"""https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout"""
_pack_ = 1
_fields_ = [("skip", c_ubyte * 446),
("partitions", Partition * 4),
("signature", c_ubyte * 2),
]
assert sizeof(MBR) == 512, "MBR definition error"
with open(image, "rb") as img:
mbr = MBR.from_buffer(bytearray(img.read(sizeof(MBR))))
assert bytes(mbr.signature) == b"\x55\xAA", "Invalid MBR signature."
return mbr