Skip to content

Commit 6426e70

Browse files
committed
Cleanup ID/volume/cluster search implementation
1 parent b54e9e6 commit 6426e70

File tree

1 file changed

+60
-37
lines changed

1 file changed

+60
-37
lines changed

src/volume_mgr.rs

Lines changed: 60 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@ use heapless::Vec;
1717
static 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
}
@@ -42,8 +42,8 @@ where
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

4949
impl<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
709732
fn solve_mode_variant(mode: Mode, dir_entry_is_some: bool) -> Mode {

0 commit comments

Comments
 (0)