emacs-devel
[Top][All Lists]
Advanced

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

Re: save-buffer: avoid data loss on interrupt


From: Jim Meyering
Subject: Re: save-buffer: avoid data loss on interrupt
Date: Thu, 15 Dec 2011 13:58:40 +0100

Jim Meyering wrote:
> 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)
...
> Date: Tue, 13 Dec 2011 17:47:28 +0100
> Subject: [PATCH] make save-buffer mostly immune to interrupts: avoid data loss

FYI, here's a patch that works also when
the file in question does not exist.
The preceding patch used file-nlinks without first
ensuring that the file actually exists.

>From e7f560e9dcb4c2128a33fa825c1809064e40f56f Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Thu, 15 Dec 2011 13:53:58 +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/ChangeLog |   18 ++++++++++++++++++
 lisp/files.el  |    5 ++++-
 2 files changed, 22 insertions(+), 1 deletions(-)

diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 74eb98c..c419cd7 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -7,6 +7,24 @@
        (makefile-makepp-font-lock-keywords): Add new patterns.
        (makefile-match-function-end): Match new [...] and [[...]].

+2011-12-13  Jim Meyering  <address@hidden>
+
+       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.
+
 2011-12-11  Juanma Barranquero  <address@hidden>

        * ses.el (ses-call-printer-return, ses-cell-property-get)
diff --git a/lisp/files.el b/lisp/files.el
index 40b6e7d..e374f69 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -4467,7 +4467,10 @@ 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
+                      (not (file-exists-p buffer-file-name))
+                      (= (file-nlinks buffer-file-name) 1)))
               (and break-hardlink-on-save
                    (file-exists-p buffer-file-name)
                    (> (file-nlinks buffer-file-name) 1)
--
1.7.8.163.g9859a



reply via email to

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