1#![no_std]
2
3extern crate byteorder;
4use byteorder::{ByteOrder, LittleEndian};
5
6mod error;
7pub use error::{MbrError, ErrorCause};
8
9mod partitions;
10pub use partitions::*;
11
12pub struct MasterBootRecord {
14 entries: [PartitionTableEntry; MAX_ENTRIES],
15}
16
17const BUFFER_SIZE: usize = 512;
18const TABLE_OFFSET: usize = 446;
19const ENTRY_SIZE: usize = 16;
20const SUFFIX_BYTES: [u8; 2] = [0x55, 0xaa];
21const MAX_ENTRIES: usize = (BUFFER_SIZE - TABLE_OFFSET - 2) / ENTRY_SIZE;
22
23impl MasterBootRecord {
24
25 pub fn from_bytes<T: AsRef<[u8]>>(bytes: &T) -> Result<MasterBootRecord, MbrError> {
32 let buffer: &[u8] = bytes.as_ref();
33 if buffer.len() < BUFFER_SIZE {
34 return Err(MbrError::from_cause(ErrorCause::BufferWrongSizeError{expected : BUFFER_SIZE, actual : buffer.len()}));
35 } else if buffer[BUFFER_SIZE - SUFFIX_BYTES.len()..BUFFER_SIZE] != SUFFIX_BYTES[..] {
36 return Err(MbrError::from_cause(ErrorCause::InvalidMBRSuffix{actual : [buffer[BUFFER_SIZE - 2], buffer[BUFFER_SIZE -1]]}));
37 }
38 let mut entries = [PartitionTableEntry::empty(); MAX_ENTRIES];
39 for idx in 0..MAX_ENTRIES {
40 let offset = TABLE_OFFSET + idx * ENTRY_SIZE;
41 let partition_type = PartitionType::from_mbr_tag_byte(buffer[offset + 4]);
42 if let PartitionType::Unknown(c) = partition_type {
43 return Err(MbrError::from_cause(ErrorCause::UnsupportedPartitionError { tag : c}));
44 }
45 let lba = LittleEndian::read_u32(&buffer[offset + 8..]);
46 let len = LittleEndian::read_u32(&buffer[offset + 12..]);
47 entries[idx] = PartitionTableEntry::new(partition_type, lba, len);
48 }
49 Ok(MasterBootRecord { entries })
50 }
51
52 pub fn serialize<T: AsMut<[u8]>>(&self, buffer: &mut T) -> Result<usize, MbrError> {
61 let buffer: &mut [u8] = buffer.as_mut();
62 if buffer.len() < BUFFER_SIZE {
63 return Err(MbrError::from_cause(ErrorCause::BufferWrongSizeError{expected : BUFFER_SIZE, actual : buffer.len()}));
64 }
65 {
66 let suffix: &mut [u8] = &mut buffer[BUFFER_SIZE - SUFFIX_BYTES.len()..BUFFER_SIZE];
67 suffix.copy_from_slice(&SUFFIX_BYTES);
68 }
69 for idx in 0..MAX_ENTRIES {
70 let offset = TABLE_OFFSET + idx * ENTRY_SIZE;
71 let entry = self.entries[idx];
72 let parition_byte = entry.partition_type.to_mbr_tag_byte();
73 let lba = entry.logical_block_address;
74 let len = entry.sector_count;
75
76 buffer[offset + 4] = parition_byte;
77 {
78 let lba_slice: &mut [u8] = &mut buffer[offset + 8..offset + 12];
79 LittleEndian::write_u32(lba_slice, lba);
80 }
81 {
82 let len_slice: &mut [u8] = &mut buffer[offset + 12..offset + 16];
83 LittleEndian::write_u32(len_slice, len);
84 }
85 }
86 Ok(BUFFER_SIZE)
87 }
88}
89
90impl PartitionTable for MasterBootRecord {
91 fn size(&self) -> usize {
92 BUFFER_SIZE
93 }
94
95 fn partition_table_entries(&self) -> &[PartitionTableEntry] {
96 &self.entries[..]
97 }
98}