]> git.eshelyaron.com Git - emacs.git/commitdiff
Optimize Tramp's copy-directory
authorMichael Albinus <michael.albinus@gmx.de>
Sat, 24 Aug 2024 10:49:32 +0000 (12:49 +0200)
committerEshel Yaron <me@eshelyaron.com>
Wed, 4 Sep 2024 07:51:27 +0000 (09:51 +0200)
* lisp/net/tramp-sh.el (tramp-sh-handle-copy-directory):
* lisp/net/tramp-smb.el (tramp-smb-handle-copy-directory):
Don't check existence of DIRNAME, this is done in
`tramp-skeleton-copy-directory' already.

* lisp/net/tramp-sh.el (tramp-sh-handle-copy-directory):
Apply `tramp-do-copy-or-rename-file-directly' if possible.

(cherry picked from commit 16cb27d1d986d8b00ee1da2f7f51e8e6f254f173)

lisp/net/tramp-sh.el
lisp/net/tramp-smb.el

index 9dc77cb301d9f61925ad107fa7dddb169bf5874c..61092ed8067ea7d1c30a34b94fc53a00ce5e2431 100644 (file)
@@ -2029,48 +2029,55 @@ ID-FORMAT valid values are `string' and `integer'."
          (t2 (tramp-tramp-file-p newname))
          target)
       (with-parsed-tramp-file-name (if t1 dirname newname) nil
-       (unless (file-exists-p dirname)
-         (tramp-error v 'file-missing dirname))
-
-       (if (and copy-directory-create-symlink
-                (setq target (file-symlink-p dirname))
-                (tramp-equal-remote dirname newname))
-           (make-symbolic-link
-            target
-            (if (directory-name-p newname)
-                (concat newname (file-name-nondirectory dirname)) newname)
-            t)
-
-         (if (and (not copy-contents)
-                  (tramp-get-method-parameter v 'tramp-copy-recursive)
-                  ;; When DIRNAME and NEWNAME are remote, they must
-                  ;; have the same method.
-                  (or (null t1) (null t2)
-                      (string-equal
-                       (tramp-file-name-method
-                        (tramp-dissect-file-name dirname))
-                       (tramp-file-name-method
-                        (tramp-dissect-file-name newname)))))
-             ;; scp or rsync DTRT.
-             (progn
-               (when (and (file-directory-p newname)
-                          (not (directory-name-p newname)))
-                 (tramp-error v 'file-already-exists newname))
-               (setq dirname (directory-file-name (expand-file-name dirname))
-                     newname (directory-file-name (expand-file-name newname)))
-               (when (and (file-directory-p newname)
-                          (not (string-equal (file-name-nondirectory dirname)
-                                             (file-name-nondirectory newname))))
-                 (setq newname
-                       (expand-file-name
-                        (file-name-nondirectory dirname) newname)))
-               (unless (file-directory-p (file-name-directory newname))
-                 (make-directory (file-name-directory newname) parents))
-               (tramp-do-copy-or-rename-file-out-of-band
-                'copy dirname newname 'ok-if-already-exists keep-date))
-
-           ;; We must do it file-wise.
-           (tramp-run-real-handler
+       (cond
+        ((and copy-directory-create-symlink
+              (setq target (file-symlink-p dirname))
+              (tramp-equal-remote dirname newname))
+         (make-symbolic-link
+          target
+          (if (directory-name-p newname)
+              (concat newname (file-name-nondirectory dirname)) newname)
+          t))
+
+        ;; Shortcut: if method, host, user are the same for both
+        ;; files, we invoke `cp' on the remote host directly.
+        ((and (not copy-contents)
+              (tramp-equal-remote dirname newname))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-already-exists newname))
+         (setq dirname (directory-file-name (expand-file-name dirname))
+               newname (directory-file-name (expand-file-name newname)))
+         (tramp-do-copy-or-rename-file-directly
+          'copy dirname newname
+          'ok-if-already-exists keep-date 'preserve-uid-gid))
+
+        ;; scp or rsync DTRT.
+        ((and (not copy-contents)
+              (tramp-get-method-parameter v 'tramp-copy-recursive)
+              ;; When DIRNAME and NEWNAME are remote, they must have
+              ;; the same method.
+              (or (null t1) (null t2)
+                  (string-equal
+                   (tramp-file-name-method (tramp-dissect-file-name dirname))
+                   (tramp-file-name-method (tramp-dissect-file-name newname)))))
+         (when (and (file-directory-p newname)
+                    (not (directory-name-p newname)))
+           (tramp-error v 'file-already-exists newname))
+         (setq dirname (directory-file-name (expand-file-name dirname))
+               newname (directory-file-name (expand-file-name newname)))
+         (when (and (file-directory-p newname)
+                    (not (string-equal (file-name-nondirectory dirname)
+                                       (file-name-nondirectory newname))))
+           (setq newname
+                 (expand-file-name (file-name-nondirectory dirname) newname)))
+         (unless (file-directory-p (file-name-directory newname))
+           (make-directory (file-name-directory newname) parents))
+         (tramp-do-copy-or-rename-file-out-of-band
+          'copy dirname newname 'ok-if-already-exists keep-date))
+
+        ;; We must do it file-wise.
+        (t (tramp-run-real-handler
             #'copy-directory
             (list dirname newname keep-date parents copy-contents))))
 
index da62773ccc64d748ce7cac8f920f78a73cbae128..2699dc130433a6498bf836c73ecfd3f4df06bff3 100644 (file)
@@ -428,9 +428,6 @@ arguments to pass to the OPERATION."
          (t2 (tramp-tramp-file-p newname))
          target)
       (with-parsed-tramp-file-name (if t1 dirname newname) nil
-       (unless (file-exists-p dirname)
-         (tramp-error v 'file-missing dirname))
-
        (if (and copy-directory-create-symlink
                 (setq target (file-symlink-p dirname))
                 (tramp-equal-remote dirname newname))