diff options
author | Brad King <brad.king@kitware.com> | 2021-05-10 14:11:48 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2021-05-10 14:12:10 (GMT) |
commit | b00a0e1d680810cdbf0efe654bbc1efae217e66b (patch) | |
tree | 0e650c574a0a7c85a0c03cae52abc9731509d444 /Source | |
parent | 3dd38ac36d49c4eea319b9813bbd1f66a7b0fb29 (diff) | |
parent | ba87a84339e17d710e582588087b507a5861944b (diff) | |
download | CMake-b00a0e1d680810cdbf0efe654bbc1efae217e66b.zip CMake-b00a0e1d680810cdbf0efe654bbc1efae217e66b.tar.gz CMake-b00a0e1d680810cdbf0efe654bbc1efae217e66b.tar.bz2 |
Merge topic 'update-kwsys'
ba87a84339 Merge branch 'upstream-KWSys' into update-kwsys
07727928f9 KWSys 2021-05-07 (979d7db0)
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !6101
Diffstat (limited to 'Source')
-rw-r--r-- | Source/kwsys/ProcessUNIX.c | 8 | ||||
-rw-r--r-- | Source/kwsys/Status.hxx.in | 2 | ||||
-rw-r--r-- | Source/kwsys/SystemTools.cxx | 123 | ||||
-rw-r--r-- | Source/kwsys/testSystemTools.cxx | 30 |
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 |