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
This commit is contained in:
parent
a9e48eaada
commit
dd0f7ba273
|
@ -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>
|
2019-01-16 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
* config/abi/pre/gnu.ver (GLIBCXX_3.4.26): Add exports for fstream
|
* config/abi/pre/gnu.ver (GLIBCXX_3.4.26): Add exports for fstream
|
||||||
|
|
|
@ -144,7 +144,11 @@ fs::path
|
||||||
fs::canonical(const path& p, error_code& ec)
|
fs::canonical(const path& p, error_code& ec)
|
||||||
{
|
{
|
||||||
path result;
|
path result;
|
||||||
|
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
|
||||||
|
const path pa = absolute(p.lexically_normal(), ec);
|
||||||
|
#else
|
||||||
const path pa = absolute(p, ec);
|
const path pa = absolute(p, ec);
|
||||||
|
#endif
|
||||||
if (ec)
|
if (ec)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
@ -483,6 +487,9 @@ fs::create_directories(const path& p, error_code& ec)
|
||||||
return false;
|
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;
|
std::stack<path> missing;
|
||||||
path pp = p;
|
path pp = p;
|
||||||
|
|
||||||
|
@ -526,6 +533,8 @@ fs::create_directories(const path& p, error_code& ec)
|
||||||
}
|
}
|
||||||
while (st.type() == file_type::not_found);
|
while (st.type() == file_type::not_found);
|
||||||
|
|
||||||
|
__glibcxx_assert(!missing.empty());
|
||||||
|
|
||||||
bool created;
|
bool created;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -1318,8 +1327,35 @@ fs::file_status
|
||||||
fs::status(const fs::path& p, error_code& ec) noexcept
|
fs::status(const fs::path& p, error_code& ec) noexcept
|
||||||
{
|
{
|
||||||
file_status status;
|
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;
|
stat_type st;
|
||||||
if (posix::stat(p.c_str(), &st))
|
if (posix::stat(str, &st))
|
||||||
{
|
{
|
||||||
int err = errno;
|
int err = errno;
|
||||||
ec.assign(err, std::generic_category());
|
ec.assign(err, std::generic_category());
|
||||||
|
|
|
@ -70,12 +70,20 @@ test01()
|
||||||
b = fs::create_directories( p/"./d4/../d5", ec );
|
b = fs::create_directories( p/"./d4/../d5", ec );
|
||||||
VERIFY( !ec );
|
VERIFY( !ec );
|
||||||
VERIFY( b );
|
VERIFY( b );
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
// create_directories("./d4/..") is a no-op, does not create "d4"
|
||||||
|
#else
|
||||||
VERIFY( is_directory(p/"d4") );
|
VERIFY( is_directory(p/"d4") );
|
||||||
|
#endif
|
||||||
VERIFY( is_directory(p/"d5") );
|
VERIFY( is_directory(p/"d5") );
|
||||||
VERIFY( is_directory(p/"./d4/../d5") );
|
VERIFY( is_directory(p/"./d4/../d5") );
|
||||||
|
|
||||||
std::uintmax_t count = remove_all(p, ec);
|
std::uintmax_t count = remove_all(p, ec);
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
VERIFY( count == 5 );
|
||||||
|
#else
|
||||||
VERIFY( count == 6 );
|
VERIFY( count == 6 );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -92,9 +100,11 @@ test02()
|
||||||
result = create_directories(file.path, ec);
|
result = create_directories(file.path, ec);
|
||||||
VERIFY( !result );
|
VERIFY( !result );
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
VERIFY( ec == std::errc::not_a_directory );
|
||||||
|
ec.clear();
|
||||||
result = create_directories(file.path / "foo", ec);
|
result = create_directories(file.path / "foo", ec);
|
||||||
VERIFY( !result );
|
VERIFY( !result );
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
VERIFY( ec == std::errc::not_a_directory );
|
||||||
|
ec.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
create_directories(p);
|
create_directories(p);
|
||||||
|
@ -105,9 +115,18 @@ test02()
|
||||||
result = create_directories(file.path, ec);
|
result = create_directories(file.path, ec);
|
||||||
VERIFY( !result );
|
VERIFY( !result );
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
VERIFY( ec == std::errc::not_a_directory );
|
||||||
|
ec.clear();
|
||||||
result = create_directories(file.path/"../bar", ec);
|
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( !result );
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
VERIFY( ec == std::errc::not_a_directory );
|
||||||
|
VERIFY( !is_directory(dir.path/"bar") );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ test02()
|
||||||
{
|
{
|
||||||
clean_env();
|
clean_env();
|
||||||
|
|
||||||
if (!set_env("TMPDIR", __gnu_test::nonexistent_path().string()))
|
if (!set_env("TMP", __gnu_test::nonexistent_path().string()))
|
||||||
return; // just give up
|
return; // just give up
|
||||||
|
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
@ -95,6 +95,13 @@ test02()
|
||||||
void
|
void
|
||||||
test03()
|
test03()
|
||||||
{
|
{
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
// No permissions support
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
clean_env();
|
||||||
|
|
||||||
auto p = __gnu_test::nonexistent_path();
|
auto p = __gnu_test::nonexistent_path();
|
||||||
create_directories(p/"tmp");
|
create_directories(p/"tmp");
|
||||||
permissions(p, fs::perms::none);
|
permissions(p, fs::perms::none);
|
||||||
|
@ -119,8 +126,10 @@ test03()
|
||||||
void
|
void
|
||||||
test04()
|
test04()
|
||||||
{
|
{
|
||||||
|
clean_env();
|
||||||
|
|
||||||
__gnu_test::scoped_file f;
|
__gnu_test::scoped_file f;
|
||||||
set_env("TMPDIR", f.path.string());
|
set_env("TMP", f.path.string());
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
auto r = fs::temp_directory_path(ec);
|
auto r = fs::temp_directory_path(ec);
|
||||||
VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
|
VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
|
||||||
|
|
|
@ -63,12 +63,20 @@ test01()
|
||||||
b = fs::create_directories( p/"./d4/../d5", ec );
|
b = fs::create_directories( p/"./d4/../d5", ec );
|
||||||
VERIFY( !ec );
|
VERIFY( !ec );
|
||||||
VERIFY( b );
|
VERIFY( b );
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
// create_directories("./d4/..") is a no-op, does not create "d4"
|
||||||
|
#else
|
||||||
VERIFY( is_directory(p/"d4") );
|
VERIFY( is_directory(p/"d4") );
|
||||||
|
#endif
|
||||||
VERIFY( is_directory(p/"d5") );
|
VERIFY( is_directory(p/"d5") );
|
||||||
VERIFY( is_directory(p/"./d4/../d5") );
|
VERIFY( is_directory(p/"./d4/../d5") );
|
||||||
|
|
||||||
std::uintmax_t count = remove_all(p, ec);
|
std::uintmax_t count = remove_all(p, ec);
|
||||||
|
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||||
|
VERIFY( count == 5 );
|
||||||
|
#else
|
||||||
VERIFY( count == 6 );
|
VERIFY( count == 6 );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -87,8 +95,8 @@ test02()
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
VERIFY( ec == std::errc::not_a_directory );
|
||||||
result = create_directories(file.path / "foo", ec);
|
result = create_directories(file.path / "foo", ec);
|
||||||
VERIFY( !result );
|
VERIFY( !result );
|
||||||
__builtin_printf("%d\n", ec.value());
|
VERIFY( ec );
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
ec.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
create_directories(p);
|
create_directories(p);
|
||||||
|
@ -101,7 +109,7 @@ test02()
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
VERIFY( ec == std::errc::not_a_directory );
|
||||||
result = create_directories(file.path/"../bar", ec);
|
result = create_directories(file.path/"../bar", ec);
|
||||||
VERIFY( !result );
|
VERIFY( !result );
|
||||||
VERIFY( ec == std::errc::not_a_directory );
|
VERIFY( ec );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue