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.
|
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.
|
||||||
|
|
||||||
|
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()),
|
&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);
|
||||||
|
@ -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> {
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user