Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ exclude = [

[features]
# Use Rust std library
std = []
std = ["embedded-io/std"]
# LFN (Long File Name) support
lfn = []
# Use dynamic allocation. When used without std please enable core_io/collections
Expand All @@ -41,6 +41,7 @@ default = ["chrono", "std", "alloc", "lfn", "unicode", "log_level_trace"]
[dependencies]
bitflags = "1.0"
log = "0.4"
embedded-io = "0.4.0"
chrono = { version = "0.4", default-features = false, features = ["clock"], optional = true }

[dev-dependencies]
Expand Down
20 changes: 14 additions & 6 deletions src/boot_sector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::u16;
use core::u8;

use crate::dir_entry::DIR_ENTRY_SIZE;
use crate::error::{Error, IoError};
use crate::error::{Error, IoError, ReadExactError};
use crate::fs::{FatType, FormatVolumeOptions, FsStatusFlags};
use crate::io::{Read, ReadLeExt, Write, WriteLeExt};
use crate::table::RESERVED_FAT_ENTRIES;
Expand Down Expand Up @@ -46,7 +46,10 @@ pub(crate) struct BiosParameterBlock {
}

impl BiosParameterBlock {
fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, R::Error> {
fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, R::Error>
where
R::Error: From<ReadExactError<R::Error>>,
{
let mut bpb = Self {
bytes_per_sector: rdr.read_u16_le()?,
sectors_per_cluster: rdr.read_u8()?,
Expand Down Expand Up @@ -420,7 +423,10 @@ pub(crate) struct BootSector {
}

impl BootSector {
pub(crate) fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, R::Error> {
pub(crate) fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, R::Error>
where
R::Error: From<ReadExactError<R::Error>>,
{
let mut boot = Self::default();
rdr.read_exact(&mut boot.bootjmp)?;
rdr.read_exact(&mut boot.oem_name)?;
Expand Down Expand Up @@ -802,6 +808,7 @@ pub(crate) fn format_boot_sector<E: IoError>(
#[cfg(test)]
mod tests {
use super::*;
use crate::io::StdErrWrapper;
use core::u32;

fn init() {
Expand Down Expand Up @@ -972,9 +979,10 @@ mod tests {
}
total_sectors_vec.push(u32::MAX);
for total_sectors in total_sectors_vec {
let (boot, _) = format_boot_sector::<()>(&FormatVolumeOptions::new(), total_sectors, bytes_per_sector)
.expect("format_boot_sector");
boot.validate::<()>().expect("validate");
let (boot, _) =
format_boot_sector::<StdErrWrapper>(&FormatVolumeOptions::new(), total_sectors, bytes_per_sector)
.expect("format_boot_sector");
boot.validate::<StdErrWrapper>().expect("validate");
}
}
}
1 change: 1 addition & 0 deletions src/dir.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[cfg(all(not(feature = "std"), feature = "alloc", feature = "lfn"))]
use alloc::vec::Vec;

use core::char;
use core::cmp;
use core::num;
Expand Down
16 changes: 10 additions & 6 deletions src/dir_entry.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::String;
use bitflags::bitflags;
use core::char;
use core::convert::TryInto;
Expand All @@ -8,10 +6,13 @@ use core::fmt;
use core::iter;
use core::str;

#[cfg(all(not(feature = "std"), feature = "alloc", feature = "lfn"))]
use alloc::string::String;

#[cfg(feature = "lfn")]
use crate::dir::LfnBuffer;
use crate::dir::{Dir, DirRawStream};
use crate::error::{Error, IoError};
use crate::error::{Error, IoError, ReadExactError};
use crate::file::File;
use crate::fs::{FatType, FileSystem, OemCpConverter, ReadWriteSeek};
use crate::io::{self, Read, ReadLeExt, Write, WriteLeExt};
Expand Down Expand Up @@ -375,17 +376,20 @@ impl DirEntryData {
}
}

pub(crate) fn deserialize<E: IoError, R: Read<Error = Error<E>>>(rdr: &mut R) -> Result<Self, Error<E>> {
pub(crate) fn deserialize<E: IoError, R: Read<Error = Error<E>>>(rdr: &mut R) -> Result<Self, Error<E>>
where
R::Error: From<ReadExactError<R::Error>>,
{
trace!("DirEntryData::deserialize");
let mut name = [0; SFN_SIZE];
match rdr.read_exact(&mut name) {
Err(Error::UnexpectedEof) => {
Err(ReadExactError::UnexpectedEof) => {
// entries can occupy all clusters of directory so there is no zero entry at the end
// handle it here by returning non-existing empty entry
return Ok(DirEntryData::File(DirFileEntryData::default()));
}
Err(err) => {
return Err(err);
return Err(err.into());
}
Ok(_) => {}
}
Expand Down
94 changes: 43 additions & 51 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
use core::fmt::Debug;
pub use embedded_io::blocking::ReadExactError;
pub use embedded_io::Error as IoError;
pub use embedded_io::ErrorKind;
pub use embedded_io::Io as IoBase;

#[cfg(feature = "std")]
use crate::io::StdErrWrapper;

/// Error enum with all errors that can be returned by functions from this crate
///
/// Generic parameter `T` is a type of external error returned by the user provided storage
Expand Down Expand Up @@ -28,17 +37,41 @@ pub enum Error<T> {
UnsupportedFileNameCharacter,
}

impl<T: Debug> IoError for Error<T> {
fn kind(&self) -> ErrorKind {
ErrorKind::Other
}
}

impl<T: IoError> From<T> for Error<T> {
fn from(error: T) -> Self {
Error::Io(error)
}
}

impl<T> From<ReadExactError<Error<T>>> for Error<T> {
fn from(error: ReadExactError<Error<T>>) -> Self {
match error {
ReadExactError::UnexpectedEof => Self::UnexpectedEof,
ReadExactError::Other(error) => error,
}
}
}

impl<T: IoError> From<ReadExactError<T>> for Error<T> {
fn from(error: ReadExactError<T>) -> Self {
match error {
ReadExactError::UnexpectedEof => Self::UnexpectedEof,
ReadExactError::Other(error) => error.into(),
}
}
}

#[cfg(feature = "std")]
impl From<Error<std::io::Error>> for std::io::Error {
fn from(error: Error<Self>) -> Self {
impl From<Error<StdErrWrapper>> for std::io::Error {
fn from(error: Error<StdErrWrapper>) -> Self {
match error {
Error::Io(io_error) => io_error,
Error::Io(io_error) => io_error.into(),
Error::UnexpectedEof | Error::NotEnoughSpace => Self::new(std::io::ErrorKind::UnexpectedEof, error),
Error::WriteZero => Self::new(std::io::ErrorKind::WriteZero, error),
Error::InvalidInput
Expand Down Expand Up @@ -81,57 +114,16 @@ impl<T: std::error::Error + 'static> std::error::Error for Error<T> {
}
}

/// Trait that should be implemented by errors returned from the user supplied storage.
///
/// Implementations for `std::io::Error` and `()` are provided by this crate.
pub trait IoError: core::fmt::Debug {
fn is_interrupted(&self) -> bool;
fn new_unexpected_eof_error() -> Self;
fn new_write_zero_error() -> Self;
}

impl<T: core::fmt::Debug + IoError> IoError for Error<T> {
fn is_interrupted(&self) -> bool {
match self {
Error::<T>::Io(io_error) => io_error.is_interrupted(),
_ => false,
}
}

fn new_unexpected_eof_error() -> Self {
Error::<T>::UnexpectedEof
}

fn new_write_zero_error() -> Self {
Error::<T>::WriteZero
}
}

impl IoError for () {
fn is_interrupted(&self) -> bool {
false
}

fn new_unexpected_eof_error() -> Self {
// empty
}

fn new_write_zero_error() -> Self {
// empty
#[cfg(feature = "std")]
impl core::fmt::Display for StdErrWrapper {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "pls implement")
}
}

#[cfg(feature = "std")]
impl IoError for std::io::Error {
fn is_interrupted(&self) -> bool {
self.kind() == std::io::ErrorKind::Interrupted
}

fn new_unexpected_eof_error() -> Self {
Self::new(std::io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")
}

fn new_write_zero_error() -> Self {
Self::new(std::io::ErrorKind::WriteZero, "failed to write whole buffer")
impl std::error::Error for StdErrWrapper {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
4 changes: 2 additions & 2 deletions src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,12 +473,12 @@ impl<IO: ReadWriteSeek, TP, OCC> Seek for File<'_, IO, TP, OCC> {
}
}

#[cfg(feature = "std")]
#[cfg(test)]
impl<IO: ReadWriteSeek, TP: TimeProvider, OCC> std::io::Seek for File<'_, IO, TP, OCC>
where
std::io::Error: From<Error<IO::Error>>,
{
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
Ok(Seek::seek(self, pos.into())?)
Ok(Seek::seek(self, crate::StdSeekPosWrapper::from(pos).into())?)
}
}
22 changes: 15 additions & 7 deletions src/fs.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::string::String;
use core::borrow::BorrowMut;
use core::cell::{Cell, RefCell};
use core::char;
Expand All @@ -9,10 +7,13 @@ use core::fmt::Debug;
use core::marker::PhantomData;
use core::u32;

#[cfg(all(not(feature = "std"), feature = "alloc", feature = "lfn"))]
use alloc::string::String;

use crate::boot_sector::{format_boot_sector, BiosParameterBlock, BootSector};
use crate::dir::{Dir, DirRawStream};
use crate::dir_entry::{DirFileEntryData, FileAttributes, SFN_PADDING, SFN_SIZE};
use crate::error::Error;
use crate::error::{Error, ReadExactError};
use crate::file::File;
use crate::io::{self, IoBase, Read, ReadLeExt, Seek, SeekFrom, Write, WriteLeExt};
use crate::table::{
Expand Down Expand Up @@ -120,11 +121,11 @@ impl FsStatusFlags {

/// A sum of `Read` and `Seek` traits.
pub trait ReadSeek: Read + Seek {}
impl<T: Read + Seek> ReadSeek for T {}
impl<T: IoBase + Read + Seek> ReadSeek for T {}

/// A sum of `Read`, `Write` and `Seek` traits.
pub trait ReadWriteSeek: Read + Write + Seek {}
impl<T: Read + Write + Seek> ReadWriteSeek for T {}
impl<T: IoBase + Read + Write + Seek> ReadWriteSeek for T {}

#[derive(Clone, Default, Debug)]
struct FsInfoSector {
Expand All @@ -138,7 +139,11 @@ impl FsInfoSector {
const STRUC_SIG: u32 = 0x6141_7272;
const TRAIL_SIG: u32 = 0xAA55_0000;

fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, Error<R::Error>> {
fn deserialize<R: Read>(rdr: &mut R) -> Result<Self, Error<R::Error>>
where
Error<<R as IoBase>::Error>: From<ReadExactError<<R as IoBase>::Error>>,
<R as IoBase>::Error: From<ReadExactError<<R as IoBase>::Error>>,
{
let lead_sig = rdr.read_u32_le()?;
if lead_sig != Self::LEAD_SIG {
error!("invalid lead_sig in FsInfo sector: {}", lead_sig);
Expand Down Expand Up @@ -362,7 +367,10 @@ impl<IO: Read + Write + Seek, TP, OCC> FileSystem<IO, TP, OCC> {
/// # Panics
///
/// Panics in non-optimized build if `storage` position returned by `seek` is not zero.
pub fn new<T: IntoStorage<IO>>(storage: T, options: FsOptions<TP, OCC>) -> Result<Self, Error<IO::Error>> {
pub fn new<T: IntoStorage<IO>>(storage: T, options: FsOptions<TP, OCC>) -> Result<Self, Error<IO::Error>>
where
IO::Error: From<ReadExactError<IO::Error>>,
{
// Make sure given image is not seeked
let mut disk = storage.into_storage();
trace!("FileSystem::new");
Expand Down
Loading