From 34a8a966c57d6bd1e62a2e713b44fc4d9ee8be2e Mon Sep 17 00:00:00 2001 From: Thanonchai W Date: Mon, 23 Jan 2023 22:28:49 -0800 Subject: [PATCH] os: TempDir uses 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 --- src/internal/syscall/windows/syscall_windows.go | 8 ++++++++ src/internal/syscall/windows/zsyscall_windows.go | 10 ++++++++++ src/os/file_windows.go | 14 +++++++++++++- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go index 8ace2a27e79fcb..1efd039f125ee8 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,13 @@ func LoadGetFinalPathNameByHandle() error { return procGetFinalPathNameByHandleW.Find() } +func LoadGetTempPath2() bool { + if err := procGetTempPath2W.Find(); err != nil { + return false + } + return true +} + //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 afd64e318e516d..966ba92b465fd5 100644 --- a/src/internal/syscall/windows/zsyscall_windows.go +++ b/src/internal/syscall/windows/zsyscall_windows.go @@ -61,6 +61,7 @@ var ( procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx") procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW") procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW") + procGetTempPath2W = modkernel32.NewProc("GetTempPath2W") procLockFileEx = modkernel32.NewProc("LockFileEx") procModule32FirstW = modkernel32.NewProc("Module32FirstW") procModule32NextW = modkernel32.NewProc("Module32NextW") @@ -219,6 +220,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 LockFileEx(file syscall.Handle, flags uint32, reserved uint32, bytesLow uint32, bytesHigh uint32, overlapped *syscall.Overlapped) (err error) { r1, _, e1 := syscall.Syscall6(procLockFileEx.Addr(), 6, uintptr(file), uintptr(flags), uintptr(reserved), uintptr(bytesLow), uintptr(bytesHigh), uintptr(unsafe.Pointer(overlapped))) if r1 == 0 { diff --git a/src/os/file_windows.go b/src/os/file_windows.go index d94b78f52478d1..6a454fa7d38674 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -14,6 +14,14 @@ import ( "unsafe" ) +var ( + tempPath2Exists bool +) + +func init() { + tempPath2Exists = windows.LoadGetTempPath2() +} + // file is the real representation of *File. // The extra level of indirection ensures that no clients of os // can overwrite this data, which could cause the finalizer @@ -300,10 +308,14 @@ func Pipe() (r *File, w *File, err error) { } func tempDir() string { + getTempPath := syscall.GetTempPath + if tempPath2Exists { + 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 }