commit:     53d7d24872527a69501f4c74a44e16e29aa3bb4a
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Mon Dec 13 07:17:04 2021 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Mon Dec 13 07:17:04 2021 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=53d7d248

libq/copy_file: employ sendfile() if possible

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 libq/copy_file.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 67 insertions(+), 11 deletions(-)

diff --git a/libq/copy_file.c b/libq/copy_file.c
index e4619ce..955fd78 100644
--- a/libq/copy_file.c
+++ b/libq/copy_file.c
@@ -1,29 +1,85 @@
 /*
- * Copyright 2005-2019 Gentoo Foundation
+ * Copyright 2005-2021 Gentoo Foundation
  * Distributed under the terms of the GNU General Public License v2
  *
  * Copyright 2011-2016 Mike Frysinger  - <[email protected]>
+ * Copyright 2021-     Fabian Groffen  - <[email protected]>
  */
 
 #include "main.h"
 #include "safe_io.h"
 #include "copy_file.h"
 
+/* includes for when sendfile is available */
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#if defined(HAVE_SENDFILE4_SUPPORT)
+/* Linux/Solaris */
+# include <sys/sendfile.h>
+#elif defined(HAVE_SENDFILE6_SUPPORT) || defined(HAVE_SENDFILE7_SUPPORT)
+/* macOS (since Darwin 9) + FreeBSD */
+# include <sys/socket.h>
+# include <sys/uio.h>
+#endif
+
 int copy_file_fd(int fd_src, int fd_dst)
 {
-       ssize_t rcnt, wcnt;
-       char buf[64 * 1024];
+#if defined(HAVE_SENDFILE4_SUPPORT) || \
+       defined(HAVE_SENDFILE6_SUPPORT) || \
+       defined(HAVE_SENDFILE7_SUPPORT)
+       struct stat stat_buf;
+       ssize_t     ret;
+       size_t      len;
+       off_t       offset = 0;
 
-       while (1) {
-               rcnt = safe_read(fd_src, buf, sizeof(buf));
-               if (rcnt < 0)
-                       return -1;
-               else if (rcnt == 0)
+       if (fstat(fd_src, &stat_buf) != -1) {
+               len = (size_t)stat_buf.st_size;
+
+#if defined(HAVE_SENDFILE4_SUPPORT)
+               /* Linux/Solaris */
+               ret = sendfile(fd_dst, fd_src, &offset, len);
+               /* everything looks fine, return success */
+               if (ret == (ssize_t)len)
                        return 0;
+#elif defined(HAVE_SENDFILE6_SUPPORT)
+               /* macOS (since Darwin 9) */
+               offset = len;
+               ret = (ssize_t)sendfile(fd_src, fd_dst, 0, &offset, NULL, 0);
+               /* everything looks fine, return success */
+               if (offset == (off_t)len)
+                       return 0;
+#elif defined(HAVE_SENDFILE7_SUPPORT)
+               /* FreeBSD */
+               ret = (ssize_t)sendfile(fd_src, fd_dst, offset, len, NULL, 
&offset, 0);
+               /* everything looks fine, return success */
+               if (offset == (off_t)len)
+                       return 0;
+#endif
 
-               wcnt = safe_write(fd_dst, buf, rcnt);
-               if (wcnt == -1)
-                       return -1;
+               /* fall back to read/write, rewind the fd */
+               lseek(fd_src, 0, SEEK_SET);
+       }
+#endif /* HAVE_SENDFILE */
+
+       /* fallback, keep in its own scope, so we avoid 64K stack alloc if
+        * sendfile works properly */
+       {
+               ssize_t rcnt, wcnt;
+               char buf[64 * 1024];
+
+               while (1) {
+                       rcnt = safe_read(fd_src, buf, sizeof(buf));
+                       if (rcnt < 0)
+                               return -1;
+                       else if (rcnt == 0)
+                               return 0;
+
+                       wcnt = safe_write(fd_dst, buf, rcnt);
+                       if (wcnt == -1)
+                               return -1;
+               }
        }
 }
 

Reply via email to