aboutsummaryrefslogtreecommitdiff
path: root/libcxx/src/filesystem/operations.cpp
diff options
context:
space:
mode:
authorMark Johnston <markjdb@gmail.com>2024-01-29 03:19:57 -0500
committerGitHub <noreply@github.com>2024-01-29 09:19:57 +0100
commit4a39d08908942b2d415db405844cbe4af73e75d4 (patch)
tree9710c8464b660bc748de126a4b1e0b6ac99d5705 /libcxx/src/filesystem/operations.cpp
parent4118082f651a05cca258c684ab1199578b57afac (diff)
downloadllvm-4a39d08908942b2d415db405844cbe4af73e75d4.zip
llvm-4a39d08908942b2d415db405844cbe4af73e75d4.tar.gz
llvm-4a39d08908942b2d415db405844cbe4af73e75d4.tar.bz2
[libc++] Fix filesystem::remove_all() on FreeBSD (#79540)
remove_all_impl() opens the target path with O_NOFOLLOW, which fails if the target is a symbolic link. On FreeBSD, rather than returning ELOOP, openat() returns EMLINK. This is unlikely to change for compatibility reasons, see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=214633 . Thus, check for EMLINK as well.
Diffstat (limited to 'libcxx/src/filesystem/operations.cpp')
-rw-r--r--libcxx/src/filesystem/operations.cpp5
1 files changed, 3 insertions, 2 deletions
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 6253d15..62bb248 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -815,8 +815,9 @@ uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) {
// If opening `p` failed because it wasn't a directory, remove it as
// a normal file instead. Note that `openat()` can return either ENOTDIR
- // or ELOOP depending on the exact reason of the failure.
- if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels) {
+ // or ELOOP depending on the exact reason of the failure. On FreeBSD it
+ // may return EMLINK instead of ELOOP, contradicting POSIX.
+ if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels || ec == errc::too_many_links) {
ec.clear();
if (::unlinkat(parent_directory, p.c_str(), /* flags = */ 0) == -1) {
ec = detail::capture_errno();