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,7 +1,7 @@
|
||||
//! APFS (volumes sem cifragem): lê o contêiner, o mapa de objetos e a árvore de arquivos de cada
|
||||
//! volume; arquivos apagados vêm de duas fontes: as árvores dos instantâneos (snapshots) e os nós
|
||||
//! antigos da árvore (copy-on-write) que ainda estão no disco. Volumes cifrados (FileVault) são
|
||||
//! detectados e deixados para a varredura por assinatura.
|
||||
//! APFS (unencrypted volumes): parses the container, object map, and file system tree of each
|
||||
//! volume; deleted files are recovered from two sources: snapshot trees and older copy-on-write
|
||||
//! B-tree nodes still resident on disk. Encrypted volumes (FileVault) are detected and left for
|
||||
//! signature carving unless unlocked.
|
||||
|
||||
use super::{make_found, merge_extents, Ctx, NewFound, VolumeScan};
|
||||
use crate::source::{read_vec, Source};
|
||||
@@ -32,13 +32,13 @@ const T_CIB: u32 = 7;
|
||||
const T_CHECKPOINT_MAP: u32 = 0x0C;
|
||||
const SUBTYPE_FSTREE: u32 = 0x0E;
|
||||
|
||||
// tipos de registro da árvore de arquivos
|
||||
// filesystem B-tree record types
|
||||
const R_SNAP_METADATA: u8 = 1;
|
||||
const R_INODE: u8 = 3;
|
||||
const R_FILE_EXTENT: u8 = 8;
|
||||
const R_DIR_REC: u8 = 9;
|
||||
|
||||
/// Soma de verificação Fletcher-64 do APFS (cobre o bloco menos os 8 bytes iniciais).
|
||||
/// APFS Fletcher-64 checksum (covers the block excluding the leading 8 bytes).
|
||||
pub fn fletcher64(data: &[u8]) -> u64 {
|
||||
let (mut s1, mut s2) = (0u64, 0u64);
|
||||
for w in data.chunks_exact(4) {
|
||||
@@ -60,7 +60,7 @@ struct Apfs<'a> {
|
||||
struct BNode {
|
||||
flags: u16,
|
||||
level: u16,
|
||||
/// (chave, valor) por entrada
|
||||
/// `(key, value)` slice pair for each node entry
|
||||
entries: Vec<(Vec<u8>, Vec<u8>)>,
|
||||
oid: u64,
|
||||
xid: u64,
|
||||
@@ -124,7 +124,7 @@ impl<'a> Apfs<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Todas as entradas de uma árvore física (mapa de objetos): filhos são endereços físicos.
|
||||
/// Collects all entries from a physical B-tree (object map): child pointers are physical block addresses.
|
||||
fn walk_physical(
|
||||
&self,
|
||||
root: u64,
|
||||
@@ -156,7 +156,7 @@ impl<'a> Apfs<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Mapa de objetos: oid -> [(xid, paddr)] ordenado por xid.
|
||||
/// Object map: `oid -> [(xid, paddr)]` sorted by transaction ID (`xid`).
|
||||
fn omap(&self, omap_paddr: u64) -> HashMap<u64, Vec<(u64, u64)>> {
|
||||
let mut m: HashMap<u64, Vec<(u64, u64)>> = HashMap::new();
|
||||
let Some(ob) = self.checked_block(omap_paddr) else {
|
||||
@@ -174,7 +174,7 @@ impl<'a> Apfs<'a> {
|
||||
m
|
||||
}
|
||||
|
||||
/// Endereço físico de um objeto ephemeral (spaceman), achado no mapa de checkpoint mais novo.
|
||||
/// Physical block address of an ephemeral object (spaceman) from the latest checkpoint map.
|
||||
fn ephemeral_paddr(&self, nx: &[u8], oid: u64) -> Option<u64> {
|
||||
let desc_blocks = le32(nx, 104) as u64;
|
||||
let desc_base = le64(nx, 112);
|
||||
@@ -203,8 +203,8 @@ impl<'a> Apfs<'a> {
|
||||
best.map(|(_, p)| p)
|
||||
}
|
||||
|
||||
/// Mapa de espaço livre do contêiner: percorre o spaceman, os chunk-info blocks e os bitmaps
|
||||
/// (bit 1 = bloco em uso).
|
||||
/// Container free-space map: walks the spaceman, chunk-info blocks (CIBs), and allocation bitmaps
|
||||
/// (bit 1 = allocated block).
|
||||
fn free_map(&self, nx: &[u8]) -> Option<Vec<Extent>> {
|
||||
let sm_oid = le64(nx, 152);
|
||||
if sm_oid == 0 {
|
||||
@@ -214,7 +214,7 @@ impl<'a> Apfs<'a> {
|
||||
if le32(&sm, 24) & OBJ_TYPE_MASK != T_SPACEMAN {
|
||||
return None;
|
||||
}
|
||||
// Com CABs (contêineres grandes) os endereços dos CIBs não ficam no spaceman.
|
||||
// With CABs (large containers), CIB addresses live in chunk-info address blocks rather than inline in the spaceman.
|
||||
if le32(&sm, 68) != 0 {
|
||||
return None;
|
||||
}
|
||||
@@ -289,7 +289,7 @@ fn lookup(m: &HashMap<u64, Vec<(u64, u64)>>, oid: u64, max_xid: u64) -> Option<u
|
||||
.map(|(_, p)| *p)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- registros
|
||||
// ---------------------------------------------------------------- records
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct Inode {
|
||||
@@ -308,7 +308,7 @@ struct Inode {
|
||||
#[derive(Clone, Debug, Default)]
|
||||
struct FileRec {
|
||||
inode: Inode,
|
||||
names: BTreeMap<u64, String>, // pai -> nome
|
||||
names: BTreeMap<u64, String>, // parent_id -> name
|
||||
}
|
||||
|
||||
type Files = HashMap<u64, FileRec>;
|
||||
@@ -327,7 +327,7 @@ fn add_record(files: &mut Files, extents: &mut Extents, k: &[u8], v: &[u8]) {
|
||||
let mut ino = Inode {
|
||||
parent: le64(v, 0),
|
||||
private_id: le64(v, 8),
|
||||
ctime: ns(le64(v, 16)), // criação
|
||||
ctime: ns(le64(v, 16)), // creation timestamp
|
||||
mtime: ns(le64(v, 24)),
|
||||
atime: ns(le64(v, 40)),
|
||||
mode: le16(v, 80),
|
||||
@@ -338,7 +338,7 @@ fn add_record(files: &mut Files, extents: &mut Extents, k: &[u8], v: &[u8]) {
|
||||
let flags = le64(v, 48);
|
||||
ino.compressed = le32(v, 68) & 0x20 != 0;
|
||||
let _ = flags;
|
||||
// campos estendidos
|
||||
// xfields (extended fields)
|
||||
let xf = &v[92..];
|
||||
if xf.len() >= 4 {
|
||||
let n = le16(xf, 0) as usize;
|
||||
@@ -383,7 +383,7 @@ fn add_record(files: &mut Files, extents: &mut Extents, k: &[u8], v: &[u8]) {
|
||||
}
|
||||
|
||||
impl Apfs<'_> {
|
||||
/// Percorre a árvore de arquivos a partir de uma raiz virtual.
|
||||
/// Walks the filesystem B-tree starting from a virtual root OID.
|
||||
fn walk_fstree(
|
||||
&self,
|
||||
root_oid: u64,
|
||||
@@ -484,7 +484,7 @@ fn open_container<'a>(src: &'a dyn Source, base: u64) -> Option<(Apfs<'a>, Vec<u
|
||||
bs,
|
||||
blocks,
|
||||
};
|
||||
// O superbloco mais recente está na área de descritores de checkpoint.
|
||||
// Find the latest valid container superblock in the checkpoint descriptor area.
|
||||
let desc_blocks = le32(&b0, 104) as u64;
|
||||
let desc_base = le64(&b0, 112);
|
||||
let mut best = b0.clone();
|
||||
@@ -548,7 +548,7 @@ pub fn scan(ctx: &mut Ctx, base: u64, part_len: u64) -> VolumeScan {
|
||||
fn scan_volume(ctx: &mut Ctx, a: &Apfs, v: &Volume, allow_stale_scan: bool, res: &mut VolumeScan) {
|
||||
let omap = a.omap(v.omap_paddr);
|
||||
let current_xid = u64::MAX;
|
||||
// Árvore atual.
|
||||
// Current live filesystem tree.
|
||||
let mut live: Files = HashMap::new();
|
||||
let mut live_ext: Extents = HashMap::new();
|
||||
let mut live_nodes: HashSet<u64> = HashSet::new();
|
||||
@@ -556,7 +556,7 @@ fn scan_volume(ctx: &mut Ctx, a: &Apfs, v: &Volume, allow_stale_scan: bool, res:
|
||||
live_nodes.insert(node);
|
||||
add_record(&mut live, &mut live_ext, k, val);
|
||||
});
|
||||
// Instantâneos.
|
||||
// Volume snapshots.
|
||||
let mut stale: Files = HashMap::new();
|
||||
let mut stale_ext: Extents = HashMap::new();
|
||||
if v.snap_tree_oid != 0 {
|
||||
@@ -583,7 +583,7 @@ fn scan_volume(ctx: &mut Ctx, a: &Apfs, v: &Volume, allow_stale_scan: bool, res:
|
||||
}
|
||||
} else {
|
||||
for (_, val) in &n.entries {
|
||||
// árvore de metadados de snapshot: filhos físicos ou virtuais
|
||||
// snapshot metadata tree: physical or virtual child references
|
||||
let c = le64(val, 0);
|
||||
stack.push(lookup(&omap, c, current_xid).unwrap_or(c));
|
||||
}
|
||||
@@ -602,7 +602,7 @@ fn scan_volume(ctx: &mut Ctx, a: &Apfs, v: &Volume, allow_stale_scan: bool, res:
|
||||
}
|
||||
}
|
||||
}
|
||||
// Nós antigos da árvore de arquivos.
|
||||
// Older evicted copy-on-write filesystem tree leaf nodes.
|
||||
if allow_stale_scan {
|
||||
let total = a.blocks;
|
||||
for p in 0..total {
|
||||
@@ -631,7 +631,7 @@ fn scan_volume(ctx: &mut Ctx, a: &Apfs, v: &Volume, allow_stale_scan: bool, res:
|
||||
}
|
||||
}
|
||||
}
|
||||
// Arquivos que só existem nas versões antigas.
|
||||
// Files present only in older tree versions or snapshots.
|
||||
let mut ids: Vec<&u64> = stale.keys().collect();
|
||||
ids.sort();
|
||||
let mut seen_first: HashSet<u64> = HashSet::new();
|
||||
@@ -648,9 +648,9 @@ fn scan_volume(ctx: &mut Ctx, a: &Apfs, v: &Volume, allow_stale_scan: bool, res:
|
||||
continue;
|
||||
};
|
||||
if ex.values().any(|e| e.2 != 0) {
|
||||
continue; // extensão cifrada
|
||||
continue; // encrypted extent
|
||||
}
|
||||
// nome e pasta: da entrada de diretório, senão do próprio inode
|
||||
// file name and parent folder: prefer directory entry, fallback to inode xfield
|
||||
let (name, parent) = match rec.names.iter().next() {
|
||||
Some((p, n)) => (n.clone(), *p),
|
||||
None => match &ino.name {
|
||||
@@ -726,13 +726,13 @@ fn scan_volume(ctx: &mut Ctx, a: &Apfs, v: &Volume, allow_stale_scan: bool, res:
|
||||
let _ = res;
|
||||
}
|
||||
|
||||
/// Trechos livres (absolutos) do contêiner, segundo o spaceman.
|
||||
/// Absolute free byte extents in the container according to the spaceman.
|
||||
pub fn free_extents(src: &dyn Source, base: u64) -> Option<Vec<Extent>> {
|
||||
let (a, nx) = open_container(src, base)?;
|
||||
a.free_map(&nx)
|
||||
}
|
||||
|
||||
/// Arquivos e pastas atuais do primeiro volume sem cifragem (caminho, tamanho, é pasta).
|
||||
/// Live files and folders in the first unencrypted volume `(path, size, is_dir)`.
|
||||
pub fn live_paths(src: &dyn Source, base: u64) -> Vec<(String, u64, bool)> {
|
||||
let Some((a, nx)) = open_container(src, base) else {
|
||||
return vec![];
|
||||
|
||||
Reference in new issue
Block a user