aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2018-08-28 15:52:18 +0000
committerredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2018-08-28 15:52:18 +0000
commit92501a31fbf78453e7192d6afa31f793e28c2bc6 (patch)
treec31ba1397fddcc5ddf4886c6586ccc9579c6ed27 /libstdc++-v3
parente24ceb4802f0cc1bb9e498af6f5bdd29e556c34b (diff)
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-8-branch@263923 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog13
-rw-r--r--libstdc++-v3/src/filesystem/std-path.cc19
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc63
3 files changed, 88 insertions, 7 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index bac81d0ae87..1bf96df8f0f 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -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-13 Jonathan Wakely <jwakely@redhat.com>
Revert
diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc
index 6f594cec1d5..d5016e06138 100644
--- a/libstdc++-v3/src/filesystem/std-path.cc
+++ b/libstdc++-v3/src/filesystem/std-path.cc
@@ -378,7 +378,7 @@ path::lexically_normal() const
{
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
// Replace each slash character in the root-name
- if (p.is_root_name())
+ if (p._M_type == _Type::_Root_name || p._M_type == _Type::_Root_dir)
{
string_type s = p.native();
std::replace(s.begin(), s.end(), L'/', L'\\');
@@ -398,7 +398,8 @@ path::lexically_normal() const
}
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;
}
else
@@ -411,8 +412,18 @@ path::lexically_normal() const
{
// Remove the filename before the trailing slash
// (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 // ???
ret /= p;
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc
index 6d0e2007a75..3b8311f81ad 100644
--- a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc
@@ -24,7 +24,17 @@
#include <testsuite_hooks.h>
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
test01()
@@ -69,8 +79,11 @@ test03()
{"/foo" , "/foo" },
{"/foo/" , "/foo/" },
{"/foo/." , "/foo/" },
- {"/foo/bar/.." , "/foo/" },
{"/foo/.." , "/" },
+ {"/foo/../.." , "/" },
+ {"/foo/bar/.." , "/foo/" },
+ {"/foo/bar/../.." , "/" },
+ {"/foo/bar/baz/../../.." , "/" }, // PR libstdc++/87116
{"/." , "/" },
{"/./" , "/" },
@@ -88,10 +101,11 @@ test03()
{"foo/.." , "." },
{"foo/../" , "." },
{"foo/../.." , ".." },
+ {"foo/../../..", "../.." },
// with root name (OS-dependent):
#if defined(_WIN32) && !defined(__CYGWIN__)
- {"C:bar/.." , "C:." },
+ {"C:bar/.." , "C:" },
#else
{"C:bar/.." , "." },
#endif
@@ -119,10 +133,53 @@ test03()
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
main()
{
test01();
test02();
test03();
+ test04();
}