Skip to content

Commit 8c944ce

Browse files
authored
Merge pull request #160 from rust-embedded-community/write-second-fat
Write to the second FAT
2 parents 52e0e4f + 17b733d commit 8c944ce

File tree

3 files changed

+56
-12
lines changed

3 files changed

+56
-12
lines changed

src/blockdevice.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,18 @@ where
137137
)
138138
}
139139

140+
/// Write back a block you read with [`Self::read_mut`] and then modified, but to two locations.
141+
///
142+
/// This is useful for updating two File Allocation Tables.
143+
pub fn write_back_with_duplicate(&mut self, duplicate: BlockIdx) -> Result<(), D::Error> {
144+
self.block_device.write(
145+
&self.block,
146+
self.block_idx.expect("write_back with no read"),
147+
)?;
148+
self.block_device.write(&self.block, duplicate)?;
149+
Ok(())
150+
}
151+
140152
/// Access a blank sector
141153
pub fn blank_mut(&mut self, block_idx: BlockIdx) -> &mut Block {
142154
self.block_idx = Some(block_idx);

src/fat/volume.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ pub struct FatVolume {
149149
/// The block the FAT starts in. Relative to start of partition (so add
150150
/// `self.lba_offset` before passing to volume manager)
151151
pub(crate) fat_start: BlockCount,
152+
/// The block the second FAT starts in. Relative to start of partition (so add
153+
/// `self.lba_offset` before passing to volume manager)
154+
pub(crate) second_fat_start: Option<BlockCount>,
152155
/// Expected number of free clusters
153156
pub(crate) free_clusters_count: Option<u32>,
154157
/// Number of the next expected free cluster
@@ -211,11 +214,15 @@ impl FatVolume {
211214
where
212215
D: BlockDevice,
213216
{
214-
let this_fat_block_num;
217+
let mut second_fat_block_num = None;
215218
match &self.fat_specific_info {
216219
FatSpecificInfo::Fat16(_fat16_info) => {
217220
let fat_offset = cluster.0 * 2;
218-
this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
221+
let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
222+
if let Some(second_fat_start) = self.second_fat_start {
223+
second_fat_block_num =
224+
Some(self.lba_start + second_fat_start.offset_bytes(fat_offset));
225+
}
219226
let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
220227
trace!("Reading FAT for update");
221228
let block = block_cache
@@ -237,7 +244,11 @@ impl FatVolume {
237244
FatSpecificInfo::Fat32(_fat32_info) => {
238245
// FAT32 => 4 bytes per entry
239246
let fat_offset = cluster.0 * 4;
240-
this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
247+
let this_fat_block_num = self.lba_start + self.fat_start.offset_bytes(fat_offset);
248+
if let Some(second_fat_start) = self.second_fat_start {
249+
second_fat_block_num =
250+
Some(self.lba_start + second_fat_start.offset_bytes(fat_offset));
251+
}
241252
let this_fat_ent_offset = (fat_offset % Block::LEN_U32) as usize;
242253
trace!("Reading FAT for update");
243254
let block = block_cache
@@ -259,7 +270,11 @@ impl FatVolume {
259270
}
260271
}
261272
trace!("Updating FAT");
262-
block_cache.write_back()?;
273+
if let Some(duplicate) = second_fat_block_num {
274+
block_cache.write_back_with_duplicate(duplicate)?;
275+
} else {
276+
block_cache.write_back()?;
277+
}
263278
Ok(())
264279
}
265280

@@ -1106,7 +1121,9 @@ impl FatVolume {
11061121
}
11071122
Err(e) => return Err(e),
11081123
};
1124+
// This new cluster is the end of the file's chain
11091125
self.update_fat(block_cache, new_cluster, ClusterId::END_OF_FILE)?;
1126+
// If there's something before this new one, update the FAT to point it at us
11101127
if let Some(cluster) = prev_cluster {
11111128
trace!(
11121129
"Updating old cluster {:?} to {:?} in FAT",
@@ -1136,6 +1153,7 @@ impl FatVolume {
11361153
Err(e) => return Err(e),
11371154
};
11381155
debug!("Next free cluster is {:?}", self.next_free_cluster);
1156+
// Record that we've allocated a cluster
11391157
if let Some(ref mut number_free_cluster) = self.free_clusters_count {
11401158
*number_free_cluster -= 1;
11411159
};
@@ -1243,6 +1261,12 @@ where
12431261
trace!("Reading BPB");
12441262
let block = block_cache.read(lba_start).map_err(Error::DeviceError)?;
12451263
let bpb = Bpb::create_from_bytes(block).map_err(Error::FormatError)?;
1264+
let fat_start = BlockCount(u32::from(bpb.reserved_block_count()));
1265+
let second_fat_start = if bpb.num_fats() == 2 {
1266+
Some(fat_start + BlockCount(bpb.fat_size()))
1267+
} else {
1268+
None
1269+
};
12461270
match bpb.fat_type {
12471271
FatType::Fat16 => {
12481272
if bpb.bytes_per_block() as usize != Block::LEN {
@@ -1252,7 +1276,6 @@ where
12521276
let root_dir_blocks = ((u32::from(bpb.root_entries_count()) * OnDiskDirEntry::LEN_U32)
12531277
+ (Block::LEN_U32 - 1))
12541278
/ Block::LEN_U32;
1255-
let fat_start = BlockCount(u32::from(bpb.reserved_block_count()));
12561279
let first_root_dir_block =
12571280
fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
12581281
let first_data_block = first_root_dir_block + BlockCount(root_dir_blocks);
@@ -1263,8 +1286,9 @@ where
12631286
contents: bpb.volume_label(),
12641287
},
12651288
blocks_per_cluster: bpb.blocks_per_cluster(),
1266-
first_data_block: (first_data_block),
1267-
fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
1289+
first_data_block,
1290+
fat_start,
1291+
second_fat_start,
12681292
free_clusters_count: None,
12691293
next_free_cluster: None,
12701294
cluster_count: bpb.total_clusters(),
@@ -1277,9 +1301,8 @@ where
12771301
}
12781302
FatType::Fat32 => {
12791303
// FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz);
1280-
let first_data_block = u32::from(bpb.reserved_block_count())
1281-
+ (u32::from(bpb.num_fats()) * bpb.fat_size());
1282-
1304+
let first_data_block =
1305+
fat_start + BlockCount(u32::from(bpb.num_fats()) * bpb.fat_size());
12831306
// Safe to unwrap since this is a Fat32 Type
12841307
let info_location = bpb.fs_info_block().unwrap();
12851308
let mut volume = FatVolume {
@@ -1289,8 +1312,9 @@ where
12891312
contents: bpb.volume_label(),
12901313
},
12911314
blocks_per_cluster: bpb.blocks_per_cluster(),
1292-
first_data_block: BlockCount(first_data_block),
1293-
fat_start: BlockCount(u32::from(bpb.reserved_block_count())),
1315+
first_data_block,
1316+
fat_start,
1317+
second_fat_start,
12941318
free_clusters_count: None,
12951319
next_free_cluster: None,
12961320
cluster_count: bpb.total_clusters(),

src/volume_mgr.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,7 @@ where
334334
/// You can't close it if there are any files or directories open on it.
335335
pub fn close_volume(&self, volume: RawVolume) -> Result<(), Error<D::Error>> {
336336
let mut data = self.data.try_borrow_mut().map_err(|_| Error::LockError)?;
337+
let data = data.deref_mut();
337338

338339
for f in data.open_files.iter() {
339340
if f.raw_volume == volume {
@@ -349,6 +350,12 @@ where
349350

350351
let volume_idx = data.get_volume_by_id(volume)?;
351352

353+
match &mut data.open_volumes[volume_idx].volume_type {
354+
VolumeType::Fat(fat) => {
355+
fat.update_info_sector(&mut data.block_cache)?;
356+
}
357+
}
358+
352359
data.open_volumes.swap_remove(volume_idx);
353360

354361
Ok(())
@@ -1552,6 +1559,7 @@ mod tests {
15521559
blocks_per_cluster: 8,
15531560
first_data_block: BlockCount(15136),
15541561
fat_start: BlockCount(32),
1562+
second_fat_start: Some(BlockCount(32 + 0x0000_1D80)),
15551563
name: fat::VolumeName::create_from_str("Pictures").unwrap(),
15561564
free_clusters_count: None,
15571565
next_free_cluster: None,

0 commit comments

Comments
 (0)