From e509da9c7dc114beab5c98b2c040a33051472b6b Mon Sep 17 00:00:00 2001 From: Nick Santos Date: Mon, 8 May 2017 12:57:45 -0400 Subject: [PATCH] fs: Change CopyDir's utimes call to not follow symlinks Following symlinks does not look like it was intended behavior here, and fails if the symlink target has not been copied yet. Signed-off-by: Nick Santos --- fs/copy_linux.go | 4 +++- fs/copy_test.go | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/copy_linux.go b/fs/copy_linux.go index 40e401797..efa924861 100644 --- a/fs/copy_linux.go +++ b/fs/copy_linux.go @@ -7,6 +7,7 @@ import ( "github.com/containerd/continuity/sysx" "github.com/pkg/errors" + "golang.org/x/sys/unix" ) func copyFileInfo(fi os.FileInfo, name string) error { @@ -21,7 +22,8 @@ func copyFileInfo(fi os.FileInfo, name string) error { } } - if err := syscall.UtimesNano(name, []syscall.Timespec{st.Atim, st.Mtim}); err != nil { + timespec := []unix.Timespec{unix.Timespec(st.Atim), unix.Timespec(st.Mtim)} + if err := unix.UtimesNanoAt(unix.AT_FDCWD, name, timespec, unix.AT_SYMLINK_NOFOLLOW); err != nil { return errors.Wrapf(err, "failed to utime %s", name) } diff --git a/fs/copy_test.go b/fs/copy_test.go index 475e76fdf..2a51bf60e 100644 --- a/fs/copy_test.go +++ b/fs/copy_test.go @@ -32,6 +32,20 @@ func TestCopyDirectory(t *testing.T) { } } +// This test used to fail because link-no-nothing.txt would be copied first, +// then file operations in dst during the CopyDir would follow the symlink and +// fail. +func TestCopyDirectoryWithLocalSymlink(t *testing.T) { + apply := fstest.Apply( + fstest.CreateFile("nothing.txt", []byte{0x00, 0x00}, 0755), + fstest.Symlink("nothing.txt", "link-no-nothing.txt"), + ) + + if err := testCopy(apply); err != nil { + t.Fatalf("Copy test failed: %+v", err) + } +} + func testCopy(apply fstest.Applier) error { t1, err := ioutil.TempDir("", "test-copy-src-") if err != nil {