var sp []sparseEntry
        var err error
        if hdr.Typeflag == TypeGNUSparse {
-               var p parser
-               hdr.Size = p.parseNumeric(rawHdr.GNU().RealSize())
-               if p.err != nil {
-                       return p.err
-               }
-
-               sp, err = tr.readOldGNUSparseMap(rawHdr)
+               sp, err = tr.readOldGNUSparseMap(hdr, rawHdr)
                if err != nil {
                        return err
                }
        return hdr, &tr.blk, p.err
 }
 
-// readOldGNUSparseMap reads the sparse map as stored in the old GNU sparse format.
-// The sparse map is stored in the tar header if it's small enough. If it's larger than four entries,
-// then one or more extension headers are used to store the rest of the sparse map.
-func (tr *Reader) readOldGNUSparseMap(blk *block) ([]sparseEntry, error) {
+// readOldGNUSparseMap reads the sparse map from the old GNU sparse format.
+// The sparse map is stored in the tar header if it's small enough.
+// If it's larger than four entries, then one or more extension headers are used
+// to store the rest of the sparse map.
+//
+// The Header.Size does not reflect the size of any extended headers used.
+// Thus, this function will read from the raw io.Reader to fetch extra headers.
+// This method mutates blk in the process.
+func (tr *Reader) readOldGNUSparseMap(hdr *Header, blk *block) ([]sparseEntry, error) {
+       // Make sure that the input format is GNU.
+       // Unfortunately, the STAR format also has a sparse header format that uses
+       // the same type flag but has a completely different layout.
+       if blk.GetFormat() != formatGNU {
+               return nil, ErrHeader
+       }
+
        var p parser
+       hdr.Size = p.parseNumeric(blk.GNU().RealSize())
+       if p.err != nil {
+               return nil, p.err
+       }
        var s sparseArray = blk.GNU().Sparse()
        var sp = make([]sparseEntry, 0, s.MaxEntries())
-       for i := 0; i < s.MaxEntries(); i++ {
-               offset := p.parseOctal(s.Entry(i).Offset())
-               numBytes := p.parseOctal(s.Entry(i).NumBytes())
-               if p.err != nil {
-                       return nil, p.err
-               }
-               if offset == 0 && numBytes == 0 {
-                       break
-               }
-               sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
-       }
-
-       for s.IsExtended()[0] > 0 {
-               // There are more entries. Read an extension header and parse its entries.
-               var blk block
-               if _, err := io.ReadFull(tr.r, blk[:]); err != nil {
-                       return nil, err
-               }
-               s = blk.Sparse()
-
+       for {
                for i := 0; i < s.MaxEntries(); i++ {
-                       offset := p.parseOctal(s.Entry(i).Offset())
-                       numBytes := p.parseOctal(s.Entry(i).NumBytes())
+                       // This termination condition is identical to GNU and BSD tar.
+                       if s.Entry(i).Offset()[0] == 0x00 {
+                               break // Don't return, need to process extended headers (even if empty)
+                       }
+                       offset := p.parseNumeric(s.Entry(i).Offset())
+                       numBytes := p.parseNumeric(s.Entry(i).NumBytes())
                        if p.err != nil {
                                return nil, p.err
                        }
-                       if offset == 0 && numBytes == 0 {
-                               break
-                       }
                        sp = append(sp, sparseEntry{offset: offset, numBytes: numBytes})
                }
+
+               if s.IsExtended()[0] > 0 {
+                       // There are more entries. Read an extension header and parse its entries.
+                       if _, err := io.ReadFull(tr.r, blk[:]); err != nil {
+                               if err == io.EOF {
+                                       err = io.ErrUnexpectedEOF
+                               }
+                               return nil, err
+                       }
+                       s = blk.Sparse()
+                       continue
+               }
+               return sp, nil // Done
        }
-       return sp, nil
 }
 
 // readGNUSparseMap1x0 reads the sparse map as stored in GNU's PAX sparse format
 
        }
 }
 
+func TestReadOldGNUSparseMap(t *testing.T) {
+       const (
+               t00 = "00000000000\x0000000000000\x00"
+               t11 = "00000000001\x0000000000001\x00"
+               t12 = "00000000001\x0000000000002\x00"
+               t21 = "00000000002\x0000000000001\x00"
+       )
+
+       mkBlk := func(size, sp0, sp1, sp2, sp3, ext string, format int) *block {
+               var blk block
+               copy(blk.GNU().RealSize(), size)
+               copy(blk.GNU().Sparse().Entry(0), sp0)
+               copy(blk.GNU().Sparse().Entry(1), sp1)
+               copy(blk.GNU().Sparse().Entry(2), sp2)
+               copy(blk.GNU().Sparse().Entry(3), sp3)
+               copy(blk.GNU().Sparse().IsExtended(), ext)
+               if format != formatUnknown {
+                       blk.SetFormat(format)
+               }
+               return &blk
+       }
+
+       vectors := []struct {
+               data   string        // Input data
+               rawHdr *block        // Input raw header
+               want   []sparseEntry // Expected sparse entries to be outputted
+               err    error         // Expected error to be returned
+       }{
+               {"", mkBlk("", "", "", "", "", "", formatUnknown), nil, ErrHeader},
+               {"", mkBlk("1234", "fewa", "", "", "", "", formatGNU), nil, ErrHeader},
+               {"", mkBlk("0031", "", "", "", "", "", formatGNU), nil, nil},
+               {"", mkBlk("1234", t00, t11, "", "", "", formatGNU),
+                       []sparseEntry{{0, 0}, {1, 1}}, nil},
+               {"", mkBlk("1234", t11, t12, t21, t11, "", formatGNU),
+                       []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}}, nil},
+               {"", mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+                       []sparseEntry{}, io.ErrUnexpectedEOF},
+               {t11 + t11,
+                       mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+                       []sparseEntry{}, io.ErrUnexpectedEOF},
+               {t11 + t21 + strings.Repeat("\x00", 512),
+                       mkBlk("1234", t11, t12, t21, t11, "\x80", formatGNU),
+                       []sparseEntry{{1, 1}, {1, 2}, {2, 1}, {1, 1}, {1, 1}, {2, 1}}, nil},
+       }
+
+       for i, v := range vectors {
+               tr := Reader{r: strings.NewReader(v.data)}
+               hdr := new(Header)
+               got, err := tr.readOldGNUSparseMap(hdr, v.rawHdr)
+               if !reflect.DeepEqual(got, v.want) && !(len(got) == 0 && len(v.want) == 0) {
+                       t.Errorf("test %d, readOldGNUSparseMap(...): got %v, want %v", i, got, v.want)
+               }
+               if err != v.err {
+                       t.Errorf("test %d, unexpected error: got %v, want %v", i, err, v.err)
+               }
+       }
+}
+
 func TestReadGNUSparseMap0x1(t *testing.T) {
        const (
                maxUint = ^uint(0)
                {pax + trash[:1], 0, io.ErrUnexpectedEOF},
                {pax + trash[:511], 0, io.ErrUnexpectedEOF},
                {sparse[:511], 0, io.ErrUnexpectedEOF},
-               // TODO(dsnet): This should pass, but currently fails.
-               // {sparse[:512], 0, io.ErrUnexpectedEOF},
+               {sparse[:512], 0, io.ErrUnexpectedEOF},
                {sparse[:3584], 1, io.EOF},
                {sparse[:9200], 1, io.EOF}, // Terminate in padding of sparse header
                {sparse[:9216], 1, io.EOF},