func readGNUSparseMap1x0(r io.Reader) ([]sparseEntry, error) {
	buf := make([]byte, 2*blockSize)
	sparseHeader := buf[:blockSize]
	readDecimal := func() (int64, error) {
		nl := bytes.IndexByte(sparseHeader, '\n')
		if nl == -1 {
			if len(sparseHeader) >= blockSize {
				return 0, ErrHeader
			}
			oldLen := len(sparseHeader)
			newLen := oldLen + blockSize
			if cap(sparseHeader) < newLen {
				copy(buf, sparseHeader)
				sparseHeader = buf[:newLen]
			} else {
				sparseHeader = sparseHeader[:newLen]
			}
			if _, err := io.ReadFull(r, sparseHeader[oldLen:newLen]); err != nil {
				return 0, err
			}
			nl = bytes.IndexByte(sparseHeader[oldLen:newLen], '\n')
			if nl == -1 {
				return 0, ErrHeader
			}
			nl += oldLen  
		}
		n, err := strconv.ParseInt(string(sparseHeader[:nl]), 10, 0)
		if err != nil {
			return 0, ErrHeader
		}
		sparseHeader = sparseHeader[nl+1:]
		return n, nil
	}
	if _, err := io.ReadFull(r, sparseHeader); err != nil {
		return nil, err
	}
	numEntries, err := readDecimal()
	if err != nil {
		return nil, err
	}
	sp := make([]sparseEntry, 0, numEntries)
	for i := int64(0); i < numEntries; i++ {
		offset, err := readDecimal()
		if err != nil {
			return nil, err
		}
		numBytes, err := readDecimal()
		if err != nil {
			return nil, err
		}
		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
	}
	return sp, nil
}
readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format version 1.0.
The sparse map is stored just before the file data and padded out to the nearest block boundary.
package tar
import (
	"bytes"
	"encoding/gob"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strconv"
	"strings"
	"time"
)
var (
	ErrHeader = errors.New("archive/tar: invalid tar header")
)
const maxNanoSecondIntSize = 9
type Reader struct {
	r       io.Reader
	err     error
	pad     int64            
	curr    numBytesReader   
	hdrBuff [blockSize]byte  
}
func (tr *Reader) Reset(r io.Reader) {
	tr.r, tr.err, tr.pad, tr.curr = r, nil, 0, nil
}
func (tr *Reader) State() ([]byte, error) {
	buf := new(bytes.Buffer)
	encoder := gob.NewEncoder(buf)
	if err := encoder.Encode(tr.pad); err != nil {
		return nil, err
	}
	encodeCurr := tr.curr != nil
	if err := encoder.Encode(encodeCurr); err != nil {
		return nil, err
	}
	if encodeCurr {
		var label string
		switch t := tr.curr.(type) {
		case *regFileReader:
			label = "rfr"
		case *sparseFileReader:
			label = "sfr"
		default:
			return nil, fmt.Errorf("unable to encode numBytesReader of type %T", t)
		}
		if err := encoder.Encode(label); err != nil {
			return nil, err
		}
		if err := encoder.Encode(tr.curr); err != nil {
			return nil, err
		}
	}
	return buf.Bytes(), nil
}
func (tr *Reader) Restore(state []byte) error {
	tr.Reset(tr.r)
	decoder := gob.NewDecoder(bytes.NewReader(state))
	if err := decoder.Decode(&tr.pad); err != nil {
		return err
	}
	var decodeCurr bool
	if err := decoder.Decode(&decodeCurr); err != nil {
		return err
	}
	if decodeCurr {
		var label string
		if err := decoder.Decode(&label); err != nil {
			return err
		}
		switch label {
		case "rfr":
			tr.curr = new(regFileReader)
		case "sfr":
			tr.curr = new(sparseFileReader)
		default:
			return fmt.Errorf("unable to restore numBytesReader with label %q", label)
		}
		if err := decoder.Decode(tr.curr); err != nil {
			return err
		}
		tr.curr.setReader(tr.r)
	}
	return nil
}
type numBytesReader interface {
	io.Reader
	numBytes() int64
	GobEncode() ([]byte, error)
	GobDecode([]byte) error
	setReader(r io.Reader)
}
type regFileReader struct {
	r  io.Reader  
	nb int64      
}
func (rfr *regFileReader) GobEncode() ([]byte, error) {
	buf := new(bytes.Buffer)
	encoder := gob.NewEncoder(buf)
	if err := encoder.Encode(rfr.nb); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
func (rfr *regFileReader) GobDecode(b []byte) error {
	decoder := gob.NewDecoder(bytes.NewReader(b))
	if err := decoder.Decode(&rfr.nb); err != nil {
		return err
	}
	return nil
}
func (rfr *regFileReader) setReader(r io.Reader) { rfr.r = r }
type sparseFileReader struct {
	rfr *regFileReader  
	sp  []sparseEntry   
	pos int64           
	tot int64           
}
func (sfr *sparseFileReader) GobEncode() ([]byte, error) {
	buf := new(bytes.Buffer)
	encoder := gob.NewEncoder(buf)
	if err := encoder.Encode(sfr.rfr); err != nil {
		return nil, err
	}
	if err := encoder.Encode(len(sfr.sp)); err != nil {
		return nil, err
	}
	for _, entry := range sfr.sp {
		if err := encoder.Encode(entry.offset); err != nil {
			return nil, err
		}
		if err := encoder.Encode(entry.numBytes); err != nil {
			return nil, err
		}
	}
	if err := encoder.Encode(sfr.pos); err != nil {
		return nil, err
	}
	if err := encoder.Encode(sfr.tot); err != nil {
		return nil, err
	}
	return buf.Bytes(), nil
}
func (sfr *sparseFileReader) GobDecode(b []byte) error {
	decoder := gob.NewDecoder(bytes.NewReader(b))
	sfr.rfr = new(regFileReader)
	if err := decoder.Decode(sfr.rfr); err != nil {
		return err
	}
	var numEntries int
	if err := decoder.Decode(&numEntries); err != nil {
		return err
	}
	sfr.sp = make([]sparseEntry, numEntries)
	for _, entry := range sfr.sp {
		if err := decoder.Decode(&entry.offset); err != nil {
			return err
		}
		if err := decoder.Decode(&entry.numBytes); err != nil {
			return err
		}
	}
	if err := decoder.Decode(&sfr.pos); err != nil {
		return err
	}
	if err := decoder.Decode(&sfr.tot); err != nil {
		return err
	}
	return nil
}
func (sfr *sparseFileReader) setReader(r io.Reader) {
	sfr.rfr.setReader(r)
}
const (
	paxGNUSparseNumBlocks = "GNU.sparse.numblocks"
	paxGNUSparseOffset    = "GNU.sparse.offset"
	paxGNUSparseNumBytes  = "GNU.sparse.numbytes"
	paxGNUSparseMap       = "GNU.sparse.map"
	paxGNUSparseName      = "GNU.sparse.name"
	paxGNUSparseMajor     = "GNU.sparse.major"
	paxGNUSparseMinor     = "GNU.sparse.minor"
	paxGNUSparseSize      = "GNU.sparse.size"
	paxGNUSparseRealSize  = "GNU.sparse.realsize"
)
const (
	oldGNUSparseMainHeaderOffset               = 386
	oldGNUSparseMainHeaderIsExtendedOffset     = 482
	oldGNUSparseMainHeaderNumEntries           = 4
	oldGNUSparseExtendedHeaderIsExtendedOffset = 504
	oldGNUSparseExtendedHeaderNumEntries       = 21
	oldGNUSparseOffsetSize                     = 12
	oldGNUSparseNumBytesSize                   = 12
)
func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
func (tr *Reader) Next() (*Header, error) {
	var hdr *Header
	if tr.err == nil {
		tr.skipUnread()
	}
	if tr.err != nil {
		return hdr, tr.err
	}
	hdr = tr.readHeader()
	if hdr == nil {
		return hdr, tr.err
	}
	switch hdr.Typeflag {
	case TypeXHeader:
		headers, err := parsePAX(tr)
		if err != nil {
			return nil, err
		}
		tr.skipUnread()
		hdr = tr.readHeader()
		if hdr == nil {
			return hdr, tr.err
		}
		mergePAX(hdr, headers)
		sp, err := tr.checkForGNUSparsePAXHeaders(hdr, headers)
		if err != nil {
			tr.err = err
			return nil, err
		}
		if sp != nil {
			tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
		}
		return hdr, nil
	case TypeGNULongName:
		realname, err := ioutil.ReadAll(tr)
		if err != nil {
			return nil, err
		}
		hdr, err := tr.Next()
		hdr.Name = cString(realname)
		return hdr, err
	case TypeGNULongLink:
		realname, err := ioutil.ReadAll(tr)
		if err != nil {
			return nil, err
		}
		hdr, err := tr.Next()
		hdr.Linkname = cString(realname)
		return hdr, err
	}
	return hdr, tr.err
}
func (tr *Reader) checkForGNUSparsePAXHeaders(hdr *Header, headers map[string]string) ([]sparseEntry, error) {
	var sparseFormat string
	major, majorOk := headers[paxGNUSparseMajor]
	minor, minorOk := headers[paxGNUSparseMinor]
	sparseName, sparseNameOk := headers[paxGNUSparseName]
	_, sparseMapOk := headers[paxGNUSparseMap]
	sparseSize, sparseSizeOk := headers[paxGNUSparseSize]
	sparseRealSize, sparseRealSizeOk := headers[paxGNUSparseRealSize]
	if majorOk && minorOk {
		sparseFormat = major + "." + minor
	} else if sparseNameOk && sparseMapOk {
		sparseFormat = "0.1"
	} else if sparseSizeOk {
		sparseFormat = "0.0"
	} else {
		return nil, nil
	}
	if sparseFormat != "0.0" && sparseFormat != "0.1" && sparseFormat != "1.0" {
		return nil, nil
	}
	if sparseNameOk {
		hdr.Name = sparseName
	}
	if sparseSizeOk {
		realSize, err := strconv.ParseInt(sparseSize, 10, 0)
		if err != nil {
			return nil, ErrHeader
		}
		hdr.Size = realSize
	} else if sparseRealSizeOk {
		realSize, err := strconv.ParseInt(sparseRealSize, 10, 0)
		if err != nil {
			return nil, ErrHeader
		}
		hdr.Size = realSize
	}
	var sp []sparseEntry
	var err error
	switch sparseFormat {
	case "0.0", "0.1":
		sp, err = readGNUSparseMap0x1(headers)
	case "1.0":
		sp, err = readGNUSparseMap1x0(tr.curr)
	}
	return sp, err
}
func mergePAX(hdr *Header, headers map[string]string) error {
	for k, v := range headers {
		switch k {
		case paxPath:
			hdr.Name = v
		case paxLinkpath:
			hdr.Linkname = v
		case paxGname:
			hdr.Gname = v
		case paxUname:
			hdr.Uname = v
		case paxUid:
			uid, err := strconv.ParseInt(v, 10, 0)
			if err != nil {
				return err
			}
			hdr.Uid = int(uid)
		case paxGid:
			gid, err := strconv.ParseInt(v, 10, 0)
			if err != nil {
				return err
			}
			hdr.Gid = int(gid)
		case paxAtime:
			t, err := parsePAXTime(v)
			if err != nil {
				return err
			}
			hdr.AccessTime = t
		case paxMtime:
			t, err := parsePAXTime(v)
			if err != nil {
				return err
			}
			hdr.ModTime = t
		case paxCtime:
			t, err := parsePAXTime(v)
			if err != nil {
				return err
			}
			hdr.ChangeTime = t
		case paxSize:
			size, err := strconv.ParseInt(v, 10, 0)
			if err != nil {
				return err
			}
			hdr.Size = int64(size)
		default:
			if strings.HasPrefix(k, paxXattr) {
				if hdr.Xattrs == nil {
					hdr.Xattrs = make(map[string]string)
				}
				hdr.Xattrs[k[len(paxXattr):]] = v
			}
		}
	}
	return nil
}
func parsePAXTime(t string) (time.Time, error) {
	buf := []byte(t)
	pos := bytes.IndexByte(buf, '.')
	var seconds, nanoseconds int64
	var err error
	if pos == -1 {
		seconds, err = strconv.ParseInt(t, 10, 0)
		if err != nil {
			return time.Time{}, err
		}
	} else {
		seconds, err = strconv.ParseInt(string(buf[:pos]), 10, 0)
		if err != nil {
			return time.Time{}, err
		}
		nano_buf := string(buf[pos+1:])
		if len(nano_buf) < maxNanoSecondIntSize {
			nano_buf += strings.Repeat("0", maxNanoSecondIntSize-len(nano_buf))
		} else if len(nano_buf) > maxNanoSecondIntSize {
			nano_buf = nano_buf[:maxNanoSecondIntSize]
		}
		nanoseconds, err = strconv.ParseInt(string(nano_buf), 10, 0)
		if err != nil {
			return time.Time{}, err
		}
	}
	ts := time.Unix(seconds, nanoseconds)
	return ts, nil
}
func parsePAX(r io.Reader) (map[string]string, error) {
	buf, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}
	var sparseMap bytes.Buffer
	headers := make(map[string]string)
	for len(buf) > 0 {
		var sp int
		sp = bytes.IndexByte(buf, ' ')
		if sp == -1 {
			return nil, ErrHeader
		}
		n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
		if err != nil {
			return nil, ErrHeader
		}
		var record []byte
		record, buf = buf[sp+1:n-1], buf[n:]
		eq := bytes.IndexByte(record, '=')
		if eq == -1 {
			return nil, ErrHeader
		}
		key, value := record[:eq], record[eq+1:]
		keyStr := string(key)
		if keyStr == paxGNUSparseOffset || keyStr == paxGNUSparseNumBytes {
			sparseMap.Write(value)
			sparseMap.Write([]byte{','})
		} else {
			headers[keyStr] = string(value)
		}
	}
	if sparseMap.Len() != 0 {
		sparseMap.Truncate(sparseMap.Len() - 1)
		headers[paxGNUSparseMap] = sparseMap.String()
	}
	return headers, nil
}
func cString(b []byte) string {
	n := 0
	for n < len(b) && b[n] != 0 {
		n++
	}
	return string(b[0:n])
}
func (tr *Reader) octal(b []byte) int64 {
	if len(b) > 0 && b[0]&0x80 != 0 {
		var x int64
		for i, c := range b {
			if i == 0 {
				c &= 0x7f  
			}
			x = x<<8 | int64(c)
		}
		return x
	}
	b = bytes.Trim(b, " \x00")
	if len(b) == 0 {
		return 0
	}
	x, err := strconv.ParseUint(cString(b), 8, 64)
	if err != nil {
		tr.err = err
	}
	return int64(x)
}
func (tr *Reader) skipUnread() {
	nr := tr.numBytes() + tr.pad  
	tr.curr, tr.pad = nil, 0
	if sr, ok := tr.r.(io.Seeker); ok {
		if _, err := sr.Seek(nr, os.SEEK_CUR); err == nil {
			return
		}
	}
	_, tr.err = io.CopyN(ioutil.Discard, tr.r, nr)
}
func (tr *Reader) verifyChecksum(header []byte) bool {
	if tr.err != nil {
		return false
	}
	given := tr.octal(header[148:156])
	unsigned, signed := checksum(header)
	return given == unsigned || given == signed
}
func (tr *Reader) readHeader() *Header {
	header := tr.hdrBuff[:]
	copy(header, zeroBlock)
	if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
		return nil
	}
	if bytes.Equal(header, zeroBlock[0:blockSize]) {
		if _, tr.err = io.ReadFull(tr.r, header); tr.err != nil {
			return nil
		}
		if bytes.Equal(header, zeroBlock[0:blockSize]) {
			tr.err = io.EOF
		} else {
			tr.err = ErrHeader  
		}
		return nil
	}
	if !tr.verifyChecksum(header) {
		tr.err = ErrHeader
		return nil
	}
	hdr := new(Header)
	s := slicer(header)
	hdr.Name = cString(s.next(100))
	hdr.Mode = tr.octal(s.next(8))
	hdr.Uid = int(tr.octal(s.next(8)))
	hdr.Gid = int(tr.octal(s.next(8)))
	hdr.Size = tr.octal(s.next(12))
	hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
	s.next(8)  
	hdr.Typeflag = s.next(1)[0]
	hdr.Linkname = cString(s.next(100))
	magic := string(s.next(8))  
	var format string
	switch {
	case magic[:6] == "ustar\x00":  
		if string(header[508:512]) == "tar\x00" {
			format = "star"
		} else {
			format = "posix"
		}
	case magic == "ustar  \x00":  
		format = "gnu"
	}
	switch format {
	case "posix", "gnu", "star":
		hdr.Uname = cString(s.next(32))
		hdr.Gname = cString(s.next(32))
		devmajor := s.next(8)
		devminor := s.next(8)
		if hdr.Typeflag == TypeChar || hdr.Typeflag == TypeBlock {
			hdr.Devmajor = tr.octal(devmajor)
			hdr.Devminor = tr.octal(devminor)
		}
		var prefix string
		switch format {
		case "posix", "gnu":
			prefix = cString(s.next(155))
		case "star":
			prefix = cString(s.next(131))
			hdr.AccessTime = time.Unix(tr.octal(s.next(12)), 0)
			hdr.ChangeTime = time.Unix(tr.octal(s.next(12)), 0)
		}
		if len(prefix) > 0 {
			hdr.Name = prefix + "/" + hdr.Name
		}
	}
	if tr.err != nil {
		tr.err = ErrHeader
		return nil
	}
	nb := int64(hdr.Size)
	tr.pad = -nb & (blockSize - 1)  
	tr.curr = &regFileReader{r: tr.r, nb: nb}
	if hdr.Typeflag == TypeGNUSparse {
		hdr.Size = tr.octal(header[483:495])
		sp := tr.readOldGNUSparseMap(header)
		if tr.err != nil {
			return nil
		}
		tr.curr = &sparseFileReader{rfr: tr.curr.(*regFileReader), sp: sp, tot: hdr.Size}
	}
	return hdr
}
type sparseEntry struct {
	offset   int64
	numBytes int64
}
func (tr *Reader) readOldGNUSparseMap(header []byte) []sparseEntry {
	isExtended := header[oldGNUSparseMainHeaderIsExtendedOffset] != 0
	spCap := oldGNUSparseMainHeaderNumEntries
	if isExtended {
		spCap += oldGNUSparseExtendedHeaderNumEntries
	}
	sp := make([]sparseEntry, 0, spCap)
	s := slicer(header[oldGNUSparseMainHeaderOffset:])
	for i := 0; i < oldGNUSparseMainHeaderNumEntries; i++ {
		offset := tr.octal(s.next(oldGNUSparseOffsetSize))
		numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
		if tr.err != nil {
			tr.err = ErrHeader
			return nil
		}
		if offset == 0 && numBytes == 0 {
			break
		}
		sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
	}
	for isExtended {
		sparseHeader := make([]byte, blockSize)
		if _, tr.err = io.ReadFull(tr.r, sparseHeader); tr.err != nil {
			return nil
		}
		isExtended = sparseHeader[oldGNUSparseExtendedHeaderIsExtendedOffset] != 0
		s = slicer(sparseHeader)
		for i := 0; i < oldGNUSparseExtendedHeaderNumEntries; i++ {
			offset := tr.octal(s.next(oldGNUSparseOffsetSize))
			numBytes := tr.octal(s.next(oldGNUSparseNumBytesSize))
			if tr.err != nil {
				tr.err = ErrHeader
				return nil
			}
			if offset == 0 && numBytes == 0 {
				break
			}
			sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
		}
	}
	return sp
}