From 0070e3297eef582c2216b9335e1476e482afe9b0 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Fri, 5 Jan 2018 22:22:12 +0000 Subject: [PATCH] PR libstdc++/83279 handle sendfile not copying entire file Backport from mainline 2017-12-14 Jonathan Wakely PR libstdc++/83279 * src/filesystem/std-ops.cc (do_copy_file): Handle sendfile not copying entire file. From-SVN: r256290 --- libstdc++-v3/ChangeLog | 7 +++ libstdc++-v3/src/filesystem/ops.cc | 74 +++++++++++++++++++----------- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 9351ad2e45a..8c2b3ed85f2 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,12 @@ 2018-01-05 Jonathan Wakely + Backport from mainline + 2017-12-14 Jonathan Wakely + + 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 diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc index f93b45bb674..feb0a1ea84a 100644 --- a/libstdc++-v3/src/filesystem/ops.cc +++ b/libstdc++-v3/src/filesystem/ops.cc @@ -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 sbin(in.fd, std::ios::in); - __gnu_cxx::stdio_filebuf 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 sbin(in.fd, ios::in|ios::binary); + __gnu_cxx::stdio_filebuf 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 != from_st->st_size) + if (n != 0) { - ec.assign(errno, std::generic_category()); - return false; - } - if (!out.close() || !in.close()) - { - ec.assign(errno, std::generic_category()); - return false; - } + 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; + } + } +#endif + + if (count && !(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; + } ec.clear(); return true; -#endif } } #endif