mirror of
https://github.com/trussed-dev/littlefs2.git
synced 2026-06-20 04:16:32 -07:00
Add chunked file API
This commit is contained in:
committed by
sosthene-nitrokey
parent
154e054329
commit
ec304b8663
@@ -12,7 +12,7 @@ pub type Bytes<SIZE> = generic_array::GenericArray<u8, SIZE>;
|
||||
|
||||
use crate::{
|
||||
driver,
|
||||
io::{self, Result},
|
||||
io::{self, OpenSeekFrom, Result},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
@@ -1248,6 +1248,24 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> {
|
||||
Ok(contents)
|
||||
}
|
||||
|
||||
/// Read a chunk of a file into a bytes vector
|
||||
/// Returns the data and the size of the file
|
||||
pub fn read_chunk<const N: usize>(
|
||||
&self,
|
||||
path: &Path,
|
||||
pos: OpenSeekFrom,
|
||||
) -> Result<(heapless::Vec<u8, N>, usize)> {
|
||||
let mut contents: heapless::Vec<u8, N> = Default::default();
|
||||
contents.resize_default(contents.capacity()).unwrap();
|
||||
let file_len = File::open_and_then(self, path, |file| {
|
||||
file.seek(pos.into())?;
|
||||
let read_n = file.read(&mut contents)?;
|
||||
contents.truncate(read_n);
|
||||
file.len()
|
||||
})?;
|
||||
Ok((contents, file_len))
|
||||
}
|
||||
|
||||
/// Write a slice as the entire contents of a file.
|
||||
///
|
||||
/// This function will create a file if it does not exist,
|
||||
@@ -1261,6 +1279,21 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> {
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Write a slice as a chunk of a file.
|
||||
///
|
||||
/// This function will not create a file if it does not exist,
|
||||
/// it will fail if the file is not already large enough with regard to the `pos` parameter
|
||||
pub fn write_chunk(&self, path: &Path, contents: &[u8], pos: OpenSeekFrom) -> Result<()> {
|
||||
#[cfg(test)]
|
||||
println!("writing {:?}", path);
|
||||
File::open_and_then(self, path, |file| {
|
||||
use io::Write;
|
||||
file.seek(pos.into())?;
|
||||
file.write_all(contents)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -82,6 +82,24 @@ impl SeekFrom {
|
||||
}
|
||||
}
|
||||
|
||||
/// Enumeration of possible methods to seek within an file that was just opened
|
||||
/// Used in the [`read_chunk`](crate::fs::Filesystem::read_chunk) and [`write_chunk`](crate::fs::Filesystem::write_chunk) methods,
|
||||
/// Where [`SeekFrom::Current`](SeekFrom::Current) would not make sense.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum OpenSeekFrom {
|
||||
Start(u32),
|
||||
End(i32),
|
||||
}
|
||||
|
||||
impl From<OpenSeekFrom> for SeekFrom {
|
||||
fn from(value: OpenSeekFrom) -> Self {
|
||||
match value {
|
||||
OpenSeekFrom::Start(o) => Self::Start(o),
|
||||
OpenSeekFrom::End(o) => Self::End(o),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 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.
|
||||
|
||||
+36
-5
@@ -4,8 +4,7 @@ use generic_array::typenum::consts;
|
||||
use crate::{
|
||||
driver,
|
||||
fs::{Attribute, File, Filesystem},
|
||||
io::{Error, Read, Result, SeekFrom},
|
||||
path::Path,
|
||||
io::{Error, OpenSeekFrom, Read, Result, SeekFrom},
|
||||
};
|
||||
|
||||
ram_storage!(
|
||||
@@ -62,10 +61,8 @@ fn format() {
|
||||
// should succeed
|
||||
assert!(Filesystem::format(&mut storage).is_ok());
|
||||
// should succeed now that storage is formatted
|
||||
let fs = Filesystem::mount(&mut alloc, &mut storage).unwrap();
|
||||
let _fs = Filesystem::mount(&mut alloc, &mut storage).unwrap();
|
||||
// check there are no segfaults
|
||||
drop(fs);
|
||||
drop(storage);
|
||||
}
|
||||
|
||||
// #[macro_use]
|
||||
@@ -312,6 +309,40 @@ fn test_seek() {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chunked() {
|
||||
let mut backend = OtherRam::default();
|
||||
let mut storage = OtherRamStorage::new(&mut backend);
|
||||
let path = b"test_chunked.txt\0".try_into().unwrap();
|
||||
let hello = b"hello world";
|
||||
let more = b"but wait, there's more";
|
||||
|
||||
Filesystem::format(&mut storage).unwrap();
|
||||
Filesystem::mount_and_then(&mut storage, |fs| {
|
||||
fs.write(path, hello)?;
|
||||
let (data, len) = fs.read_chunk::<1024>(path, OpenSeekFrom::Start(0)).unwrap();
|
||||
assert_eq!(&data, hello);
|
||||
assert_eq!(len, hello.len());
|
||||
let (data, len) = fs.read_chunk::<1024>(path, OpenSeekFrom::Start(3)).unwrap();
|
||||
assert_eq!(&data, &hello[3..]);
|
||||
assert_eq!(len, hello.len());
|
||||
fs.write_chunk(path, more, OpenSeekFrom::End(0)).unwrap();
|
||||
let (data, len) = fs
|
||||
.read_chunk::<1024>(path, OpenSeekFrom::Start(hello.len() as u32))
|
||||
.unwrap();
|
||||
assert_eq!(&data, more);
|
||||
assert_eq!(len, hello.len() + more.len());
|
||||
let (data, len) = fs
|
||||
.read_chunk::<1024>(path, OpenSeekFrom::End(-(more.len() as i32)))
|
||||
.unwrap();
|
||||
assert_eq!(&data, more);
|
||||
assert_eq!(len, hello.len() + more.len());
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_set_len() {
|
||||
let mut backend = OtherRam::default();
|
||||
|
||||
Reference in New Issue
Block a user