emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/tramp 851269d 2/2: Tramp ELPA version 2.5.0.3 released


From: Michael Albinus
Subject: [elpa] externals/tramp 851269d 2/2: Tramp ELPA version 2.5.0.3 released
Date: Tue, 30 Mar 2021 06:22:46 -0400 (EDT)

branch: externals/tramp
commit 851269dcfd7a564894ba4d4c2c7da8a97b40ce62
Author: Michael Albinus <michael.albinus@gmx.de>
Commit: Michael Albinus <michael.albinus@gmx.de>

    Tramp ELPA version 2.5.0.3 released
---
 test/tramp-tests.el  |  84 ++++++-----
 texi/tramp.texi      | 303 ++++++++++++++++++++++++++++----------
 texi/trampver.texi   |   2 +-
 tramp-adb.el         |   2 -
 tramp-cache.el       |  28 ++--
 tramp-cmds.el        |  17 ++-
 tramp-compat.el      |   2 +-
 tramp-crypt.el       |  24 +++
 tramp-fuse.el        | 205 ++++++++++++++++++++++++++
 tramp-gvfs.el        |   1 -
 tramp-integration.el |  24 ++-
 tramp-rclone.el      | 189 ++----------------------
 tramp-sh.el          | 404 ++++++++++++++-------------------------------------
 tramp-smb.el         |   7 -
 tramp-sshfs.el       | 367 ++++++++++++++++++++++++++++++++++++++++++++++
 tramp-sudoedit.el    |  22 +--
 tramp.el             | 164 ++++++++++++++++-----
 trampver.el          |   6 +-
 18 files changed, 1187 insertions(+), 664 deletions(-)

diff --git a/test/tramp-tests.el b/test/tramp-tests.el
index 719e97d..3189fa1 100644
--- a/test/tramp-tests.el
+++ b/test/tramp-tests.el
@@ -2824,9 +2824,10 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
          (should (file-exists-p (expand-file-name "bla" tmp-name2)))
          (should-error
           (delete-directory tmp-name1 nil 'trash)
-          ;; tramp-rclone.el calls the local `delete-directory'.
-          ;; This raises another error.
-          :type (if (tramp--test-rclone-p) 'error 'file-error))
+          ;; tramp-rclone.el and tramp-sshfs.el call the local
+          ;; `delete-directory'.  This raises another error.
+          :type (if (or (tramp--test-rclone-p) (tramp--test-sshfs-p))
+                    'error 'file-error))
          (delete-directory tmp-name1 'recursive 'trash)
          (should-not (file-directory-p tmp-name1))
          (should
@@ -3254,8 +3255,8 @@ This tests also `file-directory-p' and 
`file-accessible-directory-p'."
        (ignore-errors (delete-directory tmp-name1 'recursive))))))
 
 ;; Method "smb" supports `make-symbolic-link' only if the remote host
-;; has CIFS capabilities.  tramp-adb.el, tramp-gvfs.el and
-;; tramp-rclone.el do not support symbolic links at all.
+;; has CIFS capabilities.  tramp-adb.el, tramp-gvfs.el, tramp-rclone.el
+;; and tramp-sshfs.el do not support symbolic links at all.
 (defmacro tramp--test-ignore-make-symbolic-link-error (&rest body)
   "Run BODY, ignoring \"make-symbolic-link not supported\" file error."
   (declare (indent defun) (debug (body)))
@@ -3536,7 +3537,7 @@ They might differ only in time attributes or directory 
size."
 This tests also `file-executable-p', `file-writable-p' and `set-file-modes'."
   (skip-unless (tramp--test-enabled))
   (skip-unless
-   (or (tramp--test-sh-p) (tramp--test-sudoedit-p)
+   (or (tramp--test-sh-p) (tramp--test-sshfs-p) (tramp--test-sudoedit-p)
        ;; Not all tramp-gvfs.el methods support changing the file mode.
        (and
        (tramp--test-gvfs-p)
@@ -4367,11 +4368,15 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
          (and (featurep 'tramp-test-load) (unload-feature 'tramp-test-load))
          (delete-file tmp-name))))))
 
+(defun tramp--test-shell-file-name ()
+  "Return default remote shell.."
+  (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh"))
+
 (ert-deftest tramp-test28-process-file ()
   "Check `process-file'."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-crypt-p)))
 
   (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
@@ -4388,25 +4393,27 @@ This tests also `make-symbolic-link', `file-truename' 
and `add-name-to-file'."
            (should-not (zerop (process-file "binary-does-not-exist")))
            ;; Return exit code.
            (should (= 42 (process-file
-                          (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh")
+                          (tramp--test-shell-file-name)
                           nil nil nil "-c" "exit 42")))
            ;; Return exit code in case the process is interrupted,
            ;; and there's no indication for a signal describing string.
-           (let (process-file-return-signal-string)
-             (should
-              (= (+ 128 2)
-                 (process-file
-                  (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh")
-                  nil nil nil "-c" "kill -2 $$"))))
+           (unless (tramp--test-sshfs-p)
+             (let (process-file-return-signal-string)
+               (should
+                (= (+ 128 2)
+                   (process-file
+                    (tramp--test-shell-file-name)
+                    nil nil nil "-c" "kill -2 $$")))))
            ;; Return string in case the process is interrupted and
            ;; there's an indication for a signal describing string.
-           (let ((process-file-return-signal-string t))
-             (should
-              (string-match-p
-               "Interrupt\\|Signal 2"
-               (process-file
-                (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh")
-                nil nil nil "-c" "kill -2 $$"))))
+           (unless (tramp--test-sshfs-p)
+             (let ((process-file-return-signal-string t))
+               (should
+                (string-match-p
+                 "Interrupt\\|Signal 2"
+                 (process-file
+                  (tramp--test-shell-file-name)
+                  nil nil nil "-c" "kill -2 $$")))))
 
            (with-temp-buffer
              (write-region "foo" nil tmp-name)
@@ -4450,7 +4457,7 @@ This tests also `make-symbolic-link', `file-truename' and 
`add-name-to-file'."
   "Check `start-file-process'."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-crypt-p)))
 
   (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
@@ -4570,7 +4577,7 @@ If UNSTABLE is non-nil, the test is tagged as 
`:unstable'."
   "Check `make-process'."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-crypt-p)))
   ;; `make-process' supports file name handlers since Emacs 27.
   (skip-unless (tramp--test-emacs27-p))
@@ -4798,7 +4805,7 @@ INPUT, if non-nil, is a string sent to the process."
   ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for
   ;; remote processes in Emacs.  That doesn't work for tramp-adb.el.
   (skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
-                  (tramp--test-sh-p)))
+                  (tramp--test-sh-p) (tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-crypt-p)))
 
   (dolist (quoted (if (tramp--test-expensive-test) '(nil t) '(nil)))
@@ -4897,7 +4904,7 @@ INPUT, if non-nil, is a string sent to the process."
   :tags '(:expensive-test :unstable)
   (skip-unless (tramp--test-enabled))
   (skip-unless nil)
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-crypt-p)))
   ;; Prior Emacs 27, `shell-command-dont-erase-buffer' wasn't working properly.
   (skip-unless (tramp--test-emacs27-p))
@@ -5222,7 +5229,7 @@ Use direct async.")
   ;; Prior Emacs 27, `shell-file-name' was hard coded as "/bin/sh" for
   ;; remote processes in Emacs.  That doesn't work for tramp-adb.el.
   (skip-unless (or (and (tramp--test-adb-p) (tramp--test-emacs27-p))
-                  (tramp--test-sh-p)))
+                  (tramp--test-sh-p) (tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-crypt-p)))
   ;; Since Emacs 26.1.
   (skip-unless (and (fboundp 'connection-local-set-profile-variables)
@@ -5244,8 +5251,7 @@ Use direct async.")
          (with-no-warnings
            (connection-local-set-profile-variables
             'remote-sh
-            `((explicit-shell-file-name
-               . ,(if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh"))
+            `((explicit-shell-file-name . ,(tramp--test-shell-file-name))
               (explicit-sh-args . ("-c" "echo foo"))))
            (connection-local-set-profiles
             `(:application tramp
@@ -5279,7 +5285,7 @@ Use direct async.")
 (ert-deftest tramp-test35-exec-path ()
   "Check `exec-path' and `executable-find'."
   (skip-unless (tramp--test-enabled))
-  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p)))
+  (skip-unless (or (tramp--test-adb-p) (tramp--test-sh-p) 
(tramp--test-sshfs-p)))
   (skip-unless (not (tramp--test-crypt-p)))
   ;; Since Emacs 27.1.
   (skip-unless (fboundp 'exec-path))
@@ -5819,6 +5825,11 @@ Additionally, ls does not support \"--dired\"."
        "^\\(afp\\|davs?\\|smb\\)$"
        (file-remote-p tramp-test-temporary-file-directory 'method))))
 
+(defun tramp--test-sshfs-p ()
+  "Check, whether the remote host is offered by sshfs.
+This requires restrictions of file name syntax."
+  (tramp-sshfs-file-name-p tramp-test-temporary-file-directory))
+
 (defun tramp--test-sudoedit-p ()
   "Check, whether the sudoedit method is used."
   (tramp-sudoedit-file-name-p tramp-test-temporary-file-directory))
@@ -6114,7 +6125,6 @@ Use the `stat' command."
   (skip-unless (tramp--test-sh-p))
   (skip-unless (not (tramp--test-rsync-p)))
   (skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
-  (skip-unless (or (tramp--test-emacs26-p) (not (tramp--test-rclone-p))))
   ;; We cannot use `tramp-test-vec', because this fails during compilation.
   (with-parsed-tramp-file-name tramp-test-temporary-file-directory nil
     (skip-unless (tramp-get-remote-stat v)))
@@ -6134,7 +6144,6 @@ Use the `perl' command."
   (skip-unless (tramp--test-sh-p))
   (skip-unless (not (tramp--test-rsync-p)))
   (skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
-  (skip-unless (or (tramp--test-emacs26-p) (not (tramp--test-rclone-p))))
   ;; We cannot use `tramp-test-vec', because this fails during compilation.
   (with-parsed-tramp-file-name tramp-test-temporary-file-directory nil
     (skip-unless (tramp-get-remote-perl v)))
@@ -6157,7 +6166,6 @@ Use the `ls' command."
   (skip-unless (tramp--test-sh-p))
   (skip-unless (not (tramp--test-rsync-p)))
   (skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
-  (skip-unless (or (tramp--test-emacs26-p) (not (tramp--test-rclone-p))))
 
   (let ((tramp-connection-properties
         (append
@@ -6243,7 +6251,6 @@ Use the `stat' command."
   (skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
   (skip-unless (not (tramp--test-ksh-p)))
   (skip-unless (not (tramp--test-crypt-p)))
-  (skip-unless (or (tramp--test-emacs26-p) (not (tramp--test-rclone-p))))
   ;; We cannot use `tramp-test-vec', because this fails during compilation.
   (with-parsed-tramp-file-name tramp-test-temporary-file-directory nil
     (skip-unless (tramp-get-remote-stat v)))
@@ -6267,7 +6274,6 @@ Use the `perl' command."
   (skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
   (skip-unless (not (tramp--test-ksh-p)))
   (skip-unless (not (tramp--test-crypt-p)))
-  (skip-unless (or (tramp--test-emacs26-p) (not (tramp--test-rclone-p))))
   ;; We cannot use `tramp-test-vec', because this fails during compilation.
   (with-parsed-tramp-file-name tramp-test-temporary-file-directory nil
     (skip-unless (tramp-get-remote-perl v)))
@@ -6294,7 +6300,6 @@ Use the `ls' command."
   (skip-unless (not (tramp--test-windows-nt-and-pscp-psftp-p)))
   (skip-unless (not (tramp--test-ksh-p)))
   (skip-unless (not (tramp--test-crypt-p)))
-  (skip-unless (or (tramp--test-emacs26-p) (not (tramp--test-rclone-p))))
 
   (let ((tramp-connection-properties
         (append
@@ -6335,6 +6340,7 @@ Use the `ls' command."
   "Set \"process-name\" and \"process-buffer\" connection properties.
 The values are derived from PROC.  Run BODY.
 This is needed in timer functions as well as process filters and sentinels."
+  ;; FIXME: For tramp-sshfs.el, `processp' does not work.
   (declare (indent 1) (debug (processp body)))
   `(let* ((v (tramp-get-connection-property ,proc "vector" nil))
          (pname (tramp-get-connection-property v "process-name" nil))
@@ -6384,7 +6390,7 @@ process sentinels.  They shall not disturb each other."
     (define-key special-event-map [sigusr1] #'tramp--test-timeout-handler)
     (let* (;; For the watchdog.
           (default-directory (expand-file-name temporary-file-directory))
-          (shell-file-name (if (tramp--test-adb-p) "/system/bin/sh" "/bin/sh"))
+          (shell-file-name (tramp--test-shell-file-name))
           ;; It doesn't work on w32 systems.
           (watchdog
             (start-process-shell-command
@@ -6867,8 +6873,10 @@ If INTERACTIVE is non-nil, the tests are run 
interactively."
 ;; * Work on skipped tests.  Make a comment, when it is impossible.
 ;; * Revisit expensive tests, once problems in `tramp-error' are solved.
 ;; * Fix `tramp-test06-directory-file-name' for `ftp'.
-;; * Implement `tramp-test31-interrupt-process' for `adb' and for
-;;   direct async processes.
+;; * Implement `tramp-test31-interrupt-process' for `adb', `sshfs' and
+;;   for direct async processes.
+;; * Check, why direct async processes do not work for
+;;   `tramp-test43-asynchronous-requests'.
 ;; * Fix `tramp-test44-threads'.
 
 (provide 'tramp-tests)
diff --git a/texi/tramp.texi b/texi/tramp.texi
index 382feb8..7baf26c 100644
--- a/texi/tramp.texi
+++ b/texi/tramp.texi
@@ -126,6 +126,7 @@ Configuring @value{tramp} for use
 * Inline methods::              Inline methods.
 * External methods::            External methods.
 * GVFS-based methods::          @acronym{GVFS}-based external methods.
+* FUSE-based methods::          @acronym{FUSE}-based external methods.
 * Default Method::              Selecting a default method.
 * Default User::                Selecting a default user.
 * Default Host::                Selecting a default host.
@@ -139,6 +140,7 @@ Configuring @value{tramp} for use
                                 Setting own connection related information.
 * Remote programs::             How @value{tramp} finds and uses programs on 
the remote host.
 * Remote shell setup::          Remote shell setup hints.
+* FUSE setup::                  @acronym{FUSE} setup hints.
 * Android shell setup::         Android shell setup hints.
 * Auto-save and Backup::        Auto-save and Backup.
 * Keeping files encrypted::     Protect remote files by encryption.
@@ -433,7 +435,7 @@ remote host, when the buffer you call the process from has 
a remote
 @code{default-directory}.
 
 
-@anchor{Quick Start Guide: File name syntax}
+@anchor{Quick Start Guide File name syntax}
 @section File name syntax
 @cindex file name syntax
 
@@ -459,7 +461,7 @@ connection methods also support a notation for the port to 
be used, in
 which case it is written as @code{host#port}.
 
 
-@anchor{Quick Start Guide: @option{ssh} and @option{plink} methods}
+@anchor{Quick Start Guide ssh and plink methods}
 @section Using @option{ssh} and @option{plink}
 @cindex method @option{ssh}
 @cindex @option{ssh} method
@@ -478,28 +480,31 @@ an @command{ssh} server:
 @file{@trampfn{plink,user@@host,/path/to/file}}.
 
 
-@anchor{Quick Start Guide: @option{su}, @option{sudo} and @option{sg} methods}
-@section Using @option{su}, @option{sudo} and @option{sg}
+@anchor{Quick Start Guide su, sudo, doas and sg methods}
+@section Using @option{su}, @option{sudo}, @option{doas} and @option{sg}
 @cindex method @option{su}
 @cindex @option{su} method
 @cindex method @option{sudo}
 @cindex @option{sudo} method
+@cindex method @option{doas}
+@cindex @option{doas} method
 @cindex method @option{sg}
 @cindex @option{sg} method
 
 Sometimes, it is necessary to work on your local host under different
 permissions.  For this, you can use the @option{su} or @option{sudo}
-connection method.  Both methods use @samp{root} as default user name
-and the return value of @code{(system-name)} as default host name.
-Therefore, it is convenient to open a file as
+connection method.  On OpenBSD systems, the @option{doas} connection
+method offers the same functionality.  These methods use @samp{root}
+as default user name and the return value of @code{(system-name)} as
+default host name.  Therefore, it is convenient to open a file as
 @file{@trampfn{sudo,,/path/to/file}}.
 
 The method @option{sg} stands for ``switch group''; here the user name
 is used as the group to change to.  The default host name is the same.
 
 
-@anchor{Quick Start Guide: @option{ssh}, @option{plink}, @option{su}, 
@option{sudo} and @option{sg} methods}
-@section Combining @option{ssh} or @option{plink} with @option{su} or 
@option{sudo}
+@anchor{Quick Start Guide Combining ssh, plink, su, sudo and doas methods}
+@section Combining @option{ssh} or @option{plink} with @option{su}, 
@option{sudo} or @option{doas}
 @cindex method @option{ssh}
 @cindex @option{ssh} method
 @cindex method @option{plink}
@@ -508,18 +513,20 @@ is used as the group to change to.  The default host name 
is the same.
 @cindex @option{su} method
 @cindex method @option{sudo}
 @cindex @option{sudo} method
+@cindex method @option{doas}
+@cindex @option{doas} method
 
-If the @option{su} or @option{sudo} option should be performed on
-another host, it can be comnbined with a leading @option{ssh} or
-@option{plink} option.  That means that @value{tramp} connects first to
-the other host with non-administrative credentials, and changes to
-administrative credentials on that host afterwards.  In a simple case,
-the syntax looks like
+If the @option{su}, @option{sudo} or @option{doas} option should be
+performed on another host, it can be comnbined with a leading
+@option{ssh} or @option{plink} option.  That means that @value{tramp}
+connects first to the other host with non-administrative credentials,
+and changes to administrative credentials on that host afterwards.  In
+a simple case, the syntax looks like
 
@file{@value{prefix}ssh@value{postfixhop}user@@host|sudo@value{postfixhop}@value{postfix}/path/to/file}.
 @xref{Ad-hoc multi-hops}.
 
 
-@anchor{Quick Start Guide: @option{sudoedit} method}
+@anchor{Quick Start Guide sudoedit method}
 @section Using @command{sudoedit}
 @cindex method @option{sudoedit}
 @cindex @option{sudoedit} method
@@ -532,7 +539,7 @@ method, it is restricted to @samp{localhost} only, and it 
does not
 support external processes.
 
 
-@anchor{Quick Start Guide: @option{smb} method}
+@anchor{Quick Start Guide smb method}
 @section Using @command{smbclient}
 @cindex method @option{smb}
 @cindex @option{smb} method
@@ -546,7 +553,7 @@ of the local file name is the share exported by the remote 
host,
 @samp{path} in this example.
 
 
-@anchor{Quick Start Guide: GVFS-based methods}
+@anchor{Quick Start Guide GVFS-based methods}
 @section Using @acronym{GVFS}-based methods
 @cindex methods, gvfs
 @cindex gvfs-based methods
@@ -570,7 +577,7 @@ file system), @file{@trampfn{dav,user@@host,/path/to/file}},
 @file{@trampfn{mtp,device,/path/to/file}} (for media devices).
 
 
-@anchor{Quick Start Guide: GNOME Online Accounts based methods}
+@anchor{Quick Start Guide GNOME Online Accounts based methods}
 @section Using @acronym{GNOME} Online Accounts based methods
 @cindex @acronym{GNOME} Online Accounts
 @cindex method @option{gdrive}
@@ -590,21 +597,18 @@ account), or 
@file{@trampfn{nextcloud,user@@host#8081,/path/to/file}}
 (@samp{8081} stands for the port number) for OwnCloud/NextCloud files.
 
 
-@anchor{Quick Start Guide: Android}
-@section Using Android
-@cindex method @option{adb}
-@cindex @option{adb} method
-@cindex android
-
-An Android device, which is connected via USB to your local host, can
-be accessed via the @command{adb} command.  No user or host name is
-needed.  The file name syntax is @file{@trampfn{adb,,/path/to/file}}.
-
-
-@anchor{Quick Start Guide: @option{rclone} method}
-@section Using @command{rclone}
+@anchor{Quick Start Guide FUSE-based methods}
+@section Using @acronym{FUSE}-based methods
+@cindex methods, fuse
+@cindex fuse-based methods
 @cindex method @option{rclone}
 @cindex @option{rclone} method
+@cindex method @option{sshfs}
+@cindex @option{sshfs} method
+
+@acronym{FUSE, Filesystem in Userspace} allows users to mount a
+virtual file system.  It is also used by @acronym{GVFS} internally,
+but here we discuss methods which do not use the @acronym{GVFS} API.
 
 A convenient way to access system storages is the @command{rclone}
 program.  If you have configured a storage in @command{rclone} under a
@@ -612,6 +616,24 @@ name @samp{storage} (for example), you can access it via 
the remote
 file name syntax @file{@trampfn{rclone,storage,/path/to/file}}.  User
 names are not needed.
 
+On local hosts which have installed the @command{sshfs} client for
+mounting a file system based on @command{sftp}, this method can be
+used.  All remote files are available via the local mount point.
+@value{tramp} aids in mounting the file system if it isn't mounted
+yet, and it supports the access with the usual file name syntax
+@file{@trampfn{sshfs,user@@host,/path/to/file}}.
+
+
+@anchor{Quick Start Guide Android}
+@section Using Android
+@cindex method @option{adb}
+@cindex @option{adb} method
+@cindex android
+
+An Android device, which is connected via USB to your local host, can
+be accessed via the @command{adb} command.  No user or host name is
+needed.  The file name syntax is @file{@trampfn{adb,,/path/to/file}}.
+
 
 @node Configuration
 @chapter Configuring @value{tramp}
@@ -650,6 +672,7 @@ may be used in your init file:
 * Inline methods::              Inline methods.
 * External methods::            External methods.
 * GVFS-based methods::          @acronym{GVFS}-based external methods.
+* FUSE-based methods::          @acronym{FUSE}-based external methods.
 * Default Method::              Selecting a default method.
                                   Here we also try to help those who
                                   don't have the foggiest which method
@@ -666,6 +689,7 @@ may be used in your init file:
                                 Setting own connection related information.
 * Remote programs::             How @value{tramp} finds and uses programs on 
the remote host.
 * Remote shell setup::          Remote shell setup hints.
+* FUSE setup::                  @acronym{FUSE} setup hints.
 * Android shell setup::         Android shell setup hints.
 * Auto-save and Backup::        Auto-save and Backup.
 * Keeping files encrypted::     Protect remote files by encryption.
@@ -1110,7 +1134,6 @@ UNC file name specification does not allow the 
specification of a
 different user name for authentication like the @command{smbclient}
 can.
 
-
 @item @option{adb}
 @cindex method @option{adb}
 @cindex @option{adb} method
@@ -1150,45 +1173,6 @@ specified using @file{device#42} host name syntax or 
@value{tramp} can
 use the default value as declared in @command{adb} command.  Port
 numbers are not applicable to Android devices connected through USB@.
 
-
-@item @option{rclone}
-@cindex method @option{rclone}
-@cindex @option{rclone} method
-
-@vindex tramp-rclone-program
-The program @command{rclone} allows to access different system
-storages in the cloud, see @url{https://rclone.org/} for a list of
-supported systems.  If the @command{rclone} program isn't found in
-your @env{PATH} environment variable, you can tell @value{tramp} its
-absolute path via the user option @code{tramp-rclone-program}.
-
-A system storage must be configured via the @command{rclone config}
-command, outside Emacs.  If you have configured a storage in
-@command{rclone} under a name @samp{storage} (for example), you could
-access it via the remote file name
-
-@example
-@trampfn{rclone,storage,/path/to/file}
-@end example
-
-User names are part of the @command{rclone} configuration, and not
-needed in the remote file name.  If a user name is contained in the
-remote file name, it is ignored.
-
-Internally, @value{tramp} mounts the remote system storage at location
-@file{/tmp/tramp.rclone.storage}, with @file{storage} being the name
-of the configured system storage.
-
-Optional flags to the different @option{rclone} operations could be
-passed as connection property, @xref{Predefined connection
-information}.  Supported properties are @t{"mount-args"},
-@t{"copyto-args"}, @t{"moveto-args"} and @t{"about-args"}.
-
-Access via @option{rclone} is slow.  If you have an alternative method
-for accessing the system storage, you should use it.
-@ref{GVFS-based methods} for example, methods @option{gdrive} and
-@option{nextcloud}.
-
 @end table
 
 
@@ -1200,8 +1184,8 @@ for accessing the system storage, you should use it.
 
 @acronym{GVFS} is the virtual file system for the @acronym{GNOME}
 Desktop, @uref{https://en.wikipedia.org/wiki/GVFS}.  Remote files on
-@acronym{GVFS} are mounted locally through FUSE and @value{tramp} uses
-this locally mounted directory internally.
+@acronym{GVFS} are mounted locally through @acronym{FUSE} and
+@value{tramp} uses this locally mounted directory internally.
 
 Emacs uses the D-Bus mechanism to communicate with @acronym{GVFS}@.
 Emacs must have the message bus system, D-Bus integration active,
@@ -1317,6 +1301,88 @@ respectively:
 @end defopt
 
 
+@node FUSE-based methods
+@section @acronym{FUSE}-based external methods
+@cindex methods, fuse
+@cindex fuse-based methods
+
+Besides @acronym{GVFS}, there are other virtual file systems using the
+@acronym{FUSE} interface.  Remote files are mounted locally through
+@acronym{FUSE} and @value{tramp} uses this locally mounted directory
+internally.  When possible, @value{tramp} maps the remote file names
+to their respective local file name, and applies the file name
+operation on them.  For some of the file name operations this is not
+possible, @value{tramp} emulates those operations otherwise.
+
+@table @asis
+@item @option{rclone}
+@cindex method @option{rclone}
+@cindex @option{rclone} method
+
+@vindex tramp-rclone-program
+The program @command{rclone} allows to access different system
+storages in the cloud, see @url{https://rclone.org/} for a list of
+supported systems.  If the @command{rclone} program isn't found in
+your @env{PATH} environment variable, you can tell @value{tramp} its
+absolute path via the user option @code{tramp-rclone-program}.
+
+A system storage must be configured via the @command{rclone config}
+command, outside Emacs.  If you have configured a storage in
+@command{rclone} under a name @samp{storage} (for example), you could
+access it via the remote file name
+
+@example
+@trampfn{rclone,storage,/path/to/file}
+@end example
+
+User names are part of the @command{rclone} configuration, and not
+needed in the remote file name.  If a user name is contained in the
+remote file name, it is ignored.
+
+Internally, @value{tramp} mounts the remote system storage at location
+@file{/tmp/tramp.rclone.storage}, with @file{storage} being the name
+of the configured system storage.
+
+The mount point and optional flags to the different @option{rclone}
+operations could be passed as connection properties, @xref{Setup of
+rclone method}.
+
+Access via @option{rclone} is slow.  If you have an alternative method
+for accessing the system storage, you should use it.
+@ref{GVFS-based methods} for example, methods @option{gdrive} and
+@option{nextcloud}.
+
+@item @option{sshfs}
+@cindex method @option{sshfs}
+@cindex @option{sshfs} method
+
+@vindex tramp-sshfs-program
+On local hosts which have installed the @command{sshfs} client for
+mounting a file system based on @command{sftp}, this method can be
+used, see
+@url{https://github.com/libfuse/sshfs/blob/master/README.rst/}.  If
+the @command{sshfs} program isn't found in your @env{PATH} environment
+variable, you can tell @value{tramp} its absolute path via the user
+option @code{tramp-sshfs-program}.
+
+All remote files are available via the local mount point.
+@value{tramp} aids in mounting the file system if it isn't mounted
+yet.  The remote file name syntax is
+
+@example
+@trampfn{sshfs,user@@host#port,/path/to/file}
+@end example
+
+User name and port number are optional.  This method does not support
+password handling, the file system must either be mounted already, or
+the connection must be established passwordless via ssh keys.
+
+The mount point and mount arguments could be passed as connection
+properties, @xref{Setup of sshfs method}.
+
+@end table
+
+
 @node Default Method
 @section Selecting a default method
 @cindex default method
@@ -2102,6 +2168,13 @@ The default value of this property is @code{t} (not 
specified in
 @code{tramp-methods}).  If the remote host runs native MS Windows,
 this propery has no effect.
 
+@item @t{"mount-point"}
+
+The directory file name an @acronym{FUSE}-based file system is mounted
+on.  The default value of this property is
+@t{"/tmp/tramp.method.user@@host#port"} (not specified in
+@code{tramp-methods}).
+
 @item @t{"mount-args"}@*
 @t{"copyto-args"}@*
 @t{"moveto-args"}@*
@@ -2211,7 +2284,7 @@ be recomputed.  To force @value{tramp} to recompute 
afresh, call
 
 By default, @value{tramp} uses the command @command{/bin/sh} for
 starting a shell on the remote host.  This can be changed by setting
-the connection property @t{"remote-shell"}; see @pxref{Predefined
+the connection property @t{"remote-shell"}; see @ref{Predefined
 connection information}.  If you want, for example, use
 @command{/usr/bin/zsh} on a remote host, you might apply
 
@@ -2232,6 +2305,8 @@ which support this.
 This approach has also the advantage, that settings in
 @code{tramp-sh-extra-args} will be applied.  For @command{zsh}, the
 trouble with the shell prompt due to set zle options will be avoided.
+For @command{bash}, loading @file{~/.editrc} or @file{~/.inputrc} is
+suppressed.
 
 Similar problems can happen with the local shell Tramp uses to create
 a process.  By default, it uses the command @command{/bin/sh} for
@@ -2430,7 +2505,6 @@ match the end of the connection buffer.  Due to 
performance reasons,
 this search starts at the end of the buffer, and it is limited to 256
 characters backwards.
 
-
 @item Conflicting names for users and variables in @file{.profile}
 
 When a user name is the same as a variable name in a local file, such
@@ -2440,7 +2514,6 @@ variable name to something different from the user name.  
For example,
 if the user name is @env{FRUMPLE}, then change the variable name to
 @env{FRUMPLE_DIR}.
 
-
 @item Non-Bourne commands in @file{.profile}
 
 When the remote host's @file{.profile} is also used for shells other
@@ -2465,7 +2538,6 @@ To accommodate using non-Bourne shells on that remote, 
use other
 shell-specific config files.  For example, bash can use
 @file{~/.bash_profile} and ignore @file{.profile}.
 
-
 @item Interactive shell prompt
 
 @vindex INSIDE_EMACS@r{, environment variable}
@@ -2533,6 +2605,60 @@ where @samp{192.168.0.1} is the remote host IP address
 @end table
 
 
+@node FUSE setup
+@section @acronym{FUSE} setup hints
+
+The @acronym{FUSE} file systems are mounted per default at
+@file{/tmp/tramp.method.user@@host#port}.  The user name and port
+number are optional.  If the file system is already mounted, it will
+be used as it is.  If the mount point does not exist yet,
+@value{tramp} creates this directory.
+
+The mount point can be overwritten by the connection property
+@t{"mount-point"}, @ref{Predefined connection information}.
+Example:
+
+@lisp
+@group
+(add-to-list 'tramp-connection-properties
+             `(,(regexp-quote "@trampfn{sshfs,user@@host,}")
+               "mount-point"
+               ,(expand-file-name "sshfs.user@@host" user-emacs-directory)))
+@end group
+@end lisp
+
+
+@anchor{Setup of rclone method}
+@subsection @option{rclone} setup
+@cindex rclone setup
+
+The default arguments of the @command{rclone} operations
+@command{mount}, @command{coopyto}, @command{moveto} and
+@command{about} are declared in the variable @code{tramp-methods} as
+method specific parameters.  Usually, they don't need to be overwritten.
+
+If needed, these parameters can be overwritten as connection
+properties @t{"mount-args"}, @t{"copyto-args"}, @t{"moveto-args"} and
+@t{"about-args"}, @xref{Predefined connection information}.  All of
+them are list of strings.
+
+Be careful changing @t{"--dir-cache-time"}, this could delay
+visibility of files.
+
+
+@anchor{Setup of sshfs method}
+@subsection @option{sshfs} setup
+@cindex sshfs setup
+
+The method @option{sshfs} declares the mount arguments in the variable
+@code{tramp-methods}, passed to the @command{sshfs} command.  This is
+a list of list of strings, and can be overwritten by the connection
+property @t{"mount-args"}, @xref{Predefined connection information}.
+
+Additionally, it declares also the arguments for running remote
+processes, using the @command{ssh} command.  These don't need to be
+changed.
+
 @node Android shell setup
 @section Android shell setup hints
 @cindex android shell setup for ssh
@@ -4197,6 +4323,7 @@ Disable excessive traces.  Set @code{tramp-verbose} to 3 
or lower,
 default being 3.  Increase trace levels temporarily when hunting for
 bugs.
 
+
 @item
 @value{tramp} does not connect to the remote host
 
@@ -4448,6 +4575,7 @@ disable @samp{--color=yes} or @samp{--color=auto} in the 
remote host's
 @file{.bashrc} or @file{.profile}.  Turn this alias on and off to see
 if file name completion works.
 
+
 @item
 File name completion does not work in directories with large number of
 files
@@ -4846,6 +4974,7 @@ In BBDB buffer, access an entry by pressing the key 
@kbd{F}.
 
 Thanks to @value{tramp} users for contributing to these recipes.
 
+
 @item
 Why saved multi-hop file names do not work in a new Emacs session?
 
@@ -4950,6 +5079,24 @@ In case you have installed it from its Git repository, 
@ref{Recompilation}.
 
 
 @item
+I get an error @samp{tramp-file-name-handler: Invalid function:
+tramp-compat-with-mutex}
+
+Likely, you have a running Emacs session with loaded @value{tramp},
+and you try to upgrade it to another version from GNU ELPA.  Since
+@value{tramp} is not forward compatible, you must unload / reload it.
+Try the following steps:
+
+@example
+@kbd{M-x tramp-unload-tramp @key{RET}}
+@kbd{M-x load-library @key{RET} tramp @key{RET}}
+@end example
+
+If this doesn't work, you must restart Emacs with proper
+@code{load-path} for the new @value{tramp} version.
+
+
+@item
 I get an error @samp{Remote file error: Forbidden reentrant call of Tramp}
 
 @vindex remote-file-error
diff --git a/texi/trampver.texi b/texi/trampver.texi
index 580c390..dc41564 100644
--- a/texi/trampver.texi
+++ b/texi/trampver.texi
@@ -8,7 +8,7 @@
 @c In the Tramp GIT, the version numbers are auto-frobbed from
 @c tramp.el, and the bug report address is auto-frobbed from
 @c configure.ac.
-@set trampver 2.5.0.2
+@set trampver 2.5.0.3
 @set trampurl https://www.gnu.org/software/tramp/
 @set tramp-bug-report-address tramp-devel@@gnu.org
 @set emacsver 25.1
diff --git a/tramp-adb.el b/tramp-adb.el
index 6ec4d1f..aacf83e 100644
--- a/tramp-adb.el
+++ b/tramp-adb.el
@@ -44,7 +44,6 @@
   :version "24.4"
   :type 'string)
 
-;;;###tramp-autoload
 (defcustom tramp-adb-connect-if-not-connected nil
   "Try to run `adb connect' if provided device is not connected currently.
 It is used for TCP/IP devices."
@@ -56,7 +55,6 @@ It is used for TCP/IP devices."
 (defconst tramp-adb-method "adb"
   "When this method name is used, forward all calls to Android Debug Bridge.")
 
-;;;###tramp-autoload
 (defcustom tramp-adb-prompt "^[^#$\n\r]*[#$][[:space:]]"
   "Regexp used as prompt in almquist shell."
   :type 'regexp
diff --git a/tramp-cache.el b/tramp-cache.el
index dc71648..d754e73 100644
--- a/tramp-cache.el
+++ b/tramp-cache.el
@@ -162,16 +162,20 @@ Return DEFAULT if not set."
     (tramp-message
      key 8 "%s %s %s; inhibit: %s; cache used: %s; cached at: %s"
      file property value remote-file-name-inhibit-cache cache-used cached-at)
+    ;; For analysis purposes, count the number of getting this file attribute.
     (when (>= tramp-verbose 10)
       (let* ((var (intern (concat "tramp-cache-get-count-" property)))
-            (val (or (numberp (bound-and-true-p var))
-                     (progn
-                       (add-hook 'tramp-cache-unload-hook
-                                 (lambda () (makunbound var)))
-                       0))))
+            (val (or (and (boundp var) (numberp (symbol-value var))
+                          (symbol-value var))
+                     0)))
        (set var (1+ val))))
     value))
 
+(add-hook 'tramp-cache-unload-hook
+         (lambda ()
+           (dolist (var (all-completions "tramp-cache-get-count-" obarray))
+             (unintern var obarray))))
+
 ;;;###tramp-autoload
 (defun tramp-set-file-property (key file property value)
   "Set the PROPERTY of FILE to VALUE, in the cache context of KEY.
@@ -186,16 +190,20 @@ Return VALUE."
     ;; We put the timestamp there.
     (puthash property (cons (current-time) value) hash)
     (tramp-message key 8 "%s %s %s" file property value)
+    ;; For analysis purposes, count the number of setting this file attribute.
     (when (>= tramp-verbose 10)
       (let* ((var (intern (concat "tramp-cache-set-count-" property)))
-            (val (or (numberp (bound-and-true-p var))
-                     (progn
-                       (add-hook 'tramp-cache-unload-hook
-                                 (lambda () (makunbound var)))
-                       0))))
+            (val (or (and (boundp var) (numberp (symbol-value var))
+                          (symbol-value var))
+                     0)))
        (set var (1+ val))))
     value))
 
+(add-hook 'tramp-cache-unload-hook
+         (lambda ()
+           (dolist (var (all-completions "tramp-cache-set-count-" obarray))
+             (unintern var obarray))))
+
 ;;;###tramp-autoload
 (defun tramp-flush-file-property (key file property)
   "Remove PROPERTY of FILE in the cache context of KEY."
diff --git a/tramp-cmds.el b/tramp-cmds.el
index f0bbe31..d208f0e 100644
--- a/tramp-cmds.el
+++ b/tramp-cmds.el
@@ -144,11 +144,18 @@ When called interactively, a Tramp connection has to be 
selected."
 ;;;###tramp-autoload
 (defun tramp-cleanup-this-connection ()
   "Flush all connection related objects of the current buffer's connection."
+  ;; (declare (completion tramp-command-completion-p)))
   (interactive)
   (and (tramp-tramp-file-p default-directory)
        (tramp-cleanup-connection
        (tramp-dissect-file-name default-directory 'noexpand))))
 
+;; Starting with Emacs 28.1, this can be replaced by the "(declare ...)" form.
+;;;###tramp-autoload
+(function-put
+ #'tramp-cleanup-this-connection 'completion-predicate
+ #'tramp-command-completion-p)
+
 ;;;###tramp-autoload
 (defvar tramp-cleanup-all-connections-hook nil
   "List of functions to be called after all Tramp connections are cleaned up.")
@@ -201,7 +208,6 @@ This includes password cache, file cache, connection cache, 
buffers."
   (dolist (name (tramp-list-remote-buffers))
     (when (bufferp (get-buffer name)) (kill-buffer name))))
 
-;;;###tramp-autoload
 (defcustom tramp-default-rename-alist nil
   "Default target for renaming remote buffer file names.
 This is an alist of cons cells (SOURCE . TARGET).  The first
@@ -224,7 +230,6 @@ expression which always matches."
   :type '(repeat (cons (choice :tag "Source regexp" regexp sexp)
                       (choice :tag "Target   name" string (const nil)))))
 
-;;;###tramp-autoload
 (defcustom tramp-confirm-rename-file-names t
   "Whether renaming a buffer file name must be confirmed."
   :group 'tramp
@@ -243,7 +248,7 @@ function returns nil"
          (host (or (file-remote-p string 'host) ""))
          item result)
       (while (setq item (pop tdra))
-       (when (string-match-p (or (eval (car item)) "") string)
+       (when (string-match-p (or (eval (car item) t) "") string)
          (setq tdra nil
                result
                (format-spec
@@ -431,6 +436,7 @@ Interactively, TARGET is selected from 
`tramp-default-rename-alist'
 without confirmation if the prefix argument is non-nil.
 
 For details, see `tramp-rename-files'."
+  ;; (declare (completion tramp-command-completion-p))
   (interactive
    (let ((source default-directory)
         target
@@ -461,6 +467,11 @@ For details, see `tramp-rename-files'."
 
   (tramp-rename-files default-directory target))
 
+;; Starting with Emacs 28.1, this can be replaced by the "(declare ...)" form.
+;;;###tramp-autoload
+(function-put
+ #'tramp-rename-these-files 'completion-predicate #'tramp-command-completion-p)
+
 ;; Tramp version is useful in a number of situations.
 
 ;;;###tramp-autoload
diff --git a/tramp-compat.el b/tramp-compat.el
index 00e29bf..fce9e0b 100644
--- a/tramp-compat.el
+++ b/tramp-compat.el
@@ -70,7 +70,7 @@
 It is the default value of `temporary-file-directory'."
   ;; We must return a local directory.  If it is remote, we could run
   ;; into an infloop.
-  (eval (car (get 'temporary-file-directory 'standard-value))))
+  (eval (car (get 'temporary-file-directory 'standard-value)) t))
 
 (defsubst tramp-compat-make-temp-name ()
   "Generate a local temporary file name (compat function)."
diff --git a/tramp-crypt.el b/tramp-crypt.el
index f8de708..1d8c0ad 100644
--- a/tramp-crypt.el
+++ b/tramp-crypt.el
@@ -112,6 +112,18 @@ initializing a new crypted remote directory."
   "Non-nil when encryption support is available.")
 (setq tramp-crypt-enabled (executable-find tramp-crypt-encfs-program))
 
+;; This function takes action since Emacs 28.1, when
+;; `read-extended-command-predicate' is set to
+;; `command-completion-default-include-p'.
+(defun tramp-crypt-command-completion-p (symbol _buffer)
+  "A predicate for Tramp interactive commands.
+They are completed by \"M-x TAB\" only when encryption support is enabled."
+  (and tramp-crypt-enabled
+       ;; `tramp-crypt-remove-directory' needs to be completed only in
+       ;; case we have already crypted directories.
+       (or (not (eq symbol #'tramp-crypt-remove-directory))
+          tramp-crypt-directories)))
+
 ;;;###tramp-autoload
 (defconst tramp-crypt-encfs-config ".encfs6.xml"
   "Encfs configuration file name.")
@@ -481,10 +493,17 @@ directory.  File names will be also encrypted."
     (setq tramp-crypt-directories (cons name tramp-crypt-directories)))
   (tramp-register-file-name-handlers))
 
+;; `tramp-crypt-command-completion-p' is not autoloaded, and this
+;; setting isn't either.
+(function-put
+ #'tramp-crypt-add-directory 'completion-predicate
+ #'tramp-crypt-command-completion-p)
+
 (defun tramp-crypt-remove-directory (name)
   "Unmark remote directory NAME for encryption.
 Existing files in that directory and its subdirectories will be
 kept in their encrypted form."
+  ;; (declare (completion tramp-crypt-command-completion-p))
   (interactive "DRemote directory name: ")
   (unless tramp-crypt-enabled
     (tramp-user-error nil "Feature is not enabled."))
@@ -498,6 +517,11 @@ kept in their encrypted form."
     (setq tramp-crypt-directories (delete name tramp-crypt-directories))
     (tramp-register-file-name-handlers)))
 
+;; Starting with Emacs 28.1, this can be replaced by the "(declare ...)" form.
+(function-put
+ #'tramp-crypt-remove-directory 'completion-predicate
+ #'tramp-crypt-command-completion-p)
+
 ;; `auth-source' requires a user.
 (defun tramp-crypt-dissect-file-name (name)
   "Return a `tramp-file-name' structure for NAME.
diff --git a/tramp-fuse.el b/tramp-fuse.el
new file mode 100644
index 0000000..ec1db86
--- /dev/null
+++ b/tramp-fuse.el
@@ -0,0 +1,205 @@
+;;; tramp-fuse.el --- Tramp access functions for FUSE mounts  -*- 
lexical-binding:t -*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Michael Albinus <michael.albinus@gmx.de>
+;; Keywords: comm, processes
+;; Package: tramp
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; These are helper functions for FUSE file systems.
+
+;;; Code:
+
+(require 'tramp)
+
+;; File name primitives.
+
+(defun tramp-fuse-handle-delete-directory
+    (directory &optional recursive trash)
+  "Like `delete-directory' for Tramp files."
+  (with-parsed-tramp-file-name (expand-file-name directory) nil
+    (tramp-flush-directory-properties v localname)
+    (delete-directory (tramp-fuse-local-file-name directory) recursive trash)))
+
+(defun tramp-fuse-handle-delete-file (filename &optional trash)
+  "Like `delete-file' for Tramp files."
+  (with-parsed-tramp-file-name (expand-file-name filename) nil
+    (delete-file (tramp-fuse-local-file-name filename) trash)
+    (tramp-flush-file-properties v localname)))
+
+(defun tramp-fuse-handle-directory-files
+    (directory &optional full match nosort count)
+  "Like `directory-files' for Tramp files."
+  (unless (file-exists-p directory)
+    (tramp-compat-file-missing (tramp-dissect-file-name directory) directory))
+  (when (file-directory-p directory)
+    (setq directory (file-name-as-directory (expand-file-name directory)))
+    (with-parsed-tramp-file-name directory nil
+      (let ((result
+            (tramp-compat-directory-files
+             (tramp-fuse-local-file-name directory) full match nosort count)))
+       ;; Massage the result.
+       (when full
+         (let ((local (concat "^" (regexp-quote (tramp-fuse-mount-point v))))
+               (remote (directory-file-name
+                        (funcall
+                         (if (tramp-compat-file-name-quoted-p directory)
+                             #'tramp-compat-file-name-quote #'identity)
+                         (file-remote-p directory)))))
+           (setq result
+                 (mapcar
+                  (lambda (x) (replace-regexp-in-string local remote x))
+                  result))))
+       ;; Some storage systems do not return "." and "..".
+       (dolist (item '(".." "."))
+         (when (and (string-match-p (or match (regexp-quote item)) item)
+                    (not
+                     (member (if full (setq item (concat directory item)) item)
+                             result)))
+           (setq result (cons item result))))
+       ;; Return result.
+       (if nosort result (sort result #'string<))))))
+
+(defun tramp-fuse-handle-file-attributes (filename &optional id-format)
+  "Like `file-attributes' for Tramp files."
+  (with-parsed-tramp-file-name (expand-file-name filename) nil
+    (with-tramp-file-property
+        v localname (format "file-attributes-%s" id-format)
+      (file-attributes (tramp-fuse-local-file-name filename) id-format))))
+
+(defun tramp-fuse-handle-file-executable-p (filename)
+  "Like `file-executable-p' for Tramp files."
+  (with-parsed-tramp-file-name (expand-file-name filename) nil
+    (with-tramp-file-property v localname "file-executable-p"
+      (file-executable-p (tramp-fuse-local-file-name filename)))))
+
+(defun tramp-fuse-handle-file-name-all-completions (filename directory)
+  "Like `file-name-all-completions' for Tramp files."
+  (all-completions
+   filename
+   (delete-dups
+    (append
+     (file-name-all-completions
+      filename (tramp-fuse-local-file-name directory))
+     ;; Some storage systems do not return "." and "..".
+     (let (result)
+       (dolist (item '(".." ".") result)
+        (when (string-prefix-p filename item)
+          (catch 'match
+            (dolist (elt completion-regexp-list)
+              (unless (string-match-p elt item) (throw 'match nil)))
+            (setq result (cons (concat item "/") result))))))))))
+
+(defun tramp-fuse-handle-file-readable-p (filename)
+  "Like `file-readable-p' for Tramp files."
+  (with-parsed-tramp-file-name (expand-file-name filename) nil
+    (with-tramp-file-property v localname "file-readable-p"
+      (file-readable-p (tramp-fuse-local-file-name filename)))))
+
+;; This function isn't used.
+(defun tramp-fuse-handle-insert-directory
+    (filename switches &optional wildcard full-directory-p)
+  "Like `insert-directory' for Tramp files."
+  (insert-directory
+   (tramp-fuse-local-file-name filename) switches wildcard full-directory-p)
+  (goto-char (point-min))
+  (while (search-forward (tramp-fuse-local-file-name filename) nil 'noerror)
+    (replace-match filename)))
+
+(defun tramp-fuse-handle-make-directory (dir &optional parents)
+  "Like `make-directory' for Tramp files."
+  (with-parsed-tramp-file-name (expand-file-name dir) nil
+    (make-directory (tramp-fuse-local-file-name dir) parents)
+    ;; When PARENTS is non-nil, DIR could be a chain of non-existent
+    ;; directories a/b/c/...  Instead of checking, we simply flush the
+    ;; whole file cache.
+    (tramp-flush-file-properties v localname)
+    (tramp-flush-directory-properties
+     v (if parents "/" (file-name-directory localname)))))
+
+
+;; File name helper functions.
+
+(defun tramp-fuse-mount-spec (vec)
+  "Return local mount spec of VEC."
+  (if-let ((host (tramp-file-name-host vec))
+          (user (tramp-file-name-user vec)))
+      (format "%s@%s:/" user host)
+    (format "%s:/" host)))
+
+(defun tramp-fuse-mount-point (vec)
+  "Return local mount point of VEC."
+  (or (tramp-get-connection-property vec "mount-point" nil)
+      (expand-file-name
+       (concat
+       tramp-temp-name-prefix
+       (tramp-file-name-method vec) "."
+       (when (tramp-file-name-user vec)
+         (concat (tramp-file-name-user-domain vec) "@"))
+       (tramp-file-name-host-port vec))
+       (tramp-compat-temporary-file-directory))))
+
+(defun tramp-fuse-mounted-p (vec)
+  "Check, whether fuse volume determined by VEC is mounted."
+  (when (tramp-get-connection-process vec)
+    ;; We cannot use `with-connection-property', because we don't want
+    ;; to cache a nil result.
+    (or (tramp-get-connection-property
+         (tramp-get-connection-process vec) "mounted" nil)
+        (let* ((default-directory (tramp-compat-temporary-file-directory))
+               (fuse (concat "fuse." (tramp-file-name-method vec)))
+               (mount (shell-command-to-string (format "mount -t %s" fuse))))
+          (tramp-message vec 6 "%s %s" "mount -t" fuse)
+          (tramp-message vec 6 "\n%s" mount)
+          (tramp-set-connection-property
+           (tramp-get-connection-process vec) "mounted"
+           (when (string-match
+                 (format
+                   "^\\(%s\\)\\s-" (regexp-quote (tramp-fuse-mount-spec vec)))
+                 mount)
+             (match-string 1 mount)))))))
+
+(defun tramp-fuse-local-file-name (filename)
+  "Return local mount name of FILENAME."
+  (setq filename (tramp-compat-file-name-unquote (expand-file-name filename)))
+  (with-parsed-tramp-file-name filename nil
+    ;; As long as we call `tramp-*-maybe-open-connection' here,
+    ;; we cache the result.
+    (with-tramp-file-property v localname "local-file-name"
+      (funcall
+       (intern
+       (format "tramp-%s-maybe-open-connection" (tramp-file-name-method v)))
+       v)
+      (let ((quoted (tramp-compat-file-name-quoted-p localname))
+           (localname (tramp-compat-file-name-unquote localname)))
+       (funcall
+        (if quoted #'tramp-compat-file-name-quote #'identity)
+        (expand-file-name
+         (if (file-name-absolute-p localname)
+             (substring localname 1) localname)
+         (tramp-fuse-mount-point v)))))))
+
+(add-hook 'tramp-unload-hook
+         (lambda ()
+           (unload-feature 'tramp-fuse 'force)))
+
+(provide 'tramp-fuse)
+
+;;; tramp-fuse.el ends here
diff --git a/tramp-gvfs.el b/tramp-gvfs.el
index 9d4e04c..c4ec112 100644
--- a/tramp-gvfs.el
+++ b/tramp-gvfs.el
@@ -175,7 +175,6 @@ They are checked during start up via
                    (dbus-list-known-names :session))
       (setq tramp-media-methods (delete method tramp-media-methods)))))
 
-;;;###tramp-autoload
 (defcustom tramp-gvfs-zeroconf-domain "local"
   "Zeroconf domain to be used for discovering services, like host names."
   :group 'tramp
diff --git a/tramp-integration.el b/tramp-integration.el
index 64b5b48..2931b4f 100644
--- a/tramp-integration.el
+++ b/tramp-integration.el
@@ -49,6 +49,7 @@
 (defvar recentf-exclude)
 (defvar tramp-current-connection)
 (defvar tramp-postfix-host-format)
+(defvar tramp-use-ssh-controlmaster-options)
 
 ;;; Fontification of `read-file-name':
 
@@ -231,7 +232,7 @@ NAME must be equal to `tramp-current-connection'."
             (delete (info-lookup->mode-cache 'symbol 'tramp-info-lookup-mode)
                     (info-lookup->topic-cache 'symbol)))))
 
-  (dolist (mode (mapcar 'car (info-lookup->topic-value 'symbol)))
+  (dolist (mode (mapcar #'car (info-lookup->topic-value 'symbol)))
     ;; Add `tramp-info-lookup-mode' to `other-modes' for either
     ;; `emacs-lisp-mode' itself, or to modes which use
     ;; `emacs-lisp-mode' as `other-modes'.  Reset `info-lookup-cache'.
@@ -261,6 +262,23 @@ NAME must be equal to `tramp-current-connection'."
                  (delete (info-lookup->mode-cache 'symbol ',mode)
                          (info-lookup->topic-cache 'symbol))))))))
 
+;;; Integration of compile.el:
+
+;; Compilation processes use `accept-process-output' such a way that
+;; Tramp's parallel `accept-process-output' blocks.  See last part of
+;; Bug#45518.  So we don't use ssh ControlMaster options.
+(defun tramp-compile-disable-ssh-controlmaster-options ()
+  "Don't allow ssh ControlMaster while compiling."
+  (setq-local tramp-use-ssh-controlmaster-options nil))
+
+(with-eval-after-load 'compile
+  (add-hook 'compilation-mode-hook
+           #'tramp-compile-disable-ssh-controlmaster-options)
+  (add-hook 'tramp-integration-unload-hook
+           (lambda ()
+             (remove-hook 'compilation-start-hook
+                          #'tramp-compile-disable-ssh-controlmaster-options))))
+
 ;;; Default connection-local variables for Tramp:
 ;; `connection-local-set-profile-variables' and
 ;; `connection-local-set-profiles' exists since Emacs 26.1.
@@ -277,7 +295,7 @@ NAME must be equal to `tramp-current-connection'."
 
 (tramp-compat-funcall
  'connection-local-set-profiles
- `(:application tramp)
+ '(:application tramp)
  'tramp-connection-local-default-system-profile)
 
 (defconst tramp-connection-local-default-shell-variables
@@ -293,7 +311,7 @@ NAME must be equal to `tramp-current-connection'."
 (with-eval-after-load 'shell
   (tramp-compat-funcall
    'connection-local-set-profiles
-   `(:application tramp)
+   '(:application tramp)
    'tramp-connection-local-default-shell-profile))
 
 (add-hook 'tramp-unload-hook
diff --git a/tramp-rclone.el b/tramp-rclone.el
index a7f4c9b..3b6de3e 100644
--- a/tramp-rclone.el
+++ b/tramp-rclone.el
@@ -35,14 +35,13 @@
 
 ;;; Code:
 
-(eval-when-compile (require 'cl-lib))
 (require 'tramp)
+(require 'tramp-fuse)
 
 ;;;###tramp-autoload
 (defconst tramp-rclone-method "rclone"
   "When this method name is used, forward all calls to rclone mounts.")
 
-;;;###tramp-autoload
 (defcustom tramp-rclone-program "rclone"
   "Name of the rclone program."
   :group 'tramp
@@ -77,11 +76,11 @@
     ;; `byte-compiler-base-file-name' performed by default handler.
     (copy-directory . tramp-handle-copy-directory)
     (copy-file . tramp-rclone-handle-copy-file)
-    (delete-directory . tramp-rclone-handle-delete-directory)
-    (delete-file . tramp-rclone-handle-delete-file)
+    (delete-directory . tramp-fuse-handle-delete-directory)
+    (delete-file . tramp-fuse-handle-delete-file)
     ;; `diff-latest-backup-file' performed by default handler.
     (directory-file-name . tramp-handle-directory-file-name)
-    (directory-files . tramp-rclone-handle-directory-files)
+    (directory-files . tramp-fuse-handle-directory-files)
     (directory-files-and-attributes
      . tramp-handle-directory-files-and-attributes)
     (dired-compress-file . ignore)
@@ -90,15 +89,15 @@
     (expand-file-name . tramp-handle-expand-file-name)
     (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
     (file-acl . ignore)
-    (file-attributes . tramp-rclone-handle-file-attributes)
+    (file-attributes . tramp-fuse-handle-file-attributes)
     (file-directory-p . tramp-handle-file-directory-p)
     (file-equal-p . tramp-handle-file-equal-p)
-    (file-executable-p . tramp-rclone-handle-file-executable-p)
+    (file-executable-p . tramp-fuse-handle-file-executable-p)
     (file-exists-p . tramp-handle-file-exists-p)
     (file-in-directory-p . tramp-handle-file-in-directory-p)
     (file-local-copy . tramp-handle-file-local-copy)
     (file-modes . tramp-handle-file-modes)
-    (file-name-all-completions . tramp-rclone-handle-file-name-all-completions)
+    (file-name-all-completions . tramp-fuse-handle-file-name-all-completions)
     (file-name-as-directory . tramp-handle-file-name-as-directory)
     (file-name-case-insensitive-p . tramp-handle-file-name-case-insensitive-p)
     (file-name-completion . tramp-handle-file-name-completion)
@@ -110,7 +109,7 @@
     (file-notify-rm-watch . ignore)
     (file-notify-valid-p . ignore)
     (file-ownership-preserved-p . ignore)
-    (file-readable-p . tramp-rclone-handle-file-readable-p)
+    (file-readable-p . tramp-fuse-handle-file-readable-p)
     (file-regular-p . tramp-handle-file-regular-p)
     (file-remote-p . tramp-handle-file-remote-p)
     (file-selinux-context . tramp-handle-file-selinux-context)
@@ -124,7 +123,7 @@
     (insert-file-contents . tramp-handle-insert-file-contents)
     (load . tramp-handle-load)
     (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
-    (make-directory . tramp-rclone-handle-make-directory)
+    (make-directory . tramp-fuse-handle-make-directory)
     (make-directory-internal . ignore)
     (make-nearby-temp-file . tramp-handle-make-nearby-temp-file)
     (make-process . ignore)
@@ -277,86 +276,6 @@ file names."
      (list filename newname ok-if-already-exists keep-date
           preserve-uid-gid preserve-extended-attributes))))
 
-(defun tramp-rclone-handle-delete-directory
-    (directory &optional recursive trash)
-  "Like `delete-directory' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name directory) nil
-    (tramp-flush-directory-properties v localname)
-    (delete-directory (tramp-rclone-local-file-name directory) recursive 
trash)))
-
-(defun tramp-rclone-handle-delete-file (filename &optional trash)
-  "Like `delete-file' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name filename) nil
-    (delete-file (tramp-rclone-local-file-name filename) trash)
-    (tramp-flush-file-properties v localname)))
-
-(defun tramp-rclone-handle-directory-files
-    (directory &optional full match nosort count)
-  "Like `directory-files' for Tramp files."
-  (unless (file-exists-p directory)
-    (tramp-compat-file-missing (tramp-dissect-file-name directory) directory))
-  (when (file-directory-p directory)
-    (setq directory (file-name-as-directory (expand-file-name directory)))
-    (with-parsed-tramp-file-name directory nil
-      (let ((result
-            (tramp-compat-directory-files
-             (tramp-rclone-local-file-name directory) full match nosort 
count)))
-       ;; Massage the result.
-       (when full
-         (let ((local (concat "^" (regexp-quote (tramp-rclone-mount-point v))))
-               (remote (funcall (if (tramp-compat-file-name-quoted-p directory)
-                                    #'tramp-compat-file-name-quote #'identity)
-                                (file-remote-p directory))))
-           (setq result
-                 (mapcar
-                  (lambda (x) (replace-regexp-in-string local remote x))
-                  result))))
-       ;; Some storage systems do not return "." and "..".
-       (dolist (item '(".." "."))
-         (when (and (string-match-p (or match (regexp-quote item)) item)
-                    (not
-                     (member (if full (setq item (concat directory item)) item)
-                             result)))
-           (setq result (cons item result))))
-       ;; Return result.
-       (if nosort result (sort result #'string<))))))
-
-(defun tramp-rclone-handle-file-attributes (filename &optional id-format)
-  "Like `file-attributes' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name filename) nil
-    (with-tramp-file-property
-       v localname (format "file-attributes-%s" id-format)
-      (file-attributes (tramp-rclone-local-file-name filename) id-format))))
-
-(defun tramp-rclone-handle-file-executable-p (filename)
-  "Like `file-executable-p' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name filename) nil
-    (with-tramp-file-property v localname "file-executable-p"
-      (file-executable-p (tramp-rclone-local-file-name filename)))))
-
-(defun tramp-rclone-handle-file-name-all-completions (filename directory)
-  "Like `file-name-all-completions' for Tramp files."
-  (all-completions
-   filename
-   (delete-dups
-    (append
-     (file-name-all-completions
-      filename (tramp-rclone-local-file-name directory))
-     ;; Some storage systems do not return "." and "..".
-     (let (result)
-       (dolist (item '(".." ".") result)
-        (when (string-prefix-p filename item)
-          (catch 'match
-            (dolist (elt completion-regexp-list)
-              (unless (string-match-p elt item) (throw 'match nil)))
-            (setq result (cons (concat item "/") result))))))))))
-
-(defun tramp-rclone-handle-file-readable-p (filename)
-  "Like `file-readable-p' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name filename) nil
-    (with-tramp-file-property v localname "file-readable-p"
-      (file-readable-p (tramp-rclone-local-file-name filename)))))
-
 (defun tramp-rclone-handle-file-system-info (filename)
   "Like `file-system-info' for Tramp files."
   (ignore-errors
@@ -384,36 +303,6 @@ file names."
          (when (and total free)
            (list total free (- total free))))))))
 
-(defun tramp-rclone-handle-insert-directory
-  (filename switches &optional wildcard full-directory-p)
-  "Like `insert-directory' for Tramp files."
-  (insert-directory
-   (tramp-rclone-local-file-name filename) switches wildcard full-directory-p)
-  (goto-char (point-min))
-  (while (search-forward (tramp-rclone-local-file-name filename) nil 'noerror)
-    (replace-match filename)))
-
-(defun tramp-rclone-handle-insert-file-contents
-  (filename &optional visit beg end replace)
-  "Like `insert-file-contents' for Tramp files."
-  (let ((result
-        (insert-file-contents
-         (tramp-rclone-local-file-name filename) visit beg end replace)))
-    (prog1
-       (list (expand-file-name filename) (cadr result))
-      (when visit (setq buffer-file-name filename)))))
-
-(defun tramp-rclone-handle-make-directory (dir &optional parents)
-  "Like `make-directory' for Tramp files."
-  (with-parsed-tramp-file-name (expand-file-name dir) nil
-    (make-directory (tramp-rclone-local-file-name dir) parents)
-    ;; When PARENTS is non-nil, DIR could be a chain of non-existent
-    ;; directories a/b/c/...  Instead of checking, we simply flush the
-    ;; whole file cache.
-    (tramp-flush-file-properties v localname)
-    (tramp-flush-directory-properties
-     v (if parents "/" (file-name-directory localname)))))
-
 (defun tramp-rclone-handle-rename-file
   (filename newname &optional ok-if-already-exists)
   "Like `rename-file' for Tramp files."
@@ -431,50 +320,6 @@ file names."
 
 ;; File name conversions.
 
-(defun tramp-rclone-mount-point (vec)
-  "Return local mount point of VEC."
-  (expand-file-name
-   (concat
-    tramp-temp-name-prefix (tramp-file-name-method vec)
-    "." (tramp-file-name-host vec))
-   (tramp-compat-temporary-file-directory)))
-
-(defun tramp-rclone-mounted-p (vec)
-  "Check, whether storage system determined by VEC is mounted."
-  (when (tramp-get-connection-process vec)
-    ;; We cannot use `with-connection-property', because we don't want
-    ;; to cache a nil result.
-    (or (tramp-get-connection-property
-        (tramp-get-connection-process vec) "mounted" nil)
-       (let* ((default-directory (tramp-compat-temporary-file-directory))
-              (mount (shell-command-to-string "mount -t fuse.rclone")))
-         (tramp-message vec 6 "%s" "mount -t fuse.rclone")
-         (tramp-message vec 6 "\n%s" mount)
-         (tramp-set-connection-property
-          (tramp-get-connection-process vec) "mounted"
-          (when (string-match
-                 (format
-                  "^\\(%s:\\S-*\\)" (regexp-quote (tramp-file-name-host vec)))
-                 mount)
-            (match-string 1 mount)))))))
-
-(defun tramp-rclone-local-file-name (filename)
-  "Return local mount name of FILENAME."
-  (setq filename (tramp-compat-file-name-unquote (expand-file-name filename)))
-  (with-parsed-tramp-file-name filename nil
-    ;; As long as we call `tramp-rclone-maybe-open-connection' here,
-    ;; we cache the result.
-    (with-tramp-file-property v localname "local-file-name"
-      (tramp-rclone-maybe-open-connection v)
-      (let ((quoted (tramp-compat-file-name-quoted-p localname))
-           (localname (tramp-compat-file-name-unquote localname)))
-       (funcall
-        (if quoted #'tramp-compat-file-name-quote #'identity)
-        (expand-file-name
-         (if (file-name-absolute-p localname)
-             (substring localname 1) localname)
-         (tramp-rclone-mount-point v)))))))
-
 (defun tramp-rclone-remote-file-name (filename)
   "Return FILENAME as used in the `rclone' command."
   (setq filename (tramp-compat-file-name-unquote (expand-file-name filename)))
@@ -487,7 +332,7 @@ file names."
          ;; TODO: This shall be handled by `expand-file-name'.
          (setq localname
                (replace-regexp-in-string "^\\." "" (or localname "")))
-         (format "%s%s" (tramp-rclone-mounted-p v) localname)))
+         (format "%s%s" (tramp-fuse-mounted-p v) localname)))
     ;; It is a local file name.
     filename))
 
@@ -517,20 +362,18 @@ connection if a previous connection has died for some 
reason."
          (tramp-set-connection-local-variables vec)))
 
       ;; Create directory.
-      (unless (file-directory-p (tramp-rclone-mount-point vec))
-       (make-directory (tramp-rclone-mount-point vec) 'parents))
+      (unless (file-directory-p (tramp-fuse-mount-point vec))
+       (make-directory (tramp-fuse-mount-point vec) 'parents))
 
       ;; Mount.  This command does not return, so we use 0 as
       ;; DESTINATION of `tramp-call-process'.
-      (unless (tramp-rclone-mounted-p vec)
+      (unless (tramp-fuse-mounted-p vec)
        (apply
         #'tramp-call-process
         vec tramp-rclone-program nil 0 nil
-        (delq nil
-              `("mount" ,(concat host ":/")
-                ,(tramp-rclone-mount-point vec)
-                ;; This could be nil.
-                ,@(tramp-get-method-parameter vec 'tramp-mount-args))))
+        "mount" (tramp-fuse-mount-spec vec)
+        (tramp-fuse-mount-point vec)
+        (tramp-get-method-parameter vec 'tramp-mount-args))
        (while (not (file-exists-p (tramp-make-tramp-file-name vec 'noloc)))
          (tramp-cleanup-connection vec 'keep-debug 'keep-password))
 
diff --git a/tramp-sh.el b/tramp-sh.el
index 5730199..1764f2e 100644
--- a/tramp-sh.el
+++ b/tramp-sh.el
@@ -46,7 +46,6 @@
 (defconst tramp-default-remote-shell "/bin/sh"
   "The default remote shell Tramp applies.")
 
-;;;###tramp-autoload
 (defcustom tramp-inline-compress-start-size 4096
   "The minimum size of compressing where inline transfer.
 When inline transfer, compress transferred data of file whose
@@ -56,23 +55,12 @@ If it is nil, no compression at all will be applied."
   :group 'tramp
   :type '(choice (const nil) integer))
 
-;;;###tramp-autoload
 (defcustom tramp-copy-size-limit 10240
   "Maximum file size where inline copying is preferred to an out-of-the-band 
copy.
 If it is nil, out-of-the-band copy will be used without a check."
   :group 'tramp
   :type '(choice (const nil) integer))
 
-;;;###tramp-autoload
-(defcustom tramp-terminal-type "dumb"
-  "Value of TERM environment variable for logging in to remote host.
-Because Tramp wants to parse the output of the remote shell, it is easily
-confused by ANSI color escape sequences and suchlike.  Often, shell init
-files conditionalize this setup based on the TERM environment variable."
-  :group 'tramp
-  :type 'string)
-
-;;;###tramp-autoload
 (defcustom tramp-histfile-override "~/.tramp_history"
   "When invoking a shell, override the HISTFILE with this value.
 When setting to a string, it redirects the shell history to that
@@ -115,7 +103,6 @@ detected as prompt when being sent on echoing hosts, 
therefore.")
 (defconst tramp-end-of-heredoc (md5 tramp-end-of-output)
   "String used to recognize end of heredoc strings.")
 
-;;;###tramp-autoload
 (defcustom tramp-use-ssh-controlmaster-options t
   "Whether to use `tramp-ssh-controlmaster-options'.
 Set it to nil, if you use Control* or Proxy* options in your ssh
@@ -477,70 +464,6 @@ The string is used in `tramp-methods'.")
  (tramp-set-completion-function "psftp" tramp-completion-function-alist-ssh)
  (tramp-set-completion-function "fcp" tramp-completion-function-alist-ssh))
 
-;; "getconf PATH" yields:
-;; HP-UX: 
/usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
-;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
-;; GNU/Linux (Debian, Suse, RHEL): /bin:/usr/bin
-;; FreeBSD, DragonFly: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
-;; FreeBSD 12.1, Darwin: /usr/bin:/bin:/usr/sbin:/sbin
-;; IRIX64: /usr/bin
-;; QNAP QTS: ---
-;; Hydra: /run/current-system/sw/bin:/bin:/usr/bin
-;;;###tramp-autoload
-(defcustom tramp-remote-path
-  '(tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin"
-    "/usr/local/bin" "/usr/local/sbin" "/local/bin" "/local/freeware/bin"
-    "/local/gnu/bin" "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin"
-    "/opt/bin" "/opt/sbin" "/opt/local/bin")
-  "List of directories to search for executables on remote host.
-For every remote host, this variable will be set buffer local,
-keeping the list of existing directories on that host.
-
-You can use \"~\" in this list, but when searching for a shell which groks
-tilde expansion, all directory names starting with \"~\" will be ignored.
-
-`Default Directories' represent the list of directories given by
-the command \"getconf PATH\".  It is recommended to use this
-entry on head of this list, because these are the default
-directories for POSIX compatible commands.  On remote hosts which
-do not offer the getconf command (like cygwin), the value
-\"/bin:/usr/bin\" is used instead.  This entry is represented in
-the list by the special value `tramp-default-remote-path'.
-
-`Private Directories' are the settings of the $PATH environment,
-as given in your `~/.profile'.  This entry is represented in
-the list by the special value `tramp-own-remote-path'."
-  :group 'tramp
-  :type '(repeat (choice
-                 (const :tag "Default Directories" tramp-default-remote-path)
-                 (const :tag "Private Directories" tramp-own-remote-path)
-                 (string :tag "Directory"))))
-
-;;;###tramp-autoload
-(defcustom tramp-remote-process-environment
-  '("ENV=''" "TMOUT=0" "LC_CTYPE=''"
-    "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH=" "PAGER=cat"
-    "autocorrect=" "correct=")
-  "List of environment variables to be set on the remote host.
-
-Each element should be a string of the form ENVVARNAME=VALUE.  An
-entry ENVVARNAME= disables the corresponding environment variable,
-which might have been set in the init files like ~/.profile.
-
-Special handling is applied to some environment variables,
-which should not be set here:
-
-The PATH environment variable should be set via `tramp-remote-path'.
-
-The TERM environment variable should be set via `tramp-terminal-type'.
-
-The INSIDE_EMACS environment variable will automatically be set
-based on the Tramp and Emacs versions, and should not be set here."
-  :group 'tramp
-  :version "26.1"
-  :type '(repeat string))
-
-;;;###tramp-autoload
 (defcustom tramp-sh-extra-args
   '(("/bash\\'" . "-noediting -norc -noprofile")
     ("/zsh\\'" . "-f +Z -V"))
@@ -2370,53 +2293,29 @@ The method used must be an out-of-band method."
            (setq listener (number-to-string (+ 50000 (random 10000))))))
 
        ;; Compose copy command.
-       (setq host (or host "")
-             user (or user "")
-             port (or port "")
-             spec (format-spec-make
-                   ?t (tramp-get-connection-property
-                       (tramp-get-connection-process v) "temp-file" ""))
-             options (format-spec (tramp-ssh-controlmaster-options v) spec)
-             spec (format-spec-make
-                   ?h host ?u user ?p port ?r listener ?c options
-                   ?k (if keep-date " " "")
+       (setq options
+             (format-spec
+              (tramp-ssh-controlmaster-options v)
+              (format-spec-make
+               ?t (tramp-get-connection-property
+                   (tramp-get-connection-process v) "temp-file" "")))
+             spec (list
+                   ?h (or host "") ?u (or user "") ?p (or port "")
+                   ?r listener ?c options ?k (if keep-date " " "")
                     ?n (concat "2>" (tramp-get-remote-null-device v)))
              copy-program (tramp-get-method-parameter v 'tramp-copy-program)
              copy-keep-date (tramp-get-method-parameter
                              v 'tramp-copy-keep-date)
-
              copy-args
-             (delete
-              ;; " " has either been a replacement of "%k" (when
-              ;; keep-date argument is non-nil), or a replacement
-              ;; for the whole keep-date sublist.
-              " "
-              (dolist
-                  (x (tramp-get-method-parameter v 'tramp-copy-args) copy-args)
-                (setq copy-args
-                      (append
-                       copy-args
-                       (let ((y (mapcar (lambda (z) (format-spec z spec)) x)))
-                         (if (member "" y) '(" ") y))))))
-
-             copy-env
-             (delq
-              nil
-              (mapcar
-               (lambda (x)
-                 (setq x (mapcar (lambda (y) (format-spec y spec)) x))
-                 (unless (member "" x) (string-join x " ")))
-               (tramp-get-method-parameter v 'tramp-copy-env)))
-
+             ;; " " has either been a replacement of "%k" (when
+             ;; keep-date argument is non-nil), or a replacement for
+             ;; the whole keep-date sublist.
+             (delete " " (apply #'tramp-expand-args v 'tramp-copy-args spec))
+             copy-env (apply #'tramp-expand-args v 'tramp-copy-env spec)
              remote-copy-program
-             (tramp-get-method-parameter v 'tramp-remote-copy-program))
-
-       (dolist (x (tramp-get-method-parameter v 'tramp-remote-copy-args))
-         (setq remote-copy-args
-               (append
-                remote-copy-args
-                (let ((y (mapcar (lambda (z) (format-spec z spec)) x)))
-                  (if (member "" y) '(" ") y)))))
+             (tramp-get-method-parameter v 'tramp-remote-copy-program)
+             remote-copy-args
+             (apply #'tramp-expand-args v 'tramp-remote-copy-args spec))
 
        ;; Check for local copy program.
        (unless (executable-find copy-program)
@@ -2462,10 +2361,11 @@ The method used must be an out-of-band method."
                 v "process-name" (buffer-name (current-buffer)))
                (tramp-set-connection-property
                 v "process-buffer" (current-buffer))
-               (while copy-env
+               (when copy-env
                  (tramp-message
-                  orig-vec 6 "%s=\"%s\"" (car copy-env) (cadr copy-env))
-                 (setenv (pop copy-env) (pop copy-env)))
+                  orig-vec 6 "%s=\"%s\""
+                  (car copy-env) (string-join (cdr copy-env) " "))
+                 (setenv (car copy-env) (string-join (cdr copy-env) " ")))
                (setq
                 copy-args
                 (append
@@ -3754,6 +3654,8 @@ Fall back to normal file name handler if no Tramp handler 
exists."
   (setq file-name (expand-file-name file-name))
   (with-parsed-tramp-file-name file-name nil
     (let ((default-directory (file-name-directory file-name))
+          (process-environment
+           (cons "GIO_USE_FILE_MONITOR=help" process-environment))
          command events filter p sequence)
       (cond
        ;; "inotifywait".
@@ -3786,18 +3688,6 @@ Fall back to normal file name handler if no Tramp 
handler exists."
                '(created changed changes-done-hint moved deleted))
               ((memq 'attribute-change flags) '(attribute-changed)))
              sequence `(,command "monitor" ,localname)))
-       ;; "gvfs-monitor-dir".
-       ((setq command (tramp-get-remote-gvfs-monitor-dir v))
-       (setq filter #'tramp-sh-gvfs-monitor-dir-process-filter
-             events
-             (cond
-              ((and (memq 'change flags) (memq 'attribute-change flags))
-               '(created changed changes-done-hint moved deleted
-                         attribute-changed))
-              ((memq 'change flags)
-               '(created changed changes-done-hint moved deleted))
-              ((memq 'attribute-change flags) '(attribute-changed)))
-             sequence `(,command ,localname)))
        ;; None.
        (t (tramp-error
           v 'file-notify-error
@@ -3830,10 +3720,6 @@ Fall back to normal file name handler if no Tramp 
handler exists."
        (unless (process-live-p p)
          (tramp-error
           p 'file-notify-error "Monitoring not supported for `%s'" file-name))
-       ;; Set "gio-file-monitor" property if needed.
-       (when (string-equal (file-name-nondirectory command) "gio")
-         (tramp-set-connection-property
-          p "gio-file-monitor" (tramp-get-remote-gio-file-monitor v)))
        p))))
 
 (defun tramp-sh-gio-monitor-process-filter (proc string)
@@ -3854,91 +3740,64 @@ Fall back to normal file name handler if no Tramp 
handler exists."
                  "changes done" "changes-done-hint" string)
           string (tramp-compat-string-replace
                  "renamed to" "moved" string))
-    ;; https://bugs.launchpad.net/bugs/1742946
-    (when
-       (string-match-p "Monitoring not supported\\|No locations given" string)
-      (delete-process proc))
-
-    ;; Delete empty lines.
-    (setq string (tramp-compat-string-replace "\n\n" "\n" string))
-
-    (while (string-match
-           (eval-when-compile
-             (concat "^[^:]+:"
-                     "[[:space:]]\\([^:]+\\):"
-                     "[[:space:]]" (regexp-opt tramp-gio-events t)
-                     "\\([[:space:]]\\([^:]+\\)\\)?$"))
-           string)
-
-      (let* ((file (match-string 1 string))
-            (file1 (match-string 4 string))
-            (object
-             (list
-              proc
-              (list
-               (intern-soft (match-string 2 string)))
-              ;; File names are returned as absolute paths.  We must
-              ;; add the remote prefix.
-              (concat remote-prefix file)
-              (when file1 (concat remote-prefix file1)))))
-       (setq string (replace-match "" nil nil string))
-       ;; Usually, we would add an Emacs event now.  Unfortunately,
-       ;; `unread-command-events' does not accept several events at
-       ;; once.  Therefore, we apply the handler directly.
-       (when (member (cl-caadr object) events)
-         (tramp-compat-funcall
-          (lookup-key special-event-map [file-notify])
-          `(file-notify ,object file-notify-callback)))))
 
-    ;; Save rest of the string.
-    (when (zerop (length string)) (setq string nil))
-    (when string (tramp-message proc 10 "Rest string:\n%s" string))
-    (process-put proc 'rest-string string)))
-
-(defun tramp-sh-gvfs-monitor-dir-process-filter (proc string)
-  "Read output from \"gvfs-monitor-dir\" and add corresponding \
-`file-notify' events."
-  (let ((events (process-get proc 'events))
-       (remote-prefix
-        (with-current-buffer (process-buffer proc)
-          (file-remote-p default-directory)))
-       (rest-string (process-get proc 'rest-string)))
-    (when rest-string
-      (tramp-message proc 10 "Previous string:\n%s" rest-string))
-    (tramp-message proc 6 "%S\n%s" proc string)
-    (setq string (concat rest-string string)
-         ;; Attribute change is returned in unused wording.
-         string (tramp-compat-string-replace
-                 "ATTRIB CHANGED" "ATTRIBUTE_CHANGED" string))
-
-    (while (string-match
-           (concat "^[\n\r]*"
-                   "Directory Monitor Event:[\n\r]+"
-                   "Child = \\([^\n\r]+\\)[\n\r]+"
-                   "\\(Other = \\([^\n\r]+\\)[\n\r]+\\)?"
-                   "Event = \\([^[:blank:]]+\\)[\n\r]+")
-           string)
-      (let* ((file (match-string 1 string))
-            (file1 (match-string 3 string))
-            (object
-             (list
-              proc
-              (list
-               (intern-soft
-                (tramp-compat-string-replace
-                 "_" "-" (downcase (match-string 4 string)))))
-              ;; File names are returned as absolute paths.  We must
-              ;; add the remote prefix.
-              (concat remote-prefix file)
-              (when file1 (concat remote-prefix file1)))))
-       (setq string (replace-match "" nil nil string))
-       ;; Usually, we would add an Emacs event now.  Unfortunately,
-       ;; `unread-command-events' does not accept several events at
-       ;; once.  Therefore, we apply the handler directly.
-       (when (member (cl-caadr object) events)
-         (tramp-compat-funcall
-          (lookup-key special-event-map [file-notify])
-          `(file-notify ,object file-notify-callback)))))
+    (catch 'doesnt-work
+      ;; https://bugs.launchpad.net/bugs/1742946
+      (when
+          (string-match-p "Monitoring not supported\\|No locations given" 
string)
+        (delete-process proc)
+        (throw 'doesnt-work nil))
+
+      ;; Determine monitor name.
+      (unless (tramp-connection-property-p proc "gio-file-monitor")
+        (cond
+         ;; We have seen this only on cygwin gio, which uses the
+         ;; GPollFileMonitor.
+         ((string-match
+           "Can't find module 'help' specified in GIO_USE_FILE_MONITOR" string)
+          (tramp-set-connection-property
+           proc "gio-file-monitor" 'GPollFileMonitor))
+         ;; TODO: What happens, if several monitor names are reported?
+         ((string-match "\
+Supported arguments for GIO_USE_FILE_MONITOR environment variable:
+\\s-*\\([[:alpha:]]+\\) - 20" string)
+          (tramp-set-connection-property
+           proc "gio-file-monitor"
+           (intern
+            (format "G%sFileMonitor" (capitalize (match-string 1 string))))))
+         (t (throw 'doesnt-work nil)))
+        (setq string (replace-match "" nil nil string)))
+
+      ;; Delete empty lines.
+      (setq string (tramp-compat-string-replace "\n\n" "\n" string))
+
+      (while (string-match
+             (eval-when-compile
+               (concat "^[^:]+:"
+                       "[[:space:]]\\([^:]+\\):"
+                       "[[:space:]]" (regexp-opt tramp-gio-events t)
+                       "\\([[:space:]]\\([^:]+\\)\\)?$"))
+             string)
+
+        (let* ((file (match-string 1 string))
+              (file1 (match-string 4 string))
+              (object
+               (list
+                proc
+                (list
+                 (intern-soft (match-string 2 string)))
+                ;; File names are returned as absolute paths.  We
+                ;; must add the remote prefix.
+                (concat remote-prefix file)
+                (when file1 (concat remote-prefix file1)))))
+         (setq string (replace-match "" nil nil string))
+         ;; Usually, we would add an Emacs event now.  Unfortunately,
+         ;; `unread-command-events' does not accept several events at
+         ;; once.  Therefore, we apply the handler directly.
+         (when (member (cl-caadr object) events)
+           (tramp-compat-funcall
+            (lookup-key special-event-map [file-notify])
+            `(file-notify ,object file-notify-callback))))))
 
     ;; Save rest of the string.
     (when (zerop (length string)) (setq string nil))
@@ -4918,7 +4777,7 @@ If there is just some editing, retry it after 5 seconds."
       (progn
        (tramp-message
         vec 5 "Cannot timeout session, trying it again in %s seconds." 5)
-       (run-at-time 5 nil 'tramp-timeout-session vec))
+       (run-at-time 5 nil #'tramp-timeout-session vec))
     (tramp-message
      vec 3 "Timeout session %s" (tramp-make-tramp-file-name vec 'noloc))
     (tramp-cleanup-connection vec 'keep-debug nil 'keep-processes)))
@@ -5049,19 +4908,17 @@ connection if a previous connection has died for some 
reason."
                         (l-domain (tramp-file-name-domain hop))
                         (l-host (tramp-file-name-host hop))
                         (l-port (tramp-file-name-port hop))
-                        (login-program
-                         (tramp-get-method-parameter hop 'tramp-login-program))
-                        (login-args
-                         (tramp-get-method-parameter hop 'tramp-login-args))
                         (remote-shell
                          (tramp-get-method-parameter hop 'tramp-remote-shell))
                         (extra-args (tramp-get-sh-extra-args remote-shell))
                         (async-args
-                         (tramp-get-method-parameter hop 'tramp-async-args))
+                         (tramp-compat-flatten-tree
+                          (tramp-get-method-parameter hop 'tramp-async-args)))
                         (connection-timeout
                          (tramp-get-method-parameter
                           hop 'tramp-connection-timeout))
-                        (command login-program)
+                        (command
+                         (tramp-get-method-parameter hop 'tramp-login-program))
                         ;; We don't create the temporary file.  In
                         ;; fact, it is just a prefix for the
                         ;; ControlPath option of ssh; the real
@@ -5075,11 +4932,7 @@ connection if a previous connection has died for some 
reason."
                          (with-tramp-connection-property
                              (tramp-get-process vec) "temp-file"
                            (tramp-compat-make-temp-name)))
-                        spec r-shell)
-
-                   ;; Add arguments for asynchronous processes.
-                   (when (and process-name async-args)
-                     (setq login-args (append async-args login-args)))
+                        r-shell)
 
                    ;; Check, whether there is a restricted shell.
                    (dolist (elt tramp-restricted-shell-hosts-alist)
@@ -5104,31 +4957,28 @@ connection if a previous connection has died for some 
reason."
 
                    ;; Replace `login-args' place holders.
                    (setq
-                    l-host (or l-host "")
-                    l-user (or l-user "")
-                    l-port (or l-port "")
-                    spec (format-spec-make ?t tmpfile)
-                    options (format-spec options spec)
-                    spec (format-spec-make
-                          ?h l-host ?u l-user ?p l-port ?c options
-                          ?l (concat remote-shell " " extra-args " -i"))
                     command
-                    (concat
-                     ;; We do not want to see the trailing local
-                     ;; prompt in `start-file-process'.
-                     (unless r-shell "exec ")
-                     command " "
-                     (mapconcat
-                      (lambda (x)
-                        (setq x (mapcar (lambda (y) (format-spec y spec)) x))
-                        (unless (member "" x) (string-join x " ")))
-                      login-args " ")
-                     ;; Local shell could be a Windows COMSPEC.  It
-                     ;; doesn't know the ";" syntax, but we must exit
-                     ;; always for `start-file-process'.  It could
-                     ;; also be a restricted shell, which does not
-                     ;; allow "exec".
-                     (when r-shell " && exit || exit")))
+                    (mapconcat
+                     #'identity
+                     (append
+                      ;; We do not want to see the trailing local
+                      ;; prompt in `start-file-process'.
+                      (unless r-shell '("exec"))
+                      `(,command)
+                      ;; Add arguments for asynchronous processes.
+                      (when process-name async-args)
+                      (tramp-expand-args
+                       hop 'tramp-login-args
+                       ?h (or l-host "") ?u (or l-user "") ?p (or l-port "")
+                       ?c (format-spec options (format-spec-make ?t tmpfile))
+                       ?l (concat remote-shell " " extra-args " -i"))
+                      ;; Local shell could be a Windows COMSPEC.  It
+                      ;; doesn't know the ";" syntax, but we must
+                      ;; exit always for `start-file-process'.  It
+                      ;; could also be a restricted shell, which does
+                      ;; not allow "exec".
+                      (when r-shell '("&&" "exit" "||" "exit")))
+                     " "))
 
                    ;; Send the command.
                    (tramp-message vec 3 "Sending command `%s'" command)
@@ -5149,7 +4999,7 @@ connection if a previous connection has died for some 
reason."
                (when (tramp-get-connection-property p "session-timeout" nil)
                  (run-at-time
                   (tramp-get-connection-property p "session-timeout" nil) nil
-                  'tramp-timeout-session vec))
+                  #'tramp-timeout-session vec))
 
                ;; Make initial shell settings.
                (tramp-open-connection-setup-interactive-shell p vec)
@@ -5469,7 +5319,7 @@ Nonexistent directories are removed from spec."
                  (progn
                    (tramp-message
                     vec 3
-                   "`getconf PATH' not successful, using default value \"%s\"."
+                    "`getconf PATH' not successful, using default value 
\"%s\"."
                     "/bin:/usr/bin")
                    "/bin:/usr/bin"))))
             (own-remote-path
@@ -5756,42 +5606,6 @@ This command is returned only if 
`delete-by-moving-to-trash' is non-nil."
     (tramp-message vec 5 "Finding a suitable `gio-monitor' command")
     (tramp-find-executable vec "gio" (tramp-get-remote-path vec) t t)))
 
-(defun tramp-get-remote-gio-file-monitor (vec)
-  "Determine remote GFileMonitor."
-  (with-tramp-connection-property vec "gio-file-monitor"
-    (with-current-buffer (tramp-get-connection-buffer vec)
-      (tramp-message vec 5 "Finding the used GFileMonitor")
-      (when-let ((gio (tramp-get-remote-gio-monitor vec)))
-       ;; Search for the used FileMonitor.  There is no known way to
-       ;; get this information directly from gio, so we check for
-       ;; linked libraries of libgio.
-       (when (tramp-send-command-and-check vec (concat "ldd " gio))
-         (goto-char (point-min))
-         (when (re-search-forward "\\S-+/libgio\\S-+")
-           (when (tramp-send-command-and-check
-                  vec (concat "strings " (match-string 0)))
-             (goto-char (point-min))
-             (re-search-forward
-              (format
-               "^%s$"
-               (regexp-opt
-                '("GFamFileMonitor" "GFenFileMonitor"
-                  "GInotifyFileMonitor" "GKqueueFileMonitor")))
-              nil 'noerror)
-             (intern (match-string 0)))))))))
-
-(defun tramp-get-remote-gvfs-monitor-dir (vec)
-  "Determine remote `gvfs-monitor-dir' command."
-  (with-tramp-connection-property vec "gvfs-monitor-dir"
-    (tramp-message vec 5 "Finding a suitable `gvfs-monitor-dir' command")
-    ;; We distinguish "gvfs-monitor-dir.exe" from cygwin in order to
-    ;; establish better timeouts in filenotify-tests.el.  Any better
-    ;; distinction approach would be welcome!
-    (or (tramp-find-executable
-        vec "gvfs-monitor-dir.exe" (tramp-get-remote-path vec) t t)
-       (tramp-find-executable
-        vec "gvfs-monitor-dir" (tramp-get-remote-path vec) t t))))
-
 (defun tramp-get-remote-inotifywait (vec)
   "Determine remote `inotifywait' command."
   (with-tramp-connection-property vec "inotifywait"
diff --git a/tramp-smb.el b/tramp-smb.el
index 6935955..6fbf088 100644
--- a/tramp-smb.el
+++ b/tramp-smb.el
@@ -60,20 +60,17 @@
   tramp-smb-method
   '((tramp-parse-netrc "~/.netrc"))))
 
-;;;###tramp-autoload
 (defcustom tramp-smb-program "smbclient"
   "Name of SMB client to run."
   :group 'tramp
   :type 'string)
 
-;;;###tramp-autoload
 (defcustom tramp-smb-acl-program "smbcacls"
   "Name of SMB acls to run."
   :group 'tramp
   :type 'string
   :version "24.4")
 
-;;;###tramp-autoload
 (defcustom tramp-smb-conf null-device
   "Path of the \"smb.conf\" file.
 If it is nil, no \"smb.conf\" will be added to the `tramp-smb-program'
@@ -81,7 +78,6 @@ call, letting the SMB client use the default one."
   :group 'tramp
   :type '(choice (const nil) (file :must-match t)))
 
-;;;###tramp-autoload
 (defcustom tramp-smb-options nil
   "List of additional options.
 They are added to the `tramp-smb-program' call via \"--option '...'\".
@@ -305,7 +301,6 @@ See `tramp-actions-before-shell' for more info.")
 Operations not mentioned here will be handled by the default Emacs 
primitives.")
 
 ;; Options for remote processes via winexe.
-;;;###tramp-autoload
 (defcustom tramp-smb-winexe-program "winexe"
   "Name of winexe client to run.
 If it isn't found in the local $PATH, the absolute path of winexe
@@ -314,7 +309,6 @@ shall be given.  This is needed for remote processes."
   :type 'string
   :version "24.3")
 
-;;;###tramp-autoload
 (defcustom tramp-smb-winexe-shell-command "powershell.exe"
   "Shell to be used for processes on remote machines.
 This must be Powershell V2 compatible."
@@ -322,7 +316,6 @@ This must be Powershell V2 compatible."
   :type 'string
   :version "24.3")
 
-;;;###tramp-autoload
 (defcustom tramp-smb-winexe-shell-command-switch "-file -"
   "Command switch used together with `tramp-smb-winexe-shell-command'.
 This can be used to disable echo etc."
diff --git a/tramp-sshfs.el b/tramp-sshfs.el
new file mode 100644
index 0000000..c4a36fe
--- /dev/null
+++ b/tramp-sshfs.el
@@ -0,0 +1,367 @@
+;;; tramp-sshfs.el --- Tramp access functions via sshfs  -*- lexical-binding:t 
-*-
+
+;; Copyright (C) 2021 Free Software Foundation, Inc.
+
+;; Author: Michael Albinus <michael.albinus@gmx.de>
+;; Keywords: comm, processes
+;; Package: tramp
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; sshfs is a program to mount a virtual file system, based on an sftp
+;; connection.  Tramp uses its mount utility to access files and
+;; directories there.
+
+;; A remote file under sshfs control has the form
+;; "/sshfs:user@host#port:/path/to/file".  User name and port number
+;; are optional.
+
+;;; Code:
+
+(require 'tramp)
+(require 'tramp-fuse)
+
+;;;###tramp-autoload
+(defconst tramp-sshfs-method "sshfs"
+  "Tramp method for sshfs mounts.")
+
+(defcustom tramp-sshfs-program "sshfs"
+  "The sshfs mount command."
+  :group 'tramp
+  :version "28.1"
+  :type 'string)
+
+;;;###tramp-autoload
+(tramp--with-startup
+ (add-to-list 'tramp-methods
+             `(,tramp-sshfs-method
+               (tramp-mount-args            (("-C") ("-p" "%p")
+                                             ("-o" "idmap=user,reconnect")))
+               ;; These are for remote processes.
+                (tramp-login-program        "ssh")
+                (tramp-login-args           (("-q")("-l" "%u") ("-p" "%p")
+                                            ("-e" "none") ("%h") ("%l")))
+                (tramp-direct-async         t)
+                (tramp-remote-shell         ,tramp-default-remote-shell)
+                (tramp-remote-shell-login   ("-l"))
+                (tramp-remote-shell-args    ("-c"))))
+
+ (add-to-list 'tramp-connection-properties
+             `(,(format "/%s:" tramp-sshfs-method) "direct-async-process" t))
+
+ (tramp-set-completion-function
+  tramp-sshfs-method tramp-completion-function-alist-ssh))
+
+
+;; New handlers should be added here.
+;;;###tramp-autoload
+(defconst tramp-sshfs-file-name-handler-alist
+  '((access-file . tramp-handle-access-file)
+    (add-name-to-file . tramp-handle-add-name-to-file)
+    ;; `byte-compiler-base-file-name' performed by default handler.
+    (copy-directory . tramp-handle-copy-directory)
+    (copy-file . tramp-sshfs-handle-copy-file)
+    (delete-directory . tramp-fuse-handle-delete-directory)
+    (delete-file . tramp-fuse-handle-delete-file)
+    ;; `diff-latest-backup-file' performed by default handler.
+    (directory-file-name . tramp-handle-directory-file-name)
+    (directory-files . tramp-fuse-handle-directory-files)
+    (directory-files-and-attributes
+     . tramp-handle-directory-files-and-attributes)
+    (dired-compress-file . ignore)
+    (dired-uncache . tramp-handle-dired-uncache)
+    (exec-path . tramp-sshfs-handle-exec-path)
+    (expand-file-name . tramp-handle-expand-file-name)
+    (file-accessible-directory-p . tramp-handle-file-accessible-directory-p)
+    (file-acl . ignore)
+    (file-attributes . tramp-fuse-handle-file-attributes)
+    (file-directory-p . tramp-handle-file-directory-p)
+    (file-equal-p . tramp-handle-file-equal-p)
+    (file-executable-p . tramp-fuse-handle-file-executable-p)
+    (file-exists-p . tramp-handle-file-exists-p)
+    (file-in-directory-p . tramp-handle-file-in-directory-p)
+    (file-local-copy . tramp-handle-file-local-copy)
+    (file-modes . tramp-handle-file-modes)
+    (file-name-all-completions . tramp-fuse-handle-file-name-all-completions)
+    (file-name-as-directory . tramp-handle-file-name-as-directory)
+    (file-name-case-insensitive-p . tramp-handle-file-name-case-insensitive-p)
+    (file-name-completion . tramp-handle-file-name-completion)
+    (file-name-directory . tramp-handle-file-name-directory)
+    (file-name-nondirectory . tramp-handle-file-name-nondirectory)
+    ;; `file-name-sans-versions' performed by default handler.
+    (file-newer-than-file-p . tramp-handle-file-newer-than-file-p)
+    (file-notify-add-watch . ignore)
+    (file-notify-rm-watch . ignore)
+    (file-notify-valid-p . ignore)
+    (file-ownership-preserved-p . ignore)
+    (file-readable-p . tramp-fuse-handle-file-readable-p)
+    (file-regular-p . tramp-handle-file-regular-p)
+    (file-remote-p . tramp-handle-file-remote-p)
+    (file-selinux-context . tramp-handle-file-selinux-context)
+    (file-symlink-p . tramp-handle-file-symlink-p)
+    (file-system-info . tramp-sshfs-handle-file-system-info)
+    (file-truename . tramp-handle-file-truename)
+    (file-writable-p . tramp-handle-file-writable-p)
+    (find-backup-file-name . tramp-handle-find-backup-file-name)
+    ;; `get-file-buffer' performed by default handler.
+    (insert-directory . tramp-handle-insert-directory)
+    (insert-file-contents . tramp-sshfs-handle-insert-file-contents)
+    (load . tramp-handle-load)
+    (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
+    (make-directory . tramp-fuse-handle-make-directory)
+    (make-directory-internal . ignore)
+    (make-nearby-temp-file . tramp-handle-make-nearby-temp-file)
+    (make-process . tramp-handle-make-process)
+    (make-symbolic-link . tramp-handle-make-symbolic-link)
+    (process-file . tramp-sshfs-handle-process-file)
+    (rename-file . tramp-sshfs-handle-rename-file)
+    (set-file-acl . ignore)
+    (set-file-modes . tramp-sshfs-handle-set-file-modes)
+    (set-file-selinux-context . ignore)
+    (set-file-times . ignore)
+    (set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
+    (shell-command . tramp-handle-shell-command)
+    (start-file-process . tramp-handle-start-file-process)
+    (substitute-in-file-name . tramp-handle-substitute-in-file-name)
+    (temporary-file-directory . tramp-handle-temporary-file-directory)
+    (tramp-get-remote-gid . ignore)
+    (tramp-get-remote-uid . ignore)
+    (tramp-set-file-uid-gid . ignore)
+    (unhandled-file-name-directory . ignore)
+    (vc-registered . ignore)
+    (verify-visited-file-modtime . tramp-handle-verify-visited-file-modtime)
+    (write-region . tramp-sshfs-handle-write-region))
+"Alist of handler functions for Tramp SSHFS method.
+Operations not mentioned here will be handled by the default Emacs 
primitives.")
+
+;; It must be a `defsubst' in order to push the whole code into
+;; tramp-loaddefs.el.  Otherwise, there would be recursive autoloading.
+;;;###tramp-autoload
+(defsubst tramp-sshfs-file-name-p (filename)
+  "Check if it's a FILENAME for sshfs."
+  (and (tramp-tramp-file-p filename)
+       (string= (tramp-file-name-method (tramp-dissect-file-name filename))
+               tramp-sshfs-method)))
+
+;;;###tramp-autoload
+(defun tramp-sshfs-file-name-handler (operation &rest args)
+  "Invoke the sshfs handler for OPERATION and ARGS.
+First arg specifies the OPERATION, second arg is a list of
+arguments to pass to the OPERATION."
+  (if-let ((fn (assoc operation tramp-sshfs-file-name-handler-alist)))
+      (save-match-data (apply (cdr fn) args))
+    (tramp-run-real-handler operation args)))
+
+;;;###tramp-autoload
+(tramp--with-startup
+ (tramp-register-foreign-file-name-handler
+  #'tramp-sshfs-file-name-p #'tramp-sshfs-file-name-handler))
+
+
+;; File name primitives.
+
+(defun tramp-sshfs-handle-copy-file
+    (filename newname &optional ok-if-already-exists keep-date
+     preserve-uid-gid preserve-extended-attributes)
+  "Like `copy-file' for Tramp files."
+  (setq filename (expand-file-name filename)
+       newname (expand-file-name newname))
+  (if (file-directory-p filename)
+      (copy-directory filename newname keep-date t)
+    (copy-file
+     (if (tramp-sshfs-file-name-p filename)
+        (tramp-fuse-local-file-name filename) filename)
+     (if (tramp-sshfs-file-name-p newname)
+        (tramp-fuse-local-file-name newname) newname)
+     ok-if-already-exists keep-date
+     preserve-uid-gid preserve-extended-attributes)
+    (when (tramp-sshfs-file-name-p newname)
+      (with-parsed-tramp-file-name newname nil
+       (tramp-flush-file-properties v localname)))))
+
+(defun tramp-sshfs-handle-exec-path ()
+  "Like `exec-path' for Tramp files."
+  (append
+   (with-parsed-tramp-file-name default-directory nil
+     (with-tramp-connection-property (tramp-get-process v) "remote-path"
+       (with-temp-buffer
+        (process-file "getconf" nil t nil "PATH")
+        (split-string
+         (progn
+           ;; Read the expression.
+           (goto-char (point-min))
+           (buffer-substring (point) (point-at-eol)))
+         ":" 'omit))))
+   ;; The equivalent to `exec-directory'.
+   `(,(tramp-file-local-name (expand-file-name default-directory)))))
+
+(defun tramp-sshfs-handle-file-system-info (filename)
+  "Like `file-system-info' for Tramp files."
+  ;;`file-system-info' exists since Emacs 27.1.
+  (tramp-compat-funcall 'file-system-info (tramp-fuse-local-file-name 
filename)))
+
+(defun tramp-sshfs-handle-insert-file-contents
+  (filename &optional visit beg end replace)
+  "Like `insert-file-contents' for Tramp files."
+  (let ((result
+        (insert-file-contents
+         (tramp-fuse-local-file-name filename) visit beg end replace)))
+    (when visit (setq buffer-file-name filename))
+    (cons (expand-file-name filename) (cdr result))))
+
+(defun tramp-sshfs-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 default-directory nil
+    (let ((command
+          (format
+           "cd %s && exec %s"
+           localname
+           (mapconcat #'tramp-shell-quote-argument (cons program args) " "))))
+      (unwind-protect
+         (apply
+          #'tramp-call-process
+          v (tramp-get-method-parameter v 'tramp-login-program)
+          infile destination display
+          (tramp-expand-args
+           v 'tramp-login-args
+           ?h (or (tramp-file-name-host v) "")
+           ?u (or (tramp-file-name-user v) "")
+           ?p (or (tramp-file-name-port v) "")
+           ?l command))
+
+       (unless process-file-side-effects
+          (tramp-flush-directory-properties v ""))))))
+
+(defun tramp-sshfs-handle-rename-file
+    (filename newname &optional ok-if-already-exists)
+  "Like `rename-file' for Tramp files."
+  (setq filename (expand-file-name filename)
+       newname (expand-file-name newname))
+  (rename-file
+   (if (tramp-sshfs-file-name-p filename)
+       (tramp-fuse-local-file-name filename) filename)
+   (if (tramp-sshfs-file-name-p newname)
+       (tramp-fuse-local-file-name newname) newname)
+   ok-if-already-exists)
+  (when (tramp-sshfs-file-name-p filename)
+    (with-parsed-tramp-file-name filename nil
+      (tramp-flush-file-properties v localname)))
+  (when (tramp-sshfs-file-name-p newname)
+    (with-parsed-tramp-file-name newname nil
+      (tramp-flush-file-properties v localname))))
+
+(defun tramp-sshfs-handle-set-file-modes (filename mode &optional flag)
+  "Like `set-file-modes' for Tramp files."
+  (with-parsed-tramp-file-name filename nil
+    (unless (and (eq flag 'nofollow) (file-symlink-p filename))
+      (tramp-flush-file-properties v localname)
+      (tramp-compat-set-file-modes
+       (tramp-fuse-local-file-name filename) mode flag))))
+
+(defun tramp-sshfs-handle-write-region
+  (start end filename &optional append visit lockname mustbenew)
+  "Like `write-region' for Tramp files."
+  (setq filename (expand-file-name filename))
+  (with-parsed-tramp-file-name filename nil
+    (when (and mustbenew (file-exists-p filename)
+              (or (eq mustbenew 'excl)
+                  (not
+                   (y-or-n-p
+                    (format "File %s exists; overwrite anyway? " filename)))))
+      (tramp-error v 'file-already-exists filename))
+
+    (write-region
+     start end (tramp-fuse-local-file-name filename) append 'nomessage 
lockname)
+    (tramp-flush-file-properties v localname)
+
+    ;; The end.
+    (when (and (null noninteractive)
+              (or (eq visit t) (null visit) (stringp visit)))
+      (tramp-message v 0 "Wrote %s" filename))
+    (run-hooks 'tramp-handle-write-region-hook)))
+
+
+;; File name conversions.
+
+(defun tramp-sshfs-maybe-open-connection (vec)
+  "Maybe open a connection VEC.
+Does not do anything if a connection is already open, but re-opens the
+connection if a previous connection has died for some reason."
+  ;; During completion, don't reopen a new connection.
+  (unless (tramp-connectable-p vec)
+    (throw 'non-essential 'non-essential))
+
+  ;; We need a process bound to the connection buffer.  Therefore, we
+  ;; create a dummy process.  Maybe there is a better solution?
+  (unless (get-buffer-process (tramp-get-connection-buffer vec))
+    (let ((p (make-network-process
+             :name (tramp-get-connection-name vec)
+             :buffer (tramp-get-connection-buffer vec)
+             :server t :host 'local :service t :noquery t)))
+      (process-put p 'vector vec)
+      (set-process-query-on-exit-flag p nil)
+
+      ;; Set connection-local variables.
+      (tramp-set-connection-local-variables vec)
+
+      ;; Create directory.
+      (unless (file-directory-p (tramp-fuse-mount-point vec))
+       (make-directory (tramp-fuse-mount-point vec) 'parents))
+
+      (unless
+         (or (tramp-fuse-mounted-p vec)
+             (with-temp-buffer
+               (zerop
+                (apply
+                 #'tramp-call-process
+                 vec tramp-sshfs-program nil t nil
+                 (tramp-fuse-mount-spec vec)
+                 (tramp-fuse-mount-point vec)
+                 (tramp-expand-args
+                  vec 'tramp-mount-args
+                  ?p (or (tramp-file-name-port vec) "")))))
+         (tramp-error
+          vec 'file-error "Error mounting %s" (tramp-fuse-mount-spec vec))))
+
+      ;; Mark it as connected.
+      (tramp-set-connection-property
+       (tramp-get-connection-process vec) "connected" t)))
+
+  ;; In `tramp-check-cached-permissions', the connection properties
+  ;; "{uid,gid}-{integer,string}" are used.  We set them to proper values.
+  (with-tramp-connection-property
+      vec "uid-integer" (tramp-get-local-uid 'integer))
+  (with-tramp-connection-property
+      vec "gid-integer" (tramp-get-local-gid 'integer))
+  (with-tramp-connection-property
+      vec "uid-string" (tramp-get-local-uid 'string))
+  (with-tramp-connection-property
+      vec "gid-string" (tramp-get-local-gid 'string)))
+
+(add-hook 'tramp-unload-hook
+         (lambda ()
+           (unload-feature 'tramp-sshfs 'force)))
+
+(provide 'tramp-sshfs)
+
+;;; tramp-sshfs.el ends here
diff --git a/tramp-sudoedit.el b/tramp-sudoedit.el
index e181365..66737e6 100644
--- a/tramp-sudoedit.el
+++ b/tramp-sudoedit.el
@@ -791,22 +791,16 @@ in case of error, t otherwise."
   (tramp-sudoedit-maybe-open-connection vec)
   (with-current-buffer (tramp-get-connection-buffer vec)
     (erase-buffer)
-    (let* ((login (tramp-get-method-parameter vec 'tramp-sudo-login))
-          (host (or (tramp-file-name-host vec) ""))
-          (user (or (tramp-file-name-user vec) ""))
-          (spec (format-spec-make ?h host ?u user))
-          (args (append
-                 (tramp-compat-flatten-tree
-                  (mapcar
-                   (lambda (x)
-                     (setq x (mapcar (lambda (y) (format-spec y spec)) x))
-                     (unless (member "" x) x))
-                   login))
-                 (tramp-compat-flatten-tree (delq nil args))))
-          (delete-exited-processes t)
+    (let* ((delete-exited-processes t)
           (process-connection-type tramp-process-connection-type)
           (p (apply #'start-process
-                    (tramp-get-connection-name vec) (current-buffer) args))
+                    (tramp-get-connection-name vec) (current-buffer)
+                    (append
+                     (tramp-expand-args
+                      vec 'tramp-sudo-login
+                      ?h (or (tramp-file-name-host vec) "")
+                      ?u (or (tramp-file-name-user vec) ""))
+                     (tramp-compat-flatten-tree args))))
           ;; We suppress the messages `Waiting for prompts from remote shell'.
           (tramp-verbose (if (= tramp-verbose 3) 2 tramp-verbose))
           ;; We do not want to save the password.
diff --git a/tramp.el b/tramp.el
index 1ba5bcc..f509afc 100644
--- a/tramp.el
+++ b/tramp.el
@@ -386,6 +386,8 @@ Also see `tramp-default-method-alist'."
   :type 'string)
 
 (defcustom tramp-default-method-alist nil
+  ;; FIXME: This is not an "alist", because its elements are not of
+  ;; the form (KEY . VAL) but (KEY1 KEY2 VAL).
   "Default method to use for specific host/user pairs.
 This is an alist of items (HOST USER METHOD).  The first matching item
 specifies the method to use for a file name which does not specify a
@@ -413,6 +415,8 @@ This variable is regarded as obsolete, and will be removed 
soon."
   :type '(choice (const nil) string))
 
 (defcustom tramp-default-user-alist nil
+  ;; FIXME: This is not an "alist", because its elements are not of
+  ;; the form (KEY . VAL) but (KEY1 KEY2 VAL).
   "Default user to use for specific method/host pairs.
 This is an alist of items (METHOD HOST USER).  The first matching item
 specifies the user to use for a file name which does not specify a
@@ -432,6 +436,8 @@ Useful for su and sudo methods mostly."
   :type 'string)
 
 (defcustom tramp-default-host-alist nil
+  ;; FIXME: This is not an "alist", because its elements are not of
+  ;; the form (KEY . VAL) but (KEY1 KEY2 VAL).
   "Default host to use for specific method/user pairs.
 This is an alist of items (METHOD USER HOST).  The first matching item
 specifies the host to use for a file name which does not specify a
@@ -447,6 +453,8 @@ empty string for the method name."
                       (choice :tag "    Host name" string (const nil)))))
 
 (defcustom tramp-default-proxies-alist nil
+  ;; FIXME: This is not an "alist", because its elements are not of
+  ;; the form (KEY . VAL) but (KEY1 KEY2 VAL).
   "Route to be followed for specific host/user pairs.
 This is an alist of items (HOST USER PROXY).  The first matching
 item specifies the proxy to be passed for a file name located on
@@ -652,6 +660,14 @@ The regexp should match at end of buffer.
 See also `tramp-yesno-prompt-regexp'."
   :type 'regexp)
 
+(defcustom tramp-terminal-type "dumb"
+  "Value of TERM environment variable for logging in to remote host.
+Because Tramp wants to parse the output of the remote shell, it is easily
+confused by ANSI color escape sequences and suchlike.  Often, shell init
+files conditionalize this setup based on the TERM environment variable."
+  :group 'tramp
+  :type 'string)
+
 (defcustom tramp-terminal-prompt-regexp
   (concat "\\("
          "TERM = (.*)"
@@ -1235,6 +1251,67 @@ let-bind this variable."
   :version "24.4"
   :type '(choice (const nil) integer))
 
+;; "getconf PATH" yields:
+;; HP-UX: 
/usr/bin:/usr/ccs/bin:/opt/ansic/bin:/opt/langtools/bin:/opt/fortran/bin
+;; Solaris: /usr/xpg4/bin:/usr/ccs/bin:/usr/bin:/opt/SUNWspro/bin
+;; GNU/Linux (Debian, Suse, RHEL): /bin:/usr/bin
+;; FreeBSD, DragonFly: /usr/bin:/bin:/usr/sbin:/sbin: - beware trailing ":"!
+;; FreeBSD 12.1, Darwin: /usr/bin:/bin:/usr/sbin:/sbin
+;; IRIX64: /usr/bin
+;; QNAP QTS: ---
+;; Hydra: /run/current-system/sw/bin:/bin:/usr/bin
+(defcustom tramp-remote-path
+  '(tramp-default-remote-path "/bin" "/usr/bin" "/sbin" "/usr/sbin"
+    "/usr/local/bin" "/usr/local/sbin" "/local/bin" "/local/freeware/bin"
+    "/local/gnu/bin" "/usr/freeware/bin" "/usr/pkg/bin" "/usr/contrib/bin"
+    "/opt/bin" "/opt/sbin" "/opt/local/bin")
+  "List of directories to search for executables on remote host.
+For every remote host, this variable will be set buffer local,
+keeping the list of existing directories on that host.
+
+You can use \"~\" in this list, but when searching for a shell which groks
+tilde expansion, all directory names starting with \"~\" will be ignored.
+
+`Default Directories' represent the list of directories given by
+the command \"getconf PATH\".  It is recommended to use this
+entry on head of this list, because these are the default
+directories for POSIX compatible commands.  On remote hosts which
+do not offer the getconf command (like cygwin), the value
+\"/bin:/usr/bin\" is used instead.  This entry is represented in
+the list by the special value `tramp-default-remote-path'.
+
+`Private Directories' are the settings of the $PATH environment,
+as given in your `~/.profile'.  This entry is represented in
+the list by the special value `tramp-own-remote-path'."
+  :group 'tramp
+  :type '(repeat (choice
+                 (const :tag "Default Directories" tramp-default-remote-path)
+                 (const :tag "Private Directories" tramp-own-remote-path)
+                 (string :tag "Directory"))))
+
+(defcustom tramp-remote-process-environment
+  '("ENV=''" "TMOUT=0" "LC_CTYPE=''"
+    "CDPATH=" "HISTORY=" "MAIL=" "MAILCHECK=" "MAILPATH=" "PAGER=cat"
+    "autocorrect=" "correct=")
+  "List of environment variables to be set on the remote host.
+
+Each element should be a string of the form ENVVARNAME=VALUE.  An
+entry ENVVARNAME= disables the corresponding environment variable,
+which might have been set in the init files like ~/.profile.
+
+Special handling is applied to some environment variables,
+which should not be set here:
+
+The PATH environment variable should be set via `tramp-remote-path'.
+
+The TERM environment variable should be set via `tramp-terminal-type'.
+
+The INSIDE_EMACS environment variable will automatically be set
+based on the Tramp and Emacs versions, and should not be set here."
+  :group 'tramp
+  :version "26.1"
+  :type '(repeat string))
+
 (defcustom tramp-completion-reread-directory-timeout 10
   "Defines seconds since last remote command before rereading a directory.
 A remote directory might have changed its contents.  In order to
@@ -1710,6 +1787,10 @@ version, the function does nothing."
   "Used for highlighting Tramp debug buffers in `outline-mode'.")
 
 (defconst tramp-debug-font-lock-keywords
+  ;; FIXME: Make it a function instead of an ELisp expression, so you
+  ;; can evaluate it with `funcall' rather than `eval'!
+  ;; Also, in `font-lock-defaults' you can specify a function name for
+  ;; the "KEYWORDS" part, so font-lock calls it to get the actual keywords!
   '(list
     (concat "^\\(?:" tramp-debug-outline-regexp "\\).+")
     '(1 font-lock-warning-face t t)
@@ -1738,8 +1819,11 @@ The outline level is equal to the verbosity of the Tramp 
message."
        (outline-mode))
       (setq-local outline-level 'tramp-debug-outline-level)
       (setq-local font-lock-keywords
-                  `(t (eval ,tramp-debug-font-lock-keywords)
-                      ,(eval tramp-debug-font-lock-keywords)))
+                  ;; FIXME: This `(t FOO . BAR)' representation in
+                  ;; `font-lock-keywords' is supposed to be an
+                  ;; internal implementation "detail".  Don't abuse it here!
+                  `(t (eval ,tramp-debug-font-lock-keywords t)
+                      ,(eval tramp-debug-font-lock-keywords t)))
       ;; Do not edit the debug buffer.
       (use-local-map special-mode-map))
     (current-buffer)))
@@ -2625,6 +2709,14 @@ Add operations defined in `HANDLER-alist' to 
`tramp-file-name-handler'."
 
 ;;; File name handler functions for completion mode:
 
+;; This function takes action since Emacs 28.1, when
+;; `read-extended-command-predicate' is set to
+;; `command-completion-default-include-p'.
+(defun tramp-command-completion-p (_symbol buffer)
+  "A predicate for Tramp interactive commands.
+They are completed by \"M-x TAB\" only if the current buffer is remote."
+  (with-current-buffer buffer (tramp-tramp-file-p default-directory)))
+
 (defun tramp-connectable-p (vec-or-filename)
   "Check, whether it is possible to connect the remote host w/o side-effects.
 This is true, if either the remote host is already connected, or if we are
@@ -3717,15 +3809,15 @@ User is always nil."
     (setq choices tramp-default-proxies-alist)
     (while choices
       (setq item (pop choices)
-           proxy (eval (nth 2 item)))
+           proxy (eval (nth 2 item) t))
       (when (and
             ;; Host.
             (string-match-p
-             (or (eval (nth 0 item)) "")
+             (or (eval (nth 0 item) t) "")
              (or (tramp-file-name-host-port (car target-alist)) ""))
             ;; User.
             (string-match-p
-             (or (eval (nth 1 item)) "")
+             (or (eval (nth 1 item) t) "")
              (or (tramp-file-name-user-domain (car target-alist)) "")))
        (if (null proxy)
            ;; No more hops needed.
@@ -3776,6 +3868,22 @@ User is always nil."
     ;; Result.
     target-alist))
 
+(defun tramp-expand-args (vec parameter &rest spec-list)
+  "Expand login arguments as given by PARAMETER in `tramp-methods'.
+PARAMETER is a symbol like `tramp-login-args', denoting a list of
+list of strings from `tramp-methods', containing %-sequences for
+substitution.  SPEC-LIST is a list of char/value pairs used for
+`format-spec-make'."
+  (let ((args (tramp-get-method-parameter vec parameter))
+       (spec (apply 'format-spec-make spec-list)))
+    ;; Expand format spec.
+    (tramp-compat-flatten-tree
+     (mapcar
+      (lambda (x)
+       (setq x (mapcar (lambda (y) (format-spec y spec)) x))
+       (unless (member "" x) x))
+      args))))
+
 (defun tramp-direct-async-process-p (&rest args)
   "Whether direct async `make-process' can be called."
   (let ((v (tramp-dissect-file-name default-directory))
@@ -3857,14 +3965,11 @@ It does not support `:stderr'."
                (append `("cd" ,localname "&&" "(" "env") env `(,command ")"))))
 
          ;; Check for `tramp-sh-file-name-handler', because something
-         ;; is different between tramp-adb.el and tramp-sh.el.
+         ;; is different between tramp-sh.el, and tramp-adb.el or
+         ;; tramp-sshfs.el.
          (let* ((sh-file-name-handler-p (tramp-sh-file-name-handler-p v))
                 (login-program
                  (tramp-get-method-parameter v 'tramp-login-program))
-                (login-args
-                 (tramp-get-method-parameter v 'tramp-login-args))
-                (async-args
-                 (tramp-get-method-parameter v 'tramp-async-args))
                 ;; We don't create the temporary file.  In fact, it
                 ;; is just a prefix for the ControlPath option of
                 ;; ssh; the real temporary file has another name, and
@@ -3882,29 +3987,23 @@ It does not support `:stderr'."
                  (when sh-file-name-handler-p
                    (tramp-compat-funcall
                     'tramp-ssh-controlmaster-options v)))
-                spec p)
+                login-args p)
 
-           ;; Replace `login-args' place holders.
+           ;; Replace `login-args' place holders.  Split
+           ;; ControlMaster options.
            (setq
-            spec (format-spec-make ?t tmpfile)
-            options (format-spec (or options "") spec)
-            spec (format-spec-make
-                  ?h (or host "") ?u (or user "") ?p (or port "")
-                  ?c options ?l "")
-            ;; Add arguments for asynchronous processes.
-            login-args (append async-args login-args)
-            ;; Expand format spec.
-            login-args
-            (tramp-compat-flatten-tree
-             (mapcar
-              (lambda (x)
-                (setq x (mapcar (lambda (y) (format-spec y spec)) x))
-                (unless (member "" x) x))
-              login-args))
-            ;; Split ControlMaster options.
             login-args
-            (tramp-compat-flatten-tree
-             (mapcar (lambda (x) (split-string x " ")) login-args))
+            (append
+             (tramp-compat-flatten-tree
+              (tramp-get-method-parameter v 'tramp-async-args))
+             (tramp-compat-flatten-tree
+              (mapcar
+               (lambda (x) (split-string x " "))
+               (tramp-expand-args
+                v 'tramp-login-args
+                ?h (or host "") ?u (or user "") ?p (or port "")
+                ?c (format-spec (or options "") (format-spec-make ?t tmpfile))
+                ?l ""))))
             p (make-process
                :name name :buffer buffer
                :command (append `(,login-program) login-args command)
@@ -5473,11 +5572,6 @@ BODY is the backend specific code."
 ;;   strange when doing zerop, we should kill the process and start
 ;;   again.  (Greg Stark)
 ;;
-;; * I was wondering if it would be possible to use tramp even if I'm
-;;   actually using sshfs.  But when I launch a command I would like
-;;   to get it executed on the remote machine where the files really
-;;   are.  (Andrea Crotti)
-;;
 ;; * Run emerge on two remote files.  Bug is described here:
 ;;   <https://www.mail-archive.com/tramp-devel@nongnu.org/msg01041.html>.
 ;;   (Bug#6850)
diff --git a/trampver.el b/trampver.el
index c151892..34032c0 100644
--- a/trampver.el
+++ b/trampver.el
@@ -7,7 +7,7 @@
 ;; Maintainer: Michael Albinus <michael.albinus@gmx.de>
 ;; Keywords: comm, processes
 ;; Package: tramp
-;; Version: 2.5.0.2
+;; Version: 2.5.0.3
 ;; Package-Requires: ((emacs "25.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.5.0.2"
+(defconst tramp-version "2.5.0.3"
   "This version of Tramp.")
 
 ;;;###tramp-autoload
@@ -76,7 +76,7 @@
 ;; Check for Emacs version.
 (let ((x   (if (not (string-lessp emacs-version "25.1"))
       "ok"
-    (format "Tramp 2.5.0.2 is not fit for %s"
+    (format "Tramp 2.5.0.3 is not fit for %s"
             (replace-regexp-in-string "\n" "" (emacs-version))))))
   (unless (string-equal "ok" x) (error "%s" x)))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]