diff options
| author | Michael Albinus <michael.albinus@gmx.de> | 2026-04-29 08:51:08 +0200 |
|---|---|---|
| committer | Michael Albinus <michael.albinus@gmx.de> | 2026-04-29 08:51:08 +0200 |
| commit | 16c625636811ab7b78ea238d063f0c7940196ddd (patch) | |
| tree | 8084eb9daf22b5173c87dd75b572f27d17c5bb0b | |
| parent | fe4488160a4c40c0540b31997b95764571a9202f (diff) | |
Tramp ELPA version 2.8.1.4 releasedexternals/tramp
| -rw-r--r-- | README | 6 | ||||
| -rw-r--r-- | test/tramp-tests.el | 149 | ||||
| -rw-r--r-- | texi/tramp.texi | 135 | ||||
| -rw-r--r-- | texi/trampver.texi | 2 | ||||
| -rw-r--r-- | tramp-cache.el | 14 | ||||
| -rw-r--r-- | tramp-container.el | 9 | ||||
| -rw-r--r-- | tramp-sh.el | 42 | ||||
| -rw-r--r-- | tramp-sshfs.el | 2 | ||||
| -rw-r--r-- | tramp.el | 214 | ||||
| -rw-r--r-- | trampver.el | 6 |
10 files changed, 433 insertions, 146 deletions
@@ -32,11 +32,11 @@ Emacs 28 or older • Remove all byte-compiled Tramp files - $ rm -f ~/.emacs.d/elpa/tramp-2.8.1.3/tramp*.elc + $ rm -f ~/.emacs.d/elpa/tramp-2.8.1.4/tramp*.elc • Start Emacs with Tramp's source files - $ emacs -L ~/.emacs.d/elpa/tramp-2.8.1.3 -l tramp + $ emacs -L ~/.emacs.d/elpa/tramp-2.8.1.4 -l tramp This should not give you the error. @@ -50,7 +50,7 @@ Mitigation of a bug in Emacs 29.1 --------------------------------- Due to a bug in Emacs 29.1, you must apply the following change prior -installation or upgrading Tramp 2.8.1.3 from GNU ELPA: +installation or upgrading Tramp 2.8.1.4 from GNU ELPA: (when (string-equal emacs-version "29.1") (with-current-buffer diff --git a/test/tramp-tests.el b/test/tramp-tests.el index 3972e5f..a19a17d 100644 --- a/test/tramp-tests.el +++ b/test/tramp-tests.el @@ -2287,6 +2287,8 @@ being the result.") (ert-deftest tramp-test03-file-error () "Check that Tramp signals an error in case of connection problems." + (skip-unless (tramp-file-name-p tramp-test-vec)) + ;; Connect to a non-existing host. (let ((vec (copy-tramp-file-name tramp-test-vec)) ;; Don't poison it. @@ -4473,6 +4475,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ;; Check, that files in symlinked directories still work. (make-symbolic-link tmp-name4 tmp-name6) (should (file-symlink-p tmp-name6)) + (should (file-directory-p tmp-name6)) (should-not (file-regular-p tmp-name6)) (write-region "foo" nil (expand-file-name "foo" tmp-name6)) (delete-file (expand-file-name "foo" tmp-name6)) @@ -5393,7 +5396,7 @@ This tests also `make-symbolic-link', `file-truename' and `add-name-to-file'." ;; boundaries are always incorrect before that. (skip-unless (tramp--test-emacs31-p)) - (let ((remote (file-remote-p ert-remote-temporary-file-directory))) + (when-let* ((remote (file-remote-p ert-remote-temporary-file-directory))) (dolist (file `(,remote ,(concat remote "/~/") ,(concat remote "/usr//usr/") ,(concat remote remote "//usr/"))) @@ -8858,10 +8861,19 @@ process sentinels. They shall not disturb each other." "Test operation." "Test operation") -(defun tramp--handler-for-test-operation (&optional _file) +(defun tramp--handle-test-operation (&optional _file) "Test operation handler." "Test operation handler") +(defun tramp--handle-process-id (process) + "Handler for `process-id'." + ;; Return something else. + (1+ (tramp-run-real-handler #'process-id (list process)))) + +(defun tramp--test-operation-file-name-for-operation (_operation &optional _file) + "Helper function for `tramp--test-operation' handler." + default-directory) + (ert-deftest tramp-test49-external-backend-function () "Check that Tramp handles external functions for a given backend." :tags '(:expensive-test) @@ -8878,78 +8890,167 @@ process sentinels. They shall not disturb each other." ;; There is no backend specific code. (should-not (string-equal (tramp--test-operation ert-remote-temporary-file-directory) - (tramp--handler-for-test-operation + (tramp--handle-test-operation ert-remote-temporary-file-directory))) (should-not (string-equal (tramp--test-operation temporary-file-directory) - (tramp--handler-for-test-operation + (tramp--handle-test-operation temporary-file-directory))) (let ((default-directory ert-remote-temporary-file-directory)) (should-not (string-equal (tramp--test-operation) - (tramp--handler-for-test-operation)))) + (tramp--handle-test-operation)))) (let ((default-directory temporary-file-directory)) (should-not (string-equal (tramp--test-operation) - (tramp--handler-for-test-operation)))) + (tramp--handle-test-operation)))) (should-error (tramp-add-external-operation - #'tramp--test-operation - #'tramp--handler-for-test-operation 'foo) + #'tramp--test-operation #'tramp--handle-test-operation 'foo) :type 'file-missing) + (should-error + (tramp-add-external-operation + #'tramp--test-operation #'tramp--handle-test-operation backend 'foo) + :type 'remote-file-error) + ;; This doesn't hurt. (tramp-add-external-operation - #'tramp--test-operation - #'tramp--handler-for-test-operation backend) + #'tramp--test-operation #'tramp--handle-test-operation backend 'file) + ;; The backend specific function is called. (should (string-equal (tramp--test-operation ert-remote-temporary-file-directory) - (tramp--handler-for-test-operation + (tramp--handle-test-operation ert-remote-temporary-file-directory))) (should-not (string-equal (tramp--test-operation temporary-file-directory) - (tramp--handler-for-test-operation + (tramp--handle-test-operation temporary-file-directory))) (let ((default-directory ert-remote-temporary-file-directory)) (should (string-equal (tramp--test-operation) - (tramp--handler-for-test-operation))) + (tramp--handle-test-operation))) (should (string-equal (tramp--test-operation "foo") - (tramp--handler-for-test-operation "foo")))) + (tramp--handle-test-operation "foo")))) (let ((default-directory temporary-file-directory)) (should-not (string-equal (tramp--test-operation) - (tramp--handler-for-test-operation))) + (tramp--handle-test-operation))) (should-not (string-equal (tramp--test-operation "foo") - (tramp--handler-for-test-operation "foo")))) + (tramp--handle-test-operation "foo")))) - (tramp-remove-external-operation - #'tramp--test-operation backend) + (tramp-remove-external-operation #'tramp--test-operation backend) ;; There is no backend specific code. (should-not (string-equal (tramp--test-operation ert-remote-temporary-file-directory) - (tramp--handler-for-test-operation + (tramp--handle-test-operation ert-remote-temporary-file-directory))) (should-not (string-equal (tramp--test-operation temporary-file-directory) - (tramp--handler-for-test-operation + (tramp--handle-test-operation temporary-file-directory))) (let ((default-directory ert-remote-temporary-file-directory)) (should-not (string-equal (tramp--test-operation) - (tramp--handler-for-test-operation))) + (tramp--handle-test-operation))) + (should-not + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + (let ((default-directory temporary-file-directory)) + (should-not + (string-equal (tramp--test-operation) + (tramp--handle-test-operation))) + (should-not + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + + ;; Test `default-directory' arg type. + (tramp-add-external-operation + #'tramp--test-operation #'tramp--handle-test-operation + backend 'default-directory) + + ;; The backend specific function is called. + (let ((default-directory ert-remote-temporary-file-directory)) + (should + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + (let ((default-directory temporary-file-directory)) + (should-not + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + + (tramp-remove-external-operation #'tramp--test-operation backend) + ;; There is no backend specific code. + (let ((default-directory ert-remote-temporary-file-directory)) + (should-not + (string-equal (tramp--test-operation) + (tramp--handle-test-operation))) + (should-not + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + (let ((default-directory temporary-file-directory)) + (should-not + (string-equal (tramp--test-operation) + (tramp--handle-test-operation))) + (should-not + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + + ;; Test `process' arg type. + (when (and (tramp--test-supports-processes-p) (not (tramp--test-smb-p))) + (let ((default-directory ert-remote-temporary-file-directory) + proc command id) + (unwind-protect + (with-temp-buffer + (setq command '("cat") + proc + (make-process + :name "test" :buffer (current-buffer) :command command + :file-handler t)) + (should (processp proc)) + (should (eq (process-status proc) 'run)) + (should (natnump (setq id (process-id proc)))) + (tramp-add-external-operation + #'process-id #'tramp--handle-process-id backend 'process) + (should (= (process-id proc) (1+ id)))) + + ;; Cleanup. + (tramp-remove-external-operation #'process-id backend) + (ignore-errors (delete-process proc))))) + + ;; Test function arg type. + (tramp-add-external-operation + #'tramp--test-operation #'tramp--handle-test-operation + backend #'tramp--test-operation-file-name-for-operation) + + ;; The backend specific function is called. + (let ((default-directory ert-remote-temporary-file-directory)) + (should + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + (let ((default-directory temporary-file-directory)) + (should-not + (string-equal (tramp--test-operation "foo") + (tramp--handle-test-operation "foo")))) + + (tramp-remove-external-operation #'tramp--test-operation backend) + ;; There is no backend specific code. + (let ((default-directory ert-remote-temporary-file-directory)) + (should-not + (string-equal (tramp--test-operation) + (tramp--handle-test-operation))) (should-not (string-equal (tramp--test-operation "foo") - (tramp--handler-for-test-operation "foo")))) + (tramp--handle-test-operation "foo")))) (let ((default-directory temporary-file-directory)) (should-not (string-equal (tramp--test-operation) - (tramp--handler-for-test-operation))) + (tramp--handle-test-operation))) (should-not (string-equal (tramp--test-operation "foo") - (tramp--handler-for-test-operation "foo")))))) + (tramp--handle-test-operation "foo")))))) ;; This test is inspired by Bug#29163. (ert-deftest tramp-test50-auto-load () diff --git a/texi/tramp.texi b/texi/tramp.texi index 3af4dfb..79271d2 100644 --- a/texi/tramp.texi +++ b/texi/tramp.texi @@ -2042,6 +2042,12 @@ Access of a hadoop/hdfs file system. A file is accessed via the user that you want to use, and @samp{node} is the name of the hadoop server. +@c @cindex method @option{rpc} +@c @cindex @option{rpc} method +@c @item tramp-rpc +@c This is a @value{tramp} backend of its own. It uses a remote server +@c process to serve the requests, which gains better performance. + @cindex method @option{vagrant} @cindex @option{vagrant} method @item vagrant-tramp @@ -5556,6 +5562,8 @@ operations. For example, the GNU ELPA package @file{tramp-hlo} implements specialized versions of @code{dir-locals--all-files}, @code{locate-dominating-file} and @code{dir-locals-find-file} for @value{tramp}'s @code{tramp-sh} backend (@pxref{New operations}). +@c The NonGNU ELPA package @file{tramp-rpc} implements an own +@c @value{tramp} backend (@pxref{New operations}). @end itemize @@ -6728,6 +6736,45 @@ See the docstring of variable @code{tramp-methods} for possible @code{foo-tramp-executable} in this example would be a Lisp constant, which is the program name of @command{foo}. +If a parameter doesn't have a static value but must be computed at +runtime, a format specifier can be used, like @t{"%h"} in the example +above. See the docstring of @code{tramp-methods}, which patterns are +expanded in which parameter. Furthermore, other format specifiers can +be added via the variable @code{tramp-extra-expand-args}. + +The following parameters expand format specifiers for the +@code{tramp-sh} backend: @code{tramp-copy-args}, +@code{tramp-copy-env}, @code{tramp-copy-file-name}, +@code{tramp-login-args}, @code{tramp-login-program}, +@code{tramp-remote-copy-args}. + +The example above could use + +@lisp +(tramp-login-program "%b") +@end lisp + +And you could set @code{tramp-extra-expand-args} as connection-local value: + +@lisp +@group +(defun foo-tramp-get-login-program (vec) + "Return connection-local value of `tramp-login-program'." + @dots{}) +@end group + +@group +(connection-local-set-profile-variables + 'foo-tramp-connection-local-default-profile + '((tramp-extra-expand-args + ?b (foo-tramp-get-login-program (car tramp-current-connection))))) + +(connection-local-set-profiles + '(:application tramp :protocol "foo") + foo-tramp-connection-local-default-profile) +@end group +@end lisp + Another initialization could tell @value{tramp} which are the default user and host name for method @option{foo}. This is done by calling @code{tramp-set-completion-function}: @@ -6828,15 +6875,12 @@ For example, it could implement this by using an own shell script which collects the information on the remote host for this very special purpose with one round-trip per-call. -@defun tramp-add-external-operation operation function backend +@defun tramp-add-external-operation operation function backend &optional arg-type This adds an implementation of @var{operation} to @value{tramp}'s backend @var{backend}. @var{function} is the new implementation. Both @var{operation} and @var{function} shall be function symbols. -They must have the same argument list. The first argument is used to -determine, whether @value{tramp} is invoked (check for remote file -name syntax). It must be a string or nil, in the latter case -@code{default-directory} is used for the check. +They must have the same argument list. @var{backend}, also a symbol, is the feature name of a @value{tramp} backend (except @code{tramp-ftp}). The new implementation will be @@ -6844,18 +6888,18 @@ applied only for this backend. Example: @lisp @group -(defun test-operation (file) +(defun my-test-operation (file) (message "Original implementation for %s" file)) @end group @group -(defun handle-test-operation (file) +(defun my-handle-test-operation (file) (message "Handler implementation for %s" file)) @end group @group (tramp-add-external-operation - #'test-operation #'handle-test-operation 'tramp-sh) + #'my-test-operation #'my-handle-test-operation 'tramp-sh) @end group @end lisp @@ -6864,23 +6908,24 @@ Then we have the different use cases: @lisp @group ;; Local file name. -(test-operation "/a/b") +(my-test-operation "/a/b") @result{} "Original implementation for /a/b" @end group @group ;; Remote file name, handled by `tramp-sh'. -(test-operation "/ssh::/a/b") +(my-test-operation "/ssh::/a/b") @result{} "Handler implementation for /ssh::/a/b" @end group @group ;; Remote file name, handled by `tramp-gvfs'. -(test-operation "/sftp::/a/b") +(my-test-operation "/sftp::/a/b") @result{} "Original implementation for /sftp::/a/b" @end group @end lisp +@findex with-parsed-tramp-file-name @var{function} is implemented like an ordinary @value{tramp} backend handler, see the examples in @code{tramp-<backend>-handle-*} and @code{tramp-handle-*}. It can expect, that the first argument (or @@ -6888,9 +6933,71 @@ handler, see the examples in @code{tramp-<backend>-handle-*} and syntax. It shall use @value{tramp} internal macros and functions like @code{with-parsed-tramp-file-name} and the different cache functions. +@findex tramp-run-real-handler +If @var{function} must call the original function, this can be done +via @code{tramp-run-real-handler}. The implementation of the example +could look like: + +@lisp +@group +(defun my-handle-test-operation (file) + (message "Entry handler implementation for %s" file) + (tramp-run-real-handler #'my-test-operation (list file)) + (message "Exit handler implementation for %s" file)) +@end group + +@group +(my-test-operation "/ssh::/a/b") +@result{} "Entry handler implementation for /ssh::/a/b + Original implementation for /ssh::/a/b + Exit handler implementation for /ssh::/a/b" +@end group +@end lisp + If the same @var{function} shall be used for different @value{tramp} backends, @code{tramp-add-external-operation} must be called for every backend, respectively. + +The optional argument @var{arg-type} specisfies, which argument of +@var{operation} shall be used in order to determine, whether the +handler @var{function} should be called. It can be + +@itemize @minus +@item @code{file}@* +The first argument of @var{operation} is the remote file name to be +checked. This is the default, if @var{arg-type} is @code{nil}. + +@item @code{default-directory}@* +@code{default-directory} is the remote file name to be checked. + +@item @code{process}@* +@code{default-directory} of the process buffer of the first argument +of @var{operation}, a process, is the remote file name to be checked. +@end itemize + +If the first argument of @var{operation} is nil, +@code{default-directory} is the remote file name to be checked in case +of @var{arg-type} being @code{file} or @code{process}. + +@findex tramp-file-name-for-operation +If @var{arg-type} is a function symbol, it will be called with the +same arguments as @code{tramp-file-name-for-operation}. It must +return a string, which is the remote file name to be checked. + +The example above could be changed like this: + +@lisp +@group +(defun my-file-name-for-test-operation (operation &rest args) + (if (stringp (car args)) (car args) default-directory)) +@end group + +@group +(tramp-add-external-operation + #'my-test-operation #'my-handle-test-operation 'tramp-sh + #'my-file-name-for-test-operation) +@end group +@end lisp @end defun @defun tramp-remove-external-operation operation backend @@ -6902,7 +7009,7 @@ they are kept. Example: @lisp @group (tramp-remove-external-operation - #'test-operation 'tramp-sh) + #'my-test-operation 'tramp-sh) @end group @end lisp @end defun @@ -6918,6 +7025,10 @@ An example implementing this mechanism is the GNU ELPA package @code{dir-locals-find-file} for @value{tramp}'s @code{tramp-sh} backend. +@c Another example is the NonGNU ELPA package @file{tramp-rpc}. It +@c provides an own @value{tramp} backend, using a server process on the +@c remote host. + @node Traces and Profiles @chapter How to Customize Traces diff --git a/texi/trampver.texi b/texi/trampver.texi index cf9aef6..cf3fd7a 100644 --- a/texi/trampver.texi +++ b/texi/trampver.texi @@ -7,7 +7,7 @@ @c In the Tramp GIT, the version number and the bug report address @c are auto-frobbed from configure.ac. -@set trampver 2.8.1.3 +@set trampver 2.8.1.4 @set trampurl https://www.gnu.org/software/tramp/ @set tramp-bug-report-address tramp-devel@@gnu.org @set emacsver 28.1 diff --git a/tramp-cache.el b/tramp-cache.el index 1fc3fb3..b47a2aa 100644 --- a/tramp-cache.el +++ b/tramp-cache.el @@ -161,6 +161,20 @@ If KEY is `tramp-cache-undefined', don't create anything, and return nil." ;; would fail. (function-put #'tramp-get-hash-table 'tramp-suppress-trace t) +(defsubst tramp-suppress-remote-file-name-inhibit-cache () + "Weaken `remote-file-name-inhibit-cache'. +This is meant to be let-bound for code over many cache operations, like +in large directories." + ;; If `remote-file-name-inhibit-cache' is already `nil', keep it. + (cond + (;; A timestamp. Keep it. + (consp remote-file-name-inhibit-cache) remote-file-name-inhibit-cache) + (;; A number of seconds. Set a timestamp with the difference. + (numberp remote-file-name-inhibit-cache) + (time-subtract nil remote-file-name-inhibit-cache)) + (;; Cache is disabled. Set a timestamp from now on. + t (current-time)))) + ;;;###tramp-autoload (defun tramp-get-file-property (key file property &optional default) "Get the PROPERTY of FILE from the cache context of KEY. diff --git a/tramp-container.el b/tramp-container.el index 91d9b23..fec2e16 100644 --- a/tramp-container.el +++ b/tramp-container.el @@ -266,7 +266,7 @@ BODY is the backend specific code." tramp--last-hop-directory) tramp-compat-temporary-file-directory)) (program (let ((tramp-verbose 0)) - (tramp-get-method-parameter + (tramp-expand-args (make-tramp-file-name :method ,method) 'tramp-login-program))) (vec (when (tramp-tramp-file-p default-directory) @@ -656,10 +656,9 @@ see its function help for a description of the format." '((tramp-config-check . tramp-kubernetes--current-context-data) ;; This variable will be eval'ed in `tramp-expand-args'. (tramp-extra-expand-args - . (?a (tramp-kubernetes--container (car tramp-current-connection)) - ?h (tramp-kubernetes--pod (car tramp-current-connection)) - ?x (tramp-kubernetes--context-namespace - (car tramp-current-connection))))) + ?a (tramp-kubernetes--container (car tramp-current-connection)) + ?h (tramp-kubernetes--pod (car tramp-current-connection)) + ?x (tramp-kubernetes--context-namespace (car tramp-current-connection)))) "Default connection-local variables for remote kubernetes connections.") (connection-local-set-profile-variables diff --git a/tramp-sh.el b/tramp-sh.el index 08a44c8..8cade9c 100644 --- a/tramp-sh.el +++ b/tramp-sh.el @@ -4688,19 +4688,22 @@ process to set up. VEC specifies the connection." (tramp-send-command vec (format "unset %s" (string-join unset " ")) t))) + ;; FIXME: This doesn't work with `tramp-test42-utf8' and "/ssh::tmp". ;; Set connection-local variable `command-line-max-length'. ;; `command-line-max-length' exists since Emacs 31. ;; `connection-local-profile-name-for-criteria' exists since Emacs 29.1. ;; We simulate it with `make-symbol'. - (when (boundp 'command-line-max-length) - (let* ((criteria (tramp-get-connection-local-criteria vec)) - (profile (if (fboundp 'connection-local-profile-name-for-criteria) - (connection-local-profile-name-for-criteria criteria) - (make-symbol "generated-profile-name")))) - (connection-local-set-profile-variables - profile - `((command-line-max-length . ,(tramp-get-remote-pipe-buf vec)))) - (connection-local-set-profiles criteria profile))))) + ;; (when (boundp 'command-line-max-length) + ;; (let* ((arg-max (tramp-get-remote-arg-max vec)) + ;; (criteria (tramp-get-connection-local-criteria vec)) + ;; (profile (if (fboundp 'connection-local-profile-name-for-criteria) + ;; (connection-local-profile-name-for-criteria criteria) + ;; (make-symbol "generated-profile-name")))) + ;; (connection-local-set-profile-variables + ;; profile + ;; `((command-line-max-length . ,(if arg-max (floor arg-max 4) 4094)))) + ;; (connection-local-set-profiles criteria profile))))) + )) ;; Old text from documentation of tramp-methods: ;; Using a uuencode/uudecode inline method is discouraged, please use one @@ -5036,8 +5039,7 @@ Goes through the list `tramp-inline-compress-commands'." ;; Use plink options. ((string-match-p - (rx "plink" (? ".exe") eol) - (tramp-get-method-parameter vec 'tramp-login-program)) + (rx "plink" (? ".exe") eol) (tramp-expand-args vec 'tramp-login-program)) (concat (if (eq tramp-use-connection-share 'suppress) "-noshare" "-share") @@ -5397,9 +5399,7 @@ connection if a previous connection has died for some reason." (tramp-get-method-parameter hop 'tramp-connection-timeout tramp-connection-timeout)) - (command - (tramp-get-method-parameter - hop 'tramp-login-program)) + (command (tramp-expand-args hop 'tramp-login-program)) ;; We don't create the temporary file. In ;; fact, it is just a prefix for the ;; ControlPath option of ssh; the real @@ -5805,12 +5805,24 @@ Nonexistent directories are removed from spec." remote-path :test #'string-equal :from-end t)) ;; Remove non-existing directories. - (let (remote-file-name-inhibit-cache) + (let ((remote-file-name-inhibit-cache + (tramp-suppress-remote-file-name-inhibit-cache))) (tramp-bundle-read-file-names vec remote-path) (cl-remove-if (lambda (x) (not (tramp-get-file-property vec x "file-directory-p"))) remote-path)))))) +(defun tramp-get-remote-arg-max (vec) + "Return ARG_MAX config from the remote side." + (with-tramp-connection-property vec "arg-max" + (when-let* ((result + (tramp-send-command-and-read + vec (format "getconf ARG_MAX 2>%s" + (tramp-get-remote-null-device vec)) + 'noerror)) + ((natnump result))) + result))) + ;; The PIPE_BUF in POSIX [1] can be as low as 512 [2]. Here are the values ;; on various platforms: ;; - 512 on macOS, FreeBSD, NetBSD, OpenBSD, MirBSD, native Windows. diff --git a/tramp-sshfs.el b/tramp-sshfs.el index 2cb5b5b..f407315 100644 --- a/tramp-sshfs.el +++ b/tramp-sshfs.el @@ -269,7 +269,7 @@ arguments to pass to the OPERATION." (setq ret (apply #'tramp-call-process - v (tramp-get-method-parameter v 'tramp-login-program) + v (tramp-expand-args v 'tramp-login-program) nil outbuf display (tramp-expand-args v 'tramp-login-args nil @@ -7,7 +7,7 @@ ;; Maintainer: Michael Albinus <michael.albinus@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.8.1.3 +;; Version: 2.8.1.4 ;; Package-Requires: ((emacs "28.1")) ;; Package-Type: multi ;; URL: https://www.gnu.org/software/tramp/ @@ -2424,7 +2424,22 @@ arguments to pass to the OPERATION." (apply operation args))) (defvar tramp-file-name-for-operation-external nil - "List of operations added by external packages.") + "Alist of operations added by external packages. +An entry has the form `(OPERATION . ARG-TYPE)'. ARG-TYPE can be the +symbol + +- `file': the first argument of OERATION is the remote file name to be + checked. +- `default-directory': `default-directory' is the remote file name to be + checked. +- `process': `default-directory' of the process buffer of the first + argument of OPERATION is the remote file name to be checked. + +If the first argument of OPERATION is nil, `default-directory' is the +remote file name to be checked in case of `file' and `process'. + +If ARG-TYPE is a function symbol, it will be called with the same +arguments as `tramp-file-name-for-operation'. It must return a string.") ;; We handle here all file primitives. Most of them have the file ;; name as first parameter; nevertheless we check for them explicitly @@ -2434,9 +2449,7 @@ arguments to pass to the OPERATION." ;; ease the life if `file-name-handler-alist' would support a decision ;; function as well but regexp only. ;; Operations added by external packages are kept in -;; `tramp-file-name-for-operation-external'. They expect the file -;; name to be checked as first argument or, if there isn't any -;; argument, `default-directory'. +;; `tramp-file-name-for-operation-external'. (defun tramp-file-name-for-operation (operation &rest args) "Return file name related to OPERATION file primitive. ARGS are the arguments OPERATION has been called with. @@ -2446,30 +2459,32 @@ first argument of `expand-file-name' is absolute and not remote. Must be handled by the callers." (cond ;; FILE resp DIRECTORY. - ((memq operation - '(access-file byte-compiler-base-file-name delete-directory - delete-file diff-latest-backup-file directory-file-name - directory-files directory-files-and-attributes dired-compress-file - dired-uncache file-acl file-accessible-directory-p file-attributes - file-directory-p file-executable-p file-exists-p file-local-copy - file-locked-p file-modes file-name-as-directory - file-name-case-insensitive-p file-name-directory - file-name-nondirectory file-name-sans-versions - file-notify-add-watch file-ownership-preserved-p file-readable-p - file-regular-p file-remote-p file-selinux-context file-symlink-p - file-system-info file-truename file-writable-p - find-backup-file-name get-file-buffer - insert-directory insert-file-contents load lock-file make-directory - make-lock-file-name set-file-acl set-file-modes - set-file-selinux-context set-file-times substitute-in-file-name - unhandled-file-name-directory unlock-file vc-registered - ;; Emacs 28- only. - make-directory-internal - ;; Emacs 29+ only. - abbreviate-file-name - ;; Tramp internal magic file name function. - tramp-set-file-uid-gid)) - (if (file-name-absolute-p (nth 0 args)) + ((or + (memq operation + '(access-file byte-compiler-base-file-name delete-directory + delete-file diff-latest-backup-file directory-file-name + directory-files directory-files-and-attributes dired-compress-file + dired-uncache file-acl file-accessible-directory-p file-attributes + file-directory-p file-executable-p file-exists-p file-local-copy + file-locked-p file-modes file-name-as-directory + file-name-case-insensitive-p file-name-directory + file-name-nondirectory file-name-sans-versions + file-notify-add-watch file-ownership-preserved-p file-readable-p + file-regular-p file-remote-p file-selinux-context file-symlink-p + file-system-info file-truename file-writable-p + find-backup-file-name get-file-buffer + insert-directory insert-file-contents load lock-file make-directory + make-lock-file-name set-file-acl set-file-modes + set-file-selinux-context set-file-times substitute-in-file-name + unhandled-file-name-directory unlock-file vc-registered + ;; Emacs 28- only. + make-directory-internal + ;; Emacs 29+ only. + abbreviate-file-name + ;; Tramp internal magic file name function. + tramp-set-file-uid-gid)) + (eq (alist-get operation tramp-file-name-for-operation-external) 'file)) + (if (and (stringp (nth 0 args)) (file-name-absolute-p (nth 0 args))) (nth 0 args) default-directory)) ;; STRING FILE. @@ -2502,31 +2517,45 @@ Must be handled by the callers." (buffer-file-name (if (bufferp (nth 0 args)) (nth 0 args) (current-buffer)))) ;; COMMAND. - ((memq operation - '(exec-path make-nearby-temp-file make-process process-file - shell-command start-file-process temporary-file-directory - ;; Emacs 29+ only. - list-system-processes memory-info process-attributes - ;; Emacs 30+ only. - file-group-gid file-user-uid)) + ((or + (memq operation + '(exec-path make-nearby-temp-file make-process process-file + shell-command start-file-process temporary-file-directory + ;; Emacs 29+ only. + list-system-processes memory-info process-attributes + ;; Emacs 30+ only. + file-group-gid file-user-uid)) + (eq (alist-get operation tramp-file-name-for-operation-external) + 'default-directory)) default-directory) - ;; PROC. - ((memq operation '(file-notify-rm-watch file-notify-valid-p)) - (when (processp (nth 0 args)) - (tramp-get-default-directory (process-buffer (nth 0 args))))) + ;; PROC or BUFFER. + ((or + (memq operation '(file-notify-rm-watch file-notify-valid-p)) + (eq (alist-get operation tramp-file-name-for-operation-external) 'process)) + (or (when-let* (((processp (nth 0 args))) + (vec (process-get (nth 0 args) 'tramp-vector))) + (tramp-make-tramp-file-name vec)) + (when-let* + ((buf (cond + ((processp (nth 0 args)) (process-buffer (nth 0 args))) + ((bufferp (nth 0 args)) (get-buffer (nth 0 args))) + ((stringp (nth 0 args)) + ;; Process or buffer name. + (or (get-process (nth 0 args)) (get-buffer (nth 0 args))))))) + (tramp-get-default-directory buf)) + "")) ;; VEC. ((memq operation '(tramp-get-home-directory tramp-get-remote-gid tramp-get-remote-groups tramp-get-remote-uid)) (tramp-make-tramp-file-name (nth 0 args))) - ;; FILE resp DIRECTORY. - ((and (memq operation tramp-file-name-for-operation-external) - (or (stringp (nth 0 args)) (null (nth 0 args)))) - (if (and (stringp (nth 0 args)) (file-name-absolute-p (nth 0 args))) - (nth 0 args) - default-directory)) + ;; A function. + ((functionp (alist-get operation tramp-file-name-for-operation-external)) + (apply + (alist-get operation tramp-file-name-for-operation-external) + operation args)) ;; Unknown file primitive. - (t (unless (member 'remote-file-error debug-ignored-errors) + (t (unless (memq 'remote-file-error debug-ignored-errors) (tramp-error nil 'remote-file-error "Unknown file I/O primitive: %s" operation))))) @@ -2544,7 +2573,7 @@ Must be handled by the callers." (funcall (setq func (car elt)) vec) (error (setcar elt #'ignore) - (unless (member 'remote-file-error debug-ignored-errors) + (unless (memq 'remote-file-error debug-ignored-errors) (tramp-error vec 'remote-file-error "Not a valid Tramp file name function `%s'" func)))) @@ -2552,22 +2581,32 @@ Must be handled by the callers." res (cdr elt)))) res))) -(defun tramp-add-external-operation (operation function backend) +(defun tramp-add-external-operation + (operation function backend &optional arg-type) "Add FUNCTION to Tramp BACKEND as handler for OPERATION. OPERATION must not be one of the magic operations listed in Info node `(elisp) Magic File Names'. FUNCTION must have the same argument list as OPERATION. BACKEND, a symbol, must be one of the Tramp backend -packages like `tramp-sh' (except `tramp-ftp')." +packages like `tramp-sh' (except `tramp-ftp'). ARG-TYPE is either +`file' (the default), `default-directory', `process' or a function +symbol. It describes the type of the OPERATION argument to be checked. +See the docstring of `tramp-file-name-for-operation-external' for its +meaning." (require backend) (when-let* ((fnha (intern-soft (concat (symbol-name backend) "-file-name-handler-alist"))) - ((boundp fnha))) + ((boundp fnha)) + (arg-type (or arg-type 'file))) + (unless (or (memq arg-type '(file default-directory process)) + (functionp arg-type)) + (tramp-error nil 'remote-file-error "Unknown arg type: %s" arg-type)) ;; Make BACKEND aware of the new operation. (add-to-list fnha (cons operation function)) - (unless (memq operation tramp-file-name-for-operation-external) + (unless (assq operation tramp-file-name-for-operation-external) ;; Make Tramp aware of the new operation. - (add-to-list 'tramp-file-name-for-operation-external operation) + (add-to-list + 'tramp-file-name-for-operation-external (cons operation arg-type)) (put #'tramp-file-name-handler 'operations (cons operation (get 'tramp-file-name-handler 'operations))) @@ -2577,8 +2616,7 @@ packages like `tramp-sh' (except `tramp-ftp')." `(lambda (orig-fun &rest args) (if-let* ((handler (find-file-name-handler - (if (and (car args) (file-name-absolute-p (car args))) - (car args) default-directory) + (apply #'tramp-file-name-for-operation #',operation args) #',operation))) (apply handler #',operation args) (apply orig-fun args))) @@ -2605,7 +2643,7 @@ Tramp backend packages like `tramp-sh'." tramp-foreign-file-name-handler-alist) ;; Make Tramp unaware of OPERATION. (setq tramp-file-name-for-operation-external - (delq operation tramp-file-name-for-operation-external)) + (assq-delete-all operation tramp-file-name-for-operation-external)) (put #'tramp-file-name-handler 'operations (delq operation (get 'tramp-file-name-handler 'operations))) ;; Remove the advice for OPERATION. @@ -3016,6 +3054,8 @@ BODY is the backend specific code." (when (file-directory-p ,directory) (seq-uniq (delq nil (let* ((case-fold-search read-file-name-completion-ignore-case) + (remote-file-name-inhibit-cache + (tramp-suppress-remote-file-name-inhibit-cache)) (result (if (tramp-tramp-file-p ,directory) (with-parsed-tramp-file-name @@ -3027,16 +3067,14 @@ BODY is the backend specific code." (format "file-name-all-completions-%s" tramp-fnac-add-trailing-slash) - ;; Mark symlinked directories. Other - ;; directories are already marked. + ;; Mark directories, including symlinks to + ;; directories. (mapcar (lambda (x) (let ((f (file-name-concat ,directory x))) (if (and tramp-fnac-add-trailing-slash (not (string-suffix-p "/" x)) - (file-directory-p - (if (file-symlink-p f) - (file-truename f) f))) + (file-directory-p f)) (concat x "/") x))) ;; Some storage systems do not return "." and "..". (seq-union @@ -5189,11 +5227,17 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.") (delete-file local-copy))))) t))) +(defvar tramp-multi-hop-p-hook nil + "Abnormal hook for `tramp-multi-hop-p'. +This can be used by external Tramp backends to inform, that they are +multi-hop capable.") + (defun tramp-multi-hop-p (vec) "Whether the method of VEC is capable of multi-hops." (let ((tramp-verbose 0)) - (and (tramp-sh-file-name-handler-p vec) - (tramp-get-method-parameter vec 'tramp-login-args)))) + (or (and (tramp-sh-file-name-handler-p vec) + (tramp-get-method-parameter vec 'tramp-login-args)) + (run-hook-with-args-until-success 'tramp-multi-hop-p-hook vec)))) (defun tramp-add-hops (vec) "Add ad-hoc proxy definitions to `tramp-default-proxies-alist'." @@ -5325,7 +5369,7 @@ Do not set it manually, it is used buffer-local in `tramp-get-lock-pid'.") (defvar tramp-extra-expand-args nil "Method specific arguments.") -(defun tramp-expand-args (vec parameter default &rest spec-list) +(defun tramp-expand-args (vec parameter &optional default &rest spec-list) "Expand login arguments as given by PARAMETER in `tramp-methods'. PARAMETER is a symbol like `tramp-login-args', denoting a list of list of strings from `tramp-methods', containing %-sequences for @@ -5348,12 +5392,15 @@ a connection-local variable." (setq spec-list (cddr spec-list))) (setq spec (apply #'format-spec-make extra-spec-list)) ;; Expand format spec. - (flatten-tree - (mapcar - (lambda (x) - (setq x (mapcar (lambda (y) (tramp-format-spec y spec)) x)) - (unless (member "" x) x)) - args)))) + (cond + ((consp args) + (flatten-tree + (mapcar + (lambda (x) + (setq x (mapcar (lambda (y) (tramp-format-spec y spec)) x)) + (unless (member "" x) x)) + args))) + (args (tramp-format-spec args spec))))) (defun tramp-post-process-creation (proc vec) "Apply actions after creation of process PROC." @@ -5458,6 +5505,10 @@ processes." (setenv-internal env "HISTFILESIZE" "0" 'keep)) (t env)) env)) + ;; Add TERM. + (env (if sh-file-name-handler-p + (setenv-internal env "TERM" tramp-terminal-type 'keep) + env)) ;; Add INSIDE_EMACS. (env (setenv-internal env "INSIDE_EMACS" (tramp-inside-emacs) 'keep)) (env (mapcar #'tramp-shell-quote-argument (delq nil env))) @@ -5475,8 +5526,7 @@ processes." (tramp-get-method-parameter v 'tramp-direct-async) `(,(string-join command " "))) command)) - (login-program - (tramp-get-method-parameter v 'tramp-login-program)) + (login-program (tramp-expand-args v 'tramp-login-program)) ;; We don't create the temporary file. In fact, it is just ;; a prefix for the ControlPath option of ssh; the real ;; temporary file has another name, and it is created and @@ -6333,7 +6383,7 @@ Mostly useful to protect BODY from being interrupted by timers." (declare (indent 1) (debug t)) `(if (tramp-get-connection-property ,proc "locked") ;; Be kind for old versions of Emacs. - (if (member 'remote-file-error debug-ignored-errors) + (if (memq 'remote-file-error debug-ignored-errors) (throw 'non-essential 'non-essential) ;(tramp-backtrace ,proc 'force) (tramp-error @@ -6699,7 +6749,7 @@ If FILENAME is remote, a file name handler is called." ID-FORMAT valid values are `string' and `integer'." ;; We use key nil for local connection properties. (with-tramp-connection-property nil (format "uid-%s" id-format) - (if (equal id-format 'integer) (user-uid) (user-login-name)))) + (if (eq id-format 'integer) (user-uid) (user-login-name)))) (defun tramp-get-local-gid (id-format) "The gid of the local user, in ID-FORMAT. @@ -6707,8 +6757,8 @@ ID-FORMAT valid values are `string' and `integer'." ;; We use key nil for local connection properties. (with-tramp-connection-property nil (format "gid-%s" id-format) (cond - ((equal id-format 'integer) (group-gid)) - ((equal id-format 'string) (group-name (group-gid))) + ((eq id-format 'integer) (group-gid)) + ((eq id-format 'string) (group-name (group-gid))) ((file-attribute-group-id (file-attributes "~/" id-format)))))) (defun tramp-get-local-locale (&optional vec) @@ -6904,8 +6954,8 @@ ID-FORMAT valid values are `string' and `integer'." (with-tramp-connection-property vec (format "uid-%s" id-format) (tramp-file-name-handler #'tramp-get-remote-uid vec id-format))) ;; Ensure there is a valid result. - (and (equal id-format 'integer) tramp-unknown-id-integer) - (and (equal id-format 'string) tramp-unknown-id-string))) + (and (eq id-format 'integer) tramp-unknown-id-integer) + (and (eq id-format 'string) tramp-unknown-id-string))) (defun tramp-get-remote-gid (vec id-format) "The gid of the remote connection VEC, in ID-FORMAT. @@ -6914,8 +6964,8 @@ ID-FORMAT valid values are `string' and `integer'." (with-tramp-connection-property vec (format "gid-%s" id-format) (tramp-file-name-handler #'tramp-get-remote-gid vec id-format))) ;; Ensure there is a valid result. - (and (equal id-format 'integer) tramp-unknown-id-integer) - (and (equal id-format 'string) tramp-unknown-id-string))) + (and (eq id-format 'integer) tramp-unknown-id-integer) + (and (eq id-format 'string) tramp-unknown-id-string))) (defun tramp-get-remote-groups (vec id-format) "The list of groups of the remote connection VEC, in ID-FORMAT. @@ -7229,9 +7279,9 @@ verbosity of 6." (let ((default-directory temporary-file-directory)) (dolist (pid (list-system-processes)) (and-let* ((attributes (process-attributes pid)) - (comm (cdr (assoc 'comm attributes))) + (comm (cdr (assq 'comm attributes))) ((string-equal - (cdr (assoc 'user attributes)) (user-login-name))) + (cdr (assq 'user attributes)) (user-login-name))) ;; The returned command name could be truncated ;; to 15 characters. Therefore, we cannot check ;; for `string-equal'. diff --git a/trampver.el b/trampver.el index bf84e89..d1c2533 100644 --- a/trampver.el +++ b/trampver.el @@ -7,7 +7,7 @@ ;; Maintainer: Michael Albinus <michael.albinus@gmx.de> ;; Keywords: comm, processes ;; Package: tramp -;; Version: 2.8.1.3 +;; Version: 2.8.1.4 ;; Package-Requires: ((emacs "28.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.8.1.3" +(defconst tramp-version "2.8.1.4" "This version of Tramp.") ;;;###tramp-autoload @@ -76,7 +76,7 @@ ;; Check for Emacs version. (let ((x (if (not (string-version-lessp emacs-version "28.1")) "ok" - (format "Tramp 2.8.1.3 is not fit for %s" + (format "Tramp 2.8.1.4 is not fit for %s" (replace-regexp-in-string "\n" "" (emacs-version)))))) (unless (string-equal "ok" x) (error "%s" x))) |
