Skip to content

Commit b596d4a

Browse files
Merge pull request #92 from ftilde/develop
Add a local on-stack FAT cache for next_cluster
2 parents ea53bc9 + 69eef72 commit b596d4a

File tree

3 files changed

+112
-59
lines changed

3 files changed

+112
-59
lines changed

src/fat/mod.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,38 @@ pub enum FatType {
1414
Fat32,
1515
}
1616

17+
pub(crate) struct BlockCache {
18+
block: Block,
19+
idx: Option<BlockIdx>,
20+
}
21+
impl BlockCache {
22+
pub fn empty() -> Self {
23+
BlockCache {
24+
block: Block::new(),
25+
idx: None,
26+
}
27+
}
28+
pub(crate) fn read<D, T, const MAX_DIRS: usize, const MAX_FILES: usize>(
29+
&mut self,
30+
volume_mgr: &VolumeManager<D, T, MAX_DIRS, MAX_FILES>,
31+
block_idx: BlockIdx,
32+
reason: &str,
33+
) -> Result<&Block, Error<D::Error>>
34+
where
35+
D: BlockDevice,
36+
T: TimeSource,
37+
{
38+
if Some(block_idx) != self.idx {
39+
self.idx = Some(block_idx);
40+
volume_mgr
41+
.block_device
42+
.read(core::slice::from_mut(&mut self.block), block_idx, reason)
43+
.map_err(Error::DeviceError)?;
44+
}
45+
Ok(&self.block)
46+
}
47+
}
48+
1749
mod bpb;
1850
mod info;
1951
mod ondiskdirentry;
@@ -24,6 +56,8 @@ pub use info::{Fat16Info, Fat32Info, FatSpecificInfo, InfoSector};
2456
pub use ondiskdirentry::OnDiskDirEntry;
2557
pub use volume::{parse_volume, FatVolume, VolumeName};
2658

59+
use crate::{Block, BlockDevice, BlockIdx, Error, TimeSource, VolumeManager};
60+
2761
#[cfg(test)]
2862
mod test {
2963

src/fat/volume.rs

Lines changed: 74 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use crate::{
1212
use byteorder::{ByteOrder, LittleEndian};
1313
use core::convert::TryFrom;
1414

15+
use super::BlockCache;
16+
1517
/// The name given to a particular FAT formatted volume.
1618
#[cfg_attr(feature = "defmt-log", derive(defmt::Format))]
1719
#[derive(PartialEq, Eq)]
@@ -179,24 +181,21 @@ impl FatVolume {
179181
&self,
180182
volume_mgr: &VolumeManager<D, T, MAX_DIRS, MAX_FILES>,
181183
cluster: Cluster,
184+
fat_block_cache: &mut BlockCache,
182185
) -> Result<Cluster, Error<D::Error>>
183186
where
184187
D: BlockDevice,
185188
T: TimeSource,
186189
{
187-
let mut blocks = [Block::new()];
188190
match &self.fat_specific_info {
189191
FatSpecificInfo::Fat16(_fat16_info) => {
190192
let fat_offset = cluster.0 * 2;
191193
let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
192194
let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
193-
volume_mgr
194-
.block_device
195-
.read(&mut blocks, this_fat_block_num, "next_cluster")
196-
.map_err(Error::DeviceError)?;
197-
let fat_entry = LittleEndian::read_u16(
198-
&blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 1],
199-
);
195+
let block =
196+
fat_block_cache.read(&volume_mgr, this_fat_block_num, "next_cluster")?;
197+
let fat_entry =
198+
LittleEndian::read_u16(&block[this_fat_ent_offset..=this_fat_ent_offset + 1]);
200199
match fat_entry {
201200
0xFFF7 => {
202201
// Bad cluster
@@ -216,13 +215,11 @@ impl FatVolume {
216215
let fat_offset = cluster.0 * 4;
217216
let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
218217
let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
219-
volume_mgr
220-
.block_device
221-
.read(&mut blocks, this_fat_block_num, "next_cluster")
222-
.map_err(Error::DeviceError)?;
223-
let fat_entry = LittleEndian::read_u32(
224-
&blocks[0][this_fat_ent_offset..=this_fat_ent_offset + 3],
225-
) & 0x0FFF_FFFF;
218+
let block =
219+
fat_block_cache.read(&volume_mgr, this_fat_block_num, "next_cluster")?;
220+
let fat_entry =
221+
LittleEndian::read_u32(&block[this_fat_ent_offset..=this_fat_ent_offset + 3])
222+
& 0x0FFF_FFFF;
226223
match fat_entry {
227224
0x0000_0000 => {
228225
// Jumped to free space
@@ -341,18 +338,20 @@ impl FatVolume {
341338
}
342339
}
343340
if cluster != Cluster::ROOT_DIR {
344-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
345-
Ok(n) => {
346-
first_dir_block_num = self.cluster_to_block(n);
347-
Some(n)
348-
}
349-
Err(Error::EndOfFile) => {
350-
let c = self.alloc_cluster(volume_mgr, Some(cluster), true)?;
351-
first_dir_block_num = self.cluster_to_block(c);
352-
Some(c)
353-
}
354-
_ => None,
355-
};
341+
let mut block_cache = BlockCache::empty();
342+
current_cluster =
343+
match self.next_cluster(volume_mgr, cluster, &mut block_cache) {
344+
Ok(n) => {
345+
first_dir_block_num = self.cluster_to_block(n);
346+
Some(n)
347+
}
348+
Err(Error::EndOfFile) => {
349+
let c = self.alloc_cluster(volume_mgr, Some(cluster), true)?;
350+
first_dir_block_num = self.cluster_to_block(c);
351+
Some(c)
352+
}
353+
_ => None,
354+
};
356355
} else {
357356
current_cluster = None;
358357
}
@@ -399,7 +398,9 @@ impl FatVolume {
399398
}
400399
}
401400
}
402-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
401+
let mut block_cache = BlockCache::empty();
402+
current_cluster = match self.next_cluster(volume_mgr, cluster, &mut block_cache)
403+
{
403404
Ok(n) => {
404405
first_dir_block_num = self.cluster_to_block(n);
405406
Some(n)
@@ -445,6 +446,7 @@ impl FatVolume {
445446
_ => BlockCount(u32::from(self.blocks_per_cluster)),
446447
};
447448
let mut blocks = [Block::new()];
449+
let mut block_cache = BlockCache::empty();
448450
while let Some(cluster) = current_cluster {
449451
for block in first_dir_block_num.range(dir_size) {
450452
volume_mgr
@@ -467,13 +469,14 @@ impl FatVolume {
467469
}
468470
}
469471
if cluster != Cluster::ROOT_DIR {
470-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
471-
Ok(n) => {
472-
first_dir_block_num = self.cluster_to_block(n);
473-
Some(n)
474-
}
475-
_ => None,
476-
};
472+
current_cluster =
473+
match self.next_cluster(volume_mgr, cluster, &mut block_cache) {
474+
Ok(n) => {
475+
first_dir_block_num = self.cluster_to_block(n);
476+
Some(n)
477+
}
478+
_ => None,
479+
};
477480
} else {
478481
current_cluster = None;
479482
}
@@ -486,6 +489,7 @@ impl FatVolume {
486489
_ => Some(dir.cluster),
487490
};
488491
let mut blocks = [Block::new()];
492+
let mut block_cache = BlockCache::empty();
489493
while let Some(cluster) = current_cluster {
490494
let block_idx = self.cluster_to_block(cluster);
491495
for block in block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
@@ -508,7 +512,8 @@ impl FatVolume {
508512
}
509513
}
510514
}
511-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
515+
current_cluster = match self.next_cluster(volume_mgr, cluster, &mut block_cache)
516+
{
512517
Ok(n) => Some(n),
513518
_ => None,
514519
};
@@ -545,6 +550,7 @@ impl FatVolume {
545550
_ => BlockCount(u32::from(self.blocks_per_cluster)),
546551
};
547552

553+
let mut block_cache = BlockCache::empty();
548554
while let Some(cluster) = current_cluster {
549555
for block in first_dir_block_num.range(dir_size) {
550556
match self.find_entry_in_block(
@@ -558,13 +564,14 @@ impl FatVolume {
558564
}
559565
}
560566
if cluster != Cluster::ROOT_DIR {
561-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
562-
Ok(n) => {
563-
first_dir_block_num = self.cluster_to_block(n);
564-
Some(n)
565-
}
566-
_ => None,
567-
};
567+
current_cluster =
568+
match self.next_cluster(volume_mgr, cluster, &mut block_cache) {
569+
Ok(n) => {
570+
first_dir_block_num = self.cluster_to_block(n);
571+
Some(n)
572+
}
573+
_ => None,
574+
};
568575
} else {
569576
current_cluster = None;
570577
}
@@ -576,6 +583,7 @@ impl FatVolume {
576583
Cluster::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
577584
_ => Some(dir.cluster),
578585
};
586+
let mut block_cache = BlockCache::empty();
579587
while let Some(cluster) = current_cluster {
580588
let block_idx = self.cluster_to_block(cluster);
581589
for block in block_idx.range(BlockCount(u32::from(self.blocks_per_cluster))) {
@@ -589,7 +597,8 @@ impl FatVolume {
589597
x => return x,
590598
}
591599
}
592-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
600+
current_cluster = match self.next_cluster(volume_mgr, cluster, &mut block_cache)
601+
{
593602
Ok(n) => Some(n),
594603
_ => None,
595604
}
@@ -668,13 +677,15 @@ impl FatVolume {
668677
}
669678
}
670679
if cluster != Cluster::ROOT_DIR {
671-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
672-
Ok(n) => {
673-
first_dir_block_num = self.cluster_to_block(n);
674-
Some(n)
675-
}
676-
_ => None,
677-
};
680+
let mut block_cache = BlockCache::empty();
681+
current_cluster =
682+
match self.next_cluster(volume_mgr, cluster, &mut block_cache) {
683+
Ok(n) => {
684+
first_dir_block_num = self.cluster_to_block(n);
685+
Some(n)
686+
}
687+
_ => None,
688+
};
678689
} else {
679690
current_cluster = None;
680691
}
@@ -694,7 +705,9 @@ impl FatVolume {
694705
x => return x,
695706
}
696707
}
697-
current_cluster = match self.next_cluster(volume_mgr, cluster) {
708+
let mut block_cache = BlockCache::empty();
709+
current_cluster = match self.next_cluster(volume_mgr, cluster, &mut block_cache)
710+
{
698711
Ok(n) => Some(n),
699712
_ => None,
700713
}
@@ -920,10 +933,13 @@ impl FatVolume {
920933
// file doesn't have any valid cluster allocated, there is nothing to do
921934
return Ok(());
922935
}
923-
let mut next = match self.next_cluster(volume_mgr, cluster) {
924-
Ok(n) => n,
925-
Err(Error::EndOfFile) => return Ok(()),
926-
Err(e) => return Err(e),
936+
let mut next = {
937+
let mut block_cache = BlockCache::empty();
938+
match self.next_cluster(volume_mgr, cluster, &mut block_cache) {
939+
Ok(n) => n,
940+
Err(Error::EndOfFile) => return Ok(()),
941+
Err(e) => return Err(e),
942+
}
927943
};
928944
if let Some(ref mut next_free_cluster) = self.next_free_cluster {
929945
if next_free_cluster.0 > next.0 {
@@ -934,7 +950,8 @@ impl FatVolume {
934950
}
935951
self.update_fat(volume_mgr, cluster, Cluster::END_OF_FILE)?;
936952
loop {
937-
match self.next_cluster(volume_mgr, next) {
953+
let mut block_cache = BlockCache::empty();
954+
match self.next_cluster(volume_mgr, next, &mut block_cache) {
938955
Ok(n) => {
939956
self.update_fat(volume_mgr, next, Cluster::EMPTY)?;
940957
next = n;

src/volume_mgr.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
use byteorder::{ByteOrder, LittleEndian};
44
use core::convert::TryFrom;
55

6-
use crate::fat::{self, RESERVED_ENTRIES};
6+
use crate::fat::{self, BlockCache, RESERVED_ENTRIES};
7+
78
use crate::filesystem::{
89
Attributes, Cluster, DirEntry, Directory, File, IdGenerator, Mode, SearchId, ShortFileName,
910
TimeSource, MAX_FILE_SIZE,
@@ -697,9 +698,10 @@ where
697698
// How many clusters forward do we need to go?
698699
let offset_from_cluster = desired_offset - start.0;
699700
let num_clusters = offset_from_cluster / bytes_per_cluster;
701+
let mut block_cache = BlockCache::empty();
700702
for _ in 0..num_clusters {
701703
start.1 = match &volume.volume_type {
702-
VolumeType::Fat(fat) => fat.next_cluster(self, start.1)?,
704+
VolumeType::Fat(fat) => fat.next_cluster(self, start.1, &mut block_cache)?,
703705
};
704706
start.0 += bytes_per_cluster;
705707
}

0 commit comments

Comments
 (0)