Skip to content

Commit bca6ceb

Browse files
Merge branch 'develop' into update-embedded-hal
2 parents 6414fa7 + 3b5c026 commit bca6ceb

File tree

11 files changed

+391
-45
lines changed

11 files changed

+391
-45
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ The format is based on [Keep a Changelog] and this project adheres to [Semantic
88

99
* `Volume`, `Directory` and `File` are now smart! They hold references to the thing they were made from, and will clean themselves up when dropped. The trade-off is you can can't open multiple volumes, directories or files at the same time.
1010
* Renamed the old types to `RawVolume`, `RawDirectory` and `RawFile`
11+
* New method `make_dir_in_dir`
12+
* Fixed long-standing bug that caused an integer overflow when a FAT32 directory
13+
was longer than one cluster ([#74])
14+
15+
[#74]: https://github.com/rust-embedded-community/embedded-sdmmc-rs/issues/74
1116

1217
## [Version 0.6.0] - 2023-10-20
1318

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ let mut cont: VolumeManager<_, _, 6, 12, 4> = VolumeManager::new_with_limits(blo
5858
* Iterate sub-directories
5959
* Log over defmt or the common log interface (feature flags).
6060

61+
## No-std usage
62+
This repository houses no examples for no-std usage, however you can check out the following examples:
63+
- [Pi Pico](https://github.com/rp-rs/rp-hal-boards/blob/main/boards/rp-pico/examples/pico_spi_sd_card.rs)
64+
- [STM32H7XX](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/sdmmc_fat.rs)
65+
- [atsamd(pygamer)](https://github.com/atsamd-rs/atsamd/blob/master/boards/pygamer/examples/sd_card.rs)
66+
6167
## Todo List (PRs welcome!)
6268

6369
* Create new dirs

examples/big_dir.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
extern crate embedded_sdmmc;
2+
3+
mod linux;
4+
use linux::*;
5+
6+
use embedded_sdmmc::{Error, VolumeManager};
7+
8+
fn main() -> Result<(), embedded_sdmmc::Error<std::io::Error>> {
9+
env_logger::init();
10+
let mut args = std::env::args().skip(1);
11+
let filename = args.next().unwrap_or_else(|| "/dev/mmcblk0".into());
12+
let print_blocks = args.find(|x| x == "-v").map(|_| true).unwrap_or(false);
13+
let lbd = LinuxBlockDevice::new(filename, print_blocks).map_err(Error::DeviceError)?;
14+
let mut volume_mgr: VolumeManager<LinuxBlockDevice, Clock, 8, 8, 4> =
15+
VolumeManager::new_with_limits(lbd, Clock, 0xAA00_0000);
16+
let mut volume = volume_mgr
17+
.open_volume(embedded_sdmmc::VolumeIdx(1))
18+
.unwrap();
19+
println!("Volume: {:?}", volume);
20+
let mut root_dir = volume.open_root_dir().unwrap();
21+
22+
let mut file_num = 0;
23+
loop {
24+
file_num += 1;
25+
let file_name = format!("{}.da", file_num);
26+
println!("opening file {file_name} for writing");
27+
let mut file = root_dir
28+
.open_file_in_dir(
29+
file_name.as_str(),
30+
embedded_sdmmc::Mode::ReadWriteCreateOrTruncate,
31+
)
32+
.unwrap();
33+
let buf = b"hello world, from rust";
34+
println!("writing to file");
35+
file.write(&buf[..]).unwrap();
36+
println!("closing file");
37+
drop(file);
38+
}
39+
}

examples/list_dir.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,11 @@ fn list_dir(
7676
""
7777
}
7878
);
79-
if entry.attributes.is_directory() {
80-
if entry.name != embedded_sdmmc::ShortFileName::parent_dir()
81-
&& entry.name != embedded_sdmmc::ShortFileName::this_dir()
82-
{
83-
children.push(entry.name.clone());
84-
}
79+
if entry.attributes.is_directory()
80+
&& entry.name != embedded_sdmmc::ShortFileName::parent_dir()
81+
&& entry.name != embedded_sdmmc::ShortFileName::this_dir()
82+
{
83+
children.push(entry.name.clone());
8584
}
8685
})?;
8786
for child_name in children {

examples/shell.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ impl Context {
4141
println!("\thexdump <file> -> print a binary file");
4242
println!("\tcd .. -> go up a level");
4343
println!("\tcd <dir> -> change into <dir>");
44+
println!("\tmkdir <dir> -> create a directory called <dir>");
4445
println!("\tquit -> exits the program");
4546
} else if line == "0:" {
4647
self.current_volume = 0;
@@ -59,11 +60,17 @@ impl Context {
5960
};
6061
self.volume_mgr.iterate_dir(s.directory, |entry| {
6162
println!(
62-
"{:12} {:9} {} {:?}",
63-
entry.name, entry.size, entry.mtime, entry.attributes
63+
"{:12} {:9} {} {} {:X?} {:?}",
64+
entry.name,
65+
entry.size,
66+
entry.ctime,
67+
entry.mtime,
68+
entry.cluster,
69+
entry.attributes
6470
);
6571
})?;
6672
} else if let Some(arg) = line.strip_prefix("cd ") {
73+
let arg = arg.trim();
6774
let Some(s) = &mut self.volumes[self.current_volume] else {
6875
println!("This volume isn't available");
6976
return Ok(());
@@ -77,6 +84,7 @@ impl Context {
7784
s.path.push(arg.to_owned());
7885
}
7986
} else if let Some(arg) = line.strip_prefix("cat ") {
87+
let arg = arg.trim();
8088
let Some(s) = &mut self.volumes[self.current_volume] else {
8189
println!("This volume isn't available");
8290
return Ok(());
@@ -99,6 +107,7 @@ impl Context {
99107
println!("I'm afraid that file isn't UTF-8 encoded");
100108
}
101109
} else if let Some(arg) = line.strip_prefix("hexdump ") {
110+
let arg = arg.trim();
102111
let Some(s) = &mut self.volumes[self.current_volume] else {
103112
println!("This volume isn't available");
104113
return Ok(());
@@ -136,6 +145,14 @@ impl Context {
136145
}
137146
println!();
138147
}
148+
} else if let Some(arg) = line.strip_prefix("mkdir ") {
149+
let arg = arg.trim();
150+
let Some(s) = &mut self.volumes[self.current_volume] else {
151+
println!("This volume isn't available");
152+
return Ok(());
153+
};
154+
// make the dir
155+
self.volume_mgr.make_dir_in_dir(s.directory, arg)?;
139156
} else {
140157
println!("Unknown command {line:?} - try 'help' for help");
141158
}

src/fat/volume.rs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ impl FatVolume {
179179
where
180180
D: BlockDevice,
181181
{
182+
if cluster.0 > (u32::MAX / 4) {
183+
panic!("next_cluster called on invalid cluster {:x?}", cluster);
184+
}
182185
match &self.fat_specific_info {
183186
FatSpecificInfo::Fat16(_fat16_info) => {
184187
let fat_offset = cluster.0 * 2;
@@ -275,7 +278,7 @@ impl FatVolume {
275278
&mut self,
276279
block_device: &D,
277280
time_source: &T,
278-
dir: &DirectoryInfo,
281+
dir_cluster: ClusterId,
279282
name: ShortFileName,
280283
attributes: Attributes,
281284
) -> Result<DirEntry, Error<D::Error>>
@@ -289,12 +292,12 @@ impl FatVolume {
289292
// a specially reserved space on disk (see
290293
// `first_root_dir_block`). Other directories can have any size
291294
// as they are made of regular clusters.
292-
let mut current_cluster = Some(dir.cluster);
293-
let mut first_dir_block_num = match dir.cluster {
295+
let mut current_cluster = Some(dir_cluster);
296+
let mut first_dir_block_num = match dir_cluster {
294297
ClusterId::ROOT_DIR => self.lba_start + fat16_info.first_root_dir_block,
295-
_ => self.cluster_to_block(dir.cluster),
298+
_ => self.cluster_to_block(dir_cluster),
296299
};
297-
let dir_size = match dir.cluster {
300+
let dir_size = match dir_cluster {
298301
ClusterId::ROOT_DIR => {
299302
let len_bytes =
300303
u32::from(fat16_info.root_entries_count) * OnDiskDirEntry::LEN_U32;
@@ -360,19 +363,24 @@ impl FatVolume {
360363
FatSpecificInfo::Fat32(fat32_info) => {
361364
// All directories on FAT32 have a cluster chain but the root
362365
// dir starts in a specified cluster.
363-
let mut first_dir_block_num = match dir.cluster {
364-
ClusterId::ROOT_DIR => self.cluster_to_block(fat32_info.first_root_dir_cluster),
365-
_ => self.cluster_to_block(dir.cluster),
366+
let mut current_cluster = match dir_cluster {
367+
ClusterId::ROOT_DIR => Some(fat32_info.first_root_dir_cluster),
368+
_ => Some(dir_cluster),
366369
};
367-
let mut current_cluster = Some(dir.cluster);
370+
let mut first_dir_block_num = self.cluster_to_block(dir_cluster);
368371
let mut blocks = [Block::new()];
369372

370373
let dir_size = BlockCount(u32::from(self.blocks_per_cluster));
374+
// Walk the cluster chain until we run out of clusters
371375
while let Some(cluster) = current_cluster {
376+
// Loop through the blocks in the cluster
372377
for block in first_dir_block_num.range(dir_size) {
378+
// Read a block of directory entries
373379
block_device
374380
.read(&mut blocks, block, "read_dir")
375381
.map_err(Error::DeviceError)?;
382+
// Are any entries in the block we just loaded blank? If so
383+
// we can use them.
376384
for entry in 0..Block::LEN / OnDiskDirEntry::LEN {
377385
let start = entry * OnDiskDirEntry::LEN;
378386
let end = (entry + 1) * OnDiskDirEntry::LEN;
@@ -397,6 +405,8 @@ impl FatVolume {
397405
}
398406
}
399407
}
408+
// Well none of the blocks in that cluster had any space in
409+
// them, let's fetch another one.
400410
let mut block_cache = BlockCache::empty();
401411
current_cluster =
402412
match self.next_cluster(block_device, cluster, &mut block_cache) {
@@ -412,6 +422,8 @@ impl FatVolume {
412422
_ => None,
413423
};
414424
}
425+
// We ran out of clusters in the chain, and apparently we weren't
426+
// able to make the chain longer, so the disk must be full.
415427
Err(Error::NotEnoughSpace)
416428
}
417429
}
@@ -994,6 +1006,34 @@ impl FatVolume {
9941006
}
9951007
Ok(())
9961008
}
1009+
1010+
/// Writes a Directory Entry to the disk
1011+
pub(crate) fn write_entry_to_disk<D>(
1012+
&self,
1013+
block_device: &D,
1014+
entry: &DirEntry,
1015+
) -> Result<(), Error<D::Error>>
1016+
where
1017+
D: BlockDevice,
1018+
{
1019+
let fat_type = match self.fat_specific_info {
1020+
FatSpecificInfo::Fat16(_) => FatType::Fat16,
1021+
FatSpecificInfo::Fat32(_) => FatType::Fat32,
1022+
};
1023+
let mut blocks = [Block::new()];
1024+
block_device
1025+
.read(&mut blocks, entry.entry_block, "read")
1026+
.map_err(Error::DeviceError)?;
1027+
let block = &mut blocks[0];
1028+
1029+
let start = usize::try_from(entry.entry_offset).map_err(|_| Error::ConversionError)?;
1030+
block[start..start + 32].copy_from_slice(&entry.serialize(fat_type)[..]);
1031+
1032+
block_device
1033+
.write(&blocks, entry.entry_block)
1034+
.map_err(Error::DeviceError)?;
1035+
Ok(())
1036+
}
9971037
}
9981038

9991039
/// Load the boot parameter block from the start of the given partition and

src/filesystem/directory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub struct DirEntry {
5151
pub struct RawDirectory(pub(crate) SearchId);
5252

5353
impl RawDirectory {
54-
/// Convert a raw file into a droppable [`File`]
54+
/// Convert a raw directory into a droppable [`Directory`]
5555
pub fn to_directory<
5656
D,
5757
T,

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,8 @@ where
231231
InvalidOffset,
232232
/// Disk is full
233233
DiskFull,
234+
/// A directory with that name already exists
235+
DirAlreadyExists,
234236
}
235237

236238
impl<E> From<E> for Error<E>

0 commit comments

Comments
 (0)