buf_fs/
device.rs

1use core::cell::RefCell;
2
3use alloc::{rc::Rc, vec, vec::Vec};
4use embedded_sdmmc::{
5    Block, BlockCount, BlockDevice, BlockIdx, TimeSource, Timestamp, VolumeManager,
6};
7
8use crate::mbr;
9
10/// A MBR FAT-16 compatible device emulator.
11#[derive(Default, Clone)]
12pub struct Device {
13    bytes: Rc<RefCell<Vec<u8>>>,
14    resize_chunk: usize,
15    min_len: usize,
16    max_blocks: usize,
17}
18
19impl Device {
20    /// The minimum size in bytes supported by the FAT-16.
21    pub const MIN_SIZE: usize = 2_141_184;
22
23    /// The maximum size in bytes supported by the FAT-16.
24    pub const MAX_SIZE: usize = 2 * 1024 * 1024 * 1024;
25
26    /// Attempts to create a new device with the provided amount of bytes.
27    pub fn new(size: usize) -> anyhow::Result<Self> {
28        anyhow::ensure!(
29            Self::MIN_SIZE <= size,
30            "the provided amount of bytes `{size}` is below the lower limit of `{}`",
31            Self::MIN_SIZE
32        );
33
34        anyhow::ensure!(
35            size <= Self::MAX_SIZE,
36            "the provided amount of bytes `{size}` is above the upper limit of `{}`",
37            Self::MAX_SIZE
38        );
39
40        let bytes = mbr::create_mbr_with_fat(size)?;
41
42        Ok(Self {
43            bytes: Rc::new(RefCell::new(bytes)),
44            resize_chunk: 0,
45            min_len: 0,
46            max_blocks: 0,
47        })
48    }
49
50    /// Attempts to serialize the structure into raw device (MBR+part0) bytes.
51    ///
52    /// The only failure is if the device is borrowed mutably elsewhere.
53    pub fn try_to_raw_bytes(&self) -> anyhow::Result<Vec<u8>> {
54        Ok(self.bytes.try_borrow()?.clone())
55    }
56
57    /// Attempts to deserialize the structure from raw device (MBR+FAT16).
58    ///
59    /// This device can be mounted using any fstools such as fdisk and mkfs.fat.
60    pub fn from_raw_bytes_unchecked(bytes: Vec<u8>) -> Self {
61        Self {
62            bytes: Rc::new(RefCell::new(bytes)),
63            resize_chunk: 0,
64            min_len: 0,
65            max_blocks: 0,
66        }
67    }
68
69    /// Serializes the structure into bytes.
70    pub fn try_to_bytes(&self) -> anyhow::Result<Vec<u8>> {
71        let bytes = self.bytes.try_borrow()?;
72        let mut buffer = vec![0u8; bytes.len() + 24];
73
74        buffer[0..8].copy_from_slice(&(self.resize_chunk as u64).to_le_bytes());
75        buffer[8..16].copy_from_slice(&(self.min_len as u64).to_le_bytes());
76        buffer[16..24].copy_from_slice(&(self.max_blocks as u64).to_le_bytes());
77        buffer[24..].copy_from_slice(&bytes);
78
79        Ok(buffer)
80    }
81
82    /// Deserializes the structure into bytes.
83    pub fn try_from_bytes(buffer: &[u8]) -> anyhow::Result<Self> {
84        anyhow::ensure!(buffer.len() > 24, "buffer is too small.");
85
86        let mut resize_chunk = [0u8; 8];
87        let mut min_len = [0u8; 8];
88        let mut max_blocks = [0u8; 8];
89
90        resize_chunk.copy_from_slice(&buffer[..8]);
91        min_len.copy_from_slice(&buffer[8..16]);
92        max_blocks.copy_from_slice(&buffer[16..24]);
93
94        let bytes = buffer[24..].to_vec();
95
96        Ok(Self {
97            bytes: Rc::new(RefCell::new(bytes)),
98            resize_chunk: u64::from_le_bytes(resize_chunk) as usize,
99            min_len: u64::from_le_bytes(min_len) as usize,
100            max_blocks: u64::from_le_bytes(max_blocks) as usize,
101        })
102    }
103
104    /// Creates a device with the provided minimum length of the buffer.
105    pub fn with_min_len(mut self, min_len: usize) -> Self {
106        self.min_len = min_len;
107        self
108    }
109
110    /// Creates a device with the provided maximum length of the buffer.
111    pub fn with_max_len(mut self, max_len: usize) -> Self {
112        self.max_blocks = max_len / Block::LEN;
113        self
114    }
115
116    /// Creates a device with the provided minimum chunk length increase.
117    pub fn with_resize_chunk(mut self, resize_chunk: usize) -> Self {
118        self.resize_chunk = resize_chunk;
119        self
120    }
121
122    /// Opens the device into a MBR volumes manager.
123    pub fn open(self) -> VolumeManager<Self, Clock> {
124        VolumeManager::new(self, Clock::default())
125    }
126}
127
128impl BlockDevice for Device {
129    type Error = anyhow::Error;
130
131    fn read(
132        &self,
133        blocks: &mut [Block],
134        start_block_idx: BlockIdx,
135        reason: &str,
136    ) -> anyhow::Result<()> {
137        let idx = start_block_idx.0 as usize;
138        let idx = idx
139            .checked_mul(Block::LEN)
140            .ok_or_else(|| anyhow::anyhow!("block idx overflow: {reason}"))?;
141
142        let bytes = self
143            .bytes
144            .try_borrow()
145            .map_err(|e| anyhow::anyhow!("device blocked `{e}`: {reason}"))?;
146
147        for i in 0..blocks.len() {
148            let ofs = idx + i * Block::LEN;
149            let end = ofs + Block::LEN;
150
151            if end <= bytes.len() {
152                blocks[i].contents.copy_from_slice(&bytes[ofs..end]);
153            } else {
154                blocks[i].contents.fill(0);
155            }
156        }
157
158        Ok(())
159    }
160
161    fn write(&self, blocks: &[Block], start_block_idx: BlockIdx) -> anyhow::Result<()> {
162        let idx = start_block_idx.0 as usize;
163        let idx = idx
164            .checked_mul(Block::LEN)
165            .ok_or_else(|| anyhow::anyhow!("block idx overflow"))?;
166
167        let len = blocks
168            .len()
169            .checked_mul(Block::LEN)
170            .ok_or_else(|| anyhow::anyhow!("block len overflow"))?;
171
172        let last = idx
173            .checked_add(len)
174            .ok_or_else(|| anyhow::anyhow!("block last overflow"))?;
175
176        let mut bytes = self.bytes.try_borrow_mut()?;
177
178        if last > bytes.len() {
179            anyhow::ensure!(
180                self.max_blocks == 0 || last <= self.max_blocks * Block::LEN,
181                "write attempt to overflow maximum length"
182            );
183
184            let last = last.max(self.min_len).max(bytes.len() + self.resize_chunk);
185
186            bytes.resize(last, 0);
187        }
188
189        for i in 0..blocks.len() {
190            let ofs = idx + i * Block::LEN;
191
192            bytes[ofs..ofs + Block::LEN].copy_from_slice(&blocks[i].contents);
193        }
194
195        Ok(())
196    }
197
198    fn num_blocks(&self) -> anyhow::Result<BlockCount> {
199        let len = self.bytes.try_borrow()?.len();
200        let len = len / Block::LEN;
201
202        Ok(BlockCount(len as u32))
203    }
204}
205
206/// A monotonically increasing clock emulator.
207///
208/// We don't use real time as it is incompatible with several embedded systesm.
209#[derive(Debug)]
210pub struct Clock {
211    ts: RefCell<Timestamp>,
212    def: Timestamp,
213}
214
215impl Default for Clock {
216    fn default() -> Self {
217        let ts = Timestamp::from_calendar(1980, 01, 01, 13, 30, 05).expect("invalid initial ts");
218
219        Self {
220            ts: RefCell::new(ts),
221            def: ts,
222        }
223    }
224}
225
226impl TimeSource for Clock {
227    fn get_timestamp(&self) -> Timestamp {
228        let ts = { self.ts.try_borrow().map(|t| *t).unwrap_or(self.def) };
229
230        {
231            let mut tsp = ts;
232
233            tsp.seconds += 1;
234            if tsp.seconds == 60 {
235                tsp.minutes += 1;
236                tsp.seconds = 0;
237            }
238            if tsp.minutes == 60 {
239                tsp.hours += 1;
240                tsp.minutes = 0;
241            }
242            if tsp.hours == 24 {
243                tsp.zero_indexed_day += 1;
244                tsp.hours = 0;
245            }
246            if tsp.zero_indexed_day == 27 {
247                tsp.zero_indexed_month += 1;
248                tsp.zero_indexed_day = 0;
249            }
250            if tsp.zero_indexed_month == 12 {
251                tsp.year_since_1970 += 1;
252                tsp.zero_indexed_month = 0;
253            }
254
255            if let Ok(mut t) = self.ts.try_borrow_mut() {
256                *t = tsp;
257            }
258        }
259
260        ts
261    }
262}