Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 695cd8916f | |||
| 7364b73e80 | |||
| 1dbc89f959 | |||
| d299217510 | |||
| fda6c8f862 | |||
| 6b10b3c8c0 | |||
| d3c6c338ae | |||
| 93c052a3cd | |||
| 76d11fa6f4 | |||
| 9ced6ca681 | |||
| de11ec091e | |||
| 37b79d06f8 | |||
| 2f1147c7d6 | |||
| b5d1484314 | |||
| d0c5fa3ed6 | |||
| eac420791c | |||
| 6480b66bd6 |
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
========================
|
||||
|
||||
|
||||
Executable
+7
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
machine=$(uname -m)
|
||||
mkdir build-$machine
|
||||
cd build-$machine
|
||||
meson ..
|
||||
ninja
|
||||
+1
-1
@@ -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)
|
||||
|
||||
@@ -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
@@ -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