Skip to content

Commit ec304b8

Browse files
Add chunked file API
1 parent 154e054 commit ec304b8

File tree

3 files changed

+88
-6
lines changed

3 files changed

+88
-6
lines changed

src/fs.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub type Bytes<SIZE> = generic_array::GenericArray<u8, SIZE>;
1212

1313
use crate::{
1414
driver,
15-
io::{self, Result},
15+
io::{self, OpenSeekFrom, Result},
1616
path::{Path, PathBuf},
1717
};
1818

@@ -1248,6 +1248,24 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> {
12481248
Ok(contents)
12491249
}
12501250

1251+
/// Read a chunk of a file into a bytes vector
1252+
/// Returns the data and the size of the file
1253+
pub fn read_chunk<const N: usize>(
1254+
&self,
1255+
path: &Path,
1256+
pos: OpenSeekFrom,
1257+
) -> Result<(heapless::Vec<u8, N>, usize)> {
1258+
let mut contents: heapless::Vec<u8, N> = Default::default();
1259+
contents.resize_default(contents.capacity()).unwrap();
1260+
let file_len = File::open_and_then(self, path, |file| {
1261+
file.seek(pos.into())?;
1262+
let read_n = file.read(&mut contents)?;
1263+
contents.truncate(read_n);
1264+
file.len()
1265+
})?;
1266+
Ok((contents, file_len))
1267+
}
1268+
12511269
/// Write a slice as the entire contents of a file.
12521270
///
12531271
/// This function will create a file if it does not exist,
@@ -1261,6 +1279,21 @@ impl<'a, Storage: driver::Storage> Filesystem<'a, Storage> {
12611279
})?;
12621280
Ok(())
12631281
}
1282+
1283+
/// Write a slice as a chunk of a file.
1284+
///
1285+
/// This function will not create a file if it does not exist,
1286+
/// it will fail if the file is not already large enough with regard to the `pos` parameter
1287+
pub fn write_chunk(&self, path: &Path, contents: &[u8], pos: OpenSeekFrom) -> Result<()> {
1288+
#[cfg(test)]
1289+
println!("writing {:?}", path);
1290+
File::open_and_then(self, path, |file| {
1291+
use io::Write;
1292+
file.seek(pos.into())?;
1293+
file.write_all(contents)
1294+
})?;
1295+
Ok(())
1296+
}
12641297
}
12651298

12661299
#[cfg(test)]

src/io.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,24 @@ impl SeekFrom {
8282
}
8383
}
8484

85+
/// Enumeration of possible methods to seek within an file that was just opened
86+
/// Used in the [`read_chunk`](crate::fs::Filesystem::read_chunk) and [`write_chunk`](crate::fs::Filesystem::write_chunk) methods,
87+
/// Where [`SeekFrom::Current`](SeekFrom::Current) would not make sense.
88+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
89+
pub enum OpenSeekFrom {
90+
Start(u32),
91+
End(i32),
92+
}
93+
94+
impl From<OpenSeekFrom> for SeekFrom {
95+
fn from(value: OpenSeekFrom) -> Self {
96+
match value {
97+
OpenSeekFrom::Start(o) => Self::Start(o),
98+
OpenSeekFrom::End(o) => Self::End(o),
99+
}
100+
}
101+
}
102+
85103
/** The `Seek` trait provides a cursor which can be moved within a file.
86104
87105
It is possible to seek relative to either end or the current offset.

src/tests.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ use generic_array::typenum::consts;
44
use crate::{
55
driver,
66
fs::{Attribute, File, Filesystem},
7-
io::{Error, Read, Result, SeekFrom},
8-
path::Path,
7+
io::{Error, OpenSeekFrom, Read, Result, SeekFrom},
98
};
109

1110
ram_storage!(
@@ -62,10 +61,8 @@ fn format() {
6261
// should succeed
6362
assert!(Filesystem::format(&mut storage).is_ok());
6463
// should succeed now that storage is formatted
65-
let fs = Filesystem::mount(&mut alloc, &mut storage).unwrap();
64+
let _fs = Filesystem::mount(&mut alloc, &mut storage).unwrap();
6665
// check there are no segfaults
67-
drop(fs);
68-
drop(storage);
6966
}
7067

7168
// #[macro_use]
@@ -312,6 +309,40 @@ fn test_seek() {
312309
.unwrap();
313310
}
314311

312+
#[test]
313+
fn test_chunked() {
314+
let mut backend = OtherRam::default();
315+
let mut storage = OtherRamStorage::new(&mut backend);
316+
let path = b"test_chunked.txt\0".try_into().unwrap();
317+
let hello = b"hello world";
318+
let more = b"but wait, there's more";
319+
320+
Filesystem::format(&mut storage).unwrap();
321+
Filesystem::mount_and_then(&mut storage, |fs| {
322+
fs.write(path, hello)?;
323+
let (data, len) = fs.read_chunk::<1024>(path, OpenSeekFrom::Start(0)).unwrap();
324+
assert_eq!(&data, hello);
325+
assert_eq!(len, hello.len());
326+
let (data, len) = fs.read_chunk::<1024>(path, OpenSeekFrom::Start(3)).unwrap();
327+
assert_eq!(&data, &hello[3..]);
328+
assert_eq!(len, hello.len());
329+
fs.write_chunk(path, more, OpenSeekFrom::End(0)).unwrap();
330+
let (data, len) = fs
331+
.read_chunk::<1024>(path, OpenSeekFrom::Start(hello.len() as u32))
332+
.unwrap();
333+
assert_eq!(&data, more);
334+
assert_eq!(len, hello.len() + more.len());
335+
let (data, len) = fs
336+
.read_chunk::<1024>(path, OpenSeekFrom::End(-(more.len() as i32)))
337+
.unwrap();
338+
assert_eq!(&data, more);
339+
assert_eq!(len, hello.len() + more.len());
340+
341+
Ok(())
342+
})
343+
.unwrap();
344+
}
345+
315346
#[test]
316347
fn test_file_set_len() {
317348
let mut backend = OtherRam::default();

0 commit comments

Comments
 (0)