public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] PR libstdc++/79283 fix filesystem::read_symlink for /proc
@ 2017-10-25 13:08 Jonathan Wakely
  0 siblings, 0 replies; only message in thread
From: Jonathan Wakely @ 2017-10-25 13:08 UTC (permalink / raw)
  To: libstdc++, gcc-patches

[-- Attachment #1: Type: text/plain, Size: 463 bytes --]

For some paths lstat returns st_size == 0, so use a buffer with
non-zero size and then grow it dynamically if it's not big enough.

	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.

Tested x86+64-linux, committed to trunk. I'll backport the
experimental::filesystem::read_symlink part to the branches.


[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 3922 bytes --]

commit ef737409818853af3a2b9a8b22984194d8c61de7
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Wed Oct 25 02:15:25 2017 +0100

    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.

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 <filesystem>
@@ -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

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2017-10-25 12:47 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-25 13:08 [PATCH] PR libstdc++/79283 fix filesystem::read_symlink for /proc Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).