From 48b1e5b9bd3a7a0080f38d3aa8f96bdedafcb73a Mon Sep 17 00:00:00 2001 From: Ibrahim AshShohail Date: Wed, 21 Jun 2017 04:38:01 +0300 Subject: [PATCH] internal/fs: don't clone symlinks on windows copyFile calls copySymlink on Windows which fails if the user doesn't have the required permission. This is a very common case since symlinks are used heavily on Windows. This change renames copySymlink to cloneSymlink to clarify the intention and skips calling it when on Windows to fallback to copy the file content instead. Fixes #773 Signed-off-by: Ibrahim AshShohail --- internal/fs/fs.go | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/internal/fs/fs.go b/internal/fs/fs.go index a79032017b..93604852ce 100644 --- a/internal/fs/fs.go +++ b/internal/fs/fs.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "os" "path/filepath" + "runtime" "strings" "unicode" @@ -269,12 +270,15 @@ func CopyDir(src, dst string) error { // of the source file. The file mode will be copied from the source and // the copied data is synced/flushed to stable storage. func copyFile(src, dst string) (err error) { - if sym, err := IsSymlink(src); err != nil { - return err - } else if sym { - err := copySymlink(src, dst) + sym, err := IsSymlink(src) + if err != nil { return err } + // Skip cloning the symlink on Windows and fallback to copying the file content + // since creating a symlink on Windows requires additional permissions. + if sym && runtime.GOOS != "windows" { + return cloneSymlink(src, dst) + } in, err := os.Open(src) if err != nil { @@ -314,17 +318,17 @@ func copyFile(src, dst string) (err error) { return } -// copySymlink will resolve the src symlink and create a new symlink in dst. -// If src is a relative symlink, dst will also be a relative symlink. -func copySymlink(src, dst string) error { - resolved, err := os.Readlink(src) +// cloneSymlink will create a new symlink that points to the resolved path of sl. +// If sl is a relative symlink, dst will also be a relative symlink. +func cloneSymlink(sl, dst string) error { + resolved, err := os.Readlink(sl) if err != nil { return errors.Wrap(err, "failed to resolve symlink") } err = os.Symlink(resolved, dst) if err != nil { - return errors.Wrapf(err, "failed to create symlink %s to %s", src, resolved) + return errors.Wrapf(err, "failed to create symlink %s to %s", dst, resolved) } return nil