func (idx *PackIndexV2) Decode(reader io.Reader) error { hash := sha1.New() r := io.TeeReader(reader, hash) header := &(idx.packIndexV2Header) if err := binary.Read(r, binary.BigEndian, header); err != nil { return err } if header.Magic != packIndexV2HeaderMagic { return errors.New("invalid pack index header") } if header.Version != 2 { return Errorf("unexpected pack index header version %d", header.Version) } entryCount := int(header.Fanout[255]) idx.objectNames = make([]core.Sha1, entryCount) if err := binary.Read(r, binary.BigEndian, idx.objectNames); err != nil { return err } idx.crc32Checksums = make([]core.Crc32, entryCount) if err := binary.Read(r, binary.BigEndian, idx.crc32Checksums); err != nil { return err } idx.offsets = make([]uint32, entryCount) if err := binary.Read(r, binary.BigEndian, idx.offsets); err != nil { return err } higherOffsetCount := 0 for _, offset := range idx.offsets { if (offset >> 31) == 1 { higherOffsetCount += 1 } } idx.higherOffsets = make([]uint64, higherOffsetCount) if err := binary.Read(r, binary.BigEndian, idx.higherOffsets); err != nil { return err } if err := binary.Read(r, binary.BigEndian, &idx.packfileSha1); err != nil { return err } if err := binary.Read(reader, binary.BigEndian, &idx.packIndexSha1); err != nil { return err } actualSha1 := core.Sha1FromByteSlice(hash.Sum(nil)) if idx.packIndexSha1 != actualSha1 { return Errorf("pack index SHA-1 is %s, expected %s", actualSha1, idx.packIndexSha1) } return nil }
// Decode takes a reader and treats the stream it yields as an index file and // parses it. An error is returned if the stream forms an invalid index file. // Otherwise nil is returned. // // If ReaderLen is left as a zero value, then the integrity of the index file // being decoded will not be verified against the SHA-1 hash located in the // index file itself. Conversely, if ReaderLen is given a non-zero value, an // index file may be decoded successfully and still return an error from Decode // due to failing the integrity verification. // // See // https://www.kernel.org/pub/software/scm/git/docs/technical/index-format.txt // for more information on the file format. func (idx *Index) Decode(reader io.Reader) error { var shaWriter hash.Hash if idx.ReaderLen != 0 { shaWriter = sha1.New() limitWriter := util.SilentLimitWriter(shaWriter, idx.ReaderLen-sha1.Size) reader = io.TeeReader(reader, limitWriter) } r := bufio.NewReader(reader) header, err := decodeIndexHeader(idx, r) if err != nil { return err } if err = decodeIndexEntries(idx, r, header.EntriesCount); err != nil { return err } if err = decodeIndexExtensionsAndSha1(idx, r); err != nil { return err } if idx.ReaderLen != 0 && shaWriter != nil { actualSha1 := core.Sha1FromByteSlice(shaWriter.Sum(nil)) if actualSha1 != idx.sha1 { return Errorf("index SHA-1 was %s, expected %s", actualSha1, idx.sha1) } } return nil }
func (idx *PackIndexV1) Decode(reader io.Reader) error { hash := sha1.New() r := io.TeeReader(reader, hash) header := &(idx.packIndexV1Header) if err := binary.Read(r, binary.BigEndian, header); err != nil { return err } entryCount := int(header.Fanout[255]) idx.entries = make([]packIndexV1Entry, entryCount) if err := binary.Read(r, binary.BigEndian, idx.entries); err != nil { return err } if err := binary.Read(r, binary.BigEndian, &idx.packfileSha1); err != nil { return err } if err := binary.Read(reader, binary.BigEndian, &idx.packIndexSha1); err != nil { return err } actualSha1 := core.Sha1FromByteSlice(hash.Sum(nil)) if idx.packIndexSha1 != actualSha1 { return Errorf("pack index SHA-1 is %s, expected %s", actualSha1, idx.packIndexSha1) } return nil }
func tryReadSha1(r *bufio.Reader) (sha1 core.Sha1, err error) { sha1Size := 20 if tentativeSha1, _ := r.Peek(sha1Size + 1); len(tentativeSha1) == sha1Size { return core.Sha1FromByteSlice(tentativeSha1), nil } else { return core.Sha1{}, errSha1NotYetReached } }