https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93201

            Bug ID: 93201
           Summary: std::filesystem::remove_all fails to remove large
                    files
           Product: gcc
           Version: 9.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: redi at gcc dot gnu.org
  Target Milestone: ---

#include <fstream>
#include <filesystem>

int main(int argc, char** argv)
{
  if (argc < 2)
    return 1;
  std::filesystem::path dir(argv[1]);
  std::error_code ec;
  create_directory(dir, ec); // ignore errors
  std::ofstream file{dir/"file"};
  std::string s;
  s.resize(1 << 20);
  for (unsigned i = 1 << 12; i; --i)
    file.write(s.data(), s.size());
  remove_all(dir);
}

With GCC 9 this fails to remove the directory:

tmp$ ./a.out out
terminate called after throwing an instance of
'std::filesystem::__cxx11::filesystem_error'
  what():  filesystem error: cannot remove all: Directory not empty [out]
Aborted (core dumped)
tmp$ ls -l out
total 4194304
-rw-rw-r--. 1 jwakely jwakely 4294967296 Jan  8 12:01 file

The problem is that remove_all("dir/file", ec) calls status("dir/file", ec)
which fails (with the same error as PR 91947 comment 2), but then the call to
d.increment(ec) clears the error_code:

  if (s.type() == file_type::directory)
    {
      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;
    }

This means that the "if (ec)" test only ever fails if d.increment(ec)
encounters an error.

The testcase works correctly on trunk because std::filesystem is built with
LFS, but the remove_all bug that clears the error_code is still latent on
trunk.

Reply via email to