Skip to main content

fatfs/
error.rs

1/// Error enum with all errors that can be returned by functions from this crate
2///
3/// Generic parameter `T` is a type of external error returned by the user provided storage
4#[derive(Debug)]
5#[non_exhaustive]
6pub enum Error<T> {
7    /// A user provided storage instance returned an error during an input/output operation.
8    Io(T),
9    /// A read operation cannot be completed because an end of a file has been reached prematurely.
10    UnexpectedEof,
11    /// A write operation cannot be completed because `Write::write` returned 0.
12    WriteZero,
13    /// A parameter was incorrect.
14    InvalidInput,
15    /// A requested file or directory has not been found.
16    NotFound,
17    /// A file or a directory with the same name already exists.
18    AlreadyExists,
19    /// An operation cannot be finished because a directory is not empty.
20    DirectoryIsNotEmpty,
21    /// File system internal structures are corrupted/invalid.
22    CorruptedFileSystem,
23    /// There is not enough free space on the storage to finish the requested operation.
24    NotEnoughSpace,
25    /// The provided file name is either too long or empty.
26    InvalidFileNameLength,
27    /// The provided file name contains an invalid character.
28    UnsupportedFileNameCharacter,
29}
30
31impl<T: IoError> From<T> for Error<T> {
32    fn from(error: T) -> Self {
33        Error::Io(error)
34    }
35}
36
37#[cfg(feature = "std")]
38impl From<Error<std::io::Error>> for std::io::Error {
39    fn from(error: Error<Self>) -> Self {
40        match error {
41            Error::Io(io_error) => io_error,
42            Error::UnexpectedEof | Error::NotEnoughSpace => Self::new(std::io::ErrorKind::UnexpectedEof, error),
43            Error::WriteZero => Self::new(std::io::ErrorKind::WriteZero, error),
44            Error::InvalidInput
45            | Error::InvalidFileNameLength
46            | Error::UnsupportedFileNameCharacter
47            | Error::DirectoryIsNotEmpty => Self::new(std::io::ErrorKind::InvalidInput, error),
48            Error::NotFound => Self::new(std::io::ErrorKind::NotFound, error),
49            Error::AlreadyExists => Self::new(std::io::ErrorKind::AlreadyExists, error),
50            Error::CorruptedFileSystem => Self::new(std::io::ErrorKind::InvalidData, error),
51        }
52    }
53}
54
55impl<T: core::fmt::Display> core::fmt::Display for Error<T> {
56    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
57        match self {
58            Error::Io(io_error) => write!(f, "IO error: {}", io_error),
59            Error::UnexpectedEof => write!(f, "Unexpected end of file"),
60            Error::NotEnoughSpace => write!(f, "Not enough space"),
61            Error::WriteZero => write!(f, "Write zero"),
62            Error::InvalidInput => write!(f, "Invalid input"),
63            Error::InvalidFileNameLength => write!(f, "Invalid file name length"),
64            Error::UnsupportedFileNameCharacter => write!(f, "Unsupported file name character"),
65            Error::DirectoryIsNotEmpty => write!(f, "Directory is not empty"),
66            Error::NotFound => write!(f, "No such file or directory"),
67            Error::AlreadyExists => write!(f, "File or directory already exists"),
68            Error::CorruptedFileSystem => write!(f, "Corrupted file system"),
69        }
70    }
71}
72
73#[cfg(feature = "std")]
74impl<T: std::error::Error + 'static> std::error::Error for Error<T> {
75    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
76        if let Error::Io(io_error) = self {
77            Some(io_error)
78        } else {
79            None
80        }
81    }
82}
83
84/// Trait that should be implemented by errors returned from the user supplied storage.
85///
86/// Implementations for `std::io::Error` and `()` are provided by this crate.
87pub trait IoError: core::fmt::Debug {
88    fn is_interrupted(&self) -> bool;
89    fn new_unexpected_eof_error() -> Self;
90    fn new_write_zero_error() -> Self;
91}
92
93impl<T: core::fmt::Debug + IoError> IoError for Error<T> {
94    fn is_interrupted(&self) -> bool {
95        match self {
96            Error::<T>::Io(io_error) => io_error.is_interrupted(),
97            _ => false,
98        }
99    }
100
101    fn new_unexpected_eof_error() -> Self {
102        Error::<T>::UnexpectedEof
103    }
104
105    fn new_write_zero_error() -> Self {
106        Error::<T>::WriteZero
107    }
108}
109
110impl IoError for () {
111    fn is_interrupted(&self) -> bool {
112        false
113    }
114
115    fn new_unexpected_eof_error() -> Self {
116        // empty
117    }
118
119    fn new_write_zero_error() -> Self {
120        // empty
121    }
122}
123
124#[cfg(feature = "std")]
125impl IoError for std::io::Error {
126    fn is_interrupted(&self) -> bool {
127        self.kind() == std::io::ErrorKind::Interrupted
128    }
129
130    fn new_unexpected_eof_error() -> Self {
131        Self::new(std::io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")
132    }
133
134    fn new_write_zero_error() -> Self {
135        Self::new(std::io::ErrorKind::WriteZero, "failed to write whole buffer")
136    }
137}