1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! Traits and types for core I/O functionality.

pub mod prelude;

use littlefs2_sys as ll;

/// The `Read` trait allows for reading bytes from a file.
pub trait Read {
    /// Read at most buf.len() bytes.
    /// Upon success, return how many bytes were read.
    fn read(&self, buf: &mut [u8]) -> Result<usize>;

    fn read_exact(&self, buf: &mut [u8]) -> Result<()> {
        // Same assumption as for `read_to_end`.
        let len = self.read(buf)?;
        if len == buf.len() {
            Ok(())
        } else {
            // TODO: Decide whether to add an equivalent of `ErrorKind::UnexpectedEof`
            Err(Error::Io)
        }
    }

}

/** The `Write` trait allows for writing bytes to a file.

By analogy with `std::io::Write`, we also define a `flush()`
method. In the current implementation, writes are final and
flush has no effect.
*/
pub trait Write {
    /// Write at most data.len() bytes.
    /// The file will not necessarily be updated unless
    /// flush is called as there is a cache.
    /// Upon success, return how many bytes were written.
    fn write(&self, data: &[u8]) -> Result<usize>;

    /// Write out all pending writes to storage.
    fn flush(&self) -> Result<()>;

    fn write_all(&self, mut buf: &[u8]) -> Result<()> {
        while !buf.is_empty() {
            match self.write(buf) {
                Ok(0) => {
                    // failed to write whole buffer
                    return Err(Error::Io)
                }
                Ok(n) => buf = &buf[n..],
                Err(e) => return Err(e),
            }
        }
        Ok(())
    }
}

/** Enumeration of possible methods to seek within an I/O object.

Use the [`Seek`](../io/trait.Seek.html) trait.
*/
#[derive(Clone,Copy,Debug,Eq,PartialEq)]
pub enum SeekFrom {
    Start(u32),
    End(i32),
    Current(i32),
}

impl SeekFrom {
    pub(crate) fn off(self) -> i32 {
        match self {
            SeekFrom::Start(u) => u as i32,
            SeekFrom::End(i) => i,
            SeekFrom::Current(i) => i,
        }
    }

    pub(crate) fn whence(self) -> i32 {
        match self {
            SeekFrom::Start(_) => 0,
            SeekFrom::End(_) => 2,
            SeekFrom::Current(_) => 1,
        }
    }
}

/** The `Seek` trait provides a cursor which can be moved within a file.

It is possible to seek relative to either end or the current offset.
*/
pub trait Seek {
    /// Seek to an offset in bytes.
    /// If successful, returns the new position from start of file.
    fn seek(&self, pos: SeekFrom) -> Result<usize>;
}

pub type Result<T> = core::result::Result<T, Error>;

/// Definition of errors that might be returned by filesystem functionality.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum Error {
    /// Error code was >=0, operation was successful.
    Success,
    /// Input / output error occurred.
    Io,
    /// File or filesystem was corrupt.
    Corruption,
    /// No entry found with that name.
    NoSuchEntry,
    /// File or directory already exists.
    EntryAlreadyExisted,
    /// Path name is not a directory.
    PathNotDir,
    /// Path specification is to a directory.
    PathIsDir,
    /// Directory was not empty.
    DirNotEmpty,
    /// Bad file descriptor.
    BadFileDescriptor,
    /// File is too big.
    FileTooBig,
    /// Incorrect value specified to function.
    Invalid,
    /// No space left available for operation.
    NoSpace,
    /// No memory available for completing request.
    NoMemory,
    /// No attribute or data available
    NoAttribute,
    /// Filename too long
    FilenameTooLong,
    /// Unknown error occurred, integer code specified.
    Unknown(i32),
}

impl From<crate::path::Error> for Error {
    fn from(_error: crate::path::Error) -> Self {
        Error::Io
    }
}

impl From<i32> for Error {
    fn from(error_code: i32) -> Error {
        match error_code {
            n if n >= 0 => Error::Success,
            // negative codes
            ll::lfs_error_LFS_ERR_IO => Error::Io,
            ll::lfs_error_LFS_ERR_CORRUPT => Error::Corruption,
            ll::lfs_error_LFS_ERR_NOENT => Error::NoSuchEntry,
            ll::lfs_error_LFS_ERR_EXIST => Error::EntryAlreadyExisted,
            ll::lfs_error_LFS_ERR_NOTDIR => Error::PathNotDir,
            ll::lfs_error_LFS_ERR_ISDIR => Error::PathIsDir,
            ll::lfs_error_LFS_ERR_NOTEMPTY => Error::DirNotEmpty,
            ll::lfs_error_LFS_ERR_BADF => Error::BadFileDescriptor,
            ll::lfs_error_LFS_ERR_FBIG => Error::FileTooBig,
            ll::lfs_error_LFS_ERR_INVAL => Error::Invalid,
            ll::lfs_error_LFS_ERR_NOSPC => Error::NoSpace,
            ll::lfs_error_LFS_ERR_NOMEM => Error::NoMemory,
            ll::lfs_error_LFS_ERR_NOATTR => Error::NoAttribute,
            ll::lfs_error_LFS_ERR_NAMETOOLONG => Error::FilenameTooLong,
            // positive codes should always indicate success
            _ => Error::Unknown(error_code),
        }
    }
}

pub fn result_from<T>(return_value: T, error_code: ll::lfs_error) -> Result<T> {
    let error: Error = error_code.into();
    match error {
        Error::Success => Ok(return_value),
        _ => Err(error)
    }
}