From 3cb929a32af3986ad95ca511ea84d0863c29ce57 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 29 May 2019 23:00:53 +0100 Subject: [PATCH] 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(). 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: r271755 --- libstdc++-v3/ChangeLog | 11 +++++ 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, 97 insertions(+), 14 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b6b7a05..2005182 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,16 @@ 2019-05-29 Jonathan Wakely + 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. + * 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(); } -- 2.7.4