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