From e4b72836f0417b8c6b2a3741cc777e6d821da455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Fri, 22 Jan 2021 00:17:48 +0100 Subject: [PATCH] Fix file-system corruption when creating directory entries Corruption happens if: * files are created in non-root directory * directory size becomes greater or equal to cluster size Creating last directory entry in the directory cluster corrupts the cluster directly preceding the directory cluster. For 512 bytes long cluster creating 8th directory entry (counted from 1) will cause first corruption. Directory entry that causes the corruption will not be updated correctly. Fixes #42 --- CHANGELOG.md | 6 ++++++ src/file.rs | 11 +++++++++-- tests/write.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67cceab..d7d2d5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Changelog ========= +0.3.5 (not released yet) +------------------------ +Bug fixes: +* Fix file-system corruption when creating multiple directory entries in non-root directory (directory size must + be greater or equal to cluster size for corruption to happen) + 0.3.4 (2020-07-20) ------------------ Bug fixes: diff --git a/src/file.rs b/src/file.rs index 065c217..5b8051a 100644 --- a/src/file.rs +++ b/src/file.rs @@ -76,8 +76,15 @@ impl<'a, T: ReadWriteSeek> File<'a, T> { match self.current_cluster { Some(n) => { let cluster_size = self.fs.cluster_size(); - let offset_in_cluster = self.offset % cluster_size; - let offset_in_fs = self.fs.offset_from_cluster(n) + (offset_in_cluster as u64); + let offset_mod_cluster_size = self.offset % cluster_size; + let offset_in_cluster = if offset_mod_cluster_size == 0 { + // position points between clusters - we are returning previous cluster so + // offset must be set to the cluster size + cluster_size + } else { + offset_mod_cluster_size + }; + let offset_in_fs = self.fs.offset_from_cluster(n) + u64::from(offset_in_cluster); Some(offset_in_fs) }, None => None, diff --git a/tests/write.rs b/tests/write.rs index 71610ec..f4a09bb 100644 --- a/tests/write.rs +++ b/tests/write.rs @@ -349,3 +349,36 @@ fn test_dirty_flag_fat16() { fn test_dirty_flag_fat32() { call_with_tmp_img(&test_dirty_flag, FAT32_IMG, 7) } + +fn test_multiple_files_in_directory(fs: FileSystem) { + let dir = fs.root_dir().create_dir("/TMP").unwrap(); + for i in 0..8 { + let name = format!("T{}.TXT", i); + let mut file = dir.create_file(&name).unwrap(); + file.write_all(TEST_STR.as_bytes()).unwrap(); + file.flush().unwrap(); + + let file = dir.iter() + .map(|r| r.unwrap()) + .filter(|e| e.file_name() == name) + .next() + .unwrap(); + + assert_eq!(TEST_STR.len() as u64, file.len(), "Wrong file len on iteration {}", i); + } +} + +#[test] +fn test_multiple_files_in_directory_fat12() { + call_with_fs(&test_multiple_files_in_directory, FAT12_IMG, 8) +} + +#[test] +fn test_multiple_files_in_directory_fat16() { + call_with_fs(&test_multiple_files_in_directory, FAT16_IMG, 8) +} + +#[test] +fn test_multiple_files_in_directory_fat32() { + call_with_fs(&test_multiple_files_in_directory, FAT32_IMG, 8) +}