exfat-slim 0.5.0

An exFAT file system library written in safe Rust for embedded environments
Documentation
use crate::common::BLOCK_SIZE;

use super::{EXAMPLE_EXFAT_IMAGE, print};
use aligned::{A4, Aligned};
use block_device_driver::{blocks_to_slice, blocks_to_slice_mut};
use exfat_slim::blocking::BlockDevice;
use flate2::read::GzDecoder;
use std::{
    fs,
    io::Read,
    sync::{Arc, Mutex},
};

#[derive(Clone, Debug)]
pub struct InMemoryBlockDevice {
    inner: Arc<Mutex<Inner>>,
}

impl InMemoryBlockDevice {
    pub fn new() -> Self {
        let inner = Arc::new(Mutex::new(Inner::new()));
        Self { inner }
    }
}

impl BlockDevice<BLOCK_SIZE> for InMemoryBlockDevice {
    type Error = String;
    type Align = A4;

    fn read(
        &mut self,
        sector_id: u32,
        block: &mut [Aligned<Self::Align, [u8; BLOCK_SIZE]>],
    ) -> Result<(), Self::Error> {
        let mut g = self.inner.lock().unwrap();
        g.read_sector(sector_id, block)
    }

    fn write(
        &mut self,
        sector_id: u32,
        block: &[Aligned<Self::Align, [u8; BLOCK_SIZE]>],
    ) -> Result<(), Self::Error> {
        let mut g = self.inner.lock().unwrap();
        g.write_sector(sector_id, block)
    }

    fn size(&mut self) -> Result<u64, Self::Error> {
        todo!()
    }
}

#[derive(Debug)]
pub struct Inner {
    pub image: Vec<u8>,
    pub sector_offset: u32,
    pub data_block: [u8; BLOCK_SIZE],
    last_sector: Option<u32>,
}

impl Inner {
    pub fn new() -> Self {
        // this sd card image is 10MB uncompressed
        let buf = fs::read(EXAMPLE_EXFAT_IMAGE).unwrap();
        let mut reader = GzDecoder::new(buf.as_slice());
        let mut image = Vec::new();
        reader.read_to_end(&mut image).unwrap();

        Self {
            image,
            sector_offset: 0,
            data_block: [0; BLOCK_SIZE],
            last_sector: None,
        }
    }

    pub fn read_sector(
        &mut self,
        sector_id: u32,
        block: &mut [Aligned<A4, [u8; BLOCK_SIZE]>],
    ) -> Result<(), String> {
        let sector_id_with_offset = sector_id + self.sector_offset;
        match self.last_sector.as_ref() {
            Some(x) if *x == sector_id_with_offset => {
                print("READ", sector_id_with_offset, sector_id, true)
            }
            _ => {
                print("READ", sector_id_with_offset, sector_id, false);
                self.last_sector = Some(sector_id_with_offset);
            }
        }

        let pos = sector_id_with_offset as usize * BLOCK_SIZE;

        let slice = blocks_to_slice_mut(block);
        slice.copy_from_slice(&self.image[pos..pos + BLOCK_SIZE]);

        Ok(())
    }

    pub fn write_sector(
        &mut self,
        sector_id: u32,
        block: &[Aligned<A4, [u8; BLOCK_SIZE]>],
    ) -> Result<(), String> {
        let sector_id_with_offset = sector_id + self.sector_offset;
        print("WRITE", sector_id_with_offset, sector_id, false);
        let start = sector_id_with_offset as usize * BLOCK_SIZE;
        let end = start + BLOCK_SIZE;

        let max_len = self.image.len();
        if end <= max_len {
            let slice = blocks_to_slice(block);
            self.image[start..end].copy_from_slice(slice);
            self.last_sector = None;
            Ok(())
        } else {
            let error = format!(
                "attempt to write past end of image of len {}: {}",
                max_len, end
            );
            Err(error)
        }
    }
}