From 2b462958e2db15dc6f55ed361d47cdbc62d64ea0 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Thu, 13 Dec 2018 20:34:10 +0000 Subject: [PATCH] Fix handling of POSIX paths containing a root-name Fix path appending and concatenating to work correctly for a leading root-name. Check a new macro, SLASHSLASH_IS_ROOT_NAME, instead of making the behaviour depend directly on __CYGWIN__. * src/filesystem/std-path.cc (SLASHSLASH_IS_ROOT_NAME): New macro to control whether interpret paths with two slashes as a root-name. (path::operator/=(const path&)) [SLASHSLASH_IS_ROOT_NAME]: Add a root-directory when appending to a root-name. (path::_M_append(basic_string_view)) [SLASHSLASH_IS_ROOT_NAME]: Likewise. (path::operator/=(const path&)) [SLASHSLASH_IS_ROOT_NAME]: Likewise. (path::_M_concat(basic_string_view)) [SLASHSLASH_IS_ROOT_NAME]: Likewise. (path::lexically_normal()) [SLASHSLASH_IS_ROOT_NAME]: Use += instead of /= to add a root-directory to the result. * testsuite/27_io/filesystem/path/decompose/root_directory.cc: Fix expected result for Cygwin. From-SVN: r267107 --- libstdc++-v3/ChangeLog | 14 ++++ libstdc++-v3/src/filesystem/std-path.cc | 84 ++++++++++++++++--- .../path/decompose/root_directory.cc | 4 + 3 files changed, 91 insertions(+), 11 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index c1a25028f25..a4f6507c2bb 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,19 @@ 2018-12-13 Jonathan Wakely + * src/filesystem/std-path.cc (SLASHSLASH_IS_ROOT_NAME): New macro to + control whether interpret paths with two slashes as a root-name. + (path::operator/=(const path&)) [SLASHSLASH_IS_ROOT_NAME]: Add a + root-directory when appending to a root-name. + (path::_M_append(basic_string_view)) + [SLASHSLASH_IS_ROOT_NAME]: Likewise. + (path::operator/=(const path&)) [SLASHSLASH_IS_ROOT_NAME]: Likewise. + (path::_M_concat(basic_string_view)) + [SLASHSLASH_IS_ROOT_NAME]: Likewise. + (path::lexically_normal()) [SLASHSLASH_IS_ROOT_NAME]: Use += instead + of /= to add a root-directory to the result. + * testsuite/27_io/filesystem/path/decompose/root_directory.cc: Fix + expected result for Cygwin. + PR libstdc++/71044 * include/bits/fs_path.h (path::path(path&&)): Add noexcept when appropriate. Move _M_cmpts instead of reparsing the native pathname. diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc index e9c78924b8e..d2520492c03 100644 --- a/libstdc++-v3/src/filesystem/std-path.cc +++ b/libstdc++-v3/src/filesystem/std-path.cc @@ -26,6 +26,11 @@ # define _GLIBCXX_USE_CXX11_ABI 1 #endif +#ifdef __CYGWIN__ +// Interpret "//x" as a root-name, not root-dir + filename +# define SLASHSLASH_IS_ROOTNAME 1 +#endif + #include #include #include @@ -70,7 +75,7 @@ struct path::_Parser // look for root name or root directory if (is_dir_sep(input[0])) { -#ifdef __CYGWIN__ +#if SLASHSLASH_IS_ROOTNAME // look for root name, such as "//foo" if (len > 2 && input[1] == input[0]) { @@ -515,7 +520,7 @@ path::operator/=(const path& __p) string_view_type sep; if (has_filename()) sep = { &preferred_separator, 1 }; // need to add a separator -#ifdef __CYGWIN__ +#if SLASHSLASH_IS_ROOTNAME else if (_M_type() == _Type::_Root_name) // root-name with no root-dir sep = { &preferred_separator, 1 }; // need to add a separator #endif @@ -535,6 +540,10 @@ path::operator/=(const path& __p) capacity += __p._M_cmpts.size(); else if (!__p.empty() || !sep.empty()) capacity += 1; +#if SLASHSLASH_IS_ROOTNAME + if (orig_type == _Type::_Root_name) + ++capacity; // Need to insert root-directory after root-name +#endif if (orig_type == _Type::_Multi) { @@ -568,6 +577,14 @@ path::operator/=(const path& __p) string_view_type s(_M_pathname.data(), orig_pathlen); ::new(output++) _Cmpt(s, orig_type, 0); ++_M_cmpts._M_impl->_M_size; +#if SLASHSLASH_IS_ROOTNAME + if (orig_type == _Type::_Root_name) + { + ::new(output++) _Cmpt(sep, _Type::_Root_dir, + orig_pathlen + sep.length()); + ++_M_cmpts._M_impl->_M_size; + } +#endif } if (__p._M_type() == _Type::_Multi) @@ -668,7 +685,7 @@ path::_M_append(basic_string_view s) basic_string_view sep; if (has_filename()) sep = { &preferred_separator, 1 }; // need to add a separator -#ifdef __CYGWIN__ +#if SLASHSLASH_IS_ROOTNAME else if (_M_type() == _Type::_Root_name) // root-name with no root-dir sep = { &preferred_separator, 1 }; // need to add a separator #endif @@ -723,6 +740,11 @@ path::_M_append(basic_string_view s) else if (!sep.empty()) ++capacity; +#if SLASHSLASH_IS_ROOTNAME + if (orig_type == _Type::_Root_name) + ++capacity; // Need to insert root-directory after root-name +#endif + __try { _M_cmpts.type(_Type::_Multi); @@ -740,6 +762,15 @@ path::_M_append(basic_string_view s) // Create single component from original path ::new(output++) _Cmpt(orig_pathname, orig_type, 0); ++_M_cmpts._M_impl->_M_size; + +#if SLASHSLASH_IS_ROOTNAME + if (!sep.empty() && orig_type == _Type::_Root_name) + { + ::new(output++) _Cmpt(sep, _Type::_Root_dir, + orig_pathlen + sep.length()); + ++_M_cmpts._M_impl->_M_size; + } +#endif } if (next != buf.begin()) @@ -823,7 +854,11 @@ path::operator+=(const path& p) { // See if there's a filename or root-name at the end of the original path // that we can add to. - if (_M_type() == _Type::_Filename) + if (_M_type() == _Type::_Filename +#if SLASHSLASH_IS_ROOTNAME + || _M_type() == _Type::_Root_name +#endif + ) { if (p._M_type() == _Type::_Filename) { @@ -858,8 +893,6 @@ path::operator+=(const path& p) && _M_cmpts.back()._M_type() == _Type::_Filename) orig_filenamelen = 0; // current path has empty filename at end - // TODO handle "//rootname" + "foo" case for Cygwin. - int capacity = 0; if (_M_type() == _Type::_Multi) capacity += _M_cmpts.size(); @@ -884,6 +917,16 @@ path::operator+=(const path& p) ptr->_M_pathname.reserve(_M_pathname.length() + extra.length()); ptr->_M_pathname = _M_pathname; ptr->_M_pathname += extra; + +#if SLASHSLASH_IS_ROOTNAME + if (orig_type == _Type::_Root_name) + { + basic_string_view s(p._M_pathname); + ::new(output++) _Cmpt(s.substr(extra.length(), 1), + _Type::_Root_dir, orig_pathlen + extra.length()); + ++_M_cmpts._M_impl->_M_size; + } +#endif } else if (orig_filenamelen == 0 && it != last) { @@ -895,7 +938,7 @@ path::operator+=(const path& p) { basic_string_view s = it->_M_pathname; auto pos = orig_pathlen; -#ifdef __CYGWIN__ +#if SLASHSLASH_IS_ROOTNAME s.remove_prefix(2); pos += 2; #endif @@ -999,7 +1042,11 @@ path::_M_concat(basic_string_view s) { // See if there's a filename or root-name at the end of the original path // that we can add to. - if (_M_type() == _Type::_Filename) + if (_M_type() == _Type::_Filename +#if SLASHSLASH_IS_ROOTNAME + || _M_type() == _Type::_Root_name +#endif + ) { if (cmpt.str.length() == s.length()) { @@ -1031,9 +1078,6 @@ path::_M_concat(basic_string_view s) && _M_cmpts.back()._M_type() == _Type::_Filename) orig_filenamelen = 0; // original path had empty filename at end - - // TODO handle "//rootname" + "foo" case for Cygwin. - std::array<_Parser::cmpt, 64> buf; auto next = buf.begin(); @@ -1065,6 +1109,11 @@ path::_M_concat(basic_string_view s) if (is_dir_sep(s.back())) ++capacity; +#if SLASHSLASH_IS_ROOTNAME + if (orig_type == _Type::_Root_name) + ++capacity; // Need to insert root-directory after root-name +#endif + __try { _M_cmpts.type(_Type::_Multi); @@ -1080,6 +1129,15 @@ path::_M_concat(basic_string_view s) p->_M_pathname.reserve(orig_pathname.length() + extra.length()); p->_M_pathname = orig_pathname; p->_M_pathname += extra; + +#if SLASHSLASH_IS_ROOTNAME + if (orig_type == _Type::_Root_name) + { + ::new(output++) _Cmpt(s.substr(extra.length(), 1), + _Type::_Root_dir, orig_pathlen + extra.length()); + ++_M_cmpts._M_impl->_M_size; + } +#endif } else if (orig_filenamelen == 0) { @@ -1532,6 +1590,10 @@ path::lexically_normal() const } else if (is_dot(p)) ret /= path(); +#if SLASHSLASH_IS_ROOTNAME + else if (p._M_type() == _Type::_Root_dir) + ret += '/'; // using operator/=('/') would replace whole of ret +#endif else ret /= p; } diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc index da5f377de94..40af1551eeb 100644 --- a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc +++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc @@ -35,7 +35,11 @@ test01() path p2 = "/foo/bar"; VERIFY( p2.root_directory() == path("/") ); path p3 = "//foo"; +#ifdef __CYGWIN__ + VERIFY( p3.root_directory() == path() ); +#else VERIFY( p3.root_directory() == path("/") ); +#endif path p4 = "///foo"; VERIFY( p4.root_directory() == path("/") ); } -- 2.30.2