branch: externals/tramp
commit 382d8b1ed71eb3e4684d6db3aa69c3023e71ced5
Author: Michael Albinus <[email protected]>
Commit: Michael Albinus <[email protected]>

    Tramp ELPA version 2.8.0.4 released
---
 README                      |   6 +--
 test/Makefile               |   5 ++-
 test/README                 |   3 ++
 test/resources/foo.iso/foo  |   1 +
 test/resources/foo.tar.gz   | Bin 0 -> 274 bytes
 test/resources/foo.zip      | Bin 0 -> 444 bytes
 test/tramp-archive-tests.el |  91 ++++++++++++++++++++++++++++++++++++++------
 test/tramp-tests.el         |  30 +++++++++++----
 texi/tramp.texi             |  21 +++++++++-
 texi/trampver.texi          |   2 +-
 tramp-archive.el            |  11 +++---
 tramp-cache.el              |  28 +++++++-------
 tramp-cmds.el               |  28 +++++++++++---
 tramp-compat.el             |   3 ++
 tramp-gvfs.el               |   5 ++-
 tramp-message.el            |   1 -
 tramp-sh.el                 |  59 +++++++++++++++++++++++-----
 tramp.el                    |  59 ++++++++++++++++------------
 trampver.el                 |   6 +--
 19 files changed, 269 insertions(+), 90 deletions(-)

diff --git a/README b/README
index 5720b4415f..ee0e398298 100644
--- a/README
+++ b/README
@@ -32,11 +32,11 @@ Emacs 28 or older
 
    • Remove all byte-compiled Tramp files
 
-          $ rm -f ~/.emacs.d/elpa/tramp-2.8.0.3/tramp*.elc
+          $ rm -f ~/.emacs.d/elpa/tramp-2.8.0.4/tramp*.elc
 
    • Start Emacs with Tramp's source files
 
-          $ emacs -L ~/.emacs.d/elpa/tramp-2.8.0.3 -l tramp
+          $ emacs -L ~/.emacs.d/elpa/tramp-2.8.0.4 -l tramp
 
      This should not give you the error.
 
@@ -50,7 +50,7 @@ Mitigation of a bug in Emacs 29.1
 ---------------------------------
 
 Due to a bug in Emacs 29.1, you must apply the following change prior
-installation or upgrading Tramp 2.8.0.3 from GNU ELPA:
+installation or upgrading Tramp 2.8.0.4 from GNU ELPA:
 
      (when (string-equal emacs-version "29.1")
        (with-current-buffer
diff --git a/test/Makefile b/test/Makefile
index d41f3a9695..b4f0064233 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -23,7 +23,7 @@
 
 EMACS          = emacs -Q -batch -L ../
 CLEAN_FILES    = .\\\#* \\\#* .*~ *~ *.elc *.log
-TESTS          = tramp-tests
+TESTS          = tramp-tests tramp-archive-tests
 SOURCE_DIR     = ~/src/tramp
 
 TRAMP_TEST_ARGS ?=
@@ -57,3 +57,6 @@ sync:
        cp -p $(SOURCE_DIR)/test/README README
        cp -p $(SOURCE_DIR)/test/tramp-archive-tests.el tramp-archive-tests.el
        cp -p $(SOURCE_DIR)/test/tramp-tests.el tramp-tests.el
+       cp -p $(SOURCE_DIR)/test/resources/foo.iso/foo resources/foo.iso/foo
+       cp -p $(SOURCE_DIR)/test/resources/foo.tar.gz resources/foo.tar.gz
+       cp -p $(SOURCE_DIR)/test/resources/foo.zip resources/foo.zip
diff --git a/test/README b/test/README
index 9b9a437d6a..4a87719fa7 100644
--- a/test/README
+++ b/test/README
@@ -35,6 +35,9 @@ tramp-time.el (not on GNU ELPA)
         These are performance tests on Tramp.  Read the "Commentary"
         section for details.  These tests are not covered by the Makefile.
 
+resources/
+       A directory containing test files.
+
 The Makefile in this directory supports the following targets:
 
 * make all  -or-  make check
diff --git a/test/resources/foo.iso/foo b/test/resources/foo.iso/foo
new file mode 100644
index 0000000000..257cc5642c
--- /dev/null
+++ b/test/resources/foo.iso/foo
@@ -0,0 +1 @@
+foo
diff --git a/test/resources/foo.tar.gz b/test/resources/foo.tar.gz
new file mode 100644
index 0000000000..0d2e9878dd
Binary files /dev/null and b/test/resources/foo.tar.gz differ
diff --git a/test/resources/foo.zip b/test/resources/foo.zip
new file mode 100644
index 0000000000..deda1013eb
Binary files /dev/null and b/test/resources/foo.zip differ
diff --git a/test/tramp-archive-tests.el b/test/tramp-archive-tests.el
index 33dc0b9d4a..5e9ea756b9 100644
--- a/test/tramp-archive-tests.el
+++ b/test/tramp-archive-tests.el
@@ -36,12 +36,6 @@
 (defvar tramp-archive-test-file-archive (ert-resource-file "foo.tar.gz")
   "The test file archive.")
 
-(defun tramp-archive-test-file-archive-hexlified ()
-    "Return hexlified `tramp-archive-test-file-archive'.
-Do not hexlify \"/\".  This hexlified string is used in `file:///' URLs."
-  (let* ((url-unreserved-chars (cons ?/ url-unreserved-chars)))
-    (url-hexify-string tramp-archive-test-file-archive)))
-
 (defvar tramp-archive-test-archive
   (file-name-as-directory tramp-archive-test-file-archive)
   "The test archive.")
@@ -50,11 +44,28 @@ Do not hexlify \"/\".  This hexlified string is used in 
`file:///' URLs."
   (file-truename (ert-resource-file "foo.iso"))
   "A directory file name, which looks like an archive.")
 
+(defvar tramp-archive-test-cascaded-file-archive
+  (ert-resource-file "foo.zip/foo.tar.gz")
+  "The cascaded test file archive.")
+
+(defvar tramp-archive-test-cascaded-archive
+  (file-name-as-directory tramp-archive-test-cascaded-file-archive)
+  "The cascaded test archive.")
+
+(defun tramp-archive-test-file-archive-hexlified ()
+    "Return hexlified `tramp-archive-test-file-archive'.
+Do not hexlify \"/\".  This hexlified string is used in `file:///' URLs."
+  (let* ((url-unreserved-chars (cons ?/ url-unreserved-chars)))
+    (url-hexify-string tramp-archive-test-file-archive)))
+
 (setq password-cache-expiry nil
       tramp-cache-read-persistent-data t ;; For auth-sources.
       tramp-persistency-file-name nil
       tramp-verbose 0)
 
+(defvar tramp-archive-test-cascaded nil
+  "Indicator, whether we are testing a cascaded archive.")
+
 (defun tramp-archive--test-make-temp-name ()
   "Return a temporary file name for test.
 The temporary file is not created."
@@ -86,9 +97,29 @@ the origin of the temporary TMPFILE, have no write 
permissions."
     (file-exists-p tramp-archive-test-file-archive)
     (tramp-archive-file-name-p tramp-archive-test-archive))))
 
+;; These tests are inspired by Bug#79582.
+(defmacro tramp-archive--test-deftest-cascaded (test)
+  "Define ert `TEST-cascaded'."
+  (declare (indent 1))
+  `(ert-deftest ,(intern (concat (symbol-name test) "-cascaded")) ()
+     :tags '(:expensive-test)
+     ;(tramp--test-set-ert-test-documentation ',test "cascaded")
+     (skip-unless tramp-archive-enabled)
+     (if-let* ((ert-test (ert-get-test ',test))
+              (result (ert-test-most-recent-result ert-test))
+              (tramp-archive-test-file-archive
+               tramp-archive-test-cascaded-file-archive)
+              (tramp-archive-test-archive tramp-archive-test-cascaded-archive)
+              (tramp-archive-test-cascaded t))
+        (progn
+          (skip-unless (< (ert-test-result-duration result) 300))
+          (funcall (ert-test-body ert-test)))
+       (ert-skip (format "Test `%s' must run before" ',test)))))
+
 (ert-deftest tramp-archive-test01-file-name-syntax ()
   "Check archive file name syntax."
-  (should-not (tramp-archive-file-name-p tramp-archive-test-file-archive))
+  (unless tramp-archive-test-cascaded
+    (should-not (tramp-archive-file-name-p tramp-archive-test-file-archive)))
   (should (tramp-archive-file-name-p tramp-archive-test-archive))
   (should
    (string-equal
@@ -136,6 +167,8 @@ the origin of the temporary TMPFILE, have no write 
permissions."
      (concat tramp-archive-test-archive "baz.tar/"))
     "/")))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test01-file-name-syntax)
+
 (ert-deftest tramp-archive-test02-file-name-dissect ()
   "Check archive file name components."
   (skip-unless tramp-archive-enabled)
@@ -250,10 +283,13 @@ the origin of the temporary TMPFILE, have no write 
permissions."
    (string-equal
     (expand-file-name (concat tramp-archive-test-archive "./file"))
     (concat tramp-archive-test-archive "file")))
-  (should
-   (string-equal
-    (expand-file-name (concat tramp-archive-test-archive "../file"))
-    (concat (ert-resource-directory) "file"))))
+  (unless tramp-archive-test-cascaded
+    (should
+     (string-equal
+      (expand-file-name (concat tramp-archive-test-archive "../file"))
+      (concat (ert-resource-directory) "file")))))
+
+(tramp-archive--test-deftest-cascaded tramp-archive-test05-expand-file-name)
 
 ;; This test is inspired by Bug#30293.
 (ert-deftest tramp-archive-test05-expand-file-name-non-archive-directory ()
@@ -332,6 +368,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
    (unhandled-file-name-directory
     (concat tramp-archive-test-archive "path/to/file"))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test06-directory-file-name)
+
 (ert-deftest tramp-archive-test07-file-exists-p ()
   "Check `file-exist-p', `write-region' and `delete-file'."
   :tags '(:expensive-test)
@@ -355,6 +393,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
     ;; Cleanup.
     (tramp-archive-cleanup-hash)))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test07-file-exists-p)
+
 (ert-deftest tramp-archive-test08-file-local-copy ()
   "Check `file-local-copy'."
   :tags '(:expensive-test)
@@ -382,6 +422,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
       (ignore-errors (tramp-archive--test-delete tmp-name))
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test08-file-local-copy)
+
 (ert-deftest tramp-archive-test09-insert-file-contents ()
   "Check `insert-file-contents'."
   :tags '(:expensive-test)
@@ -409,6 +451,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
        ;; Cleanup.
        (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded 
tramp-archive-test09-insert-file-contents)
+
 (ert-deftest tramp-archive-test11-copy-file ()
   "Check `copy-file'."
   :tags '(:expensive-test)
@@ -475,6 +519,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
       (ignore-errors (tramp-archive--test-delete tmp-name2))
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test11-copy-file)
+
 (ert-deftest tramp-archive-test15-copy-directory ()
   "Check `copy-directory'."
   :tags '(:expensive-test)
@@ -528,6 +574,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
       (ignore-errors (tramp-archive--test-delete tmp-name2))
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test15-copy-directory)
+
 (ert-deftest tramp-archive-test16-directory-files ()
   "Check `directory-files'."
   :tags '(:expensive-test)
@@ -552,6 +600,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
       ;; Cleanup.
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test16-directory-files)
+
 (ert-deftest tramp-archive-test17-insert-directory ()
   "Check `insert-directory'."
   :tags '(:expensive-test)
@@ -600,6 +650,8 @@ This checks also `file-name-as-directory', 
`file-name-directory',
       ;; Cleanup.
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test17-insert-directory)
+
 (ert-deftest tramp-archive-test18-file-attributes ()
   "Check `file-attributes'.
 This tests also `access-file', `file-readable-p' and `file-regular-p'."
@@ -661,6 +713,8 @@ This tests also `access-file', `file-readable-p' and 
`file-regular-p'."
       ;; Cleanup.
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test18-file-attributes)
+
 (ert-deftest tramp-archive-test19-directory-files-and-attributes ()
   "Check `directory-files-and-attributes'."
   :tags '(:expensive-test)
@@ -686,6 +740,9 @@ This tests also `access-file', `file-readable-p' and 
`file-regular-p'."
       ;; Cleanup.
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded
+ tramp-archive-test19-directory-files-and-attributes)
+
 (ert-deftest tramp-archive-test20-file-modes ()
   "Check `file-modes'.
 This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
@@ -717,6 +774,8 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
       ;; Cleanup.
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test20-file-modes)
+
 (ert-deftest tramp-archive-test21-file-links ()
   "Check `file-symlink-p' and `file-truename'"
   :tags '(:expensive-test)
@@ -758,6 +817,8 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
       ;; Cleanup.
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test21-file-links)
+
 (ert-deftest tramp-archive-test26-file-name-completion ()
   "Check `file-name-completion' and `file-name-all-completions'."
   :tags '(:expensive-test)
@@ -797,6 +858,8 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
       ;; Cleanup.
       (tramp-archive-cleanup-hash))))
 
+(tramp-archive--test-deftest-cascaded 
tramp-archive-test26-file-name-completion)
+
 (ert-deftest tramp-archive-test40-make-nearby-temp-file ()
   "Check `make-nearby-temp-file' and `temporary-file-directory'."
   (skip-unless tramp-archive-enabled)
@@ -824,6 +887,8 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
     (delete-directory tmp-file)
     (should-not (file-exists-p tmp-file))))
 
+(tramp-archive--test-deftest-cascaded 
tramp-archive-test40-make-nearby-temp-file)
+
 (ert-deftest tramp-archive-test43-file-system-info ()
   "Check that `file-system-info' returns proper values."
   (skip-unless tramp-archive-enabled)
@@ -837,6 +902,8 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
                 (zerop (nth 1 fsi))
                 (zerop (nth 2 fsi))))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test43-file-system-info)
+
 ;; `file-user-uid' and `file-group-gid' were introduced in Emacs 30.1.
 (ert-deftest tramp-archive-test44-user-group-ids ()
   "Check results of user/group functions.
@@ -856,6 +923,8 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
       (should (equal uid (with-no-warnings (file-user-uid))))
       (should (equal gid (with-no-warnings (file-group-gid)))))))
 
+(tramp-archive--test-deftest-cascaded tramp-archive-test44-user-group-ids)
+
 (ert-deftest tramp-archive-test50-auto-load ()
   "Check that `tramp-archive' autoloads properly."
   :tags '(:expensive-test)
diff --git a/test/tramp-tests.el b/test/tramp-tests.el
index 3432e6eb70..7099a614a4 100644
--- a/test/tramp-tests.el
+++ b/test/tramp-tests.el
@@ -181,8 +181,11 @@ The temporary file is not created."
   `(condition-case err
        (progn ,@body)
      (file-error
-      (unless (string-equal (error-message-string err)
-                           "make-symbolic-link not supported")
+      (unless (string-match-p
+              (rx bol (| "make-symbolic-link not supported"
+                         (: "Making symbolic link"
+                            (? ":") " Operation not permitted")))
+              (error-message-string err))
        (signal (car err) (cdr err))))))
 
 ;; Don't print messages in nested `tramp--test-instrument-test-case' calls.
@@ -8540,8 +8543,7 @@ process sentinels.  They shall not disturb each other."
 (ert-deftest tramp-test48-session-timeout ()
   "Check that Tramp handles a session timeout properly."
   (skip-unless (tramp--test-enabled))
-  (skip-unless
-   (tramp-get-method-parameter tramp-test-vec 'tramp-session-timeout))
+  (skip-unless (tramp--test-sh-p))
 
   ;; We want to see the timeout message.
   (tramp--test-instrument-test-case 3
@@ -8668,11 +8670,17 @@ process sentinels.  They shall not disturb each other."
     (let ((default-directory ert-remote-temporary-file-directory))
       (should
        (string-equal (tramp--test-operation)
-                    (tramp--handler-for-test-operation))))
+                    (tramp--handler-for-test-operation)))
+      (should
+       (string-equal (tramp--test-operation "foo")
+                    (tramp--handler-for-test-operation "foo"))))
     (let ((default-directory temporary-file-directory))
       (should-not
        (string-equal (tramp--test-operation)
-                    (tramp--handler-for-test-operation))))
+                    (tramp--handler-for-test-operation)))
+      (should-not
+       (string-equal (tramp--test-operation "foo")
+                    (tramp--handler-for-test-operation "foo"))))
 
     (tramp-remove-external-operation
      #'tramp--test-operation backend)
@@ -8688,11 +8696,17 @@ process sentinels.  They shall not disturb each other."
     (let ((default-directory ert-remote-temporary-file-directory))
       (should-not
        (string-equal (tramp--test-operation)
-                    (tramp--handler-for-test-operation))))
+                    (tramp--handler-for-test-operation)))
+      (should-not
+       (string-equal (tramp--test-operation "foo")
+                    (tramp--handler-for-test-operation "foo"))))
     (let ((default-directory temporary-file-directory))
       (should-not
        (string-equal (tramp--test-operation)
-                    (tramp--handler-for-test-operation))))))
+                    (tramp--handler-for-test-operation)))
+      (should-not
+       (string-equal (tramp--test-operation "foo")
+                    (tramp--handler-for-test-operation "foo"))))))
 
 ;; This test is inspired by Bug#29163.
 (ert-deftest tramp-test50-auto-load ()
diff --git a/texi/tramp.texi b/texi/tramp.texi
index 5d281dc062..e46f7b9155 100644
--- a/texi/tramp.texi
+++ b/texi/tramp.texi
@@ -678,7 +678,10 @@ not auto loaded by Emacs.  All examples require 
@value{tramp} to be
 installed and loaded:
 
 @lisp
+@group
+(require 'tramp)
 (customize-set-variable 'tramp-verbose 6 "Enable remote command traces")
+@end group
 @end lisp
 
 For functions used to configure @value{tramp}, the following clause
@@ -852,12 +855,20 @@ as the @option{rsh} method.
 @cindex method @option{su}
 @cindex @option{su} method
 @item @option{su}
+@cindex method @option{surs}
+@cindex @option{surs} method
+@item @option{surs}
 
 Instead of connecting to a remote host, @command{su} program allows
 editing as another user.  The host can be either @samp{localhost} or
 the host returned by the function @command{(system-name)}.
 @xref{Multi-hops}, for an exception to this behavior.
 
+Method @option{surs} is the same like method @option{su}, but it uses
+the modern @command{su-rs} program.  It can be used instead wherever
+method @option{su} is mentioned in this manual.  @option{surs} is an
+optional method, @pxref{Optional methods}.
+
 @cindex method @option{androidsu}
 @cindex @option{androidsu} method
 @item @option{androidsu}
@@ -876,6 +887,9 @@ default on @code{android} systems only.
 @cindex method @option{sudo}
 @cindex @option{sudo} method
 @item @option{sudo}
+@cindex method @option{sudors}
+@cindex @option{sudors} method
+@item @option{sudors}
 
 Similar to @option{su} method, @option{sudo} uses @command{sudo}.
 @command{sudo} must have sufficient rights to start a shell.
@@ -884,6 +898,11 @@ For security reasons, a @option{sudo} connection is 
disabled after a
 predefined timeout (5 minutes by default).  This can be changed,
 @pxref{Predefined connection information}.
 
+Method @option{sudors} is the same like method @option{sudo}, but it
+uses the modern @command{sudo-rs} program.  It can be used instead
+wherever method @option{sudo} is mentioned in this manual.
+@option{sudors} is an optional method, @pxref{Optional methods}.
+
 @cindex method @option{doas}
 @cindex @option{doas} method
 @item @option{doas}
@@ -4832,7 +4851,7 @@ for which no associated buffers exist (except for Tramp 
internal
 buffers).
 
 This command is helpful to prune connections after you close remote-file
-buffers without having to either cherry pick via
+buffers without having to either cherry-pick via
 @code{tramp-cleanup-connection} or clear them all via
 @code{tramp-cleanup-all-connections}.
 @end deffn
diff --git a/texi/trampver.texi b/texi/trampver.texi
index a2ff88cd29..2fbc047817 100644
--- a/texi/trampver.texi
+++ b/texi/trampver.texi
@@ -7,7 +7,7 @@
 
 @c In the  Tramp GIT, the version number and the bug report address
 @c are auto-frobbed from configure.ac.
-@set trampver 2.8.0.3
+@set trampver 2.8.0.4
 @set trampurl https://www.gnu.org/software/tramp/
 @set tramp-bug-report-address tramp-devel@@gnu.org
 @set emacsver 28.1
diff --git a/tramp-archive.el b/tramp-archive.el
index 3de909911b..a52b8be6e0 100644
--- a/tramp-archive.el
+++ b/tramp-archive.el
@@ -338,15 +338,16 @@ arguments to pass to the OPERATION."
           (tramp-register-file-name-handlers)
           (tramp-archive-run-real-handler operation args))
 
-      (let* ((filename (apply #'tramp-archive-file-name-for-operation
+      (let* ((tramp-methods (cons `(,tramp-archive-method) tramp-methods))
+            (tramp-gvfs-methods tramp-archive-all-gvfs-methods)
+            (filename (apply #'tramp-archive-file-name-for-operation
                              operation args))
             (archive (tramp-archive-file-name-archive filename)))
 
         ;; `filename' could be a quoted file name.  Or the file
         ;; archive could be a directory, see Bug#30293.
         (if (or (null archive)
-                (not (tramp-archive-run-real-handler
-                      #'file-exists-p (list archive)))
+                (not (file-exists-p archive))
                (tramp-archive-run-real-handler
                  #'file-directory-p (list archive)))
             (tramp-archive-run-real-handler operation args)
@@ -358,9 +359,7 @@ arguments to pass to the OPERATION."
              (tramp-get-buffer (tramp-archive-dissect-file-name filename))
            (setq default-directory (file-name-as-directory archive)))
           ;; Now run the handler.
-          (let ((tramp-methods (cons `(,tramp-archive-method) tramp-methods))
-               (tramp-gvfs-methods tramp-archive-all-gvfs-methods)
-               ;; Set uid and gid.  gvfsd-archive could do it, but it doesn't.
+          (let (;; Set uid and gid.  gvfsd-archive could do it, but it doesn't.
                (tramp-unknown-id-integer (user-uid))
                (tramp-unknown-id-string (user-login-name))
                (fn (assoc operation tramp-archive-file-name-handler-alist)))
diff --git a/tramp-cache.el b/tramp-cache.el
index eedb5a3e9b..941c502fa8 100644
--- a/tramp-cache.el
+++ b/tramp-cache.el
@@ -90,6 +90,7 @@
 (require 'time-stamp)
 
 (declare-function tramp-get-method-parameter "tramp")
+(defvar tramp-verbose)
 
 ;;; -- Cache --
 
@@ -97,7 +98,6 @@
 (defvar tramp-cache-data (make-hash-table :test #'equal)
   "Hash table for remote files properties.")
 
-;;;###tramp-autoload
 (defcustom tramp-connection-properties nil
   "List of static connection properties.
 Every entry has the form (REGEXP PROPERTY VALUE).  The regexp
@@ -253,19 +253,19 @@ Return VALUE."
 
 (defun tramp-flush-file-upper-properties (key file)
   "Remove some properties of FILE's upper directory."
-  (when (file-name-absolute-p file)
-    ;; `file-name-directory' can return nil, for example for "~".
-    (when-let* ((file (file-name-directory file))
-               (file (directory-file-name file)))
-      (setq key (tramp-file-name-unify key file))
-      (unless (eq key tramp-cache-undefined)
-       (dolist (property (hash-table-keys (tramp-get-hash-table key)))
-         (when (string-match-p
-                (rx
-                 bos (| "directory-" "file-name-all-completions"
-                        "file-entries"))
-                property)
-           (tramp-flush-file-property key file property)))))))
+  (when-let* (((file-name-absolute-p file))
+             ;; `file-name-directory' can return nil, for example for "~".
+             (file (file-name-directory file))
+             (file (directory-file-name file)))
+    (setq key (tramp-file-name-unify key file))
+    (unless (eq key tramp-cache-undefined)
+      (dolist (property (hash-table-keys (tramp-get-hash-table key)))
+       (when (string-match-p
+              (rx
+               bos (| "directory-" "file-name-all-completions"
+                      "file-entries"))
+              property)
+         (tramp-flush-file-property key file property))))))
 
 ;;;###tramp-autoload
 (defun tramp-flush-file-properties (key file)
diff --git a/tramp-cmds.el b/tramp-cmds.el
index 6042209d4f..db3737500e 100644
--- a/tramp-cmds.el
+++ b/tramp-cmds.el
@@ -631,14 +631,29 @@ For details, see `tramp-rename-files'."
 (defcustom tramp-file-name-with-method "sudo"
   "Which method to be used in `tramp-file-name-with-sudo'."
   :group 'tramp
-  :version "30.1"
-  :type '(choice (const "su")
-                (const "sudo")
+  :version "31.1"
+  ;; It should be a choice of constant strings.  See
+  ;; `with-tramp-file-name-with-method'.
+  :type '(choice (const "su") (const "surs")
+                (const "sudo") (const "sudors")
                 (const "doas")
                 (const "run0")
                 (const "ksu"))
+  :initialize #'custom-initialize-default
+  :set #'tramp-set-file-name-with-method
   :link '(tramp-info-link :tag "Tramp manual" tramp-file-name-with-method))
 
+(defun tramp-set-file-name-with-method (symbol value)
+  "Set SYMBOL to value VALUE.
+Used in user option `tramp-file-name-with-method'.  If VALUE is an
+optional method, enable it."
+  (unless (string-equal (symbol-value symbol) value)
+    ;; Enable optional method.
+    (tramp-enable-method value)
+    ;; Set the value.
+    (when (assoc value tramp-methods)
+      (set-default symbol value))))
+
 (defun tramp-get-file-name-with-method ()
   "Return connection-local value of `tramp-file-name-with-method'."
   (tramp-compat-connection-local-value tramp-file-name-with-method))
@@ -651,8 +666,11 @@ Run BODY."
           (if current-prefix-arg
              (completing-read
               "Tramp method: "
-               (mapcar
-               #'cadr (cdr (get 'tramp-file-name-with-method 'custom-type)))
+              ;; Filter out enabled methods.
+              (seq-intersection
+               (mapcar #'car tramp-methods)
+               (mapcar
+                #'cadr (cdr (get 'tramp-file-name-with-method 'custom-type))))
                nil t (tramp-get-file-name-with-method))
             (tramp-get-file-name-with-method))))
      ,@body))
diff --git a/tramp-compat.el b/tramp-compat.el
index 5d463bc006..93190fec3a 100644
--- a/tramp-compat.el
+++ b/tramp-compat.el
@@ -259,5 +259,8 @@ value is the default binding of the variable."
 ;;   instead of `condition-case' when the origin of an error shall be
 ;;   kept, for example when the HANDLER propagates the error with
 ;;   `(signal (car err) (cdr err)'.
+;;
+;; * Starting with Emacs 30.1, use '(_ VALUEFORM)' instead of
+;;   '(VALUEFORM)' in 'if-let*/when-let*/and-let*'.
 
 ;;; tramp-compat.el ends here
diff --git a/tramp-gvfs.el b/tramp-gvfs.el
index c283c119b8..687cc7e1bc 100644
--- a/tramp-gvfs.el
+++ b/tramp-gvfs.el
@@ -123,7 +123,10 @@
     (and (featurep 'dbusbind)
         (tramp-compat-funcall 'dbus-get-unique-name :session)
         (or (tramp-process-running-p "gvfs-fuse-daemon")
-            (tramp-process-running-p "gvfsd-fuse"))))
+            (tramp-process-running-p "gvfsd-fuse")
+             ;; Gvfs may be built without fuse
+             ;; (cf. 
https://lists.gnu.org/archive/html/tramp-devel/2025-10/msg00009.html).
+            (tramp-process-running-p "gvfsd"))))
   "Non-nil when GVFS is available.")
 
 ;;;###tramp-autoload
diff --git a/tramp-message.el b/tramp-message.el
index a328183e18..d349179d0e 100644
--- a/tramp-message.el
+++ b/tramp-message.el
@@ -56,7 +56,6 @@
 (defvar tramp-repository-branch)
 (defvar tramp-repository-version)
 
-;;;###tramp-autoload
 (defcustom tramp-verbose 3
   "Verbosity level for Tramp messages.
 Any level x includes messages for all levels 1 .. x-1.  The levels are
diff --git a/tramp-sh.el b/tramp-sh.el
index 8922adb758..61f64e4c02 100644
--- a/tramp-sh.el
+++ b/tramp-sh.el
@@ -521,6 +521,42 @@ The string is used in `tramp-methods'.")
 
   (tramp-set-completion-function "nc" tramp-completion-function-alist-telnet))
 
+;;;###tramp-autoload
+(defun tramp-enable-surs-method ()
+  "Enable \"surs\" method."
+  (add-to-list 'tramp-methods
+               `("surs"
+                 (tramp-login-program        "su-rs")
+                 (tramp-login-args           (("-") ("%u")))
+                 (tramp-remote-shell         ,tramp-default-remote-shell)
+                 (tramp-remote-shell-login   ("-l"))
+                 (tramp-remote-shell-args    ("-c"))
+                 (tramp-connection-timeout   10)))
+
+  (add-to-list 'tramp-default-user-alist
+              `(,(rx bos "surs" eos) nil ,tramp-root-id-string))
+
+  (tramp-set-completion-function "surs" tramp-completion-function-alist-su))
+
+;;;###tramp-autoload
+(defun tramp-enable-sudors-method ()
+  "Enable \"sudors\" method."
+  (add-to-list 'tramp-methods
+               `("sudors"
+                 (tramp-login-program        "sudo-rs")
+                 (tramp-login-args           (("-u" "%u") ("-s") ("%l")))
+                 (tramp-remote-shell         ,tramp-default-remote-shell)
+                 (tramp-remote-shell-login   ("-l"))
+                 (tramp-remote-shell-args    ("-c"))
+                 (tramp-connection-timeout   10)
+                 (tramp-session-timeout      300)
+                (tramp-password-previous-hop t)))
+
+  (add-to-list 'tramp-default-user-alist
+              `(,(rx bos "sudors" eos) nil ,tramp-root-id-string))
+
+  (tramp-set-completion-function "sudors" tramp-completion-function-alist-su))
+
 ;;;###tramp-autoload
 (defun tramp-enable-run0-method ()
   "Enable \"run0\" method."
@@ -2898,15 +2934,15 @@ The method used must be an out-of-band method."
          ;; Try to insert the amount of free space.
          (goto-char (point-min))
          ;; First find the line to put it on.
-         (when (and (search-forward-regexp
-                     (rx bol (group (* blank) "total")) nil t)
-                    ;; Emacs 29.1 or later.
-                    (not (fboundp 'dired--insert-disk-space)))
-           (when-let* ((available (get-free-disk-space ".")))
-             ;; Replace "total" with "total used", to avoid confusion.
-             (replace-match "\\1 used in directory")
-             (end-of-line)
-             (insert " available " available))))
+         (when-let* (((search-forward-regexp
+                       (rx bol (group (* blank) "total")) nil t))
+                     ;; Emacs 29.1 or later.
+                     ((not (fboundp 'dired--insert-disk-space)))
+                     (available (get-free-disk-space ".")))
+           ;; Replace "total" with "total used", to avoid confusion.
+           (replace-match "\\1 used in directory")
+           (end-of-line)
+           (insert " available " available)))
 
        (prog1 (goto-char end-marker)
          (set-marker beg-marker nil)
@@ -2964,7 +3000,10 @@ the result will be a local, non-Tramp, file name."
            ;; use a user name from the config file.
            (when (and (tramp-string-empty-or-nil-p uname)
                       (string-match-p
-                       (rx bos (| "su" "sudo" "doas" "run0" "ksu") eos) 
method))
+                       (rx bos
+                           (| "su" "surs" "sudo" "sudors" "doas" "run0" "ksu")
+                           eos)
+                       method))
              (setq uname user))
            (when (setq hname (tramp-get-home-directory v uname))
              (setq localname (concat hname fname)))))
diff --git a/tramp.el b/tramp.el
index ce6c6ee63b..18991666f4 100644
--- a/tramp.el
+++ b/tramp.el
@@ -7,7 +7,7 @@
 ;; Maintainer: Michael Albinus <[email protected]>
 ;; Keywords: comm, processes
 ;; Package: tramp
-;; Version: 2.8.0.3
+;; Version: 2.8.0.4
 ;; Package-Requires: ((emacs "28.1"))
 ;; Package-Type: multi
 ;; URL: https://www.gnu.org/software/tramp/
@@ -418,12 +418,12 @@ Notes:
 All these arguments can be overwritten by connection properties.
 See Info node `(tramp) Predefined connection information'.
 
-When using `su', `sudo' or `doas' the phrase \"open connection to
-a remote host\" sounds strange, but it is used nevertheless, for
-consistency.  No connection is opened to a remote host, but `su',
-`sudo' or `doas' is started on the local host.  You should
-specify a remote host `localhost' or the name of the local host.
-Another host name is useful only in combination with
+When using `su', `surs', `sg', `sudo', `sudors', `doas', `run0' or `ksu'
+the phrase \"open connection to a remote host\" sounds strange, but it
+is used nevertheless, for consistency.  No connection is opened to a
+remote host, but the respective command is started on the local host.
+You should specify a remote host `localhost' or the name of the local
+host.  Another host name is useful only in combination with
 `tramp-default-proxies-alist'.")
 
 (defcustom tramp-default-method
@@ -927,6 +927,7 @@ Customize.  See also `tramp-change-syntax'."
                 (const :tag "Ange-FTP" simplified)
                 (const :tag "XEmacs" separate))
   :require 'tramp
+  ;; Starting with Emacs 31.1, we can use `custom-initialize-after-file' 
instead.
   :initialize #'custom-initialize-default
   :set #'tramp-set-syntax
   :link '(info-link :tag "Tramp manual" "(tramp) Change file name syntax"))
@@ -941,7 +942,7 @@ to be set, depending on VALUE."
   ;; Cleanup existing buffers.
   (unless (eq (symbol-value symbol) value)
     (tramp-cleanup-all-buffers))
-  ;; Set the value:
+  ;; Set the value.
   (set-default symbol value)
   ;; Reset the depending variables.
   (setq tramp-prefix-format (tramp-build-prefix-format)
@@ -970,6 +971,7 @@ to be set, depending on VALUE."
 ;; Initialize the Tramp syntax variables.  We want to override initial
 ;; value of `tramp-file-name-regexp'.  We do not call
 ;; `custom-set-variable', this would load Tramp via custom.el.
+;; Starting with Emacs 31.1, we can use `custom-initialize-after-file' instead.
 (tramp--with-startup
   (tramp-set-syntax 'tramp-syntax tramp-syntax))
 
@@ -1939,6 +1941,9 @@ expected to be a string, which will be used."
       (when (cadr args)
        (setq localname (and (stringp (cadr args)) (cadr args))))
       (when hop
+       ;; Do not keep the hop for the "archive" method.
+       (when (string-equal method tramp-archive-method)
+         (setq hop nil))
        ;; Keep hop in file name for completion or when indicated.
        (unless (or minibuffer-completing-file-name tramp-show-ad-hoc-proxies)
          (setq hop nil))
@@ -2553,7 +2558,9 @@ packages like `tramp-sh' (except `tramp-ftp')."
        `(lambda (orig-fun &rest args)
          (if-let* ((handler
                     (find-file-name-handler
-                     (or (car args) default-directory) #',operation)))
+                     (if (and (car args) (file-name-absolute-p (car args)))
+                         (car args) default-directory)
+                     #',operation)))
              (apply handler #',operation args)
            (apply orig-fun args)))
        `((name . ,(concat "tramp-advice-" (symbol-name operation))))))))
@@ -4085,17 +4092,17 @@ BODY is the backend specific code."
 
           (let (last-coding-system-used (need-chown t))
             ;; Set file modification time.
-            (when (or (eq ,visit t) (stringp ,visit))
-              (when-let* ((file-attr (file-attributes filename 'integer)))
-                (set-visited-file-modtime
-                 ;; We must pass modtime explicitly, because FILENAME
-                 ;; can be different from (buffer-file-name), f.e. if
-                 ;; `file-precious-flag' is set.
-                 (or (file-attribute-modification-time file-attr)
-                     (current-time)))
-                (when (and (= (file-attribute-user-id file-attr) uid)
-                           (= (file-attribute-group-id file-attr) gid))
-                  (setq need-chown nil))))
+            (when-let* (((or (eq ,visit t) (stringp ,visit)))
+                        (file-attr (file-attributes filename 'integer)))
+              (set-visited-file-modtime
+               ;; We must pass modtime explicitly, because FILENAME
+               ;; can be different from (buffer-file-name), f.e. if
+               ;; `file-precious-flag' is set.
+               (or (file-attribute-modification-time file-attr)
+                   (current-time)))
+              (when (and (= (file-attribute-user-id file-attr) uid)
+                         (= (file-attribute-group-id file-attr) gid))
+                (setq need-chown nil)))
 
             ;; Set the ownership.
              (when need-chown
@@ -5236,10 +5243,11 @@ Do not set it manually, it is used buffer-local in 
`tramp-get-lock-pid'.")
             vec "Method `%s' is not supported for multi-hops"
             (tramp-file-name-method item)))))
 
-      ;; Some methods ("su", "sg", "sudo", "doas", "run0", "ksu") do
-      ;; not use the host name in their command template.  In this
-      ;; case, the remote file name must use either a local host name
-      ;; (first hop), or a host name matching the previous hop.
+      ;; Some methods ("su", "surs", "sg", "sudo", "sudors", "doas",
+      ;; "run0", "ksu") do not use the host name in their command
+      ;; template.  In this case, the remote file name must use either
+      ;; a local host name (first hop), or a host name matching the
+      ;; previous hop.
       (let ((previous-host (or tramp-local-host-regexp "")))
        (setq choices target-alist)
        (while (setq item (pop choices))
@@ -7160,7 +7168,7 @@ verbosity of 6."
                     ;; The returned command name could be truncated
                     ;; to 15 characters.  Therefore, we cannot check
                     ;; for `string-equal'.
-                    ((string-prefix-p comm process-name))
+                    ((eq t (compare-strings comm 0 15 process-name 0 15)))
                     ((throw 'result t)))))))))
 
 ;; When calling "emacs -Q", `auth-source-search' won't be called.  If
@@ -7217,6 +7225,7 @@ Consults the auth-source package."
                      (tramp-compat-auth-info-password auth-info))))
 
         ;; Try the password cache.
+        ;; Starting with Emacs 31.1, this isn't needed anymore.
         (with-tramp-suspended-timers
           (setq auth-passwd
                 (password-read
diff --git a/trampver.el b/trampver.el
index cbd8e30e53..3af36b32b5 100644
--- a/trampver.el
+++ b/trampver.el
@@ -7,7 +7,7 @@
 ;; Maintainer: Michael Albinus <[email protected]>
 ;; Keywords: comm, processes
 ;; Package: tramp
-;; Version: 2.8.0.3
+;; Version: 2.8.0.4
 ;; Package-Requires: ((emacs "28.1"))
 ;; Package-Type: multi
 ;; URL: https://www.gnu.org/software/tramp/
@@ -40,7 +40,7 @@
 ;; ./configure" to change them.
 
 ;;;###tramp-autoload
-(defconst tramp-version "2.8.0.3"
+(defconst tramp-version "2.8.0.4"
   "This version of Tramp.")
 
 ;;;###tramp-autoload
@@ -76,7 +76,7 @@
 ;; Check for Emacs version.
 (let ((x   (if (not (string-version-lessp emacs-version "28.1"))
       "ok"
-    (format "Tramp 2.8.0.3 is not fit for %s"
+    (format "Tramp 2.8.0.4 is not fit for %s"
             (replace-regexp-in-string "\n" "" (emacs-version))))))
   (unless (string-equal "ok" x) (error "%s" x)))
 


Reply via email to