func (d *Decoder) padEntry(idx *Index, e *Entry, read int) error {
	if idx.Version == 4 {
		return nil
	}
	entrySize := read + len(e.Name)
	padLen := 8 - entrySize%8
	_, err := io.CopyN(ioutil.Discard, d.r, int64(padLen))
	return err
}
Index entries are padded out to the next 8 byte alignment
for historical reasons related to how C Git read the files.
package index
import (
	"bytes"
	"crypto/sha1"
	"errors"
	"hash"
	"io"
	"io/ioutil"
	"strconv"
	"time"
	"gopkg.in/src-d/go-git.v4/plumbing"
	"gopkg.in/src-d/go-git.v4/utils/binary"
)
var (
	DecodeVersionSupported = struct{ Min, Max uint32 }{Min: 2, Max: 4}
	ErrMalformedSignature = errors.New("malformed index signature file")
	ErrInvalidChecksum = errors.New("invalid checksum")
	errUnknownExtension = errors.New("unknown extension")
)
const (
	entryHeaderLength = 62
	entryExtended     = 0x4000
	entryValid        = 0x8000
	nameMask          = 0xfff
	intentToAddMask   = 1 << 13
	skipWorkTreeMask  = 1 << 14
)
type Decoder struct {
	r         io.Reader
	hash      hash.Hash
	lastEntry *Entry
}
func NewDecoder(r io.Reader) *Decoder {
	h := sha1.New()
	return &Decoder{
		r:    io.TeeReader(r, h),
		hash: h,
	}
}
func (d *Decoder) Decode(idx *Index) error {
	var err error
	idx.Version, err = validateHeader(d.r)
	if err != nil {
		return err
	}
	entryCount, err := binary.ReadUint32(d.r)
	if err != nil {
		return err
	}
	if err := d.readEntries(idx, int(entryCount)); err != nil {
		return err
	}
	return d.readExtensions(idx)
}
func (d *Decoder) readEntries(idx *Index, count int) error {
	for i := 0; i < count; i++ {
		e, err := d.readEntry(idx)
		if err != nil {
			return err
		}
		d.lastEntry = e
		idx.Entries = append(idx.Entries, e)
	}
	return nil
}
func (d *Decoder) readEntry(idx *Index) (*Entry, error) {
	e := &Entry{}
	var msec, mnsec, sec, nsec uint32
	var flags uint16
	flow := []interface{}{
		&sec, &nsec,
		&msec, &mnsec,
		&e.Dev,
		&e.Inode,
		&e.Mode,
		&e.UID,
		&e.GID,
		&e.Size,
		&e.Hash,
		&flags,
	}
	if err := binary.Read(d.r, flow...); err != nil {
		return nil, err
	}
	read := entryHeaderLength
	if sec != 0 || nsec != 0 {
		e.CreatedAt = time.Unix(int64(sec), int64(nsec))
	}
	if msec != 0 || mnsec != 0 {
		e.ModifiedAt = time.Unix(int64(msec), int64(mnsec))
	}
	e.Stage = Stage(flags>>12) & 0x3
	if flags&entryExtended != 0 {
		extended, err := binary.ReadUint16(d.r)
		if err != nil {
			return nil, err
		}
		read += 2
		e.IntentToAdd = extended&intentToAddMask != 0
		e.SkipWorktree = extended&skipWorkTreeMask != 0
	}
	if err := d.readEntryName(idx, e, flags); err != nil {
		return nil, err
	}
	return e, d.padEntry(idx, e, read)
}
func (d *Decoder) readEntryName(idx *Index, e *Entry, flags uint16) error {
	var name string
	var err error
	switch idx.Version {
	case 2, 3:
		len := flags & nameMask
		name, err = d.doReadEntryName(len)
	case 4:
		name, err = d.doReadEntryNameV4()
	default:
		return ErrUnsupportedVersion
	}
	if err != nil {
		return err
	}
	e.Name = name
	return nil
}
func (d *Decoder) doReadEntryNameV4() (string, error) {
	l, err := binary.ReadVariableWidthInt(d.r)
	if err != nil {
		return "", err
	}
	var base string
	if d.lastEntry != nil {
		base = d.lastEntry.Name[:len(d.lastEntry.Name)-int(l)]
	}
	name, err := binary.ReadUntil(d.r, '\x00')
	if err != nil {
		return "", err
	}
	return base + string(name), nil
}
func (d *Decoder) doReadEntryName(len uint16) (string, error) {
	name := make([]byte, len)
	if err := binary.Read(d.r, &name); err != nil {
		return "", err
	}
	return string(name), nil
}