mirror of
https://github.com/golang/go
synced 2024-11-02 08:01:26 +00:00
path/filepath: walkSymlinks: return correct error for file with trailing slash
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>
This commit is contained in:
parent
3b66c00857
commit
b32ee0a3c0
3 changed files with 60 additions and 4 deletions
|
@ -15,6 +15,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1371,3 +1372,39 @@ func TestWalkSymlink(t *testing.T) {
|
||||||
testenv.MustHaveSymlink(t)
|
testenv.MustHaveSymlink(t)
|
||||||
testWalkSymlink(t, os.Symlink)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,10 +8,13 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func walkSymlinks(path string) (string, error) {
|
func walkSymlinks(path string) (string, error) {
|
||||||
volLen := volumeNameLen(path)
|
volLen := volumeNameLen(path)
|
||||||
|
pathSeparator := string(os.PathSeparator)
|
||||||
|
|
||||||
if volLen < len(path) && os.IsPathSeparator(path[volLen]) {
|
if volLen < len(path) && os.IsPathSeparator(path[volLen]) {
|
||||||
volLen++
|
volLen++
|
||||||
}
|
}
|
||||||
|
@ -50,7 +53,7 @@ func walkSymlinks(path string) (string, error) {
|
||||||
}
|
}
|
||||||
if r < volLen {
|
if r < volLen {
|
||||||
if len(dest) > volLen {
|
if len(dest) > volLen {
|
||||||
dest += string(os.PathSeparator)
|
dest += pathSeparator
|
||||||
}
|
}
|
||||||
dest += ".."
|
dest += ".."
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,7 +65,7 @@ func walkSymlinks(path string) (string, error) {
|
||||||
// Ordinary path component. Add it to result.
|
// Ordinary path component. Add it to result.
|
||||||
|
|
||||||
if len(dest) > volumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) {
|
if len(dest) > volumeNameLen(dest) && !os.IsPathSeparator(dest[len(dest)-1]) {
|
||||||
dest += string(os.PathSeparator)
|
dest += pathSeparator
|
||||||
}
|
}
|
||||||
|
|
||||||
dest += path[start:end]
|
dest += path[start:end]
|
||||||
|
@ -76,7 +79,7 @@ func walkSymlinks(path string) (string, error) {
|
||||||
|
|
||||||
if fi.Mode()&os.ModeSymlink == 0 {
|
if fi.Mode()&os.ModeSymlink == 0 {
|
||||||
if !fi.Mode().IsDir() && end < len(path) {
|
if !fi.Mode().IsDir() && end < len(path) {
|
||||||
return "", os.ErrNotExist
|
return "", syscall.ENOTDIR
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,6 +159,18 @@ func evalSymlinksUsingGetFinalPathNameByHandle(path string) (string, error) {
|
||||||
return "", errors.New("GetFinalPathNameByHandle returned unexpected path=" + s)
|
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 {
|
func samefile(path1, path2 string) bool {
|
||||||
fi1, err := os.Lstat(path1)
|
fi1, err := os.Lstat(path1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -176,7 +188,11 @@ func evalSymlinks(path string) (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path)
|
newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path)
|
||||||
if err2 == nil {
|
if err2 == nil {
|
||||||
return toNorm(newpath2, normBase)
|
normPath, toNormErr := toNorm(newpath2, normBase)
|
||||||
|
if toNormErr != nil {
|
||||||
|
return "", toNormErr
|
||||||
|
}
|
||||||
|
return symlinkOrDir(normPath)
|
||||||
}
|
}
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue