diff --git a/src/store/filestore.rs b/src/store/filestore.rs index 95d7daa8950..9be46711fc5 100644 --- a/src/store/filestore.rs +++ b/src/store/filestore.rs @@ -2,13 +2,14 @@ use crate::{ error::{Error, Result}, // service::ReadDirState, store::{self, Store}, - types::{Location, Message, UserAttribute}, + types::{LfsStorage, Location, Message, UserAttribute}, Bytes, }; #[derive(Clone)] pub struct ReadDirState { real_dir: PathBuf, + location: Location, last: usize, } @@ -24,6 +25,8 @@ use littlefs2::{ fs::{DirEntry, Metadata}, path::{Path, PathBuf}, }; + +use super::Fs; pub type ClientId = PathBuf; pub struct ClientFilestore @@ -129,66 +132,15 @@ pub trait Filestore { ) -> Result, ReadDirFilesState)>>; } -impl Filestore for ClientFilestore { - fn read(&mut self, path: &PathBuf, location: Location) -> Result> { - let path = self.actual_path(path)?; - - store::read(self.store, location, &path) - } - - fn write(&mut self, path: &PathBuf, location: Location, data: &[u8]) -> Result<()> { - let path = self.actual_path(path)?; - store::store(self.store, location, &path, data) - } - - fn exists(&mut self, path: &PathBuf, location: Location) -> bool { - if let Ok(path) = self.actual_path(path) { - store::exists(self.store, location, &path) - } else { - false - } - } - fn metadata(&mut self, path: &PathBuf, location: Location) -> Result> { - let path = self.actual_path(path)?; - store::metadata(self.store, location, &path) - } - - fn remove_file(&mut self, path: &PathBuf, location: Location) -> Result<()> { - let path = self.actual_path(path)?; - - match store::delete(self.store, location, &path) { - true => Ok(()), - false => Err(Error::InternalError), - } - } - - fn remove_dir(&mut self, path: &PathBuf, location: Location) -> Result<()> { - let path = self.actual_path(path)?; - - match store::delete(self.store, location, &path) { - true => Ok(()), - false => Err(Error::InternalError), - } - } - - fn remove_dir_all(&mut self, path: &PathBuf, location: Location) -> Result { - let path = self.actual_path(path)?; - - store::remove_dir_all_where(self.store, location, &path, |_| true) - .map_err(|_| Error::InternalError) - } - - fn read_dir_first( +/// Generic implementation allowing the use of any filesystem. +impl ClientFilestore { + fn read_dir_first_impl( &mut self, clients_dir: &PathBuf, location: Location, not_before: Option<&PathBuf>, + fs: &'static Fs, ) -> Result> { - if location != Location::Internal { - return Err(Error::RequestNotAvailable); - } - let fs = self.store.ifs(); - let dir = self.actual_path(clients_dir)?; Ok(fs @@ -217,6 +169,7 @@ impl Filestore for ClientFilestore { let read_dir_state = ReadDirState { real_dir: dir.clone(), last: i, + location, }; let entry_client_path = self.client_path(entry.path()); // trace_now!("converted path {} to client path {}", &entry.path(), &entry_client_path); @@ -236,10 +189,16 @@ impl Filestore for ClientFilestore { }) .ok()) } - - fn read_dir_next(&mut self, state: ReadDirState) -> Result> { - let ReadDirState { real_dir, last } = state; - let fs = self.store.ifs(); + fn read_dir_next_impl( + &mut self, + state: ReadDirState, + fs: &'static Fs, + ) -> Result> { + let ReadDirState { + real_dir, + last, + location, + } = state; // all we want to do here is skip just past the previously found entry // in the directory iterator, then return it (plus state to continue on next call) @@ -255,6 +214,7 @@ impl Filestore for ClientFilestore { let read_dir_state = ReadDirState { real_dir: real_dir.clone(), last: i, + location, }; let entry_client_path = self.client_path(entry.path()); @@ -266,18 +226,13 @@ impl Filestore for ClientFilestore { }) .ok()) } - - fn read_dir_files_first( + fn read_dir_files_first_impl( &mut self, clients_dir: &PathBuf, location: Location, user_attribute: Option, + fs: &'static Fs, ) -> Result, ReadDirFilesState)>> { - if location != Location::Internal { - return Err(Error::RequestNotAvailable); - } - let fs = self.store.ifs(); - let dir = self.actual_path(clients_dir)?; Ok(fs @@ -332,9 +287,10 @@ impl Filestore for ClientFilestore { .ok()) } - fn read_dir_files_next( + fn read_dir_files_next_impl( &mut self, state: ReadDirFilesState, + fs: &'static Fs, ) -> Result, ReadDirFilesState)>> { let ReadDirFilesState { real_dir, @@ -342,7 +298,6 @@ impl Filestore for ClientFilestore { location, user_attribute, } = state; - let fs = self.store.ifs(); // all we want to do here is skip just past the previously found entry // in the directory iterator, then return it (plus state to continue on next call) @@ -388,6 +343,122 @@ impl Filestore for ClientFilestore { }) .ok()) } +} + +impl Filestore for ClientFilestore { + fn read(&mut self, path: &PathBuf, location: Location) -> Result> { + let path = self.actual_path(path)?; + + store::read(self.store, location, &path) + } + + fn write(&mut self, path: &PathBuf, location: Location, data: &[u8]) -> Result<()> { + let path = self.actual_path(path)?; + store::store(self.store, location, &path, data) + } + + fn exists(&mut self, path: &PathBuf, location: Location) -> bool { + if let Ok(path) = self.actual_path(path) { + store::exists(self.store, location, &path) + } else { + false + } + } + fn metadata(&mut self, path: &PathBuf, location: Location) -> Result> { + let path = self.actual_path(path)?; + store::metadata(self.store, location, &path) + } + + fn remove_file(&mut self, path: &PathBuf, location: Location) -> Result<()> { + let path = self.actual_path(path)?; + + match store::delete(self.store, location, &path) { + true => Ok(()), + false => Err(Error::InternalError), + } + } + + fn remove_dir(&mut self, path: &PathBuf, location: Location) -> Result<()> { + let path = self.actual_path(path)?; + + match store::delete(self.store, location, &path) { + true => Ok(()), + false => Err(Error::InternalError), + } + } + + fn remove_dir_all(&mut self, path: &PathBuf, location: Location) -> Result { + let path = self.actual_path(path)?; + + store::remove_dir_all_where(self.store, location, &path, |_| true) + .map_err(|_| Error::InternalError) + } + + fn read_dir_first( + &mut self, + clients_dir: &PathBuf, + location: Location, + not_before: Option<&PathBuf>, + ) -> Result> { + match location { + Location::Internal => { + self.read_dir_first_impl(clients_dir, location, not_before, self.store.ifs()) + } + Location::External => { + self.read_dir_first_impl(clients_dir, location, not_before, self.store.efs()) + } + Location::Volatile => { + self.read_dir_first_impl(clients_dir, location, not_before, self.store.vfs()) + } + } + } + + fn read_dir_next(&mut self, state: ReadDirState) -> Result> { + match state.location { + Location::Internal => self.read_dir_next_impl(state, self.store.ifs()), + Location::External => self.read_dir_next_impl(state, self.store.efs()), + Location::Volatile => self.read_dir_next_impl(state, self.store.vfs()), + } + } + + fn read_dir_files_first( + &mut self, + clients_dir: &PathBuf, + location: Location, + user_attribute: Option, + ) -> Result, ReadDirFilesState)>> { + match location { + Location::Internal => self.read_dir_files_first_impl( + clients_dir, + location, + user_attribute, + self.store.ifs(), + ), + Location::External => self.read_dir_files_first_impl( + clients_dir, + location, + user_attribute, + self.store.efs(), + ), + Location::Volatile => self.read_dir_files_first_impl( + clients_dir, + location, + user_attribute, + self.store.vfs(), + ), + } + } + + fn read_dir_files_next( + &mut self, + state: ReadDirFilesState, + ) -> Result, ReadDirFilesState)>> { + match state.location { + Location::Internal => self.read_dir_files_next_impl(state, self.store.ifs()), + Location::External => self.read_dir_files_next_impl(state, self.store.efs()), + Location::Volatile => self.read_dir_files_next_impl(state, self.store.vfs()), + } + } fn locate_file( &mut self, diff --git a/tests/filesystem.rs b/tests/filesystem.rs index e3e2dce27fc..08ca8efe511 100644 --- a/tests/filesystem.rs +++ b/tests/filesystem.rs @@ -4,7 +4,7 @@ use trussed::{ client::{CryptoClient, FilesystemClient}, error::Error, syscall, try_syscall, - types::{Location, Mechanism, PathBuf, StorageAttributes}, + types::{Bytes, Location, Mechanism, PathBuf, StorageAttributes}, }; mod client; @@ -53,3 +53,47 @@ fn escape_namespace_root() { assert!(try_syscall!(client.read_file(Location::Volatile, path)).is_err()); }) } + +fn iterating(location: Location) { + client::get(|client| { + syscall!(client.write_file( + location, + PathBuf::from("foo"), + Bytes::from_slice(b"foo").unwrap(), + None + )); + syscall!(client.write_file( + location, + PathBuf::from("bar"), + Bytes::from_slice(b"bar").unwrap(), + None + )); + let first_entry = syscall!(client.read_dir_first(location, PathBuf::from(""), None)) + .entry + .unwrap(); + assert_eq!(first_entry.file_name(), "bar"); + + let next_entry = syscall!(client.read_dir_next()).entry.unwrap(); + assert_eq!(next_entry.file_name(), "foo"); + + let first_data = syscall!(client.read_dir_files_first(location, PathBuf::from(""), None)) + .data + .unwrap(); + assert_eq!(first_data, b"bar"); + let next_data = syscall!(client.read_dir_files_next()).data.unwrap(); + assert_eq!(next_data, b"foo"); + }); +} + +#[test] +fn iterating_internal() { + iterating(Location::Internal); +} +#[test] +fn iterating_external() { + iterating(Location::External); +} +#[test] +fn iterating_volatile() { + iterating(Location::Volatile); +}