diff --git a/internal/smartlink/smartlink.go b/internal/smartlink/smartlink.go index f32c806a6b..c101abde5e 100644 --- a/internal/smartlink/smartlink.go +++ b/internal/smartlink/smartlink.go @@ -40,6 +40,8 @@ func LinkContents(src, dest string) error { // Link creates a link from src to target. MS decided to support Symlinks but only if you opt into developer mode (go figure), // which we cannot reasonably force on our users. So on Windows we will instead create dirs and hardlinks. func Link(src, dest string) error { + originalSrc := src + var err error src, dest, err = resolvePaths(src, dest) if err != nil { @@ -47,11 +49,14 @@ func Link(src, dest string) error { } if fileutils.IsDir(src) { - if isSymlink(src) { + if fileutils.IsSymlink(originalSrc) { + // If the original src is a symlink, the resolved src is no longer a symlink and could point + // to a parent directory, resulting in a recursive directory structure. + // Avoid any potential problems by simply linking the original link to the target. // Links to directories are okay on Linux and macOS, but will fail on Windows. // If we ever get here on Windows, the artifact being deployed is bad and there's nothing we // can do about it except receive the report from Rollbar and report it internally. - return linkFile(src, dest) + return linkFile(originalSrc, dest) } if err := fileutils.Mkdir(dest); err != nil { @@ -138,20 +143,15 @@ func UnlinkContents(src, dest string) error { return nil } -func isSymlink(src string) bool { - target, err := fileutils.SymlinkTarget(src) - return err == nil && src != target -} - // resolvePaths will resolve src and dest to absolute paths and return them. // This is to ensure that we're always comparing apples to apples when doing string comparisons on paths. func resolvePaths(src, dest string) (string, string, error) { var err error - src, err = filepath.Abs(filepath.Clean(src)) + src, err = fileutils.ResolveUniquePath(src) if err != nil { return "", "", errs.Wrap(err, "Could not resolve src path") } - dest, err = filepath.Abs(filepath.Clean(dest)) + dest, err = fileutils.ResolveUniquePath(dest) if err != nil { return "", "", errs.Wrap(err, "Could not resolve dest path") }