summaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely@redhat.com>2019-01-17 15:31:59 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2019-01-17 15:31:59 +0000
commitdd0f7ba27314978e77aab5d8da1eb6070805ee4c (patch)
tree634a3e08bd9424e9edbddd635c8537536747bcf5 /libstdc++-v3
parenta9e48eaadab4e73c7d87ea13439dda4ba76abb2b (diff)
PR libstdc++/88881 adjust filesystem::status and tests for mingw semantics
On Windows stat("foo/bar/../.") will resolve to "foo" even if that is a non-directory and "foo/bar" does not exist. This is the expected behaviour and consistent with boost::filesystem, so don't try to correct it. The only unwanted behaviour is that stat("baz/") fails due to a mingw bug (fixed in mingw-w64 v6.0.0) so add a workaround. PR libstdc++/88881 * src/c++17/fs_ops.cc (canonical(const path&, error_code&)) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Normalize path, to match behaviour of filesystem::exists. (create_directories(const path&, error_code&)): Add assertions. (status(const path&, error_code&)) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Add workaround for bug in _wstat for paths with trailing slash. * testsuite/27_io/filesystem/operations/create_directories.cc: Adjust for expected behaviour on mingw. * testsuite/experimental/filesystem/operations/create_directories.cc: Likewise. * testsuite/27_io/filesystem/operations/temp_directory_path.cc: Use "TMP" instead of "TMPDIR" and clean environment before each test. Do not test permissions on mingw targets. From-SVN: r268034
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog17
-rw-r--r--libstdc++-v3/src/c++17/fs_ops.cc38
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc19
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc13
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc14
5 files changed, 95 insertions, 6 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 2ed02544256..62d5db8b4e8 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,20 @@
+2019-01-17 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/88881
+ * src/c++17/fs_ops.cc (canonical(const path&, error_code&))
+ [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Normalize path, to match behaviour
+ of filesystem::exists.
+ (create_directories(const path&, error_code&)): Add assertions.
+ (status(const path&, error_code&)) [_GLIBCXX_FILESYSTEM_IS_WINDOWS]:
+ Add workaround for bug in _wstat for paths with trailing slash.
+ * testsuite/27_io/filesystem/operations/create_directories.cc: Adjust
+ for expected behaviour on mingw.
+ * testsuite/experimental/filesystem/operations/create_directories.cc:
+ Likewise.
+ * testsuite/27_io/filesystem/operations/temp_directory_path.cc: Use
+ "TMP" instead of "TMPDIR" and clean environment before each test. Do
+ not test permissions on mingw targets.
+
2019-01-16 Jonathan Wakely <jwakely@redhat.com>
* config/abi/pre/gnu.ver (GLIBCXX_3.4.26): Add exports for fstream
diff --git a/libstdc++-v3/src/c++17/fs_ops.cc b/libstdc++-v3/src/c++17/fs_ops.cc
index 7ece478b62a..5f8be5b7848 100644
--- a/libstdc++-v3/src/c++17/fs_ops.cc
+++ b/libstdc++-v3/src/c++17/fs_ops.cc
@@ -144,7 +144,11 @@ fs::path
fs::canonical(const path& p, error_code& ec)
{
path result;
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ const path pa = absolute(p.lexically_normal(), ec);
+#else
const path pa = absolute(p, ec);
+#endif
if (ec)
return result;
@@ -483,6 +487,9 @@ fs::create_directories(const path& p, error_code& ec)
return false;
}
+ __glibcxx_assert(st.type() == file_type::not_found);
+ // !exists(p) so there must be at least one non-existent component in p.
+
std::stack<path> missing;
path pp = p;
@@ -526,6 +533,8 @@ fs::create_directories(const path& p, error_code& ec)
}
while (st.type() == file_type::not_found);
+ __glibcxx_assert(!missing.empty());
+
bool created;
do
{
@@ -1318,8 +1327,35 @@ fs::file_status
fs::status(const fs::path& p, 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())
+ {
+ 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
+ {
+ p2.assign(s.substr(0, len));
+ }
+ __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::stat(p.c_str(), &st))
+ if (posix::stat(str, &st))
{
int err = errno;
ec.assign(err, std::generic_category());
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc
index 9ad5ef09f4a..c4411dfc1e7 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc
@@ -70,12 +70,20 @@ test01()
b = fs::create_directories( p/"./d4/../d5", ec );
VERIFY( !ec );
VERIFY( b );
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ // create_directories("./d4/..") is a no-op, does not create "d4"
+#else
VERIFY( is_directory(p/"d4") );
+#endif
VERIFY( is_directory(p/"d5") );
VERIFY( is_directory(p/"./d4/../d5") );
std::uintmax_t count = remove_all(p, ec);
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ VERIFY( count == 5 );
+#else
VERIFY( count == 6 );
+#endif
}
void
@@ -92,9 +100,11 @@ test02()
result = create_directories(file.path, ec);
VERIFY( !result );
VERIFY( ec == std::errc::not_a_directory );
+ ec.clear();
result = create_directories(file.path / "foo", ec);
VERIFY( !result );
VERIFY( ec == std::errc::not_a_directory );
+ ec.clear();
}
create_directories(p);
@@ -105,9 +115,18 @@ test02()
result = create_directories(file.path, ec);
VERIFY( !result );
VERIFY( ec == std::errc::not_a_directory );
+ ec.clear();
result = create_directories(file.path/"../bar", ec);
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ VERIFY( result );
+ VERIFY( !ec );
+ VERIFY( is_directory(dir.path/"bar") );
+ remove(dir.path/"bar");
+#else
VERIFY( !result );
VERIFY( ec == std::errc::not_a_directory );
+ VERIFY( !is_directory(dir.path/"bar") );
+#endif
}
}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
index b3ae66d7d64..2c8112f6742 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
@@ -75,7 +75,7 @@ test02()
{
clean_env();
- if (!set_env("TMPDIR", __gnu_test::nonexistent_path().string()))
+ if (!set_env("TMP", __gnu_test::nonexistent_path().string()))
return; // just give up
std::error_code ec;
@@ -95,6 +95,13 @@ test02()
void
test03()
{
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ // No permissions support
+ return;
+#endif
+
+ clean_env();
+
auto p = __gnu_test::nonexistent_path();
create_directories(p/"tmp");
permissions(p, fs::perms::none);
@@ -119,8 +126,10 @@ test03()
void
test04()
{
+ clean_env();
+
__gnu_test::scoped_file f;
- set_env("TMPDIR", f.path.string());
+ set_env("TMP", f.path.string());
std::error_code ec;
auto r = fs::temp_directory_path(ec);
VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc
index 5b3e3783af5..b6909b630d4 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directories.cc
@@ -63,12 +63,20 @@ test01()
b = fs::create_directories( p/"./d4/../d5", ec );
VERIFY( !ec );
VERIFY( b );
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ // create_directories("./d4/..") is a no-op, does not create "d4"
+#else
VERIFY( is_directory(p/"d4") );
+#endif
VERIFY( is_directory(p/"d5") );
VERIFY( is_directory(p/"./d4/../d5") );
std::uintmax_t count = remove_all(p, ec);
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ VERIFY( count == 5 );
+#else
VERIFY( count == 6 );
+#endif
}
void
@@ -87,8 +95,8 @@ test02()
VERIFY( ec == std::errc::not_a_directory );
result = create_directories(file.path / "foo", ec);
VERIFY( !result );
- __builtin_printf("%d\n", ec.value());
- VERIFY( ec == std::errc::not_a_directory );
+ VERIFY( ec );
+ ec.clear();
}
create_directories(p);
@@ -101,7 +109,7 @@ test02()
VERIFY( ec == std::errc::not_a_directory );
result = create_directories(file.path/"../bar", ec);
VERIFY( !result );
- VERIFY( ec == std::errc::not_a_directory );
+ VERIFY( ec );
}
}