sonar

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

commit 385967ee523ba3745ae38971da391e94ed74053f
parent 58ce9575b74e8f145475b7311ccd556336771733
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Fri, 18 Sep 2026 07:53:25 -0400

main: check the attributed sum against $Bitmap

The summary now prints what every file claims next to what the volume says
is allocated, so a reader can see at a glance whether the parser accounts for
the disk. On a live NTFS volume the two agree to within a rounding error, and
a wide gap would mean a decoding bug rather than missing space. The resident
file line explains the one category the per-file sums cannot attribute.

Diffstat:
Mmain.odin | 22+++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/main.odin b/main.odin @@ -98,7 +98,27 @@ print_summary :: proc(m: ^ntfs.Mft, elapsed: time.Duration) { fmt.printfln("volume %s, %d B clusters, %d B records", human(volume_bytes), m.boot.bytes_per_cluster, m.boot.record_size) fmt.printfln("mft %d slots, %d records, %d unreadable, read in %.0f ms", m.stats.records, m.stats.records_read, m.stats.records_bad, time.duration_milliseconds(elapsed)) fmt.printfln("in use %d files, %d directories, %d extra hard links", files, m.stats.directories, len(m.links)) - fmt.printfln("allocated %s across all data streams and indexes", human(allocated)) + fmt.printfln("attributed %s summed from every file run list", human(allocated)) + + /* + $Bitmap counts allocated clusters without consulting a single file, so comparing it + against the sum above checks the run list decoding. The two should agree closely; + a wide gap means clusters are allocated that no file claims, which is a parsing bug + rather than missing disk space. + */ + on_disk := m.stats.allocated_clusters * u64(m.boot.bytes_per_cluster) + if on_disk > 0 { + fmt.printfln("on disk %s marked allocated in $Bitmap", human(on_disk)) + if on_disk >= allocated { + gap := on_disk - allocated + fmt.printfln("unclaimed %s (%.2f%%) allocated but charged to no file", human(gap), 100 * f64(gap) / f64(on_disk)) + } else { + fmt.printfln("overcount %s more attributed than $Bitmap reports allocated", human(allocated - on_disk)) + } + } + if m.stats.resident_files > 0 { + fmt.printfln("resident %d files hold %s inside their MFT records, charged to $MFT", m.stats.resident_files, human(m.stats.resident_bytes)) + } } Sized :: struct {