mbr_nostd/
lib.rs

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
12/// A struct representing an MBR partition table. 
13pub 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    /// Parses the MBR table from a raw byte buffer. 
26    /// 
27    /// Throws an error in the following cases:
28    /// * `BufferWrongSizeError` if `bytes.len()` is less than 512
29    /// * `InvalidMBRSuffix` if the final 2 bytes in `bytes` are not `[0x55, 0xaa]`
30    /// * `UnsupportedPartitionError` if the MBR contains a tag that the crate does not recognize
31    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    /// Serializes this MBR partition table to a raw byte buffer. 
53    
54    /// Throws an error in the following cases:
55    /// * `BufferWrongSizeError` if `buffer.len()` is less than 512
56    /// 
57    /// Note that it only affects the partition table itself, which only appears starting
58    /// from byte `446` of the MBR; no bytes before this are affected, even though it is
59    /// still necessary to pass a full `512` byte buffer. 
60    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}