PR libstdc++/79283 fix filesystem::read_symlink for /proc
authorJonathan Wakely <jwakely@redhat.com>
Wed, 25 Oct 2017 12:42:58 +0000 (13:42 +0100)
committerJonathan Wakely <redi@gcc.gnu.org>
Wed, 25 Oct 2017 12:42:58 +0000 (13:42 +0100)
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
libstdc++-v3/src/filesystem/ops.cc
libstdc++-v3/src/filesystem/std-ops.cc

index 5a694c74675a7e38abdcda02eef010c802d493b0..afc4b7c0048d8197c5772d1e82b828fbf85bb2aa 100644 (file)
@@ -1,5 +1,10 @@
 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
        step to algorithm, for removing dot-dot elements after root-directory.
        * testsuite/27_io/filesystem/operations/canonical.cc: Use
index 61d9c89e616cd540cc68700db1e93a36b4371ad1..1ec8883fde9c81d806587a8123e4ca26ff3fdc73 100644 (file)
@@ -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;
 }
 
 
index ff7acbfc1e7737ede8df7cdbecdceab310d1e4cd..947be7ef4c568362095ab7e5ab7497a64d058da9 100644 (file)
@@ -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