summaryrefslogtreecommitdiff
path: root/libstdc++-v3/src/filesystem/ops.cc
diff options
context:
space:
mode:
authorredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2018-01-05 22:22:12 +0000
committerredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2018-01-05 22:22:12 +0000
commite69feb32a15cf5029fe2001ca2c63f77a15eb072 (patch)
tree0babcea6c19cf8d907ae482354afb418e78b5f18 /libstdc++-v3/src/filesystem/ops.cc
parentd9df9a87c4dd5df7f8b1377836ca57b95f426232 (diff)
PR libstdc++/83279 handle sendfile not copying entire file
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-7-branch@256290 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3/src/filesystem/ops.cc')
-rw-r--r--libstdc++-v3/src/filesystem/ops.cc62
1 files changed, 41 insertions, 21 deletions
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
index f93b45bb6744..feb0a1ea84a8 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<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