unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
From: Michael Albinus <michael.albinus@gmx.de>
To: Manuel Giraud <manuel@ledu-giraud.fr>
Cc: help-gnu-emacs@gnu.org, Tomas Hlavaty <tom@logand.com>,
	Tassilo Horn <tsdh@gnu.org>
Subject: Re: Dired command on same host
Date: Fri, 07 Jan 2022 16:50:00 +0100	[thread overview]
Message-ID: <87bl0n8s0n.fsf@gmx.de> (raw)
In-Reply-To: <87ee5l5drh.fsf@gmx.de> (Michael Albinus's message of "Thu, 06 Jan 2022 12:01:38 +0100")

[-- Attachment #1: Type: text/plain, Size: 1061 bytes --]

Michael Albinus <michael.albinus@gmx.de> writes:

Hi everybody,

>> ssh is able to identify the host using host keys:
>>
>> /etc/ssh/ssh_host_ed25519_key.pub
>> /etc/ssh/ssh_host_rsa_key.pub
>
> Thanks, these can be accessed via ssh-keyscan. Will use it in Tramp.

I've implemented a proof-of-concept, see appended patch to
tramp-sh.el. It is towards Emacs 29.0.50, but might also apply for Emacs
28.0.90 (for testing). After loading Tramp, there is a new user option
tramp-use-scp-direct-remote-copying which must be set to non-nil.

Direct scp copying between two remote servers shall happen then. Could
people test it? Setting tramp-verbose to 6 shall show the scp command in
the debug buffer, like in my case

--8<---------------cut here---------------start------------->8---
16:41:38.755570 tramp-do-copy-or-rename-file-out-of-band (6) # scp -p -T -R -q -r gandalf:/home/albinus/Downloads/CentOS-8.4.2105-x86_64-dvd1.iso detlef:/tmp/CentOS-8.4.2105-x86_64-dvd1.iso
--8<---------------cut here---------------end--------------->8---

Best regards, Michael.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: Type: text/x-patch, Size: 14789 bytes --]

*** /tmp/ediffuxUjdM	2022-01-07 16:33:41.019095060 +0100
--- /home/albinus/src/tramp/lisp/tramp-sh.el	2022-01-07 16:26:54.686931060 +0100
***************
*** 136,141 ****
--- 136,157 ----

  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)
+
+ (defvar tramp-scp-direct-remote-copying nil
+   "Which scp direct remote copying argument to use.
+
+ It is the string \"-R\" if supported by the local scp (since
+ release 8.7), otherwise the string \"\".  If it is nil, it will
+ be auto-detected by Tramp, if
+ `tramp-use-scp-direct-remote-copying' is non-nil..
+
+ The string is used in `tramp-methods'.")
+
  ;; Initialize `tramp-methods' with the supported methods.
  ;;;###tramp-autoload
  (tramp--with-startup
***************
*** 172,178 ****
                  (tramp-remote-shell-args    ("-c"))
                  (tramp-copy-program         "scp")
                  (tramp-copy-args            (("-P" "%p") ("-p" "%k")
! 					     ("%x") ("-q") ("-r") ("%c")))
                  (tramp-copy-keep-date       t)
                  (tramp-copy-recursive       t)))
   (add-to-list 'tramp-methods
--- 188,194 ----
                  (tramp-remote-shell-args    ("-c"))
                  (tramp-copy-program         "scp")
                  (tramp-copy-args            (("-P" "%p") ("-p" "%k")
! 					     ("%x") ("%y") ("-q") ("-r") ("%c")))
                  (tramp-copy-keep-date       t)
                  (tramp-copy-recursive       t)))
   (add-to-list 'tramp-methods
***************
*** 188,194 ****
                  (tramp-remote-shell-args    ("-c"))
                  (tramp-copy-program         "scp")
                  (tramp-copy-args            (("-P" "%p") ("-p" "%k")
! 				             ("%x") ("-q") ("-r") ("%c")))
                  (tramp-copy-keep-date       t)
                  (tramp-copy-recursive       t)))
   (add-to-list 'tramp-methods
--- 204,210 ----
                  (tramp-remote-shell-args    ("-c"))
                  (tramp-copy-program         "scp")
                  (tramp-copy-args            (("-P" "%p") ("-p" "%k")
! 				             ("%x") ("%y") ("-q") ("-r") ("%c")))
                  (tramp-copy-keep-date       t)
                  (tramp-copy-recursive       t)))
   (add-to-list 'tramp-methods
***************
*** 2241,2259 ****
      (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)))
  	 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
--- 2257,2277 ----
      (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* ((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 v1 filename newname) nil
!       (if (and v1 v2 (not (tramp-scp-direct-remote-copying-p v1 v2)))

! 	  ;; 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
***************
*** 2273,2299 ****

  	;; 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.
--- 2291,2318 ----

  	;; 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 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" (tramp-file-name-host v) listener))
  	    (setq listener (number-to-string (+ 50000 (random 10000))))))

  	;; Compose copy command.
***************
*** 2304,2313 ****
  		?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)
--- 2323,2335 ----
  		?t (tramp-get-connection-property
  		    (tramp-get-connection-process v) "temp-file" "")))
  	      spec (list
! 		    ?h (or (tramp-file-name-host v) "")
! 		    ?u (or (tramp-file-name-user v) "")
! 		    ?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 v))
  	      copy-program (tramp-get-method-parameter v 'tramp-copy-program)
  	      copy-keep-date (tramp-get-method-parameter
  			      v 'tramp-copy-keep-date)
***************
*** 2350,2356 ****
  		 #'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
--- 2372,2378 ----
  		 #'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
***************
*** 2367,2373 ****
  	  (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
--- 2389,2395 ----
  	  (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
***************
*** 2376,2382 ****
  		 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
--- 2398,2404 ----
  		 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
***************
*** 2384,2403 ****
  		 (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)

--- 2406,2426 ----
  		 (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)

***************
*** 2434,2440 ****
        (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."
--- 2457,2463 ----
        (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."
***************
*** 4824,4829 ****
--- 4847,4912 ----
  		  (setq tramp-scp-strict-file-name-checking "-T")))))))
        tramp-scp-strict-file-name-checking)))

+ (defun tramp-scp-direct-remote-copying-p (vec1 vec2)
+   "Check, whether direct remote copying between VEC1 and VEC2 is possible."
+   (and tramp-use-scp-direct-remote-copying
+        (assoc "%y" (tramp-get-method-parameter vec1 'tramp-copy-args))
+        (assoc "%y" (tramp-get-method-parameter vec2 'tramp-copy-args))
+        (with-tramp-connection-property
+ 	   (tramp-get-process vec1)
+ 	   (concat "direct-remote-copying-"
+ 		   (tramp-make-tramp-file-name vec2 'local 'hop))
+ 	 (let ((command
+ 		(if (tramp-file-name-port vec2)
+ 		    `("ssh-keyscan" ,(tramp-file-name-host vec2)
+ 		      "-p" ,(tramp-file-name-port vec2))
+ 		  `("ssh-keyscan" ,(tramp-file-name-host 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.
+ 	     (apply
+ 	      #'tramp-call-process vec1 (car command) nil t nil (cdr command))
+ 	     (goto-char (point-min))
+ 	     (while (and (not found) (not (eobp)))
+ 	       (setq string (buffer-substring
+ 			     (line-beginning-position) (line-end-position))
+ 		     found (and (not (string-match-p "^#" string))
+ 				(with-current-buffer (tramp-get-buffer vec1)
+ 				  (goto-char (point-min))
+ 				  (search-forward string nil 'noerror))))
+ 	       (forward-line))
+ 	     ;; Result.
+ 	     found)))))
+
+ (defun tramp-scp-direct-remote-copying (vec)
+   "Return the direct remote copying argument of the local scp."
+   (cond
+    ;; No options to be computed.
+    ((null (assoc "%y" (tramp-get-method-parameter vec 'tramp-copy-args)))
+     "")
+
+    ;; There is already a value to be used.
+    ((stringp tramp-scp-direct-remote-copying)
+     tramp-scp-direct-remote-copying)
+
+    ;; Determine the options.
+    (t (setq tramp-scp-direct-remote-copying "")
+       (let ((case-fold-search t))
+ 	(ignore-errors
+ 	  (when (executable-find "scp")
+ 	    (with-tramp-progress-reporter
+ 		vec 4 "Computing direct remote copying argument"
+ 	      (with-temp-buffer
+ 		(tramp-call-process vec "scp" nil t nil "-R")
+ 		(goto-char (point-min))
+ 		(unless
+                     (search-forward-regexp
+                      "\\(illegal\\|unknown\\) option -- R" nil t)
+ 		  (setq tramp-scp-strict-file-name-checking "-R")))))))
+       tramp-scp-strict-file-name-checking)))
+
  (defun tramp-timeout-session (vec)
    "Close the connection VEC after a session timeout.
  If there is just some editing, retry it after 5 seconds."
***************
*** 5977,5985 ****
  ;;
  ;; * 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.
  ;;
--- 6060,6065 ----

  reply	other threads:[~2022-01-07 15:50 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-01-04 10:24 Dired command on same host Manuel Giraud
2022-01-04 12:56 ` Michael Albinus
2022-01-04 16:25   ` Manuel Giraud
2022-01-04 18:33     ` Michael Albinus
2022-01-04 19:35       ` Tassilo Horn
2022-01-05  9:35         ` Manuel Giraud
2022-01-05 21:07           ` Tomas Hlavaty
2022-01-06 11:01             ` Michael Albinus
2022-01-07 15:50               ` Michael Albinus [this message]
2022-01-10  9:33                 ` Manuel Giraud
2022-01-10 12:56                   ` Michael Albinus
2022-01-10 14:07                     ` Manuel Giraud
2022-01-10 15:00                       ` Michael Albinus
2022-01-10 16:16                         ` Manuel Giraud
2022-01-11  8:25                           ` Michael Albinus
2022-01-11  8:59                             ` Manuel Giraud
2022-01-11  9:10                               ` Michael Albinus
2022-01-10 17:21                         ` Yuri Khan
2022-01-11  8:29                           ` Michael Albinus
2022-01-05 10:34         ` Michael Albinus
2022-01-05 13:02           ` Manuel Giraud
2022-01-05 14:37             ` Michael Albinus
2022-01-05 18:23               ` Manuel Giraud
2022-01-05  9:44       ` Manuel Giraud
2022-01-05 10:40         ` Michael Albinus
2022-01-05 11:08           ` Yuri Khan
2022-01-05 11:46             ` Michael Albinus
2022-01-05 19:55           ` Tassilo Horn

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87bl0n8s0n.fsf@gmx.de \
    --to=michael.albinus@gmx.de \
    --cc=help-gnu-emacs@gnu.org \
    --cc=manuel@ledu-giraud.fr \
    --cc=tom@logand.com \
    --cc=tsdh@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).