[Top][All Lists]

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

save-buffer: avoid data loss on interrupt

From: Jim Meyering
Subject: save-buffer: avoid data loss on interrupt
Date: Tue, 13 Dec 2011 18:13:16 +0100

Jim Meyering wrote:
> TL;DR, for a regular file with no other hard links in a writable directory,
> why is the default to rewrite in place (non-atomically), rather than to write
> to temporary-in-same-dir and then to rename, thus updating atomically?
> --------------------------------------

Note that this change helps avoid data loss when emacs is killed
while rewriting an input file.

So far, no one responded to the above, so here's a proof-of-concept patch.
This is a significant enough change that explanation like what's in the
commit log below belongs at least in etc/NEWS or in documentation.
This change is obviously not appropriate before the release.

(Obviously, before pushing it, I would also make the commit log
contents into a ChangeLog entry)

>From 3fc1719d0365707f25f512a87aa1c84e1b4fece5 Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Tue, 13 Dec 2011 17:47:28 +0100
Subject: [PATCH] make save-buffer mostly immune to interrupts: avoid data loss

When you type C-xC-s, emacs usually rewrites a file in-place.  Thus,
if it is interrupted, you may be left with a corrupt file.  Even when
emacs is not interrupted, if some process is reading that file as you
write it, it can easily process an incomplete version of it, which can
lead to errors.  You can avoid all of that by setting the buffer-local
file-precious-flag for files you care about, but it's often best not to
do that for a file with multiple hard links, because when you set that
flag, emacs' save mechanism writes a file by first writing a temporary
file in the same directory, and then renaming that (an atomic process)
to the actual file you wanted to save.  Renaming that way effectively
unlinks a file with multiple hard links.
* files.el (basic-save-buffer-2): Save via write-temp-and-rename
not just when file-precious-flag, but also when the number of hard
links is 1.
 lisp/files.el |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/lisp/files.el b/lisp/files.el
index 40b6e7d..535715c 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -4467,7 +4467,9 @@ Before and after saving the buffer, this function runs
        (setq setmodes (backup-buffer)))
     (let* ((dir (file-name-directory buffer-file-name))
            (dir-writable (file-writable-p dir)))
-      (if (or (and file-precious-flag dir-writable)
+      (if (or (and dir-writable
+                  (or file-precious-flag
+                      (= (file-nlinks buffer-file-name) 1)))
               (and break-hardlink-on-save
                    (file-exists-p buffer-file-name)
                    (> (file-nlinks buffer-file-name) 1)

reply via email to

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