RtlIsDosDeviceName_U is specifically designed to detect Windows devices.
We were using GetFullPathName to do this, but it's not the right API
for the job, as it is slower and allocates more memory.
goos: windows
goarch: amd64
pkg: path/filepath
cpu: Intel(R) Core(TM) i7-10850H CPU @ 2.70GHz
│ old.txt │ new.txt │
│ sec/op │ sec/op vs base │
IsLocal-12 5.685µ ± 59% 1.853µ ± 12% -67.41% (p=0.000 n=10)
│ old.txt │ new.txt │
│ B/op │ B/op vs base │
IsLocal-12 496.00 ± 0% 48.00 ± 0% -90.32% (p=0.000 n=10)
│ old.txt │ new.txt │
│ allocs/op │ allocs/op vs base │
IsLocal-12 10.000 ± 0% 6.000 ± 0% -40.00% (p=0.000 n=10)
Change-Id: Ib40ad7a90ab93cf7051c8d6becbce4d287f10f4e
Reviewed-on: https://go-review.googlesource.com/c/go/+/650578
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
import (
"internal/bytealg"
"internal/stringslite"
+ "internal/syscall/windows"
"syscall"
)
return true
}
// The path element is a reserved name with an extension.
- // Some Windows versions consider this a reserved name,
- // while others do not. Use FullPath to see if the name is
- // reserved.
- if p, _ := syscall.FullPath(name); len(p) >= 4 && p[:4] == `\\.\` {
- return true
+ // Since Windows 11, reserved names with extensions are no
+ // longer reserved. For example, "CON.txt" is a valid file
+ // name. Use RtlIsDosDeviceName_U to see if the name is reserved.
+ p, err := syscall.UTF16PtrFromString(name)
+ if err != nil {
+ return false
}
- return false
+ return windows.RtlIsDosDeviceName_U(p) > 0
}
func isReservedBaseName(name string) bool {
return path, "", false
}
-// isUNC reports whether path is a UNC path.
-func isUNC(path string) bool {
- return len(path) > 1 && IsPathSeparator(path[0]) && IsPathSeparator(path[1])
-}
-
// postClean adjusts the results of Clean to avoid turning a relative path
// into an absolute or rooted one.
func postClean(out *lazybuf) {
//sys NtOpenFile(handle *syscall.Handle, access uint32, oa *OBJECT_ATTRIBUTES, iosb *IO_STATUS_BLOCK, share uint32, options uint32) (ntstatus error) = ntdll.NtOpenFile
//sys rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) = ntdll.RtlNtStatusToDosErrorNoTeb
//sys NtSetInformationFile(handle syscall.Handle, iosb *IO_STATUS_BLOCK, inBuffer uintptr, inBufferLen uint32, class uint32) (ntstatus error) = ntdll.NtSetInformationFile
+//sys RtlIsDosDeviceName_U(name *uint16) (ret uint32) = ntdll.RtlIsDosDeviceName_U
procNtOpenFile = modntdll.NewProc("NtOpenFile")
procNtSetInformationFile = modntdll.NewProc("NtSetInformationFile")
procRtlGetVersion = modntdll.NewProc("RtlGetVersion")
+ procRtlIsDosDeviceName_U = modntdll.NewProc("RtlIsDosDeviceName_U")
procRtlNtStatusToDosErrorNoTeb = modntdll.NewProc("RtlNtStatusToDosErrorNoTeb")
procGetProcessMemoryInfo = modpsapi.NewProc("GetProcessMemoryInfo")
procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
return
}
+func RtlIsDosDeviceName_U(name *uint16) (ret uint32) {
+ r0, _, _ := syscall.Syscall(procRtlIsDosDeviceName_U.Addr(), 1, uintptr(unsafe.Pointer(name)), 0, 0)
+ ret = uint32(r0)
+ return
+}
+
func rtlNtStatusToDosErrorNoTeb(ntstatus NTStatus) (ret syscall.Errno) {
r0, _, _ := syscall.Syscall(procRtlNtStatusToDosErrorNoTeb.Addr(), 1, uintptr(ntstatus), 0, 0)
ret = syscall.Errno(r0)
t.Fatal("expected error, got nil")
}
}
+
+func BenchmarkIsLocal(b *testing.B) {
+ tests := islocaltests
+ if runtime.GOOS == "windows" {
+ tests = append(tests, winislocaltests...)
+ }
+ if runtime.GOOS == "plan9" {
+ tests = append(tests, plan9islocaltests...)
+ }
+ for b.Loop() {
+ for _, test := range tests {
+ filepath.IsLocal(test.path)
+ }
+ }
+}