Skip to content

Commit f7f3218

Browse files
committed
chore: development v0.1.27 - comprehensive testing complete [auto-commit]
1 parent c44e379 commit f7f3218

File tree

19 files changed

+1059
-93
lines changed

19 files changed

+1059
-93
lines changed

.cargo/config.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,15 @@ rustflags = [
4848
# =============================================================================
4949
# NOTE: Do NOT use target-cpu=native here - it breaks cross-compilation from
5050
# macOS ARM64 (the host CPU "apple-m4" is not valid for x86_64 targets).
51-
# Use x86-64-v2 for good compatibility (SSE4.2, POPCNT - supported since ~2009).
51+
# Use x86-64-v3 for AVX2 support (Intel Haswell 2013+, AMD Zen 2017+).
5252
#
5353
# NOTE: Do NOT use embed-bitcode=no here - it's incompatible with LTO (release builds).
5454
# The xwin-dev profile handles COFF archive size limits for debug builds instead.
5555
# See: docs/xwin-msvc-rlib-size-root-cause-and-workarounds.md
5656
[target.x86_64-pc-windows-msvc]
5757
linker = "rust-lld"
5858
rustflags = [
59-
"-C", "target-cpu=x86-64-v2",
59+
"-C", "target-cpu=x86-64-v3",
6060
"-C", "link-arg=/OPT:REF",
6161
"-C", "link-arg=/OPT:ICF",
6262
]

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ members = [
3232
# Workspace Package Metadata (inherited by all crates)
3333
# ─────────────────────────────────────────────────────────────────────────────
3434
[workspace.package]
35-
version = "0.1.23"
35+
version = "0.1.27"
3636
edition = "2024"
3737
rust-version = "1.85"
3838
license = "MPL-2.0 OR LicenseRef-UFFS-Commercial"

README.md

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,14 @@ uffs load-raw c_mft.raw --output parsed.parquet
192192

193193
UFFS is built as a modular Rust workspace:
194194

195-
```
196-
crates/
197-
├── uffs-polars # Polars facade (compilation isolation)
198-
├── uffs-mft # Direct MFT reading → Polars DataFrame
199-
├── uffs-core # Query engine using Polars lazy API
200-
├── uffs-cli # Command-line interface
201-
├── uffs-tui # Terminal UI (interactive)
202-
└── uffs-gui # Graphical UI (future)
203-
```
195+
| Crate | Description | Documentation |
196+
|-------|-------------|---------------|
197+
| `uffs-polars` | Polars facade (compilation isolation) | - |
198+
| `uffs-mft` | Direct MFT reading → Polars DataFrame | [📖 README](crates/uffs-mft/README.md) |
199+
| `uffs-core` | Query engine using Polars lazy API | - |
200+
| `uffs-cli` | Command-line interface (`uffs`) | - |
201+
| `uffs-tui` | Terminal UI (`uffs_tui`) | - |
202+
| `uffs-gui` | Graphical UI (`uffs_gui`) | - |
204203

205204
### Key Features
206205

@@ -211,6 +210,26 @@ crates/
211210
- **Multi-drive Parallel Search**: Query all drives concurrently
212211
- **SIMD-accelerated Pattern Matching**: Fast glob and regex support
213212

213+
### Low-Level MFT Tools
214+
215+
The `uffs_mft` binary provides direct MFT access for advanced users:
216+
217+
```bash
218+
# Quick MFT info (~10ms)
219+
uffs_mft info --drive C
220+
221+
# Full MFT analysis with file statistics (~10-30s)
222+
uffs_mft info --drive C --deep
223+
224+
# Export MFT to Parquet
225+
uffs_mft read --drive C --output mft.parquet
226+
227+
# List NTFS drives
228+
uffs_mft drives
229+
```
230+
231+
See [uffs-mft README](crates/uffs-mft/README.md) for detailed documentation.
232+
214233
---
215234

216235
## ⚠️ Requirements

crates/uffs-cli/src/main.rs

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,36 @@ static GLOBAL: MiMalloc = MiMalloc;
4242

4343
mod commands;
4444

45+
/// Parse a drive letter from various formats for CPP compatibility.
46+
///
47+
/// Accepts:
48+
/// - Single letter: `C`, `c`
49+
/// - With colon: `C:`, `c:`
50+
///
51+
/// Returns uppercase drive letter.
52+
fn parse_drive_letter(input: &str) -> Result<char, String> {
53+
let trimmed = input.trim();
54+
// Strip trailing colon if present (CPP compatibility: "C:" -> "C")
55+
let letter_str = trimmed.strip_suffix(':').unwrap_or(trimmed);
56+
57+
if letter_str.len() != 1 {
58+
return Err(format!(
59+
"Invalid drive letter '{input}': expected single letter like 'C' or 'C:'"
60+
));
61+
}
62+
63+
let ch = letter_str
64+
.chars()
65+
.next()
66+
.ok_or_else(|| format!("Invalid drive letter '{input}'"))?;
67+
68+
if !ch.is_ascii_alphabetic() {
69+
return Err(format!("Invalid drive letter '{input}': must be A-Z"));
70+
}
71+
72+
Ok(ch.to_ascii_uppercase())
73+
}
74+
4575
/// UFFS - Ultra Fast File Search using direct MFT reading
4676
#[derive(Parser)]
4777
#[command(name = "uffs")]
@@ -68,12 +98,12 @@ struct Cli {
6898
#[arg(value_name = "PATTERN")]
6999
pattern: Option<String>,
70100

71-
/// Drive letter to search (e.g., C). Overrides drive in pattern.
72-
#[arg(short, long, conflicts_with = "drives")]
101+
/// Drive letter to search (e.g., C or C:). Overrides drive in pattern.
102+
#[arg(short, long, conflicts_with = "drives", value_parser = parse_drive_letter)]
73103
drive: Option<char>,
74104

75-
/// Multiple drive letters to search concurrently (e.g., C,D,E)
76-
#[arg(long, value_delimiter = ',', conflicts_with = "drive")]
105+
/// Multiple drive letters to search concurrently (e.g., C,D,E or C:,D:,E:)
106+
#[arg(long, value_delimiter = ',', conflicts_with = "drive", value_parser = parse_drive_letter)]
77107
drives: Option<Vec<char>>,
78108

79109
/// Use pre-built index file instead of live MFT
@@ -162,12 +192,13 @@ enum Commands {
162192
/// `">.*\.log$"` - REGEX for .log files
163193
pattern: String,
164194

165-
/// Drive letter to search (e.g., C). Overrides drive in pattern.
166-
#[arg(short, long, conflicts_with = "drives")]
195+
/// Drive letter to search (e.g., C or C:). Overrides drive in pattern.
196+
#[arg(short, long, conflicts_with = "drives", value_parser = parse_drive_letter)]
167197
drive: Option<char>,
168198

169-
/// Multiple drive letters to search concurrently (e.g., C,D,E)
170-
#[arg(long, value_delimiter = ',', conflicts_with = "drive")]
199+
/// Multiple drive letters to search concurrently (e.g., C,D,E or
200+
/// C:,D:,E:)
201+
#[arg(long, value_delimiter = ',', conflicts_with = "drive", value_parser = parse_drive_letter)]
171202
drives: Option<Vec<char>>,
172203

173204
/// Use pre-built index file instead of live MFT
@@ -254,12 +285,14 @@ enum Commands {
254285

255286
/// Build an index from a drive's MFT
256287
Index {
257-
/// Drive letter to index (e.g., C). Use --drives for multiple drives.
258-
#[arg(short, long, conflicts_with = "drives")]
288+
/// Drive letter to index (e.g., C or C:). Use --drives for multiple
289+
/// drives.
290+
#[arg(short, long, conflicts_with = "drives", value_parser = parse_drive_letter)]
259291
drive: Option<char>,
260292

261-
/// Multiple drive letters to index concurrently (e.g., C,D,E)
262-
#[arg(long, value_delimiter = ',', conflicts_with = "drive")]
293+
/// Multiple drive letters to index concurrently (e.g., C,D,E or
294+
/// C:,D:,E:)
295+
#[arg(long, value_delimiter = ',', conflicts_with = "drive", value_parser = parse_drive_letter)]
263296
drives: Option<Vec<char>>,
264297

265298
/// Output file path
@@ -286,8 +319,8 @@ enum Commands {
286319

287320
/// Save raw MFT bytes to a file for offline analysis
288321
SaveRaw {
289-
/// Drive letter to read MFT from (e.g., C)
290-
#[arg(short, long)]
322+
/// Drive letter to read MFT from (e.g., C or C:)
323+
#[arg(short, long, value_parser = parse_drive_letter)]
291324
drive: char,
292325

293326
/// Output file path for raw MFT data
@@ -320,9 +353,9 @@ enum Commands {
320353

321354
/// Initialize logging with terminal + file support.
322355
///
323-
/// If `verbose` is true and `RUST_LOG` is not set, uses `info` level for terminal.
324-
/// Otherwise, terminal logging is controlled by `RUST_LOG` (default: `error`).
325-
/// File logging is controlled by `RUST_LOG_FILE` (default: `info`).
356+
/// If `verbose` is true and `RUST_LOG` is not set, uses `info` level for
357+
/// terminal. Otherwise, terminal logging is controlled by `RUST_LOG` (default:
358+
/// `error`). File logging is controlled by `RUST_LOG_FILE` (default: `info`).
326359
/// Log directory is controlled by `UFFS_LOG_DIR` (default: `~/bin/rust`).
327360
///
328361
/// Returns a guard that must be kept alive for the duration of the program.
@@ -373,18 +406,26 @@ fn init_logging(verbose: bool) -> tracing_appender::non_blocking::WorkerGuard {
373406
// Timer format
374407
let timer = UtcTime::rfc_3339();
375408

376-
// Terminal layer (with ANSI colors)
409+
// Terminal layer (with ANSI colors, file/line info, thread IDs)
377410
let terminal_layer = tracing_subscriber::fmt::layer()
378411
.with_writer(stdout)
379412
.with_timer(timer.clone())
380413
.with_ansi(true)
414+
.with_file(true)
415+
.with_line_number(true)
416+
.with_thread_ids(true)
417+
.with_target(true)
381418
.with_filter(terminal_filter);
382419

383-
// File layer (no ANSI colors)
420+
// File layer (no ANSI colors, but with full context)
384421
let file_layer = tracing_subscriber::fmt::layer()
385422
.with_writer(non_blocking)
386423
.with_timer(timer)
387424
.with_ansi(false)
425+
.with_file(true)
426+
.with_line_number(true)
427+
.with_thread_ids(true)
428+
.with_target(true)
388429
.with_filter(file_filter);
389430

390431
// Combine layers
@@ -401,8 +442,9 @@ fn init_logging(verbose: bool) -> tracing_appender::non_blocking::WorkerGuard {
401442
#[tokio::main]
402443
#[allow(clippy::too_many_lines)]
403444
async fn main() -> Result<()> {
404-
// Check for -v/--verbose flag early to set log level before initializing logging
405-
// This allows `uffs -v search ...` to show info-level logs without RUST_LOG=info
445+
// Check for -v/--verbose flag early to set log level before initializing
446+
// logging This allows `uffs -v search ...` to show info-level logs without
447+
// RUST_LOG=info
406448
let verbose = std::env::args().any(|arg| arg == "-v" || arg == "--verbose");
407449

408450
// Initialize logging with terminal + file support

0 commit comments

Comments
 (0)