Commit 220645d0 by Jonathan Wakely Committed by Jonathan Wakely

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
parent eeb517d3
2017-10-25 Jonathan Wakely <jwakely@redhat.com> 2017-10-25 Jonathan Wakely <jwakely@redhat.com>
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 * src/filesystem/std-path.cc (path::lexically_normal): Add missing
step to algorithm, for removing dot-dot elements after root-directory. step to algorithm, for removing dot-dot elements after root-directory.
* testsuite/27_io/filesystem/operations/canonical.cc: Use * testsuite/27_io/filesystem/operations/canonical.cc: Use
......
...@@ -962,26 +962,45 @@ fs::read_symlink(const path& p) ...@@ -962,26 +962,45 @@ fs::read_symlink(const path& p)
fs::path fs::read_symlink(const path& p, error_code& ec) fs::path fs::read_symlink(const path& p, error_code& ec)
{ {
path result;
#ifdef _GLIBCXX_HAVE_SYS_STAT_H #ifdef _GLIBCXX_HAVE_SYS_STAT_H
stat_type st; stat_type st;
if (::lstat(p.c_str(), &st)) if (::lstat(p.c_str(), &st))
{ {
ec.assign(errno, std::generic_category()); ec.assign(errno, std::generic_category());
return {}; return result;
} }
std::string buf(st.st_size, '\0'); std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); do
if (len == -1)
{ {
ec.assign(errno, std::generic_category()); ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
return {}; 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(); while (true);
return path{buf.data(), buf.data()+len};
#else #else
ec = std::make_error_code(std::errc::not_supported); ec = std::make_error_code(std::errc::not_supported);
return {};
#endif #endif
return result;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#ifndef _GLIBCXX_USE_CXX11_ABI #ifndef _GLIBCXX_USE_CXX11_ABI
# define _GLIBCXX_USE_CXX11_ABI 1 # define _GLIBCXX_USE_CXX11_ABI 1
# define NEED_DO_COPY_FILE
#endif #endif
#include <filesystem> #include <filesystem>
...@@ -251,6 +252,7 @@ namespace std::filesystem ...@@ -251,6 +252,7 @@ namespace std::filesystem
} }
#ifdef _GLIBCXX_HAVE_SYS_STAT_H #ifdef _GLIBCXX_HAVE_SYS_STAT_H
#ifdef NEED_DO_COPY_FILE
bool bool
fs::do_copy_file(const char* from, const char* to, fs::do_copy_file(const char* from, const char* to,
copy_options_existing_file options, copy_options_existing_file options,
...@@ -423,6 +425,7 @@ fs::do_copy_file(const char* from, const char* to, ...@@ -423,6 +425,7 @@ fs::do_copy_file(const char* from, const char* to,
return true; return true;
#endif // _GLIBCXX_USE_SENDFILE #endif // _GLIBCXX_USE_SENDFILE
} }
#endif // NEED_DO_COPY_FILE
#endif // _GLIBCXX_HAVE_SYS_STAT_H #endif // _GLIBCXX_HAVE_SYS_STAT_H
void void
...@@ -1166,26 +1169,45 @@ fs::read_symlink(const path& p) ...@@ -1166,26 +1169,45 @@ fs::read_symlink(const path& p)
fs::path fs::read_symlink(const path& p, error_code& ec) fs::path fs::read_symlink(const path& p, error_code& ec)
{ {
path result;
#ifdef _GLIBCXX_HAVE_SYS_STAT_H #ifdef _GLIBCXX_HAVE_SYS_STAT_H
stat_type st; stat_type st;
if (::lstat(p.c_str(), &st)) if (::lstat(p.c_str(), &st))
{ {
ec.assign(errno, std::generic_category()); ec.assign(errno, std::generic_category());
return {}; return result;
} }
std::string buf(st.st_size, '\0'); std::string buf(st.st_size ? st.st_size + 1 : 128, '\0');
ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size()); do
if (len == -1)
{ {
ec.assign(errno, std::generic_category()); ssize_t len = ::readlink(p.c_str(), buf.data(), buf.size());
return {}; 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(); while (true);
return path{buf.data(), buf.data()+len};
#else #else
ec = std::make_error_code(std::errc::not_supported); ec = std::make_error_code(std::errc::not_supported);
return {};
#endif #endif
return result;
} }
fs::path fs::path
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment