mirror of
https://github.com/go-gitea/gitea
synced 2024-09-18 17:56:03 +00:00
a9b4c8171f
* update gopkg.in/src-d/go-git.v4 v4.13.0 * mod tidy * vendor
178 lines
3.3 KiB
Go
178 lines
3.3 KiB
Go
package idxfile
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
|
|
"gopkg.in/src-d/go-git.v4/utils/binary"
|
|
)
|
|
|
|
var (
|
|
// ErrUnsupportedVersion is returned by Decode when the idx file version
|
|
// is not supported.
|
|
ErrUnsupportedVersion = errors.New("Unsuported version")
|
|
// ErrMalformedIdxFile is returned by Decode when the idx file is corrupted.
|
|
ErrMalformedIdxFile = errors.New("Malformed IDX file")
|
|
)
|
|
|
|
const (
|
|
fanout = 256
|
|
objectIDLength = 20
|
|
)
|
|
|
|
// Decoder reads and decodes idx files from an input stream.
|
|
type Decoder struct {
|
|
*bufio.Reader
|
|
}
|
|
|
|
// NewDecoder builds a new idx stream decoder, that reads from r.
|
|
func NewDecoder(r io.Reader) *Decoder {
|
|
return &Decoder{bufio.NewReader(r)}
|
|
}
|
|
|
|
// Decode reads from the stream and decode the content into the MemoryIndex struct.
|
|
func (d *Decoder) Decode(idx *MemoryIndex) error {
|
|
if err := validateHeader(d); err != nil {
|
|
return err
|
|
}
|
|
|
|
flow := []func(*MemoryIndex, io.Reader) error{
|
|
readVersion,
|
|
readFanout,
|
|
readObjectNames,
|
|
readCRC32,
|
|
readOffsets,
|
|
readChecksums,
|
|
}
|
|
|
|
for _, f := range flow {
|
|
if err := f(idx, d); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateHeader(r io.Reader) error {
|
|
var h = make([]byte, 4)
|
|
if _, err := io.ReadFull(r, h); err != nil {
|
|
return err
|
|
}
|
|
|
|
if !bytes.Equal(h, idxHeader) {
|
|
return ErrMalformedIdxFile
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readVersion(idx *MemoryIndex, r io.Reader) error {
|
|
v, err := binary.ReadUint32(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if v > VersionSupported {
|
|
return ErrUnsupportedVersion
|
|
}
|
|
|
|
idx.Version = v
|
|
return nil
|
|
}
|
|
|
|
func readFanout(idx *MemoryIndex, r io.Reader) error {
|
|
for k := 0; k < fanout; k++ {
|
|
n, err := binary.ReadUint32(r)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
idx.Fanout[k] = n
|
|
idx.FanoutMapping[k] = noMapping
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readObjectNames(idx *MemoryIndex, r io.Reader) error {
|
|
for k := 0; k < fanout; k++ {
|
|
var buckets uint32
|
|
if k == 0 {
|
|
buckets = idx.Fanout[k]
|
|
} else {
|
|
buckets = idx.Fanout[k] - idx.Fanout[k-1]
|
|
}
|
|
|
|
if buckets == 0 {
|
|
continue
|
|
}
|
|
|
|
idx.FanoutMapping[k] = len(idx.Names)
|
|
|
|
nameLen := int(buckets * objectIDLength)
|
|
bin := make([]byte, nameLen)
|
|
if _, err := io.ReadFull(r, bin); err != nil {
|
|
return err
|
|
}
|
|
|
|
idx.Names = append(idx.Names, bin)
|
|
idx.Offset32 = append(idx.Offset32, make([]byte, buckets*4))
|
|
idx.CRC32 = append(idx.CRC32, make([]byte, buckets*4))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readCRC32(idx *MemoryIndex, r io.Reader) error {
|
|
for k := 0; k < fanout; k++ {
|
|
if pos := idx.FanoutMapping[k]; pos != noMapping {
|
|
if _, err := io.ReadFull(r, idx.CRC32[pos]); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readOffsets(idx *MemoryIndex, r io.Reader) error {
|
|
var o64cnt int
|
|
for k := 0; k < fanout; k++ {
|
|
if pos := idx.FanoutMapping[k]; pos != noMapping {
|
|
if _, err := io.ReadFull(r, idx.Offset32[pos]); err != nil {
|
|
return err
|
|
}
|
|
|
|
for p := 0; p < len(idx.Offset32[pos]); p += 4 {
|
|
if idx.Offset32[pos][p]&(byte(1)<<7) > 0 {
|
|
o64cnt++
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if o64cnt > 0 {
|
|
idx.Offset64 = make([]byte, o64cnt*8)
|
|
if _, err := io.ReadFull(r, idx.Offset64); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func readChecksums(idx *MemoryIndex, r io.Reader) error {
|
|
if _, err := io.ReadFull(r, idx.PackfileChecksum[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := io.ReadFull(r, idx.IdxChecksum[:]); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|