embedded_fat/
blockdevice.rs

1//! Block Device support
2//!
3//! Generic code for handling block devices, such as types for identifying
4//! a particular block on a block device by its index.
5
6/// Represents a standard 512 byte block (also known as a sector). IBM PC
7/// formatted 5.25" and 3.5" floppy disks, SD/MMC cards up to 1 GiB in size
8/// and IDE/SATA Hard Drives up to about 2 TiB all have 512 byte blocks.
9///
10/// This library does not support devices with a block size other than 512
11/// bytes.
12#[derive(Clone)]
13pub struct Block {
14    /// The 512 bytes in this block (or sector).
15    pub contents: [u8; Block::LEN],
16}
17
18/// Represents the linear numeric address of a block (or sector). The first
19/// block on a disk gets `BlockIdx(0)` (which usually contains the Master Boot
20/// Record).
21#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
22#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
23pub struct BlockIdx(pub u32);
24
25/// Represents the a number of blocks (or sectors). Add this to a `BlockIdx`
26/// to get an actual address on disk.
27#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
28#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
29pub struct BlockCount(pub u32);
30
31/// An iterator returned from `Block::range`.
32pub struct BlockIter {
33    inclusive_end: BlockIdx,
34    current: BlockIdx,
35}
36
37/// Represents a block device - a device which can read and write blocks (or
38/// sectors). Only supports devices which are <= 2 TiB in size.
39pub trait BlockDevice {
40    /// The errors that the `BlockDevice` can return. Must be debug formattable.
41    type Error: core::fmt::Debug;
42    /// Read one or more blocks, starting at the given block index.
43    async fn read(
44        &self,
45        blocks: &mut [Block],
46        start_block_idx: BlockIdx,
47        reason: &str,
48    ) -> Result<(), Self::Error>;
49    /// Write one or more blocks, starting at the given block index.
50    async fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> Result<(), Self::Error>;
51    /// Determine how many blocks this device can hold.
52    async fn num_blocks(&self) -> Result<BlockCount, Self::Error>;
53}
54
55impl Block {
56    /// All our blocks are a fixed length of 512 bytes. We do not support
57    /// 'Advanced Format' Hard Drives with 4 KiB blocks, nor weird old
58    /// pre-3.5-inch floppy disk formats.
59    pub const LEN: usize = 512;
60
61    /// Sometimes we want `LEN` as a `u32` and the casts don't look nice.
62    pub const LEN_U32: u32 = 512;
63
64    /// Create a new block full of zeros.
65    pub fn new() -> Block {
66        Block {
67            contents: [0u8; Self::LEN],
68        }
69    }
70}
71
72impl Default for Block {
73    fn default() -> Self {
74        Self::new()
75    }
76}
77
78impl core::ops::Add<BlockCount> for BlockIdx {
79    type Output = BlockIdx;
80    fn add(self, rhs: BlockCount) -> BlockIdx {
81        BlockIdx(self.0 + rhs.0)
82    }
83}
84
85impl core::ops::AddAssign<BlockCount> for BlockIdx {
86    fn add_assign(&mut self, rhs: BlockCount) {
87        self.0 += rhs.0
88    }
89}
90
91impl core::ops::Add<BlockCount> for BlockCount {
92    type Output = BlockCount;
93    fn add(self, rhs: BlockCount) -> BlockCount {
94        BlockCount(self.0 + rhs.0)
95    }
96}
97
98impl core::ops::AddAssign<BlockCount> for BlockCount {
99    fn add_assign(&mut self, rhs: BlockCount) {
100        self.0 += rhs.0
101    }
102}
103
104impl core::ops::Sub<BlockCount> for BlockIdx {
105    type Output = BlockIdx;
106    fn sub(self, rhs: BlockCount) -> BlockIdx {
107        BlockIdx(self.0 - rhs.0)
108    }
109}
110
111impl core::ops::SubAssign<BlockCount> for BlockIdx {
112    fn sub_assign(&mut self, rhs: BlockCount) {
113        self.0 -= rhs.0
114    }
115}
116
117impl core::ops::Sub<BlockCount> for BlockCount {
118    type Output = BlockCount;
119    fn sub(self, rhs: BlockCount) -> BlockCount {
120        BlockCount(self.0 - rhs.0)
121    }
122}
123
124impl core::ops::SubAssign<BlockCount> for BlockCount {
125    fn sub_assign(&mut self, rhs: BlockCount) {
126        self.0 -= rhs.0
127    }
128}
129
130impl core::ops::Deref for Block {
131    type Target = [u8; 512];
132    fn deref(&self) -> &[u8; 512] {
133        &self.contents
134    }
135}
136
137impl core::ops::DerefMut for Block {
138    fn deref_mut(&mut self) -> &mut [u8; 512] {
139        &mut self.contents
140    }
141}
142
143impl core::fmt::Debug for Block {
144    fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result {
145        writeln!(fmt, "Block:")?;
146        for line in self.contents.chunks(32) {
147            for b in line {
148                write!(fmt, "{:02x}", b)?;
149            }
150            write!(fmt, " ")?;
151            for &b in line {
152                if (0x20..=0x7F).contains(&b) {
153                    write!(fmt, "{}", b as char)?;
154                } else {
155                    write!(fmt, ".")?;
156                }
157            }
158            writeln!(fmt)?;
159        }
160        Ok(())
161    }
162}
163
164impl BlockIdx {
165    /// Convert a block index into a 64-bit byte offset from the start of the
166    /// volume. Useful if your underlying block device actually works in
167    /// bytes, like `open("/dev/mmcblk0")` does on Linux.
168    pub fn into_bytes(self) -> u64 {
169        (u64::from(self.0)) * (Block::LEN as u64)
170    }
171
172    /// Create an iterator from the current `BlockIdx` through the given
173    /// number of blocks.
174    pub fn range(self, num: BlockCount) -> BlockIter {
175        BlockIter::new(self, self + BlockCount(num.0))
176    }
177}
178
179impl BlockCount {
180    /// How many blocks are required to hold this many bytes.
181    ///
182    /// ```
183    /// # use embedded_sdmmc::BlockCount;
184    /// assert_eq!(BlockCount::from_bytes(511), BlockCount(1));
185    /// assert_eq!(BlockCount::from_bytes(512), BlockCount(1));
186    /// assert_eq!(BlockCount::from_bytes(513), BlockCount(2));
187    /// assert_eq!(BlockCount::from_bytes(1024), BlockCount(2));
188    /// assert_eq!(BlockCount::from_bytes(1025), BlockCount(3));
189    /// ```
190    pub const fn from_bytes(byte_count: u32) -> BlockCount {
191        let mut count = byte_count / Block::LEN_U32;
192        if (count * Block::LEN_U32) != byte_count {
193            count += 1;
194        }
195        BlockCount(count)
196    }
197
198    /// Take a number of blocks and increment by the integer number of blocks
199    /// required to get to the block that holds the byte at the given offset.
200    pub fn offset_bytes(self, offset: u32) -> Self {
201        BlockCount(self.0 + (offset / Block::LEN_U32))
202    }
203}
204
205impl BlockIter {
206    /// Create a new `BlockIter`, from the given start block, through (and
207    /// including) the given end block.
208    pub const fn new(start: BlockIdx, inclusive_end: BlockIdx) -> BlockIter {
209        BlockIter {
210            inclusive_end,
211            current: start,
212        }
213    }
214}
215
216impl core::iter::Iterator for BlockIter {
217    type Item = BlockIdx;
218    fn next(&mut self) -> Option<Self::Item> {
219        if self.current.0 >= self.inclusive_end.0 {
220            None
221        } else {
222            let this = self.current;
223            self.current += BlockCount(1);
224            Some(this)
225        }
226    }
227}