Browse Source

Fixed handling hardlinks to symlinks in tar stream

Signed-off-by: Iavael <iavaelooeyt@gmail.com>
Iavael 10 years ago
parent
commit
ab181ce557
2 changed files with 42 additions and 2 deletions
  1. 14 2
      pkg/archive/archive.go
  2. 28 0
      pkg/archive/archive_test.go

+ 14 - 2
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
 	// There is no LChmod, so ignore mode for symlink. Also, this
 	// must happen after chown, as that can modify the file mode
 	// 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 {
 		if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
 			return err
 			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)}
 	ts := []syscall.Timespec{timeToTimespec(hdr.AccessTime), timeToTimespec(hdr.ModTime)}
 	// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
 	// 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 {
 		if err := system.UtimesNano(path, ts); err != nil && err != system.ErrNotSupportedPlatform {
 			return err
 			return err
 		}
 		}

+ 28 - 0
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) {
 func TestUntarInvalidHardlink(t *testing.T) {
 	for i, headers := range [][]*tar.Header{
 	for i, headers := range [][]*tar.Header{
 		{ // try reading victim/hello (../)
 		{ // try reading victim/hello (../)