Skip to content

Commit c63688f

Browse files
Can now close volumes.
Test coverage at 56.2%.
1 parent 33e93d7 commit c63688f

File tree

5 files changed

+299
-0
lines changed

5 files changed

+299
-0
lines changed

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ where
200200
DeleteDirAsFile,
201201
/// You can't delete an open file
202202
FileIsOpen,
203+
/// You can't close a volume with open files or directories
204+
VolumeStillInUse,
205+
/// You can't open a volume twice
206+
VolumeAlreadyOpen,
203207
/// We can't do that yet
204208
Unsupported,
205209
/// Tried to read beyond end of file

src/volume_mgr.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ where
115115
return Err(Error::TooManyOpenVolumes);
116116
}
117117

118+
for v in self.open_volumes.iter() {
119+
if v.idx == volume_idx {
120+
return Err(Error::VolumeAlreadyOpen);
121+
}
122+
}
123+
118124
let (part_type, lba_start, num_blocks) = {
119125
let mut blocks = [Block::new()];
120126
self.block_device
@@ -284,6 +290,28 @@ where
284290
}
285291
}
286292

293+
/// Close a volume
294+
///
295+
/// You can't close it if there are any files or directories open on it.
296+
pub fn close_volume(&mut self, volume: Volume) -> Result<(), Error<D::Error>> {
297+
for f in self.open_files.iter() {
298+
if f.volume_id == volume {
299+
return Err(Error::VolumeStillInUse);
300+
}
301+
}
302+
303+
for d in self.open_dirs.iter() {
304+
if d.volume_id == volume {
305+
return Err(Error::VolumeStillInUse);
306+
}
307+
}
308+
309+
let volume_idx = self.get_volume_by_id(volume)?;
310+
self.open_volumes.swap_remove(volume_idx);
311+
312+
Ok(())
313+
}
314+
287315
/// Look in a directory for a named file.
288316
pub fn find_directory_entry<N>(
289317
&mut self,

tests/directories.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,102 @@ fn fat32_root_directory_listing() {
214214
}
215215
}
216216

217+
#[test]
218+
fn open_dir_twice() {
219+
let time_source = utils::make_time_source();
220+
let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap();
221+
let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source);
222+
223+
let fat32_volume = volume_mgr
224+
.open_volume(embedded_sdmmc::VolumeIdx(1))
225+
.expect("open volume 1");
226+
227+
let root_dir = volume_mgr
228+
.open_root_dir(fat32_volume)
229+
.expect("open root dir");
230+
231+
let r = volume_mgr.open_root_dir(fat32_volume);
232+
let Err(embedded_sdmmc::Error::DirAlreadyOpen) = r else {
233+
panic!("Expected to fail opening the root dir twice: {r:?}");
234+
};
235+
236+
let r = volume_mgr.open_dir(root_dir, "README.TXT");
237+
let Err(embedded_sdmmc::Error::OpenedFileAsDir) = r else {
238+
panic!("Expected to fail opening file as dir: {r:?}");
239+
};
240+
241+
let test_dir = volume_mgr
242+
.open_dir(root_dir, "TEST")
243+
.expect("open test dir");
244+
245+
let r = volume_mgr.open_dir(root_dir, "TEST");
246+
let Err(embedded_sdmmc::Error::DirAlreadyOpen) = r else {
247+
panic!("Expected to fail opening the dir twice: {r:?}");
248+
};
249+
250+
volume_mgr.close_dir(root_dir).expect("close root dir");
251+
volume_mgr.close_dir(test_dir).expect("close test dir");
252+
253+
let r = volume_mgr.close_dir(test_dir);
254+
let Err(embedded_sdmmc::Error::BadHandle) = r else {
255+
panic!("Expected to fail closing the dir twice: {r:?}");
256+
};
257+
}
258+
259+
#[test]
260+
fn open_too_many_dirs() {
261+
let time_source = utils::make_time_source();
262+
let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap();
263+
let mut volume_mgr: embedded_sdmmc::VolumeManager<
264+
utils::RamDisk<Vec<u8>>,
265+
utils::TestTimeSource,
266+
1,
267+
4,
268+
2,
269+
> = embedded_sdmmc::VolumeManager::new_with_limits(disk, time_source, 0x1000_0000);
270+
271+
let fat32_volume = volume_mgr
272+
.open_volume(embedded_sdmmc::VolumeIdx(1))
273+
.expect("open volume 1");
274+
let root_dir = volume_mgr
275+
.open_root_dir(fat32_volume)
276+
.expect("open root dir");
277+
278+
let Err(embedded_sdmmc::Error::TooManyOpenDirs) = volume_mgr.open_dir(root_dir, "TEST") else {
279+
panic!("Expected to fail at opening too many dirs");
280+
};
281+
}
282+
283+
#[test]
284+
fn find_dir_entry() {
285+
let time_source = utils::make_time_source();
286+
let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap();
287+
let mut volume_mgr = embedded_sdmmc::VolumeManager::new(disk, time_source);
288+
289+
let fat32_volume = volume_mgr
290+
.open_volume(embedded_sdmmc::VolumeIdx(1))
291+
.expect("open volume 1");
292+
293+
let root_dir = volume_mgr
294+
.open_root_dir(fat32_volume)
295+
.expect("open root dir");
296+
297+
let dir_entry = volume_mgr
298+
.find_directory_entry(root_dir, "README.TXT")
299+
.expect("Find directory entry");
300+
assert!(dir_entry.attributes.is_archive());
301+
assert!(!dir_entry.attributes.is_directory());
302+
assert!(!dir_entry.attributes.is_hidden());
303+
assert!(!dir_entry.attributes.is_lfn());
304+
assert!(!dir_entry.attributes.is_system());
305+
assert!(!dir_entry.attributes.is_volume());
306+
307+
let r = volume_mgr.find_directory_entry(root_dir, "README.TXS");
308+
let Err(embedded_sdmmc::Error::FileNotFound) = r else {
309+
panic!("Expected not to find file: {r:?}");
310+
};
311+
}
312+
217313
// ****************************************************************************
218314
//
219315
// End Of File

tests/open_files.rs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//! File opening related tests
2+
3+
use embedded_sdmmc::{Error, Mode, VolumeIdx, VolumeManager};
4+
5+
mod utils;
6+
7+
#[test]
8+
fn open_files() {
9+
let time_source = utils::make_time_source();
10+
let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap();
11+
let mut volume_mgr: VolumeManager<utils::RamDisk<Vec<u8>>, utils::TestTimeSource, 4, 2, 1> =
12+
VolumeManager::new_with_limits(disk, time_source, 0xAA00_0000);
13+
let volume = volume_mgr.open_volume(VolumeIdx(0)).expect("open volume");
14+
let root_dir = volume_mgr.open_root_dir(volume).expect("open root dir");
15+
16+
// Open with string
17+
let f = volume_mgr
18+
.open_file_in_dir(root_dir, "README.TXT", Mode::ReadWriteTruncate)
19+
.expect("open file");
20+
21+
let r = volume_mgr.open_file_in_dir(root_dir, "README.TXT", Mode::ReadOnly);
22+
let Err(Error::FileAlreadyOpen) = r else {
23+
panic!("Expected to not open file twice: {r:?}");
24+
};
25+
26+
volume_mgr.close_file(f).expect("close file");
27+
28+
// Open with SFN
29+
30+
let dir_entry = volume_mgr
31+
.find_directory_entry(root_dir, "README.TXT")
32+
.expect("find file");
33+
34+
let f = volume_mgr
35+
.open_file_in_dir(root_dir, &dir_entry.name, Mode::ReadWriteCreateOrAppend)
36+
.expect("open file with dir entry");
37+
38+
let r = volume_mgr.open_file_in_dir(root_dir, &dir_entry.name, Mode::ReadOnly);
39+
let Err(Error::FileAlreadyOpen) = r else {
40+
panic!("Expected to not open file twice: {r:?}");
41+
};
42+
43+
// Can still spot duplicates even if name given the other way around
44+
let r = volume_mgr.open_file_in_dir(root_dir, "README.TXT", Mode::ReadOnly);
45+
let Err(Error::FileAlreadyOpen) = r else {
46+
panic!("Expected to not open file twice: {r:?}");
47+
};
48+
49+
let f2 = volume_mgr
50+
.open_file_in_dir(root_dir, "64MB.DAT", Mode::ReadWriteTruncate)
51+
.expect("open file");
52+
53+
// Hit file limit
54+
let r = volume_mgr.open_file_in_dir(root_dir, "EMPTY.DAT", Mode::ReadOnly);
55+
let Err(Error::TooManyOpenFiles) = r else {
56+
panic!("Expected to run out of file handles: {r:?}");
57+
};
58+
59+
volume_mgr.close_file(f).expect("close file");
60+
volume_mgr.close_file(f2).expect("close file");
61+
62+
// File not found
63+
let r = volume_mgr.open_file_in_dir(root_dir, "README.TXS", Mode::ReadOnly);
64+
let Err(Error::FileNotFound) = r else {
65+
panic!("Expected to not open missing file: {r:?}");
66+
};
67+
68+
// Create a new file
69+
let f3 = volume_mgr
70+
.open_file_in_dir(root_dir, "NEWFILE.DAT", Mode::ReadWriteCreate)
71+
.expect("open file");
72+
73+
volume_mgr.write(f3, b"12345").expect("write to file");
74+
volume_mgr.close_file(f3).expect("close file");
75+
76+
// Open our new file
77+
let f3 = volume_mgr
78+
.open_file_in_dir(root_dir, "NEWFILE.DAT", Mode::ReadOnly)
79+
.expect("open file");
80+
// Should have 5 bytes in it
81+
assert_eq!(volume_mgr.file_length(f3).expect("file length"), 5);
82+
volume_mgr.close_file(f3).expect("close file");
83+
84+
volume_mgr.close_dir(root_dir).expect("close dir");
85+
volume_mgr.close_volume(volume).expect("close volume");
86+
}
87+
88+
// ****************************************************************************
89+
//
90+
// End Of File
91+
//
92+
// ****************************************************************************

tests/volume.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
//! Volume related tests
2+
3+
mod utils;
4+
5+
#[test]
6+
fn open_all_volumes() {
7+
let time_source = utils::make_time_source();
8+
let disk = utils::make_block_device(utils::DISK_SOURCE).unwrap();
9+
let mut volume_mgr: embedded_sdmmc::VolumeManager<
10+
utils::RamDisk<Vec<u8>>,
11+
utils::TestTimeSource,
12+
4,
13+
4,
14+
2,
15+
> = embedded_sdmmc::VolumeManager::new_with_limits(disk, time_source, 0x1000_0000);
16+
17+
// Open Volume 0
18+
let fat16_volume = volume_mgr
19+
.open_volume(embedded_sdmmc::VolumeIdx(0))
20+
.expect("open volume 0");
21+
22+
// Fail to Open Volume 0 again
23+
let r = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0));
24+
let Err(embedded_sdmmc::Error::VolumeAlreadyOpen) = r else {
25+
panic!("Should have failed to open volume {:?}", r);
26+
};
27+
28+
volume_mgr.close_volume(fat16_volume).expect("close fat16");
29+
30+
// Open Volume 1
31+
let fat32_volume = volume_mgr
32+
.open_volume(embedded_sdmmc::VolumeIdx(1))
33+
.expect("open volume 1");
34+
35+
// Fail to Volume 1 again
36+
let r = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(1));
37+
let Err(embedded_sdmmc::Error::VolumeAlreadyOpen) = r else {
38+
panic!("Should have failed to open volume {:?}", r);
39+
};
40+
41+
// Open Volume 0 again
42+
let fat16_volume = volume_mgr
43+
.open_volume(embedded_sdmmc::VolumeIdx(0))
44+
.expect("open volume 0");
45+
46+
// Open any volume - too many volumes (0 and 1 are open)
47+
let r = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(0));
48+
let Err(embedded_sdmmc::Error::TooManyOpenVolumes) = r else {
49+
panic!("Should have failed to open volume {:?}", r);
50+
};
51+
52+
volume_mgr.close_volume(fat16_volume).expect("close fat16");
53+
volume_mgr.close_volume(fat32_volume).expect("close fat32");
54+
55+
// This isn't a valid volume
56+
let r = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(2));
57+
let Err(embedded_sdmmc::Error::FormatError(_e)) = r else {
58+
panic!("Should have failed to open volume {:?}", r);
59+
};
60+
61+
// This isn't a valid volume
62+
let r = volume_mgr.open_volume(embedded_sdmmc::VolumeIdx(9));
63+
let Err(embedded_sdmmc::Error::NoSuchVolume) = r else {
64+
panic!("Should have failed to open volume {:?}", r);
65+
};
66+
67+
let _root_dir = volume_mgr.open_root_dir(fat32_volume).expect("Open dir");
68+
69+
let r = volume_mgr.close_volume(fat32_volume);
70+
let Err(embedded_sdmmc::Error::VolumeStillInUse) = r else {
71+
panic!("Should have failed to close volume {:?}", r);
72+
};
73+
}
74+
75+
// ****************************************************************************
76+
//
77+
// End Of File
78+
//
79+
// ****************************************************************************

0 commit comments

Comments
 (0)