@@ -5,12 +5,16 @@ use core::convert::TryFrom;
5
5
6
6
use crate :: fat:: { self , RESERVED_ENTRIES } ;
7
7
use crate :: filesystem:: {
8
- Attributes , Cluster , DirEntry , Directory , File , Mode , ShortFileName , TimeSource , MAX_FILE_SIZE ,
8
+ Attributes , Cluster , DirEntry , Directory , File , IdGenerator , Mode , SearchId , ShortFileName ,
9
+ TimeSource , MAX_FILE_SIZE ,
9
10
} ;
10
11
use crate :: {
11
12
debug, Block , BlockCount , BlockDevice , BlockIdx , Error , Volume , VolumeIdx , VolumeType ,
12
13
PARTITION_ID_FAT16 , PARTITION_ID_FAT16_LBA , PARTITION_ID_FAT32_CHS_LBA , PARTITION_ID_FAT32_LBA ,
13
14
} ;
15
+ use heapless:: Vec ;
16
+
17
+ static ID_GENERATOR : IdGenerator = IdGenerator :: new ( ) ;
14
18
15
19
/// A `VolumeManager` wraps a block device and gives access to the volumes within it.
16
20
pub struct VolumeManager < D , T , const MAX_DIRS : usize = 4 , const MAX_FILES : usize = 4 >
21
25
{
22
26
pub ( crate ) block_device : D ,
23
27
pub ( crate ) timesource : T ,
24
- open_dirs : [ ( VolumeIdx , Cluster ) ; MAX_DIRS ] ,
25
- open_files : [ ( VolumeIdx , Cluster ) ; MAX_FILES ] ,
28
+ open_dirs : Vec < ( VolumeIdx , Cluster , SearchId ) , MAX_DIRS > ,
29
+ open_files : Vec < ( VolumeIdx , Cluster , SearchId ) , MAX_FILES > ,
26
30
}
27
31
28
32
impl < D , T > VolumeManager < D , T , 4 , 4 >
60
64
VolumeManager {
61
65
block_device,
62
66
timesource,
63
- open_dirs : [ ( VolumeIdx ( 0 ) , Cluster :: INVALID ) ; MAX_DIRS ] ,
64
- open_files : [ ( VolumeIdx ( 0 ) , Cluster :: INVALID ) ; MAX_FILES ] ,
67
+ open_dirs : Vec :: new ( ) ,
68
+ open_files : Vec :: new ( ) ,
65
69
}
66
70
}
67
71
@@ -157,21 +161,20 @@ where
157
161
// Find a free directory entry, and check the root dir isn't open. As
158
162
// we already know the root dir's magic cluster number, we can do both
159
163
// checks in one loop.
160
- let mut open_dirs_row = None ;
161
- for ( i, d) in self . open_dirs . iter ( ) . enumerate ( ) {
162
- if * d == ( volume. idx , Cluster :: ROOT_DIR ) {
164
+ for ( v, c, _) in self . open_dirs . iter ( ) {
165
+ if * v == volume. idx && * c == Cluster :: ROOT_DIR {
163
166
return Err ( Error :: DirAlreadyOpen ) ;
164
167
}
165
- if d. 1 == Cluster :: INVALID {
166
- open_dirs_row = Some ( i) ;
167
- break ;
168
- }
169
168
}
170
- let open_dirs_row = open_dirs_row . ok_or ( Error :: TooManyOpenDirs ) ? ;
169
+ let search_id = ID_GENERATOR . next ( ) ;
171
170
// Remember this open directory
172
- self . open_dirs [ open_dirs_row] = ( volume. idx , Cluster :: ROOT_DIR ) ;
171
+ self . open_dirs
172
+ . push ( ( volume. idx , Cluster :: ROOT_DIR , search_id) )
173
+ . map_err ( |_| Error :: TooManyOpenDirs ) ?;
174
+
173
175
Ok ( Directory {
174
176
cluster : Cluster :: ROOT_DIR ,
177
+ search_id,
175
178
} )
176
179
}
177
180
@@ -188,14 +191,9 @@ where
188
191
parent_dir : & Directory ,
189
192
name : & str ,
190
193
) -> Result < Directory , Error < D :: Error > > {
191
- // Find a free open directory table row
192
- let mut open_dirs_row = None ;
193
- for ( i, d) in self . open_dirs . iter ( ) . enumerate ( ) {
194
- if d. 1 == Cluster :: INVALID {
195
- open_dirs_row = Some ( i) ;
196
- }
194
+ if self . open_dirs . is_full ( ) {
195
+ return Err ( Error :: TooManyOpenDirs ) ;
197
196
}
198
- let open_dirs_row = open_dirs_row. ok_or ( Error :: TooManyOpenDirs ) ?;
199
197
200
198
// Open the directory
201
199
let dir_entry = match & volume. volume_type {
@@ -207,25 +205,29 @@ where
207
205
}
208
206
209
207
// Check it's not already open
210
- for ( _i , dir_table_row) in self . open_dirs . iter ( ) . enumerate ( ) {
211
- if * dir_table_row == ( volume. idx , dir_entry. cluster ) {
208
+ for dir_table_row in self . open_dirs . iter ( ) {
209
+ if dir_table_row. 0 == volume. idx && dir_table_row . 1 == dir_entry. cluster {
212
210
return Err ( Error :: DirAlreadyOpen ) ;
213
211
}
214
212
}
215
- // Remember this open directory
216
- self . open_dirs [ open_dirs_row] = ( volume. idx , dir_entry. cluster ) ;
213
+ // Remember this open directory.
214
+ let search_id = ID_GENERATOR . next ( ) ;
215
+ self . open_dirs
216
+ . push ( ( volume. idx , dir_entry. cluster , search_id) )
217
+ . map_err ( |_| Error :: TooManyOpenDirs ) ?;
218
+
217
219
Ok ( Directory {
218
220
cluster : dir_entry. cluster ,
221
+ search_id,
219
222
} )
220
223
}
221
224
222
225
/// Close a directory. You cannot perform operations on an open directory
223
226
/// and so must close it if you want to do something with it.
224
227
pub fn close_dir ( & mut self , volume : & Volume , dir : Directory ) {
225
- let target = ( volume. idx , dir. cluster ) ;
226
- for d in self . open_dirs . iter_mut ( ) {
227
- if * d == target {
228
- d. 1 = Cluster :: INVALID ;
228
+ for ( i, d) in self . open_dirs . iter ( ) . enumerate ( ) {
229
+ if d. 2 == dir. search_id {
230
+ self . open_dirs . swap_remove ( i) ;
229
231
break ;
230
232
}
231
233
}
@@ -265,10 +267,12 @@ where
265
267
dir_entry : DirEntry ,
266
268
mode : Mode ,
267
269
) -> Result < File , Error < D :: Error > > {
268
- let open_files_row = self . get_open_files_row ( ) ?;
270
+ if self . open_files . is_full ( ) {
271
+ return Err ( Error :: TooManyOpenFiles ) ;
272
+ }
269
273
// Check it's not already open
270
274
for dir_table_row in self . open_files . iter ( ) {
271
- if * dir_table_row == ( volume. idx , dir_entry. cluster ) {
275
+ if dir_table_row. 0 == volume. idx && dir_table_row . 1 == dir_entry. cluster {
272
276
return Err ( Error :: DirAlreadyOpen ) ;
273
277
}
274
278
}
@@ -280,6 +284,8 @@ where
280
284
}
281
285
282
286
let mode = solve_mode_variant ( mode, true ) ;
287
+ let search_id = ID_GENERATOR . next ( ) ;
288
+
283
289
let file = match mode {
284
290
Mode :: ReadOnly => File {
285
291
starting_cluster : dir_entry. cluster ,
@@ -288,6 +294,7 @@ where
288
294
length : dir_entry. size ,
289
295
mode,
290
296
entry : dir_entry,
297
+ search_id,
291
298
} ,
292
299
Mode :: ReadWriteAppend => {
293
300
let mut file = File {
@@ -297,6 +304,7 @@ where
297
304
length : dir_entry. size ,
298
305
mode,
299
306
entry : dir_entry,
307
+ search_id,
300
308
} ;
301
309
// seek_from_end with 0 can't fail
302
310
file. seek_from_end ( 0 ) . ok ( ) ;
@@ -310,6 +318,7 @@ where
310
318
length : dir_entry. size ,
311
319
mode,
312
320
entry : dir_entry,
321
+ search_id,
313
322
} ;
314
323
match & mut volume. volume_type {
315
324
VolumeType :: Fat ( fat) => {
@@ -330,7 +339,10 @@ where
330
339
_ => return Err ( Error :: Unsupported ) ,
331
340
} ;
332
341
// Remember this open file
333
- self . open_files [ open_files_row] = ( volume. idx , file. starting_cluster ) ;
342
+ self . open_files
343
+ . push ( ( volume. idx , file. starting_cluster , search_id) )
344
+ . map_err ( |_| Error :: TooManyOpenDirs ) ?;
345
+
334
346
Ok ( file)
335
347
}
336
348
@@ -346,7 +358,10 @@ where
346
358
VolumeType :: Fat ( fat) => fat. find_directory_entry ( self , dir, name) ,
347
359
} ;
348
360
349
- let open_files_row = self . get_open_files_row ( ) ?;
361
+ if self . open_files . is_full ( ) {
362
+ return Err ( Error :: TooManyOpenFiles ) ;
363
+ }
364
+
350
365
let dir_entry = match dir_entry {
351
366
Ok ( entry) => Some ( entry) ,
352
367
Err ( _)
@@ -375,16 +390,23 @@ where
375
390
}
376
391
} ;
377
392
393
+ let search_id = ID_GENERATOR . next ( ) ;
394
+
378
395
let file = File {
379
396
starting_cluster : entry. cluster ,
380
397
current_cluster : ( 0 , entry. cluster ) ,
381
398
current_offset : 0 ,
382
399
length : entry. size ,
383
400
mode,
384
401
entry,
402
+ search_id,
385
403
} ;
404
+
386
405
// Remember this open file
387
- self . open_files [ open_files_row] = ( volume. idx , file. starting_cluster ) ;
406
+ self . open_files
407
+ . push ( ( volume. idx , file. starting_cluster , search_id) )
408
+ . map_err ( |_| Error :: TooManyOpenFiles ) ?;
409
+
388
410
Ok ( file)
389
411
}
390
412
_ => {
@@ -428,9 +450,8 @@ where
428
450
return Err ( Error :: DeleteDirAsFile ) ;
429
451
}
430
452
431
- let target = ( volume. idx , dir_entry. cluster ) ;
432
453
for d in self . open_files . iter_mut ( ) {
433
- if * d == target {
454
+ if d . 0 == volume . idx && d . 1 == dir_entry . cluster {
434
455
return Err ( Error :: FileIsOpen ) ;
435
456
}
436
457
}
@@ -498,11 +519,6 @@ where
498
519
file. starting_cluster = match & mut volume. volume_type {
499
520
VolumeType :: Fat ( fat) => fat. alloc_cluster ( self , None , false ) ?,
500
521
} ;
501
- for f in self . open_files . iter_mut ( ) {
502
- if f. 1 == Cluster ( 0 ) {
503
- * f = ( f. 0 , file. starting_cluster )
504
- }
505
- }
506
522
507
523
file. entry . cluster = file. starting_cluster ;
508
524
debug ! ( "Alloc first cluster {:?}" , file. starting_cluster) ;
@@ -593,10 +609,9 @@ where
593
609
594
610
/// Close a file with the given full path.
595
611
pub fn close_file ( & mut self , volume : & Volume , file : File ) -> Result < ( ) , Error < D :: Error > > {
596
- let target = ( volume. idx , file. starting_cluster ) ;
597
- for d in self . open_files . iter_mut ( ) {
598
- if * d == target {
599
- d. 1 = Cluster :: INVALID ;
612
+ for ( i, f) in self . open_files . iter ( ) . enumerate ( ) {
613
+ if f. 2 == file. search_id {
614
+ self . open_files . swap_remove ( i) ;
600
615
break ;
601
616
}
602
617
}
@@ -609,7 +624,7 @@ where
609
624
. open_dirs
610
625
. iter ( )
611
626
. chain ( self . open_files . iter ( ) )
612
- . all ( |( _, c) | c == & Cluster :: INVALID )
627
+ . all ( |( _, c, _ ) | c == & Cluster :: INVALID )
613
628
}
614
629
615
630
/// Consume self and return BlockDevice and TimeSource
0 commit comments