Take immutable self reference in Dir methods
Dir methods do not change Dir object itself. They usually clone inner stream so no change really happens self struct. Underlying partition is modified but it does not have to affect API. For example see std::fs::File::set_len. This change greatly simplifies rename API usage.
This commit is contained in:
parent
4f6ed94cb3
commit
2304b13ec4
@ -35,7 +35,7 @@ You can start using library now:
|
|||||||
let img_file = File::open("fat.img")?;
|
let img_file = File::open("fat.img")?;
|
||||||
let mut buf_stream = fatfs::BufStream::new(img_file);
|
let mut buf_stream = fatfs::BufStream::new(img_file);
|
||||||
let fs = fatfs::FileSystem::new(&mut buf_stream, fatfs::FsOptions::new())?;
|
let fs = fatfs::FileSystem::new(&mut buf_stream, fatfs::FsOptions::new())?;
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut file = root_dir.create_file("hello.txt")?;
|
let mut file = root_dir.create_file("hello.txt")?;
|
||||||
file.write_all(b"Hello World!")?;
|
file.write_all(b"Hello World!")?;
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ fn main() -> io::Result<()> {
|
|||||||
let file = File::open("resources/fat32.img")?;
|
let file = File::open("resources/fat32.img")?;
|
||||||
let mut buf_rdr = BufStream::new(file);
|
let mut buf_rdr = BufStream::new(file);
|
||||||
let fs = FileSystem::new(&mut buf_rdr, FsOptions::new())?;
|
let fs = FileSystem::new(&mut buf_rdr, FsOptions::new())?;
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut file = root_dir.open_file(&env::args().nth(1).unwrap())?;
|
let mut file = root_dir.open_file(&env::args().nth(1).unwrap())?;
|
||||||
let mut buf = vec![];
|
let mut buf = vec![];
|
||||||
file.read_to_end(&mut buf)?;
|
file.read_to_end(&mut buf)?;
|
||||||
|
@ -27,7 +27,7 @@ fn main() -> io::Result<()> {
|
|||||||
let file = File::open("resources/fat32.img")?;
|
let file = File::open("resources/fat32.img")?;
|
||||||
let mut buf_rdr = BufStream::new(file);
|
let mut buf_rdr = BufStream::new(file);
|
||||||
let fs = FileSystem::new(&mut buf_rdr, FsOptions::new())?;
|
let fs = FileSystem::new(&mut buf_rdr, FsOptions::new())?;
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let dir = match env::args().nth(1) {
|
let dir = match env::args().nth(1) {
|
||||||
None => root_dir,
|
None => root_dir,
|
||||||
Some(ref path) if path == "." => root_dir,
|
Some(ref path) if path == "." => root_dir,
|
||||||
|
26
src/dir.rs
26
src/dir.rs
@ -100,7 +100,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_entry(&mut self, name: &str, is_dir: Option<bool>, mut short_name_gen: Option<&mut ShortNameGenerator>) -> io::Result<DirEntry<'a, 'b>> {
|
fn find_entry(&self, name: &str, is_dir: Option<bool>, mut short_name_gen: Option<&mut ShortNameGenerator>) -> io::Result<DirEntry<'a, 'b>> {
|
||||||
for r in self.iter() {
|
for r in self.iter() {
|
||||||
let e = r?;
|
let e = r?;
|
||||||
// compare name ignoring case
|
// compare name ignoring case
|
||||||
@ -120,7 +120,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Opens existing directory
|
/// Opens existing directory
|
||||||
pub fn open_dir(&mut self, path: &str) -> io::Result<Self> {
|
pub fn open_dir(&self, path: &str) -> io::Result<Self> {
|
||||||
let (name, rest_opt) = split_path(path);
|
let (name, rest_opt) = split_path(path);
|
||||||
let e = self.find_entry(name, Some(true), None)?;
|
let e = self.find_entry(name, Some(true), None)?;
|
||||||
match rest_opt {
|
match rest_opt {
|
||||||
@ -130,7 +130,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Opens existing file.
|
/// Opens existing file.
|
||||||
pub fn open_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> {
|
pub fn open_file(&self, path: &str) -> io::Result<File<'a, 'b>> {
|
||||||
// traverse path
|
// traverse path
|
||||||
let (name, rest_opt) = split_path(path);
|
let (name, rest_opt) = split_path(path);
|
||||||
if let Some(rest) = rest_opt {
|
if let Some(rest) = rest_opt {
|
||||||
@ -143,7 +143,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new file or opens existing without truncating.
|
/// Creates new file or opens existing without truncating.
|
||||||
pub fn create_file(&mut self, path: &str) -> io::Result<File<'a, 'b>> {
|
pub fn create_file(&self, path: &str) -> io::Result<File<'a, 'b>> {
|
||||||
// traverse path
|
// traverse path
|
||||||
let (name, rest_opt) = split_path(path);
|
let (name, rest_opt) = split_path(path);
|
||||||
if let Some(rest) = rest_opt {
|
if let Some(rest) = rest_opt {
|
||||||
@ -167,7 +167,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates new directory or opens existing.
|
/// Creates new directory or opens existing.
|
||||||
pub fn create_dir(&mut self, path: &str) -> io::Result<Self> {
|
pub fn create_dir(&self, path: &str) -> io::Result<Self> {
|
||||||
// traverse path
|
// traverse path
|
||||||
let (name, rest_opt) = split_path(path);
|
let (name, rest_opt) = split_path(path);
|
||||||
if let Some(rest) = rest_opt {
|
if let Some(rest) = rest_opt {
|
||||||
@ -202,7 +202,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&mut self) -> io::Result<bool> {
|
fn is_empty(&self) -> io::Result<bool> {
|
||||||
// check if directory contains no files
|
// check if directory contains no files
|
||||||
for r in self.iter() {
|
for r in self.iter() {
|
||||||
let e = r?;
|
let e = r?;
|
||||||
@ -219,7 +219,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
///
|
///
|
||||||
/// Make sure there is no reference to this file (no File instance) or filesystem corruption
|
/// Make sure there is no reference to this file (no File instance) or filesystem corruption
|
||||||
/// can happen.
|
/// can happen.
|
||||||
pub fn remove(&mut self, path: &str) -> io::Result<()> {
|
pub fn remove(&self, path: &str) -> io::Result<()> {
|
||||||
// traverse path
|
// traverse path
|
||||||
let (name, rest_opt) = split_path(path);
|
let (name, rest_opt) = split_path(path);
|
||||||
if let Some(rest) = rest_opt {
|
if let Some(rest) = rest_opt {
|
||||||
@ -255,7 +255,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
/// Destination directory can be cloned source directory in case of rename without moving operation.
|
/// Destination directory can be cloned source directory in case of rename without moving operation.
|
||||||
/// Make sure there is no reference to this file (no File instance) or filesystem corruption
|
/// Make sure there is no reference to this file (no File instance) or filesystem corruption
|
||||||
/// can happen.
|
/// can happen.
|
||||||
pub fn rename(&mut self, src_path: &str, dst_dir: &mut Dir, dst_path: &str) -> io::Result<()> {
|
pub fn rename(&self, src_path: &str, dst_dir: &Dir, dst_path: &str) -> io::Result<()> {
|
||||||
// traverse source path
|
// traverse source path
|
||||||
let (name, rest_opt) = split_path(src_path);
|
let (name, rest_opt) = split_path(src_path);
|
||||||
if let Some(rest) = rest_opt {
|
if let Some(rest) = rest_opt {
|
||||||
@ -272,7 +272,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
self.rename_internal(src_path, dst_dir, dst_path)
|
self.rename_internal(src_path, dst_dir, dst_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rename_internal(&mut self, src_name: &str, dst_dir: &mut Dir, dst_name: &str) -> io::Result<()> {
|
fn rename_internal(&self, src_name: &str, dst_dir: &Dir, dst_name: &str) -> io::Result<()> {
|
||||||
trace!("moving {} to {}", src_name, dst_name);
|
trace!("moving {} to {}", src_name, dst_name);
|
||||||
// find existing file
|
// find existing file
|
||||||
let e = self.find_entry(src_name, None, None)?;
|
let e = self.find_entry(src_name, None, None)?;
|
||||||
@ -300,7 +300,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_free_entries(&mut self, num_entries: usize) -> io::Result<DirRawStream<'a, 'b>> {
|
fn find_free_entries(&self, num_entries: usize) -> io::Result<DirRawStream<'a, 'b>> {
|
||||||
let mut stream = self.stream.clone();
|
let mut stream = self.stream.clone();
|
||||||
let mut first_free = 0;
|
let mut first_free = 0;
|
||||||
let mut num_free = 0;
|
let mut num_free = 0;
|
||||||
@ -334,7 +334,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
fn create_lfn_entries(&mut self, name: &str, short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> {
|
fn create_lfn_entries(&self, name: &str, short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> {
|
||||||
// get short name checksum
|
// get short name checksum
|
||||||
let lfn_chsum = lfn_checksum(&short_name);
|
let lfn_chsum = lfn_checksum(&short_name);
|
||||||
// convert long name to UTF-16
|
// convert long name to UTF-16
|
||||||
@ -351,7 +351,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
Ok((stream, start_pos))
|
Ok((stream, start_pos))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "alloc"))]
|
#[cfg(not(feature = "alloc"))]
|
||||||
fn create_lfn_entries(&mut self, _name: &str, _short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> {
|
fn create_lfn_entries(&self, _name: &str, _short_name: &[u8]) -> io::Result<(DirRawStream<'a, 'b>, u64)> {
|
||||||
let mut stream = self.find_free_entries(1)?;
|
let mut stream = self.find_free_entries(1)?;
|
||||||
let start_pos = stream.seek(io::SeekFrom::Current(0))?;
|
let start_pos = stream.seek(io::SeekFrom::Current(0))?;
|
||||||
Ok((stream, start_pos))
|
Ok((stream, start_pos))
|
||||||
@ -366,7 +366,7 @@ impl <'a, 'b> Dir<'a, 'b> {
|
|||||||
raw_entry
|
raw_entry
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_entry(&mut self, name: &str, raw_entry: DirFileEntryData) -> io::Result<DirEntry<'a, 'b>> {
|
fn write_entry(&self, name: &str, raw_entry: DirFileEntryData) -> io::Result<DirEntry<'a, 'b>> {
|
||||||
trace!("write_entry {}", name);
|
trace!("write_entry {}", name);
|
||||||
// check if name doesn't contain unsupported characters
|
// check if name doesn't contain unsupported characters
|
||||||
validate_long_name(name)?;
|
validate_long_name(name)?;
|
||||||
|
@ -350,10 +350,10 @@ pub(crate) enum DirEntryData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DirEntryData {
|
impl DirEntryData {
|
||||||
pub(crate) fn serialize(&mut self, wrt: &mut Write) -> io::Result<()> {
|
pub(crate) fn serialize(&self, wrt: &mut Write) -> io::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
&mut DirEntryData::File(ref mut file) => file.serialize(wrt),
|
&DirEntryData::File(ref file) => file.serialize(wrt),
|
||||||
&mut DirEntryData::Lfn(ref mut lfn) => lfn.serialize(wrt),
|
&DirEntryData::Lfn(ref lfn) => lfn.serialize(wrt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ fn test_root_dir_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_read_seek_short_file(fs: FileSystem) {
|
fn test_read_seek_short_file(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut short_file = root_dir.open_file("short.txt").unwrap();
|
let mut short_file = root_dir.open_file("short.txt").unwrap();
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
short_file.read_to_end(&mut buf).unwrap();
|
short_file.read_to_end(&mut buf).unwrap();
|
||||||
@ -81,7 +81,7 @@ fn test_read_seek_short_file_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_read_long_file(fs: FileSystem) {
|
fn test_read_long_file(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut long_file = root_dir.open_file("long.txt").unwrap();
|
let mut long_file = root_dir.open_file("long.txt").unwrap();
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
long_file.read_to_end(&mut buf).unwrap();
|
long_file.read_to_end(&mut buf).unwrap();
|
||||||
@ -110,7 +110,7 @@ fn test_read_long_file_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_get_dir_by_path(fs: FileSystem) {
|
fn test_get_dir_by_path(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let dir = root_dir.open_dir("very/long/path/").unwrap();
|
let dir = root_dir.open_dir("very/long/path/").unwrap();
|
||||||
let names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
let names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||||
assert_eq!(names, [".", "..", "test.txt"]);
|
assert_eq!(names, [".", "..", "test.txt"]);
|
||||||
@ -143,7 +143,7 @@ fn test_get_dir_by_path_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_get_file_by_path(fs: FileSystem) {
|
fn test_get_file_by_path(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut file = root_dir.open_file("very/long/path/test.txt").unwrap();
|
let mut file = root_dir.open_file("very/long/path/test.txt").unwrap();
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
file.read_to_end(&mut buf).unwrap();
|
file.read_to_end(&mut buf).unwrap();
|
||||||
|
@ -33,7 +33,7 @@ fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str, test_seq: u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_write_short_file(fs: FileSystem) {
|
fn test_write_short_file(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut file = root_dir.open_file("short.txt").expect("open file");
|
let mut file = root_dir.open_file("short.txt").expect("open file");
|
||||||
file.truncate().unwrap();
|
file.truncate().unwrap();
|
||||||
file.write_all(&TEST_STR.as_bytes()).unwrap();
|
file.write_all(&TEST_STR.as_bytes()).unwrap();
|
||||||
@ -59,7 +59,7 @@ fn test_write_file_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_write_long_file(fs: FileSystem) {
|
fn test_write_long_file(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut file = root_dir.open_file("long.txt").expect("open file");
|
let mut file = root_dir.open_file("long.txt").expect("open file");
|
||||||
file.truncate().unwrap();
|
file.truncate().unwrap();
|
||||||
let test_str = TEST_STR.repeat(100);
|
let test_str = TEST_STR.repeat(100);
|
||||||
@ -92,7 +92,7 @@ fn test_write_long_file_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_remove(fs: FileSystem) {
|
fn test_remove(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
assert!(root_dir.remove("very/long/path").is_err());
|
assert!(root_dir.remove("very/long/path").is_err());
|
||||||
let dir = root_dir.open_dir("very/long/path").unwrap();
|
let dir = root_dir.open_dir("very/long/path").unwrap();
|
||||||
let mut names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
let mut names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||||
@ -125,8 +125,8 @@ fn test_remove_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_create_file(fs: FileSystem) {
|
fn test_create_file(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut dir = root_dir.open_dir("very/long/path").unwrap();
|
let dir = root_dir.open_dir("very/long/path").unwrap();
|
||||||
let mut names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
let mut names = dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||||
assert_eq!(names, [".", "..", "test.txt"]);
|
assert_eq!(names, [".", "..", "test.txt"]);
|
||||||
{
|
{
|
||||||
@ -174,7 +174,7 @@ fn test_create_file_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_create_dir(fs: FileSystem) {
|
fn test_create_dir(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let parent_dir = root_dir.open_dir("very/long/path").unwrap();
|
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>>();
|
let mut names = parent_dir.iter().map(|r| r.unwrap().file_name()).collect::<Vec<String>>();
|
||||||
assert_eq!(names, [".", "..", "test.txt"]);
|
assert_eq!(names, [".", "..", "test.txt"]);
|
||||||
@ -222,16 +222,15 @@ fn test_create_dir_fat32() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn test_rename_file(fs: FileSystem) {
|
fn test_rename_file(fs: FileSystem) {
|
||||||
let mut root_dir = fs.root_dir();
|
let root_dir = fs.root_dir();
|
||||||
let mut parent_dir = root_dir.open_dir("very/long/path").unwrap();
|
let parent_dir = root_dir.open_dir("very/long/path").unwrap();
|
||||||
let entries = parent_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
|
let entries = parent_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
|
||||||
let names = entries.iter().map(|r| r.file_name()).collect::<Vec<_>>();
|
let names = entries.iter().map(|r| r.file_name()).collect::<Vec<_>>();
|
||||||
assert_eq!(names, [".", "..", "test.txt"]);
|
assert_eq!(names, [".", "..", "test.txt"]);
|
||||||
assert_eq!(entries[2].len(), 14);
|
assert_eq!(entries[2].len(), 14);
|
||||||
let stats = fs.stats().unwrap();
|
let stats = fs.stats().unwrap();
|
||||||
|
|
||||||
let mut parent_dir_cloned = parent_dir.clone();
|
parent_dir.rename("test.txt", &parent_dir, "new-long-name.txt").unwrap();
|
||||||
parent_dir.rename("test.txt", &mut parent_dir_cloned, "new-long-name.txt").unwrap();
|
|
||||||
let entries = parent_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
|
let entries = parent_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
|
||||||
let names = entries.iter().map(|r| r.file_name()).collect::<Vec<_>>();
|
let names = entries.iter().map(|r| r.file_name()).collect::<Vec<_>>();
|
||||||
assert_eq!(names, [".", "..", "new-long-name.txt"]);
|
assert_eq!(names, [".", "..", "new-long-name.txt"]);
|
||||||
@ -241,7 +240,7 @@ fn test_rename_file(fs: FileSystem) {
|
|||||||
file.read_to_end(&mut buf).unwrap();
|
file.read_to_end(&mut buf).unwrap();
|
||||||
assert_eq!(str::from_utf8(&buf).unwrap(), TEST_STR2);
|
assert_eq!(str::from_utf8(&buf).unwrap(), TEST_STR2);
|
||||||
|
|
||||||
parent_dir.rename("new-long-name.txt", &mut root_dir, "moved-file.txt").unwrap();
|
parent_dir.rename("new-long-name.txt", &root_dir, "moved-file.txt").unwrap();
|
||||||
let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
|
let entries = root_dir.iter().map(|r| r.unwrap()).collect::<Vec<_>>();
|
||||||
let names = entries.iter().map(|r| r.file_name()).collect::<Vec<_>>();
|
let names = entries.iter().map(|r| r.file_name()).collect::<Vec<_>>();
|
||||||
assert_eq!(names, ["long.txt", "short.txt", "very", "very-long-dir-name", "moved-file.txt"]);
|
assert_eq!(names, ["long.txt", "short.txt", "very", "very-long-dir-name", "moved-file.txt"]);
|
||||||
|
Loading…
Reference in New Issue
Block a user