+2020-01-08 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/93201
+ * src/c++17/fs_ops.cc (remove_all(const path&, error_code&)): Check
+ result of recursive call before incrementing iterator.
+ * src/filesystem/ops.cc (remove_all(const path&, error_code&)):
+ Likewise.
+ * testsuite/27_io/filesystem/operations/remove_all.cc: Check errors
+ are reported correctly.
+ * testsuite/experimental/filesystem/operations/remove_all.cc: Likewise.
+
2019-12-11 Jonathan Wakely <jwakely@redhat.com>
Backport from mainline
uintmax_t count = 0;
if (s.type() == file_type::directory)
{
- for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
- count += fs::remove_all(d->path(), ec);
- if (ec.value() == ENOENT)
- ec.clear();
- else if (ec)
- return -1;
+ directory_iterator d(p, ec), end;
+ while (!ec && d != end)
+ {
+ const auto removed = fs::remove_all(d->path(), ec);
+ if (removed == numeric_limits<uintmax_t>::max())
+ return -1;
+ count += removed;
+ d.increment(ec);
+ if (ec)
+ return -1;
+ }
}
if (fs::remove(p, ec))
uintmax_t count = 0;
if (s.type() == file_type::directory)
{
- for (directory_iterator d(p, ec), end; !ec && d != end; d.increment(ec))
- count += fs::remove_all(d->path(), ec);
- if (ec.value() == ENOENT)
- ec.clear();
- else if (ec)
- return -1;
+ directory_iterator d(p, ec), end;
+ while (!ec && d != end)
+ {
+ const auto removed = fs::remove_all(d->path(), ec);
+ if (removed == numeric_limits<uintmax_t>::max())
+ return -1;
+ count += removed;
+ d.increment(ec);
+ if (ec)
+ return -1;
+ }
}
if (fs::remove(p, ec))
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 );
+ }
+
+ fs::permissions(dir, fs::perms::owner_write, fs::perm_options::add);
+#endif
+}
+
int
main()
{
test01();
test02();
test03();
+ test04();
}
VERIFY( !exists(dir) );
}
+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 );
+ }
+
+ fs::permissions(dir, fs::perms::owner_write|fs::perms::add_perms);
+#endif
+}
+
int
main()
{
test01();
test02();
+ test04();
}