forked from M-Labs/rust-fatfs
Add create_dir function. (#5)
This commit is contained in:
parent
529d717e30
commit
9ec23f1234
@ -12,8 +12,9 @@ Introduction
|
||||
FAT filesystem library implemented in Rust.
|
||||
|
||||
Features:
|
||||
* read file and directory,
|
||||
* write file and directory,
|
||||
* read file or directory,
|
||||
* write file or directory,
|
||||
* create new file or directory,
|
||||
* FAT12, FAT16, FAT32 compatibility,
|
||||
* LFN (Long File Names) extension supported.
|
||||
|
||||
|
37
src/dir.rs
37
src/dir.rs
@ -27,6 +27,13 @@ impl <'a, 'b> DirRawStream<'a, 'b> {
|
||||
&DirRawStream::Root(ref slice) => Some(slice.abs_pos()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn first_cluster(&self) -> Option<u32> {
|
||||
match self {
|
||||
&DirRawStream::File(ref file) => file.first_cluster(),
|
||||
&DirRawStream::Root(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl <'a, 'b> Read for DirRawStream<'a, 'b> {
|
||||
@ -527,13 +534,35 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
Some(rest) => r?.to_dir().create_file(rest),
|
||||
None => {
|
||||
match r {
|
||||
Err(_) => Ok(self.create_file_entry(name)?.to_file()),
|
||||
Err(_) => Ok(self.create_entry(name, FileAttributes::from_bits_truncate(0), None)?.to_file()),
|
||||
Ok(e) => Ok(e.to_file())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates new directory or opens existing.
|
||||
pub fn create_dir(&mut self, path: &str) -> io::Result<Dir<'a, 'b>> {
|
||||
let (name, rest_opt) = Self::split_path(path);
|
||||
let r = self.find_entry(name);
|
||||
match rest_opt {
|
||||
Some(rest) => r?.to_dir().create_dir(rest),
|
||||
None => {
|
||||
match r {
|
||||
Err(_) => {
|
||||
let cluster = self.fs.alloc_cluster(None)?;
|
||||
let entry = self.create_entry(name, FileAttributes::DIRECTORY, Some(cluster))?;
|
||||
let mut dir = entry.to_dir();
|
||||
dir.create_entry(".", FileAttributes::DIRECTORY, entry.first_cluster())?;
|
||||
dir.create_entry("..", FileAttributes::DIRECTORY, self.stream.first_cluster())?;
|
||||
Ok(dir)
|
||||
},
|
||||
Ok(e) => Ok(e.to_dir()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&mut self) -> io::Result<bool> {
|
||||
for r in self.iter() {
|
||||
let e = r?;
|
||||
@ -635,7 +664,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
short_name
|
||||
}
|
||||
|
||||
fn create_file_entry(&mut self, name: &str) -> io::Result<DirEntry<'a, 'b>> {
|
||||
fn create_entry(&mut self, name: &str, attrs: FileAttributes, first_cluster: Option<u32>) -> io::Result<DirEntry<'a, 'b>> {
|
||||
if name.len() > 255 {
|
||||
return Err(io::Error::new(ErrorKind::InvalidInput, "filename too long"));
|
||||
}
|
||||
@ -671,10 +700,12 @@ impl <'a, 'b> Dir<'a, 'b> {
|
||||
lfn_entry.name_2.copy_from_slice(&lfn_part[11..11+2]);
|
||||
lfn_entry.serialize(&mut stream)?;
|
||||
}
|
||||
let raw_entry = DirFileEntryData {
|
||||
let mut raw_entry = DirFileEntryData {
|
||||
name: short_name,
|
||||
attrs,
|
||||
..Default::default()
|
||||
};
|
||||
raw_entry.set_first_cluster(first_cluster);
|
||||
raw_entry.serialize(&mut stream)?;
|
||||
let end_pos = stream.seek(io::SeekFrom::Current(0))?;
|
||||
let abs_pos = stream.abs_pos().map(|p| p - DIR_ENTRY_SIZE);
|
||||
|
@ -130,6 +130,10 @@ impl <'a, 'b> File<'a, 'b> {
|
||||
}
|
||||
self.entry_dirty = true;
|
||||
}
|
||||
|
||||
pub(crate) fn first_cluster(&self) -> Option<u32> {
|
||||
self.first_cluster
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> Drop for File<'a, 'b> {
|
||||
|
@ -156,3 +156,51 @@ fn test_create_file_fat16() {
|
||||
fn test_create_file_fat32() {
|
||||
call_with_fs(&test_create_file, FAT32_IMG, 4)
|
||||
}
|
||||
|
||||
fn test_create_dir(fs: FileSystem) {
|
||||
let mut root_dir = fs.root_dir();
|
||||
let parent_dir = root_dir.open_dir("very/long/path").unwrap();
|
||||
let mut names = parent_dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(names, [".", "..", "test.txt"]);
|
||||
{
|
||||
let subdir = root_dir.create_dir("very/long/path/new-dir-with-long-name").unwrap();
|
||||
names = subdir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(names, [".", ".."]);
|
||||
}
|
||||
// check if new entry is visible in parent
|
||||
names = parent_dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(names, [".", "..", "test.txt", "new-dir-with-long-name"]);
|
||||
{
|
||||
// Check if new directory can be opened and read
|
||||
let subdir = root_dir.open_dir("very/long/path/new-dir-with-long-name").unwrap();
|
||||
names = subdir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(names, [".", ".."]);
|
||||
}
|
||||
// Check if '.' is alias for new directory
|
||||
{
|
||||
let subdir = root_dir.open_dir("very/long/path/new-dir-with-long-name/.").unwrap();
|
||||
names = subdir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(names, [".", ".."]);
|
||||
}
|
||||
// Check if '..' is alias for parent directory
|
||||
{
|
||||
let subdir = root_dir.open_dir("very/long/path/new-dir-with-long-name/..").unwrap();
|
||||
names = subdir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||
assert_eq!(names, [".", "..", "test.txt", "new-dir-with-long-name"]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_dir_fat12() {
|
||||
call_with_fs(&test_create_dir, FAT12_IMG, 5)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_dir_fat16() {
|
||||
call_with_fs(&test_create_dir, FAT16_IMG, 5)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_create_dir_fat32() {
|
||||
call_with_fs(&test_create_dir, FAT32_IMG, 5)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user