From: qmuntal Date: Thu, 19 Oct 2023 16:06:27 +0000 (+0200) Subject: runtime,internal/syscall/windows: remove long path support check X-Git-Tag: go1.23rc1~1287 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c0984005487b293b4bb2f92e8cd9b58422f7831e;p=gostls13.git 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 Reviewed-by: Alex Brainman Reviewed-by: Bryan Mills Reviewed-by: David Chase --- diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index a02c96c8f0..03ceb5803f 100644 --- a/src/internal/syscall/windows/syscall_windows.go +++ b/src/internal/syscall/windows/syscall_windows.go @@ -10,6 +10,12 @@ import ( "unsafe" ) +// CanUseLongPaths is true when the OS supports opting into +// proper long path handling without the need for fixups. +// +//go:linkname CanUseLongPaths +var CanUseLongPaths bool + // UTF16PtrToString is like UTF16ToString, but takes *uint16 // as a parameter instead of []uint16. func UTF16PtrToString(p *uint16) string { diff --git a/src/os/export_windows_test.go b/src/os/export_windows_test.go index 6e1188816b..2e5904b3f5 100644 --- a/src/os/export_windows_test.go +++ b/src/os/export_windows_test.go @@ -8,7 +8,6 @@ package os var ( FixLongPath = fixLongPath - CanUseLongPaths = canUseLongPaths NewConsoleFile = newConsoleFile CommandLineToArgv = commandLineToArgv AllowReadDirFileID = &allowReadDirFileID diff --git a/src/os/path_windows.go b/src/os/path_windows.go index 0522025148..98139679d4 100644 --- a/src/os/path_windows.go +++ b/src/os/path_windows.go @@ -4,6 +4,8 @@ package os +import "internal/syscall/windows" + const ( PathSeparator = '\\' // OS-specific path separator PathListSeparator = ';' // OS-specific path list separator @@ -128,10 +130,6 @@ func dirname(path string) string { return vol + dir } -// This is set via go:linkname on runtime.canUseLongPaths, and is true when the OS -// supports opting into proper long path handling without the need for fixups. -var canUseLongPaths bool - // fixLongPath returns the extended-length (\\?\-prefixed) form of // path when needed, in order to avoid the default 260 character file // path limit imposed by Windows. If path is not easily converted to @@ -141,7 +139,7 @@ var canUseLongPaths bool // // See https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation func fixLongPath(path string) string { - if canUseLongPaths { + if windows.CanUseLongPaths { return path } // Do nothing (and don't allocate) if the path is "short". diff --git a/src/os/path_windows_test.go b/src/os/path_windows_test.go index 4e5e501d1f..6fa864a98d 100644 --- a/src/os/path_windows_test.go +++ b/src/os/path_windows_test.go @@ -16,7 +16,7 @@ import ( ) func TestFixLongPath(t *testing.T) { - if os.CanUseLongPaths { + if windows.CanUseLongPaths { return } t.Parallel() diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 7e9bbd04f2..ca443ae0c3 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -20,7 +20,6 @@ const ( //go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll" //go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll" -//go:cgo_import_dynamic runtime._CreateFileA CreateFileA%7 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll" //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll" @@ -78,7 +77,6 @@ var ( _AddVectoredExceptionHandler, _CloseHandle, _CreateEventA, - _CreateFileA, _CreateIoCompletionPort, _CreateThread, _CreateWaitableTimerA, @@ -418,29 +416,14 @@ func initHighResTimer() { } } -//go:linkname canUseLongPaths os.canUseLongPaths +//go:linkname canUseLongPaths internal/syscall/windows.CanUseLongPaths var canUseLongPaths bool -// We want this to be large enough to hold the contents of sysDirectory, *plus* -// a slash and another component that itself is greater than MAX_PATH. -var longFileName [(_MAX_PATH+1)*2 + 1]byte - -// initLongPathSupport initializes the canUseLongPaths variable, which is -// linked into os.canUseLongPaths for determining whether or not long paths -// need to be fixed up. In the best case, this function is running on newer -// Windows 10 builds, which have a bit field member of the PEB called -// "IsLongPathAwareProcess." When this is set, we don't need to go through the -// error-prone fixup function in order to access long paths. So this init -// function first checks the Windows build number, sets the flag, and then -// tests to see if it's actually working. If everything checks out, then -// canUseLongPaths is set to true, and later when called, os.fixLongPath -// returns early without doing work. +// initLongPathSupport enables long path support. func initLongPathSupport() { const ( IsLongPathAwareProcess = 0x80 PebBitFieldOffset = 3 - OPEN_EXISTING = 3 - ERROR_PATH_NOT_FOUND = 3 ) // Check that we're ≥ 10.0.15063. @@ -451,41 +434,11 @@ func initLongPathSupport() { } // Set the IsLongPathAwareProcess flag of the PEB's bit field. + // This flag is not documented, but it's known to be used + // by Windows to enable long path support. bitField := (*byte)(unsafe.Pointer(stdcall0(_RtlGetCurrentPeb) + PebBitFieldOffset)) - originalBitField := *bitField *bitField |= IsLongPathAwareProcess - // Check that this actually has an effect, by constructing a large file - // path and seeing whether we get ERROR_PATH_NOT_FOUND, rather than - // some other error, which would indicate the path is too long, and - // hence long path support is not successful. This whole section is NOT - // strictly necessary, but is a nice validity check for the near to - // medium term, when this functionality is still relatively new in - // Windows. - targ := longFileName[len(longFileName)-33 : len(longFileName)-1] - if readRandom(targ) != len(targ) { - readTimeRandom(targ) - } - start := copy(longFileName[:], sysDirectory[:sysDirectoryLen]) - const dig = "0123456789abcdef" - for i := 0; i < 32; i++ { - longFileName[start+i*2] = dig[longFileName[len(longFileName)-33+i]>>4] - longFileName[start+i*2+1] = dig[longFileName[len(longFileName)-33+i]&0xf] - } - start += 64 - for i := start; i < len(longFileName)-1; i++ { - longFileName[i] = 'A' - } - stdcall7(_CreateFileA, uintptr(unsafe.Pointer(&longFileName[0])), 0, 0, 0, OPEN_EXISTING, 0, 0) - // The ERROR_PATH_NOT_FOUND error value is distinct from - // ERROR_FILE_NOT_FOUND or ERROR_INVALID_NAME, the latter of which we - // expect here due to the final component being too long. - if getlasterror() == ERROR_PATH_NOT_FOUND { - *bitField = originalBitField - println("runtime: warning: IsLongPathAwareProcess failed to enable long paths; proceeding in fixup mode") - return - } - canUseLongPaths = true }