From: Alex Brainman Date: Sun, 13 Dec 2015 23:33:56 +0000 (+1100) Subject: path/filepath: keep walking if EvalSymlinks returns symlink X-Git-Tag: go1.6beta1~102 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=61eb7058d0bd04fe4f616ddd011e0c0cb2eaa39d;p=gostls13.git path/filepath: keep walking if EvalSymlinks returns symlink Fixes #13582 Change-Id: I220f3c7b9511b3c080874f5c42f2a431fdddcbb7 Reviewed-on: https://go-review.googlesource.com/17794 TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index 201f4fa869..db604ba91f 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -895,6 +895,75 @@ func TestEvalSymlinks(t *testing.T) { } } +func TestIssue13582(t *testing.T) { + switch runtime.GOOS { + case "android", "nacl", "plan9": + t.Skipf("skipping on %s", runtime.GOOS) + } + if !supportsSymlinks { + t.Skip("skipping because symlinks are not supported") + } + + tmpDir, err := ioutil.TempDir("", "issue13582") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpDir) + + dir := filepath.Join(tmpDir, "dir") + err = os.Mkdir(dir, 0755) + if err != nil { + t.Fatal(err) + } + linkToDir := filepath.Join(tmpDir, "link_to_dir") + err = os.Symlink(dir, linkToDir) + if err != nil { + t.Fatal(err) + } + file := filepath.Join(linkToDir, "file") + err = ioutil.WriteFile(file, nil, 0644) + if err != nil { + t.Fatal(err) + } + link1 := filepath.Join(linkToDir, "link1") + err = os.Symlink(file, link1) + if err != nil { + t.Fatal(err) + } + link2 := filepath.Join(linkToDir, "link2") + err = os.Symlink(link1, link2) + if err != nil { + t.Fatal(err) + } + + // /tmp may itself be a symlink! + realTmpDir, err := filepath.EvalSymlinks(tmpDir) + if err != nil { + t.Fatal(err) + } + realDir := filepath.Join(realTmpDir, "dir") + realFile := filepath.Join(realDir, "file") + + tests := []struct { + path, want string + }{ + {dir, realDir}, + {linkToDir, realDir}, + {file, realFile}, + {link1, realFile}, + {link2, realFile}, + } + for _, test := range tests { + have, err := filepath.EvalSymlinks(test.path) + if err != nil { + t.Fatal(err) + } + if have != test.want { + t.Errorf("EvalSymlinks(%q) returns %q, want %q", test.path, have, test.want) + } + } +} + // Test directories relative to temporary directory. // The tests are run in absTestDirs[0]. var absTestDirs = []string{ diff --git a/src/path/filepath/symlink.go b/src/path/filepath/symlink.go index dc7e9eb9bf..bc287c5ecb 100644 --- a/src/path/filepath/symlink.go +++ b/src/path/filepath/symlink.go @@ -85,7 +85,6 @@ func walkLinks(path string, linksWalked *int) (string, error) { return newpath, nil } return Join(newdir, newpath), nil - } } @@ -94,9 +93,25 @@ func walkSymlinks(path string) (string, error) { return path, nil } var linksWalked int // to protect against cycles - newpath, err := walkLinks(path, &linksWalked) - if err != nil { - return "", err + for { + i := linksWalked + newpath, err := walkLinks(path, &linksWalked) + if err != nil { + return "", err + } + if runtime.GOOS == "windows" { + // walkLinks(".", ...) always retuns "." on unix. + // But on windows it returns symlink target, if current + // directory is a symlink. Stop the walk, if symlink + // target is not absolute path, and return "." + // to the caller (just like unix does). + if path == "." && !IsAbs(newpath) { + return ".", nil + } + } + if i == linksWalked { + return Clean(newpath), nil + } + path = newpath } - return Clean(newpath), nil } diff --git a/src/path/filepath/symlink_windows.go b/src/path/filepath/symlink_windows.go index 58288731aa..eb48367ec2 100644 --- a/src/path/filepath/symlink_windows.go +++ b/src/path/filepath/symlink_windows.go @@ -47,15 +47,10 @@ func toLong(path string) (string, error) { } func evalSymlinks(path string) (string, error) { - newpath, err := walkSymlinks(path) + path, err := walkSymlinks(path) if err != nil { return "", err } - // discard the walk if path is "." and link destination is relative path (just like unix does) - if path != "." || IsAbs(newpath) { - path = newpath - } - p, err := toShort(path) if err != nil { return "", err