embedded_sdmmc/fat/
bpb.rs

1//! Boot Parameter Block
2
3use crate::{
4    blockdevice::BlockCount,
5    fat::{FatType, OnDiskDirEntry},
6};
7use byteorder::{ByteOrder, LittleEndian};
8
9/// A Boot Parameter Block.
10///
11/// This is the first sector of a FAT formatted partition, and it describes
12/// various properties of the FAT filesystem.
13pub struct Bpb<'a> {
14    data: &'a [u8; 512],
15    pub(crate) fat_type: FatType,
16    cluster_count: u32,
17}
18
19impl<'a> Bpb<'a> {
20    pub(crate) const FOOTER_VALUE: u16 = 0xAA55;
21
22    /// Attempt to parse a Boot Parameter Block from a 512 byte sector.
23    pub fn create_from_bytes(data: &[u8; 512]) -> Result<Bpb, &'static str> {
24        let mut bpb = Bpb {
25            data,
26            fat_type: FatType::Fat16,
27            cluster_count: 0,
28        };
29        if bpb.footer() != Self::FOOTER_VALUE {
30            return Err("Bad BPB footer");
31        }
32
33        let root_dir_blocks =
34            BlockCount::from_bytes(u32::from(bpb.root_entries_count()) * OnDiskDirEntry::LEN_U32).0;
35        let non_data_blocks = u32::from(bpb.reserved_block_count())
36            + (u32::from(bpb.num_fats()) * bpb.fat_size())
37            + root_dir_blocks;
38        let data_blocks = bpb.total_blocks() - non_data_blocks;
39        bpb.cluster_count = data_blocks / u32::from(bpb.blocks_per_cluster());
40        if bpb.cluster_count < 4085 {
41            return Err("FAT12 is unsupported");
42        } else if bpb.cluster_count < 65525 {
43            bpb.fat_type = FatType::Fat16;
44        } else {
45            bpb.fat_type = FatType::Fat32;
46        }
47
48        match bpb.fat_type {
49            FatType::Fat16 => Ok(bpb),
50            FatType::Fat32 if bpb.fs_ver() == 0 => {
51                // Only support FAT32 version 0.0
52                Ok(bpb)
53            }
54            _ => Err("Invalid FAT format"),
55        }
56    }
57
58    // FAT16/FAT32
59    define_field!(bytes_per_block, u16, 11);
60    define_field!(blocks_per_cluster, u8, 13);
61    define_field!(reserved_block_count, u16, 14);
62    define_field!(num_fats, u8, 16);
63    define_field!(root_entries_count, u16, 17);
64    define_field!(total_blocks16, u16, 19);
65    define_field!(media, u8, 21);
66    define_field!(fat_size16, u16, 22);
67    define_field!(blocks_per_track, u16, 24);
68    define_field!(num_heads, u16, 26);
69    define_field!(hidden_blocks, u32, 28);
70    define_field!(total_blocks32, u32, 32);
71    define_field!(footer, u16, 510);
72
73    // FAT32 only
74    define_field!(fat_size32, u32, 36);
75    define_field!(fs_ver, u16, 42);
76    define_field!(first_root_dir_cluster, u32, 44);
77    define_field!(fs_info, u16, 48);
78    define_field!(backup_boot_block, u16, 50);
79
80    /// Get the OEM name string for this volume
81    pub fn oem_name(&self) -> &[u8] {
82        &self.data[3..11]
83    }
84
85    // FAT16/FAT32 functions
86
87    /// Get the Volume Label string for this volume
88    pub fn volume_label(&self) -> &[u8] {
89        if self.fat_type != FatType::Fat32 {
90            &self.data[43..=53]
91        } else {
92            &self.data[71..=81]
93        }
94    }
95
96    // FAT32 only functions
97
98    /// On a FAT32 volume, return the free block count from the Info Block. On
99    /// a FAT16 volume, returns None.
100    pub fn fs_info_block(&self) -> Option<BlockCount> {
101        if self.fat_type != FatType::Fat32 {
102            None
103        } else {
104            Some(BlockCount(u32::from(self.fs_info())))
105        }
106    }
107
108    // Magic functions that get the right FAT16/FAT32 result
109
110    /// Get the size of the File Allocation Table in blocks.
111    pub fn fat_size(&self) -> u32 {
112        let result = u32::from(self.fat_size16());
113        if result != 0 {
114            result
115        } else {
116            self.fat_size32()
117        }
118    }
119
120    /// Get the total number of blocks in this filesystem.
121    pub fn total_blocks(&self) -> u32 {
122        let result = u32::from(self.total_blocks16());
123        if result != 0 {
124            result
125        } else {
126            self.total_blocks32()
127        }
128    }
129
130    /// Get the total number of clusters in this filesystem.
131    pub fn total_clusters(&self) -> u32 {
132        self.cluster_count
133    }
134}
135
136// ****************************************************************************
137//
138// End Of File
139//
140// ****************************************************************************