@@ -89,6 +89,19 @@ pub trait Filestore {
8989        filename :  PathBuf , 
9090    )  -> Result < Option < PathBuf > > ; 
9191
92+     /// Iterate over entries of a directory (both file and directory entries). 
93+      /// 
94+      /// This function is modeled after `std::fs::read_dir`, within the limitations of our setup. 
95+      /// 
96+      /// In case an entry was found, the returned option also contains state, so the expected 
97+      /// call to `read_dir_next` can resume operation. 
98+      fn  read_dir_nth ( 
99+         & mut  self , 
100+         dir :  & PathBuf , 
101+         location :  Location , 
102+         start_at :  usize , 
103+     )  -> Result < Option < ( DirEntry ,  ReadDirState ) > > ; 
104+ 
92105    /// Iterate over entries of a directory (both file and directory entries). 
93106     /// 
94107     /// This function is modeled after `std::fs::read_dir`, within the limitations of our setup. 
@@ -125,6 +138,21 @@ pub trait Filestore {
125138        user_attribute :  Option < UserAttribute > , 
126139    )  -> Result < Option < ( Option < Message > ,  ReadDirFilesState ) > > ; 
127140
141+     /// Iterate over contents of files inside a directory. 
142+      /// 
143+      /// This has no equivalent in `std::fs`, it is an optimization to avoid duplicate 
144+      /// calls and a more complicated state machine (interspersing read_dir_first/next calls 
145+      /// with some sort of "fetch data"). 
146+      /// 
147+      /// Additionally, files may optionally be filtered via attributes. 
148+      fn  read_dir_files_nth ( 
149+         & mut  self , 
150+         clients_dir :  & PathBuf , 
151+         location :  Location , 
152+         start_at :  usize , 
153+         user_attribute :  Option < UserAttribute > , 
154+     )  -> Result < Option < ( Option < Message > ,  ReadDirFilesState ) > > ; 
155+ 
128156    /// Continuation of `read_dir_files_first`. 
129157     fn  read_dir_files_next ( 
130158        & mut  self , 
@@ -139,6 +167,7 @@ impl<S: Store> ClientFilestore<S> {
139167        clients_dir :  & PathBuf , 
140168        location :  Location , 
141169        not_before :  Option < & PathBuf > , 
170+         start_at :  usize , 
142171        fs :  & ' static  Fs < F > , 
143172    )  -> Result < Option < ( DirEntry ,  ReadDirState ) > >  { 
144173        let  dir = self . actual_path ( clients_dir) ?; 
@@ -148,7 +177,7 @@ impl<S: Store> ClientFilestore<S> {
148177                // this is an iterator with Item = (usize, Result<DirEntry>) 
149178                ( & mut  it) 
150179                    // skip over `.` and `..` 
151-                     . skip ( 2 ) 
180+                     . skip ( 2  + start_at ) 
152181                    // todo: try ?-ing out of this (the API matches std::fs, where read/write errors 
153182                    // can occur during operation) 
154183                    // 
@@ -232,6 +261,7 @@ impl<S: Store> ClientFilestore<S> {
232261        clients_dir :  & PathBuf , 
233262        location :  Location , 
234263        user_attribute :  Option < UserAttribute > , 
264+         start_at :  usize , 
235265        fs :  & ' static  Fs < F > , 
236266    )  -> Result < Option < ( Option < Message > ,  ReadDirFilesState ) > >  { 
237267        let  dir = self . actual_path ( clients_dir) ?; 
@@ -247,8 +277,7 @@ impl<S: Store> ClientFilestore<S> {
247277                    . map ( Result :: unwrap) 
248278                    // skip over directories (including `.` and `..`) 
249279                    . filter ( |entry| entry. file_type ( ) . is_file ( ) ) 
250-                     // take first entry that meets requirements 
251-                     . find ( |entry| { 
280+                     . filter ( |entry| { 
252281                        if  let  Some ( user_attribute)  = user_attribute. as_ref ( )  { 
253282                            let  mut  path = dir. clone ( ) ; 
254283                            path. push ( entry. file_name ( ) ) ; 
@@ -257,14 +286,16 @@ impl<S: Store> ClientFilestore<S> {
257286                                . unwrap ( ) ; 
258287
259288                            if  let  Some ( attribute)  = attribute { 
260-                                 user_attribute = = attribute. data ( ) 
289+                                 user_attribute ! = attribute. data ( ) 
261290                            }  else  { 
262-                                 false 
291+                                 true 
263292                            } 
264293                        }  else  { 
265294                            true 
266295                        } 
267296                    } ) 
297+                     // take nth entry that meets requirements 
298+                     . nth ( start_at) 
268299                    // if there is an entry, construct the state that needs storing out of it, 
269300                    // and return the file's contents. 
270301                    // the client, and return both the entry and the state 
@@ -403,13 +434,32 @@ impl<S: Store> Filestore for ClientFilestore<S> {
403434    )  -> Result < Option < ( DirEntry ,  ReadDirState ) > >  { 
404435        match  location { 
405436            Location :: Internal  => { 
406-                 self . read_dir_first_impl ( clients_dir,  location,  not_before,  self . store . ifs ( ) ) 
437+                 self . read_dir_first_impl ( clients_dir,  location,  not_before,  0 ,  self . store . ifs ( ) ) 
438+             } 
439+             Location :: External  => { 
440+                 self . read_dir_first_impl ( clients_dir,  location,  not_before,  0 ,  self . store . efs ( ) ) 
441+             } 
442+             Location :: Volatile  => { 
443+                 self . read_dir_first_impl ( clients_dir,  location,  not_before,  0 ,  self . store . vfs ( ) ) 
444+             } 
445+         } 
446+     } 
447+ 
448+     fn  read_dir_nth ( 
449+         & mut  self , 
450+         clients_dir :  & PathBuf , 
451+         location :  Location , 
452+         start_at :  usize , 
453+     )  -> Result < Option < ( DirEntry ,  ReadDirState ) > >  { 
454+         match  location { 
455+             Location :: Internal  => { 
456+                 self . read_dir_first_impl ( clients_dir,  location,  None ,  start_at,  self . store . ifs ( ) ) 
407457            } 
408458            Location :: External  => { 
409-                 self . read_dir_first_impl ( clients_dir,  location,  not_before ,  self . store . efs ( ) ) 
459+                 self . read_dir_first_impl ( clients_dir,  location,  None ,  start_at ,  self . store . efs ( ) ) 
410460            } 
411461            Location :: Volatile  => { 
412-                 self . read_dir_first_impl ( clients_dir,  location,  not_before ,  self . store . vfs ( ) ) 
462+                 self . read_dir_first_impl ( clients_dir,  location,  None ,  start_at ,  self . store . vfs ( ) ) 
413463            } 
414464        } 
415465    } 
@@ -433,18 +483,53 @@ impl<S: Store> Filestore for ClientFilestore<S> {
433483                clients_dir, 
434484                location, 
435485                user_attribute, 
486+                 0 , 
487+                 self . store . ifs ( ) , 
488+             ) , 
489+             Location :: External  => self . read_dir_files_first_impl ( 
490+                 clients_dir, 
491+                 location, 
492+                 user_attribute, 
493+                 0 , 
494+                 self . store . efs ( ) , 
495+             ) , 
496+             Location :: Volatile  => self . read_dir_files_first_impl ( 
497+                 clients_dir, 
498+                 location, 
499+                 user_attribute, 
500+                 0 , 
501+                 self . store . vfs ( ) , 
502+             ) , 
503+         } 
504+     } 
505+ 
506+     fn  read_dir_files_nth ( 
507+         & mut  self , 
508+         clients_dir :  & PathBuf , 
509+         location :  Location , 
510+         start_at :  usize , 
511+         user_attribute :  Option < UserAttribute > , 
512+     )  -> Result < Option < ( Option < Message > ,  ReadDirFilesState ) > >  { 
513+         match  location { 
514+             Location :: Internal  => self . read_dir_files_first_impl ( 
515+                 clients_dir, 
516+                 location, 
517+                 user_attribute, 
518+                 start_at, 
436519                self . store . ifs ( ) , 
437520            ) , 
438521            Location :: External  => self . read_dir_files_first_impl ( 
439522                clients_dir, 
440523                location, 
441524                user_attribute, 
525+                 start_at, 
442526                self . store . efs ( ) , 
443527            ) , 
444528            Location :: Volatile  => self . read_dir_files_first_impl ( 
445529                clients_dir, 
446530                location, 
447531                user_attribute, 
532+                 start_at, 
448533                self . store . vfs ( ) , 
449534            ) , 
450535        } 
0 commit comments