Skip to content

Commit

Permalink
Add iterate_dir_lfn.
Browse files Browse the repository at this point in the history
Scoops up bits of LFN into the given LFN buffer and if it all looks OK, passes it to the user-supplied closure as a &str.
  • Loading branch information
jonathanpallant committed Oct 25, 2024
1 parent fe2bdff commit d89944c
Show file tree
Hide file tree
Showing 9 changed files with 451 additions and 143 deletions.
20 changes: 14 additions & 6 deletions examples/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@

use std::{cell::RefCell, io::prelude::*};

use embedded_sdmmc::{Error as EsError, RawDirectory, RawVolume, ShortFileName, VolumeIdx};
use embedded_sdmmc::{
Error as EsError, LfnBuffer, RawDirectory, RawVolume, ShortFileName, VolumeIdx,
};

type VolumeManager = embedded_sdmmc::VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4>;
type Directory<'a> = embedded_sdmmc::Directory<'a, LinuxBlockDevice, Clock, 8, 8, 4>;
Expand Down Expand Up @@ -229,17 +231,23 @@ impl Context {
fn dir(&self, path: &Path) -> Result<(), Error> {
println!("Directory listing of {:?}", path);
let dir = self.resolve_existing_directory(path)?;
dir.iterate_dir(|entry| {
if !entry.attributes.is_volume() && !entry.attributes.is_lfn() {
println!(
"{:12} {:9} {} {} {:08X?} {:?}",
let mut lfn_buffer = LfnBuffer::<256>::new();
dir.iterate_dir_lfn(&mut lfn_buffer, |entry, lfn| {
if !entry.attributes.is_volume() {
print!(
"{:12} {:9} {} {} {:08X?} {:5?}",
entry.name,
entry.size,
entry.ctime,
entry.mtime,
entry.cluster,
entry.attributes
entry.attributes,
);
if let Some(lfn) = lfn {
println!(" {:?}", lfn);
} else {
println!();
}
}
})?;
Ok(())
Expand Down
69 changes: 51 additions & 18 deletions src/fat/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ mod test {
fn test_dir_entries() {
#[derive(Debug)]
enum Expected {
Lfn(bool, u8, [char; 13]),
Lfn(bool, u8, u8, [u16; 13]),
Short(DirEntry),
}
let raw_data = r#"
Expand All @@ -105,6 +105,7 @@ mod test {
422e0064007400620000000f0059ffffffffffffffffffffffff0000ffffffff B..d.t.b.....Y..................
01620063006d00320037000f0059300038002d0072007000690000002d006200 .b.c.m.2.7...Y0.8.-.r.p.i...-.b.
"#;

let results = [
Expected::Short(DirEntry {
name: unsafe {
Expand All @@ -123,9 +124,10 @@ mod test {
Expected::Lfn(
true,
1,
0x47,
[
'o', 'v', 'e', 'r', 'l', 'a', 'y', 's', '\u{0000}', '\u{ffff}', '\u{ffff}',
'\u{ffff}', '\u{ffff}',
'o' as u16, 'v' as u16, 'e' as u16, 'r' as u16, 'l' as u16, 'a' as u16,
'y' as u16, 's' as u16, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
],
),
Expected::Short(DirEntry {
Expand All @@ -141,16 +143,20 @@ mod test {
Expected::Lfn(
true,
2,
0x79,
[
'-', 'p', 'l', 'u', 's', '.', 'd', 't', 'b', '\u{0000}', '\u{ffff}',
'\u{ffff}', '\u{ffff}',
'-' as u16, 'p' as u16, 'l' as u16, 'u' as u16, 's' as u16, '.' as u16,
'd' as u16, 't' as u16, 'b' as u16, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF,
],
),
Expected::Lfn(
false,
1,
0x79,
[
'b', 'c', 'm', '2', '7', '0', '8', '-', 'r', 'p', 'i', '-', 'b',
'b' as u16, 'c' as u16, 'm' as u16, '2' as u16, '7' as u16, '0' as u16,
'8' as u16, '-' as u16, 'r' as u16, 'p' as u16, 'i' as u16, '-' as u16,
'b' as u16,
],
),
Expected::Short(DirEntry {
Expand All @@ -166,8 +172,11 @@ mod test {
Expected::Lfn(
true,
1,
0x12,
[
'C', 'O', 'P', 'Y', 'I', 'N', 'G', '.', 'l', 'i', 'n', 'u', 'x',
'C' as u16, 'O' as u16, 'P' as u16, 'Y' as u16, 'I' as u16, 'N' as u16,
'G' as u16, '.' as u16, 'l' as u16, 'i' as u16, 'n' as u16, 'u' as u16,
'x' as u16,
],
),
Expected::Short(DirEntry {
Expand All @@ -183,16 +192,31 @@ mod test {
Expected::Lfn(
true,
2,
0x67,
[
'c', 'o', 'm', '\u{0}', '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
'\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
'c' as u16,
'o' as u16,
'm' as u16,
'\u{0}' as u16,
0xFFFF,
0xFFFF,
0xFFFF,
0xFFFF,
0xFFFF,
0xFFFF,
0xFFFF,
0xFFFF,
0xFFFF,
],
),
Expected::Lfn(
false,
1,
0x67,
[
'L', 'I', 'C', 'E', 'N', 'C', 'E', '.', 'b', 'r', 'o', 'a', 'd',
'L' as u16, 'I' as u16, 'C' as u16, 'E' as u16, 'N' as u16, 'C' as u16,
'E' as u16, '.' as u16, 'b' as u16, 'r' as u16, 'o' as u16, 'a' as u16,
'd' as u16,
],
),
Expected::Short(DirEntry {
Expand All @@ -208,16 +232,20 @@ mod test {
Expected::Lfn(
true,
2,
0x19,
[
'-', 'b', '.', 'd', 't', 'b', '\u{0000}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
'\u{ffff}', '\u{ffff}', '\u{ffff}',
'-' as u16, 'b' as u16, '.' as u16, 'd' as u16, 't' as u16, 'b' as u16, 0x0000,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
],
),
Expected::Lfn(
false,
1,
0x19,
[
'b', 'c', 'm', '2', '7', '0', '9', '-', 'r', 'p', 'i', '-', '2',
'b' as u16, 'c' as u16, 'm' as u16, '2' as u16, '7' as u16, '0' as u16,
'9' as u16, '-' as u16, 'r' as u16, 'p' as u16, 'i' as u16, '-' as u16,
'2' as u16,
],
),
Expected::Short(DirEntry {
Expand All @@ -233,16 +261,20 @@ mod test {
Expected::Lfn(
true,
2,
0x59,
[
'.', 'd', 't', 'b', '\u{0000}', '\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
'\u{ffff}', '\u{ffff}', '\u{ffff}', '\u{ffff}',
'.' as u16, 'd' as u16, 't' as u16, 'b' as u16, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF,
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
],
),
Expected::Lfn(
false,
1,
0x59,
[
'b', 'c', 'm', '2', '7', '0', '8', '-', 'r', 'p', 'i', '-', 'b',
'b' as u16, 'c' as u16, 'm' as u16, '2' as u16, '7' as u16, '0' as u16,
'8' as u16, '-' as u16, 'r' as u16, 'p' as u16, 'i' as u16, '-' as u16,
'b' as u16,
],
),
];
Expand All @@ -251,12 +283,13 @@ mod test {
for (part, expected) in data.chunks(OnDiskDirEntry::LEN).zip(results.iter()) {
let on_disk_entry = OnDiskDirEntry::new(part);
match expected {
Expected::Lfn(start, index, contents) if on_disk_entry.is_lfn() => {
let (calc_start, calc_index, calc_contents) =
Expected::Lfn(start, index, csum, contents) if on_disk_entry.is_lfn() => {
let (calc_start, calc_index, calc_csum, calc_contents) =
on_disk_entry.lfn_contents().unwrap();
assert_eq!(*start, calc_start);
assert_eq!(*index, calc_index);
assert_eq!(*contents, calc_contents);
assert_eq!(*csum, calc_csum);
}
Expected::Short(expected_entry) if !on_disk_entry.is_lfn() => {
let parsed_entry = on_disk_entry.get_entry(FatType::Fat32, BlockIdx(0), 0);
Expand Down
56 changes: 18 additions & 38 deletions src/fat/ondiskdirentry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,47 +78,27 @@ impl<'a> OnDiskDirEntry<'a> {
}

/// If this is an LFN, get the contents so we can re-assemble the filename.
pub fn lfn_contents(&self) -> Option<(bool, u8, [char; 13])> {
pub fn lfn_contents(&self) -> Option<(bool, u8, u8, [u16; 13])> {
if self.is_lfn() {
let mut buffer = [' '; 13];
let is_start = (self.data[0] & 0x40) != 0;
let sequence = self.data[0] & 0x1F;
// LFNs store UCS-2, so we can map from 16-bit char to 32-bit char without problem.
buffer[0] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[1..=2]))).unwrap();
buffer[1] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[3..=4]))).unwrap();
buffer[2] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[5..=6]))).unwrap();
buffer[3] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[7..=8]))).unwrap();
buffer[4] = core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[9..=10])))
.unwrap();
buffer[5] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[14..=15])))
.unwrap();
buffer[6] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[16..=17])))
.unwrap();
buffer[7] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[18..=19])))
.unwrap();
buffer[8] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[20..=21])))
.unwrap();
buffer[9] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[22..=23])))
.unwrap();
buffer[10] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[24..=25])))
.unwrap();
buffer[11] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[28..=29])))
.unwrap();
buffer[12] =
core::char::from_u32(u32::from(LittleEndian::read_u16(&self.data[30..=31])))
.unwrap();
Some((is_start, sequence, buffer))
let csum = self.data[13];
let buffer = [
LittleEndian::read_u16(&self.data[1..=2]),
LittleEndian::read_u16(&self.data[3..=4]),
LittleEndian::read_u16(&self.data[5..=6]),
LittleEndian::read_u16(&self.data[7..=8]),
LittleEndian::read_u16(&self.data[9..=10]),
LittleEndian::read_u16(&self.data[14..=15]),
LittleEndian::read_u16(&self.data[16..=17]),
LittleEndian::read_u16(&self.data[18..=19]),
LittleEndian::read_u16(&self.data[20..=21]),
LittleEndian::read_u16(&self.data[22..=23]),
LittleEndian::read_u16(&self.data[24..=25]),
LittleEndian::read_u16(&self.data[28..=29]),
LittleEndian::read_u16(&self.data[30..=31]),
];
Some((is_start, sequence, csum, buffer))
} else {
None
}
Expand Down
Loading

0 comments on commit d89944c

Please sign in to comment.