Fast implementation of Git in pure Go
at master 114 lines 2.6 kB view raw
1package read 2 3import ( 4 "encoding/binary" 5 6 "codeberg.org/lindenii/furgit/commitgraph/bloom" 7 "codeberg.org/lindenii/furgit/internal/intconv" 8) 9 10// HasBloom reports whether any layer has changed-path Bloom data. 11func (reader *Reader) HasBloom() bool { 12 for i := range reader.layers { 13 layer := &reader.layers[i] 14 if layer.chunkBloomIndex != nil && layer.chunkBloomData != nil && layer.bloomSettings != nil { 15 return true 16 } 17 } 18 19 return false 20} 21 22// BloomVersion returns the changed-path Bloom hash version, or 0 if absent. 23func (reader *Reader) BloomVersion() uint8 { 24 for i := len(reader.layers) - 1; i >= 0; i-- { 25 layer := &reader.layers[i] 26 if layer.bloomSettings != nil { 27 version, err := intconv.Uint32ToUint8(layer.bloomSettings.HashVersion) 28 if err != nil { 29 return 0 30 } 31 32 return version 33 } 34 } 35 36 return 0 37} 38 39// BloomFilterAt returns one commit's changed-path Bloom filter. 40// 41// Returns BloomUnavailableError when this commit graph has no Bloom data. 42func (reader *Reader) BloomFilterAt(pos Position) (*bloom.Filter, error) { 43 layer, err := reader.layerByPosition(pos) 44 if err != nil { 45 return nil, err 46 } 47 48 if layer.chunkBloomIndex == nil || layer.chunkBloomData == nil || layer.bloomSettings == nil { 49 return nil, &BloomUnavailableError{Pos: pos} 50 } 51 52 start, end, err := bloomRange(layer, pos.Index) 53 if err != nil { 54 return nil, err 55 } 56 57 filter := bloom.NewFilter( 58 layer.chunkBloomData[bloom.DataHeaderSize+start:bloom.DataHeaderSize+end], 59 *layer.bloomSettings, 60 ) 61 62 return filter, nil 63} 64 65func bloomRange(layer *layer, commitIndex uint32) (int, int, error) { 66 off64 := uint64(commitIndex) * 4 67 68 off, err := intconv.Uint64ToInt(off64) 69 if err != nil { 70 return 0, 0, err 71 } 72 73 end := binary.BigEndian.Uint32(layer.chunkBloomIndex[off : off+4]) 74 75 var start uint32 76 77 if commitIndex > 0 { 78 prevOff64 := uint64(commitIndex-1) * 4 79 80 prevOff, err := intconv.Uint64ToInt(prevOff64) 81 if err != nil { 82 return 0, 0, err 83 } 84 85 start = binary.BigEndian.Uint32(layer.chunkBloomIndex[prevOff : prevOff+4]) 86 } 87 88 if end < start { 89 return 0, 0, &MalformedError{Path: layer.path, Reason: "invalid BIDX range"} 90 } 91 92 bdatLen := len(layer.chunkBloomData) - bloom.DataHeaderSize 93 94 bdatLenU32, err := intconv.IntToUint32(bdatLen) 95 if err != nil { 96 return 0, 0, err 97 } 98 99 if end > bdatLenU32 { 100 return 0, 0, &MalformedError{Path: layer.path, Reason: "BIDX range out of BDAT bounds"} 101 } 102 103 startInt, err := intconv.Uint64ToInt(uint64(start)) 104 if err != nil { 105 return 0, 0, err 106 } 107 108 endInt, err := intconv.Uint64ToInt(uint64(end)) 109 if err != nil { 110 return 0, 0, err 111 } 112 113 return startInt, endInt, nil 114}