mirror of
https://github.com/Kitware/CMake.git
synced 2026-08-04 14:50:23 +00:00
file(CREATE_LINK): Fix CMP0205 to not remove content behind directory symlink
When removing the destination directory link when it already exists
before making the new link, only the (destination) link should be
removed, not the (source) directory itself. When COPY_ON_ERROR is
specified and the destination is a directory, only then should CMake
remove it, since it could likely be placing a new directory there in
its place.
With this new behavior, adjust the conditions for the symlink test from
commit a73ddd2ddb (file(CREATE_LINK): Implement COPY_ON_ERROR for
directories, 2025-10-15, v4.3.0-rc1~599^2). The newly modified test
case should be run on systems that do and don't support directory
symlinks, with slightly different outcomes that are verified.
Fixes: #27747
This commit is contained in:
@@ -3255,8 +3255,9 @@ bool HandleCreateLinkCommand(std::vector<std::string> const& args,
|
|||||||
// Check if the new file already exists and remove it.
|
// Check if the new file already exists and remove it.
|
||||||
if (cmSystemTools::PathExists(newFileName)) {
|
if (cmSystemTools::PathExists(newFileName)) {
|
||||||
cmsys::Status rmStatus;
|
cmsys::Status rmStatus;
|
||||||
if (cmp0205 == cmPolicies::NEW &&
|
if (cmp0205 == cmPolicies::NEW && arguments.CopyOnError &&
|
||||||
cmSystemTools::FileIsDirectory(newFileName)) {
|
cmSystemTools::FileIsDirectory(newFileName) &&
|
||||||
|
!cmSystemTools::FileIsSymlink(newFileName)) {
|
||||||
rmStatus = cmSystemTools::RepeatedRemoveDirectory(newFileName);
|
rmStatus = cmSystemTools::RepeatedRemoveDirectory(newFileName);
|
||||||
} else {
|
} else {
|
||||||
rmStatus = cmSystemTools::RemoveFile(newFileName);
|
rmStatus = cmSystemTools::RemoveFile(newFileName);
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
cmake_policy(SET CMP0205 NEW)
|
cmake_policy(SET CMP0205 NEW)
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0205-common.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/CMP0205-common.cmake")
|
||||||
|
|
||||||
|
# Note that unlike the tests for CMP0205 OLD and WARN, the resulting files
|
||||||
|
# in the source and destination should be the same here regardless of whether
|
||||||
|
# COPY_ON_ERROR was actually executed (i.e, whether through the link, or actual
|
||||||
|
# files).
|
||||||
|
|
||||||
|
if(NOT allFilesSrc)
|
||||||
|
message(SEND_ERROR "Source directory is empty: '${allFilesSrc}'")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(NOT allFilesDst)
|
if(NOT allFilesDst)
|
||||||
message(SEND_ERROR "Destination directory is empty: '${allFilesDst}'")
|
message(SEND_ERROR "Destination directory is empty: '${allFilesDst}'")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
cmake_policy(SET CMP0205 OLD)
|
cmake_policy(SET CMP0205 OLD)
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0205-common.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/CMP0205-common.cmake")
|
||||||
|
|
||||||
if(allFilesDst)
|
# We only really care about when COPY_ON_ERROR was actually executed, but we'll
|
||||||
message(SEND_ERROR "Directory is not empty: '${allFilesDst}'")
|
# test both cases for posterity.
|
||||||
|
|
||||||
|
if(NOT madeSymlink)
|
||||||
|
if(allFilesDst)
|
||||||
|
message(SEND_ERROR "Directory is not empty: '${allFilesDst}'")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
if(NOT allFilesDst)
|
||||||
|
message(SEND_ERROR "Destination directory is empty: '${allFilesDst}'")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
# CMP0205 is unset
|
# CMP0205 is unset
|
||||||
include("${CMAKE_CURRENT_LIST_DIR}/CMP0205-common.cmake")
|
include("${CMAKE_CURRENT_LIST_DIR}/CMP0205-common.cmake")
|
||||||
|
|
||||||
if(allFilesDst)
|
# We only really care about when COPY_ON_ERROR was actually executed, but we'll
|
||||||
message(SEND_ERROR "Directory is not empty: '${allFilesDst}'")
|
# test both cases for posterity.
|
||||||
|
|
||||||
|
if(NOT madeSymlink)
|
||||||
|
if(allFilesDst)
|
||||||
|
message(SEND_ERROR "Directory is not empty: '${allFilesDst}'")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
if(NOT allFilesDst)
|
||||||
|
message(SEND_ERROR "Destination directory is empty: '${allFilesDst}'")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -10,5 +10,30 @@ if(NOT result STREQUAL "0")
|
|||||||
message(SEND_ERROR "COPY_ON_ERROR failed: '${result}'")
|
message(SEND_ERROR "COPY_ON_ERROR failed: '${result}'")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# When CMP0205 is NEW, we must verify after running command this again that:
|
||||||
|
# * on systems which support directory symlinks, the source directory to which
|
||||||
|
# the newly-created link points is not deleted, only the symlink itself.
|
||||||
|
# * on systems which do not support directory symlinks, the destination
|
||||||
|
# directory which was created via COPY_ON_ERROR is appropriately deleted
|
||||||
|
# at the beginning of executing this command, before creating the new link
|
||||||
|
# (and copying instead, again).
|
||||||
|
cmake_policy(GET CMP0205 _cmp0205)
|
||||||
|
if("${maybe_SYMBOLIC}" STREQUAL "SYMBOLIC" AND "${_cmp0205}" STREQUAL "NEW")
|
||||||
|
file(CREATE_LINK
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/CMP0205 ${CMAKE_CURRENT_BINARY_DIR}/CMP0205-${link_name}
|
||||||
|
${maybe_SYMBOLIC}
|
||||||
|
RESULT result
|
||||||
|
COPY_ON_ERROR
|
||||||
|
)
|
||||||
|
if(NOT result STREQUAL "0")
|
||||||
|
message(SEND_ERROR "COPY_ON_ERROR failed: '${result}'")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(madeSymlink OFF)
|
||||||
|
if(IS_SYMLINK ${CMAKE_CURRENT_BINARY_DIR}/CMP0205-${link_name})
|
||||||
|
set(madeSymlink ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
file(GLOB_RECURSE allFilesSrc LIST_DIRECTORIES true RELATIVE "${CMAKE_CURRENT_LIST_DIR}/CMP0205" "${CMAKE_CURRENT_LIST_DIR}/CMP0205/*")
|
file(GLOB_RECURSE allFilesSrc LIST_DIRECTORIES true RELATIVE "${CMAKE_CURRENT_LIST_DIR}/CMP0205" "${CMAKE_CURRENT_LIST_DIR}/CMP0205/*")
|
||||||
file(GLOB_RECURSE allFilesDst LIST_DIRECTORIES true RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/CMP0205-${link_name}" "${CMAKE_CURRENT_BINARY_DIR}/CMP0205-${link_name}/*")
|
file(GLOB_RECURSE allFilesDst LIST_DIRECTORIES true RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/CMP0205-${link_name}" "${CMAKE_CURRENT_BINARY_DIR}/CMP0205-${link_name}/*")
|
||||||
|
|||||||
@@ -12,23 +12,13 @@ if(NOT WIN32
|
|||||||
run_cmake(CREATE_LINK-SYMBOLIC-noexist)
|
run_cmake(CREATE_LINK-SYMBOLIC-noexist)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
run_cmake_script(CMP0205-SymLink-WARN)
|
||||||
|
run_cmake_script(CMP0205-SymLink-OLD)
|
||||||
|
run_cmake_script(CMP0205-SymLink-NEW)
|
||||||
|
|
||||||
|
# Some older versions of macOS with HFS+ filesystems support directory hard
|
||||||
|
# links. Inspect whether this test case is applicable on the current system.
|
||||||
file(MAKE_DIRECTORY ${RunCMake_BINARY_DIR}/CMP0205-Inspect/Dest)
|
file(MAKE_DIRECTORY ${RunCMake_BINARY_DIR}/CMP0205-Inspect/Dest)
|
||||||
|
|
||||||
file(REMOVE_RECURSE ${RunCMake_BINARY_DIR}/CMP0205-Inspect-SymLink)
|
|
||||||
file(CREATE_LINK
|
|
||||||
${RunCMake_BINARY_DIR}/CMP0205-Inspect/Dest ${RunCMake_BINARY_DIR}/CMP0205-Inspect-SymLink
|
|
||||||
SYMBOLIC
|
|
||||||
RESULT SymLink_RESULT
|
|
||||||
)
|
|
||||||
if(SymLink_RESULT STREQUAL "0")
|
|
||||||
message(STATUS "CMP0205-SymLink-* skipped: directory symbolic link creation works")
|
|
||||||
file(REMOVE ${RunCMake_BINARY_DIR}/CMP0205-Inspect-SymLink)
|
|
||||||
else()
|
|
||||||
run_cmake_script(CMP0205-SymLink-WARN)
|
|
||||||
run_cmake_script(CMP0205-SymLink-OLD)
|
|
||||||
run_cmake_script(CMP0205-SymLink-NEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
file(REMOVE_RECURSE ${RunCMake_BINARY_DIR}/CMP0205-Inspect-HardLink)
|
file(REMOVE_RECURSE ${RunCMake_BINARY_DIR}/CMP0205-Inspect-HardLink)
|
||||||
file(CREATE_LINK
|
file(CREATE_LINK
|
||||||
${RunCMake_BINARY_DIR}/CMP0205-Inspect/Dest ${RunCMake_BINARY_DIR}/CMP0205-Inspect-HardLink
|
${RunCMake_BINARY_DIR}/CMP0205-Inspect/Dest ${RunCMake_BINARY_DIR}/CMP0205-Inspect-HardLink
|
||||||
|
|||||||
Reference in New Issue
Block a user