Add create_dir function. (#5)

This commit is contained in:
Rafał 2017-10-27 14:12:53 +02:00 committed by GitHub
parent 529d717e30
commit 9ec23f1234
4 changed files with 89 additions and 5 deletions

View File

@ -12,8 +12,9 @@ Introduction
FAT filesystem library implemented in Rust. FAT filesystem library implemented in Rust.
Features: Features:
* read file and directory, * read file or directory,
* write file and directory, * write file or directory,
* create new file or directory,
* FAT12, FAT16, FAT32 compatibility, * FAT12, FAT16, FAT32 compatibility,
* LFN (Long File Names) extension supported. * LFN (Long File Names) extension supported.

View File

@ -27,6 +27,13 @@ impl <'a, 'b> DirRawStream<'a, 'b> {
&DirRawStream::Root(ref slice) => Some(slice.abs_pos()), &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> { 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), Some(rest) => r?.to_dir().create_file(rest),
None => { None => {
match r { 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()) 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> { fn is_empty(&mut self) -> io::Result<bool> {
for r in self.iter() { for r in self.iter() {
let e = r?; let e = r?;
@ -635,7 +664,7 @@ impl <'a, 'b> Dir<'a, 'b> {
short_name 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 { if name.len() > 255 {
return Err(io::Error::new(ErrorKind::InvalidInput, "filename too long")); 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.name_2.copy_from_slice(&lfn_part[11..11+2]);
lfn_entry.serialize(&mut stream)?; lfn_entry.serialize(&mut stream)?;
} }
let raw_entry = DirFileEntryData { let mut raw_entry = DirFileEntryData {
name: short_name, name: short_name,
attrs,
..Default::default() ..Default::default()
}; };
raw_entry.set_first_cluster(first_cluster);
raw_entry.serialize(&mut stream)?; raw_entry.serialize(&mut stream)?;
let end_pos = stream.seek(io::SeekFrom::Current(0))?; let end_pos = stream.seek(io::SeekFrom::Current(0))?;
let abs_pos = stream.abs_pos().map(|p| p - DIR_ENTRY_SIZE); let abs_pos = stream.abs_pos().map(|p| p - DIR_ENTRY_SIZE);

View File

@ -130,6 +130,10 @@ impl <'a, 'b> File<'a, 'b> {
} }
self.entry_dirty = true; self.entry_dirty = true;
} }
pub(crate) fn first_cluster(&self) -> Option<u32> {
self.first_cluster
}
} }
impl<'a, 'b> Drop for File<'a, 'b> { impl<'a, 'b> Drop for File<'a, 'b> {

View File

@ -156,3 +156,51 @@ fn test_create_file_fat16() {
fn test_create_file_fat32() { fn test_create_file_fat32() {
call_with_fs(&test_create_file, FAT32_IMG, 4) 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)
}