mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-12-22 18:45:10 +08:00
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>
|
||||
|
||||
* 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)
|
||||
{
|
||||
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());
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) );
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user