Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a1e5f12c53 | |||
| 011986306b | |||
| e1a9050c61 | |||
| af63f35ac1 | |||
| 667cf34622 | |||
| 4c21d696e9 | |||
| 469c96b6d2 | |||
| c4485188c9 | |||
| 4dc9b612ec | |||
| 695cd8916f | |||
| 7364b73e80 | |||
| 1dbc89f959 | |||
| d299217510 | |||
| fda6c8f862 | |||
| 6b10b3c8c0 | |||
| d3c6c338ae | |||
| 93c052a3cd | |||
| 76d11fa6f4 | |||
| 9ced6ca681 | |||
| de11ec091e | |||
| 37b79d06f8 | |||
| 2f1147c7d6 | |||
| b5d1484314 | |||
| d0c5fa3ed6 | |||
| eac420791c | |||
| 6480b66bd6 | |||
| 30a2668b99 | |||
| 4ed15c4c04 | |||
| fc7a57f0dc | |||
| f0452119e0 | |||
| fb174704dd | |||
| 39663c8288 | |||
| 646a3c417b | |||
| 303126bad9 | |||
| f0a0cc2b7e | |||
| 2c7c667576 | |||
| 1846b685c4 |
@@ -0,0 +1,19 @@
|
||||
version: '{build}'
|
||||
|
||||
install:
|
||||
|
||||
# install WinFsp
|
||||
- appveyor DownloadFile https://github.com/billziss-gh/winfsp/releases/download/v1.4B2/winfsp-1.4.18211.msi
|
||||
- for %%f in ("winfsp-*.msi") do start /wait msiexec /i %%f /qn INSTALLLEVEL=1000
|
||||
|
||||
# install FUSE for Cygwin (64-bit and 32-bit)
|
||||
- C:\cygwin64\bin\env.exe -i PATH=/bin bash "%ProgramFiles(x86)%\WinFsp\opt\cygfuse\install.sh"
|
||||
- C:\cygwin\bin\env.exe -i PATH=/bin bash "%ProgramFiles(x86)%\WinFsp\opt\cygfuse\install.sh"
|
||||
|
||||
# install additional Cygwin packages (64-bit and 32-bit)
|
||||
- C:\cygwin64\setup-x86_64.exe -qnNdO -R C:\cygwin64 -s http://cygwin.mirror.constant.com -l C:\cygwin64\var\cache\setup -P libglib2.0-devel -P meson
|
||||
- C:\cygwin\setup-x86.exe -qnNdO -R C:\cygwin -s http://cygwin.mirror.constant.com -l C:\cygwin\var\cache\setup -P libglib2.0-devel -P meson
|
||||
|
||||
build_script:
|
||||
- C:\cygwin64\bin\env.exe -i PATH=/bin bash test\appveyor-build.sh
|
||||
- C:\cygwin\bin\env.exe -i PATH=/bin bash test\appveyor-build.sh
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Issue report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
PLEASE READ BEFORE REPORTING AN ISSUE
|
||||
|
||||
SSHFS does not have any active, regular contributors or developers. The current maintainer continues to apply pull requests and tries to make regular releases, but unfortunately has no capacity to do any development beyond addressing high-impact issues. When reporting bugs, please understand that unless you are including a pull request or are reporting a critical issue, you will probably not get a response.
|
||||
|
||||
To prevent the issue tracker from being flooded with issues that no-one is intending to work on, and to give more visibilty to critical issues that users should be aware of and that most urgently need attention, I will also close most bug reports once they've been inactive for a while.
|
||||
|
||||
Please note that this isn't meant to imply that you haven't found a bug - you most likely have and I'm grateful that you took the time to report it. Unfortunately, SSHFS is a purely volunteer driven project,
|
||||
and at the moment there simply aren't any volunteers.
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
|
||||
language:
|
||||
- c
|
||||
@@ -14,8 +14,8 @@ addons:
|
||||
- gcc-6
|
||||
- python-docutils
|
||||
- python3-pip
|
||||
before_install:
|
||||
- sudo -H python3 -m pip install pip==8.1.1
|
||||
- python3-setuptools
|
||||
- ninja-build
|
||||
install: test/travis-install.sh
|
||||
script: test/travis-build.sh
|
||||
|
||||
|
||||
@@ -19,21 +19,40 @@ Anatol Pomozov <anatol.pomozov@gmail.com>
|
||||
Benjamin Fleischer <fleiben@gmail.com>
|
||||
Berserker <berserker.troll@yandex.com>
|
||||
Bill Zissimopoulos <billziss@navimatics.com>
|
||||
Brandon Carter <b-carter@users.noreply.github.com>
|
||||
Chris Wolfe <cwolfe@chromium.org>
|
||||
Clayton G. Hobbs <clay@lakeserv.net>
|
||||
Daniel Lublin <daniel@lublin.se>
|
||||
DrDaveD <2129743+DrDaveD@users.noreply.github.com>
|
||||
gala <gala132@users.noreply.github.com>
|
||||
Galen Getsov <4815620+ggetsov@users.noreply.github.com>
|
||||
George Vlahavas <vlahavas@gmail.com>
|
||||
G.raud Meyer <graud@gmx.com>
|
||||
harrim4n <git@harrim4n.com>
|
||||
Jakub Jelen <jjelen@redhat.com>
|
||||
Josh Triplett <josh@joshtriplett.org>
|
||||
Julio Merino <jmmv@google.com>
|
||||
Julio Merino <jmmv@meroh.net>
|
||||
kalvdans <github@kalvdans.no-ip.org>
|
||||
Michael Forney <mforney@mforney.org>
|
||||
Mike Kelly <mike@pair.com>
|
||||
Mike Salvatore <mike.s.salvatore@gmail.com>
|
||||
Miklos Szeredi <miklos@szeredi.hu>
|
||||
Miklos Szeredi <mszeredi@suse.cz>
|
||||
mssalvatore <mike.s.salvatore@gmail.com>
|
||||
Nikolaus Rath <Nikolaus@rath.org>
|
||||
Percy Jahn <email@percyjahn.de>
|
||||
Qais Patankar <qaisjp@gmail.com>
|
||||
Quentin Rameau <quinq@fifth.space>
|
||||
Reid Wagner <wagnerreid@gmail.com>
|
||||
Rian Hunter <rian@alum.mit.edu>
|
||||
Rian Hunter <rianhunter@users.noreply.github.com>
|
||||
Samuel Murray <samuel.murray@outlook.com>
|
||||
S. D. Cloudt <s.d.cloudt@student.tue.nl>
|
||||
smheidrich <smheidrich@weltenfunktion.de>
|
||||
sunwire <50745572+sunwire@users.noreply.github.com>
|
||||
Tim Harder <radhermit@gmail.com>
|
||||
Timo Savola <timo.savola@iki.fi>
|
||||
tpoindessous <thomas@poindessous.com>
|
||||
Viktor Szakats <vszakats@users.noreply.github.com>
|
||||
Zoltan Kuscsik <zoltan.kuscsik@linaro.org>
|
||||
|
||||
@@ -1,3 +1,48 @@
|
||||
Release 3.6.0 (2019-11-03)
|
||||
--------------------------
|
||||
|
||||
* Added "-o direct_io" option.
|
||||
This option disables the use of page cache in kernel.
|
||||
This is useful for example if the file size is not known before reading it.
|
||||
For example if you mount /proc dir from a remote host without the direct_io
|
||||
option, the read always will return zero bytes instead of actual data.
|
||||
* Added --verbose option.
|
||||
* Fixed a number of compiler warnings.
|
||||
* Improved performance under OS X.
|
||||
|
||||
|
||||
Release 3.5.2 (2019-04-13)
|
||||
--------------------------
|
||||
|
||||
* Fixed "-o idmap=user" to map both UID and GID on all OSs.
|
||||
* Fixed improper handling of sequential spaces spaces in "ssh_command" option
|
||||
|
||||
Release 3.5.1 (2018-12-22)
|
||||
--------------------------
|
||||
|
||||
* Documentation updates
|
||||
* Build system updates
|
||||
* Added "BindInterface" as valid "-o" option.
|
||||
|
||||
Release 3.5.0 (2018-08-28)
|
||||
--------------------------
|
||||
|
||||
* Fixed error code returned by rename(), allowing proper fallback.
|
||||
* Port to Cygwin.
|
||||
|
||||
Release 3.4.0 (2018-06-29)
|
||||
--------------------------
|
||||
|
||||
* Make utimens(NULL) result in timestamp "now" -- no more touched files
|
||||
dated 1970-01-01
|
||||
* New `createmode` workaround.
|
||||
* Fix `fstat` workaround regression.
|
||||
|
||||
Release 3.3.2 (2018-04-29)
|
||||
--------------------------
|
||||
|
||||
* New `renamexdev` workaround.
|
||||
|
||||
Release 3.3.1 (2017-10-25)
|
||||
--------------------------
|
||||
|
||||
|
||||
+21
-5
@@ -10,6 +10,20 @@ servers support and enable this SFTP access by default, so SSHFS is
|
||||
very simple to use - there's nothing to do on the server-side.
|
||||
|
||||
|
||||
Development Status
|
||||
------------------
|
||||
|
||||
SSHFS is shipped by all major Linux distributions and has been in
|
||||
production use across a wide range of systems for many years. However,
|
||||
at present SSHFS does not have any active, regular contributors, and
|
||||
there are a number of known issues (see the bugtracker). The current
|
||||
maintainer continues to apply pull requests and makes regular
|
||||
releases, but unfortunately has no capacity to do any development
|
||||
beyond addressing high-impact issues. When reporting bugs, please
|
||||
understand that unless you are including a pull request or are
|
||||
reporting a critical issue, you will probably not get a response.
|
||||
|
||||
|
||||
How to use
|
||||
----------
|
||||
|
||||
@@ -32,7 +46,7 @@ To unmount the filesystem::
|
||||
|
||||
fusermount -u mountpoint
|
||||
|
||||
On BSD and OS-X, to unmount the filesystem::
|
||||
On BSD and macOS, to unmount the filesystem::
|
||||
|
||||
umount mountpoint
|
||||
|
||||
@@ -42,7 +56,7 @@ Installation
|
||||
|
||||
First, download the latest SSHFS release from
|
||||
https://github.com/libfuse/sshfs/releases. On Linux and BSD, you will
|
||||
also need to install libfuse_ 3.1.0 or newer. On OS-X, you need
|
||||
also need to install libfuse_ 3.1.0 or newer. On macOS, you need
|
||||
OSXFUSE_ instead. Finally, you need the Glib_ library with development
|
||||
headers (which should be available from your operating system's
|
||||
package manager).
|
||||
@@ -51,7 +65,7 @@ To build and install, we recommend to use Meson_ (version 0.38 or
|
||||
newer) and Ninja_. After extracting the sshfs tarball, create a
|
||||
(temporary) build directory and run Meson::
|
||||
|
||||
$ md build; cd build
|
||||
$ mkdir build; cd build
|
||||
$ meson ..
|
||||
|
||||
Normally, the default build options will work fine. If you
|
||||
@@ -85,8 +99,10 @@ https://lists.sourceforge.net/lists/listinfo/fuse-sshfs).
|
||||
Please report any bugs on the GitHub issue tracker at
|
||||
https://github.com/libfuse/libfuse/issues.
|
||||
|
||||
|
||||
Professional Support
|
||||
--------------------
|
||||
|
||||
Professional support is available. Please contact Nikolaus Rath
|
||||
<Nikolaus@rath.org> for details.
|
||||
Professional support is offered via `Rath Consulting`_.
|
||||
|
||||
.. _`Rath Consulting`: http://www.rath-consulting.biz
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
project('sshfs', 'c', version: '3.3.1',
|
||||
meson_version: '>= 0.38',
|
||||
project('sshfs', 'c', version: '3.6.0',
|
||||
meson_version: '>= 0.40',
|
||||
default_options: [ 'buildtype=debugoptimized' ])
|
||||
|
||||
add_global_arguments('-D_REENTRANT', '-DHAVE_CONFIG_H',
|
||||
@@ -25,7 +25,7 @@ if not cc.compiles(code, args: [ '-O0', '-Werror=unused-result' ])
|
||||
endif
|
||||
|
||||
|
||||
rst2man = find_program('rst2man', required: false)
|
||||
rst2man = find_program('rst2man', 'rst2man.py', required: false)
|
||||
|
||||
cfg = configuration_data()
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <fuse.h>
|
||||
#include <fuse_opt.h>
|
||||
#if !defined(__CYGWIN__)
|
||||
#include <fuse_lowlevel.h>
|
||||
# include <fuse_lowlevel.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
# include <fuse_darwin.h>
|
||||
@@ -38,7 +38,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/poll.h>
|
||||
#include <poll.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <glib.h>
|
||||
@@ -214,10 +214,12 @@ struct sshfs {
|
||||
struct fuse_args ssh_args;
|
||||
char *workarounds;
|
||||
int rename_workaround;
|
||||
int renamexdev_workaround;
|
||||
int truncate_workaround;
|
||||
int buflimit_workaround;
|
||||
int unrel_append;
|
||||
int fstat_workaround;
|
||||
int createmode_workaround;
|
||||
int transform_symlinks;
|
||||
int follow_symlinks;
|
||||
int no_check_root;
|
||||
@@ -242,7 +244,9 @@ struct sshfs {
|
||||
int sync_write;
|
||||
int sync_read;
|
||||
int sync_readdir;
|
||||
int direct_io;
|
||||
int debug;
|
||||
int verbose;
|
||||
int foreground;
|
||||
int reconnect;
|
||||
int delay_connect;
|
||||
@@ -262,10 +266,8 @@ struct sshfs {
|
||||
int server_version;
|
||||
unsigned remote_uid;
|
||||
unsigned local_uid;
|
||||
#ifdef __APPLE__
|
||||
unsigned remote_gid;
|
||||
unsigned local_gid;
|
||||
#endif
|
||||
int remote_uid_detected;
|
||||
unsigned blksize;
|
||||
char *progname;
|
||||
@@ -298,6 +300,7 @@ static const char *ssh_opts[] = {
|
||||
"AddressFamily",
|
||||
"BatchMode",
|
||||
"BindAddress",
|
||||
"BindInterface",
|
||||
"CertificateFile",
|
||||
"ChallengeResponseAuthentication",
|
||||
"CheckHostIP",
|
||||
@@ -397,6 +400,7 @@ static struct fuse_opt sshfs_opts[] = {
|
||||
SSHFS_OPT("no_readahead", sync_read, 1),
|
||||
SSHFS_OPT("sync_readdir", sync_readdir, 1),
|
||||
SSHFS_OPT("sshfs_debug", debug, 1),
|
||||
SSHFS_OPT("sshfs_verbose", verbose, 1),
|
||||
SSHFS_OPT("reconnect", reconnect, 1),
|
||||
SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
|
||||
SSHFS_OPT("follow_symlinks", follow_symlinks, 1),
|
||||
@@ -407,6 +411,7 @@ static struct fuse_opt sshfs_opts[] = {
|
||||
SSHFS_OPT("disable_hardlink", disable_hardlink, 1),
|
||||
SSHFS_OPT("dir_cache=yes", dir_cache, 1),
|
||||
SSHFS_OPT("dir_cache=no", dir_cache, 0),
|
||||
SSHFS_OPT("direct_io", direct_io, 1),
|
||||
|
||||
SSHFS_OPT("-h", show_help, 1),
|
||||
SSHFS_OPT("--help", show_help, 1),
|
||||
@@ -414,6 +419,8 @@ static struct fuse_opt sshfs_opts[] = {
|
||||
SSHFS_OPT("--version", show_version, 1),
|
||||
SSHFS_OPT("-d", debug, 1),
|
||||
SSHFS_OPT("debug", debug, 1),
|
||||
SSHFS_OPT("-v", verbose, 1),
|
||||
SSHFS_OPT("verbose", verbose, 1),
|
||||
SSHFS_OPT("-f", foreground, 1),
|
||||
SSHFS_OPT("-s", singlethread, 1),
|
||||
|
||||
@@ -446,12 +453,16 @@ static struct fuse_opt workaround_opts[] = {
|
||||
SSHFS_OPT("none", fstat_workaround, 0),
|
||||
SSHFS_OPT("rename", rename_workaround, 1),
|
||||
SSHFS_OPT("norename", rename_workaround, 0),
|
||||
SSHFS_OPT("renamexdev", renamexdev_workaround, 1),
|
||||
SSHFS_OPT("norenamexdev", renamexdev_workaround, 0),
|
||||
SSHFS_OPT("truncate", truncate_workaround, 1),
|
||||
SSHFS_OPT("notruncate", truncate_workaround, 0),
|
||||
SSHFS_OPT("buflimit", buflimit_workaround, 1),
|
||||
SSHFS_OPT("nobuflimit", buflimit_workaround, 0),
|
||||
SSHFS_OPT("fstat", fstat_workaround, 1),
|
||||
SSHFS_OPT("nofstat", fstat_workaround, 0),
|
||||
SSHFS_OPT("createmode", createmode_workaround, 1),
|
||||
SSHFS_OPT("nocreatemode", createmode_workaround, 0),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
@@ -782,17 +793,12 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (sshfs.remote_uid_detected) {
|
||||
if (uid == sshfs.remote_uid)
|
||||
uid = sshfs.local_uid;
|
||||
if (gid == sshfs.remote_gid)
|
||||
gid = sshfs.local_gid;
|
||||
}
|
||||
#else /* !__APPLE__ */
|
||||
if (sshfs.remote_uid_detected && uid == sshfs.remote_uid)
|
||||
uid = sshfs.local_uid;
|
||||
#endif /* __APPLE__ */
|
||||
if (sshfs.idmap == IDMAP_FILE && sshfs.uid_map)
|
||||
if (translate_id(&uid, sshfs.uid_map) == -1)
|
||||
return -EPERM;
|
||||
@@ -1037,7 +1043,7 @@ static int start_ssh(void)
|
||||
perror("failed to redirect input/output");
|
||||
_exit(1);
|
||||
}
|
||||
if (!sshfs.foreground && devnull != -1)
|
||||
if (!sshfs.verbose && !sshfs.foreground && devnull != -1)
|
||||
dup2(devnull, 2);
|
||||
|
||||
close(devnull);
|
||||
@@ -1116,11 +1122,14 @@ static int connect_to(char *host, char *port)
|
||||
sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (sock == -1) {
|
||||
perror("failed to create socket");
|
||||
freeaddrinfo(ai);
|
||||
return -1;
|
||||
}
|
||||
err = connect(sock, ai->ai_addr, ai->ai_addrlen);
|
||||
if (err == -1) {
|
||||
perror("failed to connect");
|
||||
freeaddrinfo(ai);
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
opt = 1;
|
||||
@@ -1289,9 +1298,10 @@ static void chunk_put_locked(struct read_chunk *chunk)
|
||||
pthread_mutex_unlock(&sshfs.lock);
|
||||
}
|
||||
|
||||
static int clean_req(void *key_, struct request *req)
|
||||
static int clean_req(void *key_, struct request *req, gpointer user_data_)
|
||||
{
|
||||
(void) key_;
|
||||
(void) user_data_;
|
||||
|
||||
req->error = -EIO;
|
||||
if (req->want_reply)
|
||||
@@ -1593,10 +1603,8 @@ static void sftp_detect_uid()
|
||||
|
||||
sshfs.remote_uid = stbuf.st_uid;
|
||||
sshfs.local_uid = getuid();
|
||||
#ifdef __APPLE__
|
||||
sshfs.remote_gid = stbuf.st_gid;
|
||||
sshfs.local_gid = getgid();
|
||||
#endif
|
||||
sshfs.remote_uid_detected = 1;
|
||||
DEBUG("remote_uid = %i\n", sshfs.remote_uid);
|
||||
|
||||
@@ -1737,7 +1745,7 @@ static void *sshfs_init(struct fuse_conn_info *conn,
|
||||
sshfs.sync_read = 1;
|
||||
|
||||
// These workarounds require the "path" argument.
|
||||
cfg->nullpath_ok = ~(sshfs.truncate_workaround || sshfs.fstat_workaround);
|
||||
cfg->nullpath_ok = !(sshfs.truncate_workaround || sshfs.fstat_workaround);
|
||||
|
||||
// Lookup of . and .. is supported
|
||||
conn->capable |= FUSE_CAP_EXPORT_SUPPORT;
|
||||
@@ -2310,7 +2318,7 @@ static int sshfs_rename(const char *from, const char *to, unsigned int flags)
|
||||
int err;
|
||||
|
||||
if(flags != 0)
|
||||
return EINVAL;
|
||||
return -EINVAL;
|
||||
|
||||
if (sshfs.ext_posix_rename)
|
||||
err = sshfs_ext_posix_rename(from, to);
|
||||
@@ -2333,6 +2341,8 @@ static int sshfs_rename(const char *from, const char *to, unsigned int flags)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (err == -EPERM && sshfs.renamexdev_workaround)
|
||||
err = -EXDEV;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -2415,17 +2425,12 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
if (sshfs.remote_uid_detected) {
|
||||
if (uid == sshfs.local_uid)
|
||||
uid = sshfs.remote_uid;
|
||||
if (gid == sshfs.local_gid)
|
||||
gid = sshfs.remote_gid;
|
||||
}
|
||||
#else /* !__APPLE__ */
|
||||
if (sshfs.remote_uid_detected && uid == sshfs.local_uid)
|
||||
uid = sshfs.remote_uid;
|
||||
#endif /* __APPLE__ */
|
||||
if (sshfs.idmap == IDMAP_FILE && sshfs.r_uid_map)
|
||||
if(translate_id(&uid, sshfs.r_uid_map) == -1)
|
||||
return -EPERM;
|
||||
@@ -2465,6 +2470,14 @@ static int sshfs_utimens(const char *path, const struct timespec tv[2],
|
||||
int err;
|
||||
struct buffer buf;
|
||||
struct sshfs_file *sf = NULL;
|
||||
time_t asec = tv[0].tv_sec, msec = tv[1].tv_sec;
|
||||
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
if (asec == 0)
|
||||
asec = now.tv_sec;
|
||||
if (msec == 0)
|
||||
msec = now.tv_sec;
|
||||
|
||||
if (fi != NULL) {
|
||||
sf = get_sshfs_file(fi);
|
||||
@@ -2478,8 +2491,8 @@ static int sshfs_utimens(const char *path, const struct timespec tv[2],
|
||||
else
|
||||
buf_add_buf(&buf, &sf->handle);
|
||||
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
|
||||
buf_add_uint32(&buf, tv[0].tv_sec);
|
||||
buf_add_uint32(&buf, tv[1].tv_sec);
|
||||
buf_add_uint32(&buf, asec);
|
||||
buf_add_uint32(&buf, msec);
|
||||
|
||||
err = sftp_request(sf == NULL ? SSH_FXP_SETSTAT : SSH_FXP_FSETSTAT,
|
||||
&buf, SSH_FXP_STATUS, NULL);
|
||||
@@ -2505,6 +2518,9 @@ static int sshfs_open_common(const char *path, mode_t mode,
|
||||
if (sshfs.dir_cache)
|
||||
wrctr = cache_get_write_ctr();
|
||||
|
||||
if (sshfs.direct_io)
|
||||
fi->direct_io = 1;
|
||||
|
||||
if ((fi->flags & O_ACCMODE) == O_RDONLY)
|
||||
pflags = SSH_FXF_READ;
|
||||
else if((fi->flags & O_ACCMODE) == O_WRONLY)
|
||||
@@ -3095,6 +3111,9 @@ static int sshfs_statfs(const char *path, struct statvfs *buf)
|
||||
static int sshfs_create(const char *path, mode_t mode,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
if (sshfs.createmode_workaround)
|
||||
mode = 0;
|
||||
|
||||
return sshfs_open_common(path, mode, fi);
|
||||
}
|
||||
|
||||
@@ -3139,7 +3158,7 @@ static int sshfs_getattr(const char *path, struct stat *stbuf,
|
||||
struct buffer outbuf;
|
||||
struct sshfs_file *sf = NULL;
|
||||
|
||||
if (fi != NULL || sshfs.fstat_workaround) {
|
||||
if (fi != NULL && !sshfs.fstat_workaround) {
|
||||
sf = get_sshfs_file(fi);
|
||||
if (!sshfs_file_is_conn(sf))
|
||||
return -EIO;
|
||||
@@ -3350,6 +3369,7 @@ static void usage(const char *progname)
|
||||
" -o no_readahead synchronous reads (no speculative readahead)\n"
|
||||
" -o sync_readdir synchronous readdir\n"
|
||||
" -d, --debug print some debugging information (implies -f)\n"
|
||||
" -v, --verbose print ssh replies and messages\n"
|
||||
" -o dir_cache=BOOL enable caching of directory contents (names,\n"
|
||||
" attributes, symlink targets) {yes,no} (default: yes)\n"
|
||||
" -o dcache_max_size=N sets the maximum size of the directory cache (default: 10000)\n"
|
||||
@@ -3362,12 +3382,15 @@ static void usage(const char *progname)
|
||||
" -o dcache_min_clean_interval=N\n"
|
||||
" sets the interval for forced cleaning of the\n"
|
||||
" cache if full (default: 5)\n"
|
||||
" -o direct_io enable direct i/o\n"
|
||||
" -o workaround=LIST colon separated list of workarounds\n"
|
||||
" none no workarounds enabled\n"
|
||||
" [no]rename fix renaming to existing file (default: off)\n"
|
||||
" [no]renamexdev fix moving across filesystems (default: off)\n"
|
||||
" [no]truncate fix truncate for old servers (default: off)\n"
|
||||
" [no]buflimit fix buffer fillup bug in server (default: on)\n"
|
||||
" [no]fstat always use stat() instead of fstat() (default: off)\n"
|
||||
" [no]createmode always pass mode 0 to create (default: off)\n"
|
||||
" -o idmap=TYPE user/group ID mapping (default: " IDMAP_DEFAULT ")\n"
|
||||
" none no translation of the ID space\n"
|
||||
" user only translate UID/GID of connecting user\n"
|
||||
@@ -3431,7 +3454,51 @@ static int sshfs_opt_proc(void *data, const char *arg, int key,
|
||||
return 0;
|
||||
}
|
||||
else if (!sshfs.mountpoint) {
|
||||
sshfs.mountpoint = realpath(arg, NULL);
|
||||
#if defined(__CYGWIN__)
|
||||
/*
|
||||
* On FUSE for Cygwin the mountpoint may be a drive or directory.
|
||||
* Furthermore the mountpoint must NOT exist prior to mounting.
|
||||
* So we cannot use realpath(3).
|
||||
*/
|
||||
if ((('A' <= arg[0] && arg[0] <= 'Z') || ('a' <= arg[0] && arg[0] <= 'z'))
|
||||
&& ':' == arg[1] && '\0' == arg[2]) {
|
||||
/* drive: make a copy */
|
||||
sshfs.mountpoint = strdup(arg);
|
||||
} else {
|
||||
/* path: split into dirname, basename and check dirname */
|
||||
char *dir;
|
||||
const char *base;
|
||||
const char *slash = strrchr(arg, '/');
|
||||
if (slash) {
|
||||
char *tmp = strndup(arg, slash == arg ? 1 : slash - arg);
|
||||
dir = tmp ? realpath(tmp, NULL) : 0;
|
||||
base = slash + 1;
|
||||
free(tmp);
|
||||
} else {
|
||||
dir = realpath(".", NULL);
|
||||
base = arg;
|
||||
}
|
||||
if (dir) {
|
||||
slash = '/' == dir[0] && '\0' == dir[1] ? "" : "/";
|
||||
asprintf(&sshfs.mountpoint, "%s%s%s", dir, slash, base);
|
||||
free(dir);
|
||||
}
|
||||
}
|
||||
#else
|
||||
int fd, len;
|
||||
if (sscanf(arg, "/dev/fd/%u%n", &fd, &len) == 1 &&
|
||||
len == strlen(arg)) {
|
||||
/*
|
||||
* Allow /dev/fd/N unchanged; it can be
|
||||
* use for pre-mounting a generic fuse
|
||||
* mountpoint to later be completely
|
||||
* unprivileged with libfuse >= 3.3.0.
|
||||
*/
|
||||
sshfs.mountpoint = strdup(arg);
|
||||
} else {
|
||||
sshfs.mountpoint = realpath(arg, NULL);
|
||||
}
|
||||
#endif
|
||||
if (!sshfs.mountpoint) {
|
||||
fprintf(stderr, "sshfs: bad mount point `%s': %s\n",
|
||||
arg, strerror(errno));
|
||||
@@ -3543,40 +3610,60 @@ static int read_password(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Behaves similarly to strtok(), but allows for the ' ' delimiter to be escaped
|
||||
// by '\ '.
|
||||
static char *tokenize_on_space(char *str)
|
||||
{
|
||||
static char *pos = NULL;
|
||||
char *start = NULL;
|
||||
|
||||
if (str)
|
||||
pos = str;
|
||||
|
||||
if (!pos)
|
||||
return NULL;
|
||||
|
||||
// trim any leading spaces
|
||||
while (*pos == ' ')
|
||||
pos++;
|
||||
|
||||
start = pos;
|
||||
|
||||
while (pos && *pos != '\0') {
|
||||
// break on space, but not on '\ '
|
||||
if (*pos == ' ' && *(pos - 1) != '\\') {
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (*pos == '\0') {
|
||||
pos = NULL;
|
||||
}
|
||||
else {
|
||||
*pos = '\0';
|
||||
pos++;
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
static void set_ssh_command(void)
|
||||
{
|
||||
char *s;
|
||||
char *d;
|
||||
char *token = NULL;
|
||||
int i = 0;
|
||||
int end = 0;
|
||||
|
||||
d = sshfs.ssh_command;
|
||||
s = sshfs.ssh_command;
|
||||
while (!end) {
|
||||
switch (*s) {
|
||||
case '\0':
|
||||
end = 1;
|
||||
case ' ':
|
||||
*d = '\0';
|
||||
if (i == 0) {
|
||||
replace_arg(&sshfs.ssh_args.argv[0],
|
||||
sshfs.ssh_command);
|
||||
} else {
|
||||
if (fuse_opt_insert_arg(&sshfs.ssh_args, i,
|
||||
sshfs.ssh_command) == -1)
|
||||
_exit(1);
|
||||
}
|
||||
i++;
|
||||
d = sshfs.ssh_command;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (s[1])
|
||||
s++;
|
||||
default:
|
||||
*d++ = *s;
|
||||
token = tokenize_on_space(sshfs.ssh_command);
|
||||
while (token != NULL) {
|
||||
if (i == 0) {
|
||||
replace_arg(&sshfs.ssh_args.argv[0], token);
|
||||
} else {
|
||||
if (fuse_opt_insert_arg(&sshfs.ssh_args, i, token) == -1)
|
||||
_exit(1);
|
||||
}
|
||||
s++;
|
||||
i++;
|
||||
|
||||
token = tokenize_on_space(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3842,7 +3929,11 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#ifdef __APPLE__
|
||||
sshfs.blksize = 0;
|
||||
#else
|
||||
sshfs.blksize = 4096;
|
||||
#endif
|
||||
/* SFTP spec says all servers should allow at least 32k I/O */
|
||||
sshfs.max_read = 32768;
|
||||
sshfs.max_write = 32768;
|
||||
@@ -3851,8 +3942,10 @@ int main(int argc, char *argv[])
|
||||
#else
|
||||
sshfs.rename_workaround = 0;
|
||||
#endif
|
||||
sshfs.renamexdev_workaround = 0;
|
||||
sshfs.truncate_workaround = 0;
|
||||
sshfs.buflimit_workaround = 1;
|
||||
sshfs.createmode_workaround = 0;
|
||||
sshfs.ssh_ver = 2;
|
||||
sshfs.progname = argv[0];
|
||||
sshfs.rfd = -1;
|
||||
@@ -3889,7 +3982,9 @@ int main(int argc, char *argv[])
|
||||
if (sshfs.show_version) {
|
||||
printf("SSHFS version %s\n", PACKAGE_VERSION);
|
||||
printf("FUSE library version %s\n", fuse_pkgversion());
|
||||
#if !defined(__CYGWIN__)
|
||||
fuse_lowlevel_version();
|
||||
#endif
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,12 +107,16 @@ Options
|
||||
|
||||
:rename: Emulate overwriting an existing file by deleting and
|
||||
renaming.
|
||||
:renamexdev: Make rename fail with EXDEV instead of the default EPERM
|
||||
to allow moving files across remote filesystems.
|
||||
:truncate: Work around servers that don't support truncate by
|
||||
coping the whole file, truncating it locally, and sending it
|
||||
back.
|
||||
:fstat: Work around broken servers that don't support *fstat()* by
|
||||
using *stat* instead.
|
||||
:buflimit: Work around OpenSSH "buffer fillup" bug.
|
||||
:createmode: Work around broken servers that produce an error when passing a
|
||||
non-zero mode to create, by always passing a mode of 0.
|
||||
|
||||
-o idmap=TYPE
|
||||
How to map remote UID/GIDs to local values. Possible values are:
|
||||
@@ -198,6 +202,17 @@ Options
|
||||
sets the interval for forced cleaning of the directory cache
|
||||
when full.
|
||||
|
||||
-o direct_io
|
||||
This option disables the use of page cache (file content cache) in
|
||||
the kernel for this filesystem.
|
||||
This has several affects:
|
||||
1. Each read() or write() system call will initiate one or more read or
|
||||
write operations, data will not be cached in the kernel.
|
||||
2. The return value of the read() and write() system calls will correspond
|
||||
to the return values of the read and write operations. This is useful
|
||||
for example if the file size is not known in advance (before reading it).
|
||||
e.g. /proc filesystem
|
||||
|
||||
In addition, SSHFS accepts several options common to all FUSE file
|
||||
systems. These are described in the `mount.fuse` manpage (look
|
||||
for "general", "libfuse specific", and "high-level API" options).
|
||||
@@ -228,8 +243,19 @@ removed it, but before SSHFS had the time to rename the old file. In
|
||||
this case, the rename will still fail.
|
||||
|
||||
|
||||
SSHFS hangs
|
||||
~~~~~~~~~~~
|
||||
Permission denied when moving files across remote filesystems
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Most SFTP servers return only a generic "failure" when failing to rename
|
||||
across filesystem boundaries (EXDEV). sshfs normally converts this generic
|
||||
failure to a permission denied error (EPERM). If the option ``-o
|
||||
workaround=renamexdev`` is given, generic failures will be considered EXDEV
|
||||
errors which will make programs like `mv(1)` attempt to actually move the
|
||||
file after the failed rename.
|
||||
|
||||
|
||||
SSHFS hangs for no apparent reason
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
In some cases, attempts to access the SSHFS mountpoint may freeze if
|
||||
no filesystem activity has occured for some time. This is typically
|
||||
@@ -238,6 +264,34 @@ without SSHFS being informed about that. As a workaround, you can try
|
||||
to mount with ``-o ServerAliveInterval=15``. This will force the SSH
|
||||
connection to stay alive even if you have no activity.
|
||||
|
||||
|
||||
SSHFS hangs after the connection was interrupted
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
By default, network operations in SSHFS run without timeouts, mirroring the
|
||||
default behavior of SSH itself. As a consequence, if the connection to the
|
||||
remote host is interrupted (e.g. because a network cable was removed),
|
||||
operations on files or directories under the mountpoint will block until the
|
||||
connection is either restored or closed altogether (e.g. manually).
|
||||
Applications that try to access such files or directories will generally appear
|
||||
to "freeze" when this happens.
|
||||
|
||||
If it is acceptable to discard data being read or written, a quick workaround
|
||||
is to kill the responsible ``sshfs`` process, which will make any blocking
|
||||
operations on the mounted filesystem error out and thereby "unfreeze" the
|
||||
relevant applications. Note that force unmounting with ``fusermount -zu``, on
|
||||
the other hand, does not help in this case and will leave read/write operations
|
||||
in the blocking state.
|
||||
|
||||
For a more automatic solution, one can use the ``-o ServerAliveInterval=15``
|
||||
option mentioned above, which will drop the connection after not receiving a
|
||||
response for 3 * 15 = 45 seconds from the remote host. By also supplying ``-o
|
||||
reconnect``, one can ensure that the connection is re-established as soon as
|
||||
possible afterwards. As before, this will naturally lead to loss of data that
|
||||
was in the process of being read or written at the time when the connection was
|
||||
interrupted.
|
||||
|
||||
|
||||
Mounting from /etc/fstab
|
||||
========================
|
||||
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
machine=$(uname -m)
|
||||
mkdir build-$machine
|
||||
cd build-$machine
|
||||
meson ..
|
||||
ninja
|
||||
+14
-1
@@ -102,13 +102,14 @@ def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, capfd):
|
||||
# SSHFS only supports one second resolution when setting
|
||||
# file timestamps.
|
||||
tst_utimens(mnt_dir, tol=1)
|
||||
tst_utimens_now(mnt_dir)
|
||||
|
||||
tst_link(mnt_dir, cache_timeout)
|
||||
tst_truncate_path(mnt_dir)
|
||||
tst_truncate_fd(mnt_dir)
|
||||
tst_open_unlink(mnt_dir)
|
||||
except:
|
||||
cleanup(mnt_dir)
|
||||
cleanup(mount_process, mnt_dir)
|
||||
raise
|
||||
else:
|
||||
umount(mount_process, mnt_dir)
|
||||
@@ -403,6 +404,18 @@ def tst_utimens(mnt_dir, tol=0):
|
||||
assert abs(fstat.st_atime_ns - atime_ns) < tol*1e9
|
||||
assert abs(fstat.st_mtime_ns - mtime_ns) < tol*1e9
|
||||
|
||||
def tst_utimens_now(mnt_dir):
|
||||
fullname = pjoin(mnt_dir, name_generator())
|
||||
|
||||
fd = os.open(fullname, os.O_CREAT | os.O_RDWR)
|
||||
os.close(fd)
|
||||
os.utime(fullname, None)
|
||||
|
||||
fstat = os.lstat(fullname)
|
||||
# We should get now-timestamps
|
||||
assert fstat.st_atime != 0
|
||||
assert fstat.st_mtime != 0
|
||||
|
||||
def tst_passthrough(src_dir, mnt_dir, cache_timeout):
|
||||
name = name_generator()
|
||||
src_name = pjoin(src_dir, name)
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
set -e
|
||||
|
||||
sudo python3 -m pip install pytest meson
|
||||
wget https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-linux.zip
|
||||
unzip ninja-linux.zip
|
||||
chmod 755 ninja
|
||||
sudo chown root:root ninja
|
||||
sudo mv -fv ninja /usr/local/bin
|
||||
# Meson 0.45 requires Python 3.5 or newer
|
||||
sudo python3 -m pip install pytest meson==0.44
|
||||
valgrind --version
|
||||
ninja --version
|
||||
meson --version
|
||||
@@ -28,7 +24,7 @@ ls -d1 /usr/local/lib/*-linux-gnu | sudo tee /etc/ld.so.conf.d/usrlocal.conf
|
||||
sudo ldconfig
|
||||
|
||||
# Setup ssh
|
||||
ssh-keygen -b 768 -t rsa -f ~/.ssh/id_rsa -P ''
|
||||
ssh-keygen -b 1024 -t rsa -f ~/.ssh/id_rsa -P ''
|
||||
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
ssh -o "StrictHostKeyChecking=no" localhost echo "SSH connection succeeded"
|
||||
|
||||
+8
-2
@@ -20,13 +20,19 @@ def wait_for_mount(mount_process, mnt_dir,
|
||||
elapsed += 0.1
|
||||
pytest.fail("mountpoint failed to come up")
|
||||
|
||||
def cleanup(mnt_dir):
|
||||
def cleanup(mount_process, mnt_dir):
|
||||
subprocess.call(['fusermount', '-z', '-u', mnt_dir],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.STDOUT)
|
||||
mount_process.terminate()
|
||||
try:
|
||||
mount_process.wait(1)
|
||||
except subprocess.TimeoutExpired:
|
||||
mount_process.kill()
|
||||
|
||||
|
||||
def umount(mount_process, mnt_dir):
|
||||
subprocess.check_call(['fusermount', '-z', '-u', mnt_dir ])
|
||||
subprocess.check_call(['fusermount3', '-z', '-u', mnt_dir ])
|
||||
assert not os.path.ismount(mnt_dir)
|
||||
|
||||
# Give mount process a little while to terminate. Popen.wait(timeout)
|
||||
|
||||
Reference in New Issue
Block a user