PR libstdc++/87116 fix path::lexically_normal() handling of dot-dot
Previously the logic that turned "a/b/c/../.." into "a/" failed to preserve an empty path at the end of the iteration sequence, as required by the trailing slash. That meant the result didn't meet the class invariants, and that "a/b/c/d/../../.." would remove four components instead of the three that "../../.." should remove. PR libstdc++/87116 * src/filesystem/std-path.cc (path::lexically_normal): When handling a dot-dot filename, preserve an empty final component in the iteration sequence. [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Use preferred-separator for root-directory. * testsuite/27_io/filesystem/path/generation/normal.cc: Add new tests for more than two adjacent dot-dot filenames. [_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Replace slashes with preferred-separator in expected normalized strings. From-SVN: r263922
This commit is contained in:
parent
f30bafb7fc
commit
dd35da2cbe
|
@ -1,3 +1,16 @@
|
||||||
|
2018-08-28 Jonathan Wakely <jwakely@redhat.com>
|
||||||
|
|
||||||
|
PR libstdc++/87116
|
||||||
|
* src/filesystem/std-path.cc (path::lexically_normal): When handling
|
||||||
|
a dot-dot filename, preserve an empty final component in the iteration
|
||||||
|
sequence.
|
||||||
|
[_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Use preferred-separator for
|
||||||
|
root-directory.
|
||||||
|
* testsuite/27_io/filesystem/path/generation/normal.cc: Add new tests
|
||||||
|
for more than two adjacent dot-dot filenames.
|
||||||
|
[_GLIBCXX_FILESYSTEM_IS_WINDOWS]: Replace slashes with
|
||||||
|
preferred-separator in expected normalized strings.
|
||||||
|
|
||||||
2018-08-25 Iain Sandoe <iain@sandoe.co.uk>
|
2018-08-25 Iain Sandoe <iain@sandoe.co.uk>
|
||||||
|
|
||||||
PR libstdc++/70694
|
PR libstdc++/70694
|
||||||
|
|
|
@ -438,7 +438,7 @@ path::lexically_normal() const
|
||||||
{
|
{
|
||||||
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
|
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
|
||||||
// Replace each slash character in the root-name
|
// Replace each slash character in the root-name
|
||||||
if (p._M_type == _Type::_Root_name)
|
if (p._M_type == _Type::_Root_name || p._M_type == _Type::_Root_dir)
|
||||||
{
|
{
|
||||||
string_type s = p.native();
|
string_type s = p.native();
|
||||||
std::replace(s.begin(), s.end(), L'/', L'\\');
|
std::replace(s.begin(), s.end(), L'/', L'\\');
|
||||||
|
@ -458,7 +458,8 @@ path::lexically_normal() const
|
||||||
}
|
}
|
||||||
else if (!ret.has_relative_path())
|
else if (!ret.has_relative_path())
|
||||||
{
|
{
|
||||||
if (!ret.is_absolute())
|
// remove a dot-dot filename immediately after root-directory
|
||||||
|
if (!ret.has_root_directory())
|
||||||
ret /= p;
|
ret /= p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -471,8 +472,18 @@ path::lexically_normal() const
|
||||||
{
|
{
|
||||||
// Remove the filename before the trailing slash
|
// Remove the filename before the trailing slash
|
||||||
// (equiv. to ret = ret.parent_path().remove_filename())
|
// (equiv. to ret = ret.parent_path().remove_filename())
|
||||||
ret._M_pathname.erase(elem._M_cur->_M_pos);
|
|
||||||
ret._M_cmpts.erase(elem._M_cur, ret._M_cmpts.end());
|
if (elem == ret.begin())
|
||||||
|
ret.clear();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret._M_pathname.erase(elem._M_cur->_M_pos);
|
||||||
|
// Do we still have a trailing slash?
|
||||||
|
if (std::prev(elem)->_M_type == _Type::_Filename)
|
||||||
|
ret._M_cmpts.erase(elem._M_cur);
|
||||||
|
else
|
||||||
|
ret._M_cmpts.erase(elem._M_cur, ret._M_cmpts.end());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else // ???
|
else // ???
|
||||||
ret /= p;
|
ret /= p;
|
||||||
|
|
|
@ -24,7 +24,17 @@
|
||||||
#include <testsuite_hooks.h>
|
#include <testsuite_hooks.h>
|
||||||
|
|
||||||
using std::filesystem::path;
|
using std::filesystem::path;
|
||||||
using __gnu_test::compare_paths;
|
|
||||||
|
void
|
||||||
|
compare_paths(path p, std::string expected)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
for (auto& c : expected)
|
||||||
|
if (c == '/')
|
||||||
|
c = '\\';
|
||||||
|
#endif
|
||||||
|
__gnu_test::compare_paths(p, expected);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
test01()
|
test01()
|
||||||
|
@ -69,8 +79,11 @@ test03()
|
||||||
{"/foo" , "/foo" },
|
{"/foo" , "/foo" },
|
||||||
{"/foo/" , "/foo/" },
|
{"/foo/" , "/foo/" },
|
||||||
{"/foo/." , "/foo/" },
|
{"/foo/." , "/foo/" },
|
||||||
{"/foo/bar/.." , "/foo/" },
|
|
||||||
{"/foo/.." , "/" },
|
{"/foo/.." , "/" },
|
||||||
|
{"/foo/../.." , "/" },
|
||||||
|
{"/foo/bar/.." , "/foo/" },
|
||||||
|
{"/foo/bar/../.." , "/" },
|
||||||
|
{"/foo/bar/baz/../../.." , "/" }, // PR libstdc++/87116
|
||||||
|
|
||||||
{"/." , "/" },
|
{"/." , "/" },
|
||||||
{"/./" , "/" },
|
{"/./" , "/" },
|
||||||
|
@ -88,10 +101,11 @@ test03()
|
||||||
{"foo/.." , "." },
|
{"foo/.." , "." },
|
||||||
{"foo/../" , "." },
|
{"foo/../" , "." },
|
||||||
{"foo/../.." , ".." },
|
{"foo/../.." , ".." },
|
||||||
|
{"foo/../../..", "../.." },
|
||||||
|
|
||||||
// with root name (OS-dependent):
|
// with root name (OS-dependent):
|
||||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
{"C:bar/.." , "C:." },
|
{"C:bar/.." , "C:" },
|
||||||
#else
|
#else
|
||||||
{"C:bar/.." , "." },
|
{"C:bar/.." , "." },
|
||||||
#endif
|
#endif
|
||||||
|
@ -119,10 +133,53 @@ test03()
|
||||||
compare_paths( path(test.input).lexically_normal(), test.normalized );
|
compare_paths( path(test.input).lexically_normal(), test.normalized );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
test04()
|
||||||
|
{
|
||||||
|
// PR libstdc++/87116
|
||||||
|
path p = "a/b/c";
|
||||||
|
compare_paths( (p/"../..").lexically_normal(), "a/" );
|
||||||
|
|
||||||
|
p = "a/b/c/d/e";
|
||||||
|
compare_paths( (p/"..").lexically_normal(), "a/b/c/d/" );
|
||||||
|
compare_paths( (p/"../..").lexically_normal(), "a/b/c/" );
|
||||||
|
compare_paths( (p/"../../..").lexically_normal(), "a/b/" );
|
||||||
|
compare_paths( (p/"../../../..").lexically_normal(), "a/" );
|
||||||
|
compare_paths( (p/"../../../../..").lexically_normal(), "." );
|
||||||
|
compare_paths( (p/"../../../../../..").lexically_normal(), ".." );
|
||||||
|
|
||||||
|
p = "/a/b/c/d/e";
|
||||||
|
compare_paths( (p/"..").lexically_normal(), "/a/b/c/d/" );
|
||||||
|
compare_paths( (p/"../..").lexically_normal(), "/a/b/c/" );
|
||||||
|
compare_paths( (p/"../../..").lexically_normal(), "/a/b/" );
|
||||||
|
compare_paths( (p/"../../../..").lexically_normal(), "/a/" );
|
||||||
|
compare_paths( (p/"../../../../..").lexically_normal(), "/" );
|
||||||
|
compare_paths( (p/"../../../../../..").lexically_normal(), "/" );
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
p = "A:b/c/d/e";
|
||||||
|
compare_paths( (p/"..").lexically_normal(), "A:b/c/d/" );
|
||||||
|
compare_paths( (p/"../..").lexically_normal(), "A:b/c/" );
|
||||||
|
compare_paths( (p/"../../..").lexically_normal(), "A:b/" );
|
||||||
|
compare_paths( (p/"../../../..").lexically_normal(), "A:" );
|
||||||
|
compare_paths( (p/"../../../../..").lexically_normal(), "A:.." );
|
||||||
|
compare_paths( (p/"../../../../../..").lexically_normal(), "A:../.." );
|
||||||
|
|
||||||
|
p = "A:/b/c/d/e";
|
||||||
|
compare_paths( (p/"..").lexically_normal(), "A:/b/c/d/" );
|
||||||
|
compare_paths( (p/"../..").lexically_normal(), "A:/b/c/" );
|
||||||
|
compare_paths( (p/"../../..").lexically_normal(), "A:/b/" );
|
||||||
|
compare_paths( (p/"../../../..").lexically_normal(), "A:/" );
|
||||||
|
compare_paths( (p/"../../../../..").lexically_normal(), "A:/" );
|
||||||
|
compare_paths( (p/"../../../../../..").lexically_normal(), "A:/" );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
test01();
|
test01();
|
||||||
test02();
|
test02();
|
||||||
test03();
|
test03();
|
||||||
|
test04();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue