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:
Rafał Harabień 2018-06-12 00:07:30 +02:00
parent 4f6ed94cb3
commit 2304b13ec4
7 changed files with 33 additions and 34 deletions

View File

@ -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!")?;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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