From 141b685ebd72d8168098248757d234e76648be8b Mon Sep 17 00:00:00 2001 From: Vladimir Shiryaev Date: Sun, 4 Oct 2026 15:34:59 -0700 Subject: [PATCH] [Support] Check whether a file is local by its handle on Windows --- llvm/lib/Support/Windows/Path.inc | 75 ++++++++++++++++++++++++------- 1 file changed, 59 insertions(+), 16 deletions(-) diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc index fe316d11e1b8..ffe5df2e3a21 100644 --- a/llvm/lib/Support/Windows/Path.inc +++ b/llvm/lib/Support/Windows/Path.inc @@ -29,6 +29,7 @@ #include #include #include +#include #undef max @@ -43,6 +44,32 @@ typedef int errno_t; #pragma comment(lib, "ole32.lib") // This provides CoTaskMemFree #endif +#ifndef __MINGW32__ +// The Windows SDK does not declare these types. +// The WDK declares the types in `wdm.h` and `NtQueryVolumeInformationFile` +// in `ntifs.h`. +// MinGW-w64 declares all three in `winternl.h`. +typedef enum _FSINFOCLASS { FileFsDeviceInformation = 4 } FS_INFORMATION_CLASS; + +typedef struct _FILE_FS_DEVICE_INFORMATION { + DEVICE_TYPE DeviceType; + ULONG Characteristics; +} FILE_FS_DEVICE_INFORMATION; + +// Exported by `ntdll.dll`. +extern "C" NTSYSAPI NTSTATUS NTAPI NtQueryVolumeInformationFile( + HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, + ULONG Length, FS_INFORMATION_CLASS FsInformationClass); +#endif + +// Defined only in `wdm.h` in WDK and MinGW-w64. +#ifndef FILE_REMOVABLE_MEDIA +#define FILE_REMOVABLE_MEDIA 0x00000001 +#endif +#ifndef FILE_REMOTE_DEVICE +#define FILE_REMOTE_DEVICE 0x00000010 +#endif + using namespace llvm; using llvm::sys::windows::CurCPToUTF16; @@ -549,18 +576,41 @@ static std::error_code realPathFromHandle(HANDLE H, return std::error_code(); } -std::error_code is_local(int FD, bool &Result) { - sandbox::violationIfEnabled(); +/// Returns true if the volume holding \p Handle is known to be a fixed local +/// disk. Returns false if it is not or if that could not be determined. +static bool isLocalByQueryVolumeInformationFile(HANDLE Handle) { + IO_STATUS_BLOCK IoStatus; + FILE_FS_DEVICE_INFORMATION Info; + if (::NtQueryVolumeInformationFile(Handle, &IoStatus, &Info, sizeof(Info), + FileFsDeviceInformation) < 0) + return false; - SmallVector FinalPath; - HANDLE Handle = reinterpret_cast(_get_osfhandle(FD)); + return (Info.DeviceType == FILE_DEVICE_DISK || + Info.DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) && + !(Info.Characteristics & (FILE_REMOVABLE_MEDIA | FILE_REMOTE_DEVICE)); +} + +static std::error_code is_local_internal(HANDLE Handle, bool &Result) { + // Fast path for the common case: an ordinary local disk, one system call on + // the handle. Everything else goes through the path-based check below. + if (isLocalByQueryVolumeInformationFile(Handle)) { + Result = true; + return std::error_code(); + } + SmallVector FinalPath; if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) return EC; - return is_local_internal(FinalPath, Result); } +std::error_code is_local(int FD, bool &Result) { + sandbox::violationIfEnabled(); + + HANDLE Handle = reinterpret_cast(_get_osfhandle(FD)); + return is_local_internal(Handle, Result); +} + static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { // Clear the FILE_DISPOSITION_INFO flag first, before checking if it's a // network file. On Windows 7 the function realPathFromHandle() below fails @@ -577,12 +627,8 @@ static std::error_code setDeleteDisposition(HANDLE Handle, bool Delete) { // Check if the file is on a network (non-local) drive. If so, don't // continue when DeleteFile is true, since it prevents opening the file for // writes. - SmallVector FinalPath; - if (std::error_code EC = realPathFromHandle(Handle, FinalPath)) - return EC; - bool IsLocal; - if (std::error_code EC = is_local_internal(FinalPath, IsLocal)) + if (std::error_code EC = is_local_internal(Handle, IsLocal)) return EC; if (!IsLocal) @@ -1171,12 +1217,9 @@ void mapped_file_region::unmapImpl() { // cases where we do the flushing. Only do the flushing if we aren't // sure we are on a local file system. bool IsLocal = false; - SmallVector FinalPath; - if (!realPathFromHandle(FileHandle, FinalPath)) { - // Not checking the return value here - if the check fails, assume the - // file isn't local. - is_local_internal(FinalPath, IsLocal); - } + // Not checking the return value here - if the check fails, assume the + // file isn't local. + is_local_internal(FileHandle, IsLocal); DoFlush = !IsLocal; } if (DoFlush)