-
Notifications
You must be signed in to change notification settings - Fork 730
Detect Windows junctions with GetFileAttributesEx #2013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors Windows junction and symlink detection by replacing the Realpath-based approach with a dedicated IsSymlinkOrJunction function. The change improves efficiency by using direct Windows API calls to check for reparse points instead of resolving full paths.
- Adds platform-specific
isSymlinkOrJunctionimplementations for Windows and Unix-like systems - Updates
internal.Commonstruct to useIsSymlinkOrJunctioninstead ofRealpathfield - Simplifies junction detection logic in
GetAccessibleEntries
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| internal/vfs/osvfs/symlink_windows.go | New file implementing Windows-specific junction/symlink detection using FILE_ATTRIBUTE_REPARSE_POINT |
| internal/vfs/osvfs/symlink_other.go | New file with nil function stub for Unix-like systems where detection is unnecessary |
| internal/vfs/osvfs/os.go | Updates osVFS initialization to use IsSymlinkOrJunction instead of Realpath |
| internal/vfs/internal/internal.go | Replaces Realpath field with IsSymlinkOrJunction in Common struct and simplifies detection logic in GetAccessibleEntries |
|
Any specific differences you've seen in perf? |
|
Haven't tested yet, just cleaning up some TODOs with my name on it. On any project I have it probably won't be very noticable... |
| if realpath := vfs.Realpath(fullPath); fullPath != realpath { | ||
| if stat := vfs.Stat(realpath); stat != nil { | ||
| if vfs.IsSymlinkOrJunction(fullPath) { | ||
| if stat := vfs.Stat(fullPath); stat != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If something is a junction, maybe we don't even need to stat it and just say that it's a dir? (I don't believe junctions/reparse points can be files, in which case I could rename funcs too)
| } | ||
|
|
||
| var data syscall.Win32FileAttributeData | ||
| err = syscall.GetFileAttributesEx( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might want to prepend \\?\ to automatically handle long filepaths? https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfileattributesexa
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, crap, converting those is a whole thing that is hard and not available to us outside stdlib. I'd need to do something like I did in realpath
func realpath(path string) (string, error) {
var h windows.Handle
if len(path) < 248 {
var err error
h, err = openMetadata(path)
if err != nil {
return "", err
}
defer windows.CloseHandle(h) //nolint:errcheck
} else {
// For long paths, defer to os.Open to run the path through fixLongPath.
f, err := os.Open(path)
if err != nil {
return "", err
}
defer f.Close()
// Works on directories too since https://go.dev/cl/405275.
h = windows.Handle(f.Fd())
}Guess I'll wait on things until I figure that out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't block this on it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's pretty easy to hit this on the use cases where it matters, e.g. pnpm ones, so I should definitely check it in afraid
This should be faster than doing a realpath.