summaryrefslogtreecommitdiffstats
path: root/Source/kwsys/SystemTools.cxx
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2021-05-07 13:26:05 (GMT)
committerBrad King <brad.king@kitware.com>2021-05-07 13:26:05 (GMT)
commitba87a84339e17d710e582588087b507a5861944b (patch)
treea0b2bd85e284ff5846b8c1315936203abfc9e460 /Source/kwsys/SystemTools.cxx
parenteac20afe9af631fbc7ea1b172e066875895077ce (diff)
parent07727928f9e243fd472767c27596b618ada4b5d4 (diff)
downloadCMake-ba87a84339e17d710e582588087b507a5861944b.zip
CMake-ba87a84339e17d710e582588087b507a5861944b.tar.gz
CMake-ba87a84339e17d710e582588087b507a5861944b.tar.bz2
Merge branch 'upstream-KWSys' into update-kwsys
# By KWSys Upstream * upstream-KWSys: KWSys 2021-05-07 (979d7db0)
Diffstat (limited to 'Source/kwsys/SystemTools.cxx')
-rw-r--r--Source/kwsys/SystemTools.cxx123
1 files changed, 108 insertions, 15 deletions
diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx
index 2518845..006495d 100644
--- a/Source/kwsys/SystemTools.cxx
+++ b/Source/kwsys/SystemTools.cxx
@@ -93,9 +93,43 @@
# ifndef INVALID_FILE_ATTRIBUTES
# define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
# endif
+# ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE (0x2)
+# endif
# if defined(_MSC_VER) && _MSC_VER >= 1800
# define KWSYS_WINDOWS_DEPRECATED_GetVersionEx
# endif
+// from ntifs.h, which can only be used by drivers
+typedef struct _REPARSE_DATA_BUFFER
+{
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union
+ {
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct
+ {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct
+ {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ } DUMMYUNIONNAME;
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
#endif
#if !KWSYS_CXX_HAS_ENVIRON_IN_STDLIB_H
@@ -3008,7 +3042,7 @@ bool SystemTools::FileIsSymlink(const std::string& name)
}
CloseHandle(hFile);
ULONG reparseTag =
- reinterpret_cast<PREPARSE_GUID_DATA_BUFFER>(&buffer[0])->ReparseTag;
+ reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0])->ReparseTag;
return (reparseTag == IO_REPARSE_TAG_SYMLINK) ||
(reparseTag == IO_REPARSE_TAG_MOUNT_POINT);
}
@@ -3048,31 +3082,90 @@ bool SystemTools::FileIsFIFO(const std::string& name)
#endif
}
-#if defined(_WIN32) && !defined(__CYGWIN__)
-Status SystemTools::CreateSymlink(std::string const&, std::string const&)
-{
- return Status::Windows(ERROR_NOT_SUPPORTED);
-}
-#else
Status SystemTools::CreateSymlink(std::string const& origName,
std::string const& newName)
{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ DWORD flags;
+ if (FileIsDirectory(origName)) {
+ flags = SYMBOLIC_LINK_FLAG_DIRECTORY;
+ } else {
+ flags = 0;
+ }
+
+ std::wstring origPath = Encoding::ToWindowsExtendedPath(origName);
+ std::wstring newPath = Encoding::ToWindowsExtendedPath(newName);
+
+ Status status;
+ if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(),
+ flags |
+ SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)) {
+ status = Status::Windows_GetLastError();
+ }
+ // Older Windows versions do not understand
+ // SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+ if (status.GetWindows() == ERROR_INVALID_PARAMETER) {
+ status = Status::Success();
+ if (!CreateSymbolicLinkW(newPath.c_str(), origPath.c_str(), flags)) {
+ status = Status::Windows_GetLastError();
+ }
+ }
+
+ return status;
+#else
if (symlink(origName.c_str(), newName.c_str()) < 0) {
return Status::POSIX_errno();
}
return Status::Success();
-}
#endif
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-Status SystemTools::ReadSymlink(std::string const&, std::string&)
-{
- return Status::Windows(ERROR_NOT_SUPPORTED);
}
-#else
+
Status SystemTools::ReadSymlink(std::string const& newName,
std::string& origName)
{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ std::wstring newPath = Encoding::ToWindowsExtendedPath(newName);
+ // FILE_ATTRIBUTE_REPARSE_POINT means:
+ // * a file or directory that has an associated reparse point, or
+ // * a file that is a symbolic link.
+ HANDLE hFile = CreateFileW(
+ newPath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return Status::Windows_GetLastError();
+ }
+ byte buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ DWORD bytesReturned = 0;
+ Status status;
+ if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, nullptr, 0, buffer,
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &bytesReturned,
+ nullptr)) {
+ status = Status::Windows_GetLastError();
+ }
+ CloseHandle(hFile);
+ if (!status) {
+ return status;
+ }
+ PREPARSE_DATA_BUFFER data =
+ reinterpret_cast<PREPARSE_DATA_BUFFER>(&buffer[0]);
+ USHORT substituteNameLength;
+ PCWSTR substituteNameData;
+ if (data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ substituteNameLength =
+ data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
+ substituteNameData = data->SymbolicLinkReparseBuffer.PathBuffer +
+ data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
+ } else if (data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ substituteNameLength =
+ data->MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR);
+ substituteNameData = data->MountPointReparseBuffer.PathBuffer +
+ data->MountPointReparseBuffer.SubstituteNameOffset / sizeof(WCHAR);
+ } else {
+ return Status::Windows(ERROR_REPARSE_TAG_MISMATCH);
+ }
+ std::wstring substituteName(substituteNameData, substituteNameLength);
+ origName = Encoding::ToNarrow(substituteName);
+#else
char buf[KWSYS_SYSTEMTOOLS_MAXPATH + 1];
int count = static_cast<int>(
readlink(newName.c_str(), buf, KWSYS_SYSTEMTOOLS_MAXPATH));
@@ -3082,9 +3175,9 @@ Status SystemTools::ReadSymlink(std::string const& newName,
// Add null-terminator.
buf[count] = 0;
origName = buf;
+#endif
return Status::Success();
}
-#endif
Status SystemTools::ChangeDirectory(std::string const& dir)
{