diff options
| author | Michael Albinus | 2020-11-03 18:47:32 +0100 |
|---|---|---|
| committer | Michael Albinus | 2020-11-03 18:47:32 +0100 |
| commit | 2fffc1dfdff0a37f826a67d90d8a97091207dcb2 (patch) | |
| tree | 2e914da389f96559132c38a54bca9cb690801c8d | |
| parent | f9d6e463d310db0e1931f26609d938531c56f9c3 (diff) | |
| download | emacs-2fffc1dfdff0a37f826a67d90d8a97091207dcb2.tar.gz emacs-2fffc1dfdff0a37f826a67d90d8a97091207dcb2.zip | |
Some Tramp fixes for directory-files-* and delete-*
* lisp/files.el (delete-directory): Simplify check for trash.
* lisp/net/ange-ftp.el (ange-ftp-delete-file): Implement TRASH.
* lisp/net/tramp-compat.el (tramp-compat-directory-files)
(tramp-compat-directory-files-and-attributes)
(tramp-compat-directory-empty-p): New defaliases.
* lisp/net/tramp.el (tramp-handle-directory-files-and-attributes)
(tramp-skeleton-delete-directory):
* lisp/net/tramp-gvfs.el (tramp-gvfs-handle-delete-directory): Use them.
* lisp/net/tramp-sh.el (tramp-sh-handle-directory-files-and-attributes):
Implement COUNT.
* test/lisp/net/tramp-tests.el (tramp-test14-delete-directory):
Do not run trash test for ange-ftp.
(tramp-test16-directory-files)
(tramp-test19-directory-files-and-attributes): Check COUNT argument.
| -rw-r--r-- | lisp/files.el | 5 | ||||
| -rw-r--r-- | lisp/net/ange-ftp.el | 118 | ||||
| -rw-r--r-- | lisp/net/tramp-compat.el | 27 | ||||
| -rw-r--r-- | lisp/net/tramp-gvfs.el | 2 | ||||
| -rw-r--r-- | lisp/net/tramp-sh.el | 3 | ||||
| -rw-r--r-- | lisp/net/tramp.el | 6 | ||||
| -rw-r--r-- | test/lisp/net/tramp-tests.el | 23 |
7 files changed, 118 insertions, 66 deletions
diff --git a/lisp/files.el b/lisp/files.el index e55552a2d9a..deb878cf418 100644 --- a/lisp/files.el +++ b/lisp/files.el | |||
| @@ -5867,10 +5867,7 @@ RECURSIVE if DIRECTORY is nonempty." | |||
| 5867 | ;; case, where the operation fails in delete-directory-internal. | 5867 | ;; case, where the operation fails in delete-directory-internal. |
| 5868 | ;; As `move-file-to-trash' trashes directories (empty or | 5868 | ;; As `move-file-to-trash' trashes directories (empty or |
| 5869 | ;; otherwise) as a unit, we do not need to recurse here. | 5869 | ;; otherwise) as a unit, we do not need to recurse here. |
| 5870 | (if (and (not recursive) | 5870 | (if (not (or recursive (directory-empty-p directory))) |
| 5871 | ;; Check if directory is empty apart from "." and "..". | ||
| 5872 | (directory-files | ||
| 5873 | directory 'full directory-files-no-dot-files-regexp)) | ||
| 5874 | (error "Directory is not empty, not moving to trash") | 5871 | (error "Directory is not empty, not moving to trash") |
| 5875 | (move-file-to-trash directory))) | 5872 | (move-file-to-trash directory))) |
| 5876 | ;; Otherwise, call ourselves recursively if needed. | 5873 | ;; Otherwise, call ourselves recursively if needed. |
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el index 15322219eff..e0c162df577 100644 --- a/lisp/net/ange-ftp.el +++ b/lisp/net/ange-ftp.el | |||
| @@ -3536,20 +3536,22 @@ system TYPE.") | |||
| 3536 | (setq file (expand-file-name file)) | 3536 | (setq file (expand-file-name file)) |
| 3537 | (let ((parsed (ange-ftp-ftp-name file))) | 3537 | (let ((parsed (ange-ftp-ftp-name file))) |
| 3538 | (if parsed | 3538 | (if parsed |
| 3539 | (let* ((host (nth 0 parsed)) | 3539 | (if (and delete-by-moving-to-trash trash) |
| 3540 | (user (nth 1 parsed)) | 3540 | (move-file-to-trash file) |
| 3541 | (name (ange-ftp-quote-string (nth 2 parsed))) | 3541 | (let* ((host (nth 0 parsed)) |
| 3542 | (abbr (ange-ftp-abbreviate-filename file)) | 3542 | (user (nth 1 parsed)) |
| 3543 | (result (ange-ftp-send-cmd host user | 3543 | (name (ange-ftp-quote-string (nth 2 parsed))) |
| 3544 | (list 'delete name) | 3544 | (abbr (ange-ftp-abbreviate-filename file)) |
| 3545 | (format "Deleting %s" abbr)))) | 3545 | (result (ange-ftp-send-cmd host user |
| 3546 | (or (car result) | 3546 | (list 'delete name) |
| 3547 | (signal 'ftp-error | 3547 | (format "Deleting %s" abbr)))) |
| 3548 | (list | 3548 | (or (car result) |
| 3549 | "Removing old name" | 3549 | (signal 'ftp-error |
| 3550 | (format "FTP Error: \"%s\"" (cdr result)) | 3550 | (list |
| 3551 | file))) | 3551 | "Removing old name" |
| 3552 | (ange-ftp-delete-file-entry file)) | 3552 | (format "FTP Error: \"%s\"" (cdr result)) |
| 3553 | file))) | ||
| 3554 | (ange-ftp-delete-file-entry file))) | ||
| 3553 | (ange-ftp-real-delete-file file trash)))) | 3555 | (ange-ftp-real-delete-file file trash)))) |
| 3554 | 3556 | ||
| 3555 | (defun ange-ftp-file-modtime (file) | 3557 | (defun ange-ftp-file-modtime (file) |
| @@ -4163,45 +4165,55 @@ directory, so that Emacs will know its current contents." | |||
| 4163 | 4165 | ||
| 4164 | (defun ange-ftp-delete-directory (dir &optional recursive trash) | 4166 | (defun ange-ftp-delete-directory (dir &optional recursive trash) |
| 4165 | (if (file-directory-p dir) | 4167 | (if (file-directory-p dir) |
| 4166 | (let ((parsed (ange-ftp-ftp-name dir))) | 4168 | ;; Trashing directories does not work yet, because |
| 4167 | (if recursive | 4169 | ;; `rename-file', called in `move-file-to-trash', does not |
| 4168 | (mapc | 4170 | ;; handle directories. |
| 4169 | (lambda (file) | 4171 | (if nil ; (and delete-by-moving-to-trash trash) |
| 4170 | (if (file-directory-p file) | 4172 | ;; Move non-empty dir to trash only if recursive deletion was |
| 4171 | (ange-ftp-delete-directory file recursive trash) | 4173 | ;; requested. |
| 4172 | (delete-file file trash))) | 4174 | (if (not (or recursive (directory-empty-p dir))) |
| 4173 | (directory-files dir 'full directory-files-no-dot-files-regexp))) | 4175 | (signal 'ftp-error |
| 4174 | (if parsed | 4176 | (list "Directory is not empty, not moving to trash")) |
| 4175 | (let* ((host (nth 0 parsed)) | 4177 | (move-file-to-trash dir)) |
| 4176 | (user (nth 1 parsed)) | 4178 | (let ((parsed (ange-ftp-ftp-name dir))) |
| 4177 | ;; Some ftp's on unix machines (at least on Suns) | 4179 | (if recursive |
| 4178 | ;; insist that rmdir take a filename, and not a | 4180 | (mapc |
| 4179 | ;; directory-name name as an arg. Argh!! This is a bug. | 4181 | (lambda (file) |
| 4180 | ;; Non-unix machines will probably always insist | 4182 | (if (file-directory-p file) |
| 4181 | ;; that rmdir takes a directory-name as an arg | 4183 | (ange-ftp-delete-directory file recursive) |
| 4182 | ;; (as the ftp man page says it should). | 4184 | (delete-file file))) |
| 4183 | (name (ange-ftp-quote-string | 4185 | (directory-files dir 'full directory-files-no-dot-files-regexp))) |
| 4184 | (if (eq (ange-ftp-host-type host) 'unix) | 4186 | (if parsed |
| 4185 | (ange-ftp-real-directory-file-name | 4187 | (let* ((host (nth 0 parsed)) |
| 4186 | (nth 2 parsed)) | 4188 | (user (nth 1 parsed)) |
| 4187 | (ange-ftp-real-file-name-as-directory | 4189 | ;; Some ftp's on unix machines (at least on Suns) |
| 4188 | (nth 2 parsed))))) | 4190 | ;; insist that rmdir take a filename, and not a |
| 4189 | (abbr (ange-ftp-abbreviate-filename dir)) | 4191 | ;; directory-name name as an arg. Argh!! This is a bug. |
| 4190 | (result | 4192 | ;; Non-unix machines will probably always insist |
| 4191 | (progn | 4193 | ;; that rmdir takes a directory-name as an arg |
| 4192 | ;; CWD must not in this directory. | 4194 | ;; (as the ftp man page says it should). |
| 4193 | (ange-ftp-cd host user "/" 'noerror) | 4195 | (name (ange-ftp-quote-string |
| 4194 | (ange-ftp-send-cmd host user | 4196 | (if (eq (ange-ftp-host-type host) 'unix) |
| 4195 | (list 'rmdir name) | 4197 | (ange-ftp-real-directory-file-name |
| 4196 | (format "Removing directory %s" | 4198 | (nth 2 parsed)) |
| 4197 | abbr))))) | 4199 | (ange-ftp-real-file-name-as-directory |
| 4198 | (or (car result) | 4200 | (nth 2 parsed))))) |
| 4199 | (ange-ftp-error host user | 4201 | (abbr (ange-ftp-abbreviate-filename dir)) |
| 4200 | (format "Could not remove directory %s: %s" | 4202 | (result |
| 4201 | dir | 4203 | (progn |
| 4202 | (cdr result)))) | 4204 | ;; CWD must not in this directory. |
| 4203 | (ange-ftp-delete-file-entry dir t)) | 4205 | (ange-ftp-cd host user "/" 'noerror) |
| 4204 | (ange-ftp-real-delete-directory dir recursive trash))) | 4206 | (ange-ftp-send-cmd host user |
| 4207 | (list 'rmdir name) | ||
| 4208 | (format "Removing directory %s" | ||
| 4209 | abbr))))) | ||
| 4210 | (or (car result) | ||
| 4211 | (ange-ftp-error host user | ||
| 4212 | (format "Could not remove directory %s: %s" | ||
| 4213 | dir | ||
| 4214 | (cdr result)))) | ||
| 4215 | (ange-ftp-delete-file-entry dir t)) | ||
| 4216 | (ange-ftp-real-delete-directory dir recursive trash)))) | ||
| 4205 | (error "Not a directory: %s" dir))) | 4217 | (error "Not a directory: %s" dir))) |
| 4206 | 4218 | ||
| 4207 | ;; Make a local copy of FILE and return its name. | 4219 | ;; Make a local copy of FILE and return its name. |
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el index c554a8d0c2d..9a4e16efe20 100644 --- a/lisp/net/tramp-compat.el +++ b/lisp/net/tramp-compat.el | |||
| @@ -309,6 +309,30 @@ A nil value for either argument stands for the current time." | |||
| 309 | (lambda (filename &optional timestamp _flag) | 309 | (lambda (filename &optional timestamp _flag) |
| 310 | (set-file-times filename timestamp)))) | 310 | (set-file-times filename timestamp)))) |
| 311 | 311 | ||
| 312 | ;; `directory-files' and `directory-files-and-attributes' got argument | ||
| 313 | ;; COUNT in Emacs 28.1. | ||
| 314 | (defalias 'tramp-compat-directory-files | ||
| 315 | (if (equal (tramp-compat-funcall 'func-arity #'directory-files) '(1 . 5)) | ||
| 316 | #'directory-files | ||
| 317 | (lambda (directory &optional full match nosort _count) | ||
| 318 | (directory-files directory full match nosort)))) | ||
| 319 | |||
| 320 | (defalias 'tramp-compat-directory-files-and-attributes | ||
| 321 | (if (equal (tramp-compat-funcall 'func-arity #'directory-files-and-attributes) | ||
| 322 | '(1 . 6)) | ||
| 323 | #'directory-files-and-attributes | ||
| 324 | (lambda (directory &optional full match nosort id-format _count) | ||
| 325 | (directory-files-and-attributes directory full match nosort id-format)))) | ||
| 326 | |||
| 327 | ;; `directory-empty-p' is new in Emacs 28.1. | ||
| 328 | (defalias 'tramp-compat-directory-empty-p | ||
| 329 | (if (fboundp 'directory-empty-p) | ||
| 330 | #'directory-empty-p | ||
| 331 | (lambda (dir) | ||
| 332 | (and (file-directory-p dir) | ||
| 333 | (null (tramp-compat-directory-files | ||
| 334 | dir nil directory-files-no-dot-files-regexp t 1)))))) | ||
| 335 | |||
| 312 | (add-hook 'tramp-unload-hook | 336 | (add-hook 'tramp-unload-hook |
| 313 | (lambda () | 337 | (lambda () |
| 314 | (unload-feature 'tramp-loaddefs 'force) | 338 | (unload-feature 'tramp-loaddefs 'force) |
| @@ -322,5 +346,8 @@ A nil value for either argument stands for the current time." | |||
| 322 | ;; | 346 | ;; |
| 323 | ;; * Starting with Emacs 27.1, there's no need to escape open | 347 | ;; * Starting with Emacs 27.1, there's no need to escape open |
| 324 | ;; parentheses with a backslash in docstrings anymore. | 348 | ;; parentheses with a backslash in docstrings anymore. |
| 349 | ;; | ||
| 350 | ;; * Starting with Emacs 27.1, there's `make-empty-file'. Could be | ||
| 351 | ;; used instead of `write-region'. | ||
| 325 | 352 | ||
| 326 | ;;; tramp-compat.el ends here | 353 | ;;; tramp-compat.el ends here |
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el index bf55777e335..86fb45a43b7 100644 --- a/lisp/net/tramp-gvfs.el +++ b/lisp/net/tramp-gvfs.el | |||
| @@ -1088,7 +1088,7 @@ file names." | |||
| 1088 | (delete-file file))) | 1088 | (delete-file file))) |
| 1089 | (directory-files | 1089 | (directory-files |
| 1090 | directory 'full directory-files-no-dot-files-regexp)) | 1090 | directory 'full directory-files-no-dot-files-regexp)) |
| 1091 | (when (directory-files directory nil directory-files-no-dot-files-regexp) | 1091 | (unless (tramp-compat-directory-empty-p directory) |
| 1092 | (tramp-error | 1092 | (tramp-error |
| 1093 | v 'file-error "Couldn't delete non-empty %s" directory))) | 1093 | v 'file-error "Couldn't delete non-empty %s" directory))) |
| 1094 | 1094 | ||
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 915ce2f6a65..655949a79b8 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el | |||
| @@ -1738,6 +1738,9 @@ ID-FORMAT valid values are `string' and `integer'." | |||
| 1738 | (setcar item (expand-file-name (car item) directory))) | 1738 | (setcar item (expand-file-name (car item) directory))) |
| 1739 | (push item result))) | 1739 | (push item result))) |
| 1740 | 1740 | ||
| 1741 | (when (natnump count) | ||
| 1742 | (setq result (last result count))) | ||
| 1743 | |||
| 1741 | (or (if nosort | 1744 | (or (if nosort |
| 1742 | result | 1745 | result |
| 1743 | (sort result (lambda (x y) (string< (car x) (car y))))) | 1746 | (sort result (lambda (x y) (string< (car x) (car y))))) |
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el index ce0a2b54ff5..1859e843758 100644 --- a/lisp/net/tramp.el +++ b/lisp/net/tramp.el | |||
| @@ -3145,7 +3145,7 @@ User is always nil." | |||
| 3145 | (lambda (x) | 3145 | (lambda (x) |
| 3146 | (cons x (file-attributes | 3146 | (cons x (file-attributes |
| 3147 | (if full x (expand-file-name x directory)) id-format))) | 3147 | (if full x (expand-file-name x directory)) id-format))) |
| 3148 | (directory-files directory full match nosort count))) | 3148 | (tramp-compat-directory-files directory full match nosort count))) |
| 3149 | 3149 | ||
| 3150 | (defun tramp-handle-dired-uncache (dir) | 3150 | (defun tramp-handle-dired-uncache (dir) |
| 3151 | "Like `dired-uncache' for Tramp files." | 3151 | "Like `dired-uncache' for Tramp files." |
| @@ -5346,9 +5346,7 @@ BODY is the backend specific code." | |||
| 5346 | (if (and delete-by-moving-to-trash ,trash) | 5346 | (if (and delete-by-moving-to-trash ,trash) |
| 5347 | ;; Move non-empty dir to trash only if recursive deletion was | 5347 | ;; Move non-empty dir to trash only if recursive deletion was |
| 5348 | ;; requested. | 5348 | ;; requested. |
| 5349 | (if (and (not ,recursive) | 5349 | (if (not (or ,recursive (tramp-compat-directory-empty-p ,directory))) |
| 5350 | (directory-files | ||
| 5351 | ,directory nil directory-files-no-dot-files-regexp)) | ||
| 5352 | (tramp-error | 5350 | (tramp-error |
| 5353 | v 'file-error "Directory is not empty, not moving to trash") | 5351 | v 'file-error "Directory is not empty, not moving to trash") |
| 5354 | (move-file-to-trash ,directory)) | 5352 | (move-file-to-trash ,directory)) |
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index 50db55ebb4f..2670723ecdc 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el | |||
| @@ -2783,8 +2783,9 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." | |||
| 2783 | (should-not (file-directory-p tmp-name1)) | 2783 | (should-not (file-directory-p tmp-name1)) |
| 2784 | 2784 | ||
| 2785 | ;; Trashing directories works only since Emacs 27.1. It doesn't | 2785 | ;; Trashing directories works only since Emacs 27.1. It doesn't |
| 2786 | ;; work for crypted remote directories. | 2786 | ;; work for crypted remote directories and for ange-ftp. |
| 2787 | (when (and (not (tramp--test-crypt-p)) (tramp--test-emacs27-p)) | 2787 | (when (and (not (tramp--test-crypt-p)) (not (tramp--test-ftp-p)) |
| 2788 | (tramp--test-emacs27-p)) | ||
| 2788 | (let ((trash-directory (tramp--test-make-temp-name 'local quoted)) | 2789 | (let ((trash-directory (tramp--test-make-temp-name 'local quoted)) |
| 2789 | (delete-by-moving-to-trash t)) | 2790 | (delete-by-moving-to-trash t)) |
| 2790 | (make-directory trash-directory) | 2791 | (make-directory trash-directory) |
| @@ -2925,7 +2926,15 @@ This tests also `file-directory-p' and `file-accessible-directory-p'." | |||
| 2925 | '("bla" "foo"))) | 2926 | '("bla" "foo"))) |
| 2926 | (should (equal (directory-files | 2927 | (should (equal (directory-files |
| 2927 | tmp-name1 'full directory-files-no-dot-files-regexp) | 2928 | tmp-name1 'full directory-files-no-dot-files-regexp) |
| 2928 | `(,tmp-name2 ,tmp-name3)))) | 2929 | `(,tmp-name2 ,tmp-name3))) |
| 2930 | ;; Check the COUNT arg. It exists since Emacs 28. | ||
| 2931 | (when (tramp--test-emacs28-p) | ||
| 2932 | (with-no-warnings | ||
| 2933 | (should | ||
| 2934 | (= 1 (length | ||
| 2935 | (directory-files | ||
| 2936 | tmp-name1 nil directory-files-no-dot-files-regexp | ||
| 2937 | nil 1))))))) | ||
| 2929 | 2938 | ||
| 2930 | ;; Cleanup. | 2939 | ;; Cleanup. |
| 2931 | (ignore-errors (delete-directory tmp-name1 'recursive)))))) | 2940 | (ignore-errors (delete-directory tmp-name1 'recursive)))))) |
| @@ -3443,7 +3452,13 @@ They might differ only in time attributes or directory size." | |||
| 3443 | (file-attributes (car elt)) (cdr elt)))) | 3452 | (file-attributes (car elt)) (cdr elt)))) |
| 3444 | 3453 | ||
| 3445 | (setq attr (directory-files-and-attributes tmp-name2 nil "\\`b")) | 3454 | (setq attr (directory-files-and-attributes tmp-name2 nil "\\`b")) |
| 3446 | (should (equal (mapcar #'car attr) '("bar" "boz")))) | 3455 | (should (equal (mapcar #'car attr) '("bar" "boz"))) |
| 3456 | |||
| 3457 | ;; Check the COUNT arg. It exists since Emacs 28. | ||
| 3458 | (when (tramp--test-emacs28-p) | ||
| 3459 | (with-no-warnings | ||
| 3460 | (should (= 1 (length (directory-files-and-attributes | ||
| 3461 | tmp-name2 nil "\\`b" nil nil 1))))))) | ||
| 3447 | 3462 | ||
| 3448 | ;; Cleanup. | 3463 | ;; Cleanup. |
| 3449 | (ignore-errors (delete-directory tmp-name1 'recursive)))))) | 3464 | (ignore-errors (delete-directory tmp-name1 'recursive)))))) |