#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Chs {
pub cylinder: u16,
pub head: u8,
pub sector: u8,
}
impl Chs {
#[must_use]
pub fn from_bytes(b: [u8; 3]) -> Self {
let head = b[0];
let sector = b[1] & 0x3F;
let cylinder = ((b[1] as u16 & 0xC0) << 2) | b[2] as u16;
Chs {
cylinder,
head,
sector,
}
}
#[must_use]
pub fn to_lba(self, heads_per_cylinder: u8, sectors_per_track: u8) -> Option<u32> {
if self.sector == 0 {
return None;
}
let hpc = heads_per_cylinder as u32;
let spt = sectors_per_track as u32;
if hpc == 0 || spt == 0 {
return None;
}
Some(
(self.cylinder as u32) * hpc * spt
+ (self.head as u32) * spt
+ (self.sector as u32 - 1),
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PartitionEntry {
pub status: u8,
pub chs_first: Chs,
pub type_code: TypeCode,
pub chs_last: Chs,
pub lba_start: u32,
pub lba_count: u32,
}
impl PartitionEntry {
#[must_use]
pub fn from_bytes(b: &[u8; 16]) -> Self {
PartitionEntry {
status: b[0],
chs_first: Chs::from_bytes([b[1], b[2], b[3]]),
type_code: TypeCode(b[4]),
chs_last: Chs::from_bytes([b[5], b[6], b[7]]),
lba_start: u32::from_le_bytes([b[8], b[9], b[10], b[11]]),
lba_count: u32::from_le_bytes([b[12], b[13], b[14], b[15]]),
}
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.type_code.is_empty() && self.lba_start == 0 && self.lba_count == 0
}
#[must_use]
pub fn is_bootable(&self) -> bool {
self.status == 0x80
}
#[must_use]
pub fn lba_end(&self) -> u32 {
self.lba_start
.saturating_add(self.lba_count)
.saturating_sub(1)
}
#[must_use]
pub fn is_extended(&self) -> bool {
self.type_code.is_extended()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct TypeCode(pub u8);
impl TypeCode {
#[must_use]
pub fn name(self) -> &'static str {
match self.0 {
0x00 => "Empty",
0x01 => "FAT12",
0x04 => "FAT16 <32 MB",
0x05 => "Extended (CHS)",
0x06 => "FAT16",
0x07 => "NTFS / exFAT / IFS",
0x08 => "FAT32 (EISA / AIX)",
0x0B => "FAT32 (CHS)",
0x0C => "FAT32 (LBA)",
0x0E => "FAT16 (LBA)",
0x0F => "Extended (LBA)",
0x11 => "Hidden FAT12",
0x14 => "Hidden FAT16 <32 MB",
0x16 => "Hidden FAT16",
0x17 => "Hidden NTFS / IFS",
0x1B => "Hidden FAT32 (CHS)",
0x1C => "Hidden FAT32 (LBA)",
0x1E => "Hidden FAT16 (LBA)",
0x27 => "Windows Recovery / Hidden NTFS",
0x42 => "Windows LDM / Dynamic Disk",
0x82 => "Linux Swap / Solaris",
0x83 => "Linux",
0x84 => "Hibernate (Windows)",
0x85 => "Linux Extended",
0x86 => "Linux LVM (old)",
0x87 => "NTFS Volume Set",
0x8E => "Linux LVM",
0x9F => "BSD/OS",
0xA5 => "FreeBSD",
0xA6 => "OpenBSD",
0xA9 => "NetBSD",
0xAB => "macOS Boot",
0xAF => "macOS HFS+",
0xBE => "Solaris Boot",
0xBF => "Solaris",
0xEB => "BeOS / Haiku",
0xEE => "GPT Protective MBR",
0xEF => "EFI System Partition (FAT)",
0xFB => "VMware VMFS",
0xFC => "VMware Swap",
0xFD => "Linux RAID",
0xFE => "Linux LAF / IBM IML",
_ => "Unknown",
}
}
#[must_use]
pub fn family(self) -> PartitionFamily {
match self.0 {
0x00 => PartitionFamily::Empty,
0x01 | 0x11 => PartitionFamily::Fat12,
0x04 | 0x06 | 0x0E | 0x14 | 0x16 | 0x1E => PartitionFamily::Fat16,
0x0B | 0x0C | 0x1B | 0x1C => PartitionFamily::Fat32,
0x07 | 0x17 | 0x87 => PartitionFamily::Ntfs,
0x05 | 0x0F | 0x85 => PartitionFamily::ExtendedMbr,
0x82 => PartitionFamily::LinuxSwap,
0x83 => PartitionFamily::Linux,
0x8E => PartitionFamily::LinuxLvm,
0xFD => PartitionFamily::LinuxRaid,
0x27 => PartitionFamily::WindowsRecovery,
0x42 => PartitionFamily::WindowsDynamic,
0xA5 => PartitionFamily::FreeBsd,
0xA6 => PartitionFamily::OpenBsd,
0xA9 => PartitionFamily::NetBsd,
0xAF | 0xAB => PartitionFamily::Hfs,
0xEE => PartitionFamily::GptProtective,
0xEF => PartitionFamily::EfiSystem,
0xFB | 0xFC => PartitionFamily::Vmware,
_ => PartitionFamily::Unknown(self.0),
}
}
#[must_use]
pub fn is_empty(self) -> bool {
self.0 == 0x00
}
#[must_use]
pub fn is_extended(self) -> bool {
matches!(self.0, 0x05 | 0x0F | 0x85)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PartitionFamily {
Empty,
Fat12,
Fat16,
Fat32,
Ntfs,
ExtendedMbr,
LinuxSwap,
Linux,
LinuxLvm,
LinuxRaid,
WindowsRecovery,
WindowsDynamic,
FreeBsd,
OpenBsd,
NetBsd,
Hfs,
GptProtective,
EfiSystem,
Vmware,
Unknown(u8),
}