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
This commit is contained in:
Rafał Harabień 2021-01-22 00:17:48 +01:00
parent 7b18222941
commit e4b72836f0
3 changed files with 48 additions and 2 deletions

View File

@ -1,6 +1,12 @@
Changelog 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) 0.3.4 (2020-07-20)
------------------ ------------------
Bug fixes: Bug fixes:

View File

@ -76,8 +76,15 @@ impl<'a, T: ReadWriteSeek> File<'a, T> {
match self.current_cluster { match self.current_cluster {
Some(n) => { Some(n) => {
let cluster_size = self.fs.cluster_size(); let cluster_size = self.fs.cluster_size();
let offset_in_cluster = self.offset % cluster_size; let offset_mod_cluster_size = self.offset % cluster_size;
let offset_in_fs = self.fs.offset_from_cluster(n) + (offset_in_cluster as u64); 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) Some(offset_in_fs)
}, },
None => None, None => None,

View File

@ -349,3 +349,36 @@ fn test_dirty_flag_fat16() {
fn test_dirty_flag_fat32() { fn test_dirty_flag_fat32() {
call_with_tmp_img(&test_dirty_flag, FAT32_IMG, 7) 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)
}