From fc892aec2599872e5e87b2d349b4460f905c4767 Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Thu, 10 Apr 2025 16:25:20 -0700 Subject: [PATCH] Fix FileManager.isExecutableFile for emulated x86 processes on ARM systems GetBinaryType will return ERROR_BAD_EXE_FORMAT when querying an arm64 executable from an x86 process running on an ARM system. This change switches the implementation to use SHGetFileInfoW, which isn't subject to this quirk. This also makes isExecutableFile behave more similarly to other platforms -- e.g. isExecutableFile already returns true for any file with the execute bit, even for an arm64 executable on an x86_64 macOS system (which it can't actually run). The spirit of the API is that the file is of an executable type, not necessarily that the running system is capable of executing it. The practical consequence of fixing this bug is that queries like: ```swift FileManager.default.isExecutableFile(atPath: "C:\\Windows\\system32\\cmd.exe") ``` will now correctly return true regardless of what architecture the binary is compiled for or what type of system it's running on. Closes #860 --- .../FoundationEssentials/FileManager/FileManager+Files.swift | 4 ++-- Sources/FoundationEssentials/WinSDK+Extensions.swift | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Sources/FoundationEssentials/FileManager/FileManager+Files.swift b/Sources/FoundationEssentials/FileManager/FileManager+Files.swift index 118712a64..b2666ccbc 100644 --- a/Sources/FoundationEssentials/FileManager/FileManager+Files.swift +++ b/Sources/FoundationEssentials/FileManager/FileManager+Files.swift @@ -448,8 +448,8 @@ extension _FileManagerImpl { func isExecutableFile(atPath path: String) -> Bool { #if os(Windows) return (try? path.withNTPathRepresentation { - var dwBinaryType: DWORD = 0 - return GetBinaryTypeW($0, &dwBinaryType) + // Use SHGetFileInfo instead of GetBinaryType because the latter returns the wrong answer for x86 binaries running under emulation on ARM systems. + return (SHGetFileInfoW($0, 0, nil, 0, SHGFI_EXETYPE) & 0xFFFF) != 0 }) ?? false #else _fileAccessibleForMode(path, X_OK) diff --git a/Sources/FoundationEssentials/WinSDK+Extensions.swift b/Sources/FoundationEssentials/WinSDK+Extensions.swift index 35e0d155c..f0eb3ed95 100644 --- a/Sources/FoundationEssentials/WinSDK+Extensions.swift +++ b/Sources/FoundationEssentials/WinSDK+Extensions.swift @@ -229,6 +229,10 @@ package var RRF_RT_REG_SZ: DWORD { DWORD(WinSDK.RRF_RT_REG_SZ) } +package var SHGFI_EXETYPE: UINT { + UINT(WinSDK.SHGFI_EXETYPE) +} + package var SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE: DWORD { DWORD(WinSDK.SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) }