* lisp/net/tramp.el (tramp-make-tramp-file-name): Adapt argument list.
Add hops to `tramp-default-proxies-alist'.
(tramp-find-foreign-file-name-handler): Adapt argument list.
(tramp-handle-abbreviate-file-name): Abbreviate multi-hops.
(tramp-handle-file-remote-p): Adapt handling of hops.
(tramp-add-hops): New defun.
(tramp-compute-multi-hops): Use it.
* lisp/net/tramp.el (tramp-make-tramp-hop-name, tramp-get-buffer)
(tramp-file-name-handler, tramp-handle-file-truename)
(tramp-handle-insert-file-contents, tramp-local-host-p)
(tramp-read-passwd, tramp-clear-passwd):
* lisp/net/tramp-archive.el (tramp-archive-dissect-file-name)
(tramp-archive-gvfs-file-name):
* lisp/net/tramp-cache.el (tramp-get-hash-table):
* lisp/net/tramp-sh.el (tramp-sh-handle-file-truename)
(tramp-sh-handle-make-process, tramp-sh-handle-process-file)
(tramp-sh-file-name-handler-p, tramp-get-remote-path):
* lisp/net/tramp-sshfs.el (tramp-sshfs-handle-process-file):
* lisp/net/tramp-sudoedit.el (tramp-sudoedit-handle-file-truename):
Adapt callees.
* test/lisp/net/tramp-tests.el (tramp-test02-file-name-dissect)
(tramp-test02-file-name-dissect-simplified)
(tramp-test02-file-name-dissect-separate)
(tramp-test07-abbreviate-file-name): Adapt tests.
(defun tramp-adb-get-signal-strings (vec)
"Strings to return by `process-file' in case of signals."
(with-tramp-connection-property vec "signal-strings"
- (let ((default-directory (tramp-make-tramp-file-name vec 'localname))
+ (let ((default-directory (tramp-make-tramp-file-name vec 'noloc))
;; `shell-file-name' and `shell-command-switch' are needed
;; for Emacs < 27.1, which doesn't support connection-local
;; variables in `shell-command'.
((tramp-archive-file-name-p archive)
(let ((archive
(tramp-make-tramp-file-name
- (tramp-archive-dissect-file-name archive) nil 'noarchive)))
+ (tramp-archive-dissect-file-name archive))))
(setf (tramp-file-name-host vec) (tramp-archive-gvfs-host archive)))
(puthash archive (list vec) tramp-archive-hash))
(defun tramp-archive-gvfs-file-name (name)
"Return NAME in GVFS syntax."
- (tramp-make-tramp-file-name
- (tramp-archive-dissect-file-name name) nil 'nohop))
+ (tramp-make-tramp-file-name (tramp-archive-dissect-file-name name)))
\f
;; File name primitives.
(dolist (elt tramp-connection-properties)
(when (tramp-compat-string-search
(or (nth 0 elt) "")
- (tramp-make-tramp-file-name key 'noloc 'nohop))
+ (tramp-make-tramp-file-name key 'noloc))
(tramp-set-connection-property key (nth 1 elt) (nth 2 elt)))))
hash))))
(when (file-remote-p result)
(setq result (tramp-compat-file-name-quote result 'top)))
(tramp-message v 4 "True name of `%s' is `%s'" localname result)
- result))
- 'nohop)))))
+ result)))))))
;; Basic functions.
;; `shell'. We discard hops, if existing, that's why
;; we cannot use `file-remote-p'.
(prompt (format "PS1=%s %s"
- (tramp-make-tramp-file-name v nil 'nohop)
+ (tramp-make-tramp-file-name v)
tramp-initial-end-of-output))
;; We use as environment the difference to toplevel
;; `process-environment'.
vec
(concat
"signal-strings-" (tramp-get-method-parameter vec 'tramp-remote-shell))
- (let ((default-directory (tramp-make-tramp-file-name vec 'localname))
+ (let ((default-directory (tramp-make-tramp-file-name vec 'noloc))
process-file-return-signal-string signals res result)
(setq signals
(append
(setq input (tramp-file-local-name infile))
;; INFILE must be copied to remote host.
(setq input (tramp-make-tramp-temp-file v)
- tmpinput (tramp-make-tramp-file-name v input 'nohop))
+ tmpinput (tramp-make-tramp-file-name v input))
(copy-file infile tmpinput t)))
(when input (setq command (format "%s <%s" command input)))
;; stderr must be copied to remote host. The temporary
;; file must be deleted after execution.
(setq stderr (tramp-make-tramp-temp-file v)
- tmpstderr (tramp-make-tramp-file-name v stderr 'nohop))))
+ tmpstderr (tramp-make-tramp-file-name v stderr))))
;; stderr to be discarded.
((null (cadr destination))
(setq stderr (tramp-get-remote-null-device v)))))
(defun tramp-sh-file-name-handler-p (vec)
"Whether VEC uses a method from `tramp-sh-file-name-handler'."
(and (assoc (tramp-file-name-method vec) tramp-methods)
- (eq (tramp-find-foreign-file-name-handler
- (tramp-make-tramp-file-name vec nil 'nohop))
+ (eq (tramp-find-foreign-file-name-handler vec)
'tramp-sh-file-name-handler)))
;; This must be the last entry, because `identity' always matches.
(lambda (x)
(and
(stringp x)
- (file-directory-p (tramp-make-tramp-file-name vec x 'nohop))
+ (file-directory-p (tramp-make-tramp-file-name vec x))
x))
remote-path))))))
(setq input (tramp-file-local-name infile))
;; INFILE must be copied to remote host.
(setq input (tramp-make-tramp-temp-file v)
- tmpinput (tramp-make-tramp-file-name v input 'nohop))
+ tmpinput (tramp-make-tramp-file-name v input))
(copy-file infile tmpinput t)))
(when input (setq command (format "%s <%s" command input)))
(when (file-remote-p result)
(setq result (tramp-compat-file-name-quote result 'top)))
(tramp-message v 4 "True name of `%s' is `%s'" localname result)
- result))
- 'nohop)))))
+ result)))))))
(defun tramp-sudoedit-handle-file-writable-p (filename)
"Like `file-writable-p' for Tramp files."
"Construct a Tramp file name from ARGS.
ARGS could have two different signatures. The first one is of
-type (VEC &optional LOCALNAME HOP).
+type (VEC &optional LOCALNAME).
If LOCALNAME is nil, the value in VEC is used. If it is a
symbol, a null localname will be used. Otherwise, LOCALNAME is
expected to be a string, which will be used.
-If HOP is nil, the value in VEC is used. If it is a symbol, a
-null hop will be used. Otherwise, HOP is expected to be a
-string, which will be used.
The other signature exists for backward compatibility. It has
the form (METHOD USER DOMAIN HOST PORT LOCALNAME &optional HOP)."
hop (tramp-file-name-hop (car args)))
(when (cadr args)
(setq localname (and (stringp (cadr args)) (cadr args))))
- (when (cl-caddr args)
- (setq hop (and (stringp (cl-caddr args)) (cl-caddr args)))))
+ (when hop
+ (setq hop nil)
+ ;; Assure that the hops are in `tramp-default-proxies-alist'.
+ (tramp-add-hops (car args))))
(t (setq method (nth 0 args)
user (nth 1 args)
localname)))
(set-advertised-calling-convention
- #'tramp-make-tramp-file-name '(vec &optional localname hop) "27.1")
+ #'tramp-make-tramp-file-name '(vec &optional localname) "29.1")
(defun tramp-make-tramp-hop-name (vec)
"Construct a Tramp hop name from VEC."
- (replace-regexp-in-string
- tramp-prefix-regexp ""
+ (concat
+ (tramp-file-name-hop vec)
(replace-regexp-in-string
- (concat tramp-postfix-host-regexp "$") tramp-postfix-hop-format
- (tramp-make-tramp-file-name vec 'noloc))))
+ tramp-prefix-regexp ""
+ (replace-regexp-in-string
+ (concat tramp-postfix-host-regexp "$") tramp-postfix-hop-format
+ (tramp-make-tramp-file-name vec 'noloc)))))
(defun tramp-completion-make-tramp-file-name (method user host localname)
"Construct a Tramp file name from METHOD, USER, HOST and LOCALNAME.
(tramp-get-connection-property vec "process-buffer" nil))
(setq buffer-undo-list t
default-directory
- (tramp-make-tramp-file-name vec 'noloc 'nohop))
+ (tramp-make-tramp-file-name vec 'noloc))
(current-buffer)))))
(defun tramp-get-connection-buffer (vec &optional dont-create)
;; Unknown file primitive.
(t (error "Unknown file I/O primitive: %s" operation))))
-(defun tramp-find-foreign-file-name-handler (filename &optional _operation)
+(defun tramp-find-foreign-file-name-handler (vec &optional _operation)
"Return foreign file name handler if exists."
- (when (tramp-tramp-file-p filename)
+ (when (tramp-file-name-p vec)
(let ((handler tramp-foreign-file-name-handler-alist)
- (vec (tramp-dissect-file-name filename))
elt func res)
(while handler
(setq elt (car handler)
(with-parsed-tramp-file-name filename nil
(let ((current-connection tramp-current-connection)
(foreign
- (tramp-find-foreign-file-name-handler filename operation))
+ (tramp-find-foreign-file-name-handler v operation))
(signal-hook-function #'tramp-signal-hook-function)
result)
;; Set `tramp-current-connection'.
(tramp-compat-funcall 'directory-abbrev-make-regexp home-dir) filename)
(tramp-make-tramp-file-name
vec (concat "~" (substring filename (match-beginning 1))))
- filename)))
+ (tramp-make-tramp-file-name (tramp-dissect-file-name filename)))))
(defun tramp-handle-access-file (filename string)
"Like `access-file' for Tramp files."
;; We do not want traces in the debug buffer.
(let ((tramp-verbose (min tramp-verbose 3)))
(when (tramp-tramp-file-p filename)
- (let* ((v (tramp-dissect-file-name filename))
- (p (tramp-get-connection-process v))
+ (let* ((o (tramp-dissect-file-name filename))
+ (p (tramp-get-connection-process o))
(c (and (process-live-p p)
(tramp-get-connection-property p "connected" nil))))
;; We expand the file name only, if there is already a connection.
((eq identification 'user) (tramp-file-name-user-domain v))
((eq identification 'host) (tramp-file-name-host-port v))
((eq identification 'localname) localname)
- ((eq identification 'hop) hop)
+ ;; Hop exists only in original dissected file name.
+ ((eq identification 'hop) (tramp-file-name-hop o))
(t (tramp-make-tramp-file-name v 'noloc)))))))))
(defun tramp-handle-file-selinux-context (_filename)
(expand-file-name
symlink-target
(file-name-directory v2-localname))))
- v2-localname)
- 'nohop)))
+ v2-localname))))
(when (>= numchase numchase-limit)
(tramp-error
v1 'file-error
(cond
((stringp remote-copy)
(file-local-copy
- (tramp-make-tramp-file-name
- v remote-copy 'nohop)))
+ (tramp-make-tramp-file-name v remote-copy)))
((stringp tramp-temp-buffer-file-name)
(copy-file
filename tramp-temp-buffer-file-name 'ok)
(or remote-copy (null tramp-temp-buffer-file-name)))
(delete-file local-copy))
(when (stringp remote-copy)
- (delete-file (tramp-make-tramp-file-name v remote-copy 'nohop))))
+ (delete-file (tramp-make-tramp-file-name v remote-copy))))
;; Result.
(cons filename (cdr result)))))
(and (tramp-sh-file-name-handler-p vec)
(not (tramp-get-method-parameter vec 'tramp-copy-program))))
-(defun tramp-compute-multi-hops (vec)
- "Expands VEC according to `tramp-default-proxies-alist'."
- (let ((saved-tdpa tramp-default-proxies-alist)
- (target-alist `(,vec))
- (hops (or (tramp-file-name-hop vec) ""))
- (item vec)
- choices proxy)
-
- ;; Ad-hoc proxy definitions.
+(defun tramp-add-hops (vec)
+ "Add ad-hoc proxy definitions to `tramp-default-proxies-alist'."
+ (when-let ((hops (tramp-file-name-hop vec))
+ (item vec))
(dolist (proxy (reverse (split-string hops tramp-postfix-hop-regexp 'omit)))
(let* ((host-port (tramp-file-name-host-port item))
(user-domain (tramp-file-name-user-domain item))
(add-to-list 'tramp-default-proxies-alist entry)
(setq item (tramp-dissect-file-name proxy))))
;; Save the new value.
- (when (and hops tramp-save-ad-hoc-proxies)
+ (when tramp-save-ad-hoc-proxies
(customize-save-variable
- 'tramp-default-proxies-alist tramp-default-proxies-alist))
+ 'tramp-default-proxies-alist tramp-default-proxies-alist))))
+
+(defun tramp-compute-multi-hops (vec)
+ "Expands VEC according to `tramp-default-proxies-alist'."
+ (let ((saved-tdpa tramp-default-proxies-alist)
+ (target-alist `(,vec))
+ (item vec)
+ choices proxy)
+
+ ;; Ad-hoc proxy definitions.
+ (tramp-add-hops vec)
;; Look for proxy hosts to be passed.
(setq choices tramp-default-proxies-alist)
(null tramp-crypt-enabled)
;; The local temp directory must be writable for the other user.
(file-writable-p
- (tramp-make-tramp-file-name
- vec tramp-compat-temporary-file-directory 'nohop))
+ (tramp-make-tramp-file-name vec tramp-compat-temporary-file-directory))
;; On some systems, chown runs only for root.
(or (zerop (user-uid))
(zerop (tramp-get-remote-uid vec 'integer))))))
;; multi-hop.
(tramp-get-connection-property
proc "password-vector" (process-get proc 'vector))
- 'noloc 'nohop))
+ 'noloc))
(pw-prompt
(or prompt
(with-current-buffer (process-buffer proc)
(auth-source-forget
`(:max 1 ,(and user-domain :user) ,user-domain
:host ,host-port :port ,method))
- (password-cache-remove (tramp-make-tramp-file-name vec 'noloc 'nohop))))
+ (password-cache-remove (tramp-make-tramp-file-name vec 'noloc))))
(put #'tramp-clear-passwd 'tramp-suppress-trace t)
(string-equal
(file-remote-p
"/method1:user1@host1|method2:user2@host2:/path/to/file")
- (format "/%s:%s@%s|%s:%s@%s:"
- "method1" "user1" "host1" "method2" "user2" "host2")))
+ "/method2:user2@host2:"))
(should
(string-equal
(file-remote-p
"/method1:user1@host1"
"|method2:user2@host2"
"|method3:user3@host3:/path/to/file"))
- (format "/%s:%s@%s|%s:%s@%s|%s:%s@%s:"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/method3:user3@host3:"))
(should
(string-equal
(file-remote-p
"/-:user1@host1"
"|-:user2@host2"
"|-:user3@host3:/path/to/file"))
- (format "/%s:%s@%s|%s:%s@%s|%s:%s@%s:"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/method3:user3@host3:"))
;; Expand `tramp-default-user-alist'.
(add-to-list 'tramp-default-user-alist '("method1" "host1" "user1"))
"/method1:host1"
"|method2:host2"
"|method3:host3:/path/to/file"))
- (format "/%s:%s@%s|%s:%s@%s|%s:%s@%s:"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/method3:user3@host3:"))
;; Expand `tramp-default-host-alist'.
(add-to-list 'tramp-default-host-alist '("method1" "user1" "host1"))
"/method1:user1@"
"|method2:user2@"
"|method3:user3@:/path/to/file"))
- (format "/%s:%s@%s|%s:%s@%s|%s:%s@%s:"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/method3:user3@host3:"))
;; Ad-hoc user name and host name expansion.
(setq tramp-default-method-alist nil
"/method1:user1@host1"
"|method2:user2@"
"|method3:user3@:/path/to/file"))
- (format "/%s:%s@%s|%s:%s@%s|%s:%s@%s:"
- "method1" "user1" "host1"
- "method2" "user2" "host1"
- "method3" "user3" "host1")))
+ "/method3:user3@host1:"))
(should
(string-equal
(file-remote-p
"|method2:user2@host2"
"|method3:%u@%h"
"|method4:user4%domain4@host4#1234:/path/to/file"))
- (format "/%s:%s@%s|%s:%s@%s|%s:%s@%s|%s:%s@%s:"
- "method1" "user2" "host2"
- "method2" "user2" "host2"
- "method3" "user4" "host4"
- "method4" "user4%domain4" "host4#1234"))))
+ "/method4:user4%domain4@host4#1234:")))
;; Exit.
(tramp-change-syntax syntax))))
(should
(string-equal
(file-remote-p "/user1@host1|user2@host2:/path/to/file")
- (format "/%s@%s|%s@%s:" "user1" "host1" "user2" "host2")))
+ "/user2@host2:"))
(should
(string-equal
(file-remote-p
"/user1@host1"
"|user2@host2"
"|user3@host3:/path/to/file"))
- (format "/%s@%s|%s@%s|%s@%s:"
- "user1" "host1"
- "user2" "host2"
- "user3" "host3")))
+ "/user3@host3:"))
(should
(string-equal
(file-remote-p
"/host1"
"|host2"
"|host3:/path/to/file"))
- (format "/%s@%s|%s@%s|%s@%s:"
- "user1" "host1"
- "user2" "host2"
- "user3" "host3")))
+ "/user3@host3:"))
;; Expand `tramp-default-host-alist'.
(add-to-list 'tramp-default-host-alist '(nil "user1" "host1"))
"/user1@"
"|user2@"
"|user3@:/path/to/file"))
- (format "/%s@%s|%s@%s|%s@%s:"
- "user1" "host1"
- "user2" "host2"
- "user3" "host3")))
+ "/user3@host3:"))
;; Ad-hoc user name and host name expansion.
(setq tramp-default-user-alist nil
"/user1@host1"
"|user2@"
"|user3@:/path/to/file"))
- (format "/%s@%s|%s@%s|%s@%s:"
- "user1" "host1"
- "user2" "host1"
- "user3" "host1")))
+ "/user3@host1:"))
(should
(string-equal
(file-remote-p
"|user2@host2"
"|%u@%h"
"|user4%domain4@host4#1234:/path/to/file"))
- (format "/%s@%s|%s@%s|%s@%s|%s@%s:"
- "user2" "host2"
- "user2" "host2"
- "user4" "host4"
- "user4%domain4" "host4#1234"))))
+ "/user4%domain4@host4#1234:")))
;; Exit.
(tramp-change-syntax syntax))))
(string-equal
(file-remote-p
"/[method1/user1@host1|method2/user2@host2]/path/to/file")
- (format "/[%s/%s@%s|%s/%s@%s]"
- "method1" "user1" "host1" "method2" "user2" "host2")))
+ "/[method2/user2@host2]"))
(should
(string-equal
(file-remote-p
"/[method1/user1@host1"
"|method2/user2@host2"
"|method3/user3@host3]/path/to/file"))
- (format "/[%s/%s@%s|%s/%s@%s|%s/%s@%s]"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/[method3/user3@host3]"))
(should
(string-equal
(file-remote-p
"/[/user1@host1"
"|/user2@host2"
"|/user3@host3]/path/to/file"))
- (format "/[%s/%s@%s|%s/%s@%s|%s/%s@%s]"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/[method3/user3@host3]"))
;; Expand `tramp-default-user-alist'.
(add-to-list 'tramp-default-user-alist '("method1" "host1" "user1"))
"/[method1/host1"
"|method2/host2"
"|method3/host3]/path/to/file"))
- (format "/[%s/%s@%s|%s/%s@%s|%s/%s@%s]"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/[method3/user3@host3]"))
;; Expand `tramp-default-host-alist'.
(add-to-list 'tramp-default-host-alist '("method1" "user1" "host1"))
"/[method1/user1@"
"|method2/user2@"
"|method3/user3@]/path/to/file"))
- (format "/[%s/%s@%s|%s/%s@%s|%s/%s@%s]"
- "method1" "user1" "host1"
- "method2" "user2" "host2"
- "method3" "user3" "host3")))
+ "/[method3/user3@host3]"))
;; Ad-hoc user name and host name expansion.
(setq tramp-default-method-alist nil
"/[method1/user1@host1"
"|method2/user2@"
"|method3/user3@]/path/to/file"))
- (format "/[%s/%s@%s|%s/%s@%s|%s/%s@%s]"
- "method1" "user1" "host1"
- "method2" "user2" "host1"
- "method3" "user3" "host1")))
+ "/[method3/user3@host1]"))
(should
(string-equal
(file-remote-p
"|method2/user2@host2"
"|method3/%u@%h"
"|method4/user4%domain4@host4#1234]/path/to/file"))
- (format "/[%s/%s@%s|%s/%s@%s|%s/%s@%s|%s/%s@%s]"
- "method1" "user2" "host2"
- "method2" "user2" "host2"
- "method3" "user4" "host4"
- "method4" "user4%domain4" "host4#1234"))))
+ "/[method4/user4%domain4@host4#1234]")))
;; Exit.
(tramp-change-syntax syntax))))
(skip-unless (not (tramp--test-ange-ftp-p)))
(let* ((remote-host (file-remote-p tramp-test-temporary-file-directory))
+ (remote-host-nohop
+ (tramp-make-tramp-file-name (tramp-dissect-file-name remote-host)))
;; Not all methods can expand "~".
- (home-dir (ignore-errors (expand-file-name (concat remote-host "~")))))
+ (home-dir (ignore-errors (expand-file-name (concat remote-host "~"))))
+ home-dir-nohop)
(skip-unless home-dir)
;; Check home-dir abbreviation.
(unless (string-suffix-p "~" home-dir)
(should (equal (abbreviate-file-name (concat home-dir "/foo/bar"))
- (concat remote-host "~/foo/bar")))
+ (concat remote-host-nohop "~/foo/bar")))
(should (equal (abbreviate-file-name
(concat remote-host "/nowhere/special"))
- (concat remote-host "/nowhere/special"))))
+ (concat remote-host-nohop "/nowhere/special"))))
;; Check `directory-abbrev-alist' abbreviation.
(let ((directory-abbrev-alist
(,(concat "\\`" (regexp-quote remote-host) "/nowhere")
. ,(concat remote-host "/nw")))))
(should (equal (abbreviate-file-name (concat home-dir "/foo/bar"))
- (concat remote-host "~/f/bar")))
+ (concat remote-host-nohop "~/f/bar")))
(should (equal (abbreviate-file-name
(concat remote-host "/nowhere/special"))
- (concat remote-host "/nw/special"))))
+ (concat remote-host-nohop "/nw/special"))))
;; Check that home-dir abbreviation doesn't occur when home-dir is just "/".
- (setq home-dir (concat remote-host "/"))
+ (setq home-dir (concat remote-host "/")
+ home-dir-nohop
+ (tramp-make-tramp-file-name (tramp-dissect-file-name home-dir)))
;; The remote home directory is kept in the connection property
;; "home-directory". We fake this setting.
(tramp-set-connection-property tramp-test-vec "home-directory" home-dir)
- (should (equal (concat home-dir "foo/bar")
- (abbreviate-file-name (concat home-dir "foo/bar"))))
+ (should (equal (abbreviate-file-name (concat home-dir "foo/bar"))
+ (concat home-dir-nohop "foo/bar")))
(tramp-flush-connection-property tramp-test-vec "home-directory")))
(ert-deftest tramp-test07-file-exists-p ()