#![feature(iterator_try_collect, iter_order_by)] #![cfg_attr(any(not(feature = "std"), target_arch = "riscv64"), no_std)] use core::cell::RefCell; use core::fmt::Display; use crate::{ boot_sector::Fat32BootSector, consts::FAT32_CLUSTER_MASK, dir::Dir, entry::{DirEntry, FatEntry}, error::Error, file::{File, RawFile}, path::Path, }; use io::{Read, ReadLeExt, Seek, Write}; #[cfg(feature = "alloc")] extern crate alloc; pub mod boot_sector; pub mod consts; pub mod dir; pub mod entry; pub mod error; pub mod file; pub mod path; pub trait ReadSeek: Read + Seek {} impl ReadSeek for T {} pub trait WriteSeek: Write + Seek {} impl WriteSeek for T {} pub trait ReadWriteSeek: Read + Write + Seek {} impl ReadWriteSeek for T {} #[derive(Debug, Clone, Copy)] pub struct Fat32FsInfo { pub lead_signature: u32, pub reserved1: [u8; 480], pub struct_signature: u32, pub free_count: u32, pub next_free: u32, pub reserved2: [u8; 12], pub trail_signature: u32, } impl Fat32FsInfo { pub fn deserialize(disk: &mut T) -> Result> { let lead_signature = disk.read_u32_le()?; let mut reserved1 = [0u8; _]; disk.read_exact(&mut reserved1)?; let struct_signature = disk.read_u32_le()?; let free_count = disk.read_u32_le()?; let next_free = disk.read_u32_le()?; let mut reserved2 = [0u8; _]; disk.read_exact(&mut reserved2)?; let trail_signature = disk.read_u32_le()?; Ok(Self { lead_signature, reserved1, struct_signature, free_count, next_free, reserved2, trail_signature, }) } } #[derive(Debug)] pub struct Fat32FileSystem { device: RefCell, pub boot_sector: Fat32BootSector, } impl Display for Fat32FileSystem { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.boot_sector.fmt(f) } } impl Fat32FileSystem { pub fn new(mut device: T) -> Result> { device.seek(io::SeekFrom::Start(0))?; let boot_sector = Fat32BootSector::deserialize(&mut device)?; Ok(Self { device: device.into(), boot_sector, }) } /// Get the next cluster from the current one fn get_next_cluster(&self, current_cluster: u32) -> Result> { let fat_offset = self.fat_start_offset() + (current_cluster as u64 * size_of::() as u64); self.device .borrow_mut() .seek(io::SeekFrom::Start(fat_offset))?; let next = self.device.borrow_mut().read_u32_le()? & FAT32_CLUSTER_MASK; Ok(next) } } impl Fat32FileSystem { /// Start offset of the FAT pub fn fat_start_offset(&self) -> u64 { (self.boot_sector.reserved_sector_count as u64) * (self.boot_sector.bytes_per_sector as u64) } /// Start offset for data fn data_start_offset(&self) -> u64 { let fat_size = self.boot_sector.fat_size_32 as u64; let fats = (self.boot_sector.num_fats as u64) * fat_size; fats * self.boot_sector.bytes_per_sector as u64 + self.fat_start_offset() } /// Convert a cluster number to an offset fn cluster_to_offset(&self, cluster: u32) -> u64 { let cluster_offset = (cluster.saturating_sub(2)) as u64 * self.boot_sector.sectors_per_cluster as u64 * self.boot_sector.bytes_per_sector as u64; self.data_start_offset() + cluster_offset } fn cluster_size(&self) -> u64 { (self.boot_sector.sectors_per_cluster as u64) * (self.boot_sector.bytes_per_sector as u64) } pub fn root_directory(&self) -> Dir<'_, T> { Dir::new( RawFile::new(self, self.boot_sector.root_cluster, None), self, ) } } impl Fat32FileSystem { pub fn open_entry>(&self, path: P) -> Result, Error> { let path = path.as_ref().as_str().trim_start_matches("/"); self.root_directory().open_entry(path) } pub fn open_dir>(&self, path: P) -> Result, Error> { let path = path.as_ref().as_str().trim_start_matches("/"); self.root_directory().open_dir(path) } pub fn open_file>(&self, path: P) -> Result, Error> { let path = path.as_ref().as_str().trim_start_matches("/"); self.root_directory().open_file(path) } }