@@ -17,13 +17,13 @@ use heapless::Vec;
1717static ID_GENERATOR : IdGenerator = IdGenerator :: new ( ) ;
1818
1919#[ derive( PartialEq , Eq ) ]
20- struct UniqueCluster {
20+ struct ClusterDescriptor {
2121 volume_idx : VolumeIdx ,
2222 cluster : Cluster ,
2323 search_id : SearchId ,
2424}
2525
26- impl UniqueCluster {
26+ impl ClusterDescriptor {
2727 fn compare_volume_and_cluster ( & self , volume_idx : VolumeIdx , cluster : Cluster ) -> bool {
2828 self . volume_idx == volume_idx && self . cluster == cluster
2929 }
4242{
4343 pub ( crate ) block_device : D ,
4444 pub ( crate ) timesource : T ,
45- open_dirs : Vec < UniqueCluster , MAX_DIRS > ,
46- open_files : Vec < UniqueCluster , MAX_FILES > ,
45+ open_dirs : Vec < ClusterDescriptor , MAX_DIRS > ,
46+ open_files : Vec < ClusterDescriptor , MAX_FILES > ,
4747}
4848
4949impl < D , T > VolumeManager < D , T , 4 , 4 >
@@ -167,26 +167,29 @@ where
167167 }
168168 }
169169
170- /// Open a directory.
170+ /// Open the volume's root directory.
171171 ///
172172 /// You can then read the directory entries with `iterate_dir` and `open_file_in_dir`.
173173 ///
174174 /// TODO: Work out how to prevent damage occuring to the file system while
175175 /// this directory handle is open. In particular, stop this directory
176176 /// being unlinked.
177177 pub fn open_root_dir ( & mut self , volume : & Volume ) -> Result < Directory , Error < D :: Error > > {
178+ if self . open_dirs . is_full ( ) {
179+ return Err ( Error :: TooManyOpenDirs ) ;
180+ }
181+
178182 // Find a free directory entry, and check the root dir isn't open. As
179183 // we already know the root dir's magic cluster number, we can do both
180184 // checks in one loop.
181- for u in self . open_dirs . iter ( ) {
182- if u. compare_volume_and_cluster ( volume. idx , Cluster :: ROOT_DIR ) {
183- return Err ( Error :: DirAlreadyOpen ) ;
184- }
185+ if cluster_already_open ( & self . open_dirs , volume. idx , Cluster :: ROOT_DIR ) {
186+ return Err ( Error :: DirAlreadyOpen ) ;
185187 }
188+
186189 let search_id = ID_GENERATOR . next ( ) ;
187190 // Remember this open directory
188191 self . open_dirs
189- . push ( UniqueCluster {
192+ . push ( ClusterDescriptor {
190193 volume_idx : volume. idx ,
191194 cluster : Cluster :: ROOT_DIR ,
192195 search_id,
@@ -226,15 +229,14 @@ where
226229 }
227230
228231 // Check it's not already open
229- for d in self . open_dirs . iter ( ) {
230- if d. compare_volume_and_cluster ( volume. idx , dir_entry. cluster ) {
231- return Err ( Error :: DirAlreadyOpen ) ;
232- }
232+ if cluster_already_open ( & self . open_dirs , volume. idx , dir_entry. cluster ) {
233+ return Err ( Error :: DirAlreadyOpen ) ;
233234 }
235+
234236 // Remember this open directory.
235237 let search_id = ID_GENERATOR . next ( ) ;
236238 self . open_dirs
237- . push ( UniqueCluster {
239+ . push ( ClusterDescriptor {
238240 volume_idx : volume. idx ,
239241 cluster : dir_entry. cluster ,
240242 search_id,
@@ -250,12 +252,11 @@ where
250252 /// Close a directory. You cannot perform operations on an open directory
251253 /// and so must close it if you want to do something with it.
252254 pub fn close_dir ( & mut self , volume : & Volume , dir : Directory ) {
253- for ( i, d) in self . open_dirs . iter ( ) . enumerate ( ) {
254- if d. compare_id ( dir. search_id ) {
255- self . open_dirs . swap_remove ( i) ;
256- break ;
257- }
258- }
255+ // Unwrap, because we should never be in a situation where we're attempting to close a dir
256+ // with an ID which doesn't exist in our open dirs list.
257+ let idx_to_close = cluster_position_by_id ( & self . open_dirs , dir. search_id ) . unwrap ( ) ;
258+ self . open_dirs . swap_remove ( idx_to_close) ;
259+ drop ( dir) ;
259260 }
260261
261262 /// Look in a directory for a named file.
@@ -295,12 +296,12 @@ where
295296 if self . open_files . is_full ( ) {
296297 return Err ( Error :: TooManyOpenFiles ) ;
297298 }
299+
298300 // Check it's not already open
299- for d in self . open_files . iter ( ) {
300- if d. compare_volume_and_cluster ( volume. idx , dir_entry. cluster ) {
301- return Err ( Error :: DirAlreadyOpen ) ;
302- }
301+ if cluster_already_open ( & self . open_dirs , volume. idx , dir_entry. cluster ) {
302+ return Err ( Error :: DirAlreadyOpen ) ;
303303 }
304+
304305 if dir_entry. attributes . is_directory ( ) {
305306 return Err ( Error :: OpenedDirAsFile ) ;
306307 }
@@ -363,9 +364,10 @@ where
363364 }
364365 _ => return Err ( Error :: Unsupported ) ,
365366 } ;
367+
366368 // Remember this open file
367369 self . open_files
368- . push ( UniqueCluster {
370+ . push ( ClusterDescriptor {
369371 volume_idx : volume. idx ,
370372 cluster : file. starting_cluster ,
371373 search_id,
@@ -433,7 +435,7 @@ where
433435
434436 // Remember this open file
435437 self . open_files
436- . push ( UniqueCluster {
438+ . push ( ClusterDescriptor {
437439 volume_idx : volume. idx ,
438440 cluster : file. starting_cluster ,
439441 search_id,
@@ -471,10 +473,8 @@ where
471473 return Err ( Error :: DeleteDirAsFile ) ;
472474 }
473475
474- for d in self . open_files . iter_mut ( ) {
475- if d. compare_volume_and_cluster ( volume. idx , dir_entry. cluster ) {
476- return Err ( Error :: FileIsOpen ) ;
477- }
476+ if cluster_already_open ( & self . open_files , volume. idx , dir_entry. cluster ) {
477+ return Err ( Error :: FileIsOpen ) ;
478478 }
479479
480480 match & volume. volume_type {
@@ -541,6 +541,16 @@ where
541541 VolumeType :: Fat ( fat) => fat. alloc_cluster ( self , None , false ) ?,
542542 } ;
543543
544+ // Update the cluster descriptor in our open files list
545+ let cluster_to_update = self
546+ . open_files
547+ . iter_mut ( )
548+ . find ( |d| d. compare_id ( file. search_id ) ) ;
549+
550+ if let Some ( c) = cluster_to_update {
551+ c. cluster = file. starting_cluster ;
552+ }
553+
544554 file. entry . cluster = file. starting_cluster ;
545555 debug ! ( "Alloc first cluster {:?}" , file. starting_cluster) ;
546556 }
@@ -630,12 +640,12 @@ where
630640
631641 /// Close a file with the given full path.
632642 pub fn close_file ( & mut self , volume : & Volume , file : File ) -> Result < ( ) , Error < D :: Error > > {
633- for ( i , f ) in self . open_files . iter ( ) . enumerate ( ) {
634- if f . compare_id ( file . search_id ) {
635- self . open_files . swap_remove ( i ) ;
636- break ;
637- }
638- }
643+ // Unwrap, because we should never be in a situation where we're attempting to close a file
644+ // with an ID which doesn't exist in our open files list.
645+ let idx_to_close = cluster_position_by_id ( & self . open_files , file . search_id ) . unwrap ( ) ;
646+ self . open_files . swap_remove ( idx_to_close ) ;
647+
648+ drop ( file ) ;
639649 Ok ( ( ) )
640650 }
641651
@@ -704,6 +714,19 @@ where
704714 }
705715}
706716
717+ fn cluster_position_by_id ( vec : & [ ClusterDescriptor ] , id_to_find : SearchId ) -> Option < usize > {
718+ vec. iter ( ) . position ( |f| f. compare_id ( id_to_find) )
719+ }
720+
721+ fn cluster_already_open (
722+ vec : & [ ClusterDescriptor ] ,
723+ volume_idx : VolumeIdx ,
724+ cluster : Cluster ,
725+ ) -> bool {
726+ vec. iter ( )
727+ . any ( |d| d. compare_volume_and_cluster ( volume_idx, cluster) )
728+ }
729+
707730/// Transform mode variants (ReadWriteCreate_Or_Append) to simple modes ReadWriteAppend or
708731/// ReadWriteCreate
709732fn solve_mode_variant ( mode : Mode , dir_entry_is_some : bool ) -> Mode {
0 commit comments