From: Jonathan Tomer <jktomer@google.com>
To: 35497@debbugs.gnu.org, eliz@gnu.org, michael.albinus@gmx.de
Cc: Jonathan Tomer <jktomer@google.com>
Subject: bug#35497: [PATCH v7] Don't rewrite buffer contents after saving by rename
Date: Tue, 7 May 2019 10:33:28 -0700 [thread overview]
Message-ID: <20190507173328.140935-1-jktomer@google.com> (raw)
In-Reply-To: <87r29a1hjh.fsf@gmx.de>
When `file-precious-flag' is non-nil, files are saved by renaming a
temporary file to the new name; this is an atomic operation on POSIX
so other programs will not see the file in an intermediate state.
Unfortunately, due to a paren-matching error introduced in change
574c05e219476912db3105fa164accd9ba12b35f, we would then write the
contents again in the usual way after this rename. In addition to
being wasteful, this is a serious bug: the whole point of
`file-precious-flag' is to prevent race conditions with other programs
that might otherwise see an empty file, but with this bug the race is
actually much *more* likely to be visible: the rename will alert any
inotify watchers of a change, and then the subsequent write is very
likely to truncate the file just as those programs start to read it!
* lisp/files.el (basic-save-buffer-2): Don't rewrite file contents
after saving-by-renaming.
* test/lisp/files-tests.el (files-tests-dont-rewrite-precious-files):
* test/lisp/net/tramp-tests.el (tramp-test10-write-region-file-precious-flag):
Regression tests for this change.
---
lisp/files.el | 4 ++--
test/lisp/files-tests.el | 15 +++++++++++++++
test/lisp/net/tramp-tests.el | 29 +++++++++++++++++++++++++++++
3 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/lisp/files.el b/lisp/files.el
index c05d70a00e..72518e8127 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -5256,7 +5256,7 @@ basic-save-buffer-2
(set-file-extended-attributes buffer-file-name
(nth 1 setmodes)))
(set-file-modes buffer-file-name
- (logior (car setmodes) 128))))))
+ (logior (car setmodes) 128)))))
(let (success)
(unwind-protect
(progn
@@ -5272,7 +5272,7 @@ basic-save-buffer-2
(and setmodes (not success)
(progn
(rename-file (nth 2 setmodes) buffer-file-name t)
- (setq buffer-backed-up nil))))))
+ (setq buffer-backed-up nil)))))))
setmodes))
(declare-function diff-no-select "diff"
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index ae8ea41a79..fe2e958f1c 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -1244,5 +1244,20 @@ files-tests-file-attributes-equal
(executable-find (file-name-nondirectory tmpfile))))))
(delete-file tmpfile))))
+(ert-deftest files-tests-dont-rewrite-precious-files ()
+ "Test that `file-precious-flag' forces files to be saved by
+renaming only, rather than modified in-place."
+ (let* ((temp-file-name (make-temp-file "files-tests"))
+ (advice (lambda (_start _end filename &rest _r)
+ (should-not (string= filename temp-file-name)))))
+ (unwind-protect
+ (with-current-buffer (find-file-noselect temp-file-name)
+ (advice-add #'write-region :before advice)
+ (setq-local file-precious-flag t)
+ (insert "foobar")
+ (should (null (save-buffer))))
+ (ignore-errors (advice-remove #'write-region advice))
+ (ignore-errors (delete-file temp-file-name)))))
+
(provide 'files-tests)
;;; files-tests.el ends here
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index cba697da18..0c5ea03741 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -41,6 +41,7 @@
;;; Code:
+(require 'cl-seq)
(require 'dired)
(require 'ert)
(require 'ert-x)
@@ -2270,6 +2271,34 @@ tramp--test-print-duration
;; Cleanup.
(ignore-errors (delete-file tmp-name))))))
+(ert-deftest tramp-test10-write-region-file-precious-flag ()
+ "Check that `file-precious-flag' is respected with Tramp in use."
+ (skip-unless (tramp--test-enabled))
+ (skip-unless (tramp--test-sh-p))
+
+ (let* ((tmp-name (tramp--test-make-temp-name))
+ written-files
+ (advice (lambda (_start _end filename &rest _r)
+ (push filename written-files))))
+
+ (unwind-protect
+ (with-current-buffer (find-file-noselect tmp-name)
+ ;; Write initial contents. Adapt `visited-file-modtime'
+ ;; in order to suppress confirmation.
+ (insert "foo")
+ (write-region nil nil tmp-name)
+ (set-visited-file-modtime)
+ ;; Run the test.
+ (advice-add 'write-region :before advice)
+ (setq-local file-precious-flag t)
+ (insert "bar")
+ (should (null (save-buffer)))
+ (should-not (cl-member tmp-name written-files :test #'string=)))
+
+ ;; Cleanup.
+ (ignore-errors (advice-remove 'write-region advice))
+ (ignore-errors (delete-file tmp-name)))))
+
(ert-deftest tramp-test11-copy-file ()
"Check `copy-file'."
(skip-unless (tramp--test-enabled))
--
2.21.0.1020.gf2820cf01a-goog
next prev parent reply other threads:[~2019-05-07 17:33 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-04-29 23:20 bug#35497: [PATCH] Don't rewrite buffer contents after saving by rename Jonathan Tomer
2019-04-30 7:18 ` Michael Albinus
2019-04-30 19:27 ` Jonathan Tomer
2019-04-30 20:47 ` Michael Albinus
2019-04-30 21:10 ` Jonathan Tomer
2019-04-30 21:21 ` Michael Albinus
2019-04-30 22:42 ` Jonathan Tomer
2019-05-01 0:26 ` bug#35497: [PATCH v2] " Jonathan Tomer
2019-05-01 17:48 ` bug#35497: [PATCH] " Eli Zaretskii
2019-05-01 19:29 ` Jonathan Tomer
2019-05-01 19:54 ` Eli Zaretskii
2019-05-01 19:56 ` Jonathan Tomer
2019-05-01 23:02 ` bug#35497: [PATCH v3] " Jonathan Tomer
2019-05-02 11:50 ` Michael Albinus
2019-05-02 22:04 ` Jonathan Tomer
2019-05-02 22:06 ` bug#35497: [PATCH v4] " Jonathan Tomer
2019-05-03 7:52 ` Michael Albinus
2019-05-03 12:29 ` Eli Zaretskii
2019-05-06 20:45 ` Jonathan Tomer
2019-05-07 14:05 ` Michael Albinus
2019-05-07 23:46 ` Richard Stallman
2019-05-06 20:46 ` bug#35497: [PATCH v5] " Jonathan Tomer
2019-05-06 20:48 ` bug#35497: [PATCH v6] " Jonathan Tomer
2019-05-07 14:03 ` Michael Albinus
2019-05-07 14:10 ` Michael Albinus
2019-05-07 17:25 ` Jonathan Tomer
2019-05-07 17:33 ` Jonathan Tomer [this message]
2019-05-08 7:48 ` bug#35497: [PATCH v7] " Michael Albinus
2019-05-08 17:03 ` Jonathan Tomer
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
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190507173328.140935-1-jktomer@google.com \
--to=jktomer@google.com \
--cc=35497@debbugs.gnu.org \
--cc=eliz@gnu.org \
--cc=michael.albinus@gmx.de \
/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 external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.