]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR libstdc++/83279 handle sendfile not copying entire file
authorJonathan Wakely <jwakely@redhat.com>
Fri, 5 Jan 2018 22:47:50 +0000 (22:47 +0000)
committerJonathan Wakely <redi@gcc.gnu.org>
Fri, 5 Jan 2018 22:47:50 +0000 (22:47 +0000)
Backport from mainline
2017-12-14  Jonathan Wakely  <jwakely@redhat.com>

PR libstdc++/83279
* src/filesystem/std-ops.cc (do_copy_file): Handle sendfile not
copying entire file.

From-SVN: r256296

libstdc++-v3/ChangeLog
libstdc++-v3/src/filesystem/ops.cc

index 64b559902486baad823f9b4f168f0fb5759b907b..2e3b4565339deeae1390dae12c3ccb0739806792 100644 (file)
@@ -1,5 +1,12 @@
 2018-01-05  Jonathan Wakely  <jwakely@redhat.com>
 
+       Backport from mainline
+       2017-12-14  Jonathan Wakely  <jwakely@redhat.com>
+
+       PR libstdc++/83279
+       * src/filesystem/std-ops.cc (do_copy_file): Handle sendfile not
+       copying entire file.
+
        Backport from mainline
        2018-01-04  Jonathan Wakely  <jwakely@redhat.com>
 
index b242c04e1c38fb8c600a9db49cddb78a36b16607..6c4deaf4549091713c393095cdbf09e5371cf764 100644 (file)
@@ -443,48 +443,68 @@ namespace
        return false;
       }
 
+    size_t count = from_st->st_size;
 #ifdef _GLIBCXX_USE_SENDFILE
     off_t offset = 0;
-    const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
-    if (n < 0 && (errno == ENOSYS || errno == EINVAL))
+    ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
+    if (n < 0 && errno != ENOSYS && errno != EINVAL)
       {
-#endif
-       __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
-       __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
-       if (sbin.is_open())
-         in.fd = -1;
-       if (sbout.is_open())
-         out.fd = -1;
-       if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
-         {
-           ec = std::make_error_code(std::errc::io_error);
-           return false;
-         }
-       if (!sbout.close() || !sbin.close())
+       ec.assign(errno, std::generic_category());
+       return false;
+      }
+    if ((size_t)n == count)
+      {
+       if (!out.close() || !in.close())
          {
            ec.assign(errno, std::generic_category());
            return false;
          }
-
        ec.clear();
        return true;
+      }
+    else if (n > 0)
+      count -= n;
+#endif // _GLIBCXX_USE_SENDFILE
+
+    using std::ios;
+    __gnu_cxx::stdio_filebuf<char> sbin(in.fd, ios::in|ios::binary);
+    __gnu_cxx::stdio_filebuf<char> sbout(out.fd, ios::out|ios::binary);
+
+    if (sbin.is_open())
+      in.fd = -1;
+    if (sbout.is_open())
+      out.fd = -1;
 
 #ifdef _GLIBCXX_USE_SENDFILE
+    if (n != 0)
+      {
+       if (n < 0)
+         n = 0;
+
+       const auto p1 = sbin.pubseekoff(n, ios::beg, ios::in);
+       const auto p2 = sbout.pubseekoff(n, ios::beg, ios::out);
+
+       const std::streampos errpos(std::streamoff(-1));
+       if (p1 == errpos || p2 == errpos)
+         {
+           ec = std::make_error_code(std::errc::io_error);
+           return false;
+         }
       }
-    if (n != from_st->st_size)
+#endif
+
+    if (count && !(std::ostream(&sbout) << &sbin))
       {
-       ec.assign(errno, std::generic_category());
+       ec = std::make_error_code(std::errc::io_error);
        return false;
       }
-    if (!out.close() || !in.close())
+    if (!sbout.close() || !sbin.close())
       {
        ec.assign(errno, std::generic_category());
        return false;
       }
-
     ec.clear();
     return true;
-#endif
   }
 }
 #endif