libstdc++: Fix error reporting in filesystem::copy [PR99290]

The recursive calls to filesystem::copy should stop if any of them
reports an error.

libstdc++-v3/ChangeLog:

	PR libstdc++/99290
	* src/c++17/fs_ops.cc (fs::copy): Pass error_code to
	directory_iterator constructor, and check on each iteration.
	* src/filesystem/ops.cc (fs::copy): Likewise.
	* testsuite/27_io/filesystem/operations/copy.cc: Check for
	errors during recursion.
	* testsuite/experimental/filesystem/operations/copy.cc:
	Likewise.
This commit is contained in:
Jonathan Wakely 2022-04-28 13:06:31 +01:00
parent d91cb2059f
commit 4e117418fb
4 changed files with 70 additions and 4 deletions

View file

@ -408,8 +408,12 @@ fs::copy(const path& from, const path& to, copy_options options,
// set an unused bit in options to disable further recursion
if (!is_set(options, copy_options::recursive))
options |= static_cast<copy_options>(4096);
for (const directory_entry& x : directory_iterator(from))
copy(x.path(), to/x.path().filename(), options, ec);
for (const directory_entry& x : directory_iterator(from, ec))
{
copy(x.path(), to/x.path().filename(), options, ec);
if (ec)
return;
}
}
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2683. filesystem::copy() says "no effects"

View file

@ -350,8 +350,12 @@ fs::copy(const path& from, const path& to, copy_options options,
// set an unused bit in options to disable further recursion
if (!is_set(options, copy_options::recursive))
options |= static_cast<copy_options>(4096);
for (const directory_entry& x : directory_iterator(from))
copy(x.path(), to/x.path().filename(), options, ec);
for (const directory_entry& x : directory_iterator(from, ec))
{
copy(x.path(), to/x.path().filename(), options, ec);
if (ec)
return;
}
}
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2683. filesystem::copy() says "no effects"

View file

@ -193,6 +193,34 @@ test05()
VERIFY( !ec ); // Previous value should be cleared (LWG 2683)
}
void
test_pr99290()
{
auto dir = __gnu_test::nonexistent_path();
auto source = dir/"source";
auto dest = dir/"dest";
create_directories(source/"emptydir");
create_directories(dest/"emptydir");
std::ofstream{source/"file"} << 'a';
std::ofstream{dest/"file"} << 'b';
// PR libstdc++/99290
// std::filesystem::copy does not always report errors for recursion
std::error_code ec;
copy(source, dest, ec);
VERIFY( ec == std::errc::file_exists );
#if __cpp_exceptions
try {
copy(source, dest);
VERIFY( false );
} catch (const fs::filesystem_error& e) {
VERIFY( e.code() == std::errc::file_exists );
}
#endif
remove_all(dir);
}
int
main()
{
@ -201,4 +229,5 @@ main()
test03();
test04();
test05();
test_pr99290();
}

View file

@ -190,6 +190,34 @@ test05()
VERIFY( !ec ); // Previous value should be cleared (LWG 2683)
}
void
test_pr99290()
{
auto dir = __gnu_test::nonexistent_path();
auto source = dir/"source";
auto dest = dir/"dest";
create_directories(source/"emptydir");
create_directories(dest/"emptydir");
std::ofstream{source/"file"} << 'a';
std::ofstream{dest/"file"} << 'b';
// PR libstdc++/99290
// std::filesystem::copy does not always report errors for recursion
std::error_code ec;
copy(source, dest, ec);
VERIFY( ec == std::errc::file_exists );
#if __cpp_exceptions
try {
copy(source, dest);
VERIFY( false );
} catch (const fs::filesystem_error& e) {
VERIFY( e.code() == std::errc::file_exists );
}
#endif
remove_all(dir);
}
int
main()
{
@ -198,4 +226,5 @@ main()
test03();
test04();
test05();
test_pr99290();
}