mirror of
https://github.com/Kitware/CMake.git
synced 2026-01-09 07:11:05 -06:00
Merge branch 'upstream-KWSys' into update-kwsys
# By KWSys Upstream * upstream-KWSys: KWSys 2021-11-01 (572f2a65)
This commit is contained in:
@@ -34,6 +34,10 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <cwchar>
|
||||
#endif
|
||||
|
||||
// Work-around CMake dependency scanning limitation. This must
|
||||
// duplicate the above list of headers.
|
||||
#if 0
|
||||
@@ -103,6 +107,9 @@
|
||||
# if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||
# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
|
||||
# endif
|
||||
# ifndef IO_REPARSE_TAG_APPEXECLINK
|
||||
# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL)
|
||||
# endif
|
||||
// from ntifs.h, which can only be used by drivers
|
||||
typedef struct _REPARSE_DATA_BUFFER
|
||||
{
|
||||
@@ -132,8 +139,46 @@ typedef struct _REPARSE_DATA_BUFFER
|
||||
{
|
||||
UCHAR DataBuffer[1];
|
||||
} GenericReparseBuffer;
|
||||
struct
|
||||
{
|
||||
ULONG Version;
|
||||
WCHAR StringList[1];
|
||||
// In version 3, there are 4 NUL-terminated strings:
|
||||
// * Package ID
|
||||
// * Entry Point
|
||||
// * Executable Path
|
||||
// * Application Type
|
||||
} AppExecLinkReparseBuffer;
|
||||
} DUMMYUNIONNAME;
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
|
||||
namespace {
|
||||
WCHAR* GetAppExecLink(PREPARSE_DATA_BUFFER data, size_t& len)
|
||||
{
|
||||
// We only know the layout of version 3.
|
||||
if (data->AppExecLinkReparseBuffer.Version != 3) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WCHAR* pstr = data->AppExecLinkReparseBuffer.StringList;
|
||||
|
||||
// Skip the package id and entry point strings.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
len = std::wcslen(pstr);
|
||||
if (len == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
pstr += len + 1;
|
||||
}
|
||||
|
||||
// The third string is the executable path.
|
||||
len = std::wcslen(pstr);
|
||||
if (len == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return pstr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
|
||||
@@ -1343,8 +1388,8 @@ bool SystemTools::FileExists(const std::string& filename)
|
||||
return false;
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
DWORD attr =
|
||||
GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str());
|
||||
const std::wstring path = Encoding::ToWindowsExtendedPath(filename);
|
||||
DWORD attr = GetFileAttributesW(path.c_str());
|
||||
if (attr == INVALID_FILE_ATTRIBUTES) {
|
||||
return false;
|
||||
}
|
||||
@@ -1352,12 +1397,38 @@ bool SystemTools::FileExists(const std::string& filename)
|
||||
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
// Using 0 instead of GENERIC_READ as it allows reading of file attributes
|
||||
// even if we do not have permission to read the file itself
|
||||
HANDLE handle =
|
||||
CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), 0, 0,
|
||||
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
HANDLE handle = CreateFileW(path.c_str(), 0, 0, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
// A reparse point may be an execution alias (Windows Store app), which
|
||||
// is similar to a symlink but it cannot be opened as a regular file.
|
||||
// We must look at the reparse point data explicitly.
|
||||
handle = CreateFileW(
|
||||
path.c_str(), 0, 0, nullptr, OPEN_EXISTING,
|
||||
FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
|
||||
DWORD bytesReturned = 0;
|
||||
|
||||
if (!DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer,
|
||||
MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned,
|
||||
nullptr)) {
|
||||
CloseHandle(handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
|
||||
PREPARSE_DATA_BUFFER data =
|
||||
reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0]);
|
||||
|
||||
// Assume that file exists if it is an execution alias.
|
||||
return data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK;
|
||||
}
|
||||
|
||||
CloseHandle(handle);
|
||||
@@ -3011,11 +3082,7 @@ bool SystemTools::FileIsDirectory(const std::string& inName)
|
||||
|
||||
bool SystemTools::FileIsExecutable(const std::string& name)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return SystemTools::FileExists(name, true);
|
||||
#else
|
||||
return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SystemTools::FileIsSymlink(const std::string& name)
|
||||
@@ -3164,6 +3231,15 @@ Status SystemTools::ReadSymlink(std::string const& newName,
|
||||
data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
|
||||
substituteNameData = data->MountPointReparseBuffer.PathBuffer +
|
||||
data->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
||||
} else if (data->ReparseTag == IO_REPARSE_TAG_APPEXECLINK) {
|
||||
// The reparse buffer is a list of 0-terminated non-empty strings,
|
||||
// terminated by an empty string (0-0). We need the third string.
|
||||
size_t destLen;
|
||||
substituteNameData = GetAppExecLink(data, destLen);
|
||||
if (substituteNameData == nullptr || destLen == 0) {
|
||||
return Status::Windows(ERROR_SYMLINK_NOT_SUPPORTED);
|
||||
}
|
||||
substituteNameLength = static_cast<USHORT>(destLen);
|
||||
} else {
|
||||
return Status::Windows(ERROR_REPARSE_TAG_MISMATCH);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user