Skip to main content

hadris_part/
mbr.rs

1//! MBR (Master Boot Record) partition table types.
2//!
3//! This module provides types for working with MBR partition tables, including:
4//! - CHS (Cylinder-Head-Sector) addressing
5//! - MBR partition entries
6//! - MBR partition table (4 primary partitions)
7//! - Partition type definitions
8
9use core::fmt::Debug;
10use core::ops::{Index, IndexMut};
11
12use endian_num::Le;
13
14/// A simplified enum for common MBR partition types.
15///
16/// For a complete list of partition types, see [`MbrPartitionTypeFull`].
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum MbrPartitionType {
19    /// An unused partition-table entry.
20    Empty,
21    /// A FAT12 partition.
22    Fat12,
23    /// A FAT16 partition.
24    Fat16,
25    /// A legacy extended partition.
26    Extended,
27    /// A FAT16 partition addressed through LBA extensions.
28    Fat16Lba,
29    /// An NTFS or other installable-file-system partition.
30    Ntfs,
31    /// A FAT32 partition.
32    Fat32,
33    /// A FAT32 partition addressed through LBA extensions.
34    Fat32Lba,
35    /// An extended partition addressed through LBA extensions.
36    ExtendedLba,
37    /// An ISO9660 filesystem or hidden NTFS partition.
38    Iso9660,
39    /// A Linux swap partition.
40    LinuxSwap,
41    /// A native Linux filesystem partition.
42    LinuxNative,
43    /// A Linux Logical Volume Manager partition.
44    LinuxLvm,
45    /// A Linux software RAID partition.
46    LinuxRaid,
47    /// A GPT protective MBR entry.
48    ProtectiveMbr,
49    /// An EFI System Partition.
50    EfiSystemPartition,
51    /// A partition type not represented by a named variant.
52    Unknown(u8),
53}
54
55impl MbrPartitionType {
56    /// Create a `MbrPartitionType` from a raw byte value.
57    pub const fn from_u8(value: u8) -> Self {
58        match value {
59            0x00 => Self::Empty,
60            0x01 => Self::Fat12,
61            0x04 => Self::Fat16,
62            0x05 => Self::Extended,
63            0x06 => Self::Fat16Lba,
64            0x07 => Self::Ntfs,
65            0x0b => Self::Fat32,
66            0x0c => Self::Fat32Lba,
67            0x0f => Self::ExtendedLba,
68            0x17 => Self::Iso9660,
69            0x82 => Self::LinuxSwap,
70            0x83 => Self::LinuxNative,
71            0x8E => Self::LinuxLvm,
72            0xFD => Self::LinuxRaid,
73            0xEE => Self::ProtectiveMbr,
74            0xEF => Self::EfiSystemPartition,
75            _ => Self::Unknown(value),
76        }
77    }
78
79    /// Convert this partition type to its raw byte value.
80    pub const fn to_u8(&self) -> u8 {
81        match self {
82            Self::Empty => 0x00,
83            Self::Fat12 => 0x01,
84            Self::Fat16 => 0x04,
85            Self::Extended => 0x05,
86            Self::Fat16Lba => 0x06,
87            Self::Ntfs => 0x07,
88            Self::Fat32 => 0x0b,
89            Self::Fat32Lba => 0x0c,
90            Self::ExtendedLba => 0x0f,
91            Self::Iso9660 => 0x17,
92            Self::LinuxSwap => 0x82,
93            Self::LinuxNative => 0x83,
94            Self::LinuxLvm => 0x8E,
95            Self::LinuxRaid => 0xFD,
96            Self::ProtectiveMbr => 0xEE,
97            Self::EfiSystemPartition => 0xEF,
98            Self::Unknown(value) => *value,
99        }
100    }
101
102    /// Returns whether this partition type represents an empty/unused partition.
103    pub const fn is_empty(&self) -> bool {
104        matches!(self, Self::Empty)
105    }
106
107    /// Returns whether this is a protective MBR (used for GPT disks).
108    pub const fn is_protective(&self) -> bool {
109        matches!(self, Self::ProtectiveMbr)
110    }
111}
112
113impl core::fmt::Display for MbrPartitionType {
114    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115        match self {
116            Self::Empty => write!(f, "Empty"),
117            Self::Fat12 => write!(f, "FAT12"),
118            Self::Fat16 => write!(f, "FAT16"),
119            Self::Extended => write!(f, "Extended"),
120            Self::Fat16Lba => write!(f, "FAT16 LBA"),
121            Self::Ntfs => write!(f, "NTFS"),
122            Self::Fat32 => write!(f, "FAT32"),
123            Self::Fat32Lba => write!(f, "FAT32 LBA"),
124            Self::ExtendedLba => write!(f, "Extended LBA"),
125            Self::Iso9660 => write!(f, "ISO 9660"),
126            Self::LinuxSwap => write!(f, "Linux swap"),
127            Self::LinuxNative => write!(f, "Linux"),
128            Self::LinuxLvm => write!(f, "Linux LVM"),
129            Self::LinuxRaid => write!(f, "Linux RAID"),
130            Self::ProtectiveMbr => write!(f, "GPT Protective"),
131            Self::EfiSystemPartition => write!(f, "EFI System"),
132            Self::Unknown(id) => write!(f, "Unknown (0x{id:02X})"),
133        }
134    }
135}
136
137/// A 3-byte CHS (Cylinder-Head-Sector) address.
138///
139/// CHS addressing is largely obsolete but is still required for MBR compatibility.
140/// Modern systems use LBA addressing, and values exceeding the CHS limit (approximately
141/// 8GB with 255 heads, 63 sectors, and 1024 cylinders) are represented as 0xFF, 0xFF, 0xFF.
142#[repr(transparent)]
143#[derive(Clone, Copy, PartialEq, Eq, bytemuck::Pod, bytemuck::Zeroable)]
144pub struct Chs([u8; 3]);
145
146impl Debug for Chs {
147    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
148        f.debug_struct("Chs")
149            .field("c", &self.cylinder())
150            .field("h", &self.head())
151            .field("s", &self.sector())
152            .finish()
153    }
154}
155
156impl Default for Chs {
157    fn default() -> Self {
158        Self::new(0)
159    }
160}
161
162impl Chs {
163    /// The CHS value representing "out of range" (beyond CHS addressing limits).
164    pub const OUT_OF_RANGE: Chs = Chs([0xFF, 0xFF, 0xFF]);
165
166    /// Standard sectors per track for CHS calculations.
167    const SECTORS_PER_TRACK: u32 = 63;
168    /// Standard heads per cylinder for CHS calculations.
169    const HEADS_PER_CYLINDER: u32 = 255;
170
171    /// Creates a new CHS value from an LBA address (assuming 512-byte sectors).
172    ///
173    /// If the LBA exceeds the CHS addressing limit (approximately 8GB),
174    /// returns [`Chs::OUT_OF_RANGE`].
175    pub const fn new(lba: u32) -> Self {
176        let cylinder = lba / (Self::SECTORS_PER_TRACK * Self::HEADS_PER_CYLINDER);
177        if cylinder > 0x03FF {
178            return Self::OUT_OF_RANGE;
179        }
180        let tmp = lba % (Self::SECTORS_PER_TRACK * Self::HEADS_PER_CYLINDER);
181        let head = tmp / Self::SECTORS_PER_TRACK;
182        let sector = tmp % Self::SECTORS_PER_TRACK + 1;
183        // Sector must fit in 6 bits (0-63)
184        assert!(
185            sector <= 0b00111111,
186            "Sector overflow, this should never happen"
187        );
188        Self([
189            (head & 0x00ff) as u8,
190            (sector & 0b00111111) as u8 | ((cylinder & 0x0300) >> 2) as u8,
191            (cylinder & 0xFF) as u8,
192        ])
193    }
194
195    /// Returns the head component (0-255).
196    pub const fn head(&self) -> u8 {
197        self.0[0]
198    }
199
200    /// Returns the sector component (1-63).
201    pub const fn sector(&self) -> u8 {
202        self.0[1] & 0b00111111
203    }
204
205    /// Returns the cylinder component (0-1023).
206    pub const fn cylinder(&self) -> u16 {
207        ((self.0[1] as u16 & 0b11000000) << 2) | (self.0[2] as u16)
208    }
209
210    /// Converts this CHS address to an LBA address.
211    ///
212    /// Returns `u32::MAX` for out-of-range CHS values, and for invalid values
213    /// with a sector component of 0 (CHS sectors are 1-based).
214    pub const fn as_lba(&self) -> u32 {
215        if self.0[0] == 0xFF && self.0[1] == 0xFF && self.0[2] == 0xFF {
216            return u32::MAX;
217        }
218        if self.sector() == 0 {
219            return u32::MAX;
220        }
221
222        self.cylinder() as u32 * Self::SECTORS_PER_TRACK * Self::HEADS_PER_CYLINDER
223            + self.head() as u32 * Self::SECTORS_PER_TRACK
224            + self.sector() as u32
225            - 1
226    }
227}
228
229/// An MBR partition entry (16 bytes).
230#[repr(C)]
231#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
232pub struct MbrPartition {
233    /// Boot indicator: 0x00 = non-bootable, 0x80 = bootable.
234    pub boot_indicator: u8,
235    /// Starting CHS address.
236    pub start_chs: Chs,
237    /// Partition type code.
238    pub part_type: u8,
239    /// Ending CHS address.
240    pub end_chs: Chs,
241    /// Starting LBA (sector number), little-endian on disk.
242    pub start_lba: Le<u32>,
243    /// Number of sectors in this partition, little-endian on disk.
244    pub sector_count: Le<u32>,
245}
246
247impl Default for MbrPartition {
248    fn default() -> Self {
249        Self {
250            boot_indicator: 0x00,
251            start_chs: Chs::new(0),
252            part_type: 0x00,
253            end_chs: Chs::new(0),
254            start_lba: Le::<u32>::from_ne(0),
255            sector_count: Le::<u32>::from_ne(0),
256        }
257    }
258}
259
260impl MbrPartition {
261    /// Creates a new MBR partition entry.
262    pub const fn new(part_type: MbrPartitionType, start_lba: u32, sector_count: u32) -> Self {
263        let end_lba = if sector_count > 0 {
264            start_lba.saturating_add(sector_count - 1)
265        } else {
266            start_lba
267        };
268        Self {
269            boot_indicator: 0x00,
270            start_chs: Chs::new(start_lba),
271            part_type: part_type.to_u8(),
272            end_chs: Chs::new(end_lba),
273            start_lba: Le::<u32>::from_ne(start_lba),
274            sector_count: Le::<u32>::from_ne(sector_count),
275        }
276    }
277
278    /// Creates a protective MBR partition entry for GPT disks.
279    ///
280    /// The protective MBR covers the entire disk (or up to the 32-bit limit).
281    pub const fn protective(disk_sectors: u64) -> Self {
282        // Protective MBR starts at LBA 1 and covers the entire disk
283        // (or 0xFFFFFFFF if disk is larger than 32-bit can represent)
284        let size = if disk_sectors > 0xFFFFFFFF {
285            0xFFFFFFFF
286        } else if disk_sectors > 1 {
287            (disk_sectors - 1) as u32
288        } else {
289            1
290        };
291        Self::new(MbrPartitionType::ProtectiveMbr, 1, size)
292    }
293
294    /// Returns whether this partition entry is empty (unused).
295    pub const fn is_empty(&self) -> bool {
296        self.part_type == 0x00
297    }
298
299    /// Returns the partition type.
300    pub const fn partition_type(&self) -> MbrPartitionType {
301        MbrPartitionType::from_u8(self.part_type)
302    }
303
304    /// Returns whether this partition is marked as bootable.
305    pub const fn is_bootable(&self) -> bool {
306        self.boot_indicator == 0x80
307    }
308
309    /// Sets this partition as bootable or non-bootable.
310    pub fn set_bootable(&mut self, bootable: bool) {
311        self.boot_indicator = if bootable { 0x80 } else { 0x00 };
312    }
313
314    /// Returns the ending LBA (inclusive).
315    ///
316    /// Saturates to `u32::MAX`: `start_lba` and `sector_count` come straight
317    /// from the on-disk entry, so their sum can exceed `u32::MAX` on a
318    /// corrupt image.
319    pub const fn end_lba(&self) -> u32 {
320        let start = self.start_lba.to_ne();
321        let count = self.sector_count.to_ne();
322        if count == 0 {
323            start
324        } else {
325            start.saturating_add(count - 1)
326        }
327    }
328}
329
330/// The MBR partition table (4 primary partition entries).
331#[repr(transparent)]
332#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
333pub struct MbrPartitionTable {
334    /// The four primary partition entries.
335    pub partitions: [MbrPartition; 4],
336}
337
338impl Default for MbrPartitionTable {
339    fn default() -> Self {
340        Self::new()
341    }
342}
343
344impl Debug for MbrPartitionTable {
345    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
346        let non_empty: usize = self.partitions.iter().filter(|p| !p.is_empty()).count();
347        f.debug_struct("MbrPartitionTable")
348            .field("partitions", &&self.partitions[..non_empty])
349            .finish()
350    }
351}
352
353impl MbrPartitionTable {
354    /// A zeroed (empty) MBR partition table entry.
355    const EMPTY_PARTITION: MbrPartition = MbrPartition {
356        boot_indicator: 0,
357        start_chs: Chs([0, 0, 0]),
358        part_type: 0,
359        end_chs: Chs([0, 0, 0]),
360        start_lba: Le::<u32>::from_ne(0),
361        sector_count: Le::<u32>::from_ne(0),
362    };
363
364    /// Creates a new empty MBR partition table.
365    pub const fn new() -> Self {
366        Self {
367            partitions: [Self::EMPTY_PARTITION; 4],
368        }
369    }
370
371    /// Creates a protective MBR partition table for GPT disks.
372    ///
373    /// This creates a single partition entry covering the entire disk,
374    /// with type 0xEE (GPT Protective).
375    pub const fn protective(disk_sectors: u64) -> Self {
376        let mut table = Self::new();
377        table.partitions[0] = MbrPartition::protective(disk_sectors);
378        table
379    }
380
381    /// Returns the number of non-empty partition entries.
382    pub fn count(&self) -> usize {
383        self.partitions.iter().filter(|p| !p.is_empty()).count()
384    }
385
386    /// Returns whether this appears to be a valid MBR partition table.
387    ///
388    /// Checks that boot indicators are valid (0x00 or 0x80).
389    pub fn is_valid(&self) -> bool {
390        for partition in &self.partitions {
391            // Boot indicator must be 0x00 or 0x80
392            if (partition.boot_indicator & !0x80) != 0 {
393                return false;
394            }
395        }
396        true
397    }
398
399    /// Returns whether this is a protective MBR (indicating a GPT disk).
400    pub fn is_protective(&self) -> bool {
401        !self.partitions[0].is_empty() && self.partitions[0].partition_type().is_protective()
402    }
403
404    /// Returns an iterator over non-empty partitions.
405    pub fn iter(&self) -> impl Iterator<Item = &MbrPartition> {
406        self.partitions.iter().filter(|p| !p.is_empty())
407    }
408
409    /// Returns a mutable iterator over all partition slots.
410    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut MbrPartition> {
411        self.partitions.iter_mut()
412    }
413}
414
415impl Index<usize> for MbrPartitionTable {
416    type Output = MbrPartition;
417
418    fn index(&self, index: usize) -> &Self::Output {
419        &self.partitions[index]
420    }
421}
422
423impl IndexMut<usize> for MbrPartitionTable {
424    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
425        &mut self.partitions[index]
426    }
427}
428
429/// The complete Master Boot Record structure (512 bytes).
430///
431/// @hadris-spec MBR:layout
432/// @hadris-compliance unknown
433/// @hadris-tests roundtrip::mbr_write_read_roundtrip
434#[repr(C, packed)]
435#[derive(Clone, Copy)]
436pub struct MasterBootRecord {
437    /// Bootstrap code area (446 bytes).
438    pub bootstrap: [u8; 446],
439    /// Partition table (64 bytes - 4 entries of 16 bytes each).
440    pub partition_table: MbrPartitionTable,
441    /// Boot signature (must be 0x55, 0xAA).
442    pub signature: [u8; 2],
443}
444
445// SAFETY: MasterBootRecord is #[repr(C, packed)] with 512 bytes total,
446// containing only byte arrays and MbrPartitionTable (which is Pod).
447// All bit patterns are valid.
448unsafe impl bytemuck::Pod for MasterBootRecord {}
449unsafe impl bytemuck::Zeroable for MasterBootRecord {}
450
451impl Default for MasterBootRecord {
452    fn default() -> Self {
453        Self {
454            bootstrap: [0; 446],
455            partition_table: MbrPartitionTable::default(),
456            signature: [0x55, 0xAA],
457        }
458    }
459}
460
461impl MasterBootRecord {
462    /// The required boot signature bytes.
463    pub const SIGNATURE: [u8; 2] = [0x55, 0xAA];
464
465    /// Creates a new MBR with the given partition table.
466    pub const fn new(partition_table: MbrPartitionTable) -> Self {
467        Self {
468            bootstrap: [0; 446],
469            partition_table,
470            signature: Self::SIGNATURE,
471        }
472    }
473
474    /// Creates a protective MBR for GPT disks.
475    pub const fn protective(disk_sectors: u64) -> Self {
476        Self::new(MbrPartitionTable::protective(disk_sectors))
477    }
478
479    /// Returns whether this MBR has a valid boot signature.
480    pub const fn has_valid_signature(&self) -> bool {
481        self.signature[0] == 0x55 && self.signature[1] == 0xAA
482    }
483
484    /// Returns a copy of the partition table.
485    ///
486    /// This method exists because the struct is packed and direct field access
487    /// would create a misaligned reference.
488    pub fn get_partition_table(&self) -> MbrPartitionTable {
489        // Copy the partition table to avoid alignment issues
490        self.partition_table
491    }
492
493    /// Sets the partition table.
494    ///
495    /// This method exists because the struct is packed and direct field access
496    /// would create a misaligned reference.
497    pub fn set_partition_table(&mut self, table: MbrPartitionTable) {
498        self.partition_table = table;
499    }
500
501    /// Modifies the partition table using a closure.
502    ///
503    /// This is a convenience method that gets the partition table, allows
504    /// modification via a closure, and sets it back.
505    pub fn with_partition_table<F>(&mut self, f: F)
506    where
507        F: FnOnce(&mut MbrPartitionTable),
508    {
509        let mut pt = self.get_partition_table();
510        f(&mut pt);
511        self.set_partition_table(pt);
512    }
513
514    /// Returns whether this MBR is valid (has correct signature and valid partition table).
515    pub fn is_valid(&self) -> bool {
516        let pt = self.get_partition_table();
517        self.has_valid_signature() && pt.is_valid()
518    }
519}
520
521impl Debug for MasterBootRecord {
522    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
523        let pt = self.get_partition_table();
524        f.debug_struct("MasterBootRecord")
525            .field("partition_table", &pt)
526            .field(
527                "signature",
528                &format_args!("0x{:02X}{:02X}", self.signature[0], self.signature[1]),
529            )
530            .finish()
531    }
532}
533
534/// An enum representing the full list of MBR partition types.
535///
536/// Based on the comprehensive list at <https://thestarman.pcministry.com/asm/mbr/PartTypes.htm>
537/// For a simpler interface, use [`MbrPartitionType`].
538#[repr(u8)]
539#[derive(Debug, Clone, Copy, PartialEq, Eq)]
540pub enum MbrPartitionTypeFull {
541    /// Empty partition
542    Empty = 0x00,
543    /// FAT12 partition
544    Fat12 = 0x01,
545    /// XENIX root partition
546    XenixRoot = 0x02,
547    /// XENIX /usr partition (obsolete)
548    XenixUsr = 0x03,
549    /// FAT16 partition (less than 32M)
550    Fat16S = 0x04,
551    /// Extended partition
552    Extended = 0x05,
553    /// FAT16 partition (more than 32M)
554    Fat16L = 0x06,
555    /// Installable file systems (HPFS, NTFS)
556    Installable = 0x07,
557    /// AIX bootable partition
558    AixBoot = 0x08,
559    /// AIX data partition
560    AixData = 0x09,
561    /// OS/2 Boot Manager partition
562    Os2Boot = 0x0A,
563    /// FAT32 partition
564    Fat32 = 0x0B,
565    /// FAT32 partition (using int13 extensions)
566    Fat32Lba = 0x0C,
567    /// Legacy MBR partition type `Reserved0D` (0x0D).
568    Reserved0D = 0x0D,
569    /// FAT16 partition (using int13 extensions)
570    Fat16Lba = 0x0E,
571    /// Extended partition (using int13 extensions)
572    ExtendedLba = 0x0F,
573    /// Legacy MBR partition type `Opus` (0x10).
574    Opus = 0x10,
575    /// Legacy MBR partition type `HiddenFat12` (0x11).
576    HiddenFat12 = 0x11,
577    /// Legacy MBR partition type `CompaqDiagnosis` (0x12).
578    CompaqDiagnosis = 0x12,
579    /// Legacy MBR partition type `Reserved13` (0x13).
580    Reserved13 = 0x13,
581    /// Legacy MBR partition type `HiddenFat16S` (0x14).
582    HiddenFat16S = 0x14,
583    /// Legacy MBR partition type `Reserved15` (0x15).
584    Reserved15 = 0x15,
585    /// Legacy MBR partition type `HiddenFat16L` (0x16).
586    HiddenFat16L = 0x16,
587    /// Hidden IFS (HPFS, NTFS) / ISO9660
588    HiddenIfs = 0x17,
589    /// Legacy MBR partition type `AstWindowsSwap` (0x18).
590    AstWindowsSwap = 0x18,
591    /// Legacy MBR partition type `WillowtechPhotonCos` (0x19).
592    WillowtechPhotonCos = 0x19,
593    /// Legacy MBR partition type `Reserved1A` (0x1A).
594    Reserved1A = 0x1A,
595    /// Legacy MBR partition type `HiddenFat32` (0x1B).
596    HiddenFat32 = 0x1B,
597    /// Legacy MBR partition type `HiddenFat32Lba` (0x1C).
598    HiddenFat32Lba = 0x1C,
599    /// Legacy MBR partition type `Reserved1D` (0x1D).
600    Reserved1D = 0x1D,
601    /// Legacy MBR partition type `HiddenFat16Lba` (0x1E).
602    HiddenFat16Lba = 0x1E,
603    /// Legacy MBR partition type `Reserved1F` (0x1F).
604    Reserved1F = 0x1F,
605    /// Willowsoft Overture File System
606    Ofs1 = 0x20,
607    /// Legacy MBR partition type `Reserved21` (0x21).
608    Reserved21 = 0x21,
609    /// Legacy MBR partition type `OxygenExt` (0x22).
610    OxygenExt = 0x22,
611    /// Legacy MBR partition type `Reserved23` (0x23).
612    Reserved23 = 0x23,
613    /// Legacy MBR partition type `NecMsDos` (0x24).
614    NecMsDos = 0x24,
615    /// Legacy MBR partition type `Reserved25` (0x25).
616    Reserved25 = 0x25,
617    /// Legacy MBR partition type `Reserved26` (0x26).
618    Reserved26 = 0x26,
619    /// Legacy MBR partition type `Reserved27` (0x27).
620    Reserved27 = 0x27,
621    /// Legacy MBR partition type `Reserved28` (0x28).
622    Reserved28 = 0x28,
623    /// Legacy MBR partition type `Reserved29` (0x29).
624    Reserved29 = 0x29,
625    /// Legacy MBR partition type `Reserved2A` (0x2A).
626    Reserved2A = 0x2A,
627    /// Legacy MBR partition type `Reserved2B` (0x2B).
628    Reserved2B = 0x2B,
629    /// Legacy MBR partition type `Reserved2C` (0x2C).
630    Reserved2C = 0x2C,
631    /// Legacy MBR partition type `Reserved2D` (0x2D).
632    Reserved2D = 0x2D,
633    /// Legacy MBR partition type `Reserved2E` (0x2E).
634    Reserved2E = 0x2E,
635    /// Legacy MBR partition type `Reserved2F` (0x2F).
636    Reserved2F = 0x2F,
637    /// Legacy MBR partition type `Reserved30` (0x30).
638    Reserved30 = 0x30,
639    /// Legacy MBR partition type `Reserved31` (0x31).
640    Reserved31 = 0x31,
641    /// Legacy MBR partition type `Reserved32` (0x32).
642    Reserved32 = 0x32,
643    /// Legacy MBR partition type `Reserved33` (0x33).
644    Reserved33 = 0x33,
645    /// Legacy MBR partition type `Reserved34` (0x34).
646    Reserved34 = 0x34,
647    /// Legacy MBR partition type `Reserved35` (0x35).
648    Reserved35 = 0x35,
649    /// Legacy MBR partition type `Reserved36` (0x36).
650    Reserved36 = 0x36,
651    /// Legacy MBR partition type `Reserved37` (0x37).
652    Reserved37 = 0x37,
653    /// Legacy MBR partition type `Theos` (0x38).
654    Theos = 0x38,
655    /// Legacy MBR partition type `Reserved39` (0x39).
656    Reserved39 = 0x39,
657    /// Legacy MBR partition type `Reserved3A` (0x3A).
658    Reserved3A = 0x3A,
659    /// Legacy MBR partition type `Reserved3B` (0x3B).
660    Reserved3B = 0x3B,
661    /// Legacy MBR partition type `PowerQuestFiles` (0x3C).
662    PowerQuestFiles = 0x3C,
663    /// Legacy MBR partition type `HiddenNetWare` (0x3D).
664    HiddenNetWare = 0x3D,
665    /// Legacy MBR partition type `Reserved3E` (0x3E).
666    Reserved3E = 0x3E,
667    /// Legacy MBR partition type `Reserved3F` (0x3F).
668    Reserved3F = 0x3F,
669    /// Legacy MBR partition type `Venix80286` (0x40).
670    Venix80286 = 0x40,
671    /// Legacy MBR partition type `PpcBoot` (0x41).
672    PpcBoot = 0x41,
673    /// Legacy MBR partition type `SecureFileSystem` (0x42).
674    SecureFileSystem = 0x42,
675    /// Legacy MBR partition type `AltExt2Fs` (0x43).
676    AltExt2Fs = 0x43,
677    /// Legacy MBR partition type `Reserved44` (0x44).
678    Reserved44 = 0x44,
679    /// Legacy MBR partition type `Priam` (0x45).
680    Priam = 0x45,
681    /// Legacy MBR partition type `EumelElan46` (0x46).
682    EumelElan46 = 0x46,
683    /// Legacy MBR partition type `EumelElan47` (0x47).
684    EumelElan47 = 0x47,
685    /// Legacy MBR partition type `EumelElan48` (0x48).
686    EumelElan48 = 0x48,
687    /// Legacy MBR partition type `Reserved49` (0x49).
688    Reserved49 = 0x49,
689    /// Legacy MBR partition type `Alfs` (0x4A).
690    Alfs = 0x4A,
691    /// Legacy MBR partition type `Reserved4B` (0x4B).
692    Reserved4B = 0x4B,
693    /// Legacy MBR partition type `Reserved4C` (0x4C).
694    Reserved4C = 0x4C,
695    /// Legacy MBR partition type `Qnx4D` (0x4D).
696    Qnx4D = 0x4D,
697    /// Legacy MBR partition type `Qnx4E` (0x4E).
698    Qnx4E = 0x4E,
699    /// Legacy MBR partition type `Qnx4F` (0x4F).
700    Qnx4F = 0x4F,
701    /// Legacy MBR partition type `OdmReadOnly` (0x50).
702    OdmReadOnly = 0x50,
703    /// Legacy MBR partition type `OdmReadWrite` (0x51).
704    OdmReadWrite = 0x51,
705    /// Legacy MBR partition type `CPM` (0x52).
706    CPM = 0x52,
707    /// Legacy MBR partition type `OdmWriteOnly` (0x53).
708    OdmWriteOnly = 0x53,
709    /// Legacy MBR partition type `Odm6` (0x54).
710    Odm6 = 0x54,
711    /// Legacy MBR partition type `EzDrive` (0x55).
712    EzDrive = 0x55,
713    /// Legacy MBR partition type `GoldenBow` (0x56).
714    GoldenBow = 0x56,
715    /// Legacy MBR partition type `Reserved57` (0x57).
716    Reserved57 = 0x57,
717    /// Legacy MBR partition type `Reserved58` (0x58).
718    Reserved58 = 0x58,
719    /// Legacy MBR partition type `Reserved59` (0x59).
720    Reserved59 = 0x59,
721    /// Legacy MBR partition type `Reserved5A` (0x5A).
722    Reserved5A = 0x5A,
723    /// Legacy MBR partition type `Reserved5B` (0x5B).
724    Reserved5B = 0x5B,
725    /// Legacy MBR partition type `PriamEDisk` (0x5C).
726    PriamEDisk = 0x5C,
727    /// Legacy MBR partition type `Reserved5D` (0x5D).
728    Reserved5D = 0x5D,
729    /// Legacy MBR partition type `Reserved5E` (0x5E).
730    Reserved5E = 0x5E,
731    /// Legacy MBR partition type `Reserved5F` (0x5F).
732    Reserved5F = 0x5F,
733    /// Legacy MBR partition type `Reserved60` (0x60).
734    Reserved60 = 0x60,
735    /// Legacy MBR partition type `StorageDimension1` (0x61).
736    StorageDimension1 = 0x61,
737    /// Legacy MBR partition type `Reserved62` (0x62).
738    Reserved62 = 0x62,
739    /// Legacy MBR partition type `GnuHurd` (0x63).
740    GnuHurd = 0x63,
741    /// Legacy MBR partition type `NovellNetware286` (0x64).
742    NovellNetware286 = 0x64,
743    /// Legacy MBR partition type `NovellNetware311` (0x65).
744    NovellNetware311 = 0x65,
745    /// Legacy MBR partition type `NovellNetware386` (0x66).
746    NovellNetware386 = 0x66,
747    /// Legacy MBR partition type `NovellNetware67` (0x67).
748    NovellNetware67 = 0x67,
749    /// Legacy MBR partition type `NovellNetware68` (0x68).
750    NovellNetware68 = 0x68,
751    /// Legacy MBR partition type `NovellNetware5` (0x69).
752    NovellNetware5 = 0x69,
753    /// Legacy MBR partition type `Reserved6A` (0x6A).
754    Reserved6A = 0x6A,
755    /// Legacy MBR partition type `Reserved6B` (0x6B).
756    Reserved6B = 0x6B,
757    /// Legacy MBR partition type `Reserved6C` (0x6C).
758    Reserved6C = 0x6C,
759    /// Legacy MBR partition type `Reserved6D` (0x6D).
760    Reserved6D = 0x6D,
761    /// Legacy MBR partition type `Reserved6E` (0x6E).
762    Reserved6E = 0x6E,
763    /// Legacy MBR partition type `Reserved6F` (0x6F).
764    Reserved6F = 0x6F,
765    /// Legacy MBR partition type `DiskSecureMultiBoot` (0x70).
766    DiskSecureMultiBoot = 0x70,
767    /// Legacy MBR partition type `Reserved71` (0x71).
768    Reserved71 = 0x71,
769    /// Legacy MBR partition type `Reserved72` (0x72).
770    Reserved72 = 0x72,
771    /// Legacy MBR partition type `Reserved73` (0x73).
772    Reserved73 = 0x73,
773    /// Legacy MBR partition type `Reserved74` (0x74).
774    Reserved74 = 0x74,
775    /// Legacy MBR partition type `IbmPcIx` (0x75).
776    IbmPcIx = 0x75,
777    /// Legacy MBR partition type `Reserved76` (0x76).
778    Reserved76 = 0x76,
779    /// Legacy MBR partition type `Reserved77` (0x77).
780    Reserved77 = 0x77,
781    /// Legacy MBR partition type `Reserved78` (0x78).
782    Reserved78 = 0x78,
783    /// Legacy MBR partition type `Reserved79` (0x79).
784    Reserved79 = 0x79,
785    /// Legacy MBR partition type `Reserved7A` (0x7A).
786    Reserved7A = 0x7A,
787    /// Legacy MBR partition type `Reserved7B` (0x7B).
788    Reserved7B = 0x7B,
789    /// Legacy MBR partition type `Reserved7C` (0x7C).
790    Reserved7C = 0x7C,
791    /// Legacy MBR partition type `Reserved7D` (0x7D).
792    Reserved7D = 0x7D,
793    /// Legacy MBR partition type `Reserved7E` (0x7E).
794    Reserved7E = 0x7E,
795    /// Legacy MBR partition type `Reserved7F` (0x7F).
796    Reserved7F = 0x7F,
797    /// Legacy MBR partition type `OldMinix` (0x80).
798    OldMinix = 0x80,
799    /// Legacy MBR partition type `LinuxMinix` (0x81).
800    LinuxMinix = 0x81,
801    /// Linux Swap partition
802    LinuxSwap = 0x82,
803    /// Linux native file systems (ext2/3/4, etc.)
804    LinuxNative = 0x83,
805    /// Legacy MBR partition type `Os2Hidden` (0x84).
806    Os2Hidden = 0x84,
807    /// Legacy MBR partition type `LinuxExtended` (0x85).
808    LinuxExtended = 0x85,
809    /// Legacy MBR partition type `NtStripeSet` (0x86).
810    NtStripeSet = 0x86,
811    /// Legacy MBR partition type `HpfsFtMirrored` (0x87).
812    HpfsFtMirrored = 0x87,
813    /// Legacy MBR partition type `Reserved88` (0x88).
814    Reserved88 = 0x88,
815    /// Legacy MBR partition type `Reserved89` (0x89).
816    Reserved89 = 0x89,
817    /// Legacy MBR partition type `Reserved8A` (0x8A).
818    Reserved8A = 0x8A,
819    /// Legacy MBR partition type `Reserved8B` (0x8B).
820    Reserved8B = 0x8B,
821    /// Legacy MBR partition type `Reserved8C` (0x8C).
822    Reserved8C = 0x8C,
823    /// Legacy MBR partition type `Reserved8D` (0x8D).
824    Reserved8D = 0x8D,
825    /// Linux LVM
826    LinuxLvm = 0x8E,
827    /// Legacy MBR partition type `Reserved8F` (0x8F).
828    Reserved8F = 0x8F,
829    /// Legacy MBR partition type `Reserved90` (0x90).
830    Reserved90 = 0x90,
831    /// Legacy MBR partition type `Reserved91` (0x91).
832    Reserved91 = 0x91,
833    /// Legacy MBR partition type `Reserved92` (0x92).
834    Reserved92 = 0x92,
835    /// Legacy MBR partition type `HiddenLinuxNative` (0x93).
836    HiddenLinuxNative = 0x93,
837    /// Legacy MBR partition type `AmoebaBadBlockTable` (0x94).
838    AmoebaBadBlockTable = 0x94,
839    /// Legacy MBR partition type `Reserved95` (0x95).
840    Reserved95 = 0x95,
841    /// Legacy MBR partition type `Reserved96` (0x96).
842    Reserved96 = 0x96,
843    /// Legacy MBR partition type `Reserved97` (0x97).
844    Reserved97 = 0x97,
845    /// Legacy MBR partition type `Reserved98` (0x98).
846    Reserved98 = 0x98,
847    /// Legacy MBR partition type `Mylex` (0x99).
848    Mylex = 0x99,
849    /// Legacy MBR partition type `Reserved9A` (0x9A).
850    Reserved9A = 0x9A,
851    /// Legacy MBR partition type `Reserved9B` (0x9B).
852    Reserved9B = 0x9B,
853    /// Legacy MBR partition type `Reserved9C` (0x9C).
854    Reserved9C = 0x9C,
855    /// Legacy MBR partition type `Reserved9D` (0x9D).
856    Reserved9D = 0x9D,
857    /// Legacy MBR partition type `Reserved9E` (0x9E).
858    Reserved9E = 0x9E,
859    /// Legacy MBR partition type `Bsdi` (0x9F).
860    Bsdi = 0x9F,
861    /// Legacy MBR partition type `IbmHibernation` (0xA0).
862    IbmHibernation = 0xA0,
863    /// Legacy MBR partition type `HpVolumeExpA1` (0xA1).
864    HpVolumeExpA1 = 0xA1,
865    /// Legacy MBR partition type `ReservedA2` (0xA2).
866    ReservedA2 = 0xA2,
867    /// Legacy MBR partition type `HpVolumeExpA3` (0xA3).
868    HpVolumeExpA3 = 0xA3,
869    /// Legacy MBR partition type `HpVolumeExpA4` (0xA4).
870    HpVolumeExpA4 = 0xA4,
871    /// Legacy MBR partition type `FreeBsd386` (0xA5).
872    FreeBsd386 = 0xA5,
873    /// Legacy MBR partition type `OpenBsd` (0xA6).
874    OpenBsd = 0xA6,
875    /// Legacy MBR partition type `HpVolumeExpA7` (0xA7).
876    HpVolumeExpA7 = 0xA7,
877    /// Legacy MBR partition type `MacOsX` (0xA8).
878    MacOsX = 0xA8,
879    /// Legacy MBR partition type `NetBsd` (0xA9).
880    NetBsd = 0xA9,
881    /// Legacy MBR partition type `Olivetti` (0xAA).
882    Olivetti = 0xAA,
883    /// Legacy MBR partition type `MacOsXBoot` (0xAB).
884    MacOsXBoot = 0xAB,
885    /// Legacy MBR partition type `ReservedAC` (0xAC).
886    ReservedAC = 0xAC,
887    /// Legacy MBR partition type `ReservedAD` (0xAD).
888    ReservedAD = 0xAD,
889    /// Legacy MBR partition type `ReservedAE` (0xAE).
890    ReservedAE = 0xAE,
891    /// Legacy MBR partition type `MacOsXHfsPlus` (0xAF).
892    MacOsXHfsPlus = 0xAF,
893    /// Legacy MBR partition type `BootMngrBootStar` (0xB0).
894    BootMngrBootStar = 0xB0,
895    /// Legacy MBR partition type `HpVolumeExpB1` (0xB1).
896    HpVolumeExpB1 = 0xB1,
897    /// Legacy MBR partition type `HpVolumeExpB2` (0xB2).
898    HpVolumeExpB2 = 0xB2,
899    /// Legacy MBR partition type `HpVolumeExpB3` (0xB3).
900    HpVolumeExpB3 = 0xB3,
901    /// Legacy MBR partition type `HpVolumeExpB4` (0xB4).
902    HpVolumeExpB4 = 0xB4,
903    /// Legacy MBR partition type `ReservedB5` (0xB5).
904    ReservedB5 = 0xB5,
905    /// Legacy MBR partition type `HpVolumeExpB6` (0xB6).
906    HpVolumeExpB6 = 0xB6,
907    /// Legacy MBR partition type `BsdiFs` (0xB7).
908    BsdiFs = 0xB7,
909    /// Legacy MBR partition type `BsdiSwap` (0xB8).
910    BsdiSwap = 0xB8,
911    /// Legacy MBR partition type `ReservedB9` (0xB9).
912    ReservedB9 = 0xB9,
913    /// Legacy MBR partition type `ReservedBA` (0xBA).
914    ReservedBA = 0xBA,
915    /// Legacy MBR partition type `PtsBootWizard` (0xBB).
916    PtsBootWizard = 0xBB,
917    /// Legacy MBR partition type `AcronisBackup` (0xBC).
918    AcronisBackup = 0xBC,
919    /// Legacy MBR partition type `ReservedBD` (0xBD).
920    ReservedBD = 0xBD,
921    /// Legacy MBR partition type `SolarisBoot` (0xBE).
922    SolarisBoot = 0xBE,
923    /// Legacy MBR partition type `Solaris` (0xBF).
924    Solaris = 0xBF,
925    /// Legacy MBR partition type `NovellDos` (0xC0).
926    NovellDos = 0xC0,
927    /// Legacy MBR partition type `DrDos12` (0xC1).
928    DrDos12 = 0xC1,
929    /// Legacy MBR partition type `ReservedC2` (0xC2).
930    ReservedC2 = 0xC2,
931    /// Legacy MBR partition type `ReservedC3` (0xC3).
932    ReservedC3 = 0xC3,
933    /// Legacy MBR partition type `DrDos16` (0xC4).
934    DrDos16 = 0xC4,
935    /// Legacy MBR partition type `ReservedC5` (0xC5).
936    ReservedC5 = 0xC5,
937    /// Legacy MBR partition type `DrDosHuge` (0xC6).
938    DrDosHuge = 0xC6,
939    /// Legacy MBR partition type `HpfsFtMirroredDisabled` (0xC7).
940    HpfsFtMirroredDisabled = 0xC7,
941    /// Legacy MBR partition type `ReservedC8` (0xC8).
942    ReservedC8 = 0xC8,
943    /// Legacy MBR partition type `ReservedC9` (0xC9).
944    ReservedC9 = 0xC9,
945    /// Legacy MBR partition type `ReservedCA` (0xCA).
946    ReservedCA = 0xCA,
947    /// Legacy MBR partition type `ReservedCB` (0xCB).
948    ReservedCB = 0xCB,
949    /// Legacy MBR partition type `ReservedCC` (0xCC).
950    ReservedCC = 0xCC,
951    /// Legacy MBR partition type `ReservedCD` (0xCD).
952    ReservedCD = 0xCD,
953    /// Legacy MBR partition type `ReservedCE` (0xCE).
954    ReservedCE = 0xCE,
955    /// Legacy MBR partition type `ReservedCF` (0xCF).
956    ReservedCF = 0xCF,
957    /// Legacy MBR partition type `MultiuserDos` (0xD0).
958    MultiuserDos = 0xD0,
959    /// Legacy MBR partition type `OldMultiuserDos` (0xD1).
960    OldMultiuserDos = 0xD1,
961    /// Legacy MBR partition type `ReservedD2` (0xD2).
962    ReservedD2 = 0xD2,
963    /// Legacy MBR partition type `ReservedD3` (0xD3).
964    ReservedD3 = 0xD3,
965    /// Legacy MBR partition type `OldMultiuserDos2` (0xD4).
966    OldMultiuserDos2 = 0xD4,
967    /// Legacy MBR partition type `OldMultiuserDos3` (0xD5).
968    OldMultiuserDos3 = 0xD5,
969    /// Legacy MBR partition type `OldMultiuserDos4` (0xD6).
970    OldMultiuserDos4 = 0xD6,
971    /// Legacy MBR partition type `ReservedD7` (0xD7).
972    ReservedD7 = 0xD7,
973    /// Legacy MBR partition type `Cpm86` (0xD8).
974    Cpm86 = 0xD8,
975    /// Legacy MBR partition type `ReservedD9` (0xD9).
976    ReservedD9 = 0xD9,
977    /// Legacy MBR partition type `ReservedDA` (0xDA).
978    ReservedDA = 0xDA,
979    /// Legacy MBR partition type `Cpm` (0xDB).
980    Cpm = 0xDB,
981    /// Legacy MBR partition type `ReservedDC` (0xDC).
982    ReservedDC = 0xDC,
983    /// Legacy MBR partition type `ReservedDD` (0xDD).
984    ReservedDD = 0xDD,
985    /// Legacy MBR partition type `Dell` (0xDE).
986    Dell = 0xDE,
987    /// Legacy MBR partition type `Embrm` (0xDF).
988    Embrm = 0xDF,
989    /// Legacy MBR partition type `ReservedE0` (0xE0).
990    ReservedE0 = 0xE0,
991    /// Legacy MBR partition type `SpeedStorFat12Ext` (0xE1).
992    SpeedStorFat12Ext = 0xE1,
993    /// Legacy MBR partition type `DosReadOnly` (0xE2).
994    DosReadOnly = 0xE2,
995    /// Legacy MBR partition type `SpeedStor` (0xE3).
996    SpeedStor = 0xE3,
997    /// Legacy MBR partition type `SpeedStor16Ext` (0xE4).
998    SpeedStor16Ext = 0xE4,
999    /// Legacy MBR partition type `ReservedE5` (0xE5).
1000    ReservedE5 = 0xE5,
1001    /// Legacy MBR partition type `StorageDimension2` (0xE6).
1002    StorageDimension2 = 0xE6,
1003    /// Legacy MBR partition type `ReservedE7` (0xE7).
1004    ReservedE7 = 0xE7,
1005    /// Legacy MBR partition type `ReservedE8` (0xE8).
1006    ReservedE8 = 0xE8,
1007    /// Legacy MBR partition type `ReservedE9` (0xE9).
1008    ReservedE9 = 0xE9,
1009    /// Legacy MBR partition type `ReservedEA` (0xEA).
1010    ReservedEA = 0xEA,
1011    /// Legacy MBR partition type `BeOs` (0xEB).
1012    BeOs = 0xEB,
1013    /// Legacy MBR partition type `ReservedEC` (0xEC).
1014    ReservedEC = 0xEC,
1015    /// Legacy MBR partition type `ReservedED` (0xED).
1016    ReservedED = 0xED,
1017    /// GPT Protective MBR
1018    GptProtectiveMbr = 0xEE,
1019    /// EFI System Partition
1020    EfiSystemPartition = 0xEF,
1021    /// Legacy MBR partition type `ReservedF0` (0xF0).
1022    ReservedF0 = 0xF0,
1023    /// Legacy MBR partition type `SpeedStorDimensions` (0xF1).
1024    SpeedStorDimensions = 0xF1,
1025    /// Legacy MBR partition type `UnisysDos` (0xF2).
1026    UnisysDos = 0xF2,
1027    /// Legacy MBR partition type `StorageDimension3` (0xF3).
1028    StorageDimension3 = 0xF3,
1029    /// Legacy MBR partition type `SpeedStorDimensions2` (0xF4).
1030    SpeedStorDimensions2 = 0xF4,
1031    /// Legacy MBR partition type `Prolugue` (0xF5).
1032    Prolugue = 0xF5,
1033    /// Legacy MBR partition type `StorageDimension4` (0xF6).
1034    StorageDimension4 = 0xF6,
1035    /// Legacy MBR partition type `ReservedF7` (0xF7).
1036    ReservedF7 = 0xF7,
1037    /// Legacy MBR partition type `ReservedF8` (0xF8).
1038    ReservedF8 = 0xF8,
1039    /// Legacy MBR partition type `ReservedF9` (0xF9).
1040    ReservedF9 = 0xF9,
1041    /// Legacy MBR partition type `ReservedFA` (0xFA).
1042    ReservedFA = 0xFA,
1043    /// Legacy MBR partition type `ReservedFB` (0xFB).
1044    ReservedFB = 0xFB,
1045    /// Legacy MBR partition type `ReservedFC` (0xFC).
1046    ReservedFC = 0xFC,
1047    /// Linux RAID
1048    LinuxRaid = 0xFD,
1049    /// Legacy MBR partition type `LanStep` (0xFE).
1050    LanStep = 0xFE,
1051    /// Legacy MBR partition type `BadBlockTable` (0xFF).
1052    BadBlockTable = 0xFF,
1053}
1054
1055impl MbrPartitionTypeFull {
1056    /// Create a new [`MbrPartitionTypeFull`] from a raw byte.
1057    ///
1058    /// # Safety
1059    ///
1060    /// This is safe because all 256 possible u8 values are valid enum variants.
1061    pub const fn from_u8(value: u8) -> Self {
1062        // SAFETY: All u8 values are valid variants
1063        unsafe { core::mem::transmute(value) }
1064    }
1065
1066    /// Convert this partition type to its raw byte value.
1067    pub const fn to_u8(&self) -> u8 {
1068        *self as u8
1069    }
1070}
1071
1072#[cfg(test)]
1073mod tests {
1074    use super::*;
1075
1076    #[test]
1077    fn test_chs_create() {
1078        assert_eq!(Chs::new(0), Chs([0, 1, 0]));
1079        assert_eq!(Chs::new(1), Chs([0, 2, 0]));
1080        assert_eq!(Chs::new(62), Chs([0, 63, 0]));
1081        assert_eq!(Chs::new(63), Chs([1, 1, 0]));
1082        assert_eq!(Chs::new(63 * 254), Chs([254, 1, 0]));
1083        assert_eq!(Chs::new(63 * 255), Chs([0, 1, 1]));
1084        assert_eq!(Chs::new(63 * 255 * 255), Chs([0, 1, 255]));
1085        assert_eq!(Chs::new(63 * 255 * 1023), Chs([0, (15 << 6) + 1, 255]));
1086        // Out of range
1087        assert_eq!(Chs::new(63 * 255 * 1024), Chs::OUT_OF_RANGE);
1088    }
1089
1090    #[test]
1091    fn test_chs_get_lba() {
1092        assert_eq!(Chs([0, 1, 0]).as_lba(), 0);
1093        assert_eq!(Chs([0, 2, 0]).as_lba(), 1);
1094        assert_eq!(Chs([0, 63, 0]).as_lba(), 62);
1095        assert_eq!(Chs([1, 1, 0]).as_lba(), 63);
1096        assert_eq!(Chs([254, 1, 0]).as_lba(), 63 * 254);
1097        assert_eq!(Chs([0, 1, 1]).as_lba(), 63 * 255);
1098        assert_eq!(Chs([0, 1, 255]).as_lba(), 63 * 255 * 255);
1099        assert_eq!(Chs([0, (15 << 6) + 1, 255]).as_lba(), 63 * 255 * 1023);
1100        // Out of range
1101        assert_eq!(Chs::OUT_OF_RANGE.as_lba(), u32::MAX);
1102    }
1103
1104    #[test]
1105    fn test_mbr_partition_table_size() {
1106        assert_eq!(core::mem::size_of::<MbrPartitionTable>(), 64);
1107        assert_eq!(core::mem::size_of::<MbrPartition>(), 16);
1108        assert_eq!(core::mem::size_of::<MasterBootRecord>(), 512);
1109    }
1110
1111    #[test]
1112    fn test_protective_mbr() {
1113        let mbr = MasterBootRecord::protective(1000);
1114        assert!(mbr.has_valid_signature());
1115        let pt = mbr.get_partition_table();
1116        assert!(pt.is_protective());
1117        assert_eq!(pt[0].start_lba.to_ne(), 1);
1118        assert_eq!(pt[0].sector_count.to_ne(), 999);
1119    }
1120
1121    #[test]
1122    fn test_partition_type_full_transmute() {
1123        // Verify all 256 values are valid
1124        for i in 0u8..=255 {
1125            let pt = MbrPartitionTypeFull::from_u8(i);
1126            assert_eq!(pt.to_u8(), i);
1127        }
1128    }
1129}