1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct Chs {
6 pub cylinder: u16,
7 pub head: u8,
8 pub sector: u8,
9}
10
11impl Chs {
12 #[must_use]
21 pub fn from_bytes(b: [u8; 3]) -> Self {
22 let head = b[0];
23 let sector = b[1] & 0x3F;
24 let cylinder = ((b[1] as u16 & 0xC0) << 2) | b[2] as u16;
25 Chs {
26 cylinder,
27 head,
28 sector,
29 }
30 }
31
32 #[must_use]
36 pub fn to_lba(self, heads_per_cylinder: u8, sectors_per_track: u8) -> Option<u32> {
37 if self.sector == 0 {
38 return None;
39 }
40 let hpc = heads_per_cylinder as u32;
41 let spt = sectors_per_track as u32;
42 if hpc == 0 || spt == 0 {
43 return None;
44 }
45 Some(
46 (self.cylinder as u32) * hpc * spt
47 + (self.head as u32) * spt
48 + (self.sector as u32 - 1),
49 )
50 }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct PartitionEntry {
56 pub status: u8,
58 pub chs_first: Chs,
60 pub type_code: TypeCode,
62 pub chs_last: Chs,
64 pub lba_start: u32,
66 pub lba_count: u32,
68}
69
70impl PartitionEntry {
71 #[must_use]
73 pub fn from_bytes(b: &[u8; 16]) -> Self {
74 PartitionEntry {
75 status: b[0],
76 chs_first: Chs::from_bytes([b[1], b[2], b[3]]),
77 type_code: TypeCode(b[4]),
78 chs_last: Chs::from_bytes([b[5], b[6], b[7]]),
79 lba_start: u32::from_le_bytes([b[8], b[9], b[10], b[11]]),
80 lba_count: u32::from_le_bytes([b[12], b[13], b[14], b[15]]),
81 }
82 }
83
84 #[must_use]
86 pub fn is_empty(&self) -> bool {
87 self.type_code.is_empty() && self.lba_start == 0 && self.lba_count == 0
88 }
89
90 #[must_use]
92 pub fn is_bootable(&self) -> bool {
93 self.status == 0x80
94 }
95
96 #[must_use]
98 pub fn lba_end(&self) -> u32 {
99 self.lba_start
100 .saturating_add(self.lba_count)
101 .saturating_sub(1)
102 }
103
104 #[must_use]
106 pub fn is_extended(&self) -> bool {
107 self.type_code.is_extended()
108 }
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
113pub struct TypeCode(pub u8);
114
115impl TypeCode {
116 #[must_use]
118 pub fn name(self) -> &'static str {
119 match self.0 {
120 0x00 => "Empty",
121 0x01 => "FAT12",
122 0x04 => "FAT16 <32 MB",
123 0x05 => "Extended (CHS)",
124 0x06 => "FAT16",
125 0x07 => "NTFS / exFAT / IFS",
126 0x08 => "FAT32 (EISA / AIX)",
127 0x0B => "FAT32 (CHS)",
128 0x0C => "FAT32 (LBA)",
129 0x0E => "FAT16 (LBA)",
130 0x0F => "Extended (LBA)",
131 0x11 => "Hidden FAT12",
132 0x14 => "Hidden FAT16 <32 MB",
133 0x16 => "Hidden FAT16",
134 0x17 => "Hidden NTFS / IFS",
135 0x1B => "Hidden FAT32 (CHS)",
136 0x1C => "Hidden FAT32 (LBA)",
137 0x1E => "Hidden FAT16 (LBA)",
138 0x27 => "Windows Recovery / Hidden NTFS",
139 0x42 => "Windows LDM / Dynamic Disk",
140 0x82 => "Linux Swap / Solaris",
141 0x83 => "Linux",
142 0x84 => "Hibernate (Windows)",
143 0x85 => "Linux Extended",
144 0x86 => "Linux LVM (old)",
145 0x87 => "NTFS Volume Set",
146 0x8E => "Linux LVM",
147 0x9F => "BSD/OS",
148 0xA5 => "FreeBSD",
149 0xA6 => "OpenBSD",
150 0xA9 => "NetBSD",
151 0xAB => "macOS Boot",
152 0xAF => "macOS HFS+",
153 0xBE => "Solaris Boot",
154 0xBF => "Solaris",
155 0xEB => "BeOS / Haiku",
156 0xEE => "GPT Protective MBR",
157 0xEF => "EFI System Partition (FAT)",
158 0xFB => "VMware VMFS",
159 0xFC => "VMware Swap",
160 0xFD => "Linux RAID",
161 0xFE => "Linux LAF / IBM IML",
162 _ => "Unknown",
163 }
164 }
165
166 #[must_use]
168 pub fn family(self) -> PartitionFamily {
169 match self.0 {
170 0x00 => PartitionFamily::Empty,
171 0x01 | 0x11 => PartitionFamily::Fat12,
172 0x04 | 0x06 | 0x0E | 0x14 | 0x16 | 0x1E => PartitionFamily::Fat16,
173 0x0B | 0x0C | 0x1B | 0x1C => PartitionFamily::Fat32,
174 0x07 | 0x17 | 0x87 => PartitionFamily::Ntfs,
175 0x05 | 0x0F | 0x85 => PartitionFamily::ExtendedMbr,
176 0x82 => PartitionFamily::LinuxSwap,
177 0x83 => PartitionFamily::Linux,
178 0x8E => PartitionFamily::LinuxLvm,
179 0xFD => PartitionFamily::LinuxRaid,
180 0x27 => PartitionFamily::WindowsRecovery,
181 0x42 => PartitionFamily::WindowsDynamic,
182 0xA5 => PartitionFamily::FreeBsd,
183 0xA6 => PartitionFamily::OpenBsd,
184 0xA9 => PartitionFamily::NetBsd,
185 0xAF | 0xAB => PartitionFamily::Hfs,
186 0xEE => PartitionFamily::GptProtective,
187 0xEF => PartitionFamily::EfiSystem,
188 0xFB | 0xFC => PartitionFamily::Vmware,
189 _ => PartitionFamily::Unknown(self.0),
190 }
191 }
192
193 #[must_use]
195 pub fn is_empty(self) -> bool {
196 self.0 == 0x00
197 }
198
199 #[must_use]
201 pub fn is_extended(self) -> bool {
202 matches!(self.0, 0x05 | 0x0F | 0x85)
203 }
204}
205
206#[derive(Debug, Clone, Copy, PartialEq, Eq)]
208pub enum PartitionFamily {
209 Empty,
210 Fat12,
211 Fat16,
212 Fat32,
213 Ntfs,
214 ExtendedMbr,
215 LinuxSwap,
216 Linux,
217 LinuxLvm,
218 LinuxRaid,
219 WindowsRecovery,
220 WindowsDynamic,
221 FreeBsd,
222 OpenBsd,
223 NetBsd,
224 Hfs,
225 GptProtective,
226 EfiSystem,
227 Vmware,
228 Unknown(u8),
229}