Skip to content

Commit 525d5ca

Browse files
committed
Preserve backward compatibility in Tramp
* lisp/net/tramp-crypt.el (tramp-crypt-handle-lock-file) (tramp-crypt-handle-unlock-file): Preserve backward compatibility. * lisp/net/tramp-sh.el (tramp-sh-handle-write-region): Do not create lock file twice. * lisp/net/tramp.el (tramp-handle-make-lock-file-name): Move lock file security check ... (tramp-handle-lock-file): ... here. (tramp-handle-unlock-file): Preserve backward compatibility. * test/lisp/net/tramp-tests.el (lock-file-name-transforms) (remote-file-name-inhibit-locks): Declare. (tramp-allow-unsafe-temporary-files): Set to t. (tramp-test37-make-auto-save-file-name) (tramp-test38-find-backup-file-name): Move binding of `tramp-allow-unsafe-temporary-files' up. (tramp-test39-lock-file): Bind `tramp-allow-unsafe-temporary-files'. Preserve backward compatibility. Extend test.
1 parent f45710e commit 525d5ca

File tree

4 files changed

+100
-57
lines changed

4 files changed

+100
-57
lines changed

lisp/net/tramp-crypt.el

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,9 @@ WILDCARD is not supported."
809809
(defun tramp-crypt-handle-lock-file (filename)
810810
"Like `lock-file' for Tramp files."
811811
(let (tramp-crypt-enabled)
812-
(lock-file (tramp-crypt-encrypt-file-name filename))))
812+
;; `lock-file' exists since Emacs 28.1.
813+
(tramp-compat-funcall
814+
'lock-file (tramp-crypt-encrypt-file-name filename))))
813815

814816
(defun tramp-crypt-handle-make-directory (dir &optional parents)
815817
"Like `make-directory' for Tramp files."
@@ -865,7 +867,9 @@ WILDCARD is not supported."
865867
(defun tramp-crypt-handle-unlock-file (filename)
866868
"Like `unlock-file' for Tramp files."
867869
(let (tramp-crypt-enabled)
868-
(unlock-file (tramp-crypt-encrypt-file-name filename))))
870+
;; `unlock-file' exists since Emacs 28.1.
871+
(tramp-compat-funcall
872+
'unlock-file (tramp-crypt-encrypt-file-name filename))))
869873

870874
(add-hook 'tramp-unload-hook
871875
(lambda ()

lisp/net/tramp-sh.el

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3272,7 +3272,8 @@ implementation will be used."
32723272
(or (file-directory-p localname)
32733273
(file-writable-p localname)))
32743274
;; Short track: if we are on the local host, we can run directly.
3275-
(write-region start end localname append 'no-message lockname)
3275+
(let ((create-lockfiles (not file-locked)))
3276+
(write-region start end localname append 'no-message lockname))
32763277

32773278
(let* ((modes (tramp-default-file-modes
32783279
filename (and (eq mustbenew 'excl) 'nofollow)))

lisp/net/tramp.el

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3873,43 +3873,44 @@ Return nil when there is no lockfile."
38733873
(format
38743874
"%s@%s.%s" (user-login-name) (system-name)
38753875
(tramp-get-lock-pid file))))
3876+
3877+
;; Protect against security hole.
3878+
(with-parsed-tramp-file-name file nil
3879+
(when (and (not tramp-allow-unsafe-temporary-files)
3880+
(file-in-directory-p lockname temporary-file-directory)
3881+
(zerop (or (tramp-compat-file-attribute-user-id
3882+
(file-attributes file 'integer))
3883+
tramp-unknown-id-integer))
3884+
(not (with-tramp-connection-property
3885+
(tramp-get-process v) "unsafe-temporary-file"
3886+
(yes-or-no-p
3887+
(concat
3888+
"Lock file on local temporary directory, "
3889+
"do you want to continue? ")))))
3890+
(tramp-error v 'file-error "Unsafe lock file name")))
3891+
3892+
;; Do the lock.
38763893
(let (create-lockfiles signal-hook-function)
38773894
(condition-case nil
38783895
(make-symbolic-link info lockname 'ok-if-already-exists)
38793896
(error
3880-
(write-region info nil lockname)
3881-
(set-file-modes lockname #o0644))))))))
3897+
(with-file-modes #o0644
3898+
(write-region info nil lockname)))))))))
38823899

38833900
(defun tramp-handle-make-lock-file-name (file)
38843901
"Like `make-lock-file-name' for Tramp files."
3885-
(when (and create-lockfiles
3886-
;; This variable has been introduced with Emacs 28.1.
3887-
(not (bound-and-true-p remote-file-name-inhibit-locks)))
3888-
(with-parsed-tramp-file-name file nil
3889-
(let ((result
3890-
;; Run plain `make-lock-file-name'.
3891-
(tramp-run-real-handler #'make-lock-file-name (list file))))
3892-
;; Protect against security hole.
3893-
(when (and (not tramp-allow-unsafe-temporary-files)
3894-
(file-in-directory-p result temporary-file-directory)
3895-
(zerop (or (tramp-compat-file-attribute-user-id
3896-
(file-attributes file 'integer))
3897-
tramp-unknown-id-integer))
3898-
(not (with-tramp-connection-property
3899-
(tramp-get-process v) "unsafe-temporary-file"
3900-
(yes-or-no-p
3901-
(concat
3902-
"Lock file on local temporary directory, "
3903-
"do you want to continue? ")))))
3904-
(tramp-error v 'file-error "Unsafe lock file name"))
3905-
result))))
3902+
(and create-lockfiles
3903+
;; This variable has been introduced with Emacs 28.1.
3904+
(not (bound-and-true-p remote-file-name-inhibit-locks))
3905+
(tramp-run-real-handler 'make-lock-file-name (list file))))
39063906

39073907
(defun tramp-handle-unlock-file (file)
39083908
"Like `unlock-file' for Tramp files."
39093909
(when-let ((lockname (tramp-compat-make-lock-file-name file)))
39103910
(condition-case err
39113911
(delete-file lockname)
3912-
(error (userlock--handle-unlock-error err)))))
3912+
;; `userlock--handle-unlock-error' exists since Emacs 28.1.
3913+
(error (tramp-compat-funcall 'userlock--handle-unlock-error err)))))
39133914

39143915
(defun tramp-handle-load (file &optional noerror nomessage nosuffix must-suffix)
39153916
"Like `load' for Tramp files."

test/lisp/net/tramp-tests.el

Lines changed: 67 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
(declare-function tramp-smb-get-localname "tramp-smb")
6464
(defvar ange-ftp-make-backup-files)
6565
(defvar auto-save-file-name-transforms)
66+
(defvar lock-file-name-transforms)
67+
(defvar remote-file-name-inhibit-locks)
6668
(defvar tramp-connection-properties)
6769
(defvar tramp-copy-size-limit)
6870
(defvar tramp-display-escape-sequence-regexp)
@@ -122,6 +124,7 @@
122124
(setq auth-source-save-behavior nil
123125
password-cache-expiry nil
124126
remote-file-name-inhibit-cache nil
127+
tramp-allow-unsafe-temporary-files t
125128
tramp-cache-read-persistent-data t ;; For auth-sources.
126129
tramp-copy-size-limit nil
127130
tramp-persistency-file-name nil
@@ -5481,7 +5484,8 @@ Use direct async.")
54815484

54825485
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
54835486
(let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
5484-
(tmp-name2 (tramp--test-make-temp-name nil quoted)))
5487+
(tmp-name2 (tramp--test-make-temp-name nil quoted))
5488+
tramp-allow-unsafe-temporary-files)
54855489

54865490
(unwind-protect
54875491
(progn
@@ -5569,8 +5573,7 @@ Use direct async.")
55695573

55705574
;; Create temporary file. This shall check for sensible
55715575
;; files, owned by root.
5572-
(let ((tramp-auto-save-directory temporary-file-directory)
5573-
tramp-allow-unsafe-temporary-files)
5576+
(let ((tramp-auto-save-directory temporary-file-directory))
55745577
(write-region "foo" nil tmp-name1)
55755578
(when (zerop (or (tramp-compat-file-attribute-user-id
55765579
(file-attributes tmp-name1))
@@ -5606,6 +5609,7 @@ Use direct async.")
56065609
(let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
56075610
(tmp-name2 (tramp--test-make-temp-name nil quoted))
56085611
(ange-ftp-make-backup-files t)
5612+
tramp-allow-unsafe-temporary-files
56095613
;; These settings are not used by Tramp, so we ignore them.
56105614
version-control delete-old-versions
56115615
(kept-old-versions (default-toplevel-value 'kept-old-versions))
@@ -5716,7 +5720,6 @@ Use direct async.")
57165720
;; Create temporary file. This shall check for sensible
57175721
;; files, owned by root.
57185722
(let ((backup-directory-alist `(("." . ,temporary-file-directory)))
5719-
tramp-allow-unsafe-temporary-files
57205723
tramp-backup-directory-alist)
57215724
(write-region "foo" nil tmp-name1)
57225725
(when (zerop (or (tramp-compat-file-attribute-user-id
@@ -5749,13 +5752,18 @@ Use direct async.")
57495752
(skip-unless (not (tramp--test-ange-ftp-p)))
57505753
;; Since Emacs 28.1.
57515754
(skip-unless (and (fboundp 'lock-file) (fboundp 'unlock-file)))
5755+
(skip-unless (and (fboundp 'file-locked-p) (fboundp 'make-lock-file-name)))
57525756

5757+
;; `lock-file', `unlock-file', `file-locked-p' and
5758+
;; `make-lock-file-name' exists since Emacs 28.1. We don't want to
5759+
;; see compiler warnings for older Emacsen.
57535760
(dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
57545761
(let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
57555762
(tmp-name2 (tramp--test-make-temp-name nil quoted))
57565763
(remote-file-name-inhibit-cache t)
57575764
(remote-file-name-inhibit-locks nil)
57585765
(create-lockfiles t)
5766+
tramp-allow-unsafe-temporary-files
57595767
(inhibit-message t)
57605768
;; tramp-rclone.el and tramp-sshfs.el cache the mounted files.
57615769
(tramp-cleanup-connection-hook
@@ -5767,73 +5775,102 @@ Use direct async.")
57675775
(unwind-protect
57685776
(progn
57695777
;; A simple file lock.
5770-
(should-not (file-locked-p tmp-name1))
5771-
(lock-file tmp-name1)
5772-
(should (eq (file-locked-p tmp-name1) t))
5778+
(should-not (with-no-warnings (file-locked-p tmp-name1)))
5779+
(with-no-warnings (lock-file tmp-name1))
5780+
(should (eq (with-no-warnings (file-locked-p tmp-name1)) t))
57735781

57745782
;; If it is locked already, nothing changes.
5775-
(lock-file tmp-name1)
5776-
(should (eq (file-locked-p tmp-name1) t))
5783+
(with-no-warnings (lock-file tmp-name1))
5784+
(should (eq (with-no-warnings (file-locked-p tmp-name1)) t))
57775785

57785786
;; A new connection changes process id, and also the
57795787
;; lockname contents.
57805788
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
5781-
(should (stringp (file-locked-p tmp-name1)))
5789+
(should (stringp (with-no-warnings (file-locked-p tmp-name1))))
57825790

57835791
;; When `remote-file-name-inhibit-locks' is set, nothing happens.
57845792
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
57855793
(let ((remote-file-name-inhibit-locks t))
5786-
(lock-file tmp-name1)
5787-
(should-not (file-locked-p tmp-name1)))
5794+
(with-no-warnings (lock-file tmp-name1))
5795+
(should-not (with-no-warnings (file-locked-p tmp-name1))))
57885796

57895797
;; When `lock-file-name-transforms' is set, another lock
57905798
;; file is used.
57915799
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
57925800
(let ((lock-file-name-transforms `((".*" ,tmp-name2))))
57935801
(should
57945802
(string-equal
5795-
(make-lock-file-name tmp-name1)
5796-
(make-lock-file-name tmp-name2)))
5797-
(lock-file tmp-name1)
5798-
(should (eq (file-locked-p tmp-name1) t))
5799-
(unlock-file tmp-name1)
5800-
(should-not (file-locked-p tmp-name1)))
5803+
(with-no-warnings (make-lock-file-name tmp-name1))
5804+
(with-no-warnings (make-lock-file-name tmp-name2))))
5805+
(with-no-warnings (lock-file tmp-name1))
5806+
(should (eq (with-no-warnings (file-locked-p tmp-name1)) t))
5807+
(with-no-warnings (unlock-file tmp-name1))
5808+
(should-not (with-no-warnings (file-locked-p tmp-name1))))
58015809

58025810
;; Steal the file lock.
58035811
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
58045812
(cl-letf (((symbol-function #'read-char) (lambda (&rest _args) ?s)))
5805-
(lock-file tmp-name1))
5806-
(should (eq (file-locked-p tmp-name1) t))
5813+
(with-no-warnings (lock-file tmp-name1)))
5814+
(should (eq (with-no-warnings (file-locked-p tmp-name1)) t))
58075815

58085816
;; Ignore the file lock.
58095817
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
58105818
(cl-letf (((symbol-function #'read-char) (lambda (&rest _args) ?p)))
5811-
(lock-file tmp-name1))
5812-
(should (stringp (file-locked-p tmp-name1)))
5819+
(with-no-warnings (lock-file tmp-name1)))
5820+
(should (stringp (with-no-warnings (file-locked-p tmp-name1))))
58135821

58145822
;; Quit the file lock machinery.
58155823
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)
58165824
(cl-letf (((symbol-function #'read-char) (lambda (&rest _args) ?q)))
5817-
(should-error (lock-file tmp-name1) :type 'file-locked)
5825+
(with-no-warnings
5826+
(should-error
5827+
(lock-file tmp-name1)
5828+
:type 'file-locked))
58185829
;; The same for `write-region'.
58195830
(should-error
5820-
(write-region "foo" nil tmp-name1) :type 'file-locked)
5831+
(write-region "foo" nil tmp-name1)
5832+
:type 'file-locked)
58215833
(should-error
58225834
(write-region "foo" nil tmp-name1 nil nil tmp-name1)
58235835
:type 'file-locked)
58245836
;; The same for `set-visited-file-name'.
58255837
(with-temp-buffer
58265838
(should-error
5827-
(set-visited-file-name tmp-name1) :type 'file-locked)))
5828-
(should (stringp (file-locked-p tmp-name1)))
5839+
(set-visited-file-name tmp-name1)
5840+
:type 'file-locked)))
5841+
(should (stringp (with-no-warnings (file-locked-p tmp-name1))))
58295842
(should-not (file-exists-p tmp-name1)))
58305843

58315844
;; Cleanup.
58325845
(ignore-errors (delete-file tmp-name1))
5833-
(unlock-file tmp-name1)
5834-
(unlock-file tmp-name2)
5835-
(should-not (file-locked-p tmp-name1))
5836-
(should-not (file-locked-p tmp-name2))))))
5846+
(with-no-warnings (unlock-file tmp-name1))
5847+
(with-no-warnings (unlock-file tmp-name2))
5848+
(should-not (with-no-warnings (file-locked-p tmp-name1)))
5849+
(should-not (with-no-warnings (file-locked-p tmp-name2))))
5850+
5851+
(unwind-protect
5852+
;; Create temporary file. This shall check for sensible
5853+
;; files, owned by root.
5854+
(let ((lock-file-name-transforms auto-save-file-name-transforms))
5855+
(write-region "foo" nil tmp-name1)
5856+
(when (zerop (or (tramp-compat-file-attribute-user-id
5857+
(file-attributes tmp-name1))
5858+
tramp-unknown-id-integer))
5859+
(tramp-cleanup-connection
5860+
tramp-test-vec 'keep-debug 'keep-password)
5861+
(cl-letf (((symbol-function #'yes-or-no-p) #'ignore))
5862+
(should-error
5863+
(write-region "foo" nil tmp-name1)
5864+
:type 'file-error))
5865+
(tramp-cleanup-connection
5866+
tramp-test-vec 'keep-debug 'keep-password)
5867+
(cl-letf (((symbol-function #'yes-or-no-p)
5868+
#'tramp--test-always))
5869+
(write-region "foo" nil tmp-name1))))
5870+
5871+
;; Cleanup.
5872+
(ignore-errors (delete-file tmp-name1))
5873+
(tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password)))))
58375874

58385875
;; The functions were introduced in Emacs 26.1.
58395876
(ert-deftest tramp-test40-make-nearby-temp-file ()

0 commit comments

Comments
 (0)