Hello! Attached patch implements note from sendfile manpage:
<q> Applications may wish to fall back to read(2)/write(2) in the case where sendfile() fails with EINVAL or ENOSYS. </q> Also, the patch fixes a small inconsistency in how _GLIBCXX_USE_FCHMODAT config flag is handled in do_copy_file function. 2016-08-11 Uros Bizjak <ubiz...@gmail.com> * src/filesystem/ops.cc: Always include ostream and ext/stdio_filebuf.h. (do_copy_file): Check if _GLIBCXX_USE_FCHMODAT is defined. [_GLIBCXX_USE_SENDFILE]: Fallback to read/write operations in case sendfile fails with ENOSYS or EINVAL. Patch was bootstrapped and regression tested on x86_64-linux-gnu {,-m32} on CentOS 5.11 (where sendfile returns EINVAL for file->file copy) and Fedora 24. In addition, the patch was bootstraped and regression tested with _GLIBCXX_USE_SENDFILE manually disabled after configure. OK for mainline? Uros.
Index: src/filesystem/ops.cc =================================================================== --- src/filesystem/ops.cc (revision 239384) +++ src/filesystem/ops.cc (working copy) @@ -28,7 +28,9 @@ #include <experimental/filesystem> #include <functional> +#include <ostream> #include <stack> +#include <ext/stdio_filebuf.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> @@ -48,9 +50,6 @@ #endif #ifdef _GLIBCXX_USE_SENDFILE # include <sys/sendfile.h> -#else -# include <ext/stdio_filebuf.h> -# include <ostream> #endif #if _GLIBCXX_HAVE_UTIME_H # include <utime.h> @@ -416,7 +415,7 @@ namespace #ifdef _GLIBCXX_USE_FCHMOD if (::fchmod(out.fd, from_st->st_mode)) -#elif _GLIBCXX_USE_FCHMODAT +#elif defined _GLIBCXX_USE_FCHMODAT if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0)) #else if (::chmod(to.c_str(), from_st->st_mode)) @@ -428,6 +427,31 @@ namespace #ifdef _GLIBCXX_USE_SENDFILE const auto n = ::sendfile(out.fd, in.fd, nullptr, from_st->st_size); + 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; + } + + ec.clear(); + return true; + +#ifdef _GLIBCXX_USE_SENDFILE + } if (n != from_st->st_size) { ec.assign(errno, std::generic_category()); @@ -438,27 +462,10 @@ namespace ec.assign(errno, std::generic_category()); return false; } -#else - __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; - } -#endif ec.clear(); return true; +#endif } } #endif