feat: explorador de arquivos, miniaturas, metadados e recursos periciais (0.3.0)
Release / Cria a release (push) Canceled after 0s
Release / CLI (linux-aarch64) (push) Canceled after 0s
Release / CLI (linux-x86_64) (push) Canceled after 0s
Release / CLI (macos-aarch64) (push) Canceled after 0s
Release / CLI (macos-x86_64) (push) Canceled after 0s
Release / CLI (windows-x86_64) (push) Canceled after 0s
Release / App desktop (linux-x86_64) (push) Canceled after 0s
Release / App desktop (macos-aarch64) (push) Canceled after 0s
Release / App desktop (macos-x86_64) (push) Canceled after 0s
Release / App desktop (windows-x86_64) (push) Canceled after 0s
Release / Publica a release (push) Canceled after 0s

- Explorador com grade/lista virtualizada, navegação por tipo, data EXIF, pasta e
  câmera, seleção estilo gerenciador de arquivos e visualização rápida.
- Miniaturas no núcleo, metadados (EXIF, PDF, Office, MP4), datas MACB do NTFS/FAT/exFAT.
- Hashes MD5/SHA-1/SHA-256, busca de texto no disco, exportação CSV, relatório HTML,
  detecção de duplicadas, tema, correções de interface e textos sem travessões.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Sonnet 5.5 committed 2026-10-18 16:16:20 -03:00
1 parent 1457caa453
commit 45d535bdb7
34 files changed
+4433 -365

No files matched your search

+10
View File
@@ -174,6 +174,14 @@ fn walk(
let mdate = u16::from_le_bytes([e[14], e[15]]);
let mtime = u16::from_le_bytes([e[12], e[13]]);
let mod_unix = super::dos_to_unix(mdate, mtime);
let cre_unix = super::dos_to_unix(
u16::from_le_bytes([e[10], e[11]]),
u16::from_le_bytes([e[8], e[9]]),
);
let acc_unix = super::dos_to_unix(
u16::from_le_bytes([e[18], e[19]]),
u16::from_le_bytes([e[16], e[17]]),
);
let mut stream: Option<&[u8]> = None;
let mut name_u16: Vec<u8> = vec![];
for s in 1..=secondary.min(19) {
@@ -259,6 +267,8 @@ fn walk(
origin: Origin::Exfat,
data: DataLoc::Extents { extents: ex },
modified: mod_unix,
created: cre_unix,
accessed: acc_unix,
base: conf,
note,
},
+17 -3
View File
@@ -237,6 +237,11 @@ impl Walk<'_, '_, '_, '_> {
u16::from_le_bytes([e[24], e[25]]),
u16::from_le_bytes([e[22], e[23]]),
);
let ctime = super::dos_to_unix(
u16::from_le_bytes([e[16], e[17]]),
u16::from_le_bytes([e[14], e[15]]),
);
let atime = super::dos_to_unix(u16::from_le_bytes([e[18], e[19]]), 0);
self.count += 1;
if self.count % 512 == 0 {
(self.ctx.progress)(self.count, 0);
@@ -277,7 +282,7 @@ impl Walk<'_, '_, '_, '_> {
if size == 0 || !self.fat.valid(start) {
continue;
}
self.deleted_file(&name, path, start, size, mtime);
self.deleted_file(&name, path, start, size, (ctime, mtime, atime));
}
}
@@ -291,7 +296,14 @@ impl Walk<'_, '_, '_, '_> {
v
}
fn deleted_file(&mut self, name: &str, dir: &str, start: u32, size: u64, mtime: Option<i64>) {
fn deleted_file(
&mut self,
name: &str,
dir: &str,
start: u32,
size: u64,
times: (Option<i64>, Option<i64>, Option<i64>),
) {
let fat = self.fat;
let cb = fat.cluster_bytes();
let need = size.div_ceil(cb);
@@ -336,7 +348,9 @@ impl Walk<'_, '_, '_, '_> {
data: DataLoc::Extents {
extents: trim_extents(extents, size),
},
modified: mtime,
modified: times.1,
created: times.0,
accessed: times.2,
base: conf,
note,
};
+9
View File
@@ -47,6 +47,8 @@ pub struct NewFound<'a> {
pub origin: Origin,
pub data: DataLoc,
pub modified: Option<i64>,
pub created: Option<i64>,
pub accessed: Option<i64>,
pub base: Confidence,
pub note: Option<&'a str>,
}
@@ -98,6 +100,13 @@ pub fn make_found(ctx: &Ctx, n: NewFound) -> Found {
confidence: conf,
data: n.data,
modified: n.modified,
created: n.created,
accessed: n.accessed,
taken: None,
camera: None,
px: None,
gps: false,
sig: None,
note,
}
}
+10
View File
@@ -22,6 +22,8 @@ struct Rec {
parent: u64,
name: Option<(String, u8)>,
mtime: Option<i64>,
ctime: Option<i64>,
atime: Option<i64>,
data: Option<Data>,
has_attr_list: bool,
}
@@ -199,6 +201,8 @@ pub fn scan(ctx: &mut Ctx, base: u64) -> VolumeScan {
origin: Origin::Ntfs,
data,
modified: rec.mtime,
created: rec.ctime,
accessed: rec.atime,
base: conf,
note: if rec.has_attr_list {
Some("registro com lista de atributos: pode estar incompleto")
@@ -320,6 +324,8 @@ fn parse_record(r: &mut [u8], bps: u64, _base: u64, _cl: u64) -> Option<Rec> {
parent: 0,
name: None,
mtime: None,
ctime: None,
atime: None,
data: None,
has_attr_list: false,
};
@@ -341,7 +347,11 @@ fn parse_record(r: &mut [u8], bps: u64, _base: u64, _cl: u64) -> Option<Rec> {
0x10 if !nonres => {
let vo = le16(r, p + 20) as usize;
if p + vo + 16 <= r.len() {
rec.ctime = filetime_to_unix(le64(r, p + vo));
rec.mtime = filetime_to_unix(le64(r, p + vo + 8));
if p + vo + 32 <= r.len() {
rec.atime = filetime_to_unix(le64(r, p + vo + 24));
}
}
}
0x20 => rec.has_attr_list = true,