Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 59 additions & 16 deletions llvm/lib/Support/Windows/Path.inc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <shellapi.h>
#include <shlobj.h>
#include <winioctl.h>
#include <winternl.h>

#undef max

Expand All @@ -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;
Expand Down Expand Up @@ -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<wchar_t, 128> FinalPath;
HANDLE Handle = reinterpret_cast<HANDLE>(_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<wchar_t, 128> 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<HANDLE>(_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
Expand All @@ -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<wchar_t, 128> 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)
Expand Down Expand Up @@ -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<wchar_t, 128> 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)
Expand Down