mirror of
https://github.com/gulrak/filesystem.git
synced 2026-07-31 00:36:12 +08:00
Resolve copy_symlink() handling of relative and dangling targets on Windows, refactor create_symlink for clarity, refs #211
This commit is contained in:
parent
29b5acd3d6
commit
dded74dfb5
@ -673,6 +673,8 @@ to the expected behavior.
|
||||
UTF-16 no longer drops subsequent valid code units.
|
||||
* Fix for [#210](https://github.com/gulrak/filesystem/issues/210),
|
||||
`equivalent()` now compares only filesystem identity.
|
||||
* Fix for [#211](https://github.com/gulrak/filesystem/issues/211), Windows
|
||||
`copy_symlink()` now resolves relative targets from the source link.
|
||||
* Fix for [#178](https://github.com/gulrak/filesystem/issues/178), recursive
|
||||
iteration no longer resolves symlinks unless requested.
|
||||
* Fix for [#185](https://github.com/gulrak/filesystem/issues/185),
|
||||
|
||||
@ -1938,14 +1938,8 @@ GHC_INLINE std::string systemErrorText(ErrorNumber code = 0)
|
||||
using CreateSymbolicLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, DWORD);
|
||||
using CreateHardLinkW_fp = BOOLEAN(WINAPI*)(LPCWSTR, LPCWSTR, LPSECURITY_ATTRIBUTES);
|
||||
|
||||
GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec)
|
||||
GHC_INLINE void create_symlink_unchecked(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec)
|
||||
{
|
||||
std::error_code tec;
|
||||
auto fs = status(target_name, tec);
|
||||
if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) {
|
||||
ec = detail::make_error_code(detail::portable_error::not_supported);
|
||||
return;
|
||||
}
|
||||
#if defined(__GNUC__) && __GNUC__ >= 8 || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
@ -1973,6 +1967,17 @@ GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink,
|
||||
}
|
||||
}
|
||||
|
||||
GHC_INLINE void create_symlink(const path& target_name, const path& new_symlink, bool to_directory, std::error_code& ec)
|
||||
{
|
||||
std::error_code tec;
|
||||
auto fs = status(target_name, tec);
|
||||
if ((fs.type() == file_type::directory && !to_directory) || (fs.type() == file_type::regular && to_directory)) {
|
||||
ec = detail::make_error_code(detail::portable_error::not_supported);
|
||||
return;
|
||||
}
|
||||
create_symlink_unchecked(target_name, new_symlink, to_directory, ec);
|
||||
}
|
||||
|
||||
GHC_INLINE void create_hardlink(const path& target_name, const path& new_hardlink, std::error_code& ec)
|
||||
{
|
||||
#if defined(__GNUC__) && __GNUC__ >= 8 || defined(__clang__)
|
||||
@ -4085,12 +4090,15 @@ GHC_INLINE void copy_symlink(const path& existing_symlink, const path& new_symli
|
||||
ec.clear();
|
||||
auto to = read_symlink(existing_symlink, ec);
|
||||
if (!ec) {
|
||||
if (exists(to, ec) && is_directory(to, ec)) {
|
||||
create_directory_symlink(to, new_symlink, ec);
|
||||
}
|
||||
else {
|
||||
create_symlink(to, new_symlink, ec);
|
||||
#ifdef GHC_OS_WINDOWS
|
||||
auto resolved_to = to.is_absolute() ? to : existing_symlink.parent_path() / to;
|
||||
auto to_directory = exists(resolved_to, ec) && is_directory(resolved_to, ec);
|
||||
if (!ec) {
|
||||
detail::create_symlink_unchecked(to, new_symlink, to_directory, ec);
|
||||
}
|
||||
#else
|
||||
create_symlink(to, new_symlink, ec);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1918,6 +1918,33 @@ TEST_CASE("fs.op.copy_symlink - copy_symlink", "[filesystem][operations][fs.op.c
|
||||
CHECK_NOTHROW(fs::copy_symlink("sdir", "sdirc2", ec));
|
||||
CHECK(fs::exists("sdirc2"));
|
||||
CHECK(!ec);
|
||||
|
||||
fs::create_directories("links/dir-target");
|
||||
generateFile("links/file-target");
|
||||
fs::create_directory_symlink("dir-target", "links/relative-dir-link");
|
||||
fs::create_symlink("file-target", "links/relative-file-link");
|
||||
fs::create_directory("file-target");
|
||||
|
||||
CHECK_NOTHROW(fs::copy_symlink("links/relative-dir-link", "links/relative-dir-copy"));
|
||||
CHECK(fs::is_directory("links/relative-dir-copy"));
|
||||
CHECK(fs::read_symlink("links/relative-dir-copy") == fs::path("dir-target"));
|
||||
|
||||
ec = std::make_error_code(std::errc::invalid_argument);
|
||||
CHECK_NOTHROW(fs::copy_symlink("links/relative-file-link", "links/relative-file-copy", ec));
|
||||
CHECK(!ec);
|
||||
CHECK(fs::is_regular_file("links/relative-file-copy"));
|
||||
CHECK(fs::read_symlink("links/relative-file-copy") == fs::path("file-target"));
|
||||
|
||||
fs::create_symlink("missing-target", "links/dangling-link");
|
||||
CHECK_NOTHROW(fs::copy_symlink("links/dangling-link", "links/dangling-copy", ec));
|
||||
CHECK(!ec);
|
||||
CHECK(fs::is_symlink("links/dangling-copy"));
|
||||
CHECK(fs::read_symlink("links/dangling-copy") == fs::path("missing-target"));
|
||||
|
||||
fs::create_symlink(fs::absolute("foo"), "links/absolute-link");
|
||||
CHECK_NOTHROW(fs::copy_symlink("links/absolute-link", "links/absolute-copy"));
|
||||
CHECK(fs::is_regular_file("links/absolute-copy"));
|
||||
CHECK(fs::read_symlink("links/absolute-copy") == fs::absolute("foo"));
|
||||
}
|
||||
CHECK_THROWS_AS(fs::copy_symlink("bar", "barc"), fs::filesystem_error);
|
||||
CHECK_NOTHROW(fs::copy_symlink("bar", "barc", ec));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user