Browse Source

cmSystemTools: Improve CreateLink and CreateSymlink error codes

In commit 7f89053953 (cmSystemTools: Return KWSys Status from CreateLink
and CreateSymlink, 2021-04-15) we just took the `-err` from libuv and
treated it as a POSIX error.  This is accurate on POSIX, but on Windows
does not match the POSIX error codes.

Use `uv_fs_get_system_error` to get the actual system error code.
This requires libuv 1.38 or higher.  Require that for Windows, but
fall back to the previous approach on POSIX.
Brad King 4 years ago
parent
commit
d7522b8f86

+ 5 - 1
CMakeLists.txt

@@ -644,7 +644,11 @@ macro (CMAKE_BUILD_UTILITIES)
   #---------------------------------------------------------------------
   #---------------------------------------------------------------------
   # Build libuv library.
   # Build libuv library.
   if(CMAKE_USE_SYSTEM_LIBUV)
   if(CMAKE_USE_SYSTEM_LIBUV)
-    find_package(LibUV 1.10.0)
+    if(WIN32)
+      find_package(LibUV 1.38.0)
+    else()
+      find_package(LibUV 1.10.0)
+    endif()
     if(NOT LIBUV_FOUND)
     if(NOT LIBUV_FOUND)
       message(FATAL_ERROR
       message(FATAL_ERROR
         "CMAKE_USE_SYSTEM_LIBUV is ON but a libuv is not found!")
         "CMAKE_USE_SYSTEM_LIBUV is ON but a libuv is not found!")

+ 15 - 3
Source/cmSystemTools.cxx

@@ -3173,9 +3173,15 @@ cmsys::Status cmSystemTools::CreateSymlink(std::string const& origName,
                           flags, nullptr);
                           flags, nullptr);
   cmsys::Status status;
   cmsys::Status status;
   if (err) {
   if (err) {
+#if defined(_WIN32)
+    status = cmsys::Status::Windows(uv_fs_get_system_error(&req));
+#elif UV_VERSION_MAJOR > 1 || (UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 38)
+    status = cmsys::Status::POSIX(uv_fs_get_system_error(&req));
+#else
     status = cmsys::Status::POSIX(-err);
     status = cmsys::Status::POSIX(-err);
-    std::string e =
-      "failed to create symbolic link '" + newName + "': " + uv_strerror(err);
+#endif
+    std::string e = cmStrCat("failed to create symbolic link '", newName,
+                             "': ", status.GetString());
     if (errorMessage) {
     if (errorMessage) {
       *errorMessage = std::move(e);
       *errorMessage = std::move(e);
     } else {
     } else {
@@ -3194,9 +3200,15 @@ cmsys::Status cmSystemTools::CreateLink(std::string const& origName,
     uv_fs_link(nullptr, &req, origName.c_str(), newName.c_str(), nullptr);
     uv_fs_link(nullptr, &req, origName.c_str(), newName.c_str(), nullptr);
   cmsys::Status status;
   cmsys::Status status;
   if (err) {
   if (err) {
+#if defined(_WIN32)
+    status = cmsys::Status::Windows(uv_fs_get_system_error(&req));
+#elif UV_VERSION_MAJOR > 1 || (UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 38)
+    status = cmsys::Status::POSIX(uv_fs_get_system_error(&req));
+#else
     status = cmsys::Status::POSIX(-err);
     status = cmsys::Status::POSIX(-err);
+#endif
     std::string e =
     std::string e =
-      "failed to create link '" + newName + "': " + uv_strerror(err);
+      cmStrCat("failed to create link '", newName, "': ", status.GetString());
     if (errorMessage) {
     if (errorMessage) {
       *errorMessage = std::move(e);
       *errorMessage = std::move(e);
     } else {
     } else {

+ 1 - 1
Tests/RunCMake/CommandLine/E_create_hardlink-no-directory-stderr.txt

@@ -1 +1 @@
-^CMake Error: failed to create link .* no such file or directory
+^CMake Error: failed to create link '[^']+': [A-Za-z]

+ 1 - 1
Tests/RunCMake/CommandLine/E_create_hardlink-unresolved-symlink-prereq-check.cmake

@@ -1,3 +1,3 @@
-if(${actual_stderr_var} MATCHES "operation not permitted")
+if(${actual_stderr_var} MATCHES "A required privilege is not held by the client")
   unset(msg)
   unset(msg)
 endif()
 endif()

+ 1 - 1
Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake

@@ -1,4 +1,4 @@
-if(${actual_stderr_var} MATCHES "operation not permitted")
+if(${actual_stderr_var} MATCHES "A required privilege is not held by the client")
   unset(msg)
   unset(msg)
 else()
 else()
   if(NOT IS_SYMLINK ${RunCMake_TEST_BINARY_DIR}/L)
   if(NOT IS_SYMLINK ${RunCMake_TEST_BINARY_DIR}/L)

+ 1 - 1
Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake

@@ -1,4 +1,4 @@
-if(${actual_stderr_var} MATCHES "operation not permitted")
+if(${actual_stderr_var} MATCHES "A required privilege is not held by the client")
   unset(msg)
   unset(msg)
 else()
 else()
   if(NOT IS_DIRECTORY ${RunCMake_TEST_BINARY_DIR}/L)
   if(NOT IS_DIRECTORY ${RunCMake_TEST_BINARY_DIR}/L)

+ 2 - 2
Tests/RunCMake/CommandLine/RunCMakeTest.cmake

@@ -359,7 +359,7 @@ run_cmake_command(E_create_symlink-missing-dir
 # These tests are special on Windows since it will only fail if the user
 # These tests are special on Windows since it will only fail if the user
 # running the test does not have the priveldge to create symlinks. If this
 # running the test does not have the priveldge to create symlinks. If this
 # happens we clear the msg in the -check.cmake and say that the test passes
 # happens we clear the msg in the -check.cmake and say that the test passes
-set(RunCMake_DEFAULT_stderr "(operation not permitted)?")
+set(RunCMake_DEFAULT_stderr "(A required privilege is not held by the client)?")
 set(RunCMake_TEST_BINARY_DIR
 set(RunCMake_TEST_BINARY_DIR
   ${RunCMake_BINARY_DIR}/E_create_symlink-broken-build)
   ${RunCMake_BINARY_DIR}/E_create_symlink-broken-build)
 set(RunCMake_TEST_NO_CLEAN 1)
 set(RunCMake_TEST_NO_CLEAN 1)
@@ -403,7 +403,7 @@ run_cmake_command(E_create_hardlink-no-directory
 
 
 #On Windows, if the user does not have sufficient privileges
 #On Windows, if the user does not have sufficient privileges
 #don't fail this test
 #don't fail this test
-set(RunCMake_DEFAULT_stderr "(operation not permitted)?")
+set(RunCMake_DEFAULT_stderr "(A required privilege is not held by the client)?")
 run_cmake_command(E_create_hardlink-unresolved-symlink-prereq
 run_cmake_command(E_create_hardlink-unresolved-symlink-prereq
   ${CMAKE_COMMAND} -E create_symlink ${dir}/1 ${dir}/1-symlink
   ${CMAKE_COMMAND} -E create_symlink ${dir}/1 ${dir}/1-symlink
   )
   )