Skip to content

Commit 44d3bb9

Browse files
committed
path/filepath: do not call GetFinalPathNameByHandle from EvalSymlinks
EvalSymlinks is using GetFinalPathNameByHandle to handle symlinks with unusual targets like \??\Volume{ABCD}\. But since CL 164201, os.Readlink handles path like that too. So remove all that extra code that EvalSymlinks calls when os.Readlink fails - it is not needed any more. Now that windows EvalSymlinks implementation is similar to unix implementation, we can remove all slashAfterFilePathError related code too. So do that. This also makes TestIssue29372 pass even when TMP directory refers to symlinks with target like \??\Volume{ABCD}\. So remove TestIssue29372 code that helped it pass on windows-arm. TestIssue29372 should pass as is now. Fixes #29746 Change-Id: I568d142c89d3297bff8513069bceaa6be51fe7e4 Reviewed-on: https://go-review.googlesource.com/c/164202 Run-TryBot: Alex Brainman <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 2edd559 commit 44d3bb9

File tree

5 files changed

+9
-118
lines changed

5 files changed

+9
-118
lines changed

src/path/filepath/path_test.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,16 +1377,6 @@ func TestIssue29372(t *testing.T) {
13771377
}
13781378
defer os.RemoveAll(tmpDir)
13791379

1380-
if runtime.GOOS == "windows" {
1381-
// This test is broken on windows, if temporary directory
1382-
// is a symlink. See issue 29746.
1383-
// TODO(brainman): Remove this hack once issue #29746 is fixed.
1384-
tmpDir, err = filepath.EvalSymlinks(tmpDir)
1385-
if err != nil {
1386-
t.Fatal(err)
1387-
}
1388-
}
1389-
13901380
path := filepath.Join(tmpDir, "file.txt")
13911381
err = ioutil.WriteFile(path, nil, 0644)
13921382
if err != nil {

src/path/filepath/path_windows_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,12 @@ func TestNTNamespaceSymlink(t *testing.T) {
529529
}
530530
defer os.RemoveAll(tmpdir)
531531

532+
// Make sure tmpdir is not a symlink, otherwise tests will fail.
533+
tmpdir, err = filepath.EvalSymlinks(tmpdir)
534+
if err != nil {
535+
t.Fatal(err)
536+
}
537+
532538
vol := filepath.VolumeName(tmpdir)
533539
output, err = exec.Command("cmd", "/c", "mountvol", vol, "/L").CombinedOutput()
534540
if err != nil {

src/path/filepath/symlink.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"errors"
99
"os"
1010
"runtime"
11+
"syscall"
1112
)
1213

1314
func walkSymlinks(path string) (string, error) {
@@ -78,7 +79,7 @@ func walkSymlinks(path string) (string, error) {
7879

7980
if fi.Mode()&os.ModeSymlink == 0 {
8081
if !fi.Mode().IsDir() && end < len(path) {
81-
return "", slashAfterFilePathError
82+
return "", syscall.ENOTDIR
8283
}
8384
continue
8485
}

src/path/filepath/symlink_unix.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,6 @@
22

33
package filepath
44

5-
import (
6-
"syscall"
7-
)
8-
9-
// walkSymlinks returns slashAfterFilePathError error for paths like
10-
// //path/to/existing_file/ and /path/to/existing_file/. and /path/to/existing_file/..
11-
12-
var slashAfterFilePathError = syscall.ENOTDIR
13-
145
func evalSymlinks(path string) (string, error) {
156
return walkSymlinks(path)
167
}

src/path/filepath/symlink_windows.go

Lines changed: 1 addition & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@
55
package filepath
66

77
import (
8-
"errors"
9-
"internal/syscall/windows"
10-
"os"
118
"strings"
129
"syscall"
1310
)
@@ -109,108 +106,14 @@ func toNorm(path string, normBase func(string) (string, error)) (string, error)
109106
return volume + normPath, nil
110107
}
111108

112-
// evalSymlinksUsingGetFinalPathNameByHandle uses Windows
113-
// GetFinalPathNameByHandle API to retrieve the final
114-
// path for the specified file.
115-
func evalSymlinksUsingGetFinalPathNameByHandle(path string) (string, error) {
116-
err := windows.LoadGetFinalPathNameByHandle()
117-
if err != nil {
118-
// we must be using old version of Windows
119-
return "", err
120-
}
121-
122-
if path == "" {
123-
return path, nil
124-
}
125-
126-
// Use Windows I/O manager to dereference the symbolic link, as per
127-
// https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
128-
p, err := syscall.UTF16PtrFromString(path)
129-
if err != nil {
130-
return "", err
131-
}
132-
h, err := syscall.CreateFile(p, 0, 0, nil,
133-
syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
134-
if err != nil {
135-
return "", err
136-
}
137-
defer syscall.CloseHandle(h)
138-
139-
buf := make([]uint16, 100)
140-
for {
141-
n, err := windows.GetFinalPathNameByHandle(h, &buf[0], uint32(len(buf)), windows.VOLUME_NAME_DOS)
142-
if err != nil {
143-
return "", err
144-
}
145-
if n < uint32(len(buf)) {
146-
break
147-
}
148-
buf = make([]uint16, n)
149-
}
150-
s := syscall.UTF16ToString(buf)
151-
if len(s) > 4 && s[:4] == `\\?\` {
152-
s = s[4:]
153-
if len(s) > 3 && s[:3] == `UNC` {
154-
// return path like \\server\share\...
155-
return `\` + s[3:], nil
156-
}
157-
return s, nil
158-
}
159-
return "", errors.New("GetFinalPathNameByHandle returned unexpected path=" + s)
160-
}
161-
162-
func samefile(path1, path2 string) bool {
163-
fi1, err := os.Lstat(path1)
164-
if err != nil {
165-
return false
166-
}
167-
fi2, err := os.Lstat(path2)
168-
if err != nil {
169-
return false
170-
}
171-
return os.SameFile(fi1, fi2)
172-
}
173-
174-
// walkSymlinks returns slashAfterFilePathError error for paths like
175-
// //path/to/existing_file/ and /path/to/existing_file/. and /path/to/existing_file/..
176-
177-
var slashAfterFilePathError = errors.New("attempting to walk past file path.")
178-
179109
func evalSymlinks(path string) (string, error) {
180110
newpath, err := walkSymlinks(path)
181-
if err == slashAfterFilePathError {
182-
return "", syscall.ENOTDIR
183-
}
184111
if err != nil {
185-
newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path)
186-
if err2 == nil {
187-
return toNorm(newpath2, normBase)
188-
}
189112
return "", err
190113
}
191114
newpath, err = toNorm(newpath, normBase)
192115
if err != nil {
193-
newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path)
194-
if err2 == nil {
195-
return toNorm(newpath2, normBase)
196-
}
197116
return "", err
198117
}
199-
if strings.ToUpper(newpath) == strings.ToUpper(path) {
200-
// walkSymlinks did not actually walk any symlinks,
201-
// so we don't need to try GetFinalPathNameByHandle.
202-
return newpath, nil
203-
}
204-
newpath2, err2 := evalSymlinksUsingGetFinalPathNameByHandle(path)
205-
if err2 != nil {
206-
return newpath, nil
207-
}
208-
newpath2, err2 = toNorm(newpath2, normBase)
209-
if err2 != nil {
210-
return newpath, nil
211-
}
212-
if samefile(newpath, newpath2) {
213-
return newpath, nil
214-
}
215-
return newpath2, nil
118+
return newpath, nil
216119
}

0 commit comments

Comments
 (0)