mirror of
https://github.com/vbatts/tar-split.git
synced 2024-12-19 03:46:30 +00:00
archive/tar: make output deterministic
Replaces PID in PaxHeaders with 0. Sorts PAX header keys before writing them to the archive. Fixes #12358 Change-Id: If239f89c85f1c9d9895a253fb06a47ad44960124 Reviewed-on: https://go-review.googlesource.com/13975 Reviewed-by: Russ Cox <rsc@golang.org> Reviewed-by: Joe Tsai <joetsai@digital-static.net>
This commit is contained in:
parent
bffda594f7
commit
2424f4e367
5 changed files with 70 additions and 8 deletions
|
@ -327,3 +327,14 @@ func toASCII(s string) string {
|
||||||
}
|
}
|
||||||
return buf.String()
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -179,6 +179,13 @@ func (tr *Reader) Next() (*Header, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if sp != nil {
|
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.
|
// Current file is a PAX format GNU sparse file.
|
||||||
// Set the current file reader to a sparse file reader.
|
// Set the current file reader to a sparse file reader.
|
||||||
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
|
tr.curr, tr.err = newSparseFileReader(tr.curr, sp, hdr.Size)
|
||||||
|
@ -622,10 +629,6 @@ func (tr *Reader) readHeader() *Header {
|
||||||
hdr.Uid = int(tr.octal(s.next(8)))
|
hdr.Uid = int(tr.octal(s.next(8)))
|
||||||
hdr.Gid = int(tr.octal(s.next(8)))
|
hdr.Gid = int(tr.octal(s.next(8)))
|
||||||
hdr.Size = tr.octal(s.next(12))
|
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)
|
hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||||
s.next(8) // chksum
|
s.next(8) // chksum
|
||||||
hdr.Typeflag = s.next(1)[0]
|
hdr.Typeflag = s.next(1)[0]
|
||||||
|
@ -676,12 +679,17 @@ func (tr *Reader) readHeader() *Header {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maximum value of hdr.Size is 64 GB (12 octal digits),
|
nb := hdr.Size
|
||||||
// so there's no risk of int64 overflowing.
|
if isHeaderOnlyType(hdr.Typeflag) {
|
||||||
nb := int64(hdr.Size)
|
nb = 0
|
||||||
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
|
}
|
||||||
|
if nb < 0 {
|
||||||
|
tr.err = ErrHeader
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Set the current file reader.
|
// Set the current file reader.
|
||||||
|
tr.pad = -nb & (blockSize - 1) // blockSize is a power of two
|
||||||
tr.curr = ®FileReader{r: tr.r, nb: nb}
|
tr.curr = ®FileReader{r: tr.r, nb: nb}
|
||||||
|
|
||||||
// Check for old GNU sparse format entry.
|
// Check for old GNU sparse format entry.
|
||||||
|
|
|
@ -893,3 +893,46 @@ func TestReadTruncation(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
BIN
archive/tar/testdata/hdr-only.tar
vendored
Normal file
BIN
archive/tar/testdata/hdr-only.tar
vendored
Normal file
Binary file not shown.
BIN
archive/tar/testdata/neg-size.tar
vendored
BIN
archive/tar/testdata/neg-size.tar
vendored
Binary file not shown.
Loading…
Reference in a new issue