https://gcc.gnu.org/g:92bfcd8a041bdf32c2c1098ad9cc6734eaf973e7
commit r17-2009-g92bfcd8a041bdf32c2c1098ad9cc6734eaf973e7 Author: Adam Wood <[email protected]> Date: Mon Jun 29 21:42:59 2026 -0600 libstdc++: Test that fs::remove and fs::remove_all do not follow symlinks Test that fs::remove and fs::remove_all delete an initial directory symlink instead of following it. Also test that fs::remove_all delete symlinks inside a directory rather than following them. libstdc++-v3/ChangeLog: * testsuite/27_io/filesystem/operations/remove.cc: Check that fs::remove deletes symlink instead of target. * testsuite/27_io/filesystem/operations/remove_all.cc: Likewise. Diff: --- .../27_io/filesystem/operations/remove.cc | 19 ++++++++++ .../27_io/filesystem/operations/remove_all.cc | 40 +++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove.cc index 50b1b7647167..858884517dd3 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove.cc @@ -68,6 +68,25 @@ test01() const auto dir = __gnu_test::nonexistent_path(); create_directories(dir/"a/b"); + +#ifndef NO_SYMLINKS + create_directories(dir/"real"); + create_directory_symlink(dir/"real", dir/"link"); + + ec = bad_ec; + n = remove(dir/"link", ec); + VERIFY( !ec ); + VERIFY( exists(dir/"real") ); + VERIFY( !exists(symlink_status(dir/"link")) ); + VERIFY( n ); + + ec = bad_ec; + n = remove(dir/"real", ec); + VERIFY( !ec ); + VERIFY( !exists(dir/"real") ); + VERIFY( n ); +#endif + ec.clear(); n = remove(dir/"a", ec); VERIFY( ec ); diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc index 16c215ce9996..f29e05086ef0 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc @@ -61,7 +61,7 @@ test01() #endif const auto dir = __gnu_test::nonexistent_path(); - create_directories(dir/"a/b/c"); + create_directories(dir/"a"/"b"/"c"); ec = bad_ec; n = remove_all(dir/"a", ec); VERIFY( !ec ); @@ -69,6 +69,44 @@ test01() VERIFY( exists(dir) ); VERIFY( !exists(dir/"a") ); +#ifndef NO_SYMLINKS + // Test that remove_all does not follow an initial directory symlink. + create_directories(dir/"real"); + create_directory_symlink(dir/"real", dir/"link"); + + ec = bad_ec; + n = remove_all(dir/"link", ec); + VERIFY( !ec ); + VERIFY( exists(dir/"real") ); + VERIFY( !exists(symlink_status(dir/"link")) ); + VERIFY( n == 1 ); + + ec = bad_ec; + n = remove_all(dir/"real", ec); + VERIFY( !ec ); + VERIFY( !exists(dir/"real") ); + VERIFY( n == 1 ); + + // Test that remove_all does not follow symlinks inside the directory. + create_directories(dir/"subdir"); + create_directories(dir/"target_dir"); + __gnu_test::scoped_file f2(dir/"target_file"); + create_directory_symlink(dir/"target_dir", dir/"subdir"/"link_dir"); + create_symlink(dir/"target_file", dir/"subdir"/"link_file"); + + ec = bad_ec; + n = remove_all(dir/"subdir", ec); + VERIFY( !ec ); + VERIFY( exists(dir/"target_dir") ); + VERIFY( exists(dir/"target_file") ); + VERIFY( !exists(dir/"subdir") ); + VERIFY( n == 3 ); + + f2.path.clear(); + remove(dir/"target_dir"); + remove(dir/"target_file"); +#endif + create_directories(dir/"a/b/c"); __gnu_test::scoped_file a1(dir/"a/1"); __gnu_test::scoped_file a2(dir/"a/2");
