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.

From-SVN: r256290
This commit is contained in:
Jonathan Wakely 2018-01-05 22:22:12 +00:00 committed by Jonathan Wakely
parent 826137607d
commit 0070e3297e
2 changed files with 54 additions and 27 deletions

View File

@ -1,5 +1,12 @@
2018-01-05 Jonathan Wakely <jwakely@redhat.com> 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 Backport from mainline
2018-01-04 Jonathan Wakely <jwakely@redhat.com> 2018-01-04 Jonathan Wakely <jwakely@redhat.com>

View File

@ -443,19 +443,57 @@ namespace
return false; return false;
} }
size_t count = from_st->st_size;
#ifdef _GLIBCXX_USE_SENDFILE #ifdef _GLIBCXX_USE_SENDFILE
off_t offset = 0; off_t offset = 0;
const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size); ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
if (n < 0 && (errno == ENOSYS || errno == EINVAL)) if (n < 0 && errno != ENOSYS && errno != EINVAL)
{ {
#endif ec.assign(errno, std::generic_category());
__gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in); return false;
__gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out); }
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()) if (sbin.is_open())
in.fd = -1; in.fd = -1;
if (sbout.is_open()) if (sbout.is_open())
out.fd = -1; out.fd = -1;
if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
#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;
}
}
#endif
if (count && !(std::ostream(&sbout) << &sbin))
{ {
ec = std::make_error_code(std::errc::io_error); ec = std::make_error_code(std::errc::io_error);
return false; return false;
@ -465,26 +503,8 @@ namespace
ec.assign(errno, std::generic_category()); ec.assign(errno, std::generic_category());
return false; return false;
} }
ec.clear(); ec.clear();
return true; return true;
#ifdef _GLIBCXX_USE_SENDFILE
}
if (n != from_st->st_size)
{
ec.assign(errno, std::generic_category());
return false;
}
if (!out.close() || !in.close())
{
ec.assign(errno, std::generic_category());
return false;
}
ec.clear();
return true;
#endif
} }
} }
#endif #endif