From 26fd1fba12a1a646c9f949e5e0a4fcb74e81c67e Mon Sep 17 00:00:00 2001 From: Thanonchai W Date: Fri, 27 Jan 2023 05:54:48 +0000 Subject: [PATCH] os: use GetTempPath2 on Windows if available This generates GetTempPath2. Go now tries to determine if the windows it runs on has GetTempPath2 by finding it only once at the loading time. If GetTempPath2 exists, it sets the flag so that any calls to tempDir will use it. If it doesn't exist, Go then uses GetTempPath. GetTempPath2 was generated into internal/syscall/windows since syscall is locked down. Fixes #56899 Change-Id: Iff08502aebc787fde802ee9496c070c982fbdc08 GitHub-Last-Rev: b77938953404b4e8e11f829c742e3eb109580c5e GitHub-Pull-Request: golang/go#57980 Reviewed-on: https://go-review.googlesource.com/c/go/+/463219 Run-TryBot: Quim Muntal TryBot-Result: Gopher Robot Reviewed-by: Bryan Mills Reviewed-by: Quim Muntal Reviewed-by: Dmitri Shuralyov --- src/internal/syscall/windows/syscall_windows.go | 5 +++++ src/internal/syscall/windows/zsyscall_windows.go | 10 ++++++++++ src/os/file_windows.go | 15 ++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index 311d083f45c140..672ed63922281d 100644 --- a/src/internal/syscall/windows/syscall_windows.go +++ b/src/internal/syscall/windows/syscall_windows.go @@ -151,6 +151,7 @@ const ( //sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW //sys SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf uintptr, bufsize uint32) (err error) = kernel32.SetFileInformationByHandle //sys VirtualQuery(address uintptr, buffer *MemoryBasicInformation, length uintptr) (err error) = kernel32.VirtualQuery +//sys GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) = GetTempPath2W const ( // flags for CreateToolhelp32Snapshot @@ -363,6 +364,10 @@ func LoadGetFinalPathNameByHandle() error { return procGetFinalPathNameByHandleW.Find() } +func ErrorLoadingGetTempPath2() error { + return procGetTempPath2W.Find() +} + //sys CreateEnvironmentBlock(block **uint16, token syscall.Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go index fd2f255b9b4f91..1b5a0c045e1f53 100644 --- a/src/internal/syscall/windows/zsyscall_windows.go +++ b/src/internal/syscall/windows/zsyscall_windows.go @@ -62,6 +62,7 @@ var ( procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") procGetVolumeInformationByHandleW = modkernel32.NewProc("GetVolumeInformationByHandleW") + procGetTempPath2W = modkernel32.NewProc("GetTempPath2W") procLockFileEx = modkernel32.NewProc("LockFileEx") procModule32FirstW = modkernel32.NewProc("Module32FirstW") procModule32NextW = modkernel32.NewProc("Module32NextW") @@ -220,6 +221,15 @@ func GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, return } +func GetTempPath2(buflen uint32, buf *uint16) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procGetTempPath2W.Addr(), 2, uintptr(buflen), uintptr(unsafe.Pointer(buf)), 0) + n = uint32(r0) + if n == 0 { + err = errnoErr(e1) + } + return +} + func GetVolumeInformationByHandle(file syscall.Handle, volumeNameBuffer *uint16, volumeNameSize uint32, volumeNameSerialNumber *uint32, maximumComponentLength *uint32, fileSystemFlags *uint32, fileSystemNameBuffer *uint16, fileSystemNameSize uint32) (err error) { r1, _, e1 := syscall.Syscall9(procGetVolumeInformationByHandleW.Addr(), 8, uintptr(file), uintptr(unsafe.Pointer(volumeNameBuffer)), uintptr(volumeNameSize), uintptr(unsafe.Pointer(volumeNameSerialNumber)), uintptr(unsafe.Pointer(maximumComponentLength)), uintptr(unsafe.Pointer(fileSystemFlags)), uintptr(unsafe.Pointer(fileSystemNameBuffer)), uintptr(fileSystemNameSize), 0) if r1 == 0 { diff --git a/src/os/file_windows.go b/src/os/file_windows.go index a48feca855a3af..e7ee3a56071f6d 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -9,6 +9,7 @@ import ( "internal/poll" "internal/syscall/windows" "runtime" + "sync" "syscall" "unicode/utf16" "unsafe" @@ -230,11 +231,23 @@ func Pipe() (r *File, w *File, err error) { return newFile(p[0], "|0", "pipe"), newFile(p[1], "|1", "pipe"), nil } +var ( + useGetTempPath2Once sync.Once + useGetTempPath2 bool +) + func tempDir() string { + useGetTempPath2Once.Do(func() { + useGetTempPath2 = (windows.ErrorLoadingGetTempPath2() == nil) + }) + getTempPath := syscall.GetTempPath + if useGetTempPath2 { + getTempPath = windows.GetTempPath2 + } n := uint32(syscall.MAX_PATH) for { b := make([]uint16, n) - n, _ = syscall.GetTempPath(uint32(len(b)), &b[0]) + n, _ = getTempPath(uint32(len(b)), &b[0]) if n > uint32(len(b)) { continue }