extern crate fatfs; use std::{cmp, fs, io}; use std::io::{prelude::*, SeekFrom, ErrorKind}; use fatfs::{FileSystem, FsOptions, BufStream}; trait ReadWriteSeek: Read + Write + Seek {} impl ReadWriteSeek for T where T: Read + Write + Seek {} // File wrapper for accessing part of file #[derive(Clone)] pub(crate) struct Partition { inner: T, start_offset: u64, current_offset: u64, size: u64, } impl Partition { pub(crate) fn new(mut inner: T, start_offset: u64, size: u64) -> io::Result { inner.seek(SeekFrom::Start(start_offset))?; Ok(Self { start_offset, size, inner, current_offset: 0, }) } } impl Read for Partition { fn read(&mut self, buf: &mut [u8]) -> io::Result { let max_read_size = cmp::min((self.size - self.current_offset) as usize, buf.len()); let bytes_read = self.inner.read(&mut buf[..max_read_size])?; self.current_offset += bytes_read as u64; Ok(bytes_read) } } impl Write for Partition { fn write(&mut self, buf: &[u8]) -> io::Result { let max_write_size = cmp::min((self.size - self.current_offset) as usize, buf.len()); let bytes_written = self.inner.write(&buf[..max_write_size])?; self.current_offset += bytes_written as u64; Ok(bytes_written) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } impl Seek for Partition { fn seek(&mut self, pos: SeekFrom) -> io::Result { let new_offset = match pos { SeekFrom::Current(x) => self.current_offset as i64 + x, SeekFrom::Start(x) => x as i64, SeekFrom::End(x) => self.size as i64 + x, }; if new_offset < 0 || new_offset as u64 > self.size { Err(io::Error::new(ErrorKind::InvalidInput, "invalid seek")) } else { self.inner.seek(SeekFrom::Start(self.start_offset + new_offset as u64))?; self.current_offset = new_offset as u64; Ok(self.current_offset) } } } fn main() { // Open disk image let file = fs::File::open("resources/fat32.img").unwrap(); // Provide sample partition localization. In real application it should be read from MBR/GPT. let first_lba = 0; let last_lba = 10000; // Create partition using provided start address and size in bytes let partition = Partition::::new(file, first_lba, last_lba - first_lba + 1).unwrap(); // Create buffered stream to optimize file access let mut buf_rdr = BufStream::new(partition); // Finally initialize filesystem struct using provided partition let fs = FileSystem::new(&mut buf_rdr, FsOptions::new()).unwrap(); // Read and display volume label println!("Volume Label: {}", fs.volume_label()); // other operations }