sonar

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

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

scan: build paths with the host's separator

Paths were joined with a backslash whatever was running, which the walker made
visible as soon as it ran anywhere else: a scan of /usr/share/doc reported
/usr/share/doc\ghostscript\Ghostscript.pdf.

A path is written for the machine showing it rather than for the filesystem it
came from, so an NTFS volume read from unix still prints something the shell
there would take back. The test spelled a Windows path out; it now builds one.

Diffstat:
Mscan/tree.odin | 15++++++++++-----
Mscan/tree_test.odin | 6+++++-
2 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/scan/tree.odin b/scan/tree.odin @@ -195,6 +195,12 @@ grow :: proc(t: ^Tree, needed: u32) -> bool { return true } +// Paths are written for the machine showing them rather than for the filesystem they +// came from, so an NTFS volume read from unix still prints something the shell there +// would take back. +@(private) +SEPARATOR :: `\` when ODIN_OS == .Windows else "/" + /* Rebuild a node's path by following parents to a root. @@ -222,15 +228,14 @@ path :: proc(t: ^Tree, i: u32, allocator := context.allocator) -> string { if name == "" { continue } - // The root carries its own separator on Windows, so joining blindly would - // double it. - if strings.builder_len(sb) > 0 && !strings.has_suffix(strings.to_string(sb), `\`) { - strings.write_byte(&sb, '\\') + // The root carries its own separator, so joining blindly would double it. + if strings.builder_len(sb) > 0 && !strings.has_suffix(strings.to_string(sb), SEPARATOR) { + strings.write_string(&sb, SEPARATOR) } strings.write_string(&sb, name) } if strings.builder_len(sb) == 0 { - strings.write_byte(&sb, '\\') + strings.write_string(&sb, SEPARATOR) } return strings.to_string(sb) } diff --git a/scan/tree_test.odin b/scan/tree_test.odin @@ -1,5 +1,6 @@ package scan +import "core:strings" import "core:testing" @(private = "file") @@ -82,7 +83,10 @@ test_path_walks_to_a_root :: proc(t: ^testing.T) { node(&tree, 1)^ = Node{parent = 0, name = "Windows", flags = {.Used, .Directory}} node(&tree, 2)^ = Node{parent = 1, name = "notepad.exe", flags = {.Used}} - testing.expect_value(t, path(&tree, 2, context.temp_allocator), `C:\Windows\notepad.exe`) + // Written with the separator of the machine showing the path, not the one the + // names came from, so this is built rather than spelled. + want := strings.concatenate({"C:", SEPARATOR, "Windows", SEPARATOR, "notepad.exe"}, context.temp_allocator) + testing.expect_value(t, path(&tree, 2, context.temp_allocator), want) testing.expect_value(t, path(&tree, 0, context.temp_allocator), "C:") }