From ab181ce55707de6f47d662dcdf6eab9c6c040906 Mon Sep 17 00:00:00 2001 From: Iavael Date: Mon, 2 Mar 2015 02:55:28 +0300 Subject: [PATCH] Fixed handling hardlinks to symlinks in tar stream Signed-off-by: Iavael --- pkg/archive/archive.go | 16 ++++++++++++++-- pkg/archive/archive_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/pkg/archive/archive.go b/pkg/archive/archive.go index bce66a505a..9e43d28cb1 100644 --- a/pkg/archive/archive.go +++ b/pkg/archive/archive.go @@ -349,7 +349,13 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L // There is no LChmod, so ignore mode for symlink. Also, this // must happen after chown, as that can modify the file mode - if hdr.Typeflag != tar.TypeSymlink { + if hdr.Typeflag == tar.TypeLink { + if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { + if err := os.Chmod(path, hdrInfo.Mode()); err != nil { + return err + } + } + } else if hdr.Typeflag != tar.TypeSymlink { if err := os.Chmod(path, hdrInfo.Mode()); err != nil { return err } @@ -357,7 +363,13 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)} // syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and - if hdr.Typeflag != tar.TypeSymlink { + if hdr.Typeflag == tar.TypeLink { + if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) { + if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform { + return err + } + } + } else if hdr.Typeflag != tar.TypeSymlink { if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform { return err } diff --git a/pkg/archive/archive_test.go b/pkg/archive/archive_test.go index 6cd95d5ad5..c127b307e2 100644 --- a/pkg/archive/archive_test.go +++ b/pkg/archive/archive_test.go @@ -435,6 +435,34 @@ func TestUntarInvalidFilenames(t *testing.T) { } } +func TestUntarHardlinkToSymlink(t *testing.T) { + for i, headers := range [][]*tar.Header{ + { + { + Name: "symlink1", + Typeflag: tar.TypeSymlink, + Linkname: "regfile", + Mode: 0644, + }, + { + Name: "symlink2", + Typeflag: tar.TypeLink, + Linkname: "symlink1", + Mode: 0644, + }, + { + Name: "regfile", + Typeflag: tar.TypeReg, + Mode: 0644, + }, + }, + } { + if err := testBreakout("untar", "docker-TestUntarHardlinkToSymlink", headers); err != nil { + t.Fatalf("i=%d. %v", i, err) + } + } +} + func TestUntarInvalidHardlink(t *testing.T) { for i, headers := range [][]*tar.Header{ { // try reading victim/hello (../)