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}