From 220645d0193c21b4662b2800bc5d2de493832fd7 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 25 Oct 2017 13:42:58 +0100 Subject: [PATCH] PR libstdc++/79283 fix filesystem::read_symlink for /proc PR libstdc++/79283 * src/filesystem/ops.cc (read_symlink): Handle st_size being zero. * src/filesystem/std-ops.cc (read_symlink): Likewise. (do_copy_file) [!NEED_DO_COPY_FILE]: Avoid multiple definitions. From-SVN: r254076 --- libstdc++-v3/ChangeLog | 5 ++++ libstdc++-v3/src/filesystem/ops.cc | 37 ++++++++++++++++++------ libstdc++-v3/src/filesystem/std-ops.cc | 40 ++++++++++++++++++++------ 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 5a694c74675..afc4b7c0048 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,10 @@ 2017-10-25 Jonathan Wakely + PR libstdc++/79283 + * src/filesystem/ops.cc (read_symlink): Handle st_size being zero. + * src/filesystem/std-ops.cc (read_symlink): Likewise. + (do_copy_file) [!NEED_DO_COPY_FILE]: Avoid multiple definitions. + * src/filesystem/std-path.cc (path::lexically_normal): Add missing step to algorithm, for removing dot-dot elements after root-directory. * testsuite/27_io/filesystem/operations/canonical.cc: Use diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index 61d9c89e616..1ec8883fde9 100644 --- a/libstdc++-v3/src/filesystem/ops.cc +++ b/libstdc++-v3/src/filesystem/ops.cc @@ -962,26 +962,45 @@ fs::read_symlink(const path& p) fs::path fs::read_symlink(const path& p, error_code& ec) { + path result; #ifdef _GLIBCXX_HAVE_SYS_STAT_H stat_type st; if (::lstat(p.c_str(), &st)) { ec.assign(errno, std::generic_category()); - return {}; + return result; } - std::string buf(st.st_size, '\0'); - ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); - if (len == -1) + std::string buf(st.st_size ? st.st_size + 1 : 128, '\0'); + do { - ec.assign(errno, std::generic_category()); - return {}; + ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size()); + if (len == -1) + { + ec.assign(errno, std::generic_category()); + return result; + } + else if (len == (ssize_t)buf.size()) + { + if (buf.size() > 4096) + { + ec.assign(ENAMETOOLONG, std::generic_category()); + return result; + } + buf.resize(buf.size() * 2); + } + else + { + buf.resize(len); + result.assign(buf); + ec.clear(); + break; + } } - ec.clear(); - return path{buf.data(), buf.data()+len}; + while (true); #else ec = std::make_error_code(std::errc::not_supported); - return {}; #endif + return result; } diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc index ff7acbfc1e7..947be7ef4c5 100644 --- a/libstdc++-v3/src/filesystem/std-ops.cc +++ b/libstdc++-v3/src/filesystem/std-ops.cc @@ -24,6 +24,7 @@ #ifndef _GLIBCXX_USE_CXX11_ABI # define _GLIBCXX_USE_CXX11_ABI 1 +# define NEED_DO_COPY_FILE #endif #include @@ -251,6 +252,7 @@ namespace std::filesystem } #ifdef _GLIBCXX_HAVE_SYS_STAT_H +#ifdef NEED_DO_COPY_FILE bool fs::do_copy_file(const char* from, const char* to, copy_options_existing_file options, @@ -423,6 +425,7 @@ fs::do_copy_file(const char* from, const char* to, return true; #endif // _GLIBCXX_USE_SENDFILE } +#endif // NEED_DO_COPY_FILE #endif // _GLIBCXX_HAVE_SYS_STAT_H void @@ -1166,26 +1169,45 @@ fs::read_symlink(const path& p) fs::path fs::read_symlink(const path& p, error_code& ec) { + path result; #ifdef _GLIBCXX_HAVE_SYS_STAT_H stat_type st; if (::lstat(p.c_str(), &st)) { ec.assign(errno, std::generic_category()); - return {}; + return result; } - std::string buf(st.st_size, '\0'); - ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); - if (len == -1) + std::string buf(st.st_size ? st.st_size + 1 : 128, '\0'); + do { - ec.assign(errno, std::generic_category()); - return {}; + ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size()); + if (len == -1) + { + ec.assign(errno, std::generic_category()); + return result; + } + else if (len == (ssize_t)buf.size()) + { + if (buf.size() > 4096) + { + ec.assign(ENAMETOOLONG, std::generic_category()); + return result; + } + buf.resize(buf.size() * 2); + } + else + { + buf.resize(len); + result.assign(buf); + ec.clear(); + break; + } } - ec.clear(); - return path{buf.data(), buf.data()+len}; + while (true); #else ec = std::make_error_code(std::errc::not_supported); - return {}; #endif + return result; } fs::path -- 2.30.2