C++ File System copy_file problems with older linux kernel (2.6.18)

Uros Bizjak ubizjak@gmail.com
Wed Aug 10 13:42:00 GMT 2016


On Wed, Aug 10, 2016 at 1:54 PM, Uros Bizjak <ubizjak@gmail.com> wrote:
> Hello!
>
> There is a problem with the file copy operation in C++ File System
> under older linux kernel (2.6.18), e.g. CentOS 5.11, resulting in:
>
> FAIL: experimental/filesystem/operations/copy.cc execution test
> FAIL: experimental/filesystem/operations/copy_file.cc execution test
>
> libstdc++ testsuite failures.
>
> The problem is, that file copying is performed using ::sendfile,
> although (cf sendfile manpage):
>
> <q>
> In  Linux  kernels  before  2.6.33,  out_fd must refer to a socket.
> Since Linux 2.6.33 it can be any file.
> </q>

An alternative solution is to fall-back to normal copy operations if
sendfile fails with an EINVAL errno, as outlined by attached (lightly
tested) prototype patch.

Uros.
-------------- next part --------------
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
index 9fb5b639..0bee805 100644
--- a/libstdc++-v3/src/filesystem/ops.cc
+++ b/libstdc++-v3/src/filesystem/ops.cc
@@ -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,37 +427,45 @@ namespace
 
 #ifdef _GLIBCXX_USE_SENDFILE
     const auto n = ::sendfile(out.fd, in.fd, nullptr, from_st->st_size);
-    if (n != from_st->st_size)
+    if (n == -1 && errno == EINVAL)
       {
-	ec.assign(errno, std::generic_category());
-	return false;
+#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 (!out.close() || !in.close())
+    if (n != from_st->st_size)
       {
 	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())
+    if (!out.close() || !in.close())
       {
 	ec.assign(errno, std::generic_category());
 	return false;
       }
-#endif
 
     ec.clear();
     return true;
+#endif
   }
 }
 #endif


More information about the Libstdc++ mailing list