Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Add ReadDir(Files)Nth API call, which allows skipping files (useful f…
…or resuming iteration)
  • Loading branch information
sosthene-nitrokey committed Jun 9, 2023
commit 8c31c1bf41af8da78c96a8788dcc787c19aaff8f
19 changes: 19 additions & 0 deletions src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ generate_enums! {
Hash: 12
// TODO: add ReadDir{First,Next}, not loading data, if needed for efficiency
ReadDirFilesFirst: 13
ReadDirFilesNth: 31
ReadDirFilesNext: 14
ReadFile: 15
Metadata: 26
Expand All @@ -63,6 +64,7 @@ generate_enums! {

// // CreateDir, <-- implied by WriteFile
ReadDirFirst: 31 // <-- gets Option<FileType> to restrict to just dir/file DirEntries,
ReadDirNth: 31
ReadDirNext: 32 // <-- gets Option<FileType> to restrict to just dir/file DirEntries,
// // returns simplified Metadata
// // ReadDirFilesFirst: 23 // <-- returns contents
Expand Down Expand Up @@ -229,13 +231,24 @@ pub mod request {
- dir: PathBuf
- user_attribute: Option<UserAttribute>

ReadDirFilesNth:
- location: Location
- dir: PathBuf
- start_at: usize
- user_attribute: Option<UserAttribute>

ReadDirFilesNext:

ReadDirFirst:
- location: Location
- dir: PathBuf
- not_before_filename: Option<PathBuf>

ReadDirNth:
- location: Location
- dir: PathBuf
- start_at: usize

ReadDirNext:

ReadFile:
Expand Down Expand Up @@ -419,12 +432,18 @@ pub mod reply {
ReadDirFilesFirst:
- data: Option<Message>

ReadDirFilesNth:
- data: Option<Message>

ReadDirFilesNext:
- data: Option<Message>

ReadDirFirst:
- entry: Option<DirEntry>

ReadDirNth:
- data: Option<Message>

ReadDirNext:
- entry: Option<DirEntry>

Expand Down
28 changes: 28 additions & 0 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,20 @@ impl<P: Platform> ServiceResources<P> {
};
Ok(Reply::ReadDirFirst(reply::ReadDirFirst { entry: maybe_entry } ))
}
Request::ReadDirNth(request) => {
let maybe_entry = match filestore.read_dir_nth(&request.dir, request.location, request.start_at)? {
Some((entry, read_dir_state)) => {
ctx.read_dir_state = Some(read_dir_state);
Some(entry)
}
None => {
ctx.read_dir_state = None;
None

}
};
Ok(Reply::ReadDirFirst(reply::ReadDirFirst { entry: maybe_entry } ))
}

Request::ReadDirNext(_request) => {
// ensure next call has nothing to work with, unless we store state again
Expand Down Expand Up @@ -393,6 +407,20 @@ impl<P: Platform> ServiceResources<P> {
Ok(Reply::ReadDirFilesFirst(reply::ReadDirFilesFirst { data: maybe_data } ))
}

Request::ReadDirFilesNth(request) => {
let maybe_data = match filestore.read_dir_files_nth(&request.dir, request.location, request.start_at, request.user_attribute.clone())? {
Some((data, state)) => {
ctx.read_dir_files_state = Some(state);
data
}
None => {
ctx.read_dir_files_state = None;
None
}
};
Ok(Reply::ReadDirFilesFirst(reply::ReadDirFilesFirst { data: maybe_data } ))
}

Request::ReadDirFilesNext(_request) => {
let read_dir_files_state = ctx.read_dir_files_state.take();

Expand Down
101 changes: 93 additions & 8 deletions src/store/filestore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ pub trait Filestore {
filename: &Path,
) -> Result<Option<PathBuf>>;

/// Iterate over entries of a directory (both file and directory entries).
///
/// This function is modeled after `std::fs::read_dir`, within the limitations of our setup.
///
/// In case an entry was found, the returned option also contains state, so the expected
/// call to `read_dir_next` can resume operation.
fn read_dir_nth(
&mut self,
dir: &PathBuf,
location: Location,
start_at: usize,
) -> Result<Option<(DirEntry, ReadDirState)>>;

/// Iterate over entries of a directory (both file and directory entries).
///
/// This function is modeled after `std::fs::read_dir`, within the limitations of our setup.
Expand Down Expand Up @@ -132,6 +145,21 @@ pub trait Filestore {
user_attribute: Option<UserAttribute>,
) -> Result<Option<(Option<Message>, ReadDirFilesState)>>;

/// Iterate over contents of files inside a directory.
///
/// This has no equivalent in `std::fs`, it is an optimization to avoid duplicate
/// calls and a more complicated state machine (interspersing read_dir_first/next calls
/// with some sort of "fetch data").
///
/// Additionally, files may optionally be filtered via attributes.
fn read_dir_files_nth(
&mut self,
clients_dir: &PathBuf,
location: Location,
start_at: usize,
user_attribute: Option<UserAttribute>,
) -> Result<Option<(Option<Message>, ReadDirFilesState)>>;

/// Continuation of `read_dir_files_first`.
fn read_dir_files_next(
&mut self,
Expand All @@ -146,6 +174,7 @@ impl<S: Store> ClientFilestore<S> {
clients_dir: &Path,
location: Location,
not_before: Option<&Path>,
start_at: usize,
fs: &'static Fs<F>,
) -> Result<Option<(DirEntry, ReadDirState)>> {
let dir = self.actual_path(clients_dir)?;
Expand All @@ -155,7 +184,7 @@ impl<S: Store> ClientFilestore<S> {
// this is an iterator with Item = (usize, Result<DirEntry>)
(&mut it)
// skip over `.` and `..`
.skip(2)
.skip(2 + start_at)
// todo: try ?-ing out of this (the API matches std::fs, where read/write errors
// can occur during operation)
//
Expand Down Expand Up @@ -239,6 +268,7 @@ impl<S: Store> ClientFilestore<S> {
clients_dir: &Path,
location: Location,
user_attribute: Option<UserAttribute>,
start_at: usize,
fs: &'static Fs<F>,
) -> Result<Option<(Option<Message>, ReadDirFilesState)>> {
let dir = self.actual_path(clients_dir)?;
Expand All @@ -254,8 +284,7 @@ impl<S: Store> ClientFilestore<S> {
.map(Result::unwrap)
// skip over directories (including `.` and `..`)
.filter(|entry| entry.file_type().is_file())
// take first entry that meets requirements
.find(|entry| {
.filter(|entry| {
if let Some(user_attribute) = user_attribute.as_ref() {
let mut path = dir.clone();
path.push(entry.file_name());
Expand All @@ -264,14 +293,16 @@ impl<S: Store> ClientFilestore<S> {
.unwrap();

if let Some(attribute) = attribute {
user_attribute == attribute.data()
user_attribute != attribute.data()
} else {
false
true
}
} else {
true
}
})
// take nth entry that meets requirements
.nth(start_at)
// if there is an entry, construct the state that needs storing out of it,
// and return the file's contents.
// the client, and return both the entry and the state
Expand Down Expand Up @@ -421,13 +452,32 @@ impl<S: Store> Filestore for ClientFilestore<S> {
) -> Result<Option<(DirEntry, ReadDirState)>> {
match location {
Location::Internal => {
self.read_dir_first_impl(clients_dir, location, not_before, self.store.ifs())
self.read_dir_first_impl(clients_dir, location, not_before, 0, self.store.ifs())
}
Location::External => {
self.read_dir_first_impl(clients_dir, location, not_before, 0, self.store.efs())
}
Location::Volatile => {
self.read_dir_first_impl(clients_dir, location, not_before, 0, self.store.vfs())
}
}
}

fn read_dir_nth(
&mut self,
clients_dir: &PathBuf,
location: Location,
start_at: usize,
) -> Result<Option<(DirEntry, ReadDirState)>> {
match location {
Location::Internal => {
self.read_dir_first_impl(clients_dir, location, None, start_at, self.store.ifs())
}
Location::External => {
self.read_dir_first_impl(clients_dir, location, not_before, self.store.efs())
self.read_dir_first_impl(clients_dir, location, None, start_at, self.store.efs())
}
Location::Volatile => {
self.read_dir_first_impl(clients_dir, location, not_before, self.store.vfs())
self.read_dir_first_impl(clients_dir, location, None, start_at, self.store.vfs())
}
}
}
Expand All @@ -451,18 +501,53 @@ impl<S: Store> Filestore for ClientFilestore<S> {
clients_dir,
location,
user_attribute,
0,
self.store.ifs(),
),
Location::External => self.read_dir_files_first_impl(
clients_dir,
location,
user_attribute,
0,
self.store.efs(),
),
Location::Volatile => self.read_dir_files_first_impl(
clients_dir,
location,
user_attribute,
0,
self.store.vfs(),
),
}
}

fn read_dir_files_nth(
&mut self,
clients_dir: &PathBuf,
location: Location,
start_at: usize,
user_attribute: Option<UserAttribute>,
) -> Result<Option<(Option<Message>, ReadDirFilesState)>> {
match location {
Location::Internal => self.read_dir_files_first_impl(
clients_dir,
location,
user_attribute,
start_at,
self.store.ifs(),
),
Location::External => self.read_dir_files_first_impl(
clients_dir,
location,
user_attribute,
start_at,
self.store.efs(),
),
Location::Volatile => self.read_dir_files_first_impl(
clients_dir,
location,
user_attribute,
start_at,
self.store.vfs(),
),
}
Expand Down