2
2
3
3
use super :: fail:: { fail, UnwrapOrFail } ;
4
4
5
- pub fn get_partition ( buffer : & [ u8 ] , index : usize ) -> PartitionTableEntry {
6
- if buffer. len ( ) < BUFFER_SIZE {
5
+ /// Returns the first bootable partition in the partition table.
6
+ pub fn boot_partition ( partitions_raw : & [ u8 ] ) -> Option < PartitionTableEntry > {
7
+ for index in 0 ..4 {
8
+ let entry = get_partition ( partitions_raw, index) ;
9
+ if entry. bootable {
10
+ return Some ( entry) ;
11
+ }
12
+ }
13
+ None
14
+ }
15
+
16
+ pub fn get_partition ( partitions_raw : & [ u8 ] , index : usize ) -> PartitionTableEntry {
17
+ if partitions_raw. len ( ) < PARTITIONS_AREA_SIZE {
7
18
fail ( b'a' ) ;
8
- } else if buffer. get ( BUFFER_SIZE - SUFFIX_BYTES . len ( ) ..BUFFER_SIZE ) != Some ( & SUFFIX_BYTES [ ..] ) {
9
- fail ( b'b' ) ;
10
19
}
11
20
12
- let offset = TABLE_OFFSET + index * ENTRY_SIZE ;
13
- let buffer = buffer. get ( offset..) . unwrap_or_fail ( b'c' ) ;
21
+ let offset = index * ENTRY_SIZE ;
22
+ let buffer = partitions_raw. get ( offset..) . unwrap_or_fail ( b'c' ) ;
23
+
24
+ let bootable_raw = * buffer. get ( 0 ) . unwrap_or_fail ( b'd' ) ;
25
+ let bootable = bootable_raw == 0x80 ;
14
26
15
- let partition_type = * buffer. get ( 4 ) . unwrap_or_fail ( b'd ' ) ;
27
+ let partition_type = * buffer. get ( 4 ) . unwrap_or_fail ( b'e ' ) ;
16
28
17
29
let lba = u32:: from_le_bytes (
18
30
buffer
@@ -28,64 +40,11 @@ pub fn get_partition(buffer: &[u8], index: usize) -> PartitionTableEntry {
28
40
. and_then ( |s| s. try_into ( ) . ok ( ) )
29
41
. unwrap_or_fail ( b'f' ) ,
30
42
) ;
31
- PartitionTableEntry :: new ( partition_type, lba, len)
43
+ PartitionTableEntry :: new ( bootable , partition_type, lba, len)
32
44
}
33
45
34
- /// A struct representing an MBR partition table.
35
- pub struct MasterBootRecord {
36
- entries : [ PartitionTableEntry ; MAX_ENTRIES ] ,
37
- }
38
-
39
- const BUFFER_SIZE : usize = 512 ;
40
- const TABLE_OFFSET : usize = 446 ;
46
+ const PARTITIONS_AREA_SIZE : usize = 16 * 4 ;
41
47
const ENTRY_SIZE : usize = 16 ;
42
- const SUFFIX_BYTES : [ u8 ; 2 ] = [ 0x55 , 0xaa ] ;
43
- const MAX_ENTRIES : usize = ( BUFFER_SIZE - TABLE_OFFSET - 2 ) / ENTRY_SIZE ;
44
-
45
- impl MasterBootRecord {
46
- /// Parses the MBR table from a raw byte buffer.
47
-
48
- pub fn from_bytes ( buffer : & [ u8 ] ) -> MasterBootRecord {
49
- if buffer. len ( ) < BUFFER_SIZE {
50
- fail ( b'1' ) ;
51
- } else if buffer. get ( BUFFER_SIZE - SUFFIX_BYTES . len ( ) ..BUFFER_SIZE )
52
- != Some ( & SUFFIX_BYTES [ ..] )
53
- {
54
- fail ( b'2' ) ;
55
- }
56
- let mut entries = [ PartitionTableEntry :: empty ( ) ; MAX_ENTRIES ] ;
57
-
58
- for idx in 0 ..MAX_ENTRIES {
59
- let offset = TABLE_OFFSET + idx * ENTRY_SIZE ;
60
- let buffer = buffer. get ( offset..) . unwrap_or_fail ( b'8' ) ;
61
-
62
- let partition_type = * buffer. get ( 4 ) . unwrap_or_fail ( b'4' ) ;
63
-
64
- let lba = u32:: from_le_bytes (
65
- buffer
66
- . get ( 8 ..)
67
- . and_then ( |s| s. get ( ..4 ) )
68
- . and_then ( |s| s. try_into ( ) . ok ( ) )
69
- . unwrap_or_fail ( b'5' ) ,
70
- ) ;
71
- let len = u32:: from_le_bytes (
72
- buffer
73
- . get ( 12 ..)
74
- . and_then ( |s| s. get ( ..4 ) )
75
- . and_then ( |s| s. try_into ( ) . ok ( ) )
76
- . unwrap_or_fail ( b'6' ) ,
77
- ) ;
78
- * entries. get_mut ( idx) . unwrap_or_fail ( b'7' ) =
79
- PartitionTableEntry :: new ( partition_type, lba, len) ;
80
- }
81
-
82
- MasterBootRecord { entries }
83
- }
84
-
85
- pub fn partition_table_entries ( & self ) -> & [ PartitionTableEntry ] {
86
- & self . entries [ ..]
87
- }
88
- }
89
48
90
49
/// The type of a particular partition.
91
50
#[ derive( Copy , Clone , Eq , PartialEq ) ]
@@ -129,6 +88,9 @@ impl PartitionType {
129
88
/// An entry in a partition table.
130
89
#[ derive( Copy , Clone , Eq , PartialEq ) ]
131
90
pub struct PartitionTableEntry {
91
+ /// Whether this partition is a boot partition.
92
+ pub bootable : bool ,
93
+
132
94
/// The type of partition in this entry.
133
95
pub partition_type : u8 ,
134
96
@@ -141,18 +103,16 @@ pub struct PartitionTableEntry {
141
103
142
104
impl PartitionTableEntry {
143
105
pub fn new (
106
+ bootable : bool ,
144
107
partition_type : u8 ,
145
108
logical_block_address : u32 ,
146
109
sector_count : u32 ,
147
110
) -> PartitionTableEntry {
148
111
PartitionTableEntry {
112
+ bootable,
149
113
partition_type,
150
114
logical_block_address,
151
115
sector_count,
152
116
}
153
117
}
154
-
155
- pub fn empty ( ) -> PartitionTableEntry {
156
- PartitionTableEntry :: new ( 0 , 0 , 0 )
157
- }
158
118
}
0 commit comments