@@ -17,13 +17,13 @@ use heapless::Vec;
17
17
static ID_GENERATOR : IdGenerator = IdGenerator :: new ( ) ;
18
18
19
19
#[ derive( PartialEq , Eq ) ]
20
- struct UniqueCluster {
20
+ struct ClusterDescriptor {
21
21
volume_idx : VolumeIdx ,
22
22
cluster : Cluster ,
23
23
search_id : SearchId ,
24
24
}
25
25
26
- impl UniqueCluster {
26
+ impl ClusterDescriptor {
27
27
fn compare_volume_and_cluster ( & self , volume_idx : VolumeIdx , cluster : Cluster ) -> bool {
28
28
self . volume_idx == volume_idx && self . cluster == cluster
29
29
}
42
42
{
43
43
pub ( crate ) block_device : D ,
44
44
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 > ,
47
47
}
48
48
49
49
impl < D , T > VolumeManager < D , T , 4 , 4 >
@@ -167,26 +167,29 @@ where
167
167
}
168
168
}
169
169
170
- /// Open a directory.
170
+ /// Open the volume's root directory.
171
171
///
172
172
/// You can then read the directory entries with `iterate_dir` and `open_file_in_dir`.
173
173
///
174
174
/// TODO: Work out how to prevent damage occuring to the file system while
175
175
/// this directory handle is open. In particular, stop this directory
176
176
/// being unlinked.
177
177
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
+
178
182
// Find a free directory entry, and check the root dir isn't open. As
179
183
// we already know the root dir's magic cluster number, we can do both
180
184
// 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 ) ;
185
187
}
188
+
186
189
let search_id = ID_GENERATOR . next ( ) ;
187
190
// Remember this open directory
188
191
self . open_dirs
189
- . push ( UniqueCluster {
192
+ . push ( ClusterDescriptor {
190
193
volume_idx : volume. idx ,
191
194
cluster : Cluster :: ROOT_DIR ,
192
195
search_id,
@@ -226,15 +229,14 @@ where
226
229
}
227
230
228
231
// 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 ) ;
233
234
}
235
+
234
236
// Remember this open directory.
235
237
let search_id = ID_GENERATOR . next ( ) ;
236
238
self . open_dirs
237
- . push ( UniqueCluster {
239
+ . push ( ClusterDescriptor {
238
240
volume_idx : volume. idx ,
239
241
cluster : dir_entry. cluster ,
240
242
search_id,
@@ -250,12 +252,11 @@ where
250
252
/// Close a directory. You cannot perform operations on an open directory
251
253
/// and so must close it if you want to do something with it.
252
254
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) ;
259
260
}
260
261
261
262
/// Look in a directory for a named file.
@@ -295,12 +296,12 @@ where
295
296
if self . open_files . is_full ( ) {
296
297
return Err ( Error :: TooManyOpenFiles ) ;
297
298
}
299
+
298
300
// 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 ) ;
303
303
}
304
+
304
305
if dir_entry. attributes . is_directory ( ) {
305
306
return Err ( Error :: OpenedDirAsFile ) ;
306
307
}
@@ -363,9 +364,10 @@ where
363
364
}
364
365
_ => return Err ( Error :: Unsupported ) ,
365
366
} ;
367
+
366
368
// Remember this open file
367
369
self . open_files
368
- . push ( UniqueCluster {
370
+ . push ( ClusterDescriptor {
369
371
volume_idx : volume. idx ,
370
372
cluster : file. starting_cluster ,
371
373
search_id,
@@ -433,7 +435,7 @@ where
433
435
434
436
// Remember this open file
435
437
self . open_files
436
- . push ( UniqueCluster {
438
+ . push ( ClusterDescriptor {
437
439
volume_idx : volume. idx ,
438
440
cluster : file. starting_cluster ,
439
441
search_id,
@@ -471,10 +473,8 @@ where
471
473
return Err ( Error :: DeleteDirAsFile ) ;
472
474
}
473
475
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 ) ;
478
478
}
479
479
480
480
match & volume. volume_type {
@@ -541,6 +541,16 @@ where
541
541
VolumeType :: Fat ( fat) => fat. alloc_cluster ( self , None , false ) ?,
542
542
} ;
543
543
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
+
544
554
file. entry . cluster = file. starting_cluster ;
545
555
debug ! ( "Alloc first cluster {:?}" , file. starting_cluster) ;
546
556
}
@@ -630,12 +640,12 @@ where
630
640
631
641
/// Close a file with the given full path.
632
642
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 ) ;
639
649
Ok ( ( ) )
640
650
}
641
651
@@ -704,6 +714,19 @@ where
704
714
}
705
715
}
706
716
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
+
707
730
/// Transform mode variants (ReadWriteCreate_Or_Append) to simple modes ReadWriteAppend or
708
731
/// ReadWriteCreate
709
732
fn solve_mode_variant ( mode : Mode , dir_entry_is_some : bool ) -> Mode {
0 commit comments