Add Tramp sshfs method

* doc/misc/tramp.texi (Top, Configuration): Insert sections 'FUSE-based
methods' and 'FUSE setup' in menu.
(Quick Start Guide): Fix @anchors.  Add doas.  Extend section
'Using @command{rclone}' to 'Using @acronym{FUSE}-based methods'.
(External methods): Remove rclone paragraph.
(FUSE-based methods, FUSE setup): New nodes.
(Predefined connection information): Mention "mount-point".

* etc/NEWS: Mention Tramp sshfs method.
Fix typos and other oddities.

* lisp/net/tramp-fuse.el: New file.

* lisp/net/tramp-rclone.el (tramp-fuse): Require.
(tramp-rclone-file-name-handler-alist): Replace `tramp-rclone-handle-*'
by `tramp-fuse-handle-*' where appropriate.
(tramp-rclone-handle-delete-directory)
(tramp-rclone-handle-delete-file)
(tramp-rclone-handle-directory-files)
(tramp-rclone-handle-file-attributes)
(tramp-rclone-handle-file-executable-p)
(tramp-rclone-handle-file-name-all-completions)
(tramp-rclone-handle-file-readable-p)
(tramp-rclone-handle-insert-directory)
(tramp-rclone-handle-insert-file-contents)
(tramp-rclone-handle-make-directory, tramp-rclone-mount-point)
(tramp-rclone-mounted-p, tramp-rclone-local-file-name):
Remove.  Functionality moved to tramp-fuse.el.
(tramp-rclone-remote-file-name)
(tramp-rclone-maybe-open-connection): Use `tramp-fuse-*' functions.

* lisp/net/tramp-sh.el (tramp-do-copy-or-rename-file-out-of-band):
Simplify check.

* lisp/net/tramp-sshfs.el: New file.

* lisp/net/tramp.el: Remove TODO item.

* test/lisp/net/tramp-tests.el (tramp--test-sshfs-p): New defun.
(tramp-test14-delete-directory): Use it.
This commit is contained in:
Michael Albinus 2021-03-08 12:05:29 +01:00
parent a190bc9f30
commit 11d3af3c7b
8 changed files with 789 additions and 292 deletions

View file

@ -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,7 +597,34 @@ 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}
@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
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
@ -601,18 +635,6 @@ 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}
@cindex method @option{rclone}
@cindex @option{rclone} method
A convenient way to access system storages is the @command{rclone}
program. If you have configured a storage in @command{rclone} under a
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.
@node Configuration
@chapter Configuring @value{tramp}
@cindex configuration
@ -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"}@*
@ -2430,7 +2503,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 +2512,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 +2536,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 +2603,57 @@ 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 only the mount arguments, 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}.
@node Android shell setup
@section Android shell setup hints
@cindex android shell setup for ssh
@ -4197,6 +4318,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 +4570,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 +4969,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?

View file

@ -266,8 +266,8 @@ current mode.
+++
** New user option 'read-extended-command-predicate'.
This option controls how 'M-x' performs completion of commands when
you type TAB. By default, any command that matches what you have
This user option controls how 'M-x' performs completion of commands when
you type 'TAB'. By default, any command that matches what you have
typed is considered a completion candidate, but you can customize this
option to exclude commands that are not applicable to the current
buffer's major and minor modes, and respect the command's completion
@ -369,25 +369,26 @@ Typing 'TAB' on a heading line cycles the current section between
anywhere in the buffer cycles the whole buffer between "only top-level
headings", "all headings and subheadings", and "show all" states.
*** New option 'outline-minor-mode-cycle'.
This option customizes 'outline-minor-mode', with the difference
*** New user option 'outline-minor-mode-cycle'.
This user option customizes 'outline-minor-mode', with the difference
that 'TAB' and 'S-TAB' on heading lines cycle heading visibility.
Typing 'TAB' on a heading line cycles the current section between
"hide all", "subheadings", and "show all" states. Typing 'S-TAB' on a
heading line cycles the whole buffer between "only top-level
headings", "all headings and subheadings", and "show all" states.
*** New option 'outline-minor-mode-highlight'.
This option customizes 'outline-minor-mode'. It puts highlighting
on heading lines using standard outline faces. This works well only
when there are no conflicts with faces used by the major mode.
*** New user option 'outline-minor-mode-highlight'.
This user option customizes 'outline-minor-mode'. It puts
highlighting on heading lines using standard outline faces. This
works well only when there are no conflicts with faces used by the
major mode.
* Changes in Specialized Modes and Packages in Emacs 28.1
** Macroexp
---
*** New function 'macroexp-file-name' to know the name of the current file
*** New function 'macroexp-file-name' to know the name of the current file.
---
*** New function 'macroexp-compiling-p' to know if we're compiling.
---
@ -400,17 +401,18 @@ It used to be enabled when Emacs is started in GUI mode but not when started
in text mode. The cursor still only actually blinks in GUI frames.
** Bindat
+++
*** New 'Bindat type expression' description language.
This new system is provided by the new macro 'bindat-type' and
obsoletes the old data layout specifications. It supports
arbitrary-size integers, recursive types, and more. See the Info node
'Byte Packing' in the ELisp manual for more details.
"(elisp) Byte Packing" in the ELisp manual for more details.
** pcase
+++
*** The 'or' pattern now binds the union of the vars of its sub-patterns
*** The 'or' pattern now binds the union of the vars of its sub-patterns.
If a variable is not bound by the subpattern that matched, it gets bound
to nil. This was already sometimes the case, but it is now guaranteed.
@ -1031,10 +1033,9 @@ To customize obsolete user options, use 'customize-option' or
** Edebug
---
*** Obsoletions
---
**** 'get-edebug-spec' is obsolete, replaced by 'edebug-get-spec'.
+++
**** The spec operator ':name NAME' is obsolete, use '&name' instead.
+++
@ -1066,7 +1067,7 @@ use) and HEAD is the code that matched SPEC.
+++
*** New user option 'eldoc-echo-area-display-truncation-message'.
If non-nil (the default), eldoc will display a message saying
something like "(Documentation truncated. Use `M-x eldoc-doc-buffer'
something like "(Documentation truncated. Use `M-x eldoc-doc-buffer'
to see rest)" when a message has been truncated. If nil, truncated
messages will be marked with just "..." at the end.
@ -1134,6 +1135,10 @@ preferred over the eudcb-mab.el backend.
*** New connection method "mtp", which allows accessing media devices
like cell phones, tablets or cameras.
+++
*** New connection method "sshfs", which allows accessing remote files
via a file system mounted with 'sshfs'.
+++
*** Trashed remote files are moved to the local trash directory.
All remote files, which are trashed, are moved to the local trash
@ -1555,7 +1560,7 @@ have been renamed to have "proper" public names and documented
'xref-show-definitions-buffer-at-bottom').
*** New command 'xref-quit-and-pop-marker-stack' and a binding for it
in "*xref*" buffers ('M-,'). This combination is easy to press
in "*xref*" buffers ('M-,'). This combination is easy to press
semi-accidentally if the user wants to go back in the middle of
choosing the exact definition to go to, and this should do TRT.
@ -2138,7 +2143,7 @@ messages, contain the error name of that message now.
+++
*** D-Bus events have changed their internal structure.
They carry now the destination and the error-name of an event. They
also keep the type information of their arguments. Use the
also keep the type information of their arguments. Use the
'dbus-event-*' accessor functions.
** CPerl Mode
@ -2180,7 +2185,7 @@ You can type 'C-x u u' instead of 'C-x u C-x u' to undo many changes,
'C-x { { } } ^ ^ v v' to resize the selected window interactively,
'M-g n n p p' to navigate next-error matches. Any other key exits
transient mode and then is executed normally. 'repeat-exit-key'
defines an additional key to exit mode like 'isearch-exit' (RET).
defines an additional key to exit mode like 'isearch-exit' ('RET').
* New Modes and Packages in Emacs 28.1
@ -2296,7 +2301,7 @@ by mistake and were not useful to Lisp code.
---
** Loading 'generic-x' unconditionally loads all modes.
The user option `generic-extras-enable-list' is now obsolete, and
The user option 'generic-extras-enable-list' is now obsolete, and
setting it has no effect.
---
@ -2343,8 +2348,8 @@ ledit.el, lmenu.el, lucid.el and old-whitespace.el.
'dirtrack-debug-toggle', 'dynamic-completion-table',
'easy-menu-precalculate-equivalent-keybindings',
'epa-display-verify-result', 'epg-passphrase-callback-function',
'erc-announced-server-name', 'erc-process',
'erc-default-coding-system', 'erc-send-command', 'eshell-report-bug',
'erc-announced-server-name', 'erc-default-coding-system',
'erc-process', 'erc-send-command', 'eshell-report-bug',
'eval-next-after-load', 'exchange-dot-and-mark', 'ffap-bug',
'ffap-submit-bug', 'ffap-version', 'file-cache-choose-completion',
'forward-point', 'generic-char-p', 'global-highlight-changes',
@ -2391,7 +2396,7 @@ ledit.el, lmenu.el, lucid.el and old-whitespace.el.
'semantic-toplevel-bovine-table', 'semanticdb-mode-hooks',
'set-coding-priority', 'set-process-filter-multibyte',
'shadows-compare-text-p', 'shell-dirtrack-toggle',
'speedbar-update-speed', 'speedbar-navigating-speed', 't-mouse-mode',
'speedbar-navigating-speed', 'speedbar-update-speed', 't-mouse-mode',
'term-dynamic-simple-complete', 'tooltip-hook', 'tpu-have-ispell',
'url-generate-unique-filename', 'url-temporary-directory',
'vc-arch-command', 'vc-default-working-revision' (variable),
@ -2413,6 +2418,8 @@ back in Emacs 23.1. The affected functions are: 'make-obsolete',
** The variable 'keyboard-type' is obsolete and not dynamically scoped any more.
** The 'values' variable is now obsolete.
* Lisp Changes in Emacs 28.1
@ -2449,13 +2456,13 @@ This variable holds a list of currently enabled global minor modes (as
a list of symbols).
+++
** 'define-minor-mode' now takes an :interactive argument.
** 'define-minor-mode' now takes an ':interactive' argument.
This can be used for specifying which modes this minor mode is meant
for, or to make the new minor mode non-interactive. The default value
is t.
+++
** 'define-derived-mode' now takes an :interactive argument.
** 'define-derived-mode' now takes an ':interactive' argument.
This can be used to control whether the defined mode is a command
or not, and is useful when defining commands that aren't meant to be
used by users directly.
@ -2463,8 +2470,6 @@ used by users directly.
---
** The 'easymenu' library is now preloaded.
** The 'values' variable is now obsolete.
---
** New variable 'indent-line-ignored-functions'.
This allows modes to cycle through a set of indentation functions
@ -2495,10 +2500,11 @@ When non-nil, then functions 'read-char-choice' and 'y-or-n-p' (respectively)
use the function 'read-key' to read a character instead of using the minibuffer.
---
** New variable 'use-short-answers' to use 'y-or-n-p' instead of 'yes-or-no-p'.
This eliminates the need to define an alias that maps one to another
in the init file. The same variable also controls whether the
function 'read-answer' accepts short answers.
** New user option 'use-short-answers'.
When non-nil, the function 'y-or-n-p' is used instead of
'yes-or-no-p'. This eliminates the need to define an alias that maps
one to another in the init file. The same user option also controls
whether the function 'read-answer' accepts short answers.
+++
** 'set-window-configuration' now takes an optional 'dont-set-frame'
@ -2700,7 +2706,7 @@ menu handling.
It is meant as an (experimental) aid for converting Emacs Lisp code
to lexical binding, where dynamic (special) variables bound in one
file can affect code in another. For details, see the manual section
"(Elisp) Converting to Lexical Binding".
"(elisp) Converting to Lexical Binding".
+++
*** 'byte-recompile-directory' can now compile symlinked ".el" files.

205
lisp/net/tramp-fuse.el Normal file
View file

@ -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

View file

@ -35,8 +35,8 @@
;;; Code:
(eval-when-compile (require 'cl-lib))
(require 'tramp)
(require 'tramp-fuse)
;;;###tramp-autoload
(defconst tramp-rclone-method "rclone"
@ -77,11 +77,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 +90,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 +110,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 +124,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 +277,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 +304,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 +321,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 +333,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 +363,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))

View file

@ -2397,7 +2397,7 @@ The method used must be an out-of-band method."
(append
copy-args
(let ((y (mapcar (lambda (z) (format-spec z spec)) x)))
(if (member "" y) '(" ") y))))))
(unless (member "" y) y))))))
copy-env
(delq
@ -2416,7 +2416,7 @@ The method used must be an out-of-band method."
(append
remote-copy-args
(let ((y (mapcar (lambda (z) (format-spec z spec)) x)))
(if (member "" y) '(" ") y)))))
(unless (member "" y) y)))))
;; Check for local copy program.
(unless (executable-find copy-program)

318
lisp/net/tramp-sshfs.el Normal file
View file

@ -0,0 +1,318 @@
;;; 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.")
;;;###tramp-autoload
(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
(("-p" "%p")
("-o" "idmap=user,reconnect")))))
(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 . ignore)
(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 . ignore)
(make-symbolic-link . tramp-handle-make-symbolic-link)
;; (process-file . ignore)
(rename-file . tramp-sshfs-handle-rename-file)
(set-file-acl . ignore)
(set-file-modes . ignore)
(set-file-selinux-context . ignore)
(set-file-times . ignore)
(set-visited-file-modtime . tramp-handle-set-visited-file-modtime)
;; (shell-command . ignore)
;; (start-file-process . ignore)
(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-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-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-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)
(let* ((port (or (tramp-file-name-port vec) ""))
(spec (format-spec-make ?p port))
mount-args
(mount-args
(dolist
(x
(tramp-get-method-parameter vec 'tramp-mount-args)
mount-args)
(setq mount-args
(append
mount-args
(let ((y (mapcar
(lambda (z) (format-spec z spec))
x)))
(unless (member "" y) y)))))))
(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) mount-args))))
(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

View file

@ -5447,11 +5447,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)

View file

@ -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)))
@ -5819,6 +5820,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))
@ -6761,7 +6767,6 @@ If INTERACTIVE is non-nil, the tests are run interactively."
;; * Fix `tramp-test06-directory-file-name' for `ftp'.
;; * Implement `tramp-test31-interrupt-process' for `adb' and for
;; direct async processes.
;; * Fix `tramp-test44-threads'.
(provide 'tramp-tests)