Skip to content

Commit f05c99d

Browse files
committed
Switch to using GetFinalPathNameByHandle
1 parent 8998046 commit f05c99d

File tree

9 files changed

+102
-177
lines changed

9 files changed

+102
-177
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.23.3
55
require (
66
github.com/go-json-experiment/json v0.0.0-20241127185351-9802db03f36a
77
github.com/google/go-cmp v0.6.0
8+
golang.org/x/sys v0.27.0
89
golang.org/x/tools v0.27.0
910
gotest.tools/v3 v3.5.1
1011
)

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
66
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
77
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
88
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
9+
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
10+
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
911
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
1012
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
1113
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=

internal/vfs/os.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func (vfs *osFS) Realpath(path string) string {
8282

8383
orig := path
8484
path = filepath.FromSlash(path)
85-
path, err := walkSymlinks(path)
85+
path, err := realpath(path)
8686
if err != nil {
8787
return orig
8888
}

internal/vfs/realpath_other.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build !windows
2+
3+
package vfs
4+
5+
import (
6+
"path/filepath"
7+
)
8+
9+
func realpath(path string) (string, error) {
10+
return filepath.EvalSymlinks(path)
11+
}
File renamed without changes.

internal/vfs/realpath_windows.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package vfs
2+
3+
import (
4+
"errors"
5+
"os"
6+
"syscall"
7+
8+
"golang.org/x/sys/windows"
9+
)
10+
11+
// This implementation is based on what Node's fs.realpath.native does, via libuv: https://github.com/libuv/libuv/blob/ec5a4b54f7da7eeb01679005c615fee9633cdb3b/src/win/fs.c#L2937
12+
13+
func realpath(path string) (string, error) {
14+
h, err := openMetadata(path)
15+
if err != nil {
16+
return "", err
17+
}
18+
defer windows.CloseHandle(h) //nolint:errcheck
19+
20+
// based on https://github.com/golang/go/blob/f4e3ec3dbe3b8e04a058d266adf8e048bab563f2/src/os/file_windows.go#L389
21+
22+
const _VOLUME_NAME_DOS = 0
23+
24+
buf := make([]uint16, 310) // https://github.com/microsoft/go-winio/blob/3c9576c9346a1892dee136329e7e15309e82fb4f/internal/stringbuffer/wstring.go#L13
25+
for {
26+
n, err := windows.GetFinalPathNameByHandle(h, &buf[0], uint32(len(buf)), _VOLUME_NAME_DOS)
27+
if err != nil {
28+
return "", err
29+
}
30+
if n < uint32(len(buf)) {
31+
break
32+
}
33+
buf = make([]uint16, n)
34+
}
35+
36+
s := syscall.UTF16ToString(buf)
37+
if len(s) > 4 && s[:4] == `\\?\` {
38+
s = s[4:]
39+
if len(s) > 3 && s[:3] == `UNC` {
40+
// return path like \\server\share\...
41+
return `\` + s[3:], nil
42+
}
43+
return s, nil
44+
}
45+
46+
return "", errors.New("GetFinalPathNameByHandle returned unexpected path: " + s)
47+
}
48+
49+
func openMetadata(path string) (windows.Handle, error) {
50+
// based on https://github.com/microsoft/go-winio/blob/3c9576c9346a1892dee136329e7e15309e82fb4f/pkg/fs/resolve.go#L113
51+
52+
pathUTF16, err := windows.UTF16PtrFromString(path)
53+
if err != nil {
54+
return windows.InvalidHandle, err
55+
}
56+
57+
const (
58+
_FILE_ANY_ACCESS = 0
59+
60+
_FILE_SHARE_READ = 0x01
61+
_FILE_SHARE_WRITE = 0x02
62+
_FILE_SHARE_DELETE = 0x04
63+
64+
_OPEN_EXISTING = 0x03
65+
66+
_FILE_FLAG_BACKUP_SEMANTICS = 0x0200_0000
67+
)
68+
69+
h, err := windows.CreateFile(
70+
pathUTF16,
71+
_FILE_ANY_ACCESS,
72+
_FILE_SHARE_READ|_FILE_SHARE_WRITE|_FILE_SHARE_DELETE,
73+
nil,
74+
_OPEN_EXISTING,
75+
_FILE_FLAG_BACKUP_SEMANTICS,
76+
0,
77+
)
78+
79+
if err != nil {
80+
return 0, &os.PathError{
81+
Op: "CreateFile",
82+
Path: path,
83+
Err: err,
84+
}
85+
}
86+
return h, nil
87+
}

internal/vfs/symlink.go

Lines changed: 0 additions & 156 deletions
This file was deleted.

internal/vfs/symlink_other.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

internal/vfs/symlink_windows.go

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)