}
return buf.String()
}
+
+// isHeaderOnlyType checks if the given type flag is of the type that has no
+// data section even if a size is specified.
+func isHeaderOnlyType(flag byte) bool {
+ switch flag {
+ case TypeLink, TypeSymlink, TypeChar, TypeBlock, TypeDir, TypeFifo:
+ return true
+ default:
+ return false
+ }
+}
return nil, err
}
if sp != nil {
+ // Sparse files do not make sense when applied to the special header
+ // types that never have a data section.
+ if isHeaderOnlyType(hdr.Typeflag) {
+ tr.err = ErrHeader
+ return nil, tr.err
+ }
+
// Current file is a PAX format GNU sparse file.
// Set the current file reader to a sparse file reader.
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
hdr.Uid = int(tr.octal(s.next(8)))
hdr.Gid = int(tr.octal(s.next(8)))
hdr.Size = tr.octal(s.next(12))
- if hdr.Size < 0 {
- tr.err = ErrHeader
- return nil
- }
hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
s.next(8) // chksum
hdr.Typeflag = s.next(1)[0]
return nil
}
- // Maximum value of hdr.Size is 64 GB (12 octal digits),
- // so there's no risk of int64 overflowing.
- nb := int64(hdr.Size)
- tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
+ nb := hdr.Size
+ if isHeaderOnlyType(hdr.Typeflag) {
+ nb = 0
+ }
+ if nb < 0 {
+ tr.err = ErrHeader
+ return nil
+ }
// Set the current file reader.
+ tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
tr.curr = ®FileReader{r: tr.r, nb: nb}
// Check for old GNU sparse format entry.
}
}
}
+
+// TestReadHeaderOnly tests that Reader does not attempt to read special
+// header-only files.
+func TestReadHeaderOnly(t *testing.T) {
+ f, err := os.Open("testdata/hdr-only.tar")
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ defer f.Close()
+
+ var hdrs []*Header
+ tr := NewReader(f)
+ for {
+ hdr, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Errorf("Next(): got %v, want %v", err, nil)
+ continue
+ }
+ hdrs = append(hdrs, hdr)
+
+ // If a special flag, we should read nothing.
+ cnt, _ := io.ReadFull(tr, []byte{0})
+ if cnt > 0 && hdr.Typeflag != TypeReg {
+ t.Errorf("ReadFull(...): got %d bytes, want 0 bytes", cnt)
+ }
+ }
+
+ // File is crafted with 16 entries. The later 8 are identical to the first
+ // 8 except that the size is set.
+ if len(hdrs) != 16 {
+ t.Fatalf("len(hdrs): got %d, want %d", len(hdrs), 16)
+ }
+ for i := 0; i < 8; i++ {
+ var hdr1, hdr2 = hdrs[i+0], hdrs[i+8]
+ hdr1.Size, hdr2.Size = 0, 0
+ if !reflect.DeepEqual(*hdr1, *hdr2) {
+ t.Errorf("incorrect header:\ngot %+v\nwant %+v", *hdr1, *hdr2)
+ }
+ }
+}