mirror of
https://github.com/Kitware/CMake.git
synced 2026-03-11 12:00:48 -05:00
KWSys 2021-11-01 (572f2a65)
Code extracted from:
https://gitlab.kitware.com/utils/kwsys.git
at commit 572f2a6592d671ecc865fe7821a0f4803deb9be7 (master).
Upstream Shortlog
-----------------
Brad King (3):
025a4951 SystemTools: Add Windows app exec alias support to ReadSymlink
f5b3500f SystemTools: Simplify FileIsExecutable on Windows
bcddb31b SystemTools: Fix Windows app exec alias layout
Yuriy O'Donnell (1):
29f31d17 SystemTools: Add Windows app exec alias support to FileExists()
This commit is contained in:
committed by
Brad King
parent
6015a898d4
commit
e9ab6eeeb5
@@ -34,6 +34,10 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# include <cwchar>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Work-around CMake dependency scanning limitation. This must
|
// Work-around CMake dependency scanning limitation. This must
|
||||||
// duplicate the above list of headers.
|
// duplicate the above list of headers.
|
||||||
#if 0
|
#if 0
|
||||||
@@ -103,6 +107,9 @@
|
|||||||
# if defined(_MSC_VER) && _MSC_VER >= 1800
|
# if defined(_MSC_VER) && _MSC_VER >= 1800
|
||||||
# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
|
# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef IO_REPARSE_TAG_APPEXECLINK
|
||||||
|
# define IO_REPARSE_TAG_APPEXECLINK (0x8000001BL)
|
||||||
|
# endif
|
||||||
// from ntifs.h, which can only be used by drivers
|
// from ntifs.h, which can only be used by drivers
|
||||||
typedef struct _REPARSE_DATA_BUFFER
|
typedef struct _REPARSE_DATA_BUFFER
|
||||||
{
|
{
|
||||||
@@ -132,8 +139,46 @@ typedef struct _REPARSE_DATA_BUFFER
|
|||||||
{
|
{
|
||||||
UCHAR DataBuffer[1];
|
UCHAR DataBuffer[1];
|
||||||
} GenericReparseBuffer;
|
} 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;
|
} DUMMYUNIONNAME;
|
||||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
} 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
|
#endif
|
||||||
|
|
||||||
#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
|
#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
|
||||||
@@ -1343,8 +1388,8 @@ bool SystemTools::FileExists(const std::string& filename)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
DWORD attr =
|
const std::wstring path = Encoding::ToWindowsExtendedPath(filename);
|
||||||
GetFileAttributesW(Encoding::ToWindowsExtendedPath(filename).c_str());
|
DWORD attr = GetFileAttributesW(path.c_str());
|
||||||
if (attr == INVALID_FILE_ATTRIBUTES) {
|
if (attr == INVALID_FILE_ATTRIBUTES) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1352,12 +1397,38 @@ bool SystemTools::FileExists(const std::string& filename)
|
|||||||
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||||
// Using 0 instead of GENERIC_READ as it allows reading of file attributes
|
// 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
|
// even if we do not have permission to read the file itself
|
||||||
HANDLE handle =
|
HANDLE handle = CreateFileW(path.c_str(), 0, 0, nullptr, OPEN_EXISTING,
|
||||||
CreateFileW(Encoding::ToWindowsExtendedPath(filename).c_str(), 0, 0,
|
FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||||
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
|
||||||
|
|
||||||
if (handle == INVALID_HANDLE_VALUE) {
|
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);
|
CloseHandle(handle);
|
||||||
@@ -3011,11 +3082,7 @@ bool SystemTools::FileIsDirectory(const std::string& inName)
|
|||||||
|
|
||||||
bool SystemTools::FileIsExecutable(const std::string& name)
|
bool SystemTools::FileIsExecutable(const std::string& name)
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
|
||||||
return SystemTools::FileExists(name, true);
|
|
||||||
#else
|
|
||||||
return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE);
|
return !FileIsDirectory(name) && TestFileAccess(name, TEST_FILE_EXECUTE);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SystemTools::FileIsSymlink(const std::string& name)
|
bool SystemTools::FileIsSymlink(const std::string& name)
|
||||||
@@ -3164,6 +3231,15 @@ Status SystemTools::ReadSymlink(std::string const& newName,
|
|||||||
data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
|
data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
|
||||||
substituteNameData = data->MountPointReparseBuffer.PathBuffer +
|
substituteNameData = data->MountPointReparseBuffer.PathBuffer +
|
||||||
data->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
|
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 {
|
} else {
|
||||||
return Status::Windows(ERROR_REPARSE_TAG_MISMATCH);
|
return Status::Windows(ERROR_REPARSE_TAG_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user