2398 |
(when (file-exists-p newname) |
(when (file-exists-p newname) |
2399 |
(signal 'file-already-exists |
(signal 'file-already-exists |
2400 |
(list newname)))) |
(list newname)))) |
2401 |
(with-parsed-tramp-file-name filename v1 |
(let ((t1 (tramp-tramp-file-p filename)) |
2402 |
(with-parsed-tramp-file-name newname v2 |
(t2 (tramp-tramp-file-p newname))) |
2403 |
(when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method) |
;; Check which ones of source and target are Tramp files. |
2404 |
(tramp-ange-ftp-file-name-p v2-multi-method v2-method)) |
(cond |
2405 |
(tramp-invoke-ange-ftp |
((and t1 t2) |
2406 |
(if (eq op 'copy) 'copy-file 'rename-file) |
;; Both are Tramp files. |
2407 |
filename newname ok-if-already-exists keep-date)) |
(with-parsed-tramp-file-name filename v1 |
2408 |
(let* ((mmeth (tramp-file-name-multi-method (or v1 v2))) |
(with-parsed-tramp-file-name newname v2 |
2409 |
(meth (tramp-file-name-method (or v1 v2))) |
;; Possibly invoke Ange-FTP. |
2410 |
(rcp-program (tramp-get-rcp-program mmeth meth)) |
(when (and (tramp-ange-ftp-file-name-p v1-multi-method v1-method) |
2411 |
(rcp-args (tramp-get-rcp-args mmeth meth)) |
(tramp-ange-ftp-file-name-p v2-multi-method v2-method)) |
2412 |
(trampbuf (get-buffer-create "*tramp output*"))) |
(tramp-invoke-ange-ftp |
2413 |
;; Check if we can use a shortcut. |
(if (eq op 'copy) 'copy-file 'rename-file) |
2414 |
(if (and v1-method v2-method |
filename newname ok-if-already-exists keep-date)) |
2415 |
(equal v1-multi-method v2-multi-method) |
;; Check if we can use a shortcut. |
2416 |
(equal v1-method v2-method) |
(if (and (equal v1-multi-method v2-multi-method) |
2417 |
(equal v1-host v2-host) |
(equal v1-method v2-method) |
2418 |
(equal v1-user v2-user)) |
(equal v1-host v2-host) |
2419 |
;; Shortcut: if method, host, user are the same for both |
(equal v1-user v2-user)) |
2420 |
;; files, we invoke `cp' or `mv' on the remote host directly. |
;; Shortcut: if method, host, user are the same for both |
2421 |
(tramp-do-copy-or-rename-file-directly |
;; files, we invoke `cp' or `mv' on the remote host |
2422 |
op |
;; directly. |
2423 |
v1-multi-method v1-method v1-user v1-host v1-path v2-path |
(tramp-do-copy-or-rename-file-directly |
2424 |
keep-date) |
op v1-multi-method v1-method v1-user v1-host |
2425 |
;; New algorithm: copy file first. Then, if operation is |
v1-path v2-path keep-date) |
2426 |
;; `rename', go back and delete the original file if the copy |
;; The shortcut was not possible. So we copy the |
2427 |
;; was successful. |
;; file first. If the operation was `rename', we go |
2428 |
(if rcp-program |
;; back and delete the original file (if the copy was |
2429 |
;; The following code uses a tramp program to copy the file. |
;; successful). The approach is simple-minded: we |
2430 |
(let ((f1 (if (not v1) |
;; create a new buffer, insert the contents of the |
2431 |
filename |
;; source file into it, then write out the buffer to |
2432 |
(tramp-make-rcp-program-file-name |
;; the target file. The advantage is that it doesn't |
2433 |
v1-user v1-host |
;; matter which filename handlers are used for the |
2434 |
(tramp-shell-quote-argument v1-path)))) |
;; source and target file. |
|
(f2 (if (not v2) |
|
|
newname |
|
|
(tramp-make-rcp-program-file-name |
|
|
v2-user v2-host |
|
|
(tramp-shell-quote-argument v2-path)))) |
|
|
(default-directory |
|
|
(if (tramp-tramp-file-p default-directory) |
|
|
(tramp-temporary-file-directory) |
|
|
default-directory))) |
|
|
(when keep-date |
|
|
(add-to-list 'rcp-args |
|
|
(tramp-get-rcp-keep-date-arg mmeth meth))) |
|
|
(save-excursion (set-buffer trampbuf) (erase-buffer)) |
|
|
(unless (equal 0 (apply #'call-process |
|
|
(tramp-get-rcp-program mmeth meth) |
|
|
nil trampbuf nil |
|
|
(append rcp-args (list f1 f2)))) |
|
|
(pop-to-buffer trampbuf) |
|
|
(error (concat "tramp-do-copy-or-rename-file: %s" |
|
|
" didn't work, see buffer `%s' for details") |
|
|
(tramp-get-rcp-program mmeth meth) trampbuf))) |
|
|
;; The following code uses an inline method for copying. |
|
|
;; Let's start with a simple-minded approach: we create a new |
|
|
;; buffer, insert the contents of the source file into it, |
|
|
;; then write out the buffer. This should work fine, whether |
|
|
;; the source or the target files are tramp files. |
|
|
;; CCC TODO: error checking |
|
|
(when keep-date |
|
|
(tramp-message |
|
|
1 (concat "Warning: cannot preserve file time stamp" |
|
|
" with inline copying across machines"))) |
|
|
(save-excursion |
|
|
(set-buffer trampbuf) (erase-buffer) |
|
|
(insert-file-contents-literally filename) |
|
|
(let ((coding-system-for-write 'no-conversion)) |
|
|
(write-region (point-min) (point-max) newname)))) |
|
2435 |
|
|
2436 |
;; If the operation was `rename', delete the original file. |
;; CCC: If both source and target are Tramp files, |
2437 |
(unless (eq op 'copy) |
;; and both are using the same rcp-program, then we |
2438 |
(delete-file filename))))))) |
;; can invoke rcp directly. Note that |
2439 |
|
;; default-directory should point to a local |
2440 |
|
;; directory if we want to invoke rcp. |
2441 |
|
(tramp-do-copy-or-rename-via-buffer |
2442 |
|
op filename newname keep-date trampbuf))))) |
2443 |
|
((or t1 t2) |
2444 |
|
;; Use the generic method via a Tramp buffer. |
2445 |
|
(tramp-do-copy-or-rename-via-buffer |
2446 |
|
op filename newname keep-date trampbuf)) |
2447 |
|
(t |
2448 |
|
;; One of them must be a Tramp file. |
2449 |
|
(error "Tramp implementation says this cannot happen"))))) |
2450 |
|
|
2451 |
|
(defun tramp-do-copy-or-rename-via-buffer |
2452 |
|
(op filename newname keep-date) |
2453 |
|
"Use an Emacs buffer to copy or rename a file. |
2454 |
|
First arg OP is either `copy' or `rename' and indicates the operation. |
2455 |
|
FILENAME is the source file, NEWNAME the target file. |
2456 |
|
KEEP-DATE is non-nil if NEWNAME should have the same timestamp as FILENAME." |
2457 |
|
(let ((trampbuf (get-buffer-create "*tramp output*"))) |
2458 |
|
(when keep-date |
2459 |
|
(tramp-message |
2460 |
|
1 (concat "Warning: cannot preserve file time stamp" |
2461 |
|
" with inline copying across machines"))) |
2462 |
|
(save-excursion |
2463 |
|
(set-buffer trampbuf) (erase-buffer) |
2464 |
|
(insert-file-contents-literally filename) |
2465 |
|
(let ((coding-system-for-write 'no-conversion)) |
2466 |
|
(write-region (point-min) (point-max) newname))) |
2467 |
|
;; If the operation was `rename', delete the original file. |
2468 |
|
(unless (eq op 'copy) |
2469 |
|
(delete-file filename)))) |
2470 |
|
|
2471 |
(defun tramp-do-copy-or-rename-file-directly |
(defun tramp-do-copy-or-rename-file-directly |
2472 |
(op multi-method method user host path1 path2 keep-date) |
(op multi-method method user host path1 path2 keep-date) |