Skip to content

Commit

Permalink
Merge pull request #15 from sosthene-nitrokey/read-dir-efs-nitro
Browse files Browse the repository at this point in the history
Cherry-pick trussed-dev#104
  • Loading branch information
robin-nitrokey authored Mar 9, 2023
2 parents 3134ec3 + 09784ac commit c2cae35
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 70 deletions.
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);
}

0 comments on commit c2cae35

Please sign in to comment.