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:
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)