Artifact 058e24341c37bfc73260bf12cefb108facbe970dac5229a945282341106a1150:
- File
internal/verify/check_blobs.go
— part of check-in
[f5744359d3]
at
2026-04-19 16:30:54
on branch trunk
— Initial open source release
libfossil is a pure-Go implementation of the Fossil SCM, reading and writing the same .fossil SQLite repository format as upstream Fossil.
This is the first public release of code that previously lived in a private repository. The module path is github.com/danmestas/libfossil and the binary is named libfossil to avoid $PATH collisions with upstream fossil.
Included: - Repo lifecycle (create, clone), checkout/checkin, timeline, merge, diff, annotate, shun, tag, branch, bisect, stash, undo/redo - Sync-over-HTTP protocol (client and handler) - Two SQLite drivers: modernc (pure Go, default) and ncruces (wasm-capable) - Observer interfaces (SyncObserver, CheckoutObserver) with an optional OpenTelemetry implementation in observer/otel (separate submodule) - Deterministic simulation testing harness with BUGGIFY fault injection - Kong-based embeddable CLI under cli/ and a standalone binary under cmd/libfossil/ (user: [email protected], size: 2137) [annotate] [blame] [check-ins using]
package verify import ( "fmt" libfossil "github.com/danmestas/libfossil/internal/fsltype" "github.com/danmestas/libfossil/internal/content" "github.com/danmestas/libfossil/internal/hash" "github.com/danmestas/libfossil/internal/repo" ) // checkBlobs verifies blob integrity: content hashing and delta application. // Walks every non-phantom blob, expands delta chains, hashes content, and compares against stored UUID. func checkBlobs(r *repo.Repo, report *Report) error { if r == nil { panic("checkBlobs: nil *repo.Repo") } if report == nil { panic("checkBlobs: nil *Report") } rows, err := r.DB().Query("SELECT rid, uuid FROM blob WHERE size >= 0") if err != nil { return fmt.Errorf("checkBlobs: query: %w", err) } defer rows.Close() type blobEntry struct { rid int64 uuid string } var entries []blobEntry for rows.Next() { var e blobEntry if err := rows.Scan(&e.rid, &e.uuid); err != nil { return fmt.Errorf("checkBlobs: scan: %w", err) } entries = append(entries, e) } if err := rows.Err(); err != nil { return fmt.Errorf("checkBlobs: rows: %w", err) } for _, e := range entries { report.BlobsChecked++ rid := libfossil.FslID(e.rid) data, err := content.Expand(r.DB(), rid) if err != nil { report.BlobsFailed++ report.addIssue(Issue{ Kind: IssueBlobCorrupt, RID: rid, UUID: e.uuid, Table: "blob", Message: fmt.Sprintf("rid %d: expand failed: %v", e.rid, err), }) continue } var computed string if len(e.uuid) == 64 { computed = hash.SHA3(data) } else { computed = hash.SHA1(data) } if computed != e.uuid { report.BlobsFailed++ report.addIssue(Issue{ Kind: IssueHashMismatch, RID: rid, UUID: e.uuid, Table: "blob", Message: fmt.Sprintf("rid %d: hash mismatch (stored=%s computed=%s)", e.rid, e.uuid, computed), }) continue } report.BlobsOK++ } // Postcondition: every checked blob is either OK or failed. if report.BlobsChecked != report.BlobsOK+report.BlobsFailed { panic("checkBlobs: postcondition: BlobsChecked != BlobsOK + BlobsFailed") } return nil }