]> Cypherpunks repositories - gostls13.git/commitdiff
path/filepath: keep walking if EvalSymlinks returns symlink
authorAlex Brainman <alex.brainman@gmail.com>
Sun, 13 Dec 2015 23:33:56 +0000 (10:33 +1100)
committerRuss Cox <rsc@golang.org>
Mon, 14 Dec 2015 17:21:16 +0000 (17:21 +0000)
Fixes #13582

Change-Id: I220f3c7b9511b3c080874f5c42f2a431fdddcbb7
Reviewed-on: https://go-review.googlesource.com/17794
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/path/filepath/path_test.go
src/path/filepath/symlink.go
src/path/filepath/symlink_windows.go

index 201f4fa86903fc10f251644d9de844438bd495e7..db604ba91fb4b0be3f5deaaf43cde5ac8742d879 100644 (file)
@@ -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{
index dc7e9eb9bf32e407c958929b69c3c983735704b1..bc287c5ecb36a239951325d4dada452d3099b513 100644 (file)
@@ -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
 }
index 58288731aac5ddd99d5fffd30f815e7fa3d12f55..eb48367ec2bc4a9ce93c9d2ea77b0e224f61c239 100644 (file)
@@ -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