Skip to content

Commit 4a39d08

Browse files
authored
[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.
1 parent 4118082 commit 4a39d08

File tree

2 files changed

+3
-4
lines changed

2 files changed

+3
-4
lines changed

libcxx/src/filesystem/operations.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,8 +815,9 @@ uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) {
815815

816816
// If opening `p` failed because it wasn't a directory, remove it as
817817
// a normal file instead. Note that `openat()` can return either ENOTDIR
818-
// or ELOOP depending on the exact reason of the failure.
819-
if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels) {
818+
// or ELOOP depending on the exact reason of the failure. On FreeBSD it
819+
// may return EMLINK instead of ELOOP, contradicting POSIX.
820+
if (ec == errc::not_a_directory || ec == errc::too_many_symbolic_link_levels || ec == errc::too_many_links) {
820821
ec.clear();
821822
if (::unlinkat(parent_directory, p.c_str(), /* flags = */ 0) == -1) {
822823
ec = detail::capture_errno();

libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.remove_all/remove_all.pass.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
// XFAIL: LIBCXX-FREEBSD-FIXME
10-
119
// UNSUPPORTED: c++03, c++11, c++14
1210
// UNSUPPORTED: no-filesystem
1311
// UNSUPPORTED: availability-filesystem-missing

0 commit comments

Comments
 (0)