[gcc/devel/omp/gcc-9] PR libstdc++/88881 fix filesystem::symlink_status for Windows

Tobias Burnus burnus@gcc.gnu.org
Thu Mar 5 13:59:00 GMT 2020


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

commit e49b75413aaad8680cb4a14b0e242ffc1f2f0deb
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Jun 14 19:11:22 2019 +0100

    PR libstdc++/88881 fix filesystem::symlink_status for Windows
    
    The fix for PR 88881 only added a workaround to filesystem::status, but
    filesystem::symlink_status is also affected by the _wstat bug and needs
    the same workaround.
    
    The recent change to optimize path::parent_path() means that the
    workaround can be simplified to just use parent_path().
    
    Backport from mainline
    2019-05-29  Jonathan Wakely  <jwakely@redhat.com>
    
    	PR libstdc++/88881
    	* src/c++17/fs_ops.cc [_GLIBCXX_FILESYSTEM_IS_WINDOWS]
    	(status(const path&, error_code&)): Use parent_path() to remove
    	trailing slash.
    	(symlink_status(const path&, error_code&)): Duplicate workaround for
    	bug in _wstat for paths with trailing slash.
    	* testsuite/27_io/filesystem/operations/remove_all.cc: Check path
    	with trailing slash.
    	* testsuite/27_io/filesystem/operations/status.cc: Likewise.
    	* testsuite/27_io/filesystem/operations/symlink_status.cc: Likewise.
    
    From-SVN: r272304

Diff:
---
 libstdc++-v3/ChangeLog                             | 16 ++++++++
 libstdc++-v3/src/c++17/fs_ops.cc                   | 47 +++++++++++++++-------
 .../27_io/filesystem/operations/remove_all.cc      | 33 +++++++++++++++
 .../27_io/filesystem/operations/status.cc          | 10 +++++
 .../27_io/filesystem/operations/symlink_status.cc  | 10 +++++
 5 files changed, 102 insertions(+), 14 deletions(-)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index d4cb3be..78694e6 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -3,6 +3,22 @@
 	Backport from mainline
 	2019-05-29  Jonathan Wakely  <jwakely@redhat.com>
 
+	PR libstdc++/88881
+	* src/c++17/fs_ops.cc [_GLIBCXX_FILESYSTEM_IS_WINDOWS]
+	(status(const path&, error_code&)): Use parent_path() to remove
+	trailing slash.
+	(symlink_status(const path&, error_code&)): Duplicate workaround for
+	bug in _wstat for paths with trailing slash.
+	* testsuite/27_io/filesystem/operations/remove_all.cc: Check path
+	with trailing slash.
+	* testsuite/27_io/filesystem/operations/status.cc: Likewise.
+	* testsuite/27_io/filesystem/operations/symlink_status.cc: Likewise.
+
+2019-06-14  Jonathan Wakely  <jwakely@redhat.com>
+
+	Backport from mainline
+	2019-05-29  Jonathan Wakely  <jwakely@redhat.com>
+
 	* src/c++17/fs_path.cc (path::parent_path()): Create whole path at
 	once instead of building it iteratively.
 
diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc
index 274ee7f..d806481 100644
--- a/libstdc++-v3/src/c++17/fs_ops.cc
+++ b/libstdc++-v3/src/c++17/fs_ops.cc
@@ -1395,23 +1395,19 @@ fs::status(const fs::path& p, error_code& ec) noexcept
 #if ! defined __MINGW64_VERSION_MAJOR || __MINGW64_VERSION_MAJOR < 6
   // stat() fails if there's a trailing slash (PR 88881)
   path p2;
-  if (p.has_relative_path())
+  if (p.has_relative_path() && !p.has_filename())
     {
-      wstring_view s = p.native();
-      const auto len = s.find_last_not_of(L"/\\") + wstring_view::size_type(1);
-      if (len != 0 && len != s.length())
+      __try
 	{
-	  __try
-	    {
-	      p2.assign(s.substr(0, len));
-	    }
-	  __catch(const bad_alloc&)
-	    {
-	      ec = std::make_error_code(std::errc::not_enough_memory);
-	      return status;
-	    }
+	  p2 = p.parent_path();
 	  str = p2.c_str();
 	}
+      __catch(const bad_alloc&)
+	{
+	  ec = std::make_error_code(std::errc::not_enough_memory);
+	  return status;
+	}
+      str = p2.c_str();
     }
 #endif
 #endif
@@ -1440,8 +1436,31 @@ fs::file_status
 fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
 {
   file_status status;
+  auto str = p.c_str();
+
+#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
+#if ! defined __MINGW64_VERSION_MAJOR || __MINGW64_VERSION_MAJOR < 6
+  // stat() fails if there's a trailing slash (PR 88881)
+  path p2;
+  if (p.has_relative_path() && !p.has_filename())
+    {
+      __try
+	{
+	  p2 = p.parent_path();
+	  str = p2.c_str();
+	}
+      __catch(const bad_alloc&)
+	{
+	  ec = std::make_error_code(std::errc::not_enough_memory);
+	  return status;
+	}
+      str = p2.c_str();
+    }
+#endif
+#endif
+
   stat_type st;
-  if (posix::lstat(p.c_str(), &st))
+  if (posix::lstat(str, &st))
     {
       int err = errno;
       ec.assign(err, std::generic_category());
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 119dd3d..a19bac9 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
@@ -108,9 +108,42 @@ test02()
   VERIFY( !exists(dir) );
 }
 
+void
+test03()
+{
+  // PR libstdc++/88881 symlink_status confused by trailing slash on Windows
+  const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+  unsigned removed;
+  std::error_code ec = bad_ec;
+  const auto p = __gnu_test::nonexistent_path() / ""; // with trailing slash
+
+  create_directories(p);
+  removed = remove_all(p, ec);
+  VERIFY( !ec );
+  VERIFY( removed == 1 );
+  VERIFY( !exists(p) );
+  create_directories(p);
+  removed = remove_all(p);
+  VERIFY( removed == 1 );
+  VERIFY( !exists(p) );
+
+  const auto p_subs = p/"foo/bar";
+  ec = bad_ec;
+  create_directories(p_subs);
+  removed = remove_all(p, ec);
+  VERIFY( !ec );
+  VERIFY( removed == 3 );
+  VERIFY( !exists(p) );
+  create_directories(p_subs);
+  remove_all(p);
+  VERIFY( removed == 3 );
+  VERIFY( !exists(p) );
+}
+
 int
 main()
 {
   test01();
   test02();
+  test03();
 }
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc
index 38c0f65..b65a2f2 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc
@@ -93,10 +93,20 @@ test03()
   fs::permissions(dir, fs::perms::owner_all, ec);
 }
 
+void
+test04()
+{
+  // PR libstdc++/88881
+  fs::path p = "./";
+  auto st = status(p);
+  VERIFY( is_directory(st) );
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc
index 6f01419..c097e4f 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc
@@ -111,10 +111,20 @@ test03()
   fs::permissions(dir, fs::perms::owner_all, ec);
 }
 
+void
+test04()
+{
+  // PR libstdc++/88881
+  fs::path p = "./";
+  auto st = symlink_status(p);
+  VERIFY( is_directory(st) );
+}
+
 int
 main()
 {
   test01();
   test02();
   test03();
+  test04();
 }



More information about the Libstdc++-cvs mailing list