rlb pushed a commit to branch main
in repository guile.

commit 4f39181b2f053c0a134e646226547bc05a7353fa
Author: Tomas Volf <~@wolfsden.cz>
AuthorDate: Fri Feb 28 02:10:18 2025 +0100

    filesys.c: Use scm_sendfile to copy files
    
    Use scm_sendfile instead of read-write loop.  This moves the work into
    the kernel, improving performance.  This implements Ludovic's suggestion
    from https://debbugs.gnu.org/68504
    
    * libguile/filesys.c (scm_copy_file2): Use scm_sendfile.
    
    [r...@defaultvalue.org: add NEWS]
---
 NEWS               |  4 ++++
 libguile/filesys.c | 24 ++++++++++++++----------
 2 files changed, 18 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index 2adbdf099..1b9e1877f 100644
--- a/NEWS
+++ b/NEWS
@@ -45,6 +45,10 @@ for-delimited-from-port and for-line-in-file. Of these, 
for-line-in-file
 is helpful in the common situation where you want a procedure applied to
 every line in a file.
 
+* Performance improvements
+
+** `copy-file` now relies on `sendfile` rather than a read/write loop
+
 * Changes to the distribution
 
 * Build system changes
diff --git a/libguile/filesys.c b/libguile/filesys.c
index 0e7078cf0..be223a85d 100644
--- a/libguile/filesys.c
+++ b/libguile/filesys.c
@@ -1,7 +1,7 @@
 /* Copyright 1996-2002,2004,2006,2009-2019,2021
      Free Software Foundation, Inc.
    Copyright 2021 Maxime Devos <maximede...@telenet.be>
-   Copyright 2024 Tomas Volf <~@wolfsden.cz>
+   Copyright 2024, 2025 Tomas Volf <~@wolfsden.cz>
 
    This file is part of Guile.
 
@@ -1306,10 +1306,9 @@ SCM_DEFINE (scm_copy_file2, "copy-file", 2, 0, 1,
 {
   char *c_oldfile, *c_newfile;
   int oldfd, newfd;
-  int n, rv;
+  int rv;
   SCM cow = sym_auto;
   int clone_res;
-  char buf[BUFSIZ];
   struct stat_or_stat64 oldstat;
 
   scm_dynwind_begin (0);
@@ -1354,13 +1353,18 @@ SCM_DEFINE (scm_copy_file2, "copy-file", 2, 0, 1,
     scm_syserror ("copy-file: copy-on-write failed");
 
   if (clone_res)
-    while ((n = read (oldfd, buf, sizeof buf)) > 0)
-      if (write (newfd, buf, n) != n)
-        {
-          close (oldfd);
-          close (newfd);
-          SCM_SYSERROR;
-        }
+    {
+      off_t end;
+      if ((end = lseek_or_lseek64 (oldfd, 0, SEEK_END)) < 0)
+        SCM_SYSERROR;
+      if (lseek_or_lseek64 (oldfd, 0, SEEK_SET) < 0)
+        SCM_SYSERROR;
+
+      scm_sendfile (scm_from_int (newfd),
+                    scm_from_int (oldfd),
+                    scm_from_off_t (end),
+                    SCM_UNDEFINED);
+    }
   close (oldfd);
   if (close (newfd) == -1)
     SCM_SYSERROR;

Reply via email to