*** /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 ----