unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Jim Meyering <jim@meyering.net>
To: Emacs development discussions <emacs-devel@gnu.org>
Subject: Re: save-buffer: avoid data loss on interrupt
Date: Thu, 15 Dec 2011 13:58:40 +0100	[thread overview]
Message-ID: <87liqekn3z.fsf@rho.meyering.net> (raw)
In-Reply-To: <87pqfsqtsj.fsf@rho.meyering.net> (Jim Meyering's message of "Tue, 13 Dec 2011 18:13:16 +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 <meyering@redhat.com>
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  <meyering@redhat.com>
+
+	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  <lekktu@gmail.com>

 	* 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



      parent reply	other threads:[~2011-12-15 12:58 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-09 10:26 enabling atomic-update more often, i.e., rewrite via rename Jim Meyering
2011-12-13 17:13 ` save-buffer: avoid data loss on interrupt Jim Meyering
2011-12-13 20:03   ` Paul Eggert
2011-12-13 20:52     ` Jim Meyering
2011-12-13 21:47       ` Paul Eggert
2011-12-13 22:27         ` chad
2011-12-14 14:40         ` Jim Meyering
2011-12-14 18:51           ` Paul Eggert
2011-12-15 23:53             ` Stefan Monnier
2011-12-14  2:40   ` Stefan Monnier
2011-12-15 12:58   ` Jim Meyering [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87liqekn3z.fsf@rho.meyering.net \
    --to=jim@meyering.net \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).