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

--- Comment #5 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jonathan Wakely <[email protected]>:

https://gcc.gnu.org/g:f7094fe5ff882f0c206d51ebe93f33f0193ce636

commit r17-4804-gf7094fe5ff882f0c206d51ebe93f33f0193ce636
Author: Gokbey Gazi Keskin <[email protected]>
Date:   Mon Sep 28 14:42:20 2026 +0300

    libstdc++: Fix remove_all without unlinkat or dirent::d_type [PR127555]

    When neither unlinkat nor dirent::d_type is available, _Dir::advance
    leaves every entry with file_type::none, so __erase takes the unlink
    path.  Without unlinkat _Dir::do_unlink ignores its is_directory
    argument and always calls fs::remove, i.e. ::remove, which retries as
    rmdir for a directory.  Unlinking a non-empty directory therefore
    reports the rmdir errno for "not empty" rather than the EPERM or EISDIR
    that unlink on a directory would give, the retry-as-directory path is
    not taken, and remove_all fails with (uintmax_t)-1 on the first
    non-empty sub-directory.  POSIX allows either ENOTEMPTY or EEXIST for
    that condition, so accept both, but only when unlinkat is unavailable.

    An empty directory of unknown type is still removed correctly, because
    ::remove falls back to rmdir and succeeds, so reproducing this needs a
    tree at least two levels deep.

            PR libstdc++/127555

    libstdc++-v3/ChangeLog:

            * src/c++17/fs_dir.cc (recursive_directory_iterator::__erase):
            Retry as a directory when unlink fails with ENOTEMPTY or EEXIST
            and unlinkat is not available.

    Signed-off-by: Gokbey Gazi Keskin <[email protected]>

Reply via email to