Skip to content

Commit f3e7aeb

Browse files
committed
Improve entries reading
1 parent 842adec commit f3e7aeb

File tree

3 files changed

+48
-21
lines changed

3 files changed

+48
-21
lines changed

src/fat/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,12 @@ mod test {
252252
let on_disk_entry = OnDiskDirEntry::new(part);
253253
match expected {
254254
Expected::Lfn(start, index, contents) if on_disk_entry.is_lfn() => {
255-
let (calc_start, calc_index, calc_contents) =
255+
let (calc_start, calc_index, calc_contents, _) =
256256
on_disk_entry.lfn_contents().unwrap();
257257
assert_eq!(*start, calc_start);
258258
assert_eq!(*index, calc_index);
259259
assert_eq!(*contents, calc_contents);
260+
// TODO: Check checksum
260261
}
261262
Expected::Short(expected_entry) if !on_disk_entry.is_lfn() => {
262263
let parsed_entry = on_disk_entry.get_entry(FatType::Fat32, BlockIdx(0), 0);

src/fat/ondiskdirentry.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,12 @@ impl<'a> OnDiskDirEntry<'a> {
7878
}
7979

8080
/// If this is an LFN, get the contents so we can re-assemble the filename.
81-
pub fn lfn_contents(&self) -> Option<(bool, u8, [char; 13])> {
81+
pub fn lfn_contents(&self) -> Option<(bool, u8, [char; 13], u8)> {
8282
if self.is_lfn() {
8383
let mut buffer = [' '; 13];
8484
let is_start = (self.data[0] & 0x40) != 0;
8585
let sequence = self.data[0] & 0x1F;
86+
let checksum = self.data[13];
8687
// LFNs store UCS-2, so we can map from 16-bit char to 32-bit char without problem.
8788
buffer[0] =
8889
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[1..=2]))).unwrap();
@@ -118,7 +119,7 @@ impl<'a> OnDiskDirEntry<'a> {
118119
buffer[12] =
119120
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[30..=31])))
120121
.unwrap();
121-
Some((is_start, sequence, buffer))
122+
Some((is_start, sequence, buffer, checksum))
122123
} else {
123124
None
124125
}

src/fat/volume.rs

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
};
1313
use byteorder::{ByteOrder, LittleEndian};
1414
use core::convert::TryFrom;
15-
use heapless::String;
15+
use heapless::{String, Vec};
1616

1717
/// An MS-DOS 11 character volume label.
1818
///
@@ -615,8 +615,9 @@ impl FatVolume {
615615
_ => Some(dir_info.cluster),
616616
};
617617

618-
let mut lfn_buffer = [[' '; 13]; 8];
619-
let mut lfn_pointer = 0;
618+
let mut lfn_stack = Vec::<String<32>, 8>::new();
619+
let mut current_checksum: Option<u8> = None;
620+
let mut current_sequence: Option<u8> = None;
620621

621622
while let Some(cluster) = current_cluster {
622623
let start_block_idx = self.cluster_to_block(cluster);
@@ -630,26 +631,50 @@ impl FatVolume {
630631
return Ok(());
631632
} else if dir_entry.is_valid() {
632633
if dir_entry.is_lfn() {
633-
if let Some((_, _, data)) = dir_entry.lfn_contents() {
634-
lfn_buffer[lfn_pointer] = data.clone();
635-
lfn_pointer += 1;
634+
if let Some((is_start, sequence, data, checksum)) =
635+
dir_entry.lfn_contents()
636+
{
637+
// Case for malformed LFN entries, if they ale placed before
638+
// actual entries
639+
let checksum_ok = match current_checksum {
640+
Some(c) => c == checksum,
641+
None => true,
642+
};
643+
let sequence_ok = match current_sequence {
644+
Some(s) => sequence == s - 1 && sequence < 8,
645+
None => true,
646+
};
647+
if is_start || !checksum_ok || !sequence_ok {
648+
lfn_stack.clear();
649+
current_checksum = None;
650+
current_sequence = None;
651+
} else {
652+
current_checksum = Some(checksum);
653+
current_sequence = Some(sequence);
654+
}
655+
656+
let mut name_chunk: String<32> = String::new();
657+
for i in 0..13 {
658+
if data[i] == '\0' {
659+
break;
660+
}
661+
name_chunk.push(data[i]).unwrap();
662+
}
663+
lfn_stack.push(name_chunk).unwrap();
636664
}
637665
} else {
638-
if lfn_pointer > 0 {
666+
if !lfn_stack.is_empty() {
639667
let mut filename: String<255> = String::new();
640-
while lfn_pointer > 0 {
641-
lfn_pointer -= 1;
642-
for i in 0..13 {
643-
// This will only happen on last chunk after last
644-
// character, so simple break is enough
645-
if lfn_buffer[lfn_pointer][i] == '\0' {
646-
break;
647-
} else {
648-
filename.push(lfn_buffer[lfn_pointer][i]);
649-
}
650-
}
668+
lfn_stack.reverse();
669+
for name_chunk in lfn_stack.iter() {
670+
filename.push_str(name_chunk).unwrap();
651671
}
652672
}
673+
674+
lfn_stack.clear();
675+
current_checksum = None;
676+
current_sequence = None;
677+
// TODO calculate checksum and compare with shorf file name
653678
// Safe, since Block::LEN always fits on a u32
654679
let start = (i * OnDiskDirEntry::LEN) as u32;
655680
let entry = dir_entry.get_entry(FatType::Fat32, block_idx, start);

0 commit comments

Comments
 (0)