1use core::fmt;
8
9#[derive(Debug, Clone, Copy)]
44#[repr(C, packed)]
45pub struct PartitionEntry {
46 pub bootable: u8,
48 pub start_head: u8,
50 pub start_sector: u8,
52 pub start_cylinder: u8,
54 pub partition_type: u8,
56 pub end_head: u8,
58 pub end_sector: u8,
60 pub end_cylinder: u8,
62 pub start_lba: u32,
64 pub size_sectors: u32,
66}
67
68impl PartitionEntry {
69 pub fn new() -> Self {
85 Self {
86 bootable: 0,
87 start_head: 0,
88 start_sector: 0,
89 start_cylinder: 0,
90 partition_type: 0,
91 end_head: 0,
92 end_sector: 0,
93 end_cylinder: 0,
94 start_lba: 0,
95 size_sectors: 0,
96 }
97 }
98
99 pub fn new_with_params(
130 bootable: bool,
131 partition_type: crate::PartitionKind,
132 start_lba: u32,
133 size_sectors: u32,
134 ) -> Self {
135 let mut entry = Self::new();
136 entry.bootable = if bootable { 0x80 } else { 0x00 };
137 entry.set_partition_type(partition_type);
138 entry.start_lba = start_lba.to_le();
139 entry.size_sectors = size_sectors.to_le();
140 entry
141 }
142
143 pub fn is_valid(&self) -> bool {
145 self.partition_type != 0 && self.size_sectors > 0
146 }
147
148 pub fn is_bootable(&self) -> bool {
150 self.bootable == 0x80
151 }
152
153 pub fn set_bootable(&mut self, bootable: bool) {
155 self.bootable = if bootable { 0x80 } else { 0x00 };
156 }
157
158 pub fn get_start_lba(&self) -> u32 {
160 u32::from_le(self.start_lba)
161 }
162
163 pub fn set_start_lba(&mut self, start_lba: u32) {
165 self.start_lba = start_lba.to_le();
166 }
167
168 pub fn get_size_sectors(&self) -> u32 {
170 u32::from_le(self.size_sectors)
171 }
172
173 pub fn set_size_sectors(&mut self, size_sectors: u32) {
175 self.size_sectors = size_sectors.to_le();
176 }
177
178 pub fn get_partition_type(&self) -> crate::PartitionKind {
180 crate::PartitionKind::from_u8(self.partition_type)
181 }
182
183 pub fn set_partition_type(&mut self, partition_type: crate::PartitionKind) {
185 self.partition_type = partition_type.to_u8();
186 }
187
188 pub fn get_partition_type_name(&self) -> &'static str {
190 self.get_partition_type().get_name()
191 }
192
193 pub fn get_end_lba(&self) -> u32 {
195 self.get_start_lba() + self.get_size_sectors() - 1
196 }
197
198 pub fn get_size_bytes(&self) -> u64 {
200 self.get_size_sectors() as u64 * 512
201 }
202
203 pub fn overlaps_with(&self, other: &Self) -> bool {
205 if !self.is_valid() || !other.is_valid() {
206 return false;
207 }
208
209 let self_start = self.get_start_lba();
210 let self_end = self.get_end_lba();
211 let other_start = other.get_start_lba();
212 let other_end = other.get_end_lba();
213
214 !(self_end < other_start || other_end < self_start)
215 }
216
217 pub fn contains_lba(&self, lba: u32) -> bool {
219 if !self.is_valid() {
220 return false;
221 }
222
223 let start = self.get_start_lba();
224 let end = self.get_end_lba();
225 lba >= start && lba <= end
226 }
227
228 pub fn clear(&mut self) {
230 *self = Self::new();
231 }
232}
233
234impl Default for PartitionEntry {
235 fn default() -> Self {
236 Self::new()
237 }
238}
239
240impl fmt::Display for PartitionEntry {
241 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
242 if !self.is_valid() {
243 write!(formatter, "Empty partition")
244 } else {
245 write!(
246 formatter,
247 "Partition: Type={:02X} ({}), Start_LBA={}, Size={} sectors ({} MB), Bootable={}",
248 self.partition_type,
249 self.get_partition_type_name(),
250 self.get_start_lba(),
251 self.get_size_sectors(),
252 self.get_size_bytes() / (1024 * 1024),
253 self.is_bootable()
254 )
255 }
256 }
257}
258
259#[cfg(test)]
260mod tests {
261 use super::PartitionEntry;
262 use crate::PartitionKind;
263 use alloc::format;
264
265 fn create_test_partition() -> PartitionEntry {
266 PartitionEntry::new_with_params(
267 true, PartitionKind::Fat32Lba, 2048, 204800, )
272 }
273
274 #[test]
275 fn test_partition_entry_new() {
276 let entry = PartitionEntry::new();
277 assert!(!entry.is_valid());
278 assert!(!entry.is_bootable());
279 assert_eq!(entry.get_start_lba(), 0);
280 assert_eq!(entry.get_size_sectors(), 0);
281 assert_eq!(entry.get_partition_type(), PartitionKind::Empty);
282 }
283
284 #[test]
285 fn test_partition_entry_new_with_params() {
286 let entry = create_test_partition();
287 assert!(entry.is_valid());
288 assert!(entry.is_bootable());
289 assert_eq!(entry.get_start_lba(), 2048);
290 assert_eq!(entry.get_size_sectors(), 204800);
291 assert_eq!(entry.get_partition_type(), PartitionKind::Fat32Lba);
292 }
293
294 #[test]
295 fn test_partition_entry_bootable() {
296 let mut entry = PartitionEntry::new();
297 assert!(!entry.is_bootable());
298
299 entry.set_bootable(true);
300 assert!(entry.is_bootable());
301 assert_eq!(entry.bootable, 0x80);
302
303 entry.set_bootable(false);
304 assert!(!entry.is_bootable());
305 assert_eq!(entry.bootable, 0x00);
306 }
307
308 #[test]
309 fn test_partition_entry_lba() {
310 let mut entry = PartitionEntry::new();
311 assert_eq!(entry.get_start_lba(), 0);
312
313 entry.set_start_lba(12345);
314 assert_eq!(entry.get_start_lba(), 12345);
315 }
316
317 #[test]
318 fn test_partition_entry_size() {
319 let mut entry = PartitionEntry::new();
320 assert_eq!(entry.get_size_sectors(), 0);
321
322 entry.set_size_sectors(67890);
323 assert_eq!(entry.get_size_sectors(), 67890);
324 assert_eq!(entry.get_size_bytes(), 67890 * 512);
325 }
326
327 #[test]
328 fn test_partition_entry_type() {
329 let mut entry = PartitionEntry::new();
330 assert_eq!(entry.get_partition_type(), PartitionKind::Empty);
331
332 entry.set_partition_type(PartitionKind::Linux);
333 assert_eq!(entry.get_partition_type(), PartitionKind::Linux);
334 assert_eq!(entry.partition_type, 0x83);
335 }
336
337 #[test]
338 fn test_partition_entry_end_lba() {
339 let entry = create_test_partition();
340 assert_eq!(entry.get_end_lba(), 2048 + 204800 - 1);
341 }
342
343 #[test]
344 fn test_partition_entry_overlaps() {
345 let partition1 = PartitionEntry::new_with_params(false, PartitionKind::Fat32, 1000, 2000);
346 let partition2 = PartitionEntry::new_with_params(false, PartitionKind::Linux, 2400, 1000);
347 let partition3 =
348 PartitionEntry::new_with_params(false, PartitionKind::LinuxSwap, 1500, 1000);
349
350 assert!(partition1.overlaps_with(&partition3)); assert!(partition2.overlaps_with(&partition3)); assert!(partition1.overlaps_with(&partition2)); }
355
356 #[test]
357 fn test_partition_entry_no_overlap() {
358 let partition1 = PartitionEntry::new_with_params(false, PartitionKind::Fat32, 1000, 1000);
359 let partition2 = PartitionEntry::new_with_params(false, PartitionKind::Linux, 2000, 1000);
360
361 assert!(!partition1.overlaps_with(&partition2));
363 assert!(!partition2.overlaps_with(&partition1));
364 }
365
366 #[test]
367 fn test_partition_entry_contains_lba() {
368 let entry = create_test_partition();
369
370 assert!(!entry.contains_lba(2047)); assert!(entry.contains_lba(2048)); assert!(entry.contains_lba(100000)); assert!(entry.contains_lba(206847)); assert!(!entry.contains_lba(206848)); }
376
377 #[test]
378 fn test_partition_entry_clear() {
379 let mut entry = create_test_partition();
380 assert!(entry.is_valid());
381
382 entry.clear();
383 assert!(!entry.is_valid());
384 assert!(!entry.is_bootable());
385 assert_eq!(entry.get_start_lba(), 0);
386 assert_eq!(entry.get_size_sectors(), 0);
387 }
388
389 #[test]
390 fn test_partition_entry_default() {
391 let entry = PartitionEntry::default();
392 assert!(!entry.is_valid());
393 assert_eq!(entry.get_partition_type(), PartitionKind::Empty);
394 }
395
396 #[test]
397 fn test_partition_entry_display() {
398 let entry = create_test_partition();
399 let display_string = format!("{entry}");
400
401 assert!(display_string.contains("Type=0C"));
402 assert!(display_string.contains("FAT32 LBA"));
403 assert!(display_string.contains("Start_LBA=2048"));
404 assert!(display_string.contains("Size=204800"));
405 assert!(display_string.contains("Bootable=true"));
406
407 let empty_entry = PartitionEntry::new();
408 let empty_string = format!("{empty_entry}");
409 assert!(empty_string.contains("Empty partition"));
410 }
411
412 #[test]
413 fn test_partition_entry_size_bytes() {
414 let entry = PartitionEntry::new_with_params(false, PartitionKind::Linux, 0, 2048);
415 assert_eq!(entry.get_size_bytes(), 2048 * 512); }
417
418 #[test]
419 fn test_partition_entry_validity() {
420 let valid = PartitionEntry::new_with_params(false, PartitionKind::Linux, 100, 200);
422 assert!(valid.is_valid());
423
424 let zero_size = PartitionEntry::new_with_params(false, PartitionKind::Linux, 100, 0);
426 assert!(!zero_size.is_valid());
427
428 let empty_type = PartitionEntry::new_with_params(false, PartitionKind::Empty, 100, 200);
430 assert!(!empty_type.is_valid());
431 }
432}