Compare commits

...

17 Commits

Author SHA1 Message Date
Nikolaus Rath 695cd8916f Released 3.5.2 2019-04-13 09:25:45 +01:00
mssalvatore 7364b73e80 Gracefully handle multiple spaces in ssh_command option (#169)
When using the "ssh_command" option, commands with multiple spaces in a
row will not be properly parsed. Example:

Properly parsed:
    ssh_command = "ssh -o IdentityFile=~/.ssh/id_rsa"

Improperly parsed:
    ssh_command = "ssh -o      IdentityFile=~/.ssh/id_rsa"

This commit changes the ssh_command parsing logic so that both of the
above examples are considered valid and properly handled. 

Fixes: #114.
2019-04-08 21:50:10 +01:00
DrDaveD 1dbc89f959 allow /dev/fd/N as a mountpoint (#166) 2019-03-31 04:57:21 -04:00
Nikolaus Rath d299217510 Travis CI: Use Xenial instead of Trusty. 2019-02-27 21:27:39 +00:00
mssalvatore fda6c8f862 Update clean_req() to match the definition of GHRFunc (#160)
The current definition of the clean_req() function produces a compiler
warning as it expects 2 parameters but GHRFunc expects 3. This commit
resolves issue #157.
2019-02-25 21:00:53 +00:00
Clayton G. Hobbs 6b10b3c8c0 Also remap GID under non-MacOS
The manpage says that -o idmap=user maps the UID and GID, but it
apparently only mapped the UID.  The code was in place to map the GID as
well, but it was hidden behind #ifdef __APPLE__.  This commit removes
those #ifdefs, and in a couple of cases the code inside an #else, to
make the option behave as documented.
2019-01-04 19:39:47 +00:00
Nikolaus Rath d3c6c338ae Bump meson dependency
build_by_default arg in custom_target needs 0.40.0
2018-12-22 14:34:39 +00:00
Nikolaus Rath 93c052a3cd Released 3.5.1 2018-12-22 14:33:52 +00:00
Nikolaus Rath 76d11fa6f4 Use fusermount3 instead of fusermount
We're using libfuse3, so we should be using its fusermount command.
2018-12-22 14:31:52 +00:00
Nikolaus Rath 9ced6ca681 Kill filesystem process on test cleanup. 2018-12-22 14:31:52 +00:00
Tim Harder de11ec091e meson: fallback to looking for rst2man.py
As that's what upstream docutils installs by default.
2018-12-22 14:22:24 +00:00
smheidrich 37b79d06f8 Docs: add section on interrupted connections
Also rename "SSHFS hangs" section to something more specific to
differentiate it from this new section.

Cf. issues #77 and #3.
2018-12-22 14:22:01 +00:00
S. D. Cloudt 2f1147c7d6 Added "BindInterface" as valid "-o" option. 2018-12-22 14:20:54 +00:00
Nikolaus Rath b5d1484314 Released 3.5.0 2018-08-28 14:58:39 +01:00
Bill Zissimopoulos d0c5fa3ed6 Add AppVeyor CI for Cygwin 2018-08-11 10:33:42 +01:00
Bill Zissimopoulos eac420791c Port SSHFS to Cygwin 2018-08-01 14:39:23 +01:00
Quentin Rameau 6480b66bd6 Fix error return value from rename()
Fuse operations expect negated errno values.
2018-07-25 11:03:01 +01:00
11 changed files with 199 additions and 62 deletions
+19
View File
@@ -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
+3 -1
View File
@@ -1,5 +1,5 @@
sudo: required
dist: trusty
dist: xenial
language:
- c
@@ -14,6 +14,8 @@ addons:
- gcc-6
- python-docutils
- python3-pip
- python3-setuptools
- ninja-build
install: test/travis-install.sh
script: test/travis-build.sh
+7
View File
@@ -21,7 +21,9 @@ 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>
George Vlahavas <vlahavas@gmail.com>
G.raud Meyer <graud@gmx.com>
@@ -33,13 +35,18 @@ Julio Merino <jmmv@meroh.net>
Mike Kelly <mike@pair.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>
Tim Harder <radhermit@gmail.com>
Timo Savola <timo.savola@iki.fi>
tpoindessous <thomas@poindessous.com>
Zoltan Kuscsik <zoltan.kuscsik@linaro.org>
+19
View File
@@ -1,3 +1,22 @@
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)
--------------------------
+3 -3
View File
@@ -1,5 +1,5 @@
project('sshfs', 'c', version: '3.4.0',
meson_version: '>= 0.38',
project('sshfs', 'c', version: '3.5.2',
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()
+101 -47
View File
@@ -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>
@@ -264,10 +264,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;
@@ -300,6 +298,7 @@ static const char *ssh_opts[] = {
"AddressFamily",
"BatchMode",
"BindAddress",
"BindInterface",
"CertificateFile",
"ChallengeResponseAuthentication",
"CheckHostIP",
@@ -788,17 +787,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;
@@ -1295,9 +1289,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)
@@ -1599,10 +1594,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);
@@ -2316,7 +2309,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);
@@ -2423,17 +2416,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;
@@ -3452,7 +3440,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 = arg;
} else {
sshfs.mountpoint = realpath(arg, NULL);
}
#endif
if (!sshfs.mountpoint) {
fprintf(stderr, "sshfs: bad mount point `%s': %s\n",
arg, strerror(errno));
@@ -3564,40 +3596,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);
}
}
@@ -3912,7 +3964,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);
}
+30 -2
View File
@@ -243,8 +243,8 @@ errors which will make programs like `mv(1)` attempt to actually move the
file after the failed rename.
SSHFS hangs
~~~~~~~~~~~
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
@@ -253,6 +253,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
========================
+7
View File
@@ -0,0 +1,7 @@
#!/bin/bash
machine=$(uname -m)
mkdir build-$machine
cd build-$machine
meson ..
ninja
+1 -1
View File
@@ -109,7 +109,7 @@ def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, capfd):
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)
+1 -6
View File
@@ -4,11 +4,6 @@ set -e
# Meson 0.45 requires Python 3.5 or newer
sudo python3 -m pip install pytest meson==0.44
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
valgrind --version
ninja --version
meson --version
@@ -29,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
View File
@@ -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)