From 760bb7f25f2ed76545ad40e5b014c9fb2c37cd42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sosth=C3=A8ne=20Gu=C3=A9don?= Date: Mon, 13 Mar 2023 14:36:35 +0100 Subject: [PATCH] Expose directory `tell`, `seek` and `rewind` functionnality --- src/fs.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tests.rs | 26 +++++++++++++++++++-- 2 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/fs.rs b/src/fs.rs index 421c39edb..6d2f127ec 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -1033,6 +1033,11 @@ impl ReadDirAllocation { } } +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct DirIterationTell { + tell_result: u32, +} + pub struct ReadDir<'a, 'b, S: driver::Storage> { alloc: RefCell<&'b mut ReadDirAllocation>, fs: &'b Filesystem<'a, S>, @@ -1040,6 +1045,67 @@ pub struct ReadDir<'a, 'b, S: driver::Storage> { path: PathBuf, } +impl<'a, 'b, S: driver::Storage> ReadDir<'a, 'b, S> { + /// Return the position of the directory + /// + /// The returned offset is only meant to be consumed by seek and may not make + /// sense, but does indicate the current position in the directory iteration. + /// + /// Returns the position of the directory, which can be returned to using [`seek`](Self::seek). + pub fn tell(&self) -> Result { + let value = unsafe { + ll::lfs_dir_tell( + &mut self.fs.alloc.borrow_mut().state, + &mut self.alloc.borrow_mut().state, + ) + }; + if value < 0 { + Err(io::result_from((), value).unwrap_err()) + } else { + Ok(DirIterationTell { + tell_result: value as u32, + }) + } + } + + /// Change the position of the directory + /// + /// The new off must be a value previous returned from [`tell`](Self::tell) and specifies + /// an absolute offset in the directory seek. + pub fn seek(&mut self, state: DirIterationTell) -> Result { + let value = unsafe { + ll::lfs_dir_seek( + &mut self.fs.alloc.borrow_mut().state, + &mut self.alloc.borrow_mut().state, + state.tell_result, + ) + }; + if value < 0 { + Err(io::result_from((), value).unwrap_err()) + } else { + Ok(DirIterationTell { + tell_result: value as u32, + }) + } + } + + /// Change the position of the directory to the beginning of the directory + pub fn rewind(&mut self) -> Result<()> { + let res = unsafe { + ll::lfs_dir_rewind( + &mut self.fs.alloc.borrow_mut().state, + &mut self.alloc.borrow_mut().state, + ) + }; + + if res < 0 { + Err(io::result_from((), res).unwrap_err()) + } else { + Ok(()) + } + } +} + impl<'a, 'b, S: driver::Storage> Iterator for ReadDir<'a, 'b, S> { type Item = Result; diff --git a/src/tests.rs b/src/tests.rs index 2e9bf0a9f..a5bb1e285 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -449,12 +449,16 @@ fn test_iter_dirs() { file.set_len(37)?; fs.create_file_and_then(b"/tmp/file.b\0".try_into()?, |file| file.set_len(42)) })?; + let mut tells = Vec::new(); - fs.read_dir_and_then(b"/tmp\0".try_into()?, |dir| { + fs.read_dir_and_then(b"/tmp\0".try_into()?, |mut dir| { let mut found_files: usize = 0; let mut sizes = [0usize; 4]; + let mut i = 0; - for (i, entry) in dir.enumerate() { + tells.push(dir.tell()?); + while let Some(entry) = dir.next() { + tells.push(dir.tell()?); let entry = entry?; // assert_eq!(entry.file_name(), match i { @@ -467,13 +471,31 @@ fn test_iter_dirs() { sizes[i] = entry.metadata().len(); found_files += 1; + i += 1; } assert_eq!(sizes, [0, 0, 37, 42]); assert_eq!(found_files, 4); + for (i, tell) in tells.iter().enumerate() { + dir.rewind().unwrap(); + let mut found_files: usize = 0; + let mut sizes = Vec::new(); + dir.seek(*tell)?; + + for entry in &mut dir { + let entry = entry?; + sizes.push(entry.metadata().len()); + found_files += 1; + } + + assert_eq!(sizes, [0, 0, 37, 42][i..]); + assert_eq!(found_files, 4 - i); + } Ok(()) }) + .unwrap(); + Ok(()) }) .unwrap(); }