Fix Bug#28896
* lisp/net/tramp-adb.el (tramp-adb-handle-rename-file): * lisp/net/tramp-gvfs.el (tramp-gvfs-do-copy-or-rename-file): * lisp/net/tramp-sh.el (tramp-do-copy-or-rename-file): Handle FILENAME being a directory. (Bug#28896) * test/lisp/net/tramp-tests.el (tramp-test11-copy-file) (tramp-test12-rename-file): Test also FILENAME being a directory.
This commit is contained in:
parent
d815de017b
commit
b500e06f4d
4 changed files with 304 additions and 292 deletions
|
@ -802,6 +802,11 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
|
|||
(setq filename (expand-file-name filename)
|
||||
newname (expand-file-name newname))
|
||||
|
||||
(if (file-directory-p filename)
|
||||
(progn
|
||||
(copy-directory filename newname t t)
|
||||
(delete-directory filename 'recursive))
|
||||
|
||||
(let ((t1 (tramp-tramp-file-p filename))
|
||||
(t2 (tramp-tramp-file-p newname)))
|
||||
(with-parsed-tramp-file-name (if t1 filename newname) nil
|
||||
|
@ -833,7 +838,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
|
|||
;; Rename by copy.
|
||||
(copy-file
|
||||
filename newname ok-if-already-exists 'keep-time 'preserve-uid-gid)
|
||||
(delete-file filename))))))
|
||||
(delete-file filename)))))))
|
||||
|
||||
(defun tramp-adb-handle-process-file
|
||||
(program &optional infile destination display &rest args)
|
||||
|
|
|
@ -675,6 +675,11 @@ file names."
|
|||
(unless (memq op '(copy rename))
|
||||
(error "Unknown operation `%s', must be `copy' or `rename'" op))
|
||||
|
||||
(if (file-directory-p filename)
|
||||
(progn
|
||||
(copy-directory filename newname keep-date t)
|
||||
(when (eq op 'rename) (delete-directory filename 'recursive)))
|
||||
|
||||
(let ((t1 (tramp-tramp-file-p filename))
|
||||
(t2 (tramp-tramp-file-p newname))
|
||||
(equal-remote (tramp-equal-remote filename newname))
|
||||
|
@ -738,7 +743,7 @@ file names."
|
|||
(when t2
|
||||
(with-parsed-tramp-file-name newname nil
|
||||
(tramp-flush-file-property v (file-name-directory localname))
|
||||
(tramp-flush-file-property v localname)))))))
|
||||
(tramp-flush-file-property v localname))))))))
|
||||
|
||||
(defun tramp-gvfs-handle-copy-file
|
||||
(filename newname &optional ok-if-already-exists keep-date
|
||||
|
|
|
@ -2039,6 +2039,12 @@ of `copy' and `rename'. FILENAME and NEWNAME must be absolute
|
|||
file names."
|
||||
(unless (memq op '(copy rename))
|
||||
(error "Unknown operation `%s', must be `copy' or `rename'" op))
|
||||
|
||||
(if (file-directory-p filename)
|
||||
(progn
|
||||
(copy-directory filename newname keep-date t)
|
||||
(when (eq op 'rename) (delete-directory filename 'recursive)))
|
||||
|
||||
(let ((t1 (tramp-tramp-file-p filename))
|
||||
(t2 (tramp-tramp-file-p newname))
|
||||
(length (tramp-compat-file-attribute-size
|
||||
|
@ -2128,7 +2134,7 @@ file names."
|
|||
(when t2
|
||||
(with-parsed-tramp-file-name newname v2
|
||||
(tramp-flush-file-property v2 (file-name-directory v2-localname))
|
||||
(tramp-flush-file-property v2 v2-localname)))))))
|
||||
(tramp-flush-file-property v2 v2-localname))))))))
|
||||
|
||||
(defun tramp-do-copy-or-rename-file-via-buffer (op filename newname keep-date)
|
||||
"Use an Emacs buffer to copy or rename a file.
|
||||
|
|
|
@ -1883,96 +1883,98 @@ This checks also `file-name-as-directory', `file-name-directory',
|
|||
(let (quoted)
|
||||
(let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
|
||||
(tmp-name2 (tramp--test-make-temp-name nil quoted))
|
||||
(tmp-name3 (tramp--test-make-temp-name nil quoted))
|
||||
(tmp-name4 (tramp--test-make-temp-name 'local quoted))
|
||||
(tmp-name5 (tramp--test-make-temp-name 'local quoted)))
|
||||
|
||||
;; Copy on remote side.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(copy-file tmp-name1 tmp-name2)
|
||||
(should (file-exists-p tmp-name2))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents tmp-name2)
|
||||
(should (string-equal (buffer-string) "foo")))
|
||||
(should-error
|
||||
(copy-file tmp-name1 tmp-name2)
|
||||
:type 'file-already-exists)
|
||||
(copy-file tmp-name1 tmp-name2 'ok)
|
||||
(make-directory tmp-name3)
|
||||
;; This has been changed in Emacs 26.1.
|
||||
(when (tramp--test-emacs26-p)
|
||||
(should-error
|
||||
(copy-file tmp-name1 tmp-name3)
|
||||
:type 'file-already-exists))
|
||||
(copy-file tmp-name1 (file-name-as-directory tmp-name3))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name (file-name-nondirectory tmp-name1) tmp-name3))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file tmp-name1))
|
||||
(ignore-errors (delete-file tmp-name2))
|
||||
(ignore-errors (delete-directory tmp-name3 'recursive)))
|
||||
|
||||
(tmp-name3 (tramp--test-make-temp-name 'local quoted)))
|
||||
(dolist (source-target
|
||||
`(;; Copy on remote side.
|
||||
(,tmp-name1 . ,tmp-name2)
|
||||
;; Copy from remote side to local side.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(copy-file tmp-name1 tmp-name4)
|
||||
(should (file-exists-p tmp-name4))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents tmp-name4)
|
||||
(should (string-equal (buffer-string) "foo")))
|
||||
(should-error
|
||||
(copy-file tmp-name1 tmp-name4)
|
||||
:type 'file-already-exists)
|
||||
(copy-file tmp-name1 tmp-name4 'ok)
|
||||
(make-directory tmp-name5)
|
||||
;; This has been changed in Emacs 26.1.
|
||||
(when (tramp--test-emacs26-p)
|
||||
(should-error
|
||||
(copy-file tmp-name1 tmp-name5)
|
||||
:type 'file-already-exists))
|
||||
(copy-file tmp-name1 (file-name-as-directory tmp-name5))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name (file-name-nondirectory tmp-name1) tmp-name5))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file tmp-name1))
|
||||
(ignore-errors (delete-file tmp-name4))
|
||||
(ignore-errors (delete-directory tmp-name5 'recursive)))
|
||||
|
||||
(,tmp-name1 . ,tmp-name3)
|
||||
;; Copy from local side to remote side.
|
||||
(,tmp-name3 . ,tmp-name1)))
|
||||
(let ((source (car source-target))
|
||||
(target (cdr source-target)))
|
||||
|
||||
;; Copy simple file.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil tmp-name4 nil 'nomessage)
|
||||
(copy-file tmp-name4 tmp-name1)
|
||||
(should (file-exists-p tmp-name1))
|
||||
(write-region "foo" nil source)
|
||||
(should (file-exists-p source))
|
||||
(copy-file source target)
|
||||
(should (file-exists-p target))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents tmp-name1)
|
||||
(insert-file-contents target)
|
||||
(should (string-equal (buffer-string) "foo")))
|
||||
(should-error
|
||||
(copy-file tmp-name4 tmp-name1)
|
||||
(copy-file source target)
|
||||
:type 'file-already-exists)
|
||||
(copy-file tmp-name4 tmp-name1 'ok)
|
||||
(make-directory tmp-name3)
|
||||
(copy-file source target 'ok))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file source))
|
||||
(ignore-errors (delete-file target)))
|
||||
|
||||
;; Copy file to directory.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil source)
|
||||
(should (file-exists-p source))
|
||||
(make-directory target)
|
||||
(should (file-directory-p target))
|
||||
;; This has been changed in Emacs 26.1.
|
||||
(when (tramp--test-emacs26-p)
|
||||
(should-error
|
||||
(copy-file tmp-name4 tmp-name3)
|
||||
(copy-file source target)
|
||||
:type 'file-already-exists))
|
||||
(copy-file tmp-name4 (file-name-as-directory tmp-name3))
|
||||
(copy-file source (file-name-as-directory target))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name (file-name-nondirectory tmp-name4) tmp-name3))))
|
||||
(expand-file-name (file-name-nondirectory source) target))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file tmp-name1))
|
||||
(ignore-errors (delete-file tmp-name4))
|
||||
(ignore-errors (delete-directory tmp-name3 'recursive))))))
|
||||
(ignore-errors (delete-file source))
|
||||
(ignore-errors (delete-directory target 'recursive)))
|
||||
|
||||
;; Copy directory to existing directory.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(make-directory source)
|
||||
(should (file-directory-p source))
|
||||
(write-region "foo" nil (expand-file-name "foo" source))
|
||||
(should (file-exists-p (expand-file-name "foo" source)))
|
||||
(make-directory target)
|
||||
(should (file-directory-p target))
|
||||
;; Directory `target' exists already, so we must use
|
||||
;; `file-name-as-directory'.
|
||||
(copy-file source (file-name-as-directory target))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name
|
||||
(concat (file-name-nondirectory source) "/foo") target))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-directory source 'recursive))
|
||||
(ignore-errors (delete-directory target 'recursive)))
|
||||
|
||||
;; Copy directory/file to non-existing directory.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(make-directory source)
|
||||
(should (file-directory-p source))
|
||||
(write-region "foo" nil (expand-file-name "foo" source))
|
||||
(should (file-exists-p (expand-file-name "foo" source)))
|
||||
(make-directory target)
|
||||
(should (file-directory-p target))
|
||||
(copy-file
|
||||
source
|
||||
(expand-file-name (file-name-nondirectory source) target))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name
|
||||
(concat (file-name-nondirectory source) "/foo") target))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-directory source 'recursive))
|
||||
(ignore-errors (delete-directory target 'recursive))))))))
|
||||
|
||||
(ert-deftest tramp-test12-rename-file ()
|
||||
"Check `rename-file'."
|
||||
|
@ -1983,111 +1985,105 @@ This checks also `file-name-as-directory', `file-name-directory',
|
|||
(let (quoted)
|
||||
(let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
|
||||
(tmp-name2 (tramp--test-make-temp-name nil quoted))
|
||||
(tmp-name3 (tramp--test-make-temp-name nil quoted))
|
||||
(tmp-name4 (tramp--test-make-temp-name 'local quoted))
|
||||
(tmp-name5 (tramp--test-make-temp-name 'local quoted)))
|
||||
|
||||
;; Rename on remote side.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(rename-file tmp-name1 tmp-name2)
|
||||
(should-not (file-exists-p tmp-name1))
|
||||
(should (file-exists-p tmp-name2))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents tmp-name2)
|
||||
(should (string-equal (buffer-string) "foo")))
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(should-error
|
||||
(rename-file tmp-name1 tmp-name2)
|
||||
:type 'file-already-exists)
|
||||
(rename-file tmp-name1 tmp-name2 'ok)
|
||||
(should-not (file-exists-p tmp-name1))
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(make-directory tmp-name3)
|
||||
;; This has been changed in Emacs 26.1.
|
||||
(when (tramp--test-emacs26-p)
|
||||
(should-error
|
||||
(rename-file tmp-name1 tmp-name3)
|
||||
:type 'file-already-exists))
|
||||
(rename-file tmp-name1 (file-name-as-directory tmp-name3))
|
||||
(should-not (file-exists-p tmp-name1))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name (file-name-nondirectory tmp-name1) tmp-name3))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file tmp-name1))
|
||||
(ignore-errors (delete-file tmp-name2))
|
||||
(ignore-errors (delete-directory tmp-name3 'recursive)))
|
||||
|
||||
(tmp-name3 (tramp--test-make-temp-name 'local quoted)))
|
||||
(dolist (source-target
|
||||
`(;; Rename on remote side.
|
||||
(,tmp-name1 . ,tmp-name2)
|
||||
;; Rename from remote side to local side.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(rename-file tmp-name1 tmp-name4)
|
||||
(should-not (file-exists-p tmp-name1))
|
||||
(should (file-exists-p tmp-name4))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents tmp-name4)
|
||||
(should (string-equal (buffer-string) "foo")))
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(should-error
|
||||
(rename-file tmp-name1 tmp-name4)
|
||||
:type 'file-already-exists)
|
||||
(rename-file tmp-name1 tmp-name4 'ok)
|
||||
(should-not (file-exists-p tmp-name1))
|
||||
(write-region "foo" nil tmp-name1)
|
||||
(make-directory tmp-name5)
|
||||
;; This has been changed in Emacs 26.1.
|
||||
(when (tramp--test-emacs26-p)
|
||||
(should-error
|
||||
(rename-file tmp-name1 tmp-name5)
|
||||
:type 'file-already-exists))
|
||||
(rename-file tmp-name1 (file-name-as-directory tmp-name5))
|
||||
(should-not (file-exists-p tmp-name1))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name (file-name-nondirectory tmp-name1) tmp-name5))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file tmp-name1))
|
||||
(ignore-errors (delete-file tmp-name4))
|
||||
(ignore-errors (delete-directory tmp-name5 'recursive)))
|
||||
|
||||
(,tmp-name1 . ,tmp-name3)
|
||||
;; Rename from local side to remote side.
|
||||
(,tmp-name3 . ,tmp-name1)))
|
||||
(let ((source (car source-target))
|
||||
(target (cdr source-target)))
|
||||
|
||||
;; Rename simple file.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil tmp-name4 nil 'nomessage)
|
||||
(rename-file tmp-name4 tmp-name1)
|
||||
(should-not (file-exists-p tmp-name4))
|
||||
(should (file-exists-p tmp-name1))
|
||||
(write-region "foo" nil source)
|
||||
(should (file-exists-p source))
|
||||
(rename-file source target)
|
||||
(should-not (file-exists-p source))
|
||||
(should (file-exists-p target))
|
||||
(with-temp-buffer
|
||||
(insert-file-contents tmp-name1)
|
||||
(insert-file-contents target)
|
||||
(should (string-equal (buffer-string) "foo")))
|
||||
(write-region "foo" nil tmp-name4 nil 'nomessage)
|
||||
(write-region "foo" nil source)
|
||||
(should (file-exists-p source))
|
||||
(should-error
|
||||
(rename-file tmp-name4 tmp-name1)
|
||||
(rename-file source target)
|
||||
:type 'file-already-exists)
|
||||
(rename-file tmp-name4 tmp-name1 'ok)
|
||||
(should-not (file-exists-p tmp-name4))
|
||||
(write-region "foo" nil tmp-name4 nil 'nomessage)
|
||||
(make-directory tmp-name3)
|
||||
(rename-file source target 'ok)
|
||||
(should-not (file-exists-p source)))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file source))
|
||||
(ignore-errors (delete-file target)))
|
||||
|
||||
;; Rename file to directory.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(write-region "foo" nil source)
|
||||
(should (file-exists-p source))
|
||||
(make-directory target)
|
||||
(should (file-directory-p target))
|
||||
;; This has been changed in Emacs 26.1.
|
||||
(when (tramp--test-emacs26-p)
|
||||
(should-error
|
||||
(rename-file tmp-name4 tmp-name3)
|
||||
(rename-file source target)
|
||||
:type 'file-already-exists))
|
||||
(rename-file tmp-name4 (file-name-as-directory tmp-name3))
|
||||
(should-not (file-exists-p tmp-name4))
|
||||
(rename-file source (file-name-as-directory target))
|
||||
(should-not (file-exists-p source))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name (file-name-nondirectory tmp-name4) tmp-name3))))
|
||||
(expand-file-name (file-name-nondirectory source) target))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-file tmp-name1))
|
||||
(ignore-errors (delete-file tmp-name4))
|
||||
(ignore-errors (delete-directory tmp-name3 'recursive))))))
|
||||
(ignore-errors (delete-file source))
|
||||
(ignore-errors (delete-directory target 'recursive)))
|
||||
|
||||
;; Rename directory to existing directory.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(make-directory source)
|
||||
(should (file-directory-p source))
|
||||
(write-region "foo" nil (expand-file-name "foo" source))
|
||||
(should (file-exists-p (expand-file-name "foo" source)))
|
||||
(make-directory target)
|
||||
(should (file-directory-p target))
|
||||
;; Directory `target' exists already, so we must use
|
||||
;; `file-name-as-directory'.
|
||||
(rename-file source (file-name-as-directory target))
|
||||
(should-not (file-exists-p source))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name
|
||||
(concat (file-name-nondirectory source) "/foo") target))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-directory source 'recursive))
|
||||
(ignore-errors (delete-directory target 'recursive)))
|
||||
|
||||
;; Rename directory/file to non-existing directory.
|
||||
(unwind-protect
|
||||
(progn
|
||||
(make-directory source)
|
||||
(should (file-directory-p source))
|
||||
(write-region "foo" nil (expand-file-name "foo" source))
|
||||
(should (file-exists-p (expand-file-name "foo" source)))
|
||||
(make-directory target)
|
||||
(should (file-directory-p target))
|
||||
(rename-file
|
||||
source
|
||||
(expand-file-name (file-name-nondirectory source) target))
|
||||
(should-not (file-exists-p source))
|
||||
(should
|
||||
(file-exists-p
|
||||
(expand-file-name
|
||||
(concat (file-name-nondirectory source) "/foo") target))))
|
||||
|
||||
;; Cleanup.
|
||||
(ignore-errors (delete-directory source 'recursive))
|
||||
(ignore-errors (delete-directory target 'recursive))))))))
|
||||
|
||||
(ert-deftest tramp-test13-make-directory ()
|
||||
"Check `make-directory'.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue