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.

Reply via email to