sonar

Scan files at memory bandwidth speed.
Log | Files | Refs

commit 5eb2ae2863549b9b3d5db84505618b56fc819969
parent 295a060f196d345d4b0a1c85fa8f81d16590a842
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Sun, 20 Sep 2026 09:07:48 -0300

scan: name the top of a target and the path below it

main built the path of a subtree by trimming a trailing separator off the mount
point and concatenating, in two places, with a third spelling for the banner. The
banner's was wrong: it printed the subtree alone, so scanning /usr/share/doc
announced usr/share/doc.

`top` and `location` answer both from the target itself, and cover a volume that
is mounted nowhere by naming the volume instead. That case had rendered as an
empty string.

Diffstat:
Mmain.odin | 10+++++-----
Mscan/target.odin | 23+++++++++++++++++++++++
2 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/main.odin b/main.odin @@ -103,7 +103,7 @@ run :: proc() -> int { choice := scan.choose(resolved, scan.elevated()) fmt.printfln( "sonar: %s on %s (%v, %v engine, %v io)", - resolved.root if resolved.root != "" else resolved.mount, + scan.location(resolved, context.temp_allocator), resolved.volume, resolved.fs, choice.engine, @@ -122,7 +122,7 @@ run :: proc() -> int { fmt.eprintln("error: live mode needs the MFT reader") return 1 } - return run_live(resolved.volume, strings.trim_suffix(resolved.mount, `\`), opts) + return run_live(resolved.volume, scan.top(resolved), opts) } t: scan.Tree @@ -165,11 +165,11 @@ run :: proc() -> int { fmt.eprintfln("error: %v", err) return 1 } - // The table calls its root ".", so paths would lose the drive it came from. + // The table calls its root ".", so paths would lose the volume it came from. rw := scan.writer(&t, 0) - scan.node(&t, t.root).name = scan.intern(&rw, strings.trim_suffix(resolved.mount, `\`)) + scan.node(&t, t.root).name = scan.intern(&rw, scan.top(resolved)) case .Walk: - root := resolved.mount if resolved.root == "" else fmt.tprintf("%s%s", strings.trim_suffix(resolved.mount, `\`), resolved.root) + root := scan.location(resolved, context.temp_allocator) if err := walk.scan(root, &t, wcfg); err != nil { fmt.eprintfln("error: walking %s: %v", root, err) return 1 diff --git a/scan/target.odin b/scan/target.odin @@ -1,6 +1,7 @@ package scan import "core:mem" +import "core:strings" /* What the user asked to scan, resolved once so no backend has to re-derive it. @@ -29,6 +30,28 @@ Filesystem :: enum { Network, } +/* +The top of the target, named as a path: where the volume is mounted, or the volume +itself when nothing has it mounted. No trailing separator, so a subtree joins on. +*/ +top :: proc(t: Target) -> string { + if t.mount == "" { + return t.volume + } + if len(t.mount) > 1 { + return strings.trim_right(t.mount, `\/`) + } + return t.mount +} + +// The full path of what will be scanned: the top, and the subtree below it. +location :: proc(t: Target, allocator := context.allocator) -> string { + if t.root == "" { + return strings.clone(top(t), allocator) + } + return strings.concatenate({top(t), t.root}, allocator) +} + target_destroy :: proc(t: ^Target) { delete(t.input, t.allocator) delete(t.volume, t.allocator)