Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 140 additions & 69 deletions src/store/filestore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand All @@ -24,6 +25,8 @@ use littlefs2::{
fs::{DirEntry, Metadata},
path::{Path, PathBuf},
};

use super::Fs;
pub type ClientId = PathBuf;

pub struct ClientFilestore<S>
Expand Down Expand Up @@ -129,66 +132,15 @@ pub trait Filestore {
) -> Result<Option<(Option<Message>, ReadDirFilesState)>>;
}

impl<S: Store> Filestore for ClientFilestore<S> {
fn read<const N: usize>(&mut self, path: &PathBuf, location: Location) -> Result<Bytes<N>> {
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<Option<Metadata>> {
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<usize> {
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<S: Store> ClientFilestore<S> {
fn read_dir_first_impl<F: LfsStorage + 'static>(
&mut self,
clients_dir: &PathBuf,
location: Location,
not_before: Option<&PathBuf>,
fs: &'static Fs<F>,
) -> Result<Option<(DirEntry, ReadDirState)>> {
if location != Location::Internal {
return Err(Error::RequestNotAvailable);
}
let fs = self.store.ifs();

let dir = self.actual_path(clients_dir)?;

Ok(fs
Expand Down Expand Up @@ -217,6 +169,7 @@ impl<S: Store> Filestore for ClientFilestore<S> {
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);
Expand All @@ -236,10 +189,16 @@ impl<S: Store> Filestore for ClientFilestore<S> {
})
.ok())
}

fn read_dir_next(&mut self, state: ReadDirState) -> Result<Option<(DirEntry, ReadDirState)>> {
let ReadDirState { real_dir, last } = state;
let fs = self.store.ifs();
fn read_dir_next_impl<F: LfsStorage + 'static>(
&mut self,
state: ReadDirState,
fs: &'static Fs<F>,
) -> Result<Option<(DirEntry, ReadDirState)>> {
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)
Expand All @@ -255,6 +214,7 @@ impl<S: Store> Filestore for ClientFilestore<S> {
let read_dir_state = ReadDirState {
real_dir: real_dir.clone(),
last: i,
location,
};

let entry_client_path = self.client_path(entry.path());
Expand All @@ -266,18 +226,13 @@ impl<S: Store> Filestore for ClientFilestore<S> {
})
.ok())
}

fn read_dir_files_first(
fn read_dir_files_first_impl<F: LfsStorage + 'static>(
&mut self,
clients_dir: &PathBuf,
location: Location,
user_attribute: Option<UserAttribute>,
fs: &'static Fs<F>,
) -> Result<Option<(Option<Message>, ReadDirFilesState)>> {
if location != Location::Internal {
return Err(Error::RequestNotAvailable);
}
let fs = self.store.ifs();

let dir = self.actual_path(clients_dir)?;

Ok(fs
Expand Down Expand Up @@ -332,17 +287,17 @@ impl<S: Store> Filestore for ClientFilestore<S> {
.ok())
}

fn read_dir_files_next(
fn read_dir_files_next_impl<F: LfsStorage + 'static>(
&mut self,
state: ReadDirFilesState,
fs: &'static Fs<F>,
) -> Result<Option<(Option<Message>, ReadDirFilesState)>> {
let ReadDirFilesState {
real_dir,
last,
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)
Expand Down Expand Up @@ -388,6 +343,122 @@ impl<S: Store> Filestore for ClientFilestore<S> {
})
.ok())
}
}

impl<S: Store> Filestore for ClientFilestore<S> {
fn read<const N: usize>(&mut self, path: &PathBuf, location: Location) -> Result<Bytes<N>> {
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<Option<Metadata>> {
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<usize> {
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<Option<(DirEntry, ReadDirState)>> {
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<Option<(DirEntry, ReadDirState)>> {
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<UserAttribute>,
) -> Result<Option<(Option<Message>, 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<Option<(Option<Message>, 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,
Expand Down
46 changes: 45 additions & 1 deletion tests/filesystem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}