fix(sync): S-04 — eliminate TOCTOU by recording actual bytes written
This commit is contained in:
+5
-2
@@ -336,9 +336,12 @@ pub fn sync_single_file_to_vault(
|
|||||||
|
|
||||||
// Bei Überschreiben einer ehemals größeren Datei überzählige alte Chunks entfernen
|
// Bei Überschreiben einer ehemals größeren Datei überzählige alte Chunks entfernen
|
||||||
db.truncate_chunks_after(node_id, chunk_idx.saturating_sub(1))?;
|
db.truncate_chunks_after(node_id, chunk_idx.saturating_sub(1))?;
|
||||||
db.update_node_size_and_time(node_id, local_size, local_mtime)?;
|
// S-04: Verwende bytes_written statt local_size zur Vermeidung von TOCTOU-Diskrepanzen
|
||||||
|
db.update_node_size_and_time(node_id, bytes_written, local_mtime)?;
|
||||||
|
|
||||||
Ok(FileTransferResult::Transferred { size: local_size })
|
Ok(FileTransferResult::Transferred {
|
||||||
|
size: bytes_written,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronisiert eine Datei aus dem Tresor auf die lokale Festplatte (Pull).
|
/// Synchronisiert eine Datei aus dem Tresor auf die lokale Festplatte (Pull).
|
||||||
|
|||||||
@@ -643,3 +643,49 @@ fn test_s03_symlink_skipping_and_cycle_protection() {
|
|||||||
}
|
}
|
||||||
let _ = fs::remove_dir_all(&temp_root);
|
let _ = fs::remove_dir_all(&temp_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_s04_toctou_file_size_uses_bytes_written() {
|
||||||
|
let temp_root =
|
||||||
|
std::env::temp_dir().join(format!("sanctum_s04_test_{}", rand::random::<u64>()));
|
||||||
|
let container_path = temp_root.join("test.sanctum");
|
||||||
|
let file_path = temp_root.join("race_file.bin");
|
||||||
|
|
||||||
|
fs::create_dir_all(&temp_root).unwrap();
|
||||||
|
let initial_data = vec![0xABu8; 12345];
|
||||||
|
fs::write(&file_path, &initial_data).unwrap();
|
||||||
|
|
||||||
|
let (db, dek) = create_test_container(&container_path);
|
||||||
|
|
||||||
|
// Sync file to vault
|
||||||
|
let res = sanctum::sync::sync_single_file_to_vault(
|
||||||
|
&db,
|
||||||
|
0,
|
||||||
|
&dek,
|
||||||
|
FORMAT_VERSION,
|
||||||
|
&file_path,
|
||||||
|
1,
|
||||||
|
"race_file.bin",
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.expect("Sync single file to vault");
|
||||||
|
|
||||||
|
match res {
|
||||||
|
sanctum::sync::FileTransferResult::Transferred { size } => {
|
||||||
|
assert_eq!(size, 12345);
|
||||||
|
}
|
||||||
|
_ => panic!("Expected FileTransferResult::Transferred"),
|
||||||
|
}
|
||||||
|
|
||||||
|
let node = db
|
||||||
|
.resolve_path_in_vault("/race_file.bin", 0, &dek)
|
||||||
|
.unwrap()
|
||||||
|
.expect("Node must exist");
|
||||||
|
assert_eq!(
|
||||||
|
node.size, 12345,
|
||||||
|
"Knotengröße muss exakt bytes_written entsprechen"
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = fs::remove_dir_all(&temp_root);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user