summaryrefslogtreecommitdiff
path: root/libstdc++-v3/testsuite/27_io/filesystem
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2020-01-08 16:44:45 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2020-01-08 16:44:45 +0000
commitfff148b787b897aafdc6e361d8379f3b1b280874 (patch)
tree329c98ae97dc6e2d48a0fefca9e2969966dce036 /libstdc++-v3/testsuite/27_io/filesystem
parentface749a49c35ebe5732e7a526680b454d7e6cb5 (diff)
libstdc++: Fix error handling in filesystem::remove_all (PR93201)
When recursing into a directory, any errors that occur while removing a directory entry are ignored, because the subsequent increment of the directory iterator clears the error_code object. This fixes that bug by checking the result of each recursive operation before incrementing. This is a change in observable behaviour, because previously other directory entries would still be removed even if one (or more) couldn't be removed due to errors. Now the operation stops on the first error, which is what the code intended to do all along. The standard doesn't specify what happens in this case (because the order that the entries are processed is unspecified anyway). It also improves the error reporting so that the name of the file that could not be removed is included in the filesystem_error exception. This is done by introducing a new helper type for reporting errors with additional context and a new function that uses that type. Then the overload of std::filesystem::remove_all that throws an exception can use the new function to ensure any exception contains the additional information. For std::experimental::filesystem::remove_all just fix the bug where errors are ignored. PR libstdc++/93201 * src/c++17/fs_ops.cc (do_remove_all): New function implementing more detailed error reporting for remove_all. Check result of recursive call before incrementing iterator. (remove_all(const path&), remove_all(const path&, error_code&)): Use do_remove_all. * src/filesystem/ops.cc (remove_all(const path&, error_code&)): Check result of recursive call before incrementing iterator. * testsuite/27_io/filesystem/operations/remove_all.cc: Check errors are reported correctly. * testsuite/experimental/filesystem/operations/remove_all.cc: Likewise. From-SVN: r280014
Diffstat (limited to 'libstdc++-v3/testsuite/27_io/filesystem')
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc35
1 files changed, 35 insertions, 0 deletions
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
index 5b920e490cb..7e018b51af2 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
@@ -140,10 +140,45 @@ test03()
VERIFY( !exists(p) );
}
+void
+test04()
+{
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ // no permissions
+#else
+ // PR libstdc++/93201
+ std::error_code ec;
+ std::uintmax_t n;
+
+ auto dir = __gnu_test::nonexistent_path();
+ fs::create_directory(dir);
+ __gnu_test::scoped_file f(dir/"file");
+ // remove write permission on the directory:
+ fs::permissions(dir, fs::perms::owner_read|fs::perms::owner_exec);
+ n = fs::remove_all(dir, ec);
+ VERIFY( n == -1 );
+ VERIFY( ec == std::errc::permission_denied ); // not ENOTEMPTY
+
+ try {
+ fs::remove_all(dir);
+ VERIFY( false );
+ } catch (const fs::filesystem_error& e) {
+ VERIFY( e.code() == std::errc::permission_denied );
+ // First path is the argument to remove_all
+ VERIFY( e.path1() == dir );
+ // Second path is the first file that couldn't be removed
+ VERIFY( e.path2() == dir/"file" );
+ }
+
+ fs::permissions(dir, fs::perms::owner_write, fs::perm_options::add);
+#endif
+}
+
int
main()
{
test01();
test02();
test03();
+ test04();
}