chore(i18n): finish translating code comments and scripts to English
CI / Format and clippy (push) Successful in 1m57s
CI / Dependency audit (push) Successful in 13s
CI / Check desktop app (Linux) (push) Successful in 3m54s
CI / Tests (Linux) (push) Failing after 7m25s
Release / Create release (push) Successful in 6s
Release / CLI (linux-aarch64) (push) Successful in 1m48s
Release / CLI (linux-x86_64) (push) Successful in 2m39s
Release / Desktop app (linux-aarch64) (push) Successful in 10m9s
Release / Desktop app (linux-x86_64) (push) Successful in 12m20s
Release / Desktop app (windows) (push) Successful in 7m32s
Release / Build latest.json (push) Successful in 5s
CI / Format and clippy (push) Successful in 1m57s
CI / Dependency audit (push) Successful in 13s
CI / Check desktop app (Linux) (push) Successful in 3m54s
CI / Tests (Linux) (push) Failing after 7m25s
Release / Create release (push) Successful in 6s
Release / CLI (linux-aarch64) (push) Successful in 1m48s
Release / CLI (linux-x86_64) (push) Successful in 2m39s
Release / Desktop app (linux-aarch64) (push) Successful in 10m9s
Release / Desktop app (linux-x86_64) (push) Successful in 12m20s
Release / Desktop app (windows) (push) Successful in 7m32s
Release / Build latest.json (push) Successful in 5s
Completes the English-only standardization for code, comments, scripts and CI templates (UI/CLI-facing strings stay bilingual pt-BR/en, untouched). Covers the remaining crates/, apps/gui/ui/ and apps/gui/src-tauri/ comments, .gitea/ workflow and template comments, .githooks/ hooks, and the scripts/ source comments for the files already renamed in a prior commit (check.sh, generate-logo.py, install-hooks.sh). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
This commit is contained in:
1 parent
da212e6926
commit
6328220c60
129 files changed
+1961
-1834
No files matched your search
@@ -1,4 +1,4 @@
|
||||
//! Discos com tabela de partições, espaço não particionado, partições perdidas e cifragem.
|
||||
//! Partitioned disks (GPT/MBR), unpartitioned space, lost partitions, sessions, and disconnect handling.
|
||||
|
||||
mod common;
|
||||
use common::*;
|
||||
@@ -39,7 +39,7 @@ fn png(extra: usize) -> Vec<u8> {
|
||||
v
|
||||
}
|
||||
|
||||
/// Disco: [1 MiB vazio][partição FAT32 do fixture][8 MiB não particionado com um PNG]
|
||||
/// Synthetic disk: `[1 MiB gap][FAT32 partition][8 MiB unpartitioned gap containing a PNG]`
|
||||
#[test]
|
||||
fn particao_mbr_e_espaco_nao_particionado() {
|
||||
let Some(dir) = fixtures() else { return };
|
||||
@@ -66,14 +66,14 @@ fn particao_mbr_e_espaco_nao_particionado() {
|
||||
"gap: {:?}",
|
||||
layout.gaps
|
||||
);
|
||||
// Metadados da partição (offsets corrigidos pela posição da partição)...
|
||||
// Partition metadata findings (with byte offsets translated to disk-global offsets)...
|
||||
let fat_found: Vec<_> = res
|
||||
.found
|
||||
.iter()
|
||||
.filter(|f| f.origin == Origin::Fat)
|
||||
.collect();
|
||||
assert_eq!(fat_found.len(), 7);
|
||||
// ... e o PNG no espaço não particionado.
|
||||
// ...plus the carved PNG from the unpartitioned gap.
|
||||
let carved: Vec<_> = res
|
||||
.found
|
||||
.iter()
|
||||
@@ -117,11 +117,11 @@ fn particao_perdida_e_encontrada_sem_tabela() {
|
||||
fn volume_cifrado_e_detectado_e_nao_varrido() {
|
||||
let mut disk = vec![0u8; 8 * MIB as usize];
|
||||
disk[..512].copy_from_slice(&mbr(&[(0x07, MIB, 4 * MIB), (0x83, 5 * MIB, 2 * MIB)]));
|
||||
// BitLocker na partição 1, LUKS na 2.
|
||||
// BitLocker signature in partition 1, LUKS signature in partition 2.
|
||||
disk[MIB as usize + 3..MIB as usize + 11].copy_from_slice(b"-FVE-FS-");
|
||||
let l = 5 * MIB as usize;
|
||||
disk[l..l + 6].copy_from_slice(b"LUKS\xBA\xBE");
|
||||
// Um PNG "dentro" do volume cifrado não deve ser tocado.
|
||||
// A plaintext PNG planted inside the locked container range must not be carved while locked.
|
||||
let p = png(10_000);
|
||||
let at = (2 * MIB) as usize;
|
||||
disk[at..at + p.len()].copy_from_slice(&p);
|
||||
@@ -141,7 +141,7 @@ fn volume_cifrado_e_detectado_e_nao_varrido() {
|
||||
|
||||
#[test]
|
||||
fn gpt_e_lido() {
|
||||
// GPT mínimo com 1 partição de dados.
|
||||
// Minimal GPT with 1 basic data partition.
|
||||
let mut disk = vec![0u8; 8 * MIB as usize];
|
||||
disk[..512].copy_from_slice(&mbr(&[(0xEE, 512, 8 * MIB - 512)]));
|
||||
let mut h = vec![0u8; 512];
|
||||
@@ -183,7 +183,7 @@ fn imagem_forense_e_identica_e_origem_intacta() {
|
||||
assert!(rep.bad_ranges.is_empty());
|
||||
assert_eq!(rep.sha256, sha256_file(&src_path));
|
||||
assert_eq!(sha256_file(&dest), sha256_file(&src_path));
|
||||
// Não sobrescreve arquivo existente.
|
||||
// Never overwrite an existing file in the destination directory.
|
||||
assert!(image::create_image(src.as_ref(), &dest, &|| false, &mut |_, _| {}).is_err());
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ fn pausa_e_retoma_encontra_o_mesmo() {
|
||||
let path = dir.join("ext4.img");
|
||||
let full = scan_path(&path, &ScanOptions::default());
|
||||
let src = source::open_path(&path).unwrap();
|
||||
// Cancela logo na 3ª consulta, retoma do checkpoint.
|
||||
// Cancel on the 3rd progress callback, then resume from the saved checkpoint.
|
||||
let n = std::sync::atomic::AtomicUsize::new(0);
|
||||
let cancel = || n.fetch_add(1, std::sync::atomic::Ordering::Relaxed) == 2;
|
||||
let mut sink = Collect::default();
|
||||
@@ -233,7 +233,7 @@ fn pausa_e_retoma_encontra_o_mesmo() {
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
|
||||
/// Streaming de pré-visualização: Range devolve exatamente os bytes do arquivo recuperado.
|
||||
/// Preview streaming: HTTP `Range` slices return the exact bytes of the recovered file.
|
||||
#[test]
|
||||
fn file_slice_com_range_bate_com_o_arquivo_recuperado() {
|
||||
init();
|
||||
@@ -302,7 +302,7 @@ fn configuracoes_de_tema_persistem() {
|
||||
settings::load().updates,
|
||||
"a verificação de atualização vem ligada"
|
||||
);
|
||||
// arquivo de uma versão anterior, sem o campo novo
|
||||
// legacy session JSON missing newly added fields
|
||||
std::fs::write(
|
||||
settings::config_dir().join("settings.json"),
|
||||
r#"{"theme":"dark"}"#,
|
||||
@@ -328,8 +328,8 @@ fn wait_done(eng: &service::Engine, job: &str) {
|
||||
panic!("job não terminou");
|
||||
}
|
||||
|
||||
/// Gera uma sessão no formato da v0.1.0 (sem os campos que vieram depois) a partir de uma
|
||||
/// varredura real da imagem, com o alvo informado.
|
||||
/// Strips post-v0.1.0 fields from a real scan session JSON to simulate a legacy v0.1.0 session file.
|
||||
///
|
||||
fn sessao_formato_v0_1_0(img: &std::path::Path, alvo: &str) -> tempfile::NamedTempFile {
|
||||
init();
|
||||
let eng = service::Engine::new();
|
||||
@@ -358,7 +358,7 @@ fn sessao_formato_v0_1_0(img: &std::path::Path, alvo: &str) -> tempfile::NamedTe
|
||||
tmp
|
||||
}
|
||||
|
||||
/// Uma sessão gravada pela v0.1.0 continua abrindo nas versões novas.
|
||||
/// Backward compatibility: a session saved by v0.1.0 still loads and recovers cleanly.
|
||||
#[test]
|
||||
fn sessao_da_v0_1_0_abre_e_funciona() {
|
||||
init();
|
||||
@@ -374,7 +374,7 @@ fn sessao_da_v0_1_0_abre_e_funciona() {
|
||||
assert_eq!(st["source"], true);
|
||||
let res = eng.results(&job, &service::Query::default()).unwrap();
|
||||
assert_eq!(res["total"], 7);
|
||||
// recuperar a partir da sessão antiga continua dando o mesmo conteúdo
|
||||
// recovering from the legacy session produces the exact same file contents
|
||||
let out = tempfile::tempdir().unwrap();
|
||||
let rj = eng
|
||||
.start_recover(
|
||||
@@ -392,14 +392,14 @@ fn sessao_da_v0_1_0_abre_e_funciona() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Origem indisponível não impede abrir a sessão; reapontar a origem religa tudo.
|
||||
/// A missing source does not block opening a session; relinking the source restores full access.
|
||||
#[test]
|
||||
fn sessao_abre_sem_a_origem_e_pode_ser_reconectada() {
|
||||
init();
|
||||
let Some(dir) = fixtures() else { return };
|
||||
let img = dir.join("ntfs.img");
|
||||
let tmp = sessao_formato_v0_1_0(&img, "/dev/disco-que-nao-existe");
|
||||
// sessão pausada (como as de uma varredura interrompida)
|
||||
// paused session (as produced by an interrupted scan)
|
||||
let mut v: serde_json::Value =
|
||||
serde_json::from_slice(&std::fs::read(tmp.path()).unwrap()).unwrap();
|
||||
v["done"] = serde_json::json!(false);
|
||||
@@ -413,7 +413,7 @@ fn sessao_abre_sem_a_origem_e_pode_ser_reconectada() {
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.contains("não está disponível"));
|
||||
// navegar e exportar funcionam
|
||||
// browsing, filtering, CSV export, and HTML reporting work even while the source is offline
|
||||
assert_eq!(
|
||||
eng.results(&job, &service::Query::default()).unwrap()["total"],
|
||||
7
|
||||
@@ -424,7 +424,7 @@ fn sessao_abre_sem_a_origem_e_pode_ser_reconectada() {
|
||||
.unwrap(),
|
||||
7
|
||||
);
|
||||
// pré-visualização, retomada e recuperação avisam com clareza
|
||||
// preview, resume, and recovery return a clear error while the source is offline
|
||||
assert_eq!(eng.thumb(&job, 1, 128).err(), Some(503));
|
||||
assert!(eng
|
||||
.resume(&job)
|
||||
@@ -442,7 +442,7 @@ fn sessao_abre_sem_a_origem_e_pode_ser_reconectada() {
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(e.to_string().contains("não está disponível"), "{e}");
|
||||
// reconecta
|
||||
// relink the session to the relocated disk image
|
||||
eng.relink(&job, img.to_str().unwrap(), false).unwrap();
|
||||
let st = eng.status(&job).unwrap();
|
||||
assert_eq!(st["source"], true);
|
||||
@@ -458,7 +458,7 @@ fn sessao_abre_sem_a_origem_e_pode_ser_reconectada() {
|
||||
.unwrap();
|
||||
wait_done(&eng, &rj);
|
||||
assert_eq!(hashes_in(out.path()).len(), 7);
|
||||
// arquivo que não é sessão
|
||||
// non-session file returns a clear error
|
||||
std::fs::write(tmp.path(), b"nao e json").unwrap();
|
||||
let e = eng.load_session(tmp.path().to_str().unwrap()).unwrap_err();
|
||||
assert!(
|
||||
@@ -467,7 +467,7 @@ fn sessao_abre_sem_a_origem_e_pode_ser_reconectada() {
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ desconexão e reconexão do disco
|
||||
// ------------------------------------------------------------------ disk disconnect and reconnect
|
||||
|
||||
#[test]
|
||||
fn reconexao_so_aceita_o_mesmo_disco_ou_um_clone() {
|
||||
@@ -477,14 +477,14 @@ fn reconexao_so_aceita_o_mesmo_disco_ou_um_clone() {
|
||||
let tmp = sessao_formato_v0_1_0(&img, img.to_str().unwrap());
|
||||
let eng = service::Engine::new();
|
||||
let job = eng.load_session(tmp.path().to_str().unwrap()).unwrap();
|
||||
// sessão antiga não tem impressão digital: o relink aprende a do primeiro disco aceito
|
||||
// legacy session had no fingerprint: `relink_session` records the fingerprint of the accepted disk
|
||||
eng.relink(&job, img.to_str().unwrap(), false).unwrap();
|
||||
let work = tempfile::tempdir().unwrap();
|
||||
// clone idêntico (por exemplo uma imagem do disco): aceito
|
||||
// identical clone (e.g. a raw disk image of the drive): accepted without `force`
|
||||
let clone = work.path().join("clone.img");
|
||||
std::fs::copy(&img, &clone).unwrap();
|
||||
eng.relink(&job, clone.to_str().unwrap(), false).unwrap();
|
||||
// mesmo tamanho, mas outro conteúdo inicial: recusado, a menos que force
|
||||
// same byte size but different disk content: rejected unless `force` is true
|
||||
let outro = work.path().join("outro.img");
|
||||
let mut bytes = std::fs::read(&img).unwrap();
|
||||
bytes[0..16].copy_from_slice(b"OUTRO DISCO....!");
|
||||
@@ -494,7 +494,7 @@ fn reconexao_so_aceita_o_mesmo_disco_ou_um_clone() {
|
||||
.unwrap_err();
|
||||
assert!(e.to_string().contains("conteúdo inicial"), "{e}");
|
||||
eng.relink(&job, outro.to_str().unwrap(), true).unwrap();
|
||||
// tamanho diferente: recusado
|
||||
// different byte size: rejected unless `force` is true
|
||||
let menor = work.path().join("menor.img");
|
||||
std::fs::write(&menor, &bytes[..bytes.len() / 2]).unwrap();
|
||||
let e = eng
|
||||
@@ -503,7 +503,7 @@ fn reconexao_so_aceita_o_mesmo_disco_ou_um_clone() {
|
||||
assert!(e.to_string().contains("bytes"), "{e}");
|
||||
}
|
||||
|
||||
/// Fonte que "some" a partir de certo ponto, como um disco puxado da porta USB.
|
||||
/// Simulated `Source` that fails with `EIO` past `fail_from`, mimicking an unplugged USB drive.
|
||||
struct Flaky {
|
||||
inner: MemSource,
|
||||
broken_from: u64,
|
||||
@@ -541,8 +541,8 @@ fn varredura_pausa_quando_o_disco_some_e_retoma_do_ponto_certo() {
|
||||
v
|
||||
};
|
||||
let (a, b) = (png(3000), png(4000));
|
||||
disk[2 * mib..2 * mib + a.len()].copy_from_slice(&a); // antes da falha
|
||||
disk[50 * mib..50 * mib + b.len()].copy_from_slice(&b); // depois da falha
|
||||
disk[2 * mib..2 * mib + a.len()].copy_from_slice(&a); // PNG before the disconnect point
|
||||
disk[50 * mib..50 * mib + b.len()].copy_from_slice(&b); // PNG after the disconnect point
|
||||
let flaky = Flaky {
|
||||
inner: MemSource(disk.clone()),
|
||||
broken_from: 16 * mib as u64,
|
||||
@@ -555,9 +555,9 @@ fn varredura_pausa_quando_o_disco_some_e_retoma_do_ponto_certo() {
|
||||
};
|
||||
assert!(cp.io_lost, "deveria marcar perda de E/S");
|
||||
assert_eq!(sink.found.len(), 1, "só o PNG anterior à falha");
|
||||
// o ponto de retomada não pula os blocos que falharam
|
||||
// the saved checkpoint offset does not skip past the unreadable blocks
|
||||
assert!(cp.ranges[0].next <= 16 * mib as u64 + 8 * mib as u64);
|
||||
// disco volta: retoma e acha o resto, sem duplicar o primeiro
|
||||
// once the drive is reconnected, resuming finds the second PNG without duplicating the first
|
||||
let healthy = MemSource(disk);
|
||||
let before = sink.found.clone();
|
||||
let out = scan::run(&healthy, &opts, Some(cp), &before, &|| false, &mut sink);
|
||||
@@ -577,7 +577,7 @@ fn varredura_salva_sessao_sozinha_e_ela_reabre() {
|
||||
.start_scan(img.to_str().unwrap(), ScanOptions::default())
|
||||
.unwrap();
|
||||
wait_done(&eng, &job);
|
||||
// o salvamento final roda numa thread própria
|
||||
// wait briefly for the background autosave thread to flush the final snapshot
|
||||
let mut item = None;
|
||||
for _ in 0..200 {
|
||||
let list = eng.sessions_list();
|
||||
@@ -596,7 +596,7 @@ fn varredura_salva_sessao_sozinha_e_ela_reabre() {
|
||||
assert_eq!(item["found"], 7);
|
||||
let path = item["path"].as_str().unwrap().to_string();
|
||||
assert!(std::path::Path::new(&path).exists());
|
||||
// reabre como qualquer sessão
|
||||
// reopening the autosaved session restores all findings
|
||||
let job2 = eng.load_session(&path).unwrap();
|
||||
let st = eng.status(&job2).unwrap();
|
||||
assert_eq!(
|
||||
@@ -607,13 +607,13 @@ fn varredura_salva_sessao_sozinha_e_ela_reabre() {
|
||||
),
|
||||
("done", 7, true)
|
||||
);
|
||||
// apagar
|
||||
// deleting the autosaved session removes it from the list
|
||||
eng.session_delete(&path).unwrap();
|
||||
assert!(!std::path::Path::new(&path).exists());
|
||||
assert!(eng.session_delete("/etc/passwd").is_err());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------ organização e espaço
|
||||
// ------------------------------------------------------------------ output organization and free-space check
|
||||
|
||||
#[test]
|
||||
fn recuperar_organiza_por_tipo_data_ou_tudo_junto() {
|
||||
@@ -652,7 +652,7 @@ fn recuperar_organiza_por_tipo_data_ou_tudo_junto() {
|
||||
});
|
||||
assert!(achou, "{layout:?}: {:?}", walk_names(out.path()));
|
||||
}
|
||||
// por data: usa a data de modificação (ano/mês)
|
||||
// organize by date: groups into `YYYY/YYYY-MM` by modification/capture date
|
||||
let out = tempfile::tempdir().unwrap();
|
||||
recover::recover_with(
|
||||
src.as_ref(),
|
||||
@@ -699,7 +699,7 @@ fn espaco_insuficiente_no_destino_e_avisado_antes_de_copiar() {
|
||||
let Some(dir) = fixtures() else { return };
|
||||
let img = dir.join("ntfs.img");
|
||||
let tmp = sessao_formato_v0_1_0(&img, img.to_str().unwrap());
|
||||
// sessão com um arquivo "enorme" (1 EB)
|
||||
// synthetic session with a 1 EB file to trigger the insufficient destination space check
|
||||
let mut v: serde_json::Value =
|
||||
serde_json::from_slice(&std::fs::read(tmp.path()).unwrap()).unwrap();
|
||||
v["found"][0]["size"] = serde_json::json!(1u64 << 60);
|
||||
|
||||
Reference in new issue
Block a user