branch: externals/tramp commit 41bdf56b37f1b869f8f40eb811b222c562302e7f Author: Michael Albinus <michael.albi...@gmx.de> Commit: Michael Albinus <michael.albi...@gmx.de>
Tramp ELPA version 2.5.1 released --- test/tramp-tests.el | 90 ++++++++++++++++++++++++++++++++++----- texi/tramp.texi | 17 +++++--- tramp-adb.el | 3 +- tramp-archive.el | 2 + tramp-cache.el | 7 ++-- tramp-sh.el | 15 ++----- tramp.el | 118 ++++++++++++++++++++++++++++++++++++---------------- trampver.el | 6 +-- 8 files changed, 186 insertions(+), 72 deletions(-) diff --git a/test/tramp-tests.el b/test/tramp-tests.el index 66bfe73..68caadb 100644 --- a/test/tramp-tests.el +++ b/test/tramp-tests.el @@ -229,6 +229,16 @@ is greater than 10. "%s %f sec" ,message (float-time (time-subtract (current-time) start)))))) +;; `always' is introduced with Emacs 28.1. +(defalias 'tramp--test-always + (if (fboundp 'always) + #'always + (lambda (&rest _arguments) + "Do nothing and return t. +This function accepts any number of ARGUMENTS, but ignores them. +Also see `ignore'." + t))) + (ert-deftest tramp-test00-availability () "Test availability of Tramp functions." :expected-result (if (tramp--test-enabled) :passed :failed) @@ -2454,9 +2464,9 @@ This checks also `file-name-as-directory', `file-name-directory', tramp--test-messages)))))))) ;; Do not overwrite if excluded. - (cl-letf (((symbol-function #'y-or-n-p) (lambda (_prompt) t)) + (cl-letf (((symbol-function #'y-or-n-p) #'tramp--test-always) ;; Ange-FTP. - ((symbol-function 'yes-or-no-p) (lambda (_prompt) t))) + ((symbol-function 'yes-or-no-p) #'tramp--test-always)) (write-region "foo" nil tmp-name nil nil nil 'mustbenew)) ;; `mustbenew' is passed to Tramp since Emacs 26.1. (when (tramp--test-emacs26-p) @@ -3671,7 +3681,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should-error (make-symbolic-link tmp-name1 tmp-name2 0) :type 'file-already-exists))) - (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_prompt) t))) + (cl-letf (((symbol-function #'yes-or-no-p) #'tramp--test-always)) (make-symbolic-link tmp-name1 tmp-name2 0) (should (string-equal @@ -3747,7 +3757,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." (should-error (add-name-to-file tmp-name1 tmp-name2 0) :type 'file-already-exists)) - (cl-letf (((symbol-function #'yes-or-no-p) (lambda (_prompt) t))) + (cl-letf (((symbol-function #'yes-or-no-p) #'tramp--test-always)) (add-name-to-file tmp-name1 tmp-name2 0) (should (file-regular-p tmp-name2))) (add-name-to-file tmp-name1 tmp-name2 'ok-if-already-exists) @@ -4545,7 +4555,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." If UNSTABLE is non-nil, the test is tagged as `:unstable'." (declare (indent 1)) ;; `make-process' supports file name handlers since Emacs 27. - (when (let ((file-name-handler-alist '(("" . (lambda (&rest _) t))))) + (when (let ((file-name-handler-alist '(("" . #'tramp--test-always)))) (ignore-errors (make-process :file-handler t))) `(ert-deftest ,(intern (concat (symbol-name test) "-direct-async")) () ,docstring @@ -4561,7 +4571,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." ;; `file-truename' does it by side-effect. Suppress ;; `tramp--test-enabled', in order to keep the connection. ;; Suppress "Process ... finished" messages. - (cl-letf (((symbol-function #'tramp--test-enabled) (lambda nil t)) + (cl-letf (((symbol-function #'tramp--test-enabled) #'tramp--test-always) ((symbol-function #'internal-default-process-sentinel) #'ignore)) (file-truename tramp-test-temporary-file-directory) @@ -5554,11 +5564,38 @@ Use direct async.") ("]" . "_r")) (tramp-compat-file-name-unquote tmp-name1))) tmp-name2))) - (should (file-directory-p tmp-name2)))))) + (should (file-directory-p tmp-name2))))) + + ;; Create temporary file. This shall check for sensible + ;; files, owned by root. + (let ((tramp-auto-save-directory temporary-file-directory) + tramp-allow-unsafe-temporary-files) + (write-region "foo" nil tmp-name1) + (when (zerop (or (tramp-compat-file-attribute-user-id + (file-attributes tmp-name1)) + tramp-unknown-id-integer)) + (with-temp-buffer + (setq buffer-file-name tmp-name1) + (tramp-cleanup-connection + tramp-test-vec 'keep-debug 'keep-password) + (let ((tramp-allow-unsafe-temporary-files t)) + (should (stringp (make-auto-save-file-name)))) + (tramp-cleanup-connection + tramp-test-vec 'keep-debug 'keep-password) + (cl-letf (((symbol-function #'yes-or-no-p) #'ignore)) + (should-error + (make-auto-save-file-name) + :type 'file-error)) + (tramp-cleanup-connection + tramp-test-vec 'keep-debug 'keep-password) + (cl-letf (((symbol-function #'yes-or-no-p) + #'tramp--test-always)) + (should (stringp (make-auto-save-file-name)))))))) ;; Cleanup. (ignore-errors (delete-file tmp-name1)) - (ignore-errors (delete-directory tmp-name2 'recursive)))))) + (ignore-errors (delete-directory tmp-name2 'recursive)) + (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password))))) (ert-deftest tramp-test38-find-backup-file-name () "Check `find-backup-file-name'." @@ -5672,7 +5709,37 @@ Use direct async.") (should (file-directory-p tmp-name2)))) ;; Cleanup. - (ignore-errors (delete-directory tmp-name2 'recursive)))))) + (ignore-errors (delete-directory tmp-name2 'recursive))) + + (unwind-protect + ;; Create temporary file. This shall check for sensible + ;; files, owned by root. + (let ((backup-directory-alist `(("." . ,temporary-file-directory))) + tramp-allow-unsafe-temporary-files + tramp-backup-directory-alist) + (write-region "foo" nil tmp-name1) + (when (zerop (or (tramp-compat-file-attribute-user-id + (file-attributes tmp-name1)) + tramp-unknown-id-integer)) + (tramp-cleanup-connection + tramp-test-vec 'keep-debug 'keep-password) + (let ((tramp-allow-unsafe-temporary-files t)) + (should (stringp (car (find-backup-file-name tmp-name1))))) + (tramp-cleanup-connection + tramp-test-vec 'keep-debug 'keep-password) + (cl-letf (((symbol-function #'yes-or-no-p) #'ignore)) + (should-error + (find-backup-file-name tmp-name1) + :type 'file-error)) + (tramp-cleanup-connection + tramp-test-vec 'keep-debug 'keep-password) + (cl-letf (((symbol-function #'yes-or-no-p) + #'tramp--test-always)) + (should (stringp (car (find-backup-file-name tmp-name1))))))) + + ;; Cleanup. + (ignore-errors (delete-file tmp-name1)) + (tramp-cleanup-connection tramp-test-vec 'keep-debug 'keep-password))))) ;; The functions were introduced in Emacs 26.1. (ert-deftest tramp-test39-make-nearby-temp-file () @@ -6213,8 +6280,9 @@ Use the `ls' command." x "")) (not (string-empty-p x)) ;; ?\n and ?/ shouldn't be part of any file name. ?\t, - ;; ?. and ?? do not work for "smb" method. - (replace-regexp-in-string "[\t\n/.?]" "" x))) + ;; ?. and ?? do not work for "smb" method. " " does not + ;; work at begin or end of the string for MS Windows. + (replace-regexp-in-string "[ \t\n/.?]" "" x))) language-info-alist))))))) (ert-deftest tramp-test41-utf8 () diff --git a/texi/tramp.texi b/texi/tramp.texi index 63b6eb8..9c20b3d 100644 --- a/texi/tramp.texi +++ b/texi/tramp.texi @@ -1261,7 +1261,7 @@ uses @file{@trampfn{mtp,,}} as the default name. As the name indicates, the method @option{nextcloud} allows you to access OwnCloud or NextCloud hosted files and directories. Like the @option{gdrive} method, your credentials must be populated in your -@command{Online Accounts} application outside Emacs. The method +@command{Online Accounts} application outside Emacs. The method supports port numbers. @item @option{sftp} @@ -2842,6 +2842,13 @@ auto-saved files to the same directory as the original file. Alternatively, set the user option @code{tramp-auto-save-directory} to direct all auto saves to that location. +@vindex tramp-allow-unsafe-temporary-files +Per default, @value{tramp} asks for confirmation if a +@samp{root}-owned backup or auto-save remote file has to be written to +your local temporary directory. If you want to suppress this +confirmation question, set user option +@code{tramp-allow-unsafe-temporary-files} to @code{t}. + @node Keeping files encrypted @section Protect remote files by encryption @@ -3309,12 +3316,12 @@ For ad-hoc definitions to be saved automatically in Ad-hoc proxies can take patterns @code{%h} or @code{%u} like in @code{tramp-default-proxies-alist}. The following file name expands -to user @code{root} on host @code{remotehost}, starting with an -@option{ssh} session on host @code{remotehost}: +to user @samp{root} on host @samp{remotehost}, starting with an +@option{ssh} session on host @samp{remotehost}: @samp{@value{prefix}ssh@value{postfixhop}%h|su@value{postfixhop}remotehost@value{postfix}}. On the other hand, if a trailing hop does not specify a host name, -the host name of the previous hop is reused. Therefore, the following +the host name of the previous hop is reused. Therefore, the following file name is equivalent to the previous example: @samp{@value{prefix}ssh@value{postfixhop}remotehost|su@value{postfixhop}@value{postfix}}. @@ -5294,7 +5301,7 @@ attributes cache in its process sentinel with this code: @end lisp Since @value{tramp} traverses subdirectories starting with the -root-directory, it is most likely sufficient to make the +root directory, it is most likely sufficient to make the @code{default-directory} of the process buffer as the root directory. diff --git a/tramp-adb.el b/tramp-adb.el index aacf83e..7fb0ff5 100644 --- a/tramp-adb.el +++ b/tramp-adb.el @@ -549,8 +549,7 @@ But handle the case, if the \"test\" command is not available." (when (and append (file-exists-p filename)) (copy-file filename tmpfile 'ok) (set-file-modes tmpfile (logior (or (file-modes tmpfile) 0) #o0600))) - (tramp-run-real-handler - #'write-region (list start end tmpfile append 'no-message lockname)) + (write-region start end tmpfile append 'no-message lockname) (with-tramp-progress-reporter v 3 (format-message "Moving tmp file `%s' to `%s'" tmpfile filename) diff --git a/tramp-archive.el b/tramp-archive.el index d2ee729..d723fd5 100644 --- a/tramp-archive.el +++ b/tramp-archive.el @@ -328,6 +328,8 @@ arguments to pass to the OPERATION." ;; `filename' could be a quoted file name. Or the file ;; archive could be a directory, see Bug#30293. (if (or (null archive) + (not (tramp-archive-run-real-handler + #'file-exists-p (list archive))) (tramp-archive-run-real-handler #'file-directory-p (list archive))) (tramp-archive-run-real-handler operation args) diff --git a/tramp-cache.el b/tramp-cache.el index 4d5edc5..2d11c89 100644 --- a/tramp-cache.el +++ b/tramp-cache.el @@ -70,7 +70,8 @@ ;; process key retrieved by `tramp-get-process' (the main connection ;; process). Other processes could reuse these properties, avoiding ;; recomputation when a new asynchronous process is created by -;; `make-process'. Examples are "remote-path" or "device" (tramp-adb.el). +;; `make-process'. Examples are "remote-path", +;; "unsafe-temporary-file" or "device" (tramp-adb.el). ;;; Code: @@ -472,11 +473,11 @@ used to cache connection properties of the local machine." ;; don't save either, because all other properties might ;; depend on the login name, and we want to give the ;; possibility to use another login name later on. Key - ;; "started" exists for the "ftp" method only, which must be + ;; "started" exists for the "ftp" method only, which must not ;; be kept persistent. (maphash (lambda (key value) - (if (and (tramp-file-name-p key) value + (if (and (tramp-file-name-p key) (hash-table-p value) (not (string-equal (tramp-file-name-method key) tramp-archive-method)) (not (tramp-file-name-localname key)) diff --git a/tramp-sh.el b/tramp-sh.el index 29ed944..ebd0fbf 100644 --- a/tramp-sh.el +++ b/tramp-sh.el @@ -3225,7 +3225,6 @@ implementation will be used." (run-hooks 'tramp-handle-file-local-copy-hook) tmpfile))) -;; CCC grok LOCKNAME (defun tramp-sh-handle-write-region (start end filename &optional append visit lockname mustbenew) "Like `write-region' for Tramp files." @@ -3254,9 +3253,7 @@ implementation will be used." (or (file-directory-p localname) (file-writable-p localname))))) ;; Short track: if we are on the local host, we can run directly. - (tramp-run-real-handler - #'write-region - (list start end localname append 'no-message lockname)) + (write-region start end localname append 'no-message lockname) (let* ((modes (tramp-default-file-modes filename (and (eq mustbenew 'excl) 'nofollow))) @@ -3289,13 +3286,10 @@ implementation will be used." ;; file. We call `set-visited-file-modtime' ourselves later ;; on. We must ensure that `file-coding-system-alist' ;; matches `tmpfile'. - (let (file-name-handler-alist - (file-coding-system-alist + (let ((file-coding-system-alist (tramp-find-file-name-coding-system-alist filename tmpfile))) (condition-case err - (tramp-run-real-handler - #'write-region - (list start end tmpfile append 'no-message lockname)) + (write-region start end tmpfile append 'no-message lockname) ((error quit) (setq tramp-temp-buffer-file-name nil) (delete-file tmpfile) @@ -5296,8 +5290,7 @@ Nonexistent directories are removed from spec." ;; cache the result for the session only. Otherwise, the ;; result is cached persistently. (if (memq 'tramp-own-remote-path tramp-remote-path) - (tramp-get-process vec) - vec) + (tramp-get-process vec) vec) "remote-path" (let* ((remote-path (copy-tree tramp-remote-path)) (elt1 (memq 'tramp-default-remote-path remote-path)) diff --git a/tramp.el b/tramp.el index 0b80175..10f4a2b 100644 --- a/tramp.el +++ b/tramp.el @@ -2052,7 +2052,7 @@ function is meant for debugging purposes." (put #'tramp-backtrace 'tramp-suppress-trace t) -(defsubst tramp-error (vec-or-proc signal fmt-string &rest arguments) +(defun tramp-error (vec-or-proc signal fmt-string &rest arguments) "Emit an error. VEC-OR-PROC identifies the connection to use, SIGNAL is the signal identifier to be raised, remaining arguments passed to @@ -2644,7 +2644,14 @@ If Emacs is compiled --with-threads, the body is protected by a mutex." ;; When `tramp-mode' is not enabled, or the file name is quoted, ;; we don't do anything. - (tramp-run-real-handler operation args)))) + ;; When operation is `expand-file-name', and the first argument + ;; is a local absolute file name, we end also here. Handle the + ;; MS Windows case. + (funcall + (if (and (eq operation 'expand-file-name) + (not (string-match-p "\\`[[:alpha:]]:/" (car args)))) + #'tramp-drop-volume-letter #'identity) + (tramp-run-real-handler operation args))))) (defun tramp-completion-file-name-handler (operation &rest args) "Invoke Tramp file name completion handler for OPERATION and ARGS. @@ -3661,6 +3668,11 @@ User is always nil." (and (file-directory-p (file-name-directory filename)) (file-writable-p (file-name-directory filename))))))) +(defcustom tramp-allow-unsafe-temporary-files nil + "Whether root-owned auto-save or backup files can be written to \"/tmp\"." + :version "28.1" + :type 'boolean) + (defun tramp-handle-find-backup-file-name (filename) "Like `find-backup-file-name' for Tramp files." (with-parsed-tramp-file-name filename nil @@ -3676,8 +3688,25 @@ User is always nil." (tramp-make-tramp-file-name v (cdr x)) (cdr x)))) tramp-backup-directory-alist) - backup-directory-alist))) - (tramp-run-real-handler #'find-backup-file-name (list filename))))) + backup-directory-alist)) + result) + (prog1 ;; Run plain `find-backup-file-name'. + (setq result + (tramp-run-real-handler + #'find-backup-file-name (list filename))) + ;; Protect against security hole. + (when (and (not tramp-allow-unsafe-temporary-files) + (file-in-directory-p (car result) temporary-file-directory) + (zerop (or (tramp-compat-file-attribute-user-id + (file-attributes filename 'integer)) + tramp-unknown-id-integer)) + (not (with-tramp-connection-property + (tramp-get-process v) "unsafe-temporary-file" + (yes-or-no-p + (concat + "Backup file on local temporary directory, " + "do you want to continue? "))))) + (tramp-error v 'file-error "Unsafe backup file name")))))) (defun tramp-handle-insert-directory (filename switches &optional wildcard full-directory-p) @@ -4398,8 +4427,7 @@ of." ;; We say `no-message' here because we don't want the visited file ;; modtime data to be clobbered from the temp file. We call ;; `set-visited-file-modtime' ourselves later on. - (tramp-run-real-handler - #'write-region (list start end tmpfile append 'no-message lockname)) + (write-region start end tmpfile append 'no-message lockname) (condition-case nil (rename-file tmpfile filename 'ok-if-already-exists) (error @@ -5259,37 +5287,53 @@ Return the local name of the temporary file." "Like `make-auto-save-file-name' for Tramp files. Returns a file name in `tramp-auto-save-directory' for autosaving this file, if that variable is non-nil." - (when (stringp tramp-auto-save-directory) - (setq tramp-auto-save-directory - (expand-file-name tramp-auto-save-directory))) - ;; Create directory. - (unless (or (null tramp-auto-save-directory) - (file-exists-p tramp-auto-save-directory)) - (make-directory tramp-auto-save-directory t)) - - (let ((system-type - (if (and (stringp tramp-auto-save-directory) - (tramp-tramp-file-p tramp-auto-save-directory)) - 'not-windows - system-type)) - (auto-save-file-name-transforms - (if (null tramp-auto-save-directory) - auto-save-file-name-transforms)) - (buffer-file-name - (if (null tramp-auto-save-directory) - buffer-file-name - (expand-file-name - (tramp-subst-strs-in-string - '(("_" . "|") - ("/" . "_a") - (":" . "_b") - ("|" . "__") - ("[" . "_l") - ("]" . "_r")) - (tramp-compat-file-name-unquote (buffer-file-name))) - tramp-auto-save-directory)))) - ;; Run plain `make-auto-save-file-name'. - (tramp-run-real-handler #'make-auto-save-file-name nil))) + (with-parsed-tramp-file-name buffer-file-name nil + (when (stringp tramp-auto-save-directory) + (setq tramp-auto-save-directory + (expand-file-name tramp-auto-save-directory))) + ;; Create directory. + (unless (or (null tramp-auto-save-directory) + (file-exists-p tramp-auto-save-directory)) + (make-directory tramp-auto-save-directory t)) + + (let ((system-type + (if (and (stringp tramp-auto-save-directory) + (tramp-tramp-file-p tramp-auto-save-directory)) + 'not-windows + system-type)) + (auto-save-file-name-transforms + (if (null tramp-auto-save-directory) + auto-save-file-name-transforms)) + (filename buffer-file-name) + (buffer-file-name + (if (null tramp-auto-save-directory) + buffer-file-name + (expand-file-name + (tramp-subst-strs-in-string + '(("_" . "|") + ("/" . "_a") + (":" . "_b") + ("|" . "__") + ("[" . "_l") + ("]" . "_r")) + (tramp-compat-file-name-unquote (buffer-file-name))) + tramp-auto-save-directory))) + result) + (prog1 ;; Run plain `make-auto-save-file-name'. + (setq result (tramp-run-real-handler #'make-auto-save-file-name nil)) + ;; Protect against security hole. + (when (and (not tramp-allow-unsafe-temporary-files) + (file-in-directory-p result temporary-file-directory) + (zerop (or (tramp-compat-file-attribute-user-id + (file-attributes filename 'integer)) + tramp-unknown-id-integer)) + (not (with-tramp-connection-property + (tramp-get-process v) "unsafe-temporary-file" + (yes-or-no-p + (concat + "Autosave file on local temporary directory, " + "do you want to continue? "))))) + (tramp-error v 'file-error "Unsafe autosave file name")))))) (defun tramp-subst-strs-in-string (alist string) "Replace all occurrences of the string FROM with TO in STRING. diff --git a/trampver.el b/trampver.el index 6c041b2..e6cf4c6 100644 --- a/trampver.el +++ b/trampver.el @@ -7,7 +7,7 @@ ;; Maintainer: Michael Albinus <michael.albi...@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.5.0.5 +;; Version: 2.5.1 ;; Package-Requires: ((emacs "25.1")) ;; Package-Type: multi ;; URL: https://www.gnu.org/software/tramp/ @@ -40,7 +40,7 @@ ;; ./configure" to change them. ;;;###tramp-autoload -(defconst tramp-version "2.5.0.5" +(defconst tramp-version "2.5.1" "This version of Tramp.") ;;;###tramp-autoload @@ -76,7 +76,7 @@ ;; Check for Emacs version. (let ((x (if (not (string-lessp emacs-version "25.1")) "ok" - (format "Tramp 2.5.0.5 is not fit for %s" + (format "Tramp 2.5.1 is not fit for %s" (replace-regexp-in-string "\n" "" (emacs-version)))))) (unless (string-equal "ok" x) (error "%s" x)))