swift-foundation
swift-foundation copied to clipboard
FileManager.isExecutableFile fails for wow64 processes
The following code, if compiled as an x86_64 process and run on an arm64 system, will claim that the command shell binary is not executable. This is because GetBinaryTypeW returns ERROR_BAD_EXE_FORMAT for wow64 processes.
This is not necessarily a bug in Foundation, but a quirk in the Win32 APIs. It seems worth documenting this caveat, at least.
import Foundation
import WinSDK
let fm = FileManager()
let path = "C:\\Windows\\system32\\cmd.exe"
print("\(path) isExecutable = \(fm.isExecutableFile(atPath: path))") // false
var dwBinaryType: DWORD = .max
let ret = path.withCString(encodedAs: UTF16.self) { ptr in
GetBinaryTypeW(ptr, &dwBinaryType)
}
let err = GetLastError()
print("\(ret) \(dwBinaryType) \(err)")
// err == ERROR_BAD_EXE_FORMAT
Thanks for catching this, I wonder if there's an alternative API that we can be using here that would allow us to determine if the file is executable even if the architectures don't match (or perhaps if we call GetBinaryTypeW and the error is ERROR_BAD_EXE_FORMAT, does that indicate that it is executable and we should add a special case to return true in that scenario?
Apparently you'd have to parse the PE file manually: https://stackoverflow.com/a/44338280
Actually, this may work:
func GetExecutableType(_ path: String) -> Bool {
(path.withCString(encodedAs: UTF16.self) { SHGetFileInfoW($0, 0, nil, 0, numericCast(SHGFI_EXETYPE)) } & 0xFFFF) != 0
}
I've tested this and it seems to work for the relevant cases.