feat: Guará 0.1.0 — recuperação de arquivos (núcleo, CLI e interface gráfica)
Núcleo em Rust somente leitura: NTFS, FAT, exFAT, partições MBR/GPT e perdidas, carving por estrutura, fusão sem duplicatas, confiança por arquivo, imagem forense, pausar/retomar. CLI `guara`, UI web/Tauri, CI e releases por tag. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
765cb0d4a2
57 files changed
+8621
No files matched your search
@@ -0,0 +1,88 @@
|
||||
//! Recuperação de ponta a ponta sobre imagens reais (FAT32, NTFS, ext4).
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
use guara_core::*;
|
||||
|
||||
fn check(fs: &str, only_carvable: bool) {
|
||||
let Some(dir) = fixtures() else { return };
|
||||
let img = dir.join(format!("{fs}.img"));
|
||||
let before = sha256_file(&img);
|
||||
let res = scan_path(&img, &ScanOptions::default());
|
||||
let out = tempfile::tempdir().unwrap();
|
||||
let rep = recover_all(&img, &res.found, out.path());
|
||||
assert!(rep.failed.is_empty(), "falhas: {:?}", rep.failed);
|
||||
let got = hashes_in(out.path());
|
||||
for (hash, path) in expected(&dir, fs) {
|
||||
let carvable = [".jpg", ".png", ".pdf", ".docx", ".db"]
|
||||
.iter()
|
||||
.any(|e| path.ends_with(e));
|
||||
if only_carvable && !carvable {
|
||||
continue;
|
||||
}
|
||||
assert!(
|
||||
got.contains_key(&hash),
|
||||
"[{fs}] não recuperado bit a bit: {path}"
|
||||
);
|
||||
}
|
||||
// Os dois métodos juntos não podem listar o mesmo conteúdo duas vezes.
|
||||
let mut seen = std::collections::HashSet::new();
|
||||
for f in &res.found {
|
||||
if let Some(o) = f.first_offset() {
|
||||
assert!(seen.insert(o), "[{fs}] achado duplicado no offset {o}");
|
||||
}
|
||||
}
|
||||
assert_eq!(before, sha256_file(&img), "a origem foi modificada!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fat32_recupera_apagados_com_nome_e_pasta() {
|
||||
check("fat32", false);
|
||||
let Some(dir) = fixtures() else { return };
|
||||
let res = scan_path(&dir.join("fat32.img"), &ScanOptions::default());
|
||||
assert!(res
|
||||
.found
|
||||
.iter()
|
||||
.any(|f| f.dir.as_deref() == Some("Documentos/Trabalho") && f.name == "relatorio.pdf"));
|
||||
assert!(
|
||||
res.found.iter().all(|f| f.name != "mantida.jpg"),
|
||||
"arquivo existente não deve ser listado"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ntfs_recupera_apagados() {
|
||||
check("ntfs", false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ext4_recupera_por_assinatura() {
|
||||
check("ext4", true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn varredura_rapida_nao_faz_carving() {
|
||||
let Some(dir) = fixtures() else { return };
|
||||
let res = scan_path(
|
||||
&dir.join("ext4.img"),
|
||||
&ScanOptions {
|
||||
mode: ScanMode::Quick,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
assert!(res.found.is_empty());
|
||||
let res = scan_path(
|
||||
&dir.join("ntfs.img"),
|
||||
&ScanOptions {
|
||||
mode: ScanMode::Quick,
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
assert_eq!(
|
||||
res.found
|
||||
.iter()
|
||||
.filter(|f| f.origin == Origin::Ntfs)
|
||||
.count(),
|
||||
7
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user