]> Cypherpunks repositories - gostls13.git/commitdiff
path/filepath: walkSymlinks: return correct error for file with trailing slash
authorLE Manh Cuong <cuong.manhle.vn@gmail.com>
Fri, 21 Dec 2018 04:21:02 +0000 (11:21 +0700)
committerIan Lance Taylor <iant@golang.org>
Mon, 24 Dec 2018 18:38:18 +0000 (18:38 +0000)
Rather than return os.ErrNotExist for /path/to/existing_file/,
walkSymLinks now returns syscall.ENOTDIR.

This is consistent with behavior of os.Lstat.

Fixes #29372

Change-Id: Id5c471d901db04b2f35d60f60a81b2a0be93cae9
Reviewed-on: https://go-review.googlesource.com/c/155597
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/path/filepath/path_test.go
src/path/filepath/symlink.go
src/path/filepath/symlink_windows.go

index 3434ea2e6e77ca7909d848b94fbad68def18f2ff..1b9f286c4d87ad5f1058795700dc0946d54c1970 100644 (file)
@@ -15,6 +15,7 @@ import (
        "runtime"
        "sort"
        "strings"
+       "syscall"
        "testing"
 )
 
@@ -1371,3 +1372,39 @@ func TestWalkSymlink(t *testing.T) {
        testenv.MustHaveSymlink(t)
        testWalkSymlink(t, os.Symlink)
 }
+
+func TestIssue29372(t *testing.T) {
+       f, err := ioutil.TempFile("", "issue29372")
+       if err != nil {
+               t.Fatal(err)
+       }
+       f.Close()
+       path := f.Name()
+       defer os.Remove(path)
+
+       isWin := runtime.GOOS == "windows"
+       pathSeparator := string(filepath.Separator)
+       tests := []struct {
+               path string
+               skip bool
+       }{
+               {path + strings.Repeat(pathSeparator, 1), false},
+               {path + strings.Repeat(pathSeparator, 2), false},
+               {path + strings.Repeat(pathSeparator, 1) + ".", false},
+               {path + strings.Repeat(pathSeparator, 2) + ".", false},
+               // windows.GetFinalPathNameByHandle return the directory part with trailing dot dot
+               // C:\path\to\existing_dir\existing_file\.. returns C:\path\to\existing_dir
+               {path + strings.Repeat(pathSeparator, 1) + "..", isWin},
+               {path + strings.Repeat(pathSeparator, 2) + "..", isWin},
+       }
+
+       for i, test := range tests {
+               if test.skip {
+                       continue
+               }
+               _, err = filepath.EvalSymlinks(test.path)
+               if err != syscall.ENOTDIR {
+                       t.Fatalf("test#%d: want %q, got %q", i, syscall.ENOTDIR, err)
+               }
+       }
+}
index 98a92357bedb2b5d306128d9695b0eda5457c6b3..a08b85a29cdb3c9dc7aea6d95e5088f2f26fb3bb 100644 (file)
@@ -8,10 +8,13 @@ import (
        "errors"
        "os"
        "runtime"
+       "syscall"
 )
 
 func walkSymlinks(path string) (string, error) {
        volLen := volumeNameLen(path)
+       pathSeparator := string(os.PathSeparator)
+
        if volLen < len(path) && os.IsPathSeparator(path[volLen]) {
                volLen++
        }
@@ -50,7 +53,7 @@ func walkSymlinks(path string) (string, error) {
                        }
                        if r < volLen {
                                if len(dest) > volLen {
-                                       dest += string(os.PathSeparator)
+                                       dest += pathSeparator
                                }
                                dest += ".."
                        } else {
@@ -62,7 +65,7 @@ func walkSymlinks(path string) (string, error) {
                // Ordinary path component. Add it to result.
 
                if len(dest) > volumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) {
-                       dest += string(os.PathSeparator)
+                       dest += pathSeparator
                }
 
                dest += path[start:end]
@@ -76,7 +79,7 @@ func walkSymlinks(path string) (string, error) {
 
                if fi.Mode()&os.ModeSymlink == 0 {
                        if !fi.Mode().IsDir() && end < len(path) {
-                               return "", os.ErrNotExist
+                               return "", syscall.ENOTDIR
                        }
                        continue
                }
index 7095a6b4bd575d2688b4559859dbb5b3cdc0ae0e..1108b3ddff0bd70ddbbc3f95a8676797c03cf64a 100644 (file)
@@ -159,6 +159,18 @@ func evalSymlinksUsingGetFinalPathNameByHandle(path string) (string, error) {
        return "", errors.New("GetFinalPathNameByHandle returned unexpected path=" + s)
 }
 
+func symlinkOrDir(path string) (string, error) {
+       fi, err := os.Lstat(path)
+       if err != nil {
+               return "", err
+       }
+
+       if fi.Mode()&os.ModeSymlink == 0 && !fi.Mode().IsDir() {
+               return "", syscall.ENOTDIR
+       }
+       return path, nil
+}
+
 func samefile(path1, path2 string) bool {
        fi1, err := os.Lstat(path1)
        if err != nil {
@@ -176,7 +188,11 @@ func evalSymlinks(path string) (string, error) {
        if err != nil {
                newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path)
                if err2 == nil {
-                       return toNorm(newpath2, normBase)
+                       normPath, toNormErr := toNorm(newpath2, normBase)
+                       if toNormErr != nil {
+                               return "", toNormErr
+                       }
+                       return symlinkOrDir(normPath)
                }
                return "", err
        }