emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 2c3dde9 1/2: copy-file now truncates output after w


From: Paul Eggert
Subject: [Emacs-diffs] master 2c3dde9 1/2: copy-file now truncates output after writing
Date: Sat, 30 May 2015 06:02:50 +0000

branch: master
commit 2c3dde9fc8b3ac33cc2e5071e05772f3f46d62ad
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    copy-file now truncates output after writing
    
    * src/fileio.c (Fcopy_file): Truncate output after writing rather
    than before.  This is more likely to work than truncation before
    writing, if the file system is out of space or the user is over
    disk quota (Bug#20595).  Also, check for read errors.
---
 src/fileio.c |   30 +++++++++++++++++++++++-------
 1 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/src/fileio.c b/src/fileio.c
index 796f08d..a969d3b 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -1871,8 +1871,6 @@ permissions.  */)
   bool already_exists = false;
   mode_t new_mask;
   int ifd, ofd;
-  int n;
-  char buf[16 * 1024];
   struct stat st;
 #endif
 
@@ -1974,6 +1972,8 @@ permissions.  */)
 
   record_unwind_protect_int (close_file_unwind, ofd);
 
+  off_t oldsize = 0, newsize = 0;
+
   if (already_exists)
     {
       struct stat out_st;
@@ -1982,15 +1982,31 @@ permissions.  */)
       if (st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
        report_file_errno ("Input and output files are the same",
                           list2 (file, newname), 0);
-      if (ftruncate (ofd, 0) != 0)
-       report_file_error ("Truncating output file", newname);
+      if (S_ISREG (out_st.st_mode))
+       oldsize = out_st.st_size;
     }
 
   immediate_quit = 1;
   QUIT;
-  while ((n = emacs_read (ifd, buf, sizeof buf)) > 0)
-    if (emacs_write_sig (ofd, buf, n) != n)
-      report_file_error ("Write error", newname);
+  while (true)
+    {
+      char buf[MAX_ALLOCA];
+      ptrdiff_t n = emacs_read (ifd, buf, sizeof buf);
+      if (n < 0)
+       report_file_error ("Read error", file);
+      if (n == 0)
+       break;
+      if (emacs_write_sig (ofd, buf, n) != n)
+       report_file_error ("Write error", newname);
+      newsize += n;
+    }
+
+  /* Truncate any existing output file after writing the data.  This
+     is more likely to work than truncation before writing, if the
+     file system is out of space or the user is over disk quota.  */
+  if (newsize < oldsize && ftruncate (ofd, newsize) != 0)
+    report_file_error ("Truncating output file", newname);
+
   immediate_quit = 0;
 
 #ifndef MSDOS



reply via email to

[Prev in Thread] Current Thread [Next in Thread]