emacs-31 bcb83d7d2ad 2/3: Fix error handling in Tramp delete-{file, directory}

Michael Albinus via Mailing list for Emacs changes <[email protected]> Wed, 1 Jul 2026 11:01:54 -0400 (EDT)
Newsgroups gmane.emacs.diffs
Message-ID <[email protected]>
branch: emacs-31
commit bcb83d7d2ad1d34a6683fc466654437b1e25ad16
Author: Michael Albinus <[email protected]>
Commit: Michael Albinus <[email protected]>

    Fix error handling in Tramp delete-{file,directory}
    
    * lisp/net/tramp-smb.el (tramp-smb-handle-delete-directory):
    * lisp/net/tramp.el (tramp-skeleton-delete-directory): Fail if
    DIRECTORY is missing.
    (tramp-skeleton-delete-file): Don't fail if DIRECTORY is missing.
    
    * test/lisp/net/tramp-tests.el (tramp-test14-delete-directory):
    Adapt test.
---
 lisp/net/tramp-smb.el        | 57 ++++++++++++++++++++++----------------------
 lisp/net/tramp.el            | 24 ++++++++++---------
 test/lisp/net/tramp-tests.el | 10 ++++++++
 3 files changed, 51 insertions(+), 40 deletions(-)

diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index ac54e47e376..6f88c7dedba 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -651,36 +651,35 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are completely ignored."
 (defun tramp-smb-handle-delete-directory (directory &optional recursive trash)
   "Like `delete-directory' for Tramp files."
   (tramp-skeleton-delete-directory directory recursive trash
-    (when (file-exists-p directory)
-      (when recursive
-	(mapc
-	 (lambda (file)
-	   (if (file-directory-p file)
-	       (delete-directory file recursive)
-	     (delete-file file)))
-	 ;; We do not want to delete "." and "..".
-	 (directory-files directory 'full directory-files-no-dot-files-regexp)))
+    (when recursive
+      (mapc
+       (lambda (file)
+	 (if (file-directory-p file)
+	     (delete-directory file recursive)
+	   (delete-file file)))
+       ;; We do not want to delete "." and "..".
+       (directory-files directory 'full directory-files-no-dot-files-regexp)))
+
+    ;; We must also flush the cache of the directory, because
+    ;; `file-attributes' reads the values from there.
+    (tramp-flush-directory-properties v localname)
+    (unless (tramp-smb-send-command
+	     v (format
+		"%s %s"
+		(if (tramp-smb-get-cifs-capabilities v)
+		    "posix_rmdir" "rmdir")
+		(tramp-smb-shell-quote-localname v)))
+      ;; Error.
+      (with-current-buffer (tramp-get-connection-buffer v)
+	(goto-char (point-min))
+	(search-forward-regexp tramp-smb-errors nil t)
+	(tramp-error v 'file-error "%s `%s'" (match-string 0) directory)))
 
-      ;; We must also flush the cache of the directory, because
-      ;; `file-attributes' reads the values from there.
-      (tramp-flush-directory-properties v localname)
-      (unless (tramp-smb-send-command
-	       v (format
-		  "%s %s"
-		  (if (tramp-smb-get-cifs-capabilities v)
-		      "posix_rmdir" "rmdir")
-		  (tramp-smb-shell-quote-localname v)))
-	;; Error.
-	(with-current-buffer (tramp-get-connection-buffer v)
-	  (goto-char (point-min))
-	  (search-forward-regexp tramp-smb-errors nil t)
-	  (tramp-error v 'file-error "%s `%s'" (match-string 0) directory)))
-
-      ;; "rmdir" does not report an error.  So we check ourselves.
-      ;; Deletion of a watched directory could be pending.
-      (when (and (not (tramp-directory-watched directory))
-		 (file-exists-p directory))
-        (tramp-error v 'file-error "`%s' not removed" directory)))))
+    ;; "rmdir" does not report an error.  So we check ourselves.
+    ;; Deletion of a watched directory could be pending.
+    (when (and (not (tramp-directory-watched directory))
+	       (file-exists-p directory))
+      (tramp-error v 'file-error "`%s' not removed" directory))))
 
 (defun tramp-smb-handle-delete-file (filename &optional trash)
   "Like `delete-file' for Tramp files."
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index c5ecbdd9675..78e1d34ebab 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -3734,14 +3734,15 @@ BODY is the backend specific code."
 		 ;; This variable exists since Emacs 30.1.
 		 (not (bound-and-true-p
 		       remote-file-name-inhibit-delete-by-moving-to-trash)))))
-       (if (and delete-by-moving-to-trash ,trash)
-	   ;; Move non-empty dir to trash only if recursive deletion was
-	   ;; requested.
-	   (if (not (or ,recursive (directory-empty-p ,directory)))
-	       (tramp-error
-		v 'file-error "Directory is not empty, not moving to trash")
-	     (move-file-to-trash ,directory))
-	 ,@body)
+       (tramp-barf-if-file-missing v ,directory
+	 (if (and delete-by-moving-to-trash ,trash)
+	     ;; Move non-empty dir to trash only if recursive deletion was
+	     ;; requested.
+	     (if (not (or ,recursive (directory-empty-p ,directory)))
+		 (tramp-error
+		  v 'file-error "Directory is not empty, not moving to trash")
+	       (move-file-to-trash ,directory))
+	   ,@body))
        (tramp-flush-directory-properties v localname))))
 
 (defmacro tramp-skeleton-delete-file (filename &optional trash &rest body)
@@ -3754,9 +3755,10 @@ BODY is the backend specific code."
 		 ;; This variable exists since Emacs 30.1.
 		 (not (bound-and-true-p
 		       remote-file-name-inhibit-delete-by-moving-to-trash)))))
-       (if (and delete-by-moving-to-trash ,trash)
-	   (move-file-to-trash ,filename)
-	 ,@body)
+       (ignore-errors
+	 (if (and delete-by-moving-to-trash ,trash)
+	     (move-file-to-trash ,filename)
+	   ,@body))
        (tramp-flush-file-properties v localname))))
 
 (defmacro tramp-skeleton-directory-files
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index b622a08dce3..6badf064efe 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -3322,6 +3322,16 @@ This tests also `file-directory-p' and `file-accessible-directory-p'."
   (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil)))
     (let* ((tmp-name1 (tramp--test-make-temp-name nil quoted))
 	   (tmp-name2 (expand-file-name "foo" tmp-name1)))
+      ;; Deleting a non-existing file should not fail.
+      (delete-file tmp-name1)
+      (delete-file tmp-name1 'trash)
+      ;; Deleting a non-existing directory should fail.
+      (should-error
+       (delete-directory tmp-name1)
+       :type 'file-missing)
+      (should-error
+       (delete-directory tmp-name1 nil 'trash)
+       :type 'file-missing)
       ;; Delete empty directory.
       (make-directory tmp-name1)
       (should (file-directory-p tmp-name1))