Source code for nobodd.mbr

# nobodd: a boot configuration tool for the Raspberry Pi
#
# Copyright (c) 2023-2024 Dave Jones <dave.jones@canonical.com>
# Copyright (c) 2023-2024 Canonical Ltd.
#
# SPDX-License-Identifier: GPL-3.0

import struct
from collections import namedtuple

from .tools import labels, formats


# Structures sourced from the Wikipedia page on the Master Boot Record [1],
# specifically the "structure of a classic generic MBR". We don't bother with
# of the later more complicated variants because the only thing we care about
# is the four primary partitions anyway.
#
# [1]: https://en.wikipedia.org/wiki/Master_boot_record

MBR_HEADER = """
218x  bootstrap_code
H     zero
B     physical_drive
B     seconds
B     minutes
B     hours
216x  bootstrap_code
I     disk_sig
H     copy_protect
16s   partition_1
16s   partition_2
16s   partition_3
16s   partition_4
H     boot_sig
"""

[docs] class MBRHeader(namedtuple('MBRHeader', labels(MBR_HEADER))): """ A :func:`~collections.namedtuple` representing the fields of the `MBR header`_. .. _MBR header: https://en.wikipedia.org/wiki/Master_boot_record#Sector_layout """ __slots__ = () _FORMAT = struct.Struct(formats(MBR_HEADER)) def __bytes__(self): return self._FORMAT.pack(*self)
[docs] @classmethod def from_bytes(cls, s): """ Construct a :class:`MBRHeader` from the byte-string *s*. """ return cls(*cls._FORMAT.unpack(s))
[docs] @classmethod def from_buffer(cls, buf, offset=0): """ Construct a :class:`MBRHeader` from the specified *offset* (which defaults to 0) in the buffer protocol object, *buf*. """ return cls(*cls._FORMAT.unpack_from(buf, offset))
@property def partitions(self): """ Returns a sequence of the partitions defined by the header. This is always 4 elements long, and not all elements are guaranteed to be valid, or in order on the disk. """ return ( self.partition_1, self.partition_2, self.partition_3, self.partition_4, )
MBR_PARTITION = """ B status 3s first_chs B part_type 3s last_chs I first_lba I part_size """
[docs] class MBRPartition(namedtuple('MBRPartition', labels(MBR_PARTITION))): """ A :func:`~collections.namedtuple` representing the fields of an `MBR partition entry`_. .. _MBR partition entry: https://en.wikipedia.org/wiki/Master_boot_record#Partition_table_entries """ __slots__ = () _FORMAT = struct.Struct(formats(MBR_PARTITION)) def __bytes__(self): return self._FORMAT.pack(*self)
[docs] @classmethod def from_bytes(cls, s): """ Construct a :class:`MBRPartition` from the byte-string *s*. """ return cls(*cls._FORMAT.unpack(s))
[docs] @classmethod def from_buffer(cls, buf, offset=0): """ Construct a :class:`MBRPartition` from the specified *offset* (which defaults to 0) in the buffer protocol object, *buf*. """ return cls(*cls._FORMAT.unpack_from(buf, offset))