From 6e38573de2ab9ae03937762754dcde175ee2d9b6 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Fri, 24 Apr 2015 15:37:53 +0200 Subject: [PATCH 01/10] archive/tar: fix error message Write should return ErrWriteAfterClose instead of ErrWriteTooLong when called after Close. Change-Id: If5ec4ef924e4c56489e0d426976f7e5fad79be9b Reviewed-on: https://go-review.googlesource.com/9259 Reviewed-by: Brad Fitzpatrick Signed-off-by: Vincent Batts --- archive/tar/writer.go | 2 +- archive/tar/writer_test.go | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/archive/tar/writer.go b/archive/tar/writer.go index dafb2ca..9dbc01a 100644 --- a/archive/tar/writer.go +++ b/archive/tar/writer.go @@ -355,7 +355,7 @@ func paxHeader(msg string) string { // hdr.Size bytes are written after WriteHeader. func (tw *Writer) Write(b []byte) (n int, err error) { if tw.closed { - err = ErrWriteTooLong + err = ErrWriteAfterClose return } overwrite := false diff --git a/archive/tar/writer_test.go b/archive/tar/writer_test.go index 5e42e32..650899a 100644 --- a/archive/tar/writer_test.go +++ b/archive/tar/writer_test.go @@ -489,3 +489,20 @@ func TestValidTypeflagWithPAXHeader(t *testing.T) { } } } + +func TestWriteAfterClose(t *testing.T) { + var buffer bytes.Buffer + tw := NewWriter(&buffer) + + hdr := &Header{ + Name: "small.txt", + Size: 5, + } + if err := tw.WriteHeader(hdr); err != nil { + t.Fatalf("Failed to write header: %s", err) + } + tw.Close() + if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose { + t.Fatalf("Write: got %v; want ErrWriteAfterClose", err) + } +} From 576b2737620ba2ca0fb6c27552c2dfa8eadb0072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Haugen?= Date: Wed, 27 May 2015 10:44:44 +0200 Subject: [PATCH 02/10] archive/tar: don't panic on negative file size Fixes #10959. Fixes #10960. Change-Id: I9a81a0e2b8275338d0d1c3f7f7265e0fd91f3de2 Reviewed-on: https://go-review.googlesource.com/10402 TryBot-Result: Gobot Gobot Reviewed-by: David Symonds Signed-off-by: Vincent Batts --- archive/tar/reader.go | 4 ++++ archive/tar/reader_test.go | 16 ++++++++++++++++ archive/tar/testdata/neg-size.tar | Bin 0 -> 512 bytes 3 files changed, 20 insertions(+) create mode 100644 archive/tar/testdata/neg-size.tar diff --git a/archive/tar/reader.go b/archive/tar/reader.go index c72e002..0b0c3b1 100644 --- a/archive/tar/reader.go +++ b/archive/tar/reader.go @@ -553,6 +553,10 @@ func (tr *Reader) readHeader() *Header { 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] diff --git a/archive/tar/reader_test.go b/archive/tar/reader_test.go index 9601ffe..ab1e844 100644 --- a/archive/tar/reader_test.go +++ b/archive/tar/reader_test.go @@ -741,3 +741,19 @@ func TestUninitializedRead(t *testing.T) { } } + +// Negative header size should not cause panic. +// Issues 10959 and 10960. +func TestNegativeHdrSize(t *testing.T) { + f, err := os.Open("testdata/neg-size.tar") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := NewReader(f) + _, err = r.Next() + if err != ErrHeader { + t.Error("want ErrHeader, got", err) + } + io.Copy(ioutil.Discard, r) +} diff --git a/archive/tar/testdata/neg-size.tar b/archive/tar/testdata/neg-size.tar new file mode 100644 index 0000000000000000000000000000000000000000..5deea3d05c4da5a4ddda34ef7ad781088464e71b GIT binary patch literal 512 zcma)(!3}~i7=@d#07(~c0h9N)Na`Hy;GL8N4j!7YfmcUy4Hj^R-s|6LkswAdq{%Dq zeeYEkfGqY#(eVIvtUD=3dmgO>+WvmJu?!(Z2_k7dfq;C)3dnfX`l0#IeAe0qQ-^2= z|8jB*JI{8kO)-jdf^$wdJ_vEWkPIQXm^d{2NhUoLEEza^mVV&QNE^63LaKtd9rtDs zE>me;9Em{+eZ^Y>snQ&s!17bkhjcz=H=J(=e>|P(sS8Gxj+6N@Z7t^ E15rerKmY&$ literal 0 HcmV?d00001 From 55dceefe42a7ad9268aea544a8b6826f9d9a5c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5vard=20Haugen?= Date: Thu, 28 May 2015 13:48:47 +0200 Subject: [PATCH 03/10] archive/tar: terminate when reading malformed sparse files Fixes #10968. Change-Id: I027bc571a71629ac49c2a0ff101b2950af6e7531 Reviewed-on: https://go-review.googlesource.com/10482 Reviewed-by: David Symonds Run-TryBot: David Symonds TryBot-Result: Gobot Gobot Signed-off-by: Vincent Batts --- archive/tar/reader.go | 3 +++ archive/tar/reader_test.go | 19 +++++++++++++++++++ archive/tar/testdata/issue10968.tar | Bin 0 -> 512 bytes 3 files changed, 22 insertions(+) create mode 100644 archive/tar/testdata/issue10968.tar diff --git a/archive/tar/reader.go b/archive/tar/reader.go index 0b0c3b1..dbc5698 100644 --- a/archive/tar/reader.go +++ b/archive/tar/reader.go @@ -899,6 +899,9 @@ func (sfr *sparseFileReader) Read(b []byte) (n int, err error) { // Otherwise, we're at the end of the file return 0, io.EOF } + if sfr.tot < sfr.sp[0].offset { + return 0, io.ErrUnexpectedEOF + } if sfr.pos < sfr.sp[0].offset { // We're in a hole n = sfr.readHole(b, sfr.sp[0].offset) diff --git a/archive/tar/reader_test.go b/archive/tar/reader_test.go index ab1e844..6ffb383 100644 --- a/archive/tar/reader_test.go +++ b/archive/tar/reader_test.go @@ -757,3 +757,22 @@ func TestNegativeHdrSize(t *testing.T) { } io.Copy(ioutil.Discard, r) } + +// This used to hang in (*sparseFileReader).readHole due to missing +// verification of sparse offsets against file size. +func TestIssue10968(t *testing.T) { + f, err := os.Open("testdata/issue10968.tar") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := NewReader(f) + _, err = r.Next() + if err != nil { + t.Fatal(err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != io.ErrUnexpectedEOF { + t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err) + } +} diff --git a/archive/tar/testdata/issue10968.tar b/archive/tar/testdata/issue10968.tar new file mode 100644 index 0000000000000000000000000000000000000000..1cc837bcff14cd822a26e43034955c82e852ab29 GIT binary patch literal 512 zcmbVI!41MN47Ah*kg@;^fX)>lI!AWsgI^V-_Q4}k$6}2x&>iv*cG6Oc`at9n#lG|1 zIi>(iak!RTol#boyD`0c^v(cHJJuvHh-e39;{t(!nc@gWsV;O@FkUc{-h`pC817Ix zgh|QIatu;A!G^JZ7UC1V_vGb4bURuTWAy6SS-Fx(D=wcI#QP1Y#wzX?HAf0_+~lp> yN?iGbw2JFgJjd0vnp9WIo>K3V$tfee6;KE|`1A3J$tp?9B&Y7`+Gwrtzls-lP-;g2 literal 0 HcmV?d00001 From 69de764807dae1f3b43badebbb958f7fcb3d70c8 Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Fri, 12 Jun 2015 22:49:42 +0200 Subject: [PATCH 04/10] archive/tar: fix slice bounds out of range Sanity check the pax-header size field before using it. Fixes #11167. Change-Id: I9d5d0210c3990e6fb9434c3fe333be0d507d5962 Reviewed-on: https://go-review.googlesource.com/10954 Reviewed-by: David Symonds Signed-off-by: Vincent Batts --- archive/tar/reader.go | 2 +- archive/tar/reader_test.go | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/archive/tar/reader.go b/archive/tar/reader.go index dbc5698..6f219da 100644 --- a/archive/tar/reader.go +++ b/archive/tar/reader.go @@ -397,7 +397,7 @@ func parsePAX(r io.Reader) (map[string]string, error) { } // Parse the first token as a decimal integer. n, err := strconv.ParseInt(string(buf[:sp]), 10, 0) - if err != nil { + if err != nil || n < 5 || int64(len(buf)) < n { return nil, ErrHeader } // Extract everything between the decimal and the n -1 on the diff --git a/archive/tar/reader_test.go b/archive/tar/reader_test.go index 6ffb383..311db77 100644 --- a/archive/tar/reader_test.go +++ b/archive/tar/reader_test.go @@ -462,9 +462,14 @@ func TestParsePAXHeader(t *testing.T) { t.Error("Buffer wasn't consumed") } } - badHeader := bytes.NewReader([]byte("3 somelongkey=")) - if _, err := parsePAX(badHeader); err != ErrHeader { - t.Fatal("Unexpected success when parsing bad header") + badHeaderTests := [][]byte{ + []byte("3 somelongkey=\n"), + []byte("50 tooshort=\n"), + } + for _, test := range badHeaderTests { + if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader { + t.Fatal("Unexpected success when parsing bad header") + } } } From 2e5698249c892bebc0326a4307410b205783ad22 Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Sat, 13 Jun 2015 10:53:06 +0200 Subject: [PATCH 05/10] archive/tar: add missing error checks Check for errors when reading the headers following the pax headers. Fixes #11169. Change-Id: Ifec4a949ec8df8b49fa7cb7a67eb826fe2282ad8 Reviewed-on: https://go-review.googlesource.com/11031 Reviewed-by: Russ Cox Signed-off-by: Vincent Batts --- archive/tar/reader.go | 6 ++++++ archive/tar/reader_test.go | 15 +++++++++++++++ archive/tar/testdata/issue11169.tar | Bin 0 -> 602 bytes 3 files changed, 21 insertions(+) create mode 100644 archive/tar/testdata/issue11169.tar diff --git a/archive/tar/reader.go b/archive/tar/reader.go index 6f219da..4168ea2 100644 --- a/archive/tar/reader.go +++ b/archive/tar/reader.go @@ -138,7 +138,13 @@ func (tr *Reader) Next() (*Header, error) { // We actually read the whole file, // but this skips alignment padding tr.skipUnread() + if tr.err != nil { + return nil, tr.err + } hdr = tr.readHeader() + if hdr == nil { + return nil, tr.err + } mergePAX(hdr, headers) // Check for a PAX format sparse file diff --git a/archive/tar/reader_test.go b/archive/tar/reader_test.go index 311db77..da01f26 100644 --- a/archive/tar/reader_test.go +++ b/archive/tar/reader_test.go @@ -781,3 +781,18 @@ func TestIssue10968(t *testing.T) { t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err) } } + +// Do not panic if there are errors in header blocks after the pax header. +// Issue 11169 +func TestIssue11169(t *testing.T) { + f, err := os.Open("testdata/issue11169.tar") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := NewReader(f) + _, err = r.Next() + if err == nil { + t.Fatal("Unexpected success") + } +} diff --git a/archive/tar/testdata/issue11169.tar b/archive/tar/testdata/issue11169.tar new file mode 100644 index 0000000000000000000000000000000000000000..4d71fa15260609ecee0c8c751cfebf49be8763ac GIT binary patch literal 602 zcmdPX4@j)=NKH&hEh^SCG%+zV)=x}KWS}ZA00J`;69y0s1n9JZp|KHzp^>Svp`nSX svAH3G0gzz?R8~P%SKu(Lw74X(2 Date: Wed, 4 Mar 2015 12:29:16 -0500 Subject: [PATCH 06/10] archive/tar: fix round-trip attributes The issue was identified while working with round trip FileInfo of the headers of hardlinks. Also, additional test cases for hard link handling. (review carried over from http://golang.org/cl/165860043) Fixes #9027 Change-Id: I9e3a724c8de72eb1b0fbe0751a7b488894911b76 Reviewed-on: https://go-review.googlesource.com/6790 Reviewed-by: Russ Cox Signed-off-by: Vincent Batts --- archive/tar/common.go | 4 +- archive/tar/stat_unix.go | 46 ++++++++++++++++------ archive/tar/tar_test.go | 63 ++++++++++++++++++++++++------ archive/tar/testdata/hardlink.tar | Bin 0 -> 2560 bytes archive/tar/writer_test.go | 38 ++++++++++++++++++ 5 files changed, 127 insertions(+), 24 deletions(-) create mode 100644 archive/tar/testdata/hardlink.tar diff --git a/archive/tar/common.go b/archive/tar/common.go index e363aa7..855e5fc 100644 --- a/archive/tar/common.go +++ b/archive/tar/common.go @@ -139,8 +139,8 @@ func (fi headerFileInfo) Mode() (mode os.FileMode) { } switch fi.h.Typeflag { - case TypeLink, TypeSymlink: - // hard link, symbolic link + case TypeSymlink: + // symbolic link mode |= os.ModeSymlink case TypeChar: // character device node diff --git a/archive/tar/stat_unix.go b/archive/tar/stat_unix.go index cb843db..24b9311 100644 --- a/archive/tar/stat_unix.go +++ b/archive/tar/stat_unix.go @@ -16,17 +16,41 @@ func init() { } func statUnix(fi os.FileInfo, h *Header) error { - sys, ok := fi.Sys().(*syscall.Stat_t) - if !ok { - return nil + switch sys := fi.Sys().(type) { + case *syscall.Stat_t: + h.Uid = int(sys.Uid) + h.Gid = int(sys.Gid) + // TODO(bradfitz): populate username & group. os/user + // doesn't cache LookupId lookups, and lacks group + // lookup functions. + h.AccessTime = statAtime(sys) + h.ChangeTime = statCtime(sys) + // TODO(bradfitz): major/minor device numbers? + if fi.Mode().IsRegular() && sys.Nlink > 1 { + h.Typeflag = TypeLink + h.Size = 0 + // TODO(vbatts): Linkname? + } + case *Header: + // for the roundtrip logic + h.Uid = sys.Uid + h.Gid = sys.Gid + h.Uname = sys.Uname + h.Gname = sys.Gname + h.AccessTime = sys.AccessTime + h.ChangeTime = sys.ChangeTime + if sys.Xattrs != nil { + h.Xattrs = make(map[string]string) + for k, v := range sys.Xattrs { + h.Xattrs[k] = v + } + } + if sys.Typeflag == TypeLink { + // hard link + h.Typeflag = TypeLink + h.Size = 0 + h.Linkname = sys.Linkname + } } - h.Uid = int(sys.Uid) - h.Gid = int(sys.Gid) - // TODO(bradfitz): populate username & group. os/user - // doesn't cache LookupId lookups, and lacks group - // lookup functions. - h.AccessTime = statAtime(sys) - h.ChangeTime = statCtime(sys) - // TODO(bradfitz): major/minor device numbers? return nil } diff --git a/archive/tar/tar_test.go b/archive/tar/tar_test.go index ed333f3..d63c072 100644 --- a/archive/tar/tar_test.go +++ b/archive/tar/tar_test.go @@ -147,17 +147,6 @@ func TestHeaderRoundTrip(t *testing.T) { }, fm: 0644, }, - // hard link. - { - h: &Header{ - Name: "hard.txt", - Mode: 0644 | c_ISLNK, - Size: 0, - ModTime: time.Unix(1360600916, 0), - Typeflag: TypeLink, - }, - fm: 0644 | os.ModeSymlink, - }, // symbolic link. { h: &Header{ @@ -246,6 +235,33 @@ func TestHeaderRoundTrip(t *testing.T) { }, fm: 0600 | os.ModeSticky, }, + // hard link. + { + h: &Header{ + Name: "hard.txt", + Mode: 0644 | c_ISREG, + Size: 0, + Linkname: "file.txt", + ModTime: time.Unix(1360600916, 0), + Typeflag: TypeLink, + }, + fm: 0644, + }, + // More information. + { + h: &Header{ + Name: "info.txt", + Mode: 0600 | c_ISREG, + Size: 0, + Uid: 1000, + Gid: 1000, + ModTime: time.Unix(1360602540, 0), + Uname: "slartibartfast", + Gname: "users", + Typeflag: TypeReg, + }, + fm: 0600, + }, } for i, g := range golden { @@ -268,12 +284,37 @@ func TestHeaderRoundTrip(t *testing.T) { if got, want := h2.Size, g.h.Size; got != want { t.Errorf("i=%d: Size: got %v, want %v", i, got, want) } + if got, want := h2.Uid, g.h.Uid; got != want { + t.Errorf("i=%d: Uid: got %d, want %d", i, got, want) + } + if got, want := h2.Gid, g.h.Gid; got != want { + t.Errorf("i=%d: Gid: got %d, want %d", i, got, want) + } + if got, want := h2.Uname, g.h.Uname; got != want { + t.Errorf("i=%d: Uname: got %q, want %q", i, got, want) + } + if got, want := h2.Gname, g.h.Gname; got != want { + t.Errorf("i=%d: Gname: got %q, want %q", i, got, want) + } + if got, want := h2.Linkname, g.h.Linkname; got != want { + t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want) + } + if got, want := h2.Typeflag, g.h.Typeflag; got != want { + t.Logf("%#v %#v", g.h, fi.Sys()) + t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want) + } if got, want := h2.Mode, g.h.Mode; got != want { t.Errorf("i=%d: Mode: got %o, want %o", i, got, want) } if got, want := fi.Mode(), g.fm; got != want { t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want) } + if got, want := h2.AccessTime, g.h.AccessTime; got != want { + t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want) + } + if got, want := h2.ChangeTime, g.h.ChangeTime; got != want { + t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want) + } if got, want := h2.ModTime, g.h.ModTime; got != want { t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want) } diff --git a/archive/tar/testdata/hardlink.tar b/archive/tar/testdata/hardlink.tar new file mode 100644 index 0000000000000000000000000000000000000000..9cd1a26572e44150ded8a628fefb28fa089645d1 GIT binary patch literal 2560 zcmYex%t_TNsVHHfAus>}GZPaAAZ2K7Y5<}Q3?Y0F6C}!DXk=n;YGz~#VjCD58=09i zC>YStO>m=2i%SxVfKDn)N-QZUh6`gbN{dsA@JNF_1@sD>#xP)T3IyjQ7L{Zs0g1H4 z;u5aG>Bv!6(JTZq5{ps>JpTi;4Ql>3F*i14P%uoRL*X>S^FPfJ)~LawAut*OgFXZR DcLg^L literal 0 HcmV?d00001 diff --git a/archive/tar/writer_test.go b/archive/tar/writer_test.go index 650899a..fe46a67 100644 --- a/archive/tar/writer_test.go +++ b/archive/tar/writer_test.go @@ -147,6 +147,44 @@ var writerTests = []*writerTest{ }, }, }, + // This file was produced using gnu tar 1.26 + // echo "Slartibartfast" > file.txt + // ln file.txt hard.txt + // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt + { + file: "testdata/hardlink.tar", + entries: []*writerTestEntry{ + { + header: &Header{ + Name: "file.txt", + Mode: 0644, + Uid: 1000, + Gid: 100, + Size: 15, + ModTime: time.Unix(1425484303, 0), + Typeflag: '0', + Uname: "vbatts", + Gname: "users", + }, + contents: "Slartibartfast\n", + }, + { + header: &Header{ + Name: "hard.txt", + Mode: 0644, + Uid: 1000, + Gid: 100, + Size: 0, + ModTime: time.Unix(1425484303, 0), + Typeflag: '1', + Linkname: "file.txt", + Uname: "vbatts", + Gname: "users", + }, + // no contents + }, + }, + }, } // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection. From 8eee43d0df37ee91baff4b12af1821845080d0df Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 26 Jun 2015 14:31:35 -0700 Subject: [PATCH 07/10] archive/tar: disable new failing test on windows and plan9 Update #11426 Change-Id: If406d2efcc81965825a63c76f5448d544ba2a740 Reviewed-on: https://go-review.googlesource.com/11590 Reviewed-by: Austin Clements Signed-off-by: Vincent Batts --- archive/tar/tar_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/archive/tar/tar_test.go b/archive/tar/tar_test.go index d63c072..715884a 100644 --- a/archive/tar/tar_test.go +++ b/archive/tar/tar_test.go @@ -10,6 +10,7 @@ import ( "os" "path" "reflect" + "runtime" "strings" "testing" "time" @@ -135,6 +136,9 @@ type headerRoundTripTest struct { } func TestHeaderRoundTrip(t *testing.T) { + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + t.Skipf("skipping on %s; issue 11426", runtime.GOOS) + } golden := []headerRoundTripTest{ // regular file. { From 27e18409b9d3df7bfa99336f0669b649c4384581 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Fri, 26 Jun 2015 15:13:52 -0700 Subject: [PATCH 08/10] archive/tar: also skip header roundtrip test on nacl Update #11426 Change-Id: I7abc4ed2241a7a3af6d57c934786f36de4f97b77 Reviewed-on: https://go-review.googlesource.com/11592 Run-TryBot: Brad Fitzpatrick Reviewed-by: Brad Fitzpatrick Signed-off-by: Vincent Batts --- archive/tar/tar_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archive/tar/tar_test.go b/archive/tar/tar_test.go index 715884a..3fdd83d 100644 --- a/archive/tar/tar_test.go +++ b/archive/tar/tar_test.go @@ -136,7 +136,7 @@ type headerRoundTripTest struct { } func TestHeaderRoundTrip(t *testing.T) { - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" || runtime.GOOS == "nacl" { t.Skipf("skipping on %s; issue 11426", runtime.GOOS) } golden := []headerRoundTripTest{ From 3b34dbd368ec2fd76f6d552714ae954056cc58ec Mon Sep 17 00:00:00 2001 From: Alex Brainman Date: Mon, 29 Jun 2015 16:42:28 +1000 Subject: [PATCH 09/10] archive/tar: move round-trip reading into common os file Fixes #11426 Change-Id: I77368b0e852149ed4533e139cc43887508ac7f78 Reviewed-on: https://go-review.googlesource.com/11662 Reviewed-by: Austin Clements Reviewed-by: Russ Cox Signed-off-by: Vincent Batts --- archive/tar/common.go | 24 +++++++++++++++++++ archive/tar/stat_unix.go | 51 +++++++++++++--------------------------- archive/tar/tar_test.go | 4 ---- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/archive/tar/common.go b/archive/tar/common.go index 855e5fc..c31df06 100644 --- a/archive/tar/common.go +++ b/archive/tar/common.go @@ -249,6 +249,30 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { if fm&os.ModeSticky != 0 { h.Mode |= c_ISVTX } + // If possible, populate additional fields from OS-specific + // FileInfo fields. + if sys, ok := fi.Sys().(*Header); ok { + // This FileInfo came from a Header (not the OS). Use the + // original Header to populate all remaining fields. + h.Uid = sys.Uid + h.Gid = sys.Gid + h.Uname = sys.Uname + h.Gname = sys.Gname + h.AccessTime = sys.AccessTime + h.ChangeTime = sys.ChangeTime + if sys.Xattrs != nil { + h.Xattrs = make(map[string]string) + for k, v := range sys.Xattrs { + h.Xattrs[k] = v + } + } + if sys.Typeflag == TypeLink { + // hard link + h.Typeflag = TypeLink + h.Size = 0 + h.Linkname = sys.Linkname + } + } if sysStat != nil { return h, sysStat(fi, h) } diff --git a/archive/tar/stat_unix.go b/archive/tar/stat_unix.go index 24b9311..27d112f 100644 --- a/archive/tar/stat_unix.go +++ b/archive/tar/stat_unix.go @@ -16,41 +16,22 @@ func init() { } func statUnix(fi os.FileInfo, h *Header) error { - switch sys := fi.Sys().(type) { - case *syscall.Stat_t: - h.Uid = int(sys.Uid) - h.Gid = int(sys.Gid) - // TODO(bradfitz): populate username & group. os/user - // doesn't cache LookupId lookups, and lacks group - // lookup functions. - h.AccessTime = statAtime(sys) - h.ChangeTime = statCtime(sys) - // TODO(bradfitz): major/minor device numbers? - if fi.Mode().IsRegular() && sys.Nlink > 1 { - h.Typeflag = TypeLink - h.Size = 0 - // TODO(vbatts): Linkname? - } - case *Header: - // for the roundtrip logic - h.Uid = sys.Uid - h.Gid = sys.Gid - h.Uname = sys.Uname - h.Gname = sys.Gname - h.AccessTime = sys.AccessTime - h.ChangeTime = sys.ChangeTime - if sys.Xattrs != nil { - h.Xattrs = make(map[string]string) - for k, v := range sys.Xattrs { - h.Xattrs[k] = v - } - } - if sys.Typeflag == TypeLink { - // hard link - h.Typeflag = TypeLink - h.Size = 0 - h.Linkname = sys.Linkname - } + sys, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + return nil + } + h.Uid = int(sys.Uid) + h.Gid = int(sys.Gid) + // TODO(bradfitz): populate username & group. os/user + // doesn't cache LookupId lookups, and lacks group + // lookup functions. + h.AccessTime = statAtime(sys) + h.ChangeTime = statCtime(sys) + // TODO(bradfitz): major/minor device numbers? + if fi.Mode().IsRegular() && sys.Nlink > 1 { + h.Typeflag = TypeLink + h.Size = 0 + // TODO(vbatts): Linkname? } return nil } diff --git a/archive/tar/tar_test.go b/archive/tar/tar_test.go index 3fdd83d..d63c072 100644 --- a/archive/tar/tar_test.go +++ b/archive/tar/tar_test.go @@ -10,7 +10,6 @@ import ( "os" "path" "reflect" - "runtime" "strings" "testing" "time" @@ -136,9 +135,6 @@ type headerRoundTripTest struct { } func TestHeaderRoundTrip(t *testing.T) { - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" || runtime.GOOS == "nacl" { - t.Skipf("skipping on %s; issue 11426", runtime.GOOS) - } golden := []headerRoundTripTest{ // regular file. { From 4d4b53c78ba7d13a7971e493b8913295c4575f70 Mon Sep 17 00:00:00 2001 From: Vincent Batts Date: Mon, 3 Aug 2015 12:26:38 -0400 Subject: [PATCH 10/10] archive/tar: don't treat multiple file system links as a tar hardlink Do not assume that if stat shows multiple links that we should mark the file as a hardlink in the tar format. If the hardlink link was not referenced, this caused a link to "/". On an overlay file system, all files have multiple links. The caller must keep the inode references and set TypeLink, Size = 0, and LinkName themselves. Change-Id: I873b8a235bc8f8fbb271db74ee54232da36ca013 Reviewed-on: https://go-review.googlesource.com/13045 Reviewed-by: Ian Lance Taylor Signed-off-by: Vincent Batts --- archive/tar/stat_unix.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/archive/tar/stat_unix.go b/archive/tar/stat_unix.go index 27d112f..cb843db 100644 --- a/archive/tar/stat_unix.go +++ b/archive/tar/stat_unix.go @@ -28,10 +28,5 @@ func statUnix(fi os.FileInfo, h *Header) error { h.AccessTime = statAtime(sys) h.ChangeTime = statCtime(sys) // TODO(bradfitz): major/minor device numbers? - if fi.Mode().IsRegular() && sys.Nlink > 1 { - h.Typeflag = TypeLink - h.Size = 0 - // TODO(vbatts): Linkname? - } return nil }