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.
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.

View File

@ -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);

View File

@ -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> {

View File

@ -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)
}