Files
riscv64-kernel/crates/bffs/src/lib.rs

152 lines
4.6 KiB
Rust

#![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<T: Read + Seek> ReadSeek for T {}
pub trait WriteSeek: Write + Seek {}
impl<T: Write + Seek> WriteSeek for T {}
pub trait ReadWriteSeek: Read + Write + Seek {}
impl<T: Read + Write + Seek> 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<T: Read>(disk: &mut T) -> Result<Self, Error<T::Error>> {
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<T> {
device: RefCell<T>,
pub boot_sector: Fat32BootSector,
}
impl<T> Display for Fat32FileSystem<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.boot_sector.fmt(f)
}
}
impl<T: ReadSeek> Fat32FileSystem<T> {
pub fn new(mut device: T) -> Result<Self, Error<T::Error>> {
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<u32, Error<T::Error>> {
let fat_offset =
self.fat_start_offset() + (current_cluster as u64 * size_of::<FatEntry>() 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<T> Fat32FileSystem<T> {
/// 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<T: ReadSeek> Fat32FileSystem<T> {
pub fn open_entry<P: AsRef<Path>>(&self, path: P) -> Result<DirEntry<'_, T>, Error<T::Error>> {
let path = path.as_ref().as_str().trim_start_matches("/");
self.root_directory().open_entry(path)
}
pub fn open_dir<P: AsRef<Path>>(&self, path: P) -> Result<Dir<'_, T>, Error<T::Error>> {
let path = path.as_ref().as_str().trim_start_matches("/");
self.root_directory().open_dir(path)
}
pub fn open_file<P: AsRef<Path>>(&self, path: P) -> Result<File<'_, T>, Error<T::Error>> {
let path = path.as_ref().as_str().trim_start_matches("/");
self.root_directory().open_file(path)
}
}