file_system/mbr/partition/
entry.rs1use core::fmt;
8
9use shared::Unit;
10
11use crate::mbr::PartitionKind;
12
13#[derive(Debug, Clone, Copy)]
48pub struct PartitionEntry {
49 pub bootable: bool,
51 pub start_head: u8,
53 pub start_sector: u8,
55 pub start_cylinder: u8,
57 pub kind: PartitionKind,
59 pub end_head: u8,
61 pub end_sector: u8,
63 pub end_cylinder: u8,
65 pub start_block: u32,
67 pub block_count: u32,
69}
70
71impl PartitionEntry {
72 pub const SIZE: usize = 16;
73 pub const BOOTABLE_FLAG: u8 = 0x80;
74
75 pub fn parse(data: &[u8]) -> Option<Self> {
76 if data.len() < Self::SIZE {
77 return None;
78 }
79
80 Some(Self {
81 bootable: data[0] == Self::BOOTABLE_FLAG,
82 start_head: data[1],
83 start_sector: data[2],
84 start_cylinder: data[3],
85 kind: PartitionKind::from_u8(data[4]),
86 end_head: data[5],
87 end_sector: data[6],
88 end_cylinder: data[7],
89 start_block: u32::from_le_bytes([data[8], data[9], data[10], data[11]]),
90 block_count: u32::from_le_bytes([data[12], data[13], data[14], data[15]]),
91 })
92 }
93
94 pub fn new_empty() -> Self {
110 Self {
111 bootable: false,
112 start_head: 0,
113 start_sector: 0,
114 start_cylinder: 0,
115 kind: PartitionKind::Empty,
116 end_head: 0,
117 end_sector: 0,
118 end_cylinder: 0,
119 start_block: 0,
120 block_count: 0,
121 }
122 }
123
124 pub fn new_with_params(
155 bootable: bool,
156 kind: PartitionKind,
157 start_lba: u32,
158 size_sectors: u32,
159 ) -> Self {
160 let mut entry = Self::new_empty();
161 entry.bootable = bootable;
162 entry.kind = kind;
163 entry.start_block = start_lba.to_le();
164 entry.block_count = size_sectors.to_le();
165 entry
166 }
167
168 pub fn to_bytes(&self) -> [u8; Self::SIZE] {
169 let mut data = [0u8; Self::SIZE];
170
171 data[0] = if self.bootable {
172 Self::BOOTABLE_FLAG
173 } else {
174 0x00
175 };
176 data[1] = self.start_head;
177 data[2] = self.start_sector;
178 data[3] = self.start_cylinder;
179 data[4] = self.kind.to_u8();
180 data[5] = self.end_head;
181 data[6] = self.end_sector;
182 data[7] = self.end_cylinder;
183 data[8..12].copy_from_slice(&self.start_block.to_le_bytes());
184 data[12..16].copy_from_slice(&self.block_count.to_le_bytes());
185
186 data
187 }
188
189 pub fn is_valid(&self) -> bool {
191 self.kind != PartitionKind::Empty && self.block_count > 0
192 }
193
194 pub fn overlaps_with(&self, other: &Self) -> bool {
196 if !self.is_valid() || !other.is_valid() {
197 return false;
198 }
199
200 let self_start = self.start_block;
201 let self_end = self.start_block + self.block_count - 1;
202 let other_start = other.start_block;
203 let other_end = other.start_block + other.block_count - 1;
204
205 !(self_end < other_start || other_end < self_start)
206 }
207
208 pub fn contains_lba(&self, lba: u32) -> bool {
210 if !self.is_valid() {
211 return false;
212 }
213
214 let start = self.start_block;
215 let end = self.start_block + self.block_count - 1;
216 lba >= start && lba <= end
217 }
218
219 pub fn clear(&mut self) {
221 *self = Self::new_empty();
222 }
223}
224
225impl Default for PartitionEntry {
226 fn default() -> Self {
227 Self::new_empty()
228 }
229}
230
231impl fmt::Display for PartitionEntry {
232 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
233 if !self.is_valid() {
234 write!(formatter, "Empty partition")
235 } else {
236 write!(
237 formatter,
238 "Partition: Type={:02X} ({}), Start_LBA={}, Size={} sectors ({}), Bootable={}",
239 self.kind.to_u8(),
240 self.kind,
241 self.start_block,
242 self.block_count,
243 Unit::new(self.block_count * 512, "B"),
244 self.bootable
245 )
246 }
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use crate::mbr::Mbr;
253
254 use super::{PartitionEntry, PartitionKind};
255 use alloc::format;
256
257 fn create_test_partition() -> PartitionEntry {
258 PartitionEntry::new_with_params(
259 true, PartitionKind::Fat32Lba, Mbr::MINIMUM_START_BLOCK as u32, 204800, )
264 }
265
266 #[test]
267 fn test_partition_entry_new() {
268 let entry = PartitionEntry::new_empty();
269 assert!(!entry.is_valid());
270 assert!(!entry.bootable);
271 assert_eq!(entry.start_block, 0);
272 assert_eq!(entry.block_count, 0);
273 assert_eq!(entry.kind, PartitionKind::Empty);
274 }
275
276 #[test]
277 fn test_partition_entry_new_with_params() {
278 let entry = create_test_partition();
279 assert!(entry.is_valid());
280 assert!(entry.bootable);
281 assert_eq!(entry.start_block, 2048);
282 assert_eq!(entry.block_count, 204800);
283 assert_eq!(entry.kind, PartitionKind::Fat32Lba);
284 }
285
286 #[test]
287 fn test_partition_entry_overlaps() {
288 let partition1 = PartitionEntry::new_with_params(false, PartitionKind::Fat32, 1000, 2000);
289 let partition2 = PartitionEntry::new_with_params(false, PartitionKind::Linux, 2400, 1000);
290 let partition3 =
291 PartitionEntry::new_with_params(false, PartitionKind::LinuxSwap, 1500, 1000);
292
293 assert!(partition1.overlaps_with(&partition3)); assert!(partition2.overlaps_with(&partition3)); assert!(partition1.overlaps_with(&partition2)); }
298
299 #[test]
300 fn test_partition_entry_no_overlap() {
301 let partition1 = PartitionEntry::new_with_params(false, PartitionKind::Fat32, 1000, 1000);
302 let partition2 = PartitionEntry::new_with_params(false, PartitionKind::Linux, 2000, 1000);
303
304 assert!(!partition1.overlaps_with(&partition2));
306 assert!(!partition2.overlaps_with(&partition1));
307 }
308
309 #[test]
310 fn test_partition_entry_contains_lba() {
311 let entry = create_test_partition();
312
313 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)); }
319
320 #[test]
321 fn test_partition_entry_clear() {
322 let mut entry = create_test_partition();
323 assert!(entry.is_valid());
324
325 entry.clear();
326 assert!(!entry.is_valid());
327 assert!(!entry.bootable);
328 assert_eq!(entry.start_block, 0);
329 assert_eq!(entry.block_count, 0);
330 }
331
332 #[test]
333 fn test_partition_entry_default() {
334 let entry = PartitionEntry::default();
335 assert!(!entry.is_valid());
336 assert_eq!(entry.kind, PartitionKind::Empty);
337 }
338
339 #[test]
340 fn test_partition_entry_display() {
341 let entry = create_test_partition();
342 let display_string = format!("{entry}");
343
344 assert!(display_string.contains("Type=0C"));
345 assert!(display_string.contains("FAT32 LBA"));
346 assert!(display_string.contains("Start_LBA=2048"));
347 assert!(display_string.contains("Size=204800"));
348 assert!(display_string.contains("Bootable=true"));
349
350 let empty_entry = PartitionEntry::new_empty();
351 let empty_string = format!("{empty_entry}");
352 assert!(empty_string.contains("Empty partition"));
353 }
354
355 #[test]
356 fn test_partition_entry_validity() {
357 let valid = PartitionEntry::new_with_params(false, PartitionKind::Linux, 100, 200);
359 assert!(valid.is_valid());
360
361 let zero_size = PartitionEntry::new_with_params(false, PartitionKind::Linux, 100, 0);
363 assert!(!zero_size.is_valid());
364
365 let empty_type = PartitionEntry::new_with_params(false, PartitionKind::Empty, 100, 200);
367 assert!(!empty_type.is_valid());
368 }
369}