diff options
author | redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2018-01-05 18:02:18 +0000 |
---|---|---|
committer | redi <redi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2018-01-05 18:02:18 +0000 |
commit | 5310392950a93a58fb59a6f659d01137c4b682ec (patch) | |
tree | 3ed7c9569ed1cbe6f874fc17ea1c273eefa56808 /libstdc++-v3/src/filesystem/std-ops.cc | |
parent | e6ece981d1c67e546251b3af1ead9e04ca3cdb45 (diff) | |
download | gcc-5310392950a93a58fb59a6f659d01137c4b682ec.tar.gz |
PR libstdc++/83626 handle ENOENT due to filesystem race
PR libstdc++/83626
* src/filesystem/ops.cc (remove(const path&, error_code&)): Do not
report an error for ENOENT.
(remove_all(const path&)): Fix type of result variable.
(remove_all(const path&, error_code&)): Use non-throwing increment
for directory iterator. Call POSIX remove directly to avoid redundant
calls to symlink_status. Do not report errors for ENOENT.
* src/filesystem/std-ops.cc: Likewise.
* testsuite/27_io/filesystem/operations/remove_all.cc: Test throwing
overload.
* testsuite/experimental/filesystem/operations/remove_all.cc:
Likewise.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@256283 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3/src/filesystem/std-ops.cc')
-rw-r--r-- | libstdc++-v3/src/filesystem/std-ops.cc | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc index 6ff280a9c76..2411bbb7977 100644 --- a/libstdc++-v3/src/filesystem/std-ops.cc +++ b/libstdc++-v3/src/filesystem/std-ops.cc @@ -1274,13 +1274,16 @@ fs::remove(const path& p, error_code& ec) noexcept ec.clear(); return false; // Nothing to do, not an error. } - if (::remove(p.c_str()) != 0) + if (::remove(p.c_str()) == 0) { - ec.assign(errno, std::generic_category()); - return false; + ec.clear(); + return true; } - ec.clear(); - return true; + else if (errno == ENOENT) + ec.clear(); + else + ec.assign(errno, std::generic_category()); + return false; } @@ -1288,7 +1291,7 @@ std::uintmax_t fs::remove_all(const path& p) { error_code ec; - bool result = remove_all(p, ec); + const auto result = remove_all(p, ec); if (ec) _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec)); return result; @@ -1300,15 +1303,29 @@ fs::remove_all(const path& p, error_code& ec) const auto s = symlink_status(p, ec); if (!status_known(s)) return -1; + ec.clear(); + if (s.type() == file_type::not_found) + return 0; + uintmax_t count = 0; if (s.type() == file_type::directory) - for (directory_iterator d(p, ec), end; !ec && d != end; ++d) - count += fs::remove_all(d->path(), ec); - if (!ec && fs::remove(p, ec)) + { + 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; + } + + if (::remove(p.c_str()) == 0) ++count; - if (ec) - return -1; + else if (errno != ENOENT) + { + ec.assign(errno, std::generic_category()); + return -1; + } return count; } |