From 6139a05241aa3f082b49cbfe90ce61ceb0189bf7 Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Sat, 22 Jan 2022 17:12:14 +0100 Subject: [PATCH] Add direct remote copying in Tramp's scp support * doc/misc/tramp.texi: Use @trampfn{} function where possible. (Top, Configuration): Insert section 'Ssh setup' and remove section 'Windows setup hints' in menu. (Default Method): Mention tramp-use-scp-direct-remote-copying. (Ssh setup): New node. (Windows setup hints): Move it to that new node. (Frequently Asked Questions): Move items about ssh config to that node. * etc/NEWS: Add Tramp's direct remote copying feature. Fix typos. * lisp/net/tramp-sh.el (tramp-use-scp-direct-remote-copying): New defcustom. (tramp-methods) : Add "%y" marker. (tramp-scp-direct-remote-copying): New defun. (tramp-do-copy-or-rename-file-out-of-band): Extend for direct remote copying. * lisp/net/tramp.el (tramp-methods): Extend docstring. (tramp-password-prompt-not-unique): New defvar. (tramp-read-passwd): Adapt docstring. (tramp-read-passwd-without-cache): New defun. (tramp-action-password): Call it. --- doc/misc/tramp.texi | 435 ++++++++++++++++++++++----------------- etc/NEWS | 58 +++--- lisp/net/tramp-sh.el | 474 +++++++++++++++++++++++++------------------ lisp/net/tramp.el | 37 +++- 4 files changed, 598 insertions(+), 406 deletions(-) diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi index 6a198e9bfb5..ea544218ecd 100644 --- a/doc/misc/tramp.texi +++ b/doc/misc/tramp.texi @@ -133,19 +133,21 @@ Configuring @value{tramp} for use * Multi-hops:: Connecting to a remote host using multiple hops. * Firewalls:: Passing firewalls. * Customizing Methods:: Using Non-Standard Methods. -* Customizing Completion:: Selecting config files for user/host name completion. +* Customizing Completion:: Selecting config files for user/host name @c +completion. * Password handling:: Reusing passwords for several connections. * Connection caching:: Reusing connection related information. * Predefined connection information:: Setting own connection related information. -* Remote programs:: How @value{tramp} finds and uses programs on the remote host. +* Remote programs:: How @value{tramp} finds and uses programs @c +on the remote host. * Remote shell setup:: Remote shell setup hints. +* Ssh setup:: Ssh setup hints. * FUSE setup:: @acronym{FUSE} setup hints. * Android shell setup:: Android shell setup hints. * Auto-save File Lock and Backup:: Auto-save, File Lock and Backup. * Keeping files encrypted:: Protect remote files by encryption. -* Windows setup hints:: Issues with Cygwin ssh. Using @value{tramp} @@ -523,7 +525,7 @@ performed on another host, it can be comnbined with a leading connects first to the other host with non-administrative credentials, and changes to administrative credentials on that host afterwards. In a simple case, the syntax looks like -@file{@value{prefix}ssh@value{postfixhop}user@@host|sudo@value{postfixhop}@value{postfix}/path/to/file}. +@file{@trampfn{ssh@value{postfixhop}user@@host|sudo,,/path/to/file}}. @xref{Ad-hoc multi-hops}. @@ -683,19 +685,21 @@ may be used in your init file: * Multi-hops:: Connecting to a remote host using multiple hops. * Firewalls:: Passing firewalls. * Customizing Methods:: Using Non-Standard Methods. -* Customizing Completion:: Selecting config files for user/host name completion. +* Customizing Completion:: Selecting config files for user/host name @c +completion. * Password handling:: Reusing passwords for several connections. * Connection caching:: Reusing connection related information. * Predefined connection information:: Setting own connection related information. -* Remote programs:: How @value{tramp} finds and uses programs on the remote host. +* Remote programs:: How @value{tramp} finds and uses programs @c +on the remote host. * Remote shell setup:: Remote shell setup hints. +* Ssh setup:: Ssh setup hints. * FUSE setup:: @acronym{FUSE} setup hints. * Android shell setup:: Android shell setup hints. * Auto-save File Lock and Backup:: Auto-save, File Lock and Backup. * Keeping files encrypted:: Protect remote files by encryption. -* Windows setup hints:: Issues with Cygwin ssh. @end menu @@ -1234,7 +1238,8 @@ be populated in your @command{Online Accounts} application outside Emacs. Since Google Drive uses cryptic blob file names internally, @value{tramp} works with the @code{display-name} of the files. This could produce unexpected behavior in case two files in the same -directory have the same @code{display-name}, such a situation must be avoided. +directory have the same @code{display-name}, such a situation must be +avoided. @item @option{mtp} @cindex method @option{mtp} @@ -1448,7 +1453,7 @@ External methods might be more efficient for large files, but most @value{tramp} users edit small files more often than large files. Enable compression, @code{tramp-inline-compress-start-size}, for a -performance boost for large files. +performance boost for large files with inline methods. Since @command{ssh} has become the most common method of remote host access and it has the most reasonable security protocols, use @@ -1474,6 +1479,10 @@ For editing large files, @option{scp} is faster than @option{ssh}. @option{pscp} is faster than @option{plink}. But this speed improvement is not always true. +When copying large files between two different remote hosts via +@option{scp}, set @code{tramp-use-scp-direct-remote-copying} to +non-@code{nil}. + @node Default User @section Selecting a default user @@ -1689,8 +1698,8 @@ Sometimes, it is not possible to reach a remote host directly. A firewall might be in the way, which could be passed via a proxy server. -Both ssh and PuTTY support such proxy settings, using an HTTP tunnel -via the @command{CONNECT} command (conforming to RFC 2616, 2817 +Both OpenSSH and PuTTY support such proxy settings, using an HTTP +tunnel via the @command{CONNECT} command (conforming to RFC 2616, 2817 specifications). Proxy servers using HTTP 1.1 or later protocol support this command. @@ -1804,7 +1813,7 @@ hadoop server. @cindex @option{vagrant} method Convenience method to access vagrant boxes. It is often used in multi-hop file names like -@file{@value{prefix}vagrant@value{postfixhop}box|sudo@value{postfixhop}box@value{postfix}/path/to/file}, +@file{@trampfn{vagrant@value{postfixhop}box|sudo,box,/path/to/file}}, where @samp{box} is the name of the vagrant box. @end table @@ -2606,6 +2615,211 @@ where @samp{192.168.0.1} is the remote host IP address @end table +@node Ssh setup +@section Ssh setup hints + +The most common @value{tramp} connection family is based on either +@command{ssh} or @command{scp} of OpenSSH, or @command{plink} or +@command{pscp} of PuTTY on MS Windows. In the following, some +configuration recommendations are given. + + +@subsection Detection of session hangouts + +@vindex ServerAliveInterval@r{, ssh option} +@vindex ServerAliveCountMax@r{, ssh option} +@command{ssh} sessions on the local host hang when the network is +down. @value{tramp} cannot safely detect such hangs. OpenSSH can be +configured to kill such hangs with the following settings in +@file{~/.ssh/config}: + +@example +@group +Host * + ServerAliveInterval 5 + ServerAliveCountMax 2 +@end group +@end example + +The corresponding PuTTY configuration is in the @option{Connection} +entry, @option{Seconds between keepalives} option. Set this to 5. +There is no counter which could be set. + + +@subsection Using ssh connection sharing + +@vindex ControlPath@r{, ssh option} +@vindex ControlPersist@r{, ssh option} +@value{tramp} uses the @option{ControlMaster=auto} OpenSSH option by +default, if possible. However, it overwrites @option{ControlPath} +settings when initiating @command{ssh} sessions. @value{tramp} does +this to fend off a stall if a master session opened outside the Emacs +session is no longer open. That is why @value{tramp} prompts for the +password again even if there is an @command{ssh} already open. + +@vindex tramp-ssh-controlmaster-options +Some OpenSSH versions support a @option{ControlPersist} option, which +allows you to set the @option{ControlPath} provided the variable +@code{tramp-ssh-controlmaster-options} is customized as follows: + +@lisp +@group +(customize-set-variable + 'tramp-ssh-controlmaster-options + (concat + "-o ControlPath=/tmp/ssh-ControlPath-%%r@@%%h:%%p " + "-o ControlMaster=auto -o ControlPersist=yes")) +@end group +@end lisp + +Note how @samp{%r}, @samp{%h} and @samp{%p} must be encoded as +@samp{%%r}, @samp{%%h} and @samp{%%p}. + +@vindex tramp-use-ssh-controlmaster-options +If the @file{~/.ssh/config} file is configured appropriately for the +above behavior, then any changes to @command{ssh} can be suppressed +with this @code{nil} setting: + +@lisp +(customize-set-variable 'tramp-use-ssh-controlmaster-options nil) +@end lisp + +@vindex ProxyCommand@r{, ssh option} +@vindex ProxyJump@r{, ssh option} +This should also be set to @code{nil} if you use the +@option{ProxyCommand} or @option{ProxyJump} options in your +@command{ssh} configuration. + +In order to use the @option{ControlMaster} option, @value{tramp} must +check whether the @command{ssh} client supports this option. This is +only possible on the local host, for the first hop. @value{tramp} +does not use this option on proxy hosts, therefore. + +If you want to use this option also for the other hops, you must +configure @file{~/.ssh/config} on the proxy host: + +@example +@group +Host * + ControlMaster auto + ControlPath tramp.%C + ControlPersist no +@end group +@end example + +Check the @samp{ssh_config(5)} man page whether these options are +supported on your proxy host. + +On MS Windows, @code{tramp-use-ssh-controlmaster-options} is set to +@code{nil} by default, because the MS Windows and MSYS2 +implementations of @command{OpenSSH} do not support this option properly. + +In PuTTY, you can achieve connection sharing in the @option{Connection/SSH} +entry, enabling the @option{Share SSH connections if possible} option. + + +@subsection Configure direct copying between two remote servers + +@vindex tramp-use-scp-direct-remote-copying +@value{tramp} uses a temporary local copy when copying two files +between different remote hosts via external methods. This behavior is +due to authentication problems @value{tramp} cannot handle +sufficiently. However, for @option{scp} connections this can be +changed. When a file shall be copied between two different remote +hosts @samp{source} and @samp{target}, and + +@itemize @minus +@item +Variable @code{tramp-use-scp-direct-remote-copying} is non-@code{nil}, + +@item +Remote host @samp{source} doesn't use the @option{RemoteCommand} +option in @file{~/.ssh/config}, + +@item +Remote host @samp{target} shows the same host key when seen from the +local host and from host @samp{source}, and + +@item +@command{scp} running on host @samp{source} can authenticate to host +@samp{target} without requiring a password, +@end itemize + +@noindent +@value{tramp} applies direct remote copying between hosts +@samp{source} and @samp{target} like + +@example +scp -p -T -R -q -r source:/path/to/file target:/path/to/another/file +@end example + +This protects also your local temporary directory from overrun when +copying large files. + +If these conditions do not apply, and +@code{tramp-use-scp-direct-remote-copying} is non-@code{nil}, the +option @samp{-3} is used instead of @samp{-R}. + +@c FIXME +When @value{tramp} uses direct remote copying, password caches are not +consulted. + + +@subsection Issues with Cygwin ssh +@cindex cygwin, issues + +This section is incomplete. Please share your solutions. + +@cindex method @option{sshx} with cygwin +@cindex @option{sshx} method with cygwin + +Cygwin's @command{ssh} works only with a Cygwin version of Emacs. To +check for compatibility: type @kbd{M-x eshell @key{RET}}, and start +@kbd{ssh test.host @key{RET}}. Incompatibilities trigger this +message: + +@example +Pseudo-terminal will not be allocated because stdin is not a terminal. +@end example + +Some older versions of Cygwin's @command{ssh} work with the +@option{sshx} access method. Consult Cygwin's FAQ at +@uref{https://cygwin.com/faq/} for details. + +@cindex cygwin and @command{fakecygpty} +@cindex @command{fakecygpty} and cygwin + +On @uref{https://www.emacswiki.org/emacs/SshWithNTEmacs, the Emacs +Wiki} it is explained how to use the helper program +@command{fakecygpty} to fix this problem. + +@cindex method @option{scpx} with cygwin +@cindex @option{scpx} method with cygwin + +When using the @option{scpx} access method, Emacs may call +@command{scp} with MS Windows file naming, such as @file{c:/foo}. But +the version of @command{scp} that is installed with Cygwin does not +know about MS Windows file naming, which causes it to incorrectly look +for a host named @samp{c}. + +A workaround: write a wrapper script for @option{scp} to convert +Windows file names to Cygwin file names. + +@cindex cygwin and @command{ssh-agent} +@cindex @env{SSH_AUTH_SOCK} and emacs on ms windows +@vindex SSH_AUTH_SOCK@r{, environment variable} + +When using the @command{ssh-agent} on MS Windows for password-less +interaction, @option{ssh} methods depend on the environment variable +@env{SSH_AUTH_SOCK}. But this variable is not set when Emacs is +started from a Desktop shortcut and authentication fails. + +One workaround is to use an MS Windows based SSH Agent, such as +@command{Pageant}. It is part of the PuTTY Suite of tools. + +The fallback is to start Emacs from a shell. + + @node FUSE setup @section @acronym{FUSE} setup hints @@ -2828,10 +3042,10 @@ Example: The backup file name of @file{@trampfn{su,root@@localhost,/etc/secretfile}} would be @ifset unified -@file{@trampfn{su,root@@localhost,~/.emacs.d/backups/!su:root@@localhost:!etc!secretfile~}} +@file{@trampfn{su,root@@localhost,~/.emacs.d/backups/!su:root@@localhost:!etc!secretfile~}}. @end ifset @ifset separate -@file{@trampfn{su,root@@localhost,~/.emacs.d/backups/![su!root@@localhost]!etc!secretfile~}} +@file{@trampfn{su,root@@localhost,~/.emacs.d/backups/![su!root@@localhost]!etc!secretfile~}}. @end ifset @vindex auto-save-file-name-transforms @@ -2985,62 +3199,6 @@ subdirectories will remain encrypted. @end deffn -@node Windows setup hints -@section Issues with Cygwin ssh -@cindex cygwin, issues - -This section is incomplete. Please share your solutions. - -@cindex method @option{sshx} with cygwin -@cindex @option{sshx} method with cygwin - -Cygwin's @command{ssh} works only with a Cygwin version of Emacs. To -check for compatibility: type @kbd{M-x eshell @key{RET}}, and start -@kbd{ssh test.host @key{RET}}. Incompatibilities trigger this -message: - -@example -Pseudo-terminal will not be allocated because stdin is not a terminal. -@end example - -Some older versions of Cygwin's @command{ssh} work with the -@option{sshx} access method. Consult Cygwin's FAQ at -@uref{https://cygwin.com/faq/} for details. - -@cindex cygwin and @command{fakecygpty} -@cindex @command{fakecygpty} and cygwin - -On @uref{https://www.emacswiki.org/emacs/SshWithNTEmacs, the Emacs -Wiki} it is explained how to use the helper program -@command{fakecygpty} to fix this problem. - -@cindex method @option{scpx} with cygwin -@cindex @option{scpx} method with cygwin - -When using the @option{scpx} access method, Emacs may call -@command{scp} with MS Windows file naming, such as @file{c:/foo}. But -the version of @command{scp} that is installed with Cygwin does not -know about MS Windows file naming, which causes it to incorrectly look -for a host named @samp{c}. - -A workaround: write a wrapper script for @option{scp} to convert -Windows file names to Cygwin file names. - -@cindex cygwin and @command{ssh-agent} -@cindex @env{SSH_AUTH_SOCK} and emacs on ms windows -@vindex SSH_AUTH_SOCK@r{, environment variable} - -When using the @command{ssh-agent} on MS Windows for password-less -interaction, @option{ssh} methods depend on the environment variable -@env{SSH_AUTH_SOCK}. But this variable is not set when Emacs is -started from a Desktop shortcut and authentication fails. - -One workaround is to use an MS Windows based SSH Agent, such as -Pageant. It is part of the Putty Suite of tools. - -The fallback is to start Emacs from a shell. - - @node Usage @chapter Using @value{tramp} @cindex using @value{tramp} @@ -3085,23 +3243,23 @@ is a feature of Emacs that may cause missed prompts when using on the remote host @var{host}, using the method @var{method}. @table @file -@item @value{prefix}ssh@value{postfixhop}melancholia@value{postfix}.emacs +@item @trampfn{ssh,melancholia,.emacs} For the file @file{.emacs} located in the home directory, on the host @code{melancholia}, using method @code{ssh}. -@item @value{prefix}ssh@value{postfixhop}melancholia.danann.net@value{postfix}.emacs +@item @trampfn{ssh,melancholia.danann.net,.emacs} For the file @file{.emacs} specified using the fully qualified domain name of the host. -@item @value{prefix}ssh@value{postfixhop}melancholia@value{postfix}~/.emacs +@item @trampfn{ssh,melancholia,~/.emacs} For the file @file{.emacs} specified using the @file{~}, which is expanded. -@item @value{prefix}ssh@value{postfixhop}melancholia@value{postfix}~daniel/.emacs +@item @trampfn{ssh,melancholia,~daniel/.emacs} For the file @file{.emacs} located in @code{daniel}'s home directory on the host, @code{melancholia}. The @file{~} construct is expanded to the home directory of that user on the remote host. -@item @value{prefix}ssh@value{postfixhop}melancholia@value{postfix}/etc/squid.conf +@item @trampfn{ssh,melancholia,/etc/squid.conf} For the file @file{/etc/squid.conf} on the host @code{melancholia}. @end table @@ -3115,12 +3273,9 @@ brackets @file{@value{ipv6prefix}} and @file{@value{ipv6postfix}}. @end ifset By default, @value{tramp} will use the current local user name as the -remote user name for log in to the remote host. Specifying a different -name using the proper syntax will override this default behavior: - -@example -@trampfn{method,user@@host,path/to/file} -@end example +remote user name for log in to the remote host. Specifying a +different name using the proper syntax will override this default +behavior: @file{@trampfn{method,user@@host,path/to/file}}. @file{@trampfn{ssh,daniel@@melancholia,.emacs}} is for file @file{.emacs} in @code{daniel}'s home directory on the host, @@ -3316,8 +3471,9 @@ remote host name and file name. For example, hopping over a single proxy @samp{bird@@bastion} to a remote file on @samp{you@@remotehost}: @example -@c @kbd{C-x C-f @trampfn{ssh@value{postfixhop}bird@@bastion|ssh,you,remotehost,/path} @key{RET}} -@kbd{C-x C-f @value{prefix}ssh@value{postfixhop}bird@@bastion|ssh@value{postfixhop}you@@remotehost@value{postfix}/path @key{RET}} +@c @kbd{C-x C-f @trampfn{ssh@value{postfixhop}bird@@bastion|ssh,you@@remotehost,/path} @key{RET}} +@kbd{C-x C-f @value{prefix}ssh@value{postfixhop}bird@@bastion|@c +ssh@value{postfixhop}you@@remotehost@value{postfix}/path @key{RET}} @end example Each involved method must be an inline method (@pxref{Inline methods}). @@ -3345,12 +3501,12 @@ 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 @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}}. +@samp{@trampfn{ssh@value{postfixhop}%h|su,remotehost,}}. -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 +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 file name is equivalent to the previous example: -@samp{@value{prefix}ssh@value{postfixhop}remotehost|su@value{postfixhop}@value{postfix}}. +@samp{@trampfn{ssh@value{postfixhop}remotehost|su,,}}. @node Remote processes @@ -3971,7 +4127,9 @@ would trigger renaming of buffer file names on @samp{badhost} to @samp{goodhost}, including changing the directory name. @lisp -("@trampfn{ssh,.+\\\\.company\\\\.org,}" . "@value{prefix}ssh@value{postfixhop}multi.hop|ssh@value{postfixhop}%h@value{postfix}") +("@trampfn{ssh,.+\\\\.company\\\\.org,}" @c +. "@value{prefix}ssh@value{postfixhop}multi.hop|@c +ssh@value{postfixhop}%h@value{postfix}") @end lisp routes all connections to a host in @samp{company.org} via @@ -4231,7 +4389,8 @@ It is even possible to access file archives in file archives, as (progn (url-handler-mode 1) (find-file - "https://ftp.debian.org/debian/pool/main/c/coreutils/coreutils_8.28-1_amd64.deb/control.tar.gz/control")) + "https://ftp.debian.org/debian/pool/main/c/coreutils/\ +coreutils_8.28-1_amd64.deb/control.tar.gz/control")) @end group @end lisp @@ -4537,97 +4696,6 @@ In order to disable those optimizations, set user option @code{tramp-local-host-regexp} to @code{nil}. -@item -@value{tramp} does not recognize if a @command{ssh} session hangs - -@vindex ServerAliveInterval@r{, ssh option} -@command{ssh} sessions on the local host hang when the network is -down. @value{tramp} cannot safely detect such hangs. The network -configuration for @command{ssh} can be configured to kill such hangs -with the following command in the @file{~/.ssh/config}: - -@example -@group -Host * - ServerAliveInterval 5 -@end group -@end example - - -@item -@value{tramp} does not use default @command{ssh} @option{ControlPath} - -@vindex ControlPath@r{, ssh option} -@vindex ControlPersist@r{, ssh option} -@value{tramp} overwrites @option{ControlPath} settings when initiating -@command{ssh} sessions. @value{tramp} does this to fend off a stall -if a master session opened outside the Emacs session is no longer -open. That is why @value{tramp} prompts for the password again even -if there is an @command{ssh} already open. - -@vindex tramp-ssh-controlmaster-options -Some @command{ssh} versions support a @option{ControlPersist} option, -which allows you to set the @option{ControlPath} provided the variable -@code{tramp-ssh-controlmaster-options} is customized as follows: - -@lisp -@group -(customize-set-variable - 'tramp-ssh-controlmaster-options - (concat - "-o ControlPath=/tmp/ssh-ControlPath-%%r@@%%h:%%p " - "-o ControlMaster=auto -o ControlPersist=yes")) -@end group -@end lisp - -Note how @samp{%r}, @samp{%h} and @samp{%p} must be encoded as -@samp{%%r}, @samp{%%h} and @samp{%%p}. - -@vindex tramp-use-ssh-controlmaster-options -If the @file{~/.ssh/config} file is configured appropriately for the -above behavior, then any changes to @command{ssh} can be suppressed -with this @code{nil} setting: - -@lisp -(customize-set-variable 'tramp-use-ssh-controlmaster-options nil) -@end lisp - -@vindex ProxyCommand@r{, ssh option} -@vindex ProxyJump@r{, ssh option} -This should also be set to @code{nil} if you use the -@option{ProxyCommand} or @option{ProxyJump} options in your -@command{ssh} configuration. - -On MS Windows, @code{tramp-use-ssh-controlmaster-options} is set to -@code{nil} by default, because the MS Windows and MSYS2 -implementations of @command{OpenSSH} do not support this option properly. - - -@item -On multi-hop connections, @value{tramp} does not use @command{ssh} -@option{ControlMaster} - -In order to use the @option{ControlMaster} option, @value{tramp} must -check whether the @command{ssh} client supports this option. This is -only possible on the local host, for the first hop. @value{tramp} -does not use this option on proxy hosts. - -If you want to use this option also for the other hops, you must -configure @file{~/.ssh/config} on the proxy host: - -@example -@group -Host * - ControlMaster auto - ControlPath tramp.%C - ControlPersist no -@end group -@end example - -Check the @samp{ssh_config(5)} man page whether these options are -supported on your proxy host. - - @item Does @value{tramp} support @acronym{SSH} security keys? @@ -5075,7 +5143,8 @@ Why saved multi-hop file names do not work in a new Emacs session? When saving ad-hoc multi-hop @value{tramp} file names (@pxref{Ad-hoc multi-hops}) via bookmarks, recent files, filecache, bbdb, or another package, use the full ad-hoc file name including all hops, like -@file{@trampfn{ssh,bird@@bastion|ssh@value{postfixhop}news.my.domain,/opt/news/etc}}. +@file{@trampfn{ssh,bird@@bastion|ssh@value{postfixhop}@c +news.my.domain,/opt/news/etc}}. Alternatively, when saving abbreviated multi-hop file names @file{@trampfn{ssh,news@@news.my.domain,/opt/news/etc}}, the user @@ -5384,7 +5453,7 @@ bind it to non-@code{nil} value. Keeping a local cache of remote file attributes in sync with the remote host is a time-consuming operation. Flushing and re-querying these attributes can tax @value{tramp} to a grinding halt on busy -remote servers. +remote hosts. To get around these types of slow-downs in @value{tramp}'s responsiveness, set the @code{process-file-side-effects} to @code{nil} @@ -5539,6 +5608,8 @@ function call traces are written to the buffer @file{*trace-output*}. @c @c * Say something about the .login and .profile files of the remote @c shells. +@c @c * Explain how tramp.el works in principle: open a shell on a remote @c host and then send commands to it. +@c @c * Consistent small or capitalized words especially in menus. diff --git a/etc/NEWS b/etc/NEWS index 048f6d5598b..5297db3e2d5 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -72,8 +72,8 @@ work on any underlying window system supported by GDK, such as Wayland and Broadway. --- -** The docstrings of preloaded files are not in 'etc/DOC' any more. -Instead, they're fetched as needed from the corresponding '.elc' file, +** The docstrings of preloaded files are not in "etc/DOC" any more. +Instead, they're fetched as needed from the corresponding ".elc" file, as was already the case for all the non-preloaded files. @@ -94,10 +94,10 @@ time. --- ** Support for old EIEIO functions is not autoloaded any more. -You need an explicit (require 'eieio-compat) to use 'defmethod' -and 'defgeneric' (which have been made obsolete in Emacs-25 with +You need an explicit '(require 'eieio-compat)' to use 'defmethod' +and 'defgeneric' (which have been made obsolete in Emacs 25.1 with 'cl-defmethod' and 'cl-defgeneric'). -Similarly you might need to (require 'eieio-compat) before loading +Similarly you might need to '(require 'eieio-compat)' before loading files that were compiled with an old EIEIO (Emacs<25). --- @@ -260,13 +260,13 @@ These will take you (respectively) to the next and previous "page". ** Outline Mode *** Support for customizing the default visibility state of headings. -Customize the option 'outline-default-state' to define what headings -will be visible after Outline mode is turned on. When equal to a -number, the option 'outline-default-rules' determines the visibility -of the subtree starting at the corresponding level. Values are -provided to control showing a heading subtree depending on whether the -heading matches a regexp, or on whether its subtree has long lines or -is itself too long. +Customize the user option 'outline-default-state' to define what +headings will be visible after Outline mode is turned on. When equal +to a number, the user option 'outline-default-rules' determines the +visibility of the subtree starting at the corresponding level. Values +are provided to control showing a heading subtree depending on whether +the heading matches a regexp, or on whether its subtree has long lines +or is itself too long. ** Outline Minor Mode @@ -414,15 +414,15 @@ received. ** Minibuffer and Completions -*** The *Completions* buffer can now be automatically selected. -To enable this behavior, customize the option 'completion-auto-select' -to t. Then pressing TAB will switch to the *Completions* buffer when -it pops up that buffer. +*** The "*Completions*" buffer can now be automatically selected. +To enable this behavior, customize the user option +'completion-auto-select' to t. Then pressing 'TAB' will switch to the +"*Completions*" buffer when it pops up that buffer. *** New user option 'completion-wrap-movement'. When non-nil, the commands 'next-completion' and 'previous-completion' automatically wrap around on reaching the beginning or the end of -the *Completions* buffer. +the "*Completions*" buffer. ** Isearch and Replace @@ -484,7 +484,7 @@ If non-nil, 'C-c C-a' will put attached files at the end of the message. --- *** Message Mode now supports image yanking. ---- ++++ *** New user option 'message-server-alist'. This controls automatic insertion of the "X-Message-SMTP-Method" header before sending a message. @@ -836,6 +836,12 @@ When calling 'abbreviate-file-name' on a Tramp filename, the result will abbreviate the user's home directory, for example by abbreviating "/ssh:user@host:/home/user" to "/ssh:user@host:~". ++++ +*** New user option 'tramp-use-scp-direct-remote-copying'. +When set to non-nil, Tramp does not copy files between two remote +hosts via a local copy in its temporary directory, but let the 'scp' +command do this job. + ** Browse URL --- @@ -991,7 +997,7 @@ read back by the Emacs Lisp reader. This variable allows changing how Emacs prints unreadable objects. --- -** The variable 'polling-period' now accepts floating point values. +** The user option 'polling-period' now accepts floating point values. This means Emacs can now poll for input during Lisp execution more frequently than once in a second. @@ -1039,7 +1045,7 @@ wheel on some mice, or when the user's finger moves off the touchpad. +++ ** New event type 'pinch'. -This event is sent when a user peforms a pinch gesture on a touchpad, +This event is sent when a user performs a pinch gesture on a touchpad, which is comprised of placing two fingers on the touchpad and moving them towards or away from each other. @@ -1199,14 +1205,14 @@ This can be used to check whether a specific font has a glyph for a character. +++ -** 'window-text-pixel-size' now accepts a new argument 'ignore-line-at-end'. +** 'window-text-pixel-size' now accepts a new argument IGNORE-LINE-AT-END. This controls whether or not the last screen line of the text being measured will be counted for the purpose of calculating the text dimensions. +++ -** 'window-text-pixel-size' understands a new meaning of 'from'. -Specifying a cons as the from argument allows to start measuring text +** 'window-text-pixel-size' understands a new meaning of FROM. +Specifying a cons as the FROM argument allows to start measuring text from a specified amount of pixels above or below a position. --- @@ -1383,9 +1389,9 @@ cookies set by web pages on disk. This variable is bound to t during the preparation of a "*Help*" buffer. +++ -** Timestamps like (1 . 1000) now work without warnings being generated. -For example, (time-add nil '(1 . 1000)) no longer warns that the -(1 . 1000) acts like (1000 . 1000000). This warning, which was a +** Timestamps like '(1 . 1000)' now work without warnings being generated. +For example, '(time-add nil '(1 . 1000))' no longer warns that the +'(1 . 1000)' acts like '(1000 . 1000000)'. This warning, which was a temporary transition aid for Emacs 27, has served its purpose. +++ diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index f0ceabe568b..98192bd96d5 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -38,6 +38,7 @@ (declare-function dired-compress-file "dired-aux") (declare-function dired-remove-file "dired-aux") (defvar dired-compress-file-suffixes) +;; Added in Emacs 28.1. (defvar process-file-return-signal-string) (defvar vc-handled-backends) (defvar vc-bzr-program) @@ -136,6 +137,12 @@ be auto-detected by Tramp. The string is used in `tramp-methods'.") +(defcustom tramp-use-scp-direct-remote-copying nil + "Whether to use direct copying between two remote hosts." + :group 'tramp + :version "29.1" + :type 'boolean) + ;; Initialize `tramp-methods' with the supported methods. ;;;###tramp-autoload (tramp--with-startup @@ -172,7 +179,7 @@ The string is used in `tramp-methods'.") (tramp-remote-shell-args ("-c")) (tramp-copy-program "scp") (tramp-copy-args (("-P" "%p") ("-p" "%k") - ("%x") ("-q") ("-r") ("%c"))) + ("%x") ("%y") ("-q") ("-r") ("%c"))) (tramp-copy-keep-date t) (tramp-copy-recursive t))) (add-to-list 'tramp-methods @@ -188,7 +195,7 @@ The string is used in `tramp-methods'.") (tramp-remote-shell-args ("-c")) (tramp-copy-program "scp") (tramp-copy-args (("-P" "%p") ("-p" "%k") - ("%x") ("-q") ("-r") ("%c"))) + ("%x") ("%y") ("-q") ("-r") ("%c"))) (tramp-copy-keep-date t) (tramp-copy-recursive t))) (add-to-list 'tramp-methods @@ -2240,200 +2247,210 @@ the uid and gid from FILENAME." (op filename newname ok-if-already-exists keep-date) "Invoke `scp' program to copy. The method used must be an out-of-band method." - (let* ((t1 (tramp-tramp-file-p filename)) - (t2 (tramp-tramp-file-p newname)) - (orig-vec (tramp-dissect-file-name (if t1 filename newname))) + (let* ((v1 (and (tramp-tramp-file-p filename) + (tramp-dissect-file-name filename))) + (v2 (and (tramp-tramp-file-p newname) + (tramp-dissect-file-name newname))) + (v (or v1 v2)) copy-program copy-args copy-env copy-keep-date listener spec options source target remote-copy-program remote-copy-args p) - (with-parsed-tramp-file-name (if t1 filename newname) nil - (if (and t1 t2) - - ;; Both are Tramp files. We shall optimize it when the - ;; methods for FILENAME and NEWNAME are the same. - (let* ((dir-flag (file-directory-p filename)) - (tmpfile (tramp-compat-make-temp-file localname dir-flag))) - (if dir-flag - (setq tmpfile - (expand-file-name - (file-name-nondirectory newname) tmpfile))) - (unwind-protect - (progn - (tramp-do-copy-or-rename-file-out-of-band - op filename tmpfile ok-if-already-exists keep-date) - (tramp-do-copy-or-rename-file-out-of-band - 'rename tmpfile newname ok-if-already-exists keep-date)) - ;; Save exit. - (ignore-errors - (if dir-flag - (delete-directory - (expand-file-name ".." tmpfile) 'recursive) - (delete-file tmpfile))))) - - ;; Check which ones of source and target are Tramp files. - (setq source (funcall - (if (and (string-equal method "rsync") - (file-directory-p filename) - (not (file-exists-p newname))) - #'file-name-as-directory - #'identity) - (if t1 - (tramp-make-copy-program-file-name v) - (tramp-compat-file-name-unquote filename))) - target (if t2 - (tramp-make-copy-program-file-name v) - (tramp-compat-file-name-unquote newname))) - - ;; Check for user. There might be an interactive setting. - (setq user (or (tramp-file-name-user v) - (tramp-get-connection-property v "login-as" nil))) - - ;; Check for listener port. - (when (tramp-get-method-parameter v 'tramp-remote-copy-args) - (setq listener (number-to-string (+ 50000 (random 10000)))) - (while - (zerop (tramp-call-process v "nc" nil nil nil "-z" host listener)) - (setq listener (number-to-string (+ 50000 (random 10000)))))) - - ;; Compose copy command. - (setq options - (format-spec - (tramp-ssh-controlmaster-options v) - (format-spec-make - ?t (tramp-get-connection-property - (tramp-get-connection-process v) "temp-file" ""))) - spec (list - ?h (or host "") ?u (or user "") ?p (or port "") - ?r listener ?c options ?k (if keep-date " " "") - ?n (concat "2>" (tramp-get-remote-null-device v)) - ?x (tramp-scp-strict-file-name-checking v)) - copy-program (tramp-get-method-parameter v 'tramp-copy-program) - copy-keep-date (tramp-get-method-parameter - v 'tramp-copy-keep-date) - copy-args - ;; " " has either been a replacement of "%k" (when - ;; keep-date argument is non-nil), or a replacement for - ;; the whole keep-date sublist. - (delete " " (apply #'tramp-expand-args v 'tramp-copy-args spec)) - ;; `tramp-ssh-controlmaster-options' is a string instead - ;; of a list. Unflatten it. - copy-args - (tramp-compat-flatten-tree - (mapcar - (lambda (x) (if (tramp-compat-string-search " " x) - (split-string x) x)) - copy-args)) - copy-env (apply #'tramp-expand-args v 'tramp-copy-env spec) - remote-copy-program - (tramp-get-method-parameter v 'tramp-remote-copy-program) - remote-copy-args - (apply #'tramp-expand-args v 'tramp-remote-copy-args spec)) - - ;; Check for local copy program. - (unless (executable-find copy-program) - (tramp-error - v 'file-error "Cannot find local copy program: %s" copy-program)) - - ;; Install listener on the remote side. The prompt must be - ;; consumed later on, when the process does not listen anymore. - (when remote-copy-program - (unless (with-tramp-connection-property - v (concat "remote-copy-program-" remote-copy-program) - (tramp-find-executable - v remote-copy-program (tramp-get-remote-path v))) - (tramp-error - v 'file-error - "Cannot find remote listener: %s" remote-copy-program)) - (setq remote-copy-program - (mapconcat - #'identity - (append - (list remote-copy-program) remote-copy-args - (list (if t1 (concat "<" source) (concat ">" target)) "&")) - " ")) - (tramp-send-command v remote-copy-program) - (with-timeout - (60 (tramp-error - v 'file-error - "Listener process not running on remote host: `%s'" - remote-copy-program)) - (tramp-send-command v (format "netstat -l | grep -q :%s" listener)) - (while (not (tramp-send-command-and-check v nil)) - (tramp-send-command - v (format "netstat -l | grep -q :%s" listener))))) + (if (and v1 v2 (zerop (length (tramp-scp-direct-remote-copying v1 v2)))) - (with-temp-buffer + ;; Both are Tramp files. We cannot use direct remote copying. + (let* ((dir-flag (file-directory-p filename)) + (tmpfile (tramp-compat-make-temp-file + (tramp-file-name-localname v1) dir-flag))) + (if dir-flag + (setq tmpfile + (expand-file-name + (file-name-nondirectory newname) tmpfile))) (unwind-protect - ;; The default directory must be remote. - (let ((default-directory - (file-name-directory (if t1 filename newname))) - (process-environment (copy-sequence process-environment))) - ;; Set the transfer process properties. - (tramp-set-connection-property - v "process-name" (buffer-name (current-buffer))) - (tramp-set-connection-property - v "process-buffer" (current-buffer)) - (when copy-env - (tramp-message - orig-vec 6 "%s=\"%s\"" - (car copy-env) (string-join (cdr copy-env) " ")) - (setenv (car copy-env) (string-join (cdr copy-env) " "))) - (setq - copy-args - (append - copy-args - (if remote-copy-program - (list (if t1 (concat ">" target) (concat "<" source))) - (list source target))) - ;; Use an asynchronous process. By this, password - ;; can be handled. We don't set a timeout, because - ;; the copying of large files can last longer than 60 - ;; secs. - p (let ((default-directory tramp-compat-temporary-file-directory)) - (apply - #'start-process - (tramp-get-connection-name v) - (tramp-get-connection-buffer v) - copy-program copy-args))) - (tramp-message orig-vec 6 "%s" (string-join (process-command p) " ")) - (process-put p 'vector orig-vec) - (process-put p 'adjust-window-size-function #'ignore) - (set-process-query-on-exit-flag p nil) + (progn + (tramp-do-copy-or-rename-file-out-of-band + op filename tmpfile ok-if-already-exists keep-date) + (tramp-do-copy-or-rename-file-out-of-band + 'rename tmpfile newname ok-if-already-exists keep-date)) + ;; Save exit. + (ignore-errors + (if dir-flag + (delete-directory + (expand-file-name ".." tmpfile) 'recursive) + (delete-file tmpfile))))) + + ;; Check which ones of source and target are Tramp files. + (setq source (funcall + (if (and (string-equal (tramp-file-name-method v) "rsync") + (file-directory-p filename) + (not (file-exists-p newname))) + #'file-name-as-directory + #'identity) + (if v1 + (tramp-make-copy-program-file-name v1) + (tramp-compat-file-name-unquote filename))) + target (if v2 + (tramp-make-copy-program-file-name v2) + (tramp-compat-file-name-unquote newname))) + + ;; Check for listener port. + (when (tramp-get-method-parameter v 'tramp-remote-copy-args) + (setq listener (number-to-string (+ 50000 (random 10000)))) + (while + (zerop (tramp-call-process + v "nc" nil nil nil "-z" (tramp-file-name-host v) listener)) + (setq listener (number-to-string (+ 50000 (random 10000)))))) + + ;; Compose copy command. + (setq options + (format-spec + (tramp-ssh-controlmaster-options v) + (format-spec-make + ?t (tramp-get-connection-property + (tramp-get-connection-process v) "temp-file" ""))) + spec (list + ;; "%h" and "%u" do not happen in `tramp-copy-args' + ;; of `scp', so it is save to use `v'. + ?h (or (tramp-file-name-host v) "") + ?u (or (tramp-file-name-user v) + ;; There might be an interactive setting. + (tramp-get-connection-property v "login-as" nil) + "") + ;; For direct remote copying, the port must be the + ;; same for source and target. + ?p (or (tramp-file-name-port v) "") + ?r listener ?c options ?k (if keep-date " " "") + ?n (concat "2>" (tramp-get-remote-null-device v)) + ?x (tramp-scp-strict-file-name-checking v) + ?y (tramp-scp-direct-remote-copying v1 v2)) + copy-program (tramp-get-method-parameter v 'tramp-copy-program) + copy-keep-date (tramp-get-method-parameter + v 'tramp-copy-keep-date) + copy-args + ;; " " has either been a replacement of "%k" (when + ;; keep-date argument is non-nil), or a replacement for + ;; the whole keep-date sublist. + (delete " " (apply #'tramp-expand-args v 'tramp-copy-args spec)) + ;; `tramp-ssh-controlmaster-options' is a string instead + ;; of a list. Unflatten it. + copy-args + (tramp-compat-flatten-tree + (mapcar + (lambda (x) (if (tramp-compat-string-search " " x) + (split-string x) x)) + copy-args)) + copy-env (apply #'tramp-expand-args v 'tramp-copy-env spec) + remote-copy-program + (tramp-get-method-parameter v 'tramp-remote-copy-program) + remote-copy-args + (apply #'tramp-expand-args v 'tramp-remote-copy-args spec)) + + ;; Check for local copy program. + (unless (executable-find copy-program) + (tramp-error + v 'file-error "Cannot find local copy program: %s" copy-program)) + + ;; Install listener on the remote side. The prompt must be + ;; consumed later on, when the process does not listen anymore. + (when remote-copy-program + (unless (with-tramp-connection-property + v (concat "remote-copy-program-" remote-copy-program) + (tramp-find-executable + v remote-copy-program (tramp-get-remote-path v))) + (tramp-error + v 'file-error + "Cannot find remote listener: %s" remote-copy-program)) + (setq remote-copy-program + (mapconcat + #'identity + (append + (list remote-copy-program) remote-copy-args + (list (if v1 (concat "<" source) (concat ">" target)) "&")) + " ")) + (tramp-send-command v remote-copy-program) + (with-timeout + (60 (tramp-error + v 'file-error + "Listener process not running on remote host: `%s'" + remote-copy-program)) + (tramp-send-command v (format "netstat -l | grep -q :%s" listener)) + (while (not (tramp-send-command-and-check v nil)) + (tramp-send-command + v (format "netstat -l | grep -q :%s" listener))))) + + (with-temp-buffer + (unwind-protect + ;; The default directory must be remote. + (let ((default-directory + (file-name-directory (if v1 filename newname))) + (process-environment (copy-sequence process-environment))) + ;; Set the transfer process properties. + (tramp-set-connection-property + v "process-name" (buffer-name (current-buffer))) + (tramp-set-connection-property + v "process-buffer" (current-buffer)) + (when copy-env + (tramp-message + v 6 "%s=\"%s\"" + (car copy-env) (string-join (cdr copy-env) " ")) + (setenv (car copy-env) (string-join (cdr copy-env) " "))) + (setq + copy-args + (append + copy-args + (if remote-copy-program + (list (if v1 (concat ">" target) (concat "<" source))) + (list source target))) + ;; Use an asynchronous process. By this, password can + ;; be handled. We don't set a timeout, because the + ;; copying of large files can last longer than 60 secs. + p (let ((default-directory + tramp-compat-temporary-file-directory)) + (apply + #'start-process + (tramp-get-connection-name v) + (tramp-get-connection-buffer v) + copy-program copy-args))) + (tramp-message v 6 "%s" (string-join (process-command p) " ")) + (process-put p 'vector v) + (process-put p 'adjust-window-size-function #'ignore) + (set-process-query-on-exit-flag p nil) + + ;; We must adapt `tramp-local-end-of-line' for sending + ;; the password. Also, we indicate that perhaps several + ;; password prompts might appear. + (let ((tramp-local-end-of-line tramp-rsh-end-of-line) + (tramp-password-prompt-not-unique (and v1 v2))) + (tramp-process-actions + p v nil tramp-actions-copy-out-of-band))) + + ;; Reset the transfer process properties. + (tramp-flush-connection-property v "process-name") + (tramp-flush-connection-property v "process-buffer") + ;; Clear the remote prompt. + (when (and remote-copy-program + (not (tramp-send-command-and-check v nil))) + ;; Houston, we have a problem! Likely, the listener is + ;; still running, so let's clear everything (but the + ;; cached password). + (tramp-cleanup-connection v 'keep-debug 'keep-password)))) + + ;; Handle KEEP-DATE argument. + (when (and keep-date (not copy-keep-date)) + (tramp-compat-set-file-times + newname + (file-attribute-modification-time (file-attributes filename)) + (unless ok-if-already-exists 'nofollow))) + + ;; Set the mode. + (unless (and keep-date copy-keep-date) + (ignore-errors + (set-file-modes newname (tramp-default-file-modes filename))))) - ;; We must adapt `tramp-local-end-of-line' for - ;; sending the password. - (let ((tramp-local-end-of-line tramp-rsh-end-of-line)) - (tramp-process-actions - p v nil tramp-actions-copy-out-of-band))) - - ;; Reset the transfer process properties. - (tramp-flush-connection-property v "process-name") - (tramp-flush-connection-property v "process-buffer") - ;; Clear the remote prompt. - (when (and remote-copy-program - (not (tramp-send-command-and-check v nil))) - ;; Houston, we have a problem! Likely, the listener is - ;; still running, so let's clear everything (but the - ;; cached password). - (tramp-cleanup-connection v 'keep-debug 'keep-password)))) - - ;; Handle KEEP-DATE argument. - (when (and keep-date (not copy-keep-date)) - (tramp-compat-set-file-times - newname - (file-attribute-modification-time (file-attributes filename)) - (unless ok-if-already-exists 'nofollow))) - - ;; Set the mode. - (unless (and keep-date copy-keep-date) - (ignore-errors - (set-file-modes newname (tramp-default-file-modes filename))))) - - ;; If the operation was `rename', delete the original file. - (unless (eq op 'copy) - (if (file-regular-p filename) - (delete-file filename) - (delete-directory filename 'recursive)))))) + ;; If the operation was `rename', delete the original file. + (unless (eq op 'copy) + (if (file-regular-p filename) + (delete-file filename) + (delete-directory filename 'recursive))))) (defun tramp-sh-handle-make-directory (dir &optional parents) "Like `make-directory' for Tramp files." @@ -4806,7 +4823,7 @@ Goes through the list `tramp-inline-compress-commands'." ((stringp tramp-scp-strict-file-name-checking) tramp-scp-strict-file-name-checking) - ;; Determine the options. + ;; Determine the option. (t (setq tramp-scp-strict-file-name-checking "") (let ((case-fold-search t)) (ignore-errors @@ -4822,6 +4839,78 @@ Goes through the list `tramp-inline-compress-commands'." (setq tramp-scp-strict-file-name-checking "-T"))))))) tramp-scp-strict-file-name-checking))) +(defun tramp-scp-direct-remote-copying (vec1 vec2) + "Return the direct remote copying argument of the local scp." + (cond + ((or (not tramp-use-scp-direct-remote-copying) (null vec1) (null vec2) + (not (tramp-get-process vec1)) + (not (equal (tramp-file-name-port vec1) (tramp-file-name-port vec2))) + (null (assoc "%y" (tramp-get-method-parameter vec1 'tramp-copy-args))) + (null (assoc "%y" (tramp-get-method-parameter vec2 'tramp-copy-args)))) + "") + + ((let ((case-fold-search t)) + (and + ;; Check, whether "scp" supports "-R" option. + (with-tramp-connection-property nil "scp-R" + (when (executable-find "scp") + (with-temp-buffer + (tramp-call-process vec1 "scp" nil t nil "-R") + (goto-char (point-min)) + (not (search-forward-regexp + "\\(illegal\\|unknown\\) option -- R" nil 'noerror))))) + + ;; Check, that RemoteCommand is not used. + (with-tramp-connection-property (tramp-get-process vec1) "remote-command" + (let ((command `("ssh" "-G" ,(tramp-file-name-host vec1)))) + (with-temp-buffer + (tramp-call-process + vec1 tramp-encoding-shell nil t nil + tramp-encoding-command-switch + (mapconcat #'identity command " ")) + (goto-char (point-min)) + (not (search-forward "remotecommand" nil 'noerror))))) + + ;; Check hostkeys. + (with-tramp-connection-property + (tramp-get-process vec1) + (concat "direct-remote-copying-" + (tramp-make-tramp-file-name vec2 'noloc)) + (let ((command + (append + `("ssh" "-G" ,(tramp-file-name-host vec2) "|" + "grep" "-i" "^hostname" "|" "cut" "-d\" \"" "-f2" "|" + "ssh-keyscan" "-f" "-") + (when (tramp-file-name-port vec2) + `("-p" ,(tramp-file-name-port vec2))))) + found string) + (with-temp-buffer + ;; Check hostkey of VEC2, seen from VEC1. + (tramp-send-command vec1 (mapconcat #'identity command " ")) + ;; Check hostkey of VEC2, seen locally. + (tramp-call-process + vec1 tramp-encoding-shell nil t nil tramp-encoding-command-switch + (mapconcat #'identity command " ")) + (goto-char (point-min)) + (while (and (not found) (not (eobp))) + (setq string + (buffer-substring + (line-beginning-position) (line-end-position)) + string + (and + (string-match "^[^# ]+ \\S-+ \\(\\S-+\\)$" string) + (match-string 1 string)) + found + (and string + (with-current-buffer (tramp-get-buffer vec1) + (goto-char (point-min)) + (search-forward string nil 'noerror)))) + (forward-line)) + found))))) + "-R") + + (t "-3"))) + (defun tramp-timeout-session (vec) "Close the connection VEC after a session timeout. If there is just some editing, retry it after 5 seconds." @@ -5975,9 +6064,6 @@ function cell is returned to be applied on a buffer." ;; ;; * Use lsh instead of ssh. (Alfred M. Szmidt) ;; -;; * Optimize out-of-band copying when both methods are scp-like (not -;; rsync). -;; ;; * Keep a second connection open for out-of-band methods like scp or ;; rsync. ;; diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index b258121549d..c6e55ff6889 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el @@ -255,6 +255,8 @@ pair of the form (KEY VALUE). The following KEYs are defined: - \"%n\" expands to \"2>/dev/null\". - \"%x\" is replaced by the `tramp-scp-strict-file-name-checking' argument if it is supported. + - \"%y\" is replaced by the `tramp-scp-direct-remote-copying' + argument if it is supported. The existence of `tramp-login-args', combined with the absence of `tramp-copy-args', is an indication that the @@ -1387,6 +1389,11 @@ Will be called once the password has been verified by successful authentication.") (put 'tramp-password-save-function 'tramp-suppress-trace t) +(defvar tramp-password-prompt-not-unique nil + "Whether several passwords might be requested. +This shouldn't be set explicitly. It is let-bound, for example +during direct remote copying with scp.") + (defconst tramp-completion-file-name-handler-alist '((file-name-all-completions . tramp-completion-handle-file-name-all-completions) @@ -4751,7 +4758,9 @@ of." ;; Let's check whether a wrong password has been sent already. ;; Sometimes, the process returns a new password request ;; immediately after rejecting the previous (wrong) one. - (unless (tramp-get-connection-property vec "first-password-request" nil) + (unless (or tramp-password-prompt-not-unique + (tramp-get-connection-property + vec "first-password-request" nil)) (tramp-clear-passwd vec)) (goto-char (point-min)) (tramp-check-for-regexp proc tramp-process-action-regexp) @@ -4759,7 +4768,13 @@ of." ;; We don't call `tramp-send-string' in order to hide the ;; password from the debug buffer and the traces. (process-send-string - proc (concat (tramp-read-passwd proc) tramp-local-end-of-line)) + proc + (concat + (funcall + (if tramp-password-prompt-not-unique + #'tramp-read-passwd-without-cache #'tramp-read-passwd) + proc) + tramp-local-end-of-line)) ;; Hide password prompt. (narrow-to-region (point-max) (point-max)))) t) @@ -5705,8 +5720,7 @@ verbosity of 6." ;; tramp-cache-read-persistent-data t)'" instead. (defun tramp-read-passwd (proc &optional prompt) "Read a password from user (compat function). -Consults the auth-source package. -Invokes `password-read' if available, `read-passwd' else." +Consults the auth-source package." (let* (;; If `auth-sources' contains "~/.authinfo.gpg", and ;; `exec-path' contains a relative file name like ".", it ;; could happen that the "gpg" command is not found. So we @@ -5783,6 +5797,21 @@ Invokes `password-read' if available, `read-passwd' else." (put #'tramp-read-passwd 'tramp-suppress-trace t) +(defun tramp-read-passwd-without-cache (proc &optional prompt) + "Read a password from user (compat function)." + ;; We suspend the timers while reading the password. + (let ((stimers (with-timeout-suspend))) + (unwind-protect + (password-read + (or prompt + (with-current-buffer (process-buffer proc) + (tramp-check-for-regexp proc tramp-password-prompt-regexp) + (match-string 0)))) + ;; Reenable the timers. + (with-timeout-unsuspend stimers)))) + +(put #'tramp-read-passwd-without-cache 'tramp-suppress-trace t) + (defun tramp-clear-passwd (vec) "Clear password cache for connection related to VEC." (let ((method (tramp-file-name-method vec)) -- 2.39.5