Skip to content

Commit c098400

Browse files
committed
runtime,internal/syscall/windows: remove long path support check
The runtime currently enables long path support process-wide by updating the process environment block (PEB). It then tries to create a file using a long path to check if the PEB update made any difference. There hasn't been any report that the PEB update was not effective, and the check itself is quite tricky, so it's time to remove it. While here, linkname `runtime.canUseLongPaths` to a variable in internal/syscall/windows instead of the os package so it is easier to consume from other packages. Change-Id: I549380b7f2c242dc4db20d5be603840282de69b9 Reviewed-on: https://go-review.googlesource.com/c/go/+/536495 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Alex Brainman <[email protected]> Reviewed-by: Bryan Mills <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent 28b8851 commit c098400

File tree

5 files changed

+14
-58
lines changed

5 files changed

+14
-58
lines changed

src/internal/syscall/windows/syscall_windows.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import (
1010
"unsafe"
1111
)
1212

13+
// CanUseLongPaths is true when the OS supports opting into
14+
// proper long path handling without the need for fixups.
15+
//
16+
//go:linkname CanUseLongPaths
17+
var CanUseLongPaths bool
18+
1319
// UTF16PtrToString is like UTF16ToString, but takes *uint16
1420
// as a parameter instead of []uint16.
1521
func UTF16PtrToString(p *uint16) string {

src/os/export_windows_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package os
88

99
var (
1010
FixLongPath = fixLongPath
11-
CanUseLongPaths = canUseLongPaths
1211
NewConsoleFile = newConsoleFile
1312
CommandLineToArgv = commandLineToArgv
1413
AllowReadDirFileID = &allowReadDirFileID

src/os/path_windows.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package os
66

7+
import "internal/syscall/windows"
8+
79
const (
810
PathSeparator = '\\' // OS-specific path separator
911
PathListSeparator = ';' // OS-specific path list separator
@@ -128,10 +130,6 @@ func dirname(path string) string {
128130
return vol + dir
129131
}
130132

131-
// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS
132-
// supports opting into proper long path handling without the need for fixups.
133-
var canUseLongPaths bool
134-
135133
// fixLongPath returns the extended-length (\\?\-prefixed) form of
136134
// path when needed, in order to avoid the default 260 character file
137135
// path limit imposed by Windows. If path is not easily converted to
@@ -141,7 +139,7 @@ var canUseLongPaths bool
141139
//
142140
// See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation
143141
func fixLongPath(path string) string {
144-
if canUseLongPaths {
142+
if windows.CanUseLongPaths {
145143
return path
146144
}
147145
// Do nothing (and don't allocate) if the path is "short".

src/os/path_windows_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
)
1717

1818
func TestFixLongPath(t *testing.T) {
19-
if os.CanUseLongPaths {
19+
if windows.CanUseLongPaths {
2020
return
2121
}
2222
t.Parallel()

src/runtime/os_windows.go

Lines changed: 4 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ const (
2020
//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll"
2121
//go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll"
2222
//go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll"
23-
//go:cgo_import_dynamic runtime._CreateFileA CreateFileA%7 "kernel32.dll"
2423
//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
2524
//go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
2625
//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
@@ -78,7 +77,6 @@ var (
7877
_AddVectoredExceptionHandler,
7978
_CloseHandle,
8079
_CreateEventA,
81-
_CreateFileA,
8280
_CreateIoCompletionPort,
8381
_CreateThread,
8482
_CreateWaitableTimerA,
@@ -418,29 +416,14 @@ func initHighResTimer() {
418416
}
419417
}
420418

421-
//go:linkname canUseLongPaths os.canUseLongPaths
419+
//go:linkname canUseLongPaths internal/syscall/windows.CanUseLongPaths
422420
var canUseLongPaths bool
423421

424-
// We want this to be large enough to hold the contents of sysDirectory, *plus*
425-
// a slash and another component that itself is greater than MAX_PATH.
426-
var longFileName [(_MAX_PATH+1)*2 + 1]byte
427-
428-
// initLongPathSupport initializes the canUseLongPaths variable, which is
429-
// linked into os.canUseLongPaths for determining whether or not long paths
430-
// need to be fixed up. In the best case, this function is running on newer
431-
// Windows 10 builds, which have a bit field member of the PEB called
432-
// "IsLongPathAwareProcess." When this is set, we don't need to go through the
433-
// error-prone fixup function in order to access long paths. So this init
434-
// function first checks the Windows build number, sets the flag, and then
435-
// tests to see if it's actually working. If everything checks out, then
436-
// canUseLongPaths is set to true, and later when called, os.fixLongPath
437-
// returns early without doing work.
422+
// initLongPathSupport enables long path support.
438423
func initLongPathSupport() {
439424
const (
440425
IsLongPathAwareProcess = 0x80
441426
PebBitFieldOffset = 3
442-
OPEN_EXISTING = 3
443-
ERROR_PATH_NOT_FOUND = 3
444427
)
445428

446429
// Check that we're ≥ 10.0.15063.
@@ -451,41 +434,11 @@ func initLongPathSupport() {
451434
}
452435

453436
// Set the IsLongPathAwareProcess flag of the PEB's bit field.
437+
// This flag is not documented, but it's known to be used
438+
// by Windows to enable long path support.
454439
bitField := (*byte)(unsafe.Pointer(stdcall0(_RtlGetCurrentPeb) + PebBitFieldOffset))
455-
originalBitField := *bitField
456440
*bitField |= IsLongPathAwareProcess
457441

458-
// Check that this actually has an effect, by constructing a large file
459-
// path and seeing whether we get ERROR_PATH_NOT_FOUND, rather than
460-
// some other error, which would indicate the path is too long, and
461-
// hence long path support is not successful. This whole section is NOT
462-
// strictly necessary, but is a nice validity check for the near to
463-
// medium term, when this functionality is still relatively new in
464-
// Windows.
465-
targ := longFileName[len(longFileName)-33 : len(longFileName)-1]
466-
if readRandom(targ) != len(targ) {
467-
readTimeRandom(targ)
468-
}
469-
start := copy(longFileName[:], sysDirectory[:sysDirectoryLen])
470-
const dig = "0123456789abcdef"
471-
for i := 0; i < 32; i++ {
472-
longFileName[start+i*2] = dig[longFileName[len(longFileName)-33+i]>>4]
473-
longFileName[start+i*2+1] = dig[longFileName[len(longFileName)-33+i]&0xf]
474-
}
475-
start += 64
476-
for i := start; i < len(longFileName)-1; i++ {
477-
longFileName[i] = 'A'
478-
}
479-
stdcall7(_CreateFileA, uintptr(unsafe.Pointer(&longFileName[0])), 0, 0, 0, OPEN_EXISTING, 0, 0)
480-
// The ERROR_PATH_NOT_FOUND error value is distinct from
481-
// ERROR_FILE_NOT_FOUND or ERROR_INVALID_NAME, the latter of which we
482-
// expect here due to the final component being too long.
483-
if getlasterror() == ERROR_PATH_NOT_FOUND {
484-
*bitField = originalBitField
485-
println("runtime: warning: IsLongPathAwareProcess failed to enable long paths; proceeding in fixup mode")
486-
return
487-
}
488-
489442
canUseLongPaths = true
490443
}
491444

0 commit comments

Comments
 (0)