|
2 | 2 |
|
3 | 3 | use super::split_array_ref; |
4 | 4 |
|
| 5 | +// Size of single directory entry in bytes |
| 6 | +const DIR_ENTRY_SIZE: u32 = 32; |
| 7 | + |
5 | 8 | pub(crate) struct BootSector { |
6 | | - bootjmp: [u8; 3], |
7 | | - oem_name: [u8; 8], |
8 | 9 | pub(crate) bpb: BiosParameterBlock, |
9 | | - boot_code: [u8; 448], |
10 | | - boot_sig: [u8; 2], |
11 | 10 | } |
12 | 11 |
|
13 | 12 | impl BootSector { |
14 | 13 | pub(crate) fn deserialize(bytes: &[u8]) -> Self { |
15 | 14 | let mut boot = Self::default(); |
16 | | - let (&bootjmp, bytes) = split_array_ref(bytes); |
17 | | - let (&oem_name, bytes) = split_array_ref(bytes); |
| 15 | + // let (&bootjmp, bytes) = split_array_ref(bytes); |
| 16 | + // let (&oem_name, bytes) = split_array_ref(bytes); |
| 17 | + |
| 18 | + let bytes = &bytes[3 + 8..]; |
18 | 19 |
|
19 | | - boot.bootjmp = bootjmp; |
20 | | - boot.oem_name = oem_name; |
| 20 | + // boot.bootjmp = bootjmp; |
| 21 | + // boot.oem_name = oem_name; |
21 | 22 | boot.bpb = BiosParameterBlock::deserialize(bytes); |
22 | 23 |
|
23 | | - let bytes = if boot.bpb.is_fat32() { |
24 | | - let (boot_code, bytes): (&[_; 420], _) = split_array_ref(bytes); |
25 | | - boot.boot_code[0..420].copy_from_slice(&boot_code[..]); |
26 | | - bytes |
27 | | - } else { |
28 | | - let (&boot_code, bytes) = split_array_ref(bytes); |
29 | | - boot.boot_code = boot_code; |
30 | | - bytes |
31 | | - }; |
32 | | - let (&boot_sig, bytes) = split_array_ref(bytes); |
33 | | - boot.boot_sig = boot_sig; |
| 24 | + // let bytes = if boot.bpb.is_fat32() { |
| 25 | + // let (boot_code, bytes): (&[_; 420], _) = split_array_ref(bytes); |
| 26 | + // boot.boot_code[0..420].copy_from_slice(&boot_code[..]); |
| 27 | + // bytes |
| 28 | + // } else { |
| 29 | + // let (&boot_code, bytes) = split_array_ref(bytes); |
| 30 | + // boot.boot_code = boot_code; |
| 31 | + // bytes |
| 32 | + // }; |
| 33 | + // let (&boot_sig, bytes) = split_array_ref(bytes); |
| 34 | + // boot.boot_sig = boot_sig; |
34 | 35 | boot |
35 | 36 | } |
36 | 37 | } |
37 | 38 |
|
38 | 39 | impl Default for BootSector { |
39 | 40 | fn default() -> Self { |
40 | 41 | Self { |
41 | | - bootjmp: Default::default(), |
42 | | - oem_name: Default::default(), |
43 | 42 | bpb: BiosParameterBlock::default(), |
44 | | - boot_code: [0; 448], |
45 | | - boot_sig: Default::default(), |
46 | 43 | } |
47 | 44 | } |
48 | 45 | } |
@@ -158,4 +155,86 @@ impl BiosParameterBlock { |
158 | 155 | // this provides a simple way to detect FAT32 |
159 | 156 | self.sectors_per_fat_16 == 0 |
160 | 157 | } |
| 158 | + |
| 159 | + pub(crate) fn sectors_per_fat(&self) -> u32 { |
| 160 | + if self.is_fat32() { |
| 161 | + self.sectors_per_fat_32 |
| 162 | + } else { |
| 163 | + u32::from(self.sectors_per_fat_16) |
| 164 | + } |
| 165 | + } |
| 166 | + |
| 167 | + pub(crate) fn total_sectors(&self) -> u32 { |
| 168 | + if self.total_sectors_16 == 0 { |
| 169 | + self.total_sectors_32 |
| 170 | + } else { |
| 171 | + u32::from(self.total_sectors_16) |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + pub(crate) fn reserved_sectors(&self) -> u32 { |
| 176 | + u32::from(self.reserved_sectors) |
| 177 | + } |
| 178 | + |
| 179 | + pub(crate) fn root_dir_sectors(&self) -> u32 { |
| 180 | + let root_dir_bytes = u32::from(self.root_entries) * DIR_ENTRY_SIZE; |
| 181 | + (root_dir_bytes + u32::from(self.bytes_per_sector) - 1) / u32::from(self.bytes_per_sector) |
| 182 | + } |
| 183 | + |
| 184 | + pub(crate) fn sectors_per_all_fats(&self) -> u32 { |
| 185 | + u32::from(self.fats) * self.sectors_per_fat() |
| 186 | + } |
| 187 | + |
| 188 | + pub(crate) fn first_data_sector(&self) -> u32 { |
| 189 | + let root_dir_sectors = self.root_dir_sectors(); |
| 190 | + let fat_sectors = self.sectors_per_all_fats(); |
| 191 | + self.reserved_sectors() + fat_sectors + root_dir_sectors |
| 192 | + } |
| 193 | + |
| 194 | + pub(crate) fn total_clusters(&self) -> u32 { |
| 195 | + let total_sectors = self.total_sectors(); |
| 196 | + let first_data_sector = self.first_data_sector(); |
| 197 | + let data_sectors = total_sectors - first_data_sector; |
| 198 | + data_sectors / u32::from(self.sectors_per_cluster) |
| 199 | + } |
| 200 | + |
| 201 | + pub fn fat_type(&self) -> FatType { |
| 202 | + FatType::from_clusters(self.total_clusters()) |
| 203 | + } |
| 204 | + |
| 205 | + /// Returns a root directory object allowing for futher penetration of a filesystem structure. |
| 206 | + pub fn check_root_dir(&self) { |
| 207 | + match self.fat_type() { |
| 208 | + FatType::Fat12 | FatType::Fat16 => crate::fail(b'y'), |
| 209 | + FatType::Fat32 => { |
| 210 | + self.root_dir_first_cluster; |
| 211 | + crate::fail(b'z'); |
| 212 | + } |
| 213 | + } |
| 214 | + } |
| 215 | +} |
| 216 | + |
| 217 | +pub enum FatType { |
| 218 | + /// 12 bits per FAT entry |
| 219 | + Fat12, |
| 220 | + /// 16 bits per FAT entry |
| 221 | + Fat16, |
| 222 | + /// 32 bits per FAT entry |
| 223 | + Fat32, |
| 224 | +} |
| 225 | + |
| 226 | +impl FatType { |
| 227 | + const FAT16_MIN_CLUSTERS: u32 = 4085; |
| 228 | + const FAT32_MIN_CLUSTERS: u32 = 65525; |
| 229 | + const FAT32_MAX_CLUSTERS: u32 = 0x0FFF_FFF4; |
| 230 | + |
| 231 | + pub(crate) fn from_clusters(total_clusters: u32) -> Self { |
| 232 | + if total_clusters < Self::FAT16_MIN_CLUSTERS { |
| 233 | + FatType::Fat12 |
| 234 | + } else if total_clusters < Self::FAT32_MIN_CLUSTERS { |
| 235 | + FatType::Fat16 |
| 236 | + } else { |
| 237 | + FatType::Fat32 |
| 238 | + } |
| 239 | + } |
161 | 240 | } |
0 commit comments