+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
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;
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;
}
while (st.type() == file_type::not_found);
+ __glibcxx_assert(!missing.empty());
+
bool created;
do
{
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());
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
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);
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
}
}
{
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;
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);
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) );
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
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);
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 );
}
}