mod any;
#[cfg(feature = "exfat")]
mod exfat;
#[cfg(feature = "fat")]
mod fat;
#[cfg(feature = "littlefs")]
mod littlefs;
#[cfg(test)]
mod tests;
pub use any::{
AnyDir, AnyDirIter, AnyError, AnyFile, AnyVolume, FormatAs, Found, format, mount, mount_found,
probe,
};
#[cfg(feature = "exfat")]
pub use exfat::ExfatDirIter;
#[cfg(feature = "fat")]
pub use fat::FatDirIter;
#[cfg(feature = "littlefs")]
pub use littlefs::LittleFsDirIter;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum FsType {
Fat,
Exfat,
LittleFs,
}
impl FsType {
pub fn as_str(self) -> &'static str {
match self {
FsType::Fat => "fat",
FsType::Exfat => "exfat",
FsType::LittleFs => "littlefs",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Kind {
File,
Dir,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Metadata {
kind: Kind,
len: u64,
}
impl Metadata {
pub fn new(kind: Kind, len: u64) -> Self {
Self { kind, len }
}
pub fn kind(&self) -> Kind {
self.kind
}
pub fn is_dir(&self) -> bool {
self.kind == Kind::Dir
}
pub fn is_file(&self) -> bool {
self.kind == Kind::File
}
pub fn len(&self) -> u64 {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
}
#[derive(Debug, Clone, Copy)]
pub struct Entry<'a> {
name: &'a [u8],
meta: Metadata,
}
impl<'a> Entry<'a> {
pub fn new(name: &'a [u8], meta: Metadata) -> Self {
Self { name, meta }
}
pub fn name(&self) -> &'a [u8] {
self.name
}
pub fn name_str(&self) -> Option<&'a str> {
core::str::from_utf8(self.name).ok()
}
pub fn metadata(&self) -> Metadata {
self.meta
}
pub fn is_dir(&self) -> bool {
self.meta.is_dir()
}
pub fn len(&self) -> u64 {
self.meta.len
}
pub fn is_empty(&self) -> bool {
self.meta.len == 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ErrorKind {
Io,
NotRecognised,
Geometry,
Corrupt,
Unsupported,
ReadOnly,
NotFound,
NotADirectory,
IsADirectory,
AlreadyExists,
DirectoryNotEmpty,
InvalidName,
InvalidPath,
DirectoryFull,
NoSpace,
FileTooLarge,
InvalidOffset,
WrongVolume,
}
pub trait VolumeError {
fn kind(&self) -> ErrorKind;
fn is_not_found(&self) -> bool {
self.kind() == ErrorKind::NotFound
}
}
pub trait Volume: Sized {
type Error: VolumeError;
type Device;
type File: VolumeFile<Self> + core::fmt::Debug;
type Dir: Copy + core::fmt::Debug;
type DirIter<'a>: VolumeDirIter<Error = Self::Error>
where
Self: 'a;
fn fs_type(&self) -> FsType;
fn root(&self) -> Self::Dir;
fn open_dir(&mut self, path: &str) -> Result<Self::Dir, Self::Error>;
fn iter_dir(&mut self, dir: Self::Dir) -> Self::DirIter<'_>;
fn metadata(&mut self, path: &str) -> Result<Metadata, Self::Error>;
fn exists(&mut self, path: &str) -> Result<bool, Self::Error> {
match self.metadata(path) {
Ok(_) => Ok(true),
Err(e) if e.is_not_found() => Ok(false),
Err(e) => Err(e),
}
}
fn create_dir(&mut self, path: &str) -> Result<Self::Dir, Self::Error>;
fn remove_dir(&mut self, path: &str) -> Result<(), Self::Error>;
fn remove_file(&mut self, path: &str) -> Result<(), Self::Error>;
fn open_file(&mut self, path: &str) -> Result<Self::File, Self::Error>;
fn create_file(&mut self, path: &str) -> Result<Self::File, Self::Error>;
fn open_or_create_file(&mut self, path: &str) -> Result<Self::File, Self::Error>;
fn flush(&mut self) -> Result<(), Self::Error>;
fn total_bytes(&self) -> u64;
fn free_bytes(&mut self) -> Result<u64, Self::Error>;
fn statfs(&mut self) -> Result<crate::fs::StatFs, Self::Error> {
const UNIT: u64 = 512;
let blocks = self.total_bytes() / UNIT;
let free = self.free_bytes()? / UNIT;
Ok(crate::fs::StatFs {
block_size: UNIT as u32,
blocks,
blocks_free: free,
blocks_avail: free,
inodes: 0,
inodes_free: 0,
name_max: 255,
})
}
fn unmount(self) -> Result<Self::Device, Self::Error>;
}
pub trait VolumeFile<V: Volume> {
fn len(&self) -> u64;
fn is_empty(&self) -> bool {
self.len() == 0
}
fn pos(&self) -> u64;
fn seek(&mut self, vol: &mut V, pos: u64) -> Result<(), V::Error>;
fn seek_to_end(&mut self, vol: &mut V) -> Result<(), V::Error> {
let len = self.len();
self.seek(vol, len)
}
fn read(&mut self, vol: &mut V, buf: &mut [u8]) -> Result<usize, V::Error>;
fn read_exact(&mut self, vol: &mut V, buf: &mut [u8]) -> Result<(), V::Error>;
fn write(&mut self, vol: &mut V, buf: &[u8]) -> Result<usize, V::Error>;
fn write_all(&mut self, vol: &mut V, buf: &[u8]) -> Result<(), V::Error>;
fn set_len(&mut self, vol: &mut V, len: u64) -> Result<(), V::Error>;
fn flush(&mut self, vol: &mut V) -> Result<(), V::Error>;
}
pub trait VolumeDirIter {
type Error: VolumeError;
fn next(&mut self) -> Result<Option<Entry<'_>>, Self::Error>;
}