Do not remove source file in Dir::rename if destination already exists

Previous code removed source file before returning an error.
It also caused a clusters leak. Now it returns error before doing any
modifications on the partition.
This commit is contained in:
Rafał Harabień 2018-06-17 22:25:22 +02:00
parent 4afd38a150
commit 8c1dae9f0c
2 changed files with 11 additions and 6 deletions

View File

@ -298,6 +298,12 @@ impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
trace!("moving {} to {}", src_name, dst_name);
// find existing file
let e = self.find_entry(src_name, None, None)?;
// check if destionation filename is unused
let mut short_name_gen = ShortNameGenerator::new(dst_name);
let r = dst_dir.find_entry(dst_name, None, Some(&mut short_name_gen));
if r.is_ok() {
return Err(io::Error::new(ErrorKind::AlreadyExists, "destination file already exists"))
}
// free long and short name entries
let mut stream = self.stream.clone();
stream.seek(SeekFrom::Start(e.offset_range.0 as u64))?;
@ -309,12 +315,6 @@ impl <'a, T: ReadWriteSeek + 'a> Dir<'a, T> {
stream.seek(SeekFrom::Current(-(DIR_ENTRY_SIZE as i64)))?;
data.serialize(&mut stream)?;
}
// check if destionation filename is unused
let mut short_name_gen = ShortNameGenerator::new(dst_name);
let r = dst_dir.find_entry(dst_name, None, Some(&mut short_name_gen));
if r.is_ok() {
return Err(io::Error::new(ErrorKind::AlreadyExists, "destination file already exists"))
}
// save new directory entry
let short_name = short_name_gen.generate()?;
let sfn_entry = e.data.renamed(short_name);

View File

@ -271,6 +271,11 @@ fn test_rename_file(fs: FileSystem) {
file.read_to_end(&mut buf).unwrap();
assert_eq!(str::from_utf8(&buf).unwrap(), TEST_STR2);
assert!(root_dir.rename("moved-file.txt", &root_dir, "short.txt").is_err());
let entries = root_dir.iter().map(|r| r.unwrap()).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"]);
let new_stats = fs.stats().unwrap();
assert_eq!(new_stats.free_clusters(), stats.free_clusters());
}