On Fri, 4 Feb 2022 at 23:55, Jonathan Wakely wrote: > +// Used to implement filesystem::remove_all. > +fs::recursive_directory_iterator& > +fs::recursive_directory_iterator::__erase(error_code* ecptr) > +{ > + error_code ec; > + if (!_M_dirs) > + { > + ec = std::make_error_code(errc::invalid_argument); > + return *this; > + } > + > + // We never want to skip permission denied when removing files. > + const bool skip_permission_denied = false; > + // We never want to follow directory symlinks when removing files. > + const bool nofollow = true; > + > + // Loop until we find something we can remove. > + while (!ec) > + { > + auto& top = _M_dirs->top(); > + > + if (top.entry._M_type == file_type::directory) > + { > + _Dir dir = top.open_subdir(skip_permission_denied, nofollow, ec); > + if (!ec) > + { > + __glibcxx_assert(dir.dirp != nullptr); > + if (dir.advance(skip_permission_denied, ec)) > + { > + // Non-empty directory, recurse into it. > + _M_dirs->push(std::move(dir)); > + continue; > + } > + if (!ec) > + { > + // Directory is empty so we can remove it. > + if (top.rmdir(ec)) > + break; // Success > + } > + } > + } > + else if (top.unlink(ec)) > + break; // Success > + else if (top.entry._M_type == file_type::none) > + { > + // We did not have a cached type, so it's possible that top.entry > + // is actually a directory, and that's why the unlink above failed. > +#ifdef EPERM > + // POSIX.1-2017 says unlinking a directory returns EPERM, > + // but LSB allows EISDIR too. Some targets don't even define EPERM. > + if (ec.value() == EPERM || ec.value() == EISDIR) > +#else > + if (ec.value() == EISDIR) > +#endif
This doesn't work on Windows because the top.unlink(ec) sets a Windows error using the system category, so doesn't match the errno values here. I have a fix. > std::uintmax_t > fs::remove_all(const path& p) > { > - return fs::do_remove_all(p, ErrorReporter{"cannot remove all", p}); > + uintmax_t count = 0; > + auto st = filesystem::status(p); > + if (!exists(st)) > + return 0; > + if (is_directory(st)) Gah, this remove_all(const path&) overload was supposed to be using the same logic as the one below with an error_code parameter. I'll fix it on Monday.