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

    Tramp ELPA version 2.8.1 released
---
 README              |   6 +-
 test/tramp-tests.el | 281 ++++++++++++++++++++------------
 texi/tramp.texi     | 107 ++++++++----
 texi/trampver.texi  |   2 +-
 tramp-adb.el        |  87 +++++-----
 tramp-sh.el         |   3 +-
 tramp-smb.el        | 458 +++++++++++++++++++++++++++++++---------------------
 tramp-sshfs.el      |   2 +-
 tramp.el            |  16 +-
 trampver.el         |   6 +-
 10 files changed, 604 insertions(+), 364 deletions(-)

diff --git a/README b/README
index d791d2ec7e..529a204ba0 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.5/tramp*.elc
+          $ rm -f ~/.emacs.d/elpa/tramp-2.8.1/tramp*.elc
 
    • Start Emacs with Tramp's source files
 
-          $ emacs -L ~/.emacs.d/elpa/tramp-2.8.0.5 -l tramp
+          $ emacs -L ~/.emacs.d/elpa/tramp-2.8.1 -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.5 from GNU ELPA:
+installation or upgrading Tramp 2.8.1 from GNU ELPA:
 
      (when (string-equal emacs-version "29.1")
        (with-current-buffer
diff --git a/test/tramp-tests.el b/test/tramp-tests.el
index 76e9a47e41..979ff7edfc 100644
--- a/test/tramp-tests.el
+++ b/test/tramp-tests.el
@@ -80,6 +80,9 @@
 (declare-function tramp-method-out-of-band-p "tramp-sh")
 (declare-function tramp-smb-get-localname "tramp-smb")
 (defvar ange-ftp-make-backup-files)
+(defvar auto-revert-notify-watch-descriptor)
+(defvar auto-revert-remote-files)
+(defvar auto-revert-use-notify)
 (defvar comp-warn-primitives)
 (defvar tramp-connection-properties)
 (defvar tramp-copy-size-limit)
@@ -147,6 +150,8 @@
 
 (setq auth-source-cache-expiry nil
       auth-source-save-behavior nil
+      auto-revert-remote-files t
+      auto-revert-use-notify t
       ert-batch-backtrace-right-margin nil
       password-cache-expiry nil
       remote-file-name-inhibit-cache nil
@@ -3878,7 +3883,7 @@ This tests also `access-file', `file-readable-p',
              (delete-file tmp-name2)
 
              ;; A non-existent or cyclic link target makes the file
-             ;; unaccessible.
+             ;; inaccessible.
              (dolist (target
                       `("does-not-exist" ,(file-name-nondirectory tmp-name2)))
                (make-symbolic-link target tmp-name2)
@@ -5338,18 +5343,36 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
           kill-buffer-query-functions)
       (unwind-protect
          (progn
-           ;; We cannot use "/bin/true" and "/bin/false"; those paths
-           ;; do not exist on MS Windows.
-           (should (zerop (process-file "true")))
-           (should-not (zerop (process-file "false")))
+           ;; In the "smb" case, default-directory must have a share.
+           (when (tramp--test-smb-p)
+             (let ((default-directory
+                    (concat (file-remote-p default-directory) "/")))
+               (should-not
+                (zerop (process-file "exit" nil nil nil "-not" "$true")))))
+           (should
+            (zerop
+             (if (tramp--test-smb-p)
+                 ;; $true is converted to 1 in Powershell.
+                 (process-file "exit" nil nil nil "-not" "$true")
+               (process-file "true"))))
+           (should-not
+            (zerop
+             (if (tramp--test-smb-p)
+                 ;; $false is converted to 0 in Powershell.
+                 (process-file "exit" nil nil nil "-not" "$false")
+               (process-file "false"))))
            (should-not (zerop (process-file "binary-does-not-exist")))
            ;; Return exit code.
-           (should (= 42 (process-file
-                          (tramp--test-shell-file-name) nil nil nil
-                          (tramp--test-shell-command-switch) "exit 42")))
+           ;; FIXME: Make it work with the shell also in the "smb" case.
+           (should
+            (= 42 (if (tramp--test-smb-p)
+                      (process-file "exit" nil nil nil "42")
+                    (process-file
+                     (tramp--test-shell-file-name) nil nil nil
+                     (tramp--test-shell-command-switch) "exit 42"))))
            ;; Return exit code in case the process is interrupted,
            ;; and there's no indication for a signal describing string.
-           (unless (tramp--test-sshfs-p)
+           (unless (or (tramp--test-sshfs-p) (tramp--test-smb-p))
              (let (process-file-return-signal-string)
                (should
                 (= (+ 128 2)
@@ -5358,7 +5381,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
                     (tramp--test-shell-command-switch) "kill -2 $$")))))
            ;; Return string in case the process is interrupted and
            ;; there's an indication for a signal describing string.
-           (unless (tramp--test-sshfs-p)
+           (unless (or (tramp--test-sshfs-p) (tramp--test-smb-p))
              (let ((process-file-return-signal-string t))
                (should
                 (string-match-p
@@ -5375,7 +5398,12 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
              (with-temp-buffer
                (write-region "foo" nil tmp-name)
                (should (file-exists-p tmp-name))
-               (should (zerop (process-file "ls" nil destination nil fnnd)))
+               (should
+                (zerop
+                 (if (tramp--test-smb-p)
+                     (process-file
+                      (format "(ls %s).Name" fnnd) nil destination)
+                   (process-file "ls" nil destination nil fnnd))))
                (with-current-buffer
                    (if (bufferp destination) destination (current-buffer))
                  ;; "ls" could produce colorized output.
@@ -5390,7 +5418,12 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
                  (goto-char (point-max)))
 
                ;; Second run.  The output must be appended.
-               (should (zerop (process-file "ls" nil destination t fnnd)))
+               (should
+                (zerop
+                 (if (tramp--test-smb-p)
+                     (process-file
+                      (format "(ls %s).Name" fnnd) nil destination t)
+                   (process-file "ls" nil destination t fnnd))))
                (with-current-buffer
                    (if (bufferp destination) destination (current-buffer))
                  ;; "ls" could produce colorized output.
@@ -5416,7 +5449,9 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
                (write-region "foo" nil tmp-name)
                (should (file-exists-p tmp-name))
                (should (zerop (process-file "cat" tmp-name t)))
-               (should (string-equal "foo" (buffer-string)))
+               (should
+                (string-equal
+                 (if (tramp--test-smb-p) "foo\n" "foo") (buffer-string)))
                (should-not (get-buffer-window (current-buffer) t))
                (delete-file tmp-name)))
 
@@ -5443,7 +5478,9 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
                  (insert-file-contents tmp-name)
                  (should
                   (string-match-p
-                   (rx "cat:" (* nonl) " No such file or directory")
+                   (rx (| (: "cat:" (* nonl) "No such file or directory")
+                          ;; MS Windows.
+                          (: "cat : Cannot find path")))
                    (buffer-string)))
                  (should-not (get-buffer-window (current-buffer) t))
                  (delete-file tmp-name)))))
@@ -5475,30 +5512,33 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
          kill-buffer-query-functions command proc)
 
       ;; Simple process.
-      (unwind-protect
-         (with-temp-buffer
-           (setq command '("cat")
-                 proc
-                 (apply #'start-file-process "test1" (current-buffer) command))
-           (should (processp proc))
-           (should (equal (process-status proc) 'run))
-           (should (equal (process-get proc 'remote-command) command))
-           (process-send-string proc "foo\n")
-           (process-send-eof proc)
-           ;; Read output.
-           (with-timeout (10 (tramp--test-timeout-handler))
-             (while (< (- (point-max) (point-min)) (length "foo"))
-               (while (accept-process-output proc 0 nil t))))
-            ;; Some `cat' implementations do not support the `cat -'
-            ;; call.  We skip then.
-            (skip-unless
-             (not
-              (string-match-p (rx "cat: -: input file is output file\n")
-                              (buffer-string))))
-           (should (string-match-p "foo" (buffer-string))))
+      ;; The "smb" method does not support stdin redirection.
+      (unless (tramp--test-smb-p)
+       (unwind-protect
+           (with-temp-buffer
+             (setq command '("cat")
+                   proc
+                   (apply
+                    #'start-file-process "test1" (current-buffer) command))
+             (should (processp proc))
+             (should (equal (process-status proc) 'run))
+             (should (equal (process-get proc 'remote-command) command))
+             (process-send-string proc "foo\n")
+             (process-send-eof proc)
+             ;; Read output.
+             (with-timeout (10 (tramp--test-timeout-handler))
+               (while (< (- (point-max) (point-min)) (length "foo"))
+                 (while (accept-process-output proc 0 nil t))))
+              ;; Some `cat' implementations do not support the `cat -'
+              ;; call.  We skip then.
+              (skip-unless
+               (not
+               (string-match-p (rx "cat: -: input file is output file\n")
+                               (buffer-string))))
+             (should (string-match-p "foo" (buffer-string))))
 
-       ;; Cleanup.
-       (ignore-errors (delete-process proc)))
+         ;; Cleanup.
+         (ignore-errors (delete-process proc))))
 
       ;; Simple process using a file.
       (unwind-protect
@@ -5512,7 +5552,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
            (should (equal (process-get proc 'remote-command) command))
            ;; Read output.
            (with-timeout (10 (tramp--test-timeout-handler))
-             (while (< (- (point-max) (point-min)) (length "foo"))
+             (while (not (string-match-p "foo" (buffer-string)))
                (while (accept-process-output proc 0 nil t))))
            (should (string-match-p "foo" (buffer-string))))
 
@@ -5522,24 +5562,33 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
          (delete-file tmp-name)))
 
       ;; Process filter.
+      ;; The "smb" method does not support the "cat" stdin
+      ;; redirection.  The "adb" method does not support late process
+      ;; filter setting for the "echo" command.
       (unwind-protect
          (with-temp-buffer
-           (setq command '("cat")
+           (setq command (if (tramp--test-smb-p) '("echo" "foo") '("cat"))
                  proc
                  (apply #'start-file-process "test3" (current-buffer) command))
            (should (processp proc))
-           (should (equal (process-status proc) 'run))
+           ;(should (equal (process-status proc) 'run))
            (should (equal (process-get proc 'remote-command) command))
            (set-process-filter
             proc
-            (lambda (p s) (with-current-buffer (process-buffer p) (insert s))))
-           (process-send-string proc "foo\n")
-           (process-send-eof proc)
+            (lambda (p s)
+              (with-current-buffer
+                  (process-buffer p)
+                (insert
+                 (replace-regexp-in-string
+                  (rx bol "foo" (? "\r") eol) "foobar" s)))))
+           (unless (tramp--test-smb-p)
+             (process-send-string proc "foo\n")
+             (process-send-eof proc))
            ;; Read output.
            (with-timeout (10 (tramp--test-timeout-handler))
-             (while (< (- (point-max) (point-min)) (length "foo"))
+             (while (not (string-match-p "foobar" (buffer-string)))
                (while (accept-process-output proc 0 nil t))))
-           (should (string-match-p "foo" (buffer-string))))
+           (should (string-match-p "foobar" (buffer-string))))
 
        ;; Cleanup.
        (ignore-errors (delete-process proc)))
@@ -5668,36 +5717,39 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
   (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil)))
     (let ((default-directory ert-remote-temporary-file-directory)
          (tmp-name (tramp--test-make-temp-name nil quoted))
+         (inhibit-message (not (ignore-errors (edebug-mode))))
          kill-buffer-query-functions command proc)
       (should-not (apply #'make-process nil)) ; Use `apply' to avoid warnings.
 
       ;; Simple process.
-      (unwind-protect
-         (with-temp-buffer
-           (setq command '("cat")
-                 proc
-                 (make-process
-                  :name "test1" :buffer (current-buffer) :command command
-                  :file-handler t))
-           (should (processp proc))
-           (should (equal (process-status proc) 'run))
-           (should (equal (process-get proc 'remote-command) command))
-           (process-send-string proc "foo\n")
-           (process-send-eof proc)
-           ;; Read output.
-           (with-timeout (10 (tramp--test-timeout-handler))
-             (while (< (- (point-max) (point-min)) (length "foo"))
-               (while (accept-process-output proc 0 nil t))))
-            ;; Some `cat' implementations do not support the `cat -'
-            ;; call.  We skip then.
-            (skip-unless
-             (not
-              (string-match-p (rx "cat: -: input file is output file\n")
-                              (buffer-string))))
-           (should (string-match-p "foo" (buffer-string))))
+      ;; The "smb" method does not support stdin redirection.
+      (unless (tramp--test-smb-p)
+       (unwind-protect
+           (with-temp-buffer
+             (setq command '("cat")
+                   proc
+                   (make-process
+                    :name "test1" :buffer (current-buffer) :command command
+                    :file-handler t))
+             (should (processp proc))
+             (should (equal (process-status proc) 'run))
+             (should (equal (process-get proc 'remote-command) command))
+             (process-send-string proc "foo\n")
+             (process-send-eof proc)
+             ;; Read output.
+             (with-timeout (10 (tramp--test-timeout-handler))
+               (while (< (- (point-max) (point-min)) (length "foo"))
+                 (while (accept-process-output proc 0 nil t))))
+              ;; Some `cat' implementations do not support the `cat -'
+              ;; call.  We skip then.
+              (skip-unless
+               (not
+               (string-match-p (rx "cat: -: input file is output file\n")
+                               (buffer-string))))
+             (should (string-match-p "foo" (buffer-string))))
 
-       ;; Cleanup.
-       (ignore-errors (delete-process proc)))
+         ;; Cleanup.
+         (ignore-errors (delete-process proc))))
 
       ;; Simple process using a file.
       (unwind-protect
@@ -5713,7 +5765,7 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
            (should (equal (process-get proc 'remote-command) command))
            ;; Read output.
            (with-timeout (10 (tramp--test-timeout-handler))
-             (while (< (- (point-max) (point-min)) (length "foo"))
+             (while (not (string-match-p "foo" (buffer-string)))
                (while (accept-process-output proc 0 nil t))))
            (should (string-match-p "foo" (buffer-string))))
 
@@ -5725,24 +5777,26 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
       ;; Process filter.
       (unwind-protect
          (with-temp-buffer
-           (setq command '("cat")
+           (setq command '("echo" "foo")
                  proc
                  (make-process
                   :name "test3" :buffer (current-buffer) :command command
                   :filter
                   (lambda (p s)
-                    (with-current-buffer (process-buffer p) (insert s)))
+                    (with-current-buffer
+                        (process-buffer p)
+                      (insert
+                       (replace-regexp-in-string
+                        (rx bol "foo" (? "\r") eol) "foobar" s))))
                   :file-handler t))
            (should (processp proc))
-           (should (equal (process-status proc) 'run))
+           ;(should (equal (process-status proc) 'run))
            (should (equal (process-get proc 'remote-command) command))
-           (process-send-string proc "foo\n")
-           (process-send-eof proc)
            ;; Read output.
            (with-timeout (10 (tramp--test-timeout-handler))
-             (while (not (string-match-p "foo" (buffer-string)))
+             (while (not (string-match-p "foobar" (buffer-string)))
                (while (accept-process-output proc 0 nil t))))
-           (should (string-match-p "foo" (buffer-string))))
+           (should (string-match-p "foobar" (buffer-string))))
 
        ;; Cleanup.
        (ignore-errors (delete-process proc)))
@@ -5819,13 +5873,19 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
                (with-current-buffer stderr
                  (with-timeout (10 (tramp--test-timeout-handler))
                    (while (not (string-match-p
-                                "No such file or directory" (buffer-string)))
-                     (while (accept-process-output
-                             (get-buffer-process stderr) 0 nil t))))
+                                (rx (| "No such file or directory"
+                                       "Cannot find path"))
+                                (buffer-string)))
+                     (when-let* ((p (or (get-buffer-process stderr)
+                                        auto-revert-notify-watch-descriptor))
+                                 ((processp p)))
+                       (while (accept-process-output p 0 nil t)))))
                  (delete-process proc)
                  (should
                   (string-match-p
-                   (rx "cat:" (* nonl) " No such file or directory")
+                   (rx (| (: "cat:" (* nonl) "No such file or directory")
+                          ;; MS Windows.
+                          (: "cat : Cannot find path")))
                    (buffer-string)))))
 
            ;; Cleanup.
@@ -5845,13 +5905,19 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
              (should (equal (process-get proc 'remote-command) command))
              ;; Read stderr.
              (with-timeout (10 (tramp--test-timeout-handler))
-               (while (accept-process-output proc nil nil t)))
+               (let ((remote-file-name-inhibit-cache t))
+                 (while
+                     (or (not (file-exists-p tmp-name))
+                         (zerop
+                          (file-attribute-size (file-attributes tmp-name)))))))
              (delete-process proc)
              (with-temp-buffer
                (insert-file-contents tmp-name)
                (should
                 (string-match-p
-                 (rx "cat:" (* nonl) " No such file or directory")
+                 (rx (| (: "cat:" (* nonl) "No such file or directory")
+                        ;; MS Windows.
+                        (: "cat : Cannot find path")))
                  (buffer-string)))))
 
          ;; Cleanup.
@@ -6093,9 +6159,11 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
 INPUT, if non-nil, is a string sent to the process."
   (let ((proc (async-shell-command command output-buffer error-buffer))
        (delete-exited-processes t))
-    (should (equal (process-get proc 'remote-command)
-                  (with-connection-local-variables
-                   `(,shell-file-name ,shell-command-switch ,command))))
+    ;; `tramp-smb-handle-shell-command' modifies the command.
+    (unless (tramp--test-smb-p)
+      (should (equal (process-get proc 'remote-command)
+                    (with-connection-local-variables
+                     `(,shell-file-name ,shell-command-switch ,command)))))
     (cl-letf (((symbol-function #'shell-command-sentinel) #'ignore))
       (when (stringp input)
        (process-send-string proc input))
@@ -6139,7 +6207,9 @@ INPUT, if non-nil, is a string sent to the process."
              (should (file-exists-p tmp-name))
              (funcall
               this-shell-command
-              (format "ls %s" (file-name-nondirectory tmp-name))
+              (format
+               (if (tramp--test-smb-p) "(ls %s).Name" "ls %s")
+               (file-name-nondirectory tmp-name))
               (current-buffer))
              ;; "ls" could produce colorized output.
              (goto-char (point-min))
@@ -6154,7 +6224,8 @@ INPUT, if non-nil, is a string sent to the process."
          (ignore-errors (delete-file tmp-name)))
 
        ;; Test `{async-}shell-command' with error buffer.
-       (unless (tramp-direct-async-process-p)
+       ;; Method "smb" does not support ">&2" construct.
+       (unless (or (tramp--test-smb-p) (tramp-direct-async-process-p))
          (let ((stderr (generate-new-buffer "*stderr*")))
            (unwind-protect
                (with-temp-buffer
@@ -6170,7 +6241,8 @@ INPUT, if non-nil, is a string sent to the process."
              (ignore-errors (kill-buffer stderr))))))
 
       ;; Test sending string to `async-shell-command'.
-      (when (tramp--test-asynchronous-processes-p)
+      (when (and (not (tramp--test-smb-p))
+                (tramp--test-asynchronous-processes-p))
        (unwind-protect
            (with-temp-buffer
              (write-region "foo" nil tmp-name)
@@ -6550,6 +6622,8 @@ INPUT, if non-nil, is a string sent to the process."
   :tags '(:expensive-test :tramp-asynchronous-processes)
   (skip-unless (tramp--test-enabled))
   (skip-unless (tramp--test-supports-processes-p))
+  ;; FIXME: Make it work despite if ~/.emacs_powershell.
+  (skip-unless (not (tramp--test-smb-p)))
 
   (let ((default-directory ert-remote-temporary-file-directory)
        explicit-shell-file-name kill-buffer-query-functions
@@ -7552,13 +7626,13 @@ This requires restrictions of file name syntax."
 (defun tramp--test-supports-processes-p ()
   "Return whether the method under test supports external processes."
   (unless (tramp--test-crypt-p)
-    ;; We use it to enable/disable tests in a given test run, for
-    ;; example for remote processes on MS Windows.
-    (if (tramp-connection-property-p
-         tramp-test-vec "tramp--test-supports-processes-p")
-       (tramp-get-connection-property
-        tramp-test-vec "tramp--test-supports-processes-p")
-      (or (tramp--test-adb-p) (tramp--test-sh-p) (tramp--test-sshfs-p)))))
+    (or (tramp--test-adb-p) (tramp--test-sh-p) (tramp--test-sshfs-p)
+       (and (tramp--test-smb-p)
+            (file-writable-p
+             (file-name-concat
+              (file-remote-p ert-remote-temporary-file-directory)
+              ;; We check a directory on the "ADMIN$" share.
+              "ADMIN$" "Boot"))))))
 
 (defun tramp--test-supports-set-file-modes-p ()
   "Return whether the method under test supports setting file modes."
@@ -7728,7 +7802,11 @@ This requires restrictions of file name syntax."
                ;; `default-directory' with special characters.  See
                ;; Bug#53846.
                (when (and (tramp--test-expensive-test-p)
-                          (tramp--test-supports-processes-p))
+                          (tramp--test-supports-processes-p)
+                          ;; FIXME: tramp-smb.el should implement this.
+                          (not (and (tramp--test-smb-p)
+                                    (string-match-p
+                                     (rx (or (any "[$") (not ascii))) file1))))
                  (let ((default-directory file1))
                    (dolist (this-shell-command
                             (append
@@ -7988,6 +8066,7 @@ process sentinels.  They shall not disturb each other."
   (skip-unless (not (tramp--test-telnet-p)))
   (skip-unless (not (tramp--test-box-p)))
   (skip-unless (not (tramp--test-windows-nt-p)))
+  (skip-unless (not (tramp--test-smb-p)))
 
   (with-timeout
       (tramp--test-asynchronous-requests-timeout (tramp--test-timeout-handler))
@@ -8912,7 +8991,10 @@ Since it unloads Tramp, it shall be the last test to 
run."
   (require 'tramp)
   (require 'tramp-archive)
   (should (featurep 'tramp))
-  (should (featurep 'tramp-archive)))
+  (should (featurep 'tramp-archive))
+
+  ;; Disabled further tests.
+  (setq tramp--test-enabled-checked '(t)))
 
 (defun tramp-test-all (&optional interactive)
   "Run all tests for \\[tramp].
@@ -8944,6 +9026,7 @@ If INTERACTIVE is non-nil, the tests are run 
interactively."
 ;; * Implement `tramp-test31-interrupt-process' and
 ;;   `tramp-test31-signal-process' for "adb", "sshfs" and for direct
 ;;   async processes.  Check, why they don't run stable.
+;; * Fix the limitations for "smb" in `tramp--test-check-files'.
 ;; * Check, why `tramp-test45-asynchronous-requests' often fails.  The
 ;;   famous reentrant error?
 ;; * Check, why direct async processes do not work for
diff --git a/texi/tramp.texi b/texi/tramp.texi
index 4334e89e65..f53abb5c22 100644
--- a/texi/tramp.texi
+++ b/texi/tramp.texi
@@ -3176,6 +3176,14 @@ connection cleanup or on Emacs exiting.
 @subsection @option{rclone} setup
 @cindex rclone setup
 
+Check, that your @command{rclone} program is compiled with mount
+support.  Call @samp{rclone mount} and check for an error message.
+
+Sometimes, the saved configuration expires.  In this case, you must
+renew it with the command @samp{rclone config reconnect
+@var{remote}:}, with @var{remote} being the name of your configured
+system storage.
+
 The default arguments of the @command{rclone} operations
 @command{mount}, @command{copyto}, @command{moveto} and
 @command{about} are declared in the variable @code{tramp-methods} as
@@ -4438,7 +4446,7 @@ uid=0(root) gid=0(root) groups=0(root)
 
 @anchor{Running a debugger on a remote host}
 @subsection Running a debugger on a remote host
-@cindex @file{gud.el}
+@cindex @file{gud.el} file
 @cindex @code{gdb}
 @cindex @code{perldb}
 
@@ -4489,38 +4497,77 @@ Arguments of the program to be debugged must be 
literal, can take
 relative or absolute paths, but not remote paths.
 
 
+@anchor{Running remote processes on MS Windows hosts}
 @subsection Running remote processes on MS Windows hosts
 @cindex @command{winexe}
 @cindex @command{powershell}
 
-@command{winexe} runs processes on a remote MS Windows host, and
-@value{tramp} can use it for @code{process-file} and
-@code{start-file-process}.
+@strong{Note}: This is an experimental feature.
 
-@code{tramp-smb-winexe-program} specifies the local @command{winexe}
-command.  Powershell V2.0 on the remote host is required to run
-processes triggered from @value{tramp}.
+The program @command{winexe} from the Samba suite runs processes on a
+remote MS Windows host, and @value{tramp} uses it for
+@code{make-process}, @code{process-file} and
+@code{start-file-process}.  It does not work for remote Samba servers.
 
-@code{explicit-shell-file-name} and @code{explicit-*-args} have to
-be set properly so @kbd{M-x shell @key{RET}} can open a proper remote
-shell on a MS Windows host.  To open @command{cmd}, set it as follows:
+@c FIXME: Verify powershell version.
+@vindex tramp-smb-winexe-program
+@code{tramp-smb-winexe-program} specifies the local @command{winexe}
+program.  Powershell V2.0 on the remote MS Windows host is required to
+run processes triggered from @value{tramp}.
+
+@c https://woshub.com/enable-remote-access-to-admin-shares-in-workgroup/
+The remote user on the remote MS Windows host must be member of the
+local computer Administrators group of that remote MS Windows host.
+Since @command{winexe} uses the administrative share @file{ADMIN$} of
+that remote MS Windows host, the remote MS Windows host must be either
+part of an Active Directory domain, or the Remote UAC (User Account
+Control for remote connections) must be disabled.  The latter can be
+achieved by creating the
+@samp{HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\ 
LocalAccountTokenFilterPolicy}
+parameter in the MS Windows registry as DWORD (32-bit) with the value 1.
+
+Check, that the default remote temporary file directory is usable.
+Otherwise, change it, for example (with adapted @t{"user"} and
+@t{"host"}):
 
 @lisp
-@group
-(setq explicit-shell-file-name "cmd"
-      explicit-cmd-args '("/q"))
-@end group
+(add-to-list 'tramp-connection-properties
+             (list (regexp-quote "host")
+                  "tmpdir" "/Users/user/AppData/Local/Temp"))
 @end lisp
 
 @noindent
-To open @command{powershell} as a remote shell, use this:
+@xref{Predefined connection information}.
 
-@lisp
-@group
-(setq explicit-shell-file-name "powershell"
-      explicit-powershell-args '("-file" "-"))
-@end group
-@end lisp
+Redirection from stdin is not supported.
+
+@vindex auto-revert-remote-files
+If you use a remote asynchronous process with a separate error buffer,
+you must ensure that remote files can be auto-reverted.  Set user
+option @code{auto-revert-remote-files} to a non-@code{nil} value.
+
+@vindex tramp-smb-connection-local-powershell-profile
+@vindex tramp-smb-prompt
+@cindex @file{.emacs_powershell} file
+@code{shell} and @code{shell-command} are configured to use
+@command{powershell} on the remote MS Windows host.  If you want to
+change this, consider using another connection-local profile but
+@code{tramp-smb-connection-local-powershell-profile}.
+
+If you run a remote @code{shell}, you might consider to add the
+following line to your local @file{~/.emacs_powershell} file:
+
+@smallexample
+function prompt @{ "PS " + ((Get-Location).Path | Convert-Path) + "> " @}
+@end smallexample
+
+@noindent
+Note, that the configured prompt must match @code{tramp-smb-prompt}.
+
+If you run a remote @code{shell-command}, you must use
+@command{powershell} syntax.  For example, if you want to run a shell
+command from @code{dired}, use the command @t{"(ls * ).Name"} instead
+of @t{"ls"}.
 
 
 @subsection Remote process connection type
@@ -5500,12 +5547,12 @@ Disable excessive traces.  Set @code{tramp-verbose} to 
3 or lower,
 default being 3.  Increase trace levels temporarily when hunting for
 bugs.
 
-@c @item
-@c Use a package with @value{tramp} specific implementation of high-level
-@c operations.  For example, the GNU ELPA package @file{tramp-hlo}
-@c implements specialized versions of @code{dir-locals--all-files},
-@c @code{locate-dominating-file} and @code{dir-locals-find-file} for
-@c @value{tramp}'s @code{tramp-sh} backend (@pxref{New operations}).
+@item
+Use a package with @value{tramp} specific implementation of high-level
+operations.  For example, the GNU ELPA package @file{tramp-hlo}
+implements specialized versions of @code{dir-locals--all-files},
+@code{locate-dominating-file} and @code{dir-locals-find-file} for
+@value{tramp}'s @code{tramp-sh} backend (@pxref{New operations}).
 @end itemize
 
 
@@ -6855,6 +6902,12 @@ Shell scripts intended for the @code{tramp-sh} backend 
are used as a
 format string.  They must observe the restrictions for format
 specifiers, as documented in @code{tramp-expand-script}.
 
+An example implementing this mechanism is the GNU ELPA package
+@file{tramp-hlo}. It implements specialized versions of
+@code{dir-locals--all-files}, @code{locate-dominating-file} and
+@code{dir-locals-find-file} for @value{tramp}'s @code{tramp-sh}
+backend.
+
 
 @node Traces and Profiles
 @chapter How to Customize Traces
diff --git a/texi/trampver.texi b/texi/trampver.texi
index da53b5c62d..ee4d5b2a35 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.5
+@set trampver 2.8.1
 @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-adb.el b/tramp-adb.el
index 5d6c053868..99fcacd8de 100644
--- a/tramp-adb.el
+++ b/tramp-adb.el
@@ -266,11 +266,7 @@ arguments to pass to the OPERATION."
   (with-parsed-tramp-file-name filename nil
     (tramp-convert-file-attributes v localname id-format
       (and
-       (tramp-adb-send-command-and-check
-       v (format "(%s -d -l %s; echo tramp_exit_status $?) | cat"
-                 (tramp-adb-get-ls-command v)
-                 (tramp-shell-quote-argument localname))
-        nil t)
+       (tramp-adb-do-ls v "-d -l" localname)
        (with-current-buffer (tramp-get-buffer v)
         (tramp-adb-sh-fix-ls-output)
         (cdar (tramp-do-parse-file-attributes-with-ls v)))))))
@@ -320,26 +316,21 @@ arguments to pass to the OPERATION."
   (tramp-skeleton-directory-files-and-attributes
       directory full match nosort id-format count
     (with-current-buffer (tramp-get-buffer v)
-      (when (tramp-adb-send-command-and-check
-            v (format "(%s -a -l %s; echo tramp_exit_status $?) | cat"
-                      (tramp-adb-get-ls-command v)
-                      (tramp-shell-quote-argument localname))
-             nil t)
-       ;; We insert also filename/. and filename/.., because "ls"
-       ;; doesn't on some file systems, like "sdcard".
-       (unless (search-backward-regexp (rx "." eol) nil t)
-         (narrow-to-region (point-max) (point-max))
-         (tramp-adb-send-command
-          v (format "%s -d -a -l %s %s | cat"
-                    (tramp-adb-get-ls-command v)
-                    (tramp-shell-quote-argument
-                     (file-name-concat localname "."))
-                    (tramp-shell-quote-argument
-                     (file-name-concat localname ".."))))
-         (replace-regexp-in-region
-          (rx (literal (file-name-unquote (file-name-as-directory localname))))
-          "" (point-min))
-         (widen)))
+      (save-restriction
+       (when (tramp-adb-do-ls v "-a -l" localname)
+         ;; We insert also filename/. and filename/.., because "ls"
+         ;; doesn't on some file systems, like "sdcard".
+         (goto-char (point-max))
+         (unless (search-backward-regexp (rx "." eol) nil t)
+           (narrow-to-region (point-max) (point-max))
+           (when (tramp-adb-do-ls
+                  v "-d -a -l"
+                  (file-name-concat localname ".")
+                  (file-name-concat localname ".."))
+             (replace-regexp-in-region
+              (rx
+               (literal (file-name-unquote (file-name-as-directory 
localname))))
+              "" (point-min))))))
       (tramp-adb-sh-fix-ls-output)
       (tramp-do-parse-file-attributes-with-ls v))))
 
@@ -366,6 +357,24 @@ arguments to pass to the OPERATION."
       "ls --color=never")
      (t "ls"))))
 
+;; "ls" returns exit code 1 for permission problems and alike.  Ignore
+;; those messages.  (Bug#80054)
+(defun tramp-adb-do-ls (vec switches &rest filenames)
+  "Call \"ls\" on a remote adb device with SWITCHES.
+Return non-il if the call was successful.  Ignore return code 1 stderr
+output."
+  (ignore-errors
+    (and-let*
+       ((ret (tramp-adb-send-command-and-check
+              vec (format
+                   "(%s %s %s 2>%s; echo tramp_exit_status $?) | cat"
+                   (tramp-adb-get-ls-command vec) switches
+                   (mapconcat #'tramp-shell-quote-argument filenames " ")
+                   (tramp-get-remote-null-device vec))
+              t t))
+        ((natnump ret))
+        ((<= ret 1))))))
+
 (defun tramp-adb-sh-fix-ls-output (&optional sort-by-time)
   "Insert dummy 0 in empty size columns.
 Android's \"ls\" command doesn't insert size column for directories:
@@ -446,22 +455,17 @@ Emacs dired can't find files."
      filename
      (with-parsed-tramp-file-name (expand-file-name directory) nil
        (with-tramp-file-property v localname "file-name-all-completions"
-        (unless (tramp-adb-send-command-and-check
-                 v (format "(%s -a %s; echo tramp_exit_status $?) | cat"
-                           (tramp-adb-get-ls-command v)
-                           (tramp-shell-quote-argument localname))
-                  nil t)
-          (erase-buffer))
-        (mapcar
-         (lambda (f)
-           (if (file-directory-p (expand-file-name f directory))
-               (file-name-as-directory f)
-             f))
-         (with-current-buffer (tramp-get-buffer v)
-           (mapcar
-            (lambda (l)
-              (and (not (string-match-p (rx bol (* blank) eol) l)) l))
-            (split-string (buffer-string) "\n" 'omit)))))))))
+        (when (tramp-adb-do-ls v "-a" localname)
+          (mapcar
+           (lambda (f)
+             (if (file-directory-p (expand-file-name f directory))
+                 (file-name-as-directory f)
+               f))
+           (with-current-buffer (tramp-get-buffer v)
+             (mapcar
+              (lambda (l)
+                (and (not (string-match-p (rx bol (* blank) eol) l)) l))
+              (split-string (buffer-string) "\n" 'omit))))))))))
 
 (defun tramp-adb-handle-file-local-copy (filename)
   "Like `file-local-copy' for Tramp files."
@@ -756,6 +760,7 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
              (with-current-buffer outbuf
                (insert-buffer-substring (tramp-get-connection-buffer v)))
              (when (and display (get-buffer-window outbuf t)) (redisplay))))
+
        ;; When the user did interrupt, we should do it also.  We use
        ;; return code -1 as marker.
        (quit
diff --git a/tramp-sh.el b/tramp-sh.el
index 5ed3e91da2..488f7e4919 100644
--- a/tramp-sh.el
+++ b/tramp-sh.el
@@ -3369,6 +3369,7 @@ will be used."
                 (insert
                 (tramp-get-buffer-string (tramp-get-connection-buffer v))))
              (when (and display (get-buffer-window outbuf t)) (redisplay))))
+
        ;; When the user did interrupt, we should do it also.  We use
        ;; return code -1 as marker.
        (quit
@@ -5229,7 +5230,7 @@ If there is a modified buffer, retry it after 60 seconds."
        (and-let* (((or (buffer-modified-p buf)
                       (with-current-buffer buf
                         ;; We don't know whether autorevert.el has
-                        ;; been loaded alreaddy.
+                        ;; been loaded already.
                         (tramp-compat-funcall 'auto-revert-active-p))))
                  (bfn (buffer-file-name buf))
                  (v (tramp-ensure-dissected-file-name bfn))
diff --git a/tramp-smb.el b/tramp-smb.el
index fdda945f12..2013c3980d 100644
--- a/tramp-smb.el
+++ b/tramp-smb.el
@@ -239,6 +239,7 @@ See `tramp-actions-before-shell' for more info.")
      . tramp-handle-directory-files-and-attributes)
     (dired-compress-file . ignore)
     (dired-uncache . tramp-handle-dired-uncache)
+    ;; TODO: Add implementation.
     (exec-path . ignore)
     (expand-file-name . tramp-smb-handle-expand-file-name)
     (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
@@ -286,7 +287,7 @@ See `tramp-actions-before-shell' for more info.")
     (make-directory-internal . ignore)
     (make-lock-file-name . tramp-handle-make-lock-file-name)
     (make-nearby-temp-file . tramp-handle-make-nearby-temp-file)
-    (make-process . ignore)
+    (make-process . tramp-smb-handle-make-process)
     (make-symbolic-link . tramp-smb-handle-make-symbolic-link)
     (memory-info . ignore)
     (process-attributes . ignore)
@@ -297,8 +298,8 @@ See `tramp-actions-before-shell' for more info.")
     (set-file-selinux-context . ignore)
     (set-file-times . tramp-smb-handle-set-file-times)
     (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
-    (shell-command . tramp-handle-shell-command)
-    (start-file-process . tramp-smb-handle-start-file-process)
+    (shell-command . tramp-smb-handle-shell-command)
+    (start-file-process . tramp-handle-start-file-process)
     (substitute-in-file-name . tramp-smb-handle-substitute-in-file-name)
     (temporary-file-directory . tramp-handle-temporary-file-directory)
     (tramp-get-home-directory . tramp-smb-handle-get-home-directory)
@@ -1266,6 +1267,121 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
     (unless (file-directory-p dir)
       (tramp-error v 'file-error "Couldn't make directory %s" dir))))
 
+(defvar tramp-smb-matching-line nil
+  "Regexp to delete from current buffer.")
+
+(defun tramp-smb-delete-matching-lines (string)
+  "Delete matching lines in current buffer.
+Remove this function from `comint-preoutput-filter-functions'."
+  (save-excursion
+    (goto-char (point-min))
+    (unless
+       (zerop (delete-matching-lines tramp-smb-matching-line))
+      (setq tramp-smb-matching-line nil)
+      (remove-hook 'comint-preoutput-filter-functions
+                  #'tramp-smb-delete-matching-lines 'local))
+    string))
+
+;; We use BUFFER also as connection buffer during setup.  Because of
+;; this, its original contents must be saved, and restored once
+;; connection has been setup.
+(defun tramp-smb-handle-make-process (&rest args)
+  "Like `make-process' for Tramp files.
+If method parameter `tramp-direct-async' and connection-local variable
+`tramp-direct-async-process' are non-nil, an alternative implementation
+will be used."
+  (if (tramp-direct-async-process-p args)
+      (apply #'tramp-handle-make-process args)
+    (tramp-skeleton-make-process args nil t
+      (let* ((command (string-join command " "))
+            ;; STDERR can also be a file name.
+            (tmpstderr
+             (and stderr
+                  (tramp-unquote-file-local-name
+                   (if (stringp stderr)
+                       stderr (tramp-make-tramp-temp-name v)))))
+            (remote-tmpstderr
+             (and tmpstderr (tramp-make-tramp-file-name v tmpstderr)))
+            (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
+            p)
+       (if tmpstderr
+           (setq command (format "%s 2>//%s%s" command host tmpstderr)))
+
+       ;; Handle error buffer.
+       (when (bufferp stderr)
+         (make-empty-file remote-tmpstderr)
+         (with-current-buffer stderr
+           (setq buffer-read-only nil
+                 default-directory (file-name-directory remote-tmpstderr))
+           (setq-local buffer-file-name remote-tmpstderr
+                       auto-revert-notify-exclude-dir-regexp
+                       "nothing-to-be-excluded"
+                       create-lockfiles t)
+           (set-visited-file-modtime)
+           (set-buffer-modified-p nil)
+           (auto-save-mode -1)
+           (auto-save-visited-mode -1)
+           (auto-revert-tail-mode 1)))
+
+       (with-tramp-saved-connection-properties
+           v '(" process-name" " process-buffer")
+         (unwind-protect
+             (save-excursion
+               (save-restriction
+                 ;; Set the new process properties.
+                 (tramp-set-connection-property v " process-name" name)
+                 (tramp-set-connection-property v " process-buffer" buffer)
+                 ;; Activate narrowing in order to save BUFFER contents.
+                 (with-current-buffer (tramp-get-connection-buffer v)
+                   (let ((buffer-undo-list t))
+                     (narrow-to-region (point-max) (point-max))
+                     (tramp-smb-call-winexe v)
+                     (tramp-message v 6 "%s" command)
+                     (tramp-send-string v command)
+                     (setq
+                      tramp-smb-matching-line (rx bol (literal command) eol))
+                     (add-hook 'comint-preoutput-filter-functions
+                               #'tramp-smb-delete-matching-lines nil 'local)))
+                 (setq p (tramp-get-connection-process v))
+                 ;; Set sentinel and filter.
+                 (when sentinel
+                   (set-process-sentinel p sentinel))
+                 (when filter
+                   (set-process-filter p filter))
+                 (process-put p 'remote-command orig-command)
+                 ;; Set query flag and process marker for this
+                 ;; process.  We ignore errors, because the process
+                 ;; could have finished already.
+                 (ignore-errors
+                   (set-process-query-on-exit-flag p (null noquery))
+                   (set-marker (process-mark p) (point)))
+                 ;; We must flush them here already; otherwise
+                 ;; `delete-file' will fail.
+                 (tramp-flush-connection-property v " process-name")
+                 (tramp-flush-connection-property v " process-buffer")
+                 ;; Stop auto-revert.  Delete stderr file.
+                 (when (bufferp stderr)
+                   (add-function
+                    :after (process-sentinel p)
+                    (lambda (_proc _msg)
+                      (with-current-buffer stderr
+                        (auto-revert-tail-mode -1)
+                        (let ((remote-file-name-inhibit-locks t))
+                          (revert-buffer nil 'noconfirm)))
+                      (ignore-errors
+                        (delete-file remote-tmpstderr)))))
+                 ;; Return value.
+                 p))
+
+           ;; Save exit.
+           ;; FIXME: Does `tramp-get-connection-buffer' return the proper 
value?
+           (with-current-buffer (tramp-get-connection-buffer v)
+             (if (string-search tramp-temp-buffer-name (buffer-name))
+                 (progn
+                   (set-process-buffer (tramp-get-connection-process v) nil)
+                   (kill-buffer (current-buffer)))
+               (set-buffer-modified-p bmp)))))))))
+
 (defun tramp-smb-handle-make-symbolic-link
     (target linkname &optional ok-if-already-exists)
   "Like `make-symbolic-link' for Tramp files."
@@ -1286,120 +1402,66 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
 (defun tramp-smb-handle-process-file
   (program &optional infile destination display &rest args)
   "Like `process-file' for Tramp files."
-  ;; The implementation is not complete yet.
-  (when (and (numberp destination) (zerop destination))
-    (error "Implementation does not handle immediate return"))
-
-  (with-parsed-tramp-file-name (expand-file-name default-directory) nil
-    (let* ((name (file-name-nondirectory program))
-          (name1 name)
-          (i 0)
-          input tmpinput outbuf command ret)
-
-      ;; Determine input.
-      (when infile
-       (setq infile (file-name-unquote (expand-file-name infile)))
-       (if (tramp-equal-remote default-directory infile)
-           ;; INFILE is on the same remote host.
-           (setq input (tramp-unquote-file-local-name infile))
-         ;; INFILE must be copied to remote host.
-         (setq input (tramp-make-tramp-temp-file v)
-               tmpinput (tramp-make-tramp-file-name v input))
-         (copy-file infile tmpinput t))
-       ;; Transform input into a filename powershell does understand.
-       (setq input (format "//%s%s" host input)))
-
-      ;; Determine output.
-      (cond
-       ;; Just a buffer.
-       ((bufferp destination)
-       (setq outbuf destination))
-       ;; A buffer name.
-       ((stringp destination)
-       (setq outbuf (get-buffer-create destination)))
-       ;; (REAL-DESTINATION ERROR-DESTINATION)
-       ((consp destination)
-       ;; output.
-       (cond
-        ((bufferp (car destination))
-         (setq outbuf (car destination)))
-        ((stringp (car destination))
-         (setq outbuf (get-buffer-create (car destination))))
-        ((car destination)
-         (setq outbuf (current-buffer))))
-       ;; stderr.
-       (tramp-warning v "%s" "STDERR not supported"))
-       ;; 't
-       (destination
-       (setq outbuf (current-buffer))))
+  (tramp-skeleton-process-file program infile destination display args
+    (let ((name
+          (string-replace "*tramp" "*tramp process" (tramp-buffer-name v))))
+      ;; Transform input and stderr into a filename powershell does understand.
+      (when input
+       (setq input
+             (and (not (string-equal input (tramp-get-remote-null-device v)))
+                  (format
+                   "//%s%s" host (tramp-smb-shell-quote-argument input)))))
+      (when stderr
+       (setq stderr
+             (and (not (string-equal stderr (tramp-get-remote-null-device v)))
+                  (format
+                   "//%s%s" host (tramp-smb-shell-quote-argument stderr)))))
 
       ;; Construct command.
       (setq command (string-join (cons program args) " ")
+           command (if stderr
+                       (format "%s 2>%s" command stderr)
+                     command)
            command (if input
-                       (format
-                        "get-content %s | & %s"
-                        (tramp-smb-shell-quote-argument input) command)
-                     (format "& %s" command)))
-
-      (while (get-process name1)
-       ;; NAME must be unique as process name.
-       (setq i (1+ i)
-             name1 (format "%s<%d>" name i)))
+                       (format "Get-Content %s | & %s" input command)
+                     command))
 
       ;; Call it.
       (condition-case nil
          (with-tramp-saved-connection-properties
              v '(" process-name" " process-buffer")
            ;; Set the new process properties.
-           (tramp-set-connection-property v " process-name" name1)
+           (tramp-set-connection-property v " process-name" name)
            (tramp-set-connection-property
-            v " process-buffer"
-            (or outbuf (generate-new-buffer tramp-temp-buffer-name)))
-           (tramp-flush-connection-property v " process-exit-status")
+            ;; v " process-buffer"
+            ;; (or outbuf (generate-new-buffer tramp-temp-buffer-name)))
+            v " process-buffer" (generate-new-buffer tramp-temp-buffer-name))
            (with-current-buffer (tramp-get-connection-buffer v)
              ;; Preserve buffer contents.
              (narrow-to-region (point-max) (point-max))
              (tramp-smb-call-winexe v)
-             (when (tramp-smb-get-share v)
-               (tramp-smb-send-command
-                v (format "cd //%s%s" host
-                          (tramp-smb-shell-quote-argument
-                           (file-name-directory localname)))))
-             (tramp-smb-send-command v command)
-             ;; Preserve command output.
-             (narrow-to-region (point-max) (point-max))
-             (let ((p (tramp-get-connection-process v)))
-               (tramp-smb-send-command v "exit $lasterrorcode")
-               (while (process-live-p p)
-                 (sleep-for 0.1)
-                 (setq ret (process-exit-status p))))
-             (delete-region (point-min) (point-max))
-             (widen)))
+             (tramp-flush-connection-property v " process-exit-status")
+             (tramp-smb-send-command
+              v (format "%s; exit -not $?" command))
+             (while (not (setq ret (tramp-get-connection-property
+                                    v " process-exit-status")))
+               (sleep-for 0.1))
+             (unless (natnump ret) (setq ret 1))
+             ;; We should add the output anyway.
+             (when outbuf
+               (with-current-buffer outbuf
+                 (insert-buffer-substring (tramp-get-connection-buffer v)))
+               (when (and display (get-buffer-window outbuf t)) (redisplay)))))
 
        ;; When the user did interrupt, we should do it also.  We use
        ;; return code -1 as marker.
        (quit
+        (kill-buffer (tramp-get-connection-buffer v))
         (setq ret -1))
        ;; Handle errors.
        (error
-        (setq ret 1)))
-
-      ;; We should redisplay the output.
-      (when (and display outbuf (get-buffer-window outbuf t)) (redisplay))
-
-      ;; Cleanup.  We remove all file cache values for the connection,
-      ;; because the remote process could have changed them.
-      (when tmpinput (delete-file tmpinput))
-      ;; FIXME: Does connection-property " process-buffer" still exist?
-      (unless outbuf
-       (kill-buffer (tramp-get-connection-property v " process-buffer")))
-      (when process-file-side-effects
-       (tramp-flush-directory-properties v "/"))
-
-      ;; Return exit status.
-      (if (equal ret -1)
-         (keyboard-quit)
-       ret))))
+        (kill-buffer (tramp-get-connection-buffer v))
+        (setq ret 1))))))
 
 (defun tramp-smb-handle-rename-file
   (filename newname &optional ok-if-already-exists)
@@ -1543,62 +1605,18 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
         (tramp-smb-shell-quote-localname v)
         (format-time-string "%Y:%m:%d-%H:%M:%S" (tramp-defined-time time))))))
 
-;; We use BUFFER also as connection buffer during setup.  Because of
-;; this, its original contents must be saved, and restored once
-;; connection has been setup.
-(defun tramp-smb-handle-start-file-process (name buffer program &rest args)
-  "Like `start-file-process' for Tramp files."
-  (with-parsed-tramp-file-name default-directory nil
-    (let* ((buffer
-           (if buffer
-               (get-buffer-create buffer)
-             ;; BUFFER can be nil.  We use a temporary buffer.
-             (generate-new-buffer tramp-temp-buffer-name)))
-          (command (string-join (cons program args) " "))
-          (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer)))
-          (name1 name)
-          (i 0)
-          p)
-      (unwind-protect
-         (with-tramp-saved-connection-properties
-             v '(" process-name" " process-buffer")
-           (save-excursion
-             (save-restriction
-               (while (get-process name1)
-                 ;; NAME must be unique as process name.
-                 (setq i (1+ i)
-                       name1 (format "%s<%d>" name i)))
-               ;; Set the new process properties.
-               (tramp-set-connection-property v " process-name" name1)
-               (tramp-set-connection-property v " process-buffer" buffer)
-               ;; Activate narrowing in order to save BUFFER contents.
-               (with-current-buffer (tramp-get-connection-buffer v)
-                 (let ((buffer-undo-list t))
-                   (narrow-to-region (point-max) (point-max))
-                   (tramp-smb-call-winexe v)
-                   (when (tramp-smb-get-share v)
-                     (tramp-smb-send-command
-                      v (format
-                         "cd //%s%s"
-                         host
-                         (tramp-smb-shell-quote-argument
-                          (file-name-directory localname)))))
-                   (tramp-message v 6 "(%s); exit" command)
-                   (tramp-send-string v command)))
-               (setq p (tramp-get-connection-process v))
-               (when program
-                 (process-put p 'remote-command (cons program args)))
-               ;; Return value.
-               p)))
-
-       ;; Save exit.
-       ;; FIXME: Does `tramp-get-connection-buffer' return the proper value?
-       (with-current-buffer (tramp-get-connection-buffer v)
-         (if (string-search tramp-temp-buffer-name (buffer-name))
-             (progn
-               (set-process-buffer (tramp-get-connection-process v) nil)
-               (kill-buffer (current-buffer)))
-           (set-buffer-modified-p bmp)))))))
+(defun tramp-smb-handle-shell-command
+    (command &optional output-buffer error-buffer)
+  "Like `shell-command' for Tramp files."
+
+  (let* (;; "& wait" is added by `dired-shell-stuff-it'.
+        (asynchronous
+         (string-match-p
+          (rx (? (* blank) "& wait") (* blank) "&" (* blank) eos) command))
+        (command (substring command 0 asynchronous))
+        (command (string-join `("\"" "&" "{" ,command "}" "\"") " "))
+        (command (if asynchronous (concat command "; exit &") command)))
+    (tramp-handle-shell-command command output-buffer error-buffer)))
 
 (defun tramp-smb-handle-substitute-in-file-name (filename)
   "Like `substitute-in-file-name' for Tramp files.
@@ -1661,25 +1679,28 @@ VEC or USER, or if there is no home directory, return 
nil."
       (when (string-match (rx bol (? "/") (group (+ (not "/"))) "/") localname)
        (match-string 1 localname)))))
 
-(defun tramp-smb-get-localname (vec)
+(defun tramp-smb-get-localname (vec &optional share)
   "Return the file name of LOCALNAME.
+If SHARE is non-nil, include the share name.
 If VEC has no cifs capabilities, exchange \"/\" by \"\\\\\"."
   (save-match-data
     (let ((localname (tramp-file-name-unquote-localname vec)))
-      (setq
-       localname
-       (if (string-match
-           (rx bol (? "/") (+ (not "/")) (group "/" (* nonl))) localname)
-          ;; There is a share, separated by "/".
-          (if (not (tramp-smb-get-cifs-capabilities vec))
-              (mapconcat
-               (lambda (x) (if (equal x ?/) "\\" (char-to-string x)))
-               (match-string 1 localname) "")
-            (match-string 1 localname))
-        ;; There is just a share.
-        (if (string-match (rx bol (? "/") (group (+ (not "/"))) eol) localname)
-            (match-string 1 localname)
-          "")))
+      (unless share
+       (setq
+        localname
+        (if (string-match
+             (rx bol (? "/") (+ (not "/")) (group "/" (* nonl))) localname)
+            ;; There is a share, separated by "/".
+            (if (not (tramp-smb-get-cifs-capabilities vec))
+                (mapconcat
+                 (lambda (x) (if (equal x ?/) "\\" (char-to-string x)))
+                 (match-string 1 localname) "")
+              (match-string 1 localname))
+          ;; There is just a share.
+          (if (string-match
+               (rx bol (? "/") (group (+ (not "/"))) eol) localname)
+              (match-string 1 localname)
+            ""))))
 
       ;; Sometimes we have discarded `substitute-in-file-name'.
       (when (string-match (rx (group "$$") (| "/" eol)) localname)
@@ -1939,7 +1960,13 @@ function waits for output unless NOOUTPUT is set."
   (tramp-smb-maybe-open-connection vec)
   (tramp-message vec 6 "%s" command)
   (tramp-send-string vec command)
-  (unless nooutput (tramp-smb-wait-for-output vec)))
+  (unless nooutput
+    (prog1
+       (tramp-smb-wait-for-output vec)
+      (with-current-buffer (tramp-get-connection-buffer vec)
+       (save-excursion
+         (goto-char (point-min))
+         (delete-matching-lines (rx bol (literal command) eol)))))))
 
 (defun tramp-smb-maybe-open-connection (vec &optional argument)
   "Maybe open a connection to HOST, log in as USER, using `tramp-smb-program'.
@@ -2047,6 +2074,11 @@ If ARGUMENT is non-nil, use it as argument for
 
              (let* (coding-system-for-read
                     (process-connection-type tramp-process-connection-type)
+                    ;; There might be some unfortunate values of
+                     ;; `tramp-smb-connection-local-default-system-variables'.
+                     ;(path-separator (default-value 'path-separator))
+                     ;(null-device (default-value 'null-device))
+                     ;(exec-suffixes (default-value 'exec-suffixes))
                     (p (apply #'tramp-start-process vec
                               (tramp-get-connection-name vec)
                               (tramp-get-connection-buffer vec)
@@ -2054,6 +2086,10 @@ If ARGUMENT is non-nil, use it as argument for
                                   tramp-smb-winexe-program tramp-smb-program)
                               args)))
 
+               ;; Set sentinel.  Initialize variables.
+               (set-process-sentinel p #'tramp-process-sentinel)
+               (setq tramp-current-connection (cons vec (current-time)))
+
                ;; Set connection-local variables.
                (tramp-set-connection-local-variables vec)
 
@@ -2104,7 +2140,9 @@ Removes smb prompt.  Returns nil if an error message has 
appeared."
          (inhibit-read-only t))
 
       ;; Read pending output.
-      (while (not (search-forward-regexp tramp-smb-prompt nil t))
+      (tramp-accept-process-output p)
+      (while (and (process-live-p p)
+                 (not (search-forward-regexp tramp-smb-prompt nil t)))
        (while (tramp-accept-process-output p))
        (goto-char (point-min)))
       (tramp-message vec 6 "%S\n%s" p (buffer-string))
@@ -2138,6 +2176,10 @@ Removes smb prompt.  Returns nil if an error message has 
appeared."
   (when (tramp-file-name-port vec)
     (tramp-error vec 'file-error "Port not supported for remote processes"))
 
+  ;; Check share.
+  (unless (tramp-smb-get-share vec)
+    (tramp-error vec 'file-error "Default directory must contain a share."))
+
   ;; In case of "NT_STATUS_RPC_SS_CONTEXT_MISMATCH", the remote server
   ;; is a Samba server.  winexe cannot install the respective service there.
   (tramp-smb-maybe-open-connection
@@ -2150,26 +2192,29 @@ Removes smb prompt.  Returns nil if an error message 
has appeared."
 
   ;; Suppress "^M".  Shouldn't we specify utf8?
   (set-process-coding-system (tramp-get-connection-process vec) 'raw-text-dos)
-
-  ;; Set width to 128 ($bufsize.Width) or 102 ($winsize.Width),
-  ;; respectively.  $winsize.Width cannot be larger.  This avoids
-  ;; mixing prompt and long error messages.
+  ;; Enable UTF-8 encoding.  Suppress "^M".
+  ;; (set-process-coding-system (tramp-get-connection-process vec) 'utf-8-dos)
+  ;; (tramp-smb-send-command vec "$PSDefaultParameterValues['*:Encoding'] = 
'utf8'")
+  ;; This avoids mixing prompt and long error messages.
   (tramp-smb-send-command vec "$rawui = (Get-Host).UI.RawUI")
-  (tramp-smb-send-command vec "$bufsize = $rawui.BufferSize")
-  (tramp-smb-send-command vec "$winsize = $rawui.WindowSize")
-  (tramp-smb-send-command vec "$bufsize.Width = 128")
-  (tramp-smb-send-command vec "$winsize.Width = 102")
-  (tramp-smb-send-command vec "$rawui.BufferSize = $bufsize")
-  (tramp-smb-send-command vec "$rawui.WindowSize = $winsize"))
+  (tramp-smb-send-command vec "$rawui.WindowSize = $rawui.MaxWindowSize")
+  (tramp-smb-send-command vec "$rawui.BufferSize.Width = 1024")
+  ;; Goto `default-directory'.
+  (tramp-smb-send-command
+   vec (format
+       "cd //%s%s"
+       (tramp-file-name-host vec)
+       (tramp-smb-shell-quote-localname vec 'share))))
 
 (defun tramp-smb-shell-quote-argument (s)
   "Similar to `shell-quote-argument', but uses Windows cmd syntax."
   (let ((system-type 'ms-dos))
     (tramp-unquote-shell-quote-argument s)))
 
-(defun tramp-smb-shell-quote-localname (vec)
-  "Call `tramp-smb-shell-quote-argument' on localname of VEC."
-  (tramp-smb-shell-quote-argument (tramp-smb-get-localname vec)))
+(defun tramp-smb-shell-quote-localname (vec &optional share)
+  "Call `tramp-smb-shell-quote-argument' on localname of VEC.
+SHARE will be passed to the call of `tramp-smb-get-localname'."
+  (tramp-smb-shell-quote-argument (tramp-smb-get-localname vec share)))
 
 ;;; Default connection-local variables for Tramp.
 
@@ -2194,6 +2239,57 @@ Removes smb prompt.  Returns nil if an error message has 
appeared."
  `(:application tramp :protocol ,tramp-smb-method)
  'tramp-smb-connection-local-default-system-profile)
 
+;; (defconst tramp-smb-connection-local-bash-variables
+;;   '((explicit-shell-file-name . "bash")
+;;     (explicit-bash-args . ("--norc" "--noediting" "-i"))
+;;     (shell-file-name . "bash")
+;;     (shell-command-switch . "-c"))
+;;   "Default connection-local bash variables for remote smb connections.")
+
+;; (connection-local-set-profile-variables
+;;  'tramp-smb-connection-local-bash-profile
+;;  tramp-smb-connection-local-bash-variables)
+
+(defconst tramp-smb-connection-local-powershell-variables
+  `((explicit-shell-file-name . "powershell")
+    (explicit-powershell-args . ("-file" "-"))
+    (shell-file-name . "powershell")
+    (shell-command-switch . "-command")
+    (shell-history-file-name . t))
+  "Default connection-local powershell variables for remote smb connections.")
+
+(connection-local-set-profile-variables
+ 'tramp-smb-connection-local-powershell-profile
+ tramp-smb-connection-local-powershell-variables)
+
+(defun tramp-smb-shell-prompt ()
+  "Set `comint-prompt-regexp' to a proper value."
+  ;; Used for remote `shell-mode' buffers.
+  (when (tramp-smb-file-name-p default-directory)
+    (setq-local comint-prompt-regexp tramp-smb-prompt)))
+
+;; (defconst tramp-smb-connection-local-cmd-variables
+;;   '((explicit-shell-file-name . "cmd")
+;;     (explicit-cmd-args . ("/Q"))
+;;     (shell-file-name . "cmd")
+;;     (shell-command-switch . "/C"))
+;;   "Default connection-local cmd variables for remote smb connections.")
+
+;; (connection-local-set-profile-variables
+;;  'tramp-smb-connection-local-cmd-profile
+;;  tramp-smb-connection-local-cmd-variables)
+
+(with-eval-after-load 'shell
+  (connection-local-set-profiles
+   `(:application tramp :protocol ,tramp-smb-method)
+   'tramp-smb-connection-local-powershell-profile)
+  (add-hook 'shell-mode-hook
+           #'tramp-smb-shell-prompt)
+  (add-hook 'tramp-smb-unload-hook
+           (lambda ()
+             (remove-hook 'shell-mode-hook
+                          #'tramp-smb-shell-prompt))))
+
 (add-hook 'tramp-unload-hook
          (lambda ()
            (unload-feature 'tramp-smb 'force)))
diff --git a/tramp-sshfs.el b/tramp-sshfs.el
index cbc083a1fe..6e59a877e1 100644
--- a/tramp-sshfs.el
+++ b/tramp-sshfs.el
@@ -253,7 +253,7 @@ arguments to pass to the OPERATION."
 (defun tramp-sshfs-handle-process-file
   (program &optional infile destination display &rest args)
   "Like `process-file' for Tramp files."
-  ;; STDERR is not impelmemted.
+  ;; STDERR is not implemented.
   (when (consp destination)
     (setcdr destination `(,tramp-cache-undefined)))
   (tramp-skeleton-process-file program infile destination display args
diff --git a/tramp.el b/tramp.el
index 82a0953ecb..1866c7dad6 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.5
+;; Version: 2.8.1
 ;; Package-Requires: ((emacs "28.1"))
 ;; Package-Type: multi
 ;; URL: https://www.gnu.org/software/tramp/
@@ -785,7 +785,7 @@ The regexp should match at end of buffer."
         "Place your finger on the reader again"
         "Swipe your finger again"
         "Swipe was too short, try again"
-        "Your finger was not centred, try swiping your finger again"
+        "Your finger was not centered, try swiping your finger again"
         "Remove your finger, and try swiping your finger again")
       (* nonl) (* (any "\r\n")))
   "Regexp matching fingerprint prompts.
@@ -2545,7 +2545,7 @@ Must be handled by the callers."
       res)))
 
 (defun tramp-add-external-operation (operation function backend)
-  "Add FUNTION to Tramp BACKEND as handler for OPERATION.
+  "Add FUNCTION to Tramp BACKEND as handler for OPERATION.
 OPERATION must not be one of the magic operations listed in Info
 node `(elisp) Magic File Names'.  FUNCTION must have the same argument
 list as OPERATION.  BACKEND, a symbol, must be one of the Tramp backend
@@ -2922,7 +2922,9 @@ not in completion mode."
   ;; check, whether DIRECTORY is "/method:" or "/[method/".
   (let ((dir (or directory default-directory "/")))
     (cond
-     ((file-name-absolute-p filename) filename)
+     ((file-name-absolute-p filename)
+      ;; FILENAME could be like "~/".  We must expand this.
+      (tramp-run-real-handler #'expand-file-name (list filename directory)))
      ((and (eq tramp-syntax 'simplified)
            (string-match-p (rx (regexp tramp-postfix-host-regexp) eos) dir))
       (concat dir filename))
@@ -3821,8 +3823,8 @@ BODY is the backend specific code."
 
 (defmacro tramp-skeleton-make-process (args null-command stderr-file &rest 
body)
   "Skeleton for `tramp-*-handle-make-process'.
-NULL-COMMAND indicates a possible empty command.  STDERR-FILE means,
-that a stederr file is supported.  BODY is the backend specific code."
+NULL-COMMAND indicates a possible empty command.  STDERR-FILE means
+that a stderr file is supported.  BODY is the backend specific code."
   (declare (indent 3) (debug t))
   `(when ,args
      (with-parsed-tramp-file-name (expand-file-name default-directory) nil
@@ -3978,7 +3980,7 @@ BODY is the backend specific code."
          ((null (cadr ,destination))
           (setq stderr (tramp-get-remote-null-device v)))
          ((eq (cadr ,destination) tramp-cache-undefined)
-          ;; stderr is not impelmemted.
+          ;; stderr is not implemented.
           (tramp-warning v "%s" "STDERR not supported"))))
        ;; t
        (,destination
diff --git a/trampver.el b/trampver.el
index 71bb71f0ae..51e04e0a1c 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.5
+;; Version: 2.8.1
 ;; 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.5"
+(defconst tramp-version "2.8.1"
   "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.5 is not fit for %s"
+    (format "Tramp 2.8.1 is not fit for %s"
             (replace-regexp-in-string "\n" "" (emacs-version))))))
   (unless (string-equal "ok" x) (error "%s" x)))
 

Reply via email to