From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2140) id 615B3384147F; Mon, 27 Jun 2022 13:35:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 615B3384147F Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Alexandre Oliva To: gcc-cvs@gcc.gnu.org, libstdc++-cvs@gcc.gnu.org Subject: [gcc(refs/users/aoliva/heads/testme)] libstdc++: retry removal of dir entries if dir removal fails X-Act-Checkin: gcc X-Git-Author: Alexandre Oliva X-Git-Refname: refs/users/aoliva/heads/testme X-Git-Oldrev: 5bde8cf8d7378a991aa2d8683312b60d092b69f9 X-Git-Newrev: b48f65918a6797ce8024d19412762b742d875405 Message-Id: <20220627133544.615B3384147F@sourceware.org> Date: Mon, 27 Jun 2022 13:35:44 +0000 (GMT) X-BeenThere: libstdc++-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 27 Jun 2022 13:35:44 -0000 https://gcc.gnu.org/g:b48f65918a6797ce8024d19412762b742d875405 commit b48f65918a6797ce8024d19412762b742d875405 Author: Alexandre Oliva Date: Mon Jun 27 05:30:54 2022 -0300 libstdc++: retry removal of dir entries if dir removal fails On some target systems (e.g. rtems6.0), removing directory components while iterating over directory entries may cause some of the directory entries to be skipped, which prevents the removal of the parent directory from succeeding. Advancing the iterator before removing a member proved not to be enough, so I've instead arranged for remove_all to retry the removal of components if the removal of the parent dir fails after removing at least one entry. The fail will be permanent only if no components got removed in the current try. for libstdc++-v3/ChangeLog * src/c++17/fs_ops.cc (remove_all): Retry removal of directory entries. Diff: --- libstdc++-v3/src/c++17/fs_ops.cc | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc index 435368fa5c5..de99e02af4c 100644 --- a/libstdc++-v3/src/c++17/fs_ops.cc +++ b/libstdc++-v3/src/c++17/fs_ops.cc @@ -1286,6 +1286,8 @@ fs::remove_all(const path& p) { error_code ec; uintmax_t count = 0; + retry: + uintmax_t init_count = count; recursive_directory_iterator dir(p, directory_options{64|128}, ec); switch (ec.value()) // N.B. assumes ec.category() == std::generic_category() { @@ -1295,7 +1297,16 @@ fs::remove_all(const path& p) const recursive_directory_iterator end; while (dir != end) { - dir.__erase(); // throws on error + /* Avoid exceptions if we may retry on fail on systems that + miss dir entries when removing while iterating. */ + if (count > init_count) + { + dir.__erase(&ec); + if (ec) + goto retry; + } + else + dir.__erase(); // throws on error ++count; } } @@ -1303,7 +1314,7 @@ fs::remove_all(const path& p) break; case ENOENT: // Our work here is done. - return 0; + return count; case ENOTDIR: case ELOOP: // Not a directory, will remove below. @@ -1313,6 +1324,18 @@ fs::remove_all(const path& p) _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec)); } + if (count > init_count) + { + if (int last = fs::remove(p, ec); !ec) + return count + last; + else + // Some systems seem to skip entries in the dir iteration if + // you remove dir entries while iterating, so if we removed + // anything in the dir in this round, and failed to remove + // the dir (presumably because it wasn't empty), retry. + goto retry; + } + // Remove p itself, which is either a non-directory or is now empty. return count + fs::remove(p); } @@ -1321,6 +1344,8 @@ std::uintmax_t fs::remove_all(const path& p, error_code& ec) { uintmax_t count = 0; + retry: + uintmax_t init_count = count; recursive_directory_iterator dir(p, directory_options{64|128}, ec); switch (ec.value()) // N.B. assumes ec.category() == std::generic_category() { @@ -1332,7 +1357,12 @@ fs::remove_all(const path& p, error_code& ec) { dir.__erase(&ec); if (ec) - return -1; + { + if (count > init_count) + goto retry; + else + return -1; + } ++count; } } @@ -1341,7 +1371,7 @@ fs::remove_all(const path& p, error_code& ec) case ENOENT: // Our work here is done. ec.clear(); - return 0; + return count; case ENOTDIR: case ELOOP: // Not a directory, will remove below. @@ -1354,6 +1384,8 @@ fs::remove_all(const path& p, error_code& ec) // Remove p itself, which is either a non-directory or is now empty. if (int last = fs::remove(p, ec); !ec) return count + last; + if (count > init_count) + goto retry; return -1; }