From e15054a4f93fc54806e84aa7036e60168e78e823 Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Fri, 6 Mar 2026 08:05:51 +0800 Subject: format/commitgraph: Add initial commit-graph support --- format/commitgraph/hash.go | 79 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 format/commitgraph/hash.go (limited to 'format/commitgraph/hash.go') diff --git a/format/commitgraph/hash.go b/format/commitgraph/hash.go new file mode 100644 index 00000000..55bc0195 --- /dev/null +++ b/format/commitgraph/hash.go @@ -0,0 +1,79 @@ +package commitgraph + +import ( + "bytes" + "fmt" + "io" + + "codeberg.org/lindenii/furgit/objectid" +) + +// HashVersion returns the commit-graph hash version. +func (reader *Reader) HashVersion() uint8 { + return reader.hashVersion +} + +func validateChainBaseHashes(algo objectid.Algorithm, chain []string, idx int, graph *layer) error { + if idx == 0 { + if len(graph.chunkBaseGraphs) != 0 { + return &ErrMalformed{Path: graph.path, Reason: "unexpected BASE chunk in first graph"} + } + + return nil + } + + hashSize := algo.Size() + + expectedLen := idx * hashSize + if len(graph.chunkBaseGraphs) != expectedLen { + return &ErrMalformed{ + Path: graph.path, + Reason: fmt.Sprintf("BASE chunk length %d does not match expected %d", len(graph.chunkBaseGraphs), expectedLen), + } + } + + for i := range idx { + start := i * hashSize + end := start + hashSize + + baseHash, err := objectid.FromBytes(algo, graph.chunkBaseGraphs[start:end]) + if err != nil { + return err + } + + if baseHash.String() != chain[i] { + return &ErrMalformed{ + Path: graph.path, + Reason: fmt.Sprintf("BASE chunk mismatch at index %d", i), + } + } + } + + return nil +} + +func verifyTrailerHash(data []byte, algo objectid.Algorithm, path string) error { + hashSize := algo.Size() + if len(data) < hashSize { + return &ErrMalformed{Path: path, Reason: "file too short for trailer"} + } + + hashImpl, err := algo.New() + if err != nil { + return err + } + + _, err = io.Copy(hashImpl, bytes.NewReader(data[:len(data)-hashSize])) + if err != nil { + return err + } + + got := hashImpl.Sum(nil) + + want := data[len(data)-hashSize:] + if !bytes.Equal(got, want) { + return &ErrMalformed{Path: path, Reason: "trailer hash mismatch"} + } + + return nil +} -- cgit v1.3.1-10-gc9f91