summaryrefslogtreecommitdiffstats
path: root/Source
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
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')
-rw-r--r--Source/kwsys/ProcessUNIX.c8
-rw-r--r--Source/kwsys/Status.hxx.in2
-rw-r--r--Source/kwsys/SystemTools.cxx123
-rw-r--r--Source/kwsys/testSystemTools.cxx30
4 files changed, 132 insertions, 31 deletions
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index 5ae846a..a8a15dd 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -2894,10 +2894,10 @@ static void kwsysProcessesSignalHandler(int signum
/* Re-Install our handler. Repeat call until it is not interrupted. */
{
struct sigaction newSigAction;
- struct sigaction& oldSigAction;
+ struct sigaction* oldSigAction;
memset(&newSigAction, 0, sizeof(struct sigaction));
- newSigChldAction.sa_handler = kwsysProcessesSignalHandler;
- newSigChldAction.sa_flags = SA_NOCLDSTOP;
+ newSigAction.sa_handler = kwsysProcessesSignalHandler;
+ newSigAction.sa_flags = SA_NOCLDSTOP;
sigemptyset(&newSigAction.sa_mask);
switch (signum) {
case SIGCHLD:
@@ -2912,7 +2912,7 @@ static void kwsysProcessesSignalHandler(int signum
oldSigAction = &kwsysProcessesOldSigTermAction;
break;
default:
- return 0;
+ return;
}
while ((sigaction(signum, &newSigAction, oldSigAction) < 0) &&
(errno == EINTR))
diff --git a/Source/kwsys/Status.hxx.in b/Source/kwsys/Status.hxx.in
index feb5b84..ed46d5c 100644
--- a/Source/kwsys/Status.hxx.in
+++ b/Source/kwsys/Status.hxx.in
@@ -70,7 +70,7 @@ public:
#ifdef _WIN32
/** If the kind is "Windows", returns the GetLastError()-style value.
Otherwise, returns 0. */
- int GetWindows() const
+ unsigned int GetWindows() const
{
return this->Kind_ == Kind::Windows ? this->Windows_ : 0;
}
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)
{
diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx
index 04f66ff..700eaf7 100644
--- a/Source/kwsys/testSystemTools.cxx
+++ b/Source/kwsys/testSystemTools.cxx
@@ -29,6 +29,7 @@
# ifdef _MSC_VER
# define umask _umask
# endif
+# include <windows.h>
#endif
#include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */
// Visual C++ does not define mode_t.
@@ -425,21 +426,28 @@ static bool CheckFileOperations()
res = false;
}
-#if !defined(_WIN32)
std::string const testBadSymlink(testNewDir + "/badSymlink.txt");
std::string const testBadSymlinkTgt(testNewDir + "/missing/symlinkTgt.txt");
- if (!kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink)) {
- std::cerr << "Problem with CreateSymlink for: " << testBadSymlink << " -> "
- << testBadSymlinkTgt << std::endl;
- res = false;
- }
+ kwsys::Status const symlinkStatus =
+ kwsys::SystemTools::CreateSymlink(testBadSymlinkTgt, testBadSymlink);
+#if defined(_WIN32)
+ // Under Windows, the user may not have enough privileges to create symlinks
+ if (symlinkStatus.GetWindows() != ERROR_PRIVILEGE_NOT_HELD)
+#endif
+ {
+ if (!symlinkStatus) {
+ std::cerr << "CreateSymlink for: " << testBadSymlink << " -> "
+ << testBadSymlinkTgt
+ << " failed: " << symlinkStatus.GetString() << std::endl;
+ res = false;
+ }
- if (!kwsys::SystemTools::Touch(testBadSymlink, false)) {
- std::cerr << "Problem with Touch (no create) for: " << testBadSymlink
- << std::endl;
- res = false;
+ if (!kwsys::SystemTools::Touch(testBadSymlink, false)) {
+ std::cerr << "Problem with Touch (no create) for: " << testBadSymlink
+ << std::endl;
+ res = false;
+ }
}
-#endif
if (!kwsys::SystemTools::Touch(testNewDir, false)) {
std::cerr << "Problem with Touch (no create) for: " << testNewDir