summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/cmFileCommand.cxx20
-rw-r--r--Source/cmFileCopier.cxx44
-rw-r--r--Source/cmSystemTools.cxx43
-rw-r--r--Source/cmSystemTools.h10
-rw-r--r--Source/cmcmd.cxx7
-rw-r--r--Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-result.txt1
-rw-r--r--Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stderr.txt12
-rw-r--r--Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stdout.txt12
-rw-r--r--Tests/RunCMake/install/DIRECTORY-symlink-clobber.cmake11
-rw-r--r--Tests/RunCMake/install/RunCMakeTest.cmake4
10 files changed, 122 insertions, 42 deletions
diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx
index bec9fb2..421ff12 100644
--- a/Source/cmFileCommand.cxx
+++ b/Source/cmFileCommand.cxx
@@ -2960,11 +2960,23 @@ bool HandleCreateLinkCommand(std::vector<std::string> const& args,
// Check if the command requires a symbolic link.
if (arguments.Symbolic) {
- completed = static_cast<bool>(
- cmSystemTools::CreateSymlink(fileName, newFileName, &result));
+ cmsys::Status linked =
+ cmSystemTools::CreateSymlinkQuietly(fileName, newFileName);
+ if (linked) {
+ completed = true;
+ } else {
+ result = cmStrCat("failed to create symbolic link '", newFileName,
+ "': ", linked.GetString());
+ }
} else {
- completed = static_cast<bool>(
- cmSystemTools::CreateLink(fileName, newFileName, &result));
+ cmsys::Status linked =
+ cmSystemTools::CreateLinkQuietly(fileName, newFileName);
+ if (linked) {
+ completed = true;
+ } else {
+ result = cmStrCat("failed to create link '", newFileName,
+ "': ", linked.GetString());
+ }
}
// Check if copy-on-error is enabled in the arguments.
diff --git a/Source/cmFileCopier.cxx b/Source/cmFileCopier.cxx
index 1667807..ef55abf 100644
--- a/Source/cmFileCopier.cxx
+++ b/Source/cmFileCopier.cxx
@@ -15,7 +15,11 @@
#include "cmValue.h"
#ifdef _WIN32
+# include <winerror.h>
+
# include "cmsys/FStream.hxx"
+#else
+# include <cerrno>
#endif
#include <cstring>
@@ -504,11 +508,12 @@ bool cmFileCopier::InstallSymlinkChain(std::string& fromFile,
cmSystemTools::RemoveFile(toFile);
cmSystemTools::MakeDirectory(toFilePath);
- if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot create symlink \"" << toFile
- << "\": " << cmSystemTools::GetLastSystemError() << ".";
- this->Status.SetError(e.str());
+ cmsys::Status status =
+ cmSystemTools::CreateSymlinkQuietly(symlinkTarget, toFile);
+ if (!status) {
+ std::string e = cmStrCat(this->Name, " cannot create symlink\n ",
+ toFile, "\nbecause: ", status.GetString());
+ this->Status.SetError(e);
return false;
}
}
@@ -557,12 +562,24 @@ bool cmFileCopier::InstallSymlink(const std::string& fromFile,
cmSystemTools::MakeDirectory(cmSystemTools::GetFilenamePath(toFile));
// Create the symlink.
- if (!cmSystemTools::CreateSymlink(symlinkTarget, toFile)) {
- std::ostringstream e;
- e << this->Name << " cannot duplicate symlink \"" << fromFile
- << "\" at \"" << toFile
- << "\": " << cmSystemTools::GetLastSystemError() << ".";
- this->Status.SetError(e.str());
+ cmsys::Status status =
+ cmSystemTools::CreateSymlinkQuietly(symlinkTarget, toFile);
+ if (!status) {
+#ifdef _WIN32
+ bool const errorFileExists = status.GetWindows() == ERROR_FILE_EXISTS;
+#else
+ bool const errorFileExists = status.GetPOSIX() == EEXIST;
+#endif
+ std::string reason;
+ if (errorFileExists && cmSystemTools::FileIsDirectory(toFile)) {
+ reason = "A directory already exists at that location";
+ } else {
+ reason = status.GetString();
+ }
+ std::string e =
+ cmStrCat(this->Name, " cannot duplicate symlink\n ", fromFile,
+ "\nat\n ", toFile, "\nbecause: ", reason);
+ this->Status.SetError(e);
return false;
}
}
@@ -630,7 +647,10 @@ bool cmFileCopier::InstallDirectory(const std::string& source,
{
// Inform the user about this directory installation.
this->ReportCopy(destination, TypeDir,
- !cmSystemTools::FileIsDirectory(destination));
+ !( // Report "Up-to-date:" for existing directories,
+ // but not symlinks to them.
+ cmSystemTools::FileIsDirectory(destination) &&
+ !cmSystemTools::FileIsSymlink(destination)));
// check if default dir creation permissions were set
mode_t default_dir_mode_v = 0;
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 5737cc1..ee74908 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -3590,8 +3590,19 @@ std::string cmSystemTools::EncodeURL(std::string const& in, bool escapeSlashes)
}
cmsys::Status cmSystemTools::CreateSymlink(std::string const& origName,
- std::string const& newName,
- std::string* errorMessage)
+ std::string const& newName)
+{
+ cmsys::Status status =
+ cmSystemTools::CreateSymlinkQuietly(origName, newName);
+ if (!status) {
+ cmSystemTools::Error(cmStrCat("failed to create symbolic link '", newName,
+ "': ", status.GetString()));
+ }
+ return status;
+}
+
+cmsys::Status cmSystemTools::CreateSymlinkQuietly(std::string const& origName,
+ std::string const& newName)
{
uv_fs_t req;
int flags = 0;
@@ -3611,20 +3622,23 @@ cmsys::Status cmSystemTools::CreateSymlink(std::string const& origName,
#else
status = cmsys::Status::POSIX(-err);
#endif
- std::string e = cmStrCat("failed to create symbolic link '", newName,
- "': ", status.GetString());
- if (errorMessage) {
- *errorMessage = std::move(e);
- } else {
- cmSystemTools::Error(e);
- }
}
return status;
}
cmsys::Status cmSystemTools::CreateLink(std::string const& origName,
- std::string const& newName,
- std::string* errorMessage)
+ std::string const& newName)
+{
+ cmsys::Status status = cmSystemTools::CreateLinkQuietly(origName, newName);
+ if (!status) {
+ cmSystemTools::Error(
+ cmStrCat("failed to create link '", newName, "': ", status.GetString()));
+ }
+ return status;
+}
+
+cmsys::Status cmSystemTools::CreateLinkQuietly(std::string const& origName,
+ std::string const& newName)
{
uv_fs_t req;
int err =
@@ -3638,13 +3652,6 @@ cmsys::Status cmSystemTools::CreateLink(std::string const& origName,
#else
status = cmsys::Status::POSIX(-err);
#endif
- std::string e =
- cmStrCat("failed to create link '", newName, "': ", status.GetString());
- if (errorMessage) {
- *errorMessage = std::move(e);
- } else {
- cmSystemTools::Error(e);
- }
}
return status;
}
diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h
index b02a977..87b354c 100644
--- a/Source/cmSystemTools.h
+++ b/Source/cmSystemTools.h
@@ -595,14 +595,16 @@ public:
/** Create a symbolic link if the platform supports it. Returns whether
creation succeeded. */
static cmsys::Status CreateSymlink(std::string const& origName,
- std::string const& newName,
- std::string* errorMessage = nullptr);
+ std::string const& newName);
+ static cmsys::Status CreateSymlinkQuietly(std::string const& origName,
+ std::string const& newName);
/** Create a hard link if the platform supports it. Returns whether
creation succeeded. */
static cmsys::Status CreateLink(std::string const& origName,
- std::string const& newName,
- std::string* errorMessage = nullptr);
+ std::string const& newName);
+ static cmsys::Status CreateLinkQuietly(std::string const& origName,
+ std::string const& newName);
/** Get the system name. */
static cm::string_view GetSystemName();
diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx
index 00c9bda..16944e6 100644
--- a/Source/cmcmd.cxx
+++ b/Source/cmcmd.cxx
@@ -1700,16 +1700,15 @@ cmsys::Status cmcmd::SymlinkInternal(std::string const& file,
}
std::string linktext = cmSystemTools::GetFilenameName(file);
#if defined(_WIN32) && !defined(__CYGWIN__)
- std::string errorMessage;
- cmsys::Status status =
- cmSystemTools::CreateSymlink(linktext, link, &errorMessage);
+ cmsys::Status status = cmSystemTools::CreateSymlinkQuietly(linktext, link);
// Creating a symlink will fail with ERROR_PRIVILEGE_NOT_HELD if the user
// does not have SeCreateSymbolicLinkPrivilege, or if developer mode is not
// active. In that case, we try to copy the file.
if (status.GetWindows() == ERROR_PRIVILEGE_NOT_HELD) {
status = cmSystemTools::CopyFileAlways(file, link);
} else if (!status) {
- cmSystemTools::Error(errorMessage);
+ cmSystemTools::Error(cmStrCat("failed to create symbolic link '", link,
+ "': ", status.GetString()));
}
return status;
#else
diff --git a/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-result.txt b/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stderr.txt b/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stderr.txt
new file mode 100644
index 0000000..d082b8a
--- /dev/null
+++ b/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stderr.txt
@@ -0,0 +1,12 @@
+^CMake Error at cmake_install.cmake:[0-9]+ \(file\):
+ file INSTALL cannot duplicate symlink
+
+ [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/new/dir
+
+ at
+
+ [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/root-all/dest/dir
+
+ because: A directory already exists at that location
diff --git a/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stdout.txt b/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stdout.txt
new file mode 100644
index 0000000..db8ca10
--- /dev/null
+++ b/Tests/RunCMake/install/DIRECTORY-symlink-clobber-all-stdout.txt
@@ -0,0 +1,12 @@
+-- Installing: [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/root-all/dest/dir
+-- Installing: [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/root-all/dest/dir/file
+-- Installing: [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/root-all/dest/lnk
+-- Installing: [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/root-all/dest/lnk
+-- Up-to-date: [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/root-all/dest/lnk/file
+-- Installing: [^
+]*/Tests/RunCMake/install/DIRECTORY-symlink-clobber-build/root-all/dest/dir
diff --git a/Tests/RunCMake/install/DIRECTORY-symlink-clobber.cmake b/Tests/RunCMake/install/DIRECTORY-symlink-clobber.cmake
new file mode 100644
index 0000000..ac7a2cf
--- /dev/null
+++ b/Tests/RunCMake/install/DIRECTORY-symlink-clobber.cmake
@@ -0,0 +1,11 @@
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/old/dir)
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/old/dir/file "")
+file(CREATE_LINK dir ${CMAKE_CURRENT_BINARY_DIR}/old/lnk SYMBOLIC)
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/old/dir DESTINATION dest)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/old/lnk DESTINATION dest)
+
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/new/lnk)
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/new/lnk/file "")
+file(CREATE_LINK lnk ${CMAKE_CURRENT_BINARY_DIR}/new/dir SYMBOLIC)
+install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/new/lnk DESTINATION dest)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/new/dir DESTINATION dest)
diff --git a/Tests/RunCMake/install/RunCMakeTest.cmake b/Tests/RunCMake/install/RunCMakeTest.cmake
index 7c12d4a..477ffe0 100644
--- a/Tests/RunCMake/install/RunCMakeTest.cmake
+++ b/Tests/RunCMake/install/RunCMakeTest.cmake
@@ -175,6 +175,10 @@ run_install_test(FILES-PERMISSIONS)
run_install_test(TARGETS-RPATH)
run_install_test(InstallRequiredSystemLibraries)
+if(UNIX)
+ run_install_test(DIRECTORY-symlink-clobber)
+endif()
+
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-two-bundle)
run_cmake(TARGETS-RUNTIME_DEPENDENCIES-macos-no-framework)