Compare commits

..

36 Commits

Author SHA1 Message Date
Nikolaus Rath fc63c64602 Released 3.1.0 2017-08-04 15:42:38 +02:00
Nikolaus Rath 1e6e067fdf Disable writeback cache for now
Writeback cache seems to cause dataloss in some situations.
We need to investigate this first.

See https://github.com/libfuse/sshfs/issues/72.
2017-08-04 15:39:25 +02:00
Nikolaus Rath 44a56f0cac Removed unused variable. 2017-08-04 15:39:16 +02:00
Nikolaus Rath 653de120c8 Don't check st_mode of mountpoint
It is not clear what this check is supposed to achieve, and it seems to
fail in some situations (cf issue #57).

Fixes: #57.
2017-08-03 18:48:37 +02:00
Nikolaus Rath 63300fd564 Accept -o cache_* options for backward compatibility.
Fixes: #73.
2017-08-03 18:26:19 +02:00
Nikolaus Rath 45710c81d7 Travis: use alternative workaround suggested by support. 2017-07-27 21:21:46 +02:00
Nikolaus Rath 161ece55a3 Travis: disable trusty workaround
According to Travis support, this should be working now. We will see...
2017-07-27 19:15:30 +02:00
Benjamin Fleischer db149d1d87 Fall back to global I/O size on macOS
The st_blksize value of struct stat represents the optimal block size
for file I/O operations. FUSE for macOS will use this value when
preforming read or write operations on the file. The smaller st_blksize
is the more context switches are required to complete the operation.

Setting st_blksize to 0 results in FUSE for macOS falling back to the
global I/O size, that can be specified through the "-o iosize=..."
mount-time option.

Fixes osxfuse/osxfuse#389 and osxfuse/sshfs#33
2017-07-13 16:06:05 +02:00
Benjamin Fleischer 861d308a03 Don't require mount point to exists on macOS
By default volumes are mounted under /Volumes on macOS. Since macOS
10.12 the /Volumes directory is root-owned. In order to allow non-
privileged users to mount FUSE volumes under /Volumes FUSE will create
non-existent mount points automatically.

Fixes osxfuse/sshfs#27
2017-07-13 16:04:12 +02:00
Nikolaus Rath 319f0dde18 sshfs_open_commin(): fix compiler warning
wrctr cannot be used without having been initialized,
but the compiler is too dumb to see that.
2017-07-12 16:46:02 +02:00
Nikolaus Rath 82766d1093 sftp_readdir_async(): don't access request when it may have been freed
Fixes: #7
2017-07-12 16:45:17 +02:00
Nikolaus Rath 6f6491cd13 Travis: add /usr/local/lib* to ld configuration 2017-07-08 13:30:44 +02:00
Nikolaus Rath 03a693d295 Travis: install libfuse from git master 2017-07-08 13:23:18 +02:00
Nikolaus Rath 55eb1f00e6 Travis: Build libfuse with gcc-6
gcc-4.8 has trouble with libfuse 3.1.0 symbol versioning.
2017-07-08 13:14:21 +02:00
Nikolaus Rath 37b6969067 Travis: use libfuse 3.1.0 2017-07-08 12:59:20 +02:00
Nikolaus Rath ff6194b5c7 Released 3.0.0 2017-07-08 12:47:09 +02:00
Nikolaus Rath af31551e18 Include test files in "make dist" 2017-07-08 12:43:18 +02:00
Nikolaus Rath 82e899fb21 Switch to libfuse 3.1.0
libfuse 3.0.0 is rather new and not widely used yet, so requiring
libfuse 3.1.0 right away shouldn't be a problem.
2017-07-08 12:26:45 +02:00
Nikolaus Rath 34146444ce Switch to libfuse 3.0. 2017-07-08 12:25:13 +02:00
Nikolaus Rath 6cc86fc0bd Abort on glib assertion errors. 2017-07-08 00:37:25 +02:00
Nikolaus Rath 73e4cf79b0 Travis: use sudo-enabled environment. 2017-07-08 00:34:03 +02:00
Nikolaus Rath a202e2dcc8 Added information about professional support. 2017-07-08 00:34:02 +02:00
Nikolaus Rath c711bf738f Re-enabled cache support. 2017-07-08 00:34:01 +02:00
Nikolaus Rath 493081e8f6 Split readdir() into opendir(), readdir() and releasedir()
This re-enables support for nullpath_ok. The cache remains disabled.
2017-06-22 14:22:58 -07:00
Nikolaus Rath 3033dbc22e Transition from getdir() to readdir(), temporarily disable cache
This commit enables the use of readdir() instead of getdir(). It also
completely disables the cache and the nullpath_ok feature. This will
be fixed in the next commits.
2017-06-22 14:22:58 -07:00
Nikolaus Rath 5f4619bac3 Added unit tests and travis integration 2017-06-22 14:22:57 -07:00
Nikolaus Rath b66ecb9c3a Fix Meson manpage install
Without this, Meson is looking for sshfs.1 in the source
directory. However, since that is a generated file it is in the build
directory.
2017-06-22 14:21:33 -07:00
Nikolaus Rath 9ac5829b89 Compile with -g -O2 by default. 2017-06-22 14:21:07 -07:00
Nikolaus Rath 9cfeaf5120 Added .rst suffix to ChangeLog.
That way, programs are more likely to highlight the file correctly.
2017-06-20 16:39:18 -07:00
Nikolaus Rath 56d6030f9c Document hardlink limitation. 2017-06-20 16:39:16 -07:00
Nikolaus Rath 152617e53f Converted README from Markdown to Restructured Text. 2017-06-20 16:38:46 -07:00
Nikolaus Rath 0908f570dc Dropped obsolete FUSE 2.x #ifdefs 2017-06-20 11:29:19 -07:00
Nikolaus Rath 5bc9ff371d Added .dir-locals.el to setup correct indentation in Emacs 2017-06-19 15:18:11 -07:00
Nikolaus Rath 4379773a9e Updated mailing list information. 2017-06-08 16:53:26 -04:00
Nikolaus Rath 6056149d16 Fixed compiler warnings 2017-06-07 13:42:34 -04:00
Nikolaus Rath 53a14aeaf1 Dropped support for libfuse < 2.9
This is in preparation for the move to libfuse 3.0
2017-06-07 13:42:34 -04:00
13 changed files with 636 additions and 710 deletions
+3 -7
View File
@@ -1,5 +1,5 @@
sudo: required
dist: xenial
dist: trusty
language:
- c
@@ -12,12 +12,8 @@ addons:
- clang
- gcc
- gcc-6
- fuse
- libfuse2
- libfuse-dev
- python3-pip
- python3-setuptools
- ninja-build
before_install:
- pip install pip==8.1.1 && pip3 install pip==8.1.1
install: test/travis-install.sh
script: test/travis-build.sh
+17 -6
View File
@@ -1,14 +1,25 @@
Unreleased Changes
-------------------------
Release 3.1.0 (2017-08-04)
--------------------------
* Fixed improper handling of sequential spaces spaces in "ssh_command" option
Release 2.10 (2017-08-03)
-------------------------
* Temporarily disabled the writeback cache feature, since there
have been reports of dataloss when appending to files when
writeback caching is enabled.
* Fixed a crash due to a race condition when listing
directory contents.
* For improved backwards compatibility, SSHFS now also silently
accepts the old ``-o cache_*`` options.
Release 3.0.0 (2017-07-08)
--------------------------
* sshfs now requires libfuse 3.1.0 or newer.
* When supported by the kernel, sshfs now uses writeback caching.
* The `cache` option has been renamed to `dir_cache` for clarity.
* Added unit tests
* --debug now behaves like -o debug_sshfs, i.e. it enables sshfs
debugging messages rather than libfuse debugging messages.
* Documented limited hardlink support.
* Added support for building with Meson.
* Added support for more SSH options.
+1 -1
View File
@@ -14,7 +14,7 @@ endif
sshfs_LDADD = $(SSHFS_LIBS)
sshfs_CFLAGS = $(SSHFS_CFLAGS)
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\" \
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=31 -DLIBDIR=\"$(libdir)\" \
-DIDMAP_DEFAULT="\"$(IDMAP_DEFAULT)\""
EXTRA_DIST = sshfs.1.in meson.build
+6 -19
View File
@@ -10,20 +10,6 @@ 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
----------
@@ -46,7 +32,7 @@ To unmount the filesystem::
fusermount -u mountpoint
On BSD and macOS, to unmount the filesystem::
On BSD and OS-X, to unmount the filesystem::
umount mountpoint
@@ -56,9 +42,10 @@ Installation
First, download the latest SSHFS release from
https://github.com/libfuse/sshfs/releases. On Linux and BSD, you will
also need to have libfuse_ installed. On macOS, you need macFUSE_
instead. Finally, you need the Glib_ development package (which should
be available from your operating system's package manager).
also need to install libfuse_ 3.1.0 or newer. On OS-X, you need
OSXFUSE_ instead. Finally, you need the Glib_ library with development
headers (which should be available from your operating system's
package manager).
To build and install, we recommend to use Meson_ (version 0.38 or
newer) and Ninja_. After extracting the sshfs tarball, create a
@@ -82,7 +69,7 @@ tests requires the `py.test`_ Python module)::
$ sudo ninja install
.. _libfuse: http://github.com/libfuse/libfuse
.. _macFUSE: https://macfuse.io/
.. _OSXFUSE: https://osxfuse.github.io/
.. _Glib: https://developer.gnome.org/glib/stable/
.. _Meson: http://mesonbuild.com/
.. _Ninja: https://ninja-build.org/
+172 -166
View File
@@ -8,6 +8,7 @@
#include "cache.h"
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -27,7 +28,7 @@ struct cache {
unsigned int max_size;
unsigned int clean_interval_secs;
unsigned int min_clean_interval_secs;
struct fuse_cache_operations *next_oper;
struct fuse_operations *next_oper;
GHashTable *table;
pthread_mutex_t lock;
time_t last_cleaned;
@@ -46,14 +47,22 @@ struct node {
time_t valid;
};
struct fuse_cache_dirhandle {
struct readdir_handle {
const char *path;
fuse_dirh_t h;
fuse_dirfil_t filler;
void *buf;
fuse_fill_dir_t filler;
GPtrArray *dir;
uint64_t wrctr;
};
struct file_handle {
/* Did we send an open request to the underlying fs? */
int is_open;
/* If so, this will hold its handle */
unsigned long fs_fh;
};
static void free_node(gpointer node_)
{
struct node *node = (struct node *) node_;
@@ -108,9 +117,6 @@ static void cache_purge_parent(const char *path)
void cache_invalidate(const char *path)
{
if (!cache.on)
return;
pthread_mutex_lock(&cache.lock);
cache_purge(path);
pthread_mutex_unlock(&cache.lock);
@@ -168,9 +174,6 @@ void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr)
{
struct node *node;
if (!cache.on)
return;
pthread_mutex_lock(&cache.lock);
if (wrctr == cache.write_ctr) {
node = cache_get(path);
@@ -248,12 +251,25 @@ uint64_t cache_get_write_ctr(void)
return res;
}
static int cache_getattr(const char *path, struct stat *stbuf)
static void *cache_init(struct fuse_conn_info *conn,
struct fuse_config *cfg)
{
void *res;
res = cache.next_oper->init(conn, cfg);
// Cache requires a path for each request
cfg->nullpath_ok = 0;
return res;
}
static int cache_getattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
int err = cache_get_attr(path, stbuf);
if (err) {
uint64_t wrctr = cache_get_write_ctr();
err = cache.next_oper->oper.getattr(path, stbuf);
err = cache.next_oper->getattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf, wrctr);
}
@@ -277,17 +293,53 @@ static int cache_readlink(const char *path, char *buf, size_t size)
}
}
pthread_mutex_unlock(&cache.lock);
err = cache.next_oper->oper.readlink(path, buf, size);
err = cache.next_oper->readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
return err;
}
static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
const struct stat *stbuf)
static int cache_opendir(const char *path, struct fuse_file_info *fi)
{
int err = ch->filler(ch->h, name, 0, 0);
(void) path;
struct file_handle *cfi;
cfi = malloc(sizeof(struct file_handle));
if(cfi == NULL)
return -ENOMEM;
cfi->is_open = 0;
fi->fh = (unsigned long) cfi;
return 0;
}
static int cache_releasedir(const char *path, struct fuse_file_info *fi)
{
int err;
struct file_handle *cfi;
cfi = (struct file_handle*) fi->fh;
if(cfi->is_open) {
fi->fh = cfi->fs_fh;
err = cache.next_oper->releasedir(path, fi);
} else
err = 0;
free(cfi);
return err;
}
static int cache_dirfill (void *buf, const char *name,
const struct stat *stbuf, off_t off,
enum fuse_fill_dir_flags flags)
{
int err;
struct readdir_handle *ch;
ch = (struct readdir_handle*) buf;
err = ch->filler(ch->buf, name, stbuf, off, flags);
if (!err) {
g_ptr_array_add(ch->dir, g_strdup(name));
if (stbuf->st_mode & S_IFMT) {
@@ -302,61 +354,66 @@ static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
return err;
}
static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi,
enum fuse_readdir_flags flags)
{
struct fuse_cache_dirhandle ch;
struct readdir_handle ch;
struct file_handle *cfi;
int err;
char **dir;
struct node *node;
assert(offset == 0);
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL && node->dir != NULL) {
time_t now = time(NULL);
if (node->dir_valid - now >= 0) {
for(dir = node->dir; *dir != NULL; dir++)
filler(h, *dir, 0, 0);
// FIXME: What about st_mode?
filler(buf, *dir, NULL, 0, 0);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
cfi = (struct file_handle*) fi->fh;
if(cfi->is_open)
fi->fh = cfi->fs_fh;
else {
if(cache.next_oper->opendir) {
err = cache.next_oper->opendir(path, fi);
if(err)
return err;
}
cfi->is_open = 1;
cfi->fs_fh = fi->fh;
}
ch.path = path;
ch.h = h;
ch.buf = buf;
ch.filler = filler;
ch.dir = g_ptr_array_new();
ch.wrctr = cache_get_write_ctr();
err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill);
err = cache.next_oper->readdir(path, &ch, cache_dirfill, offset, fi, flags);
g_ptr_array_add(ch.dir, NULL);
dir = (char **) ch.dir->pdata;
if (!err)
if (!err) {
cache_add_dir(path, dir);
else
} else {
g_strfreev(dir);
}
g_ptr_array_free(ch.dir, FALSE);
return err;
}
static int cache_unity_dirfill(fuse_cache_dirh_t ch, const char *name,
const struct stat *stbuf)
{
(void) stbuf;
return ch->filler(ch->h, name, 0, 0);
}
static int cache_unity_getdir(const char *path, fuse_dirh_t h,
fuse_dirfil_t filler)
{
struct fuse_cache_dirhandle ch;
ch.h = h;
ch.filler = filler;
return cache.next_oper->cache_getdir(path, &ch, cache_unity_dirfill);
}
static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
{
int err = cache.next_oper->oper.mknod(path, mode, rdev);
int err = cache.next_oper->mknod(path, mode, rdev);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -364,7 +421,7 @@ static int cache_mknod(const char *path, mode_t mode, dev_t rdev)
static int cache_mkdir(const char *path, mode_t mode)
{
int err = cache.next_oper->oper.mkdir(path, mode);
int err = cache.next_oper->mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -372,7 +429,7 @@ static int cache_mkdir(const char *path, mode_t mode)
static int cache_unlink(const char *path)
{
int err = cache.next_oper->oper.unlink(path);
int err = cache.next_oper->unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -380,7 +437,7 @@ static int cache_unlink(const char *path)
static int cache_rmdir(const char *path)
{
int err = cache.next_oper->oper.rmdir(path);
int err = cache.next_oper->rmdir(path);
if (!err)
cache_invalidate_dir(path);
return err;
@@ -388,15 +445,15 @@ static int cache_rmdir(const char *path)
static int cache_symlink(const char *from, const char *to)
{
int err = cache.next_oper->oper.symlink(from, to);
int err = cache.next_oper->symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
}
static int cache_rename(const char *from, const char *to)
static int cache_rename(const char *from, const char *to, unsigned int flags)
{
int err = cache.next_oper->oper.rename(from, to);
int err = cache.next_oper->rename(from, to, flags);
if (!err)
cache_do_rename(from, to);
return err;
@@ -404,7 +461,7 @@ static int cache_rename(const char *from, const char *to)
static int cache_link(const char *from, const char *to)
{
int err = cache.next_oper->oper.link(from, to);
int err = cache.next_oper->link(from, to);
if (!err) {
cache_invalidate(from);
cache_invalidate_dir(to);
@@ -412,33 +469,28 @@ static int cache_link(const char *from, const char *to)
return err;
}
static int cache_chmod(const char *path, mode_t mode)
static int cache_chmod(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.chmod(path, mode);
int err = cache.next_oper->chmod(path, mode, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_chown(const char *path, uid_t uid, gid_t gid)
static int cache_chown(const char *path, uid_t uid, gid_t gid,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.chown(path, uid, gid);
int err = cache.next_oper->chown(path, uid, gid, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_truncate(const char *path, off_t size)
static int cache_utimens(const char *path, const struct timespec tv[2],
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.truncate(path, size);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_utime(const char *path, struct utimbuf *buf)
{
int err = cache.next_oper->oper.utime(path, buf);
int err = cache.next_oper->utimens(path, tv, fi);
if (!err)
cache_invalidate(path);
return err;
@@ -447,140 +499,95 @@ static int cache_utime(const char *path, struct utimbuf *buf)
static int cache_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
int res = cache.next_oper->oper.write(path, buf, size, offset, fi);
int res = cache.next_oper->write(path, buf, size, offset, fi);
if (res >= 0)
cache_invalidate_write(path);
return res;
}
#if FUSE_VERSION >= 25
static int cache_create(const char *path, mode_t mode,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.create(path, mode, fi);
int err = cache.next_oper->create(path, mode, fi);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_ftruncate(const char *path, off_t size,
struct fuse_file_info *fi)
static int cache_truncate(const char *path, off_t size,
struct fuse_file_info *fi)
{
int err = cache.next_oper->oper.ftruncate(path, size, fi);
int err = cache.next_oper->truncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
int err = cache_get_attr(path, stbuf);
if (err) {
uint64_t wrctr = cache_get_write_ctr();
err = cache.next_oper->oper.fgetattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf, wrctr);
}
return err;
}
#endif
static void cache_unity_fill(struct fuse_cache_operations *oper,
struct fuse_operations *cache_oper)
{
#if FUSE_VERSION >= 23
cache_oper->init = oper->oper.init;
#endif
cache_oper->getattr = oper->oper.getattr;
cache_oper->access = oper->oper.access;
cache_oper->readlink = oper->oper.readlink;
cache_oper->getdir = cache_unity_getdir;
cache_oper->mknod = oper->oper.mknod;
cache_oper->mkdir = oper->oper.mkdir;
cache_oper->symlink = oper->oper.symlink;
cache_oper->unlink = oper->oper.unlink;
cache_oper->rmdir = oper->oper.rmdir;
cache_oper->rename = oper->oper.rename;
cache_oper->link = oper->oper.link;
cache_oper->chmod = oper->oper.chmod;
cache_oper->chown = oper->oper.chown;
cache_oper->truncate = oper->oper.truncate;
cache_oper->utime = oper->oper.utime;
cache_oper->open = oper->oper.open;
cache_oper->read = oper->oper.read;
cache_oper->write = oper->oper.write;
cache_oper->flush = oper->oper.flush;
cache_oper->release = oper->oper.release;
cache_oper->fsync = oper->oper.fsync;
cache_oper->statfs = oper->oper.statfs;
cache_oper->setxattr = oper->oper.setxattr;
cache_oper->getxattr = oper->oper.getxattr;
cache_oper->listxattr = oper->oper.listxattr;
cache_oper->removexattr = oper->oper.removexattr;
#if FUSE_VERSION >= 25
cache_oper->create = oper->oper.create;
cache_oper->ftruncate = oper->oper.ftruncate;
cache_oper->fgetattr = oper->oper.fgetattr;
#endif
#if FUSE_VERSION >= 29
cache_oper->flag_nullpath_ok = oper->oper.flag_nullpath_ok;
cache_oper->flag_nopath = oper->oper.flag_nopath;
#endif
}
static void cache_fill(struct fuse_cache_operations *oper,
static void cache_fill(struct fuse_operations *oper,
struct fuse_operations *cache_oper)
{
cache_oper->getattr = oper->oper.getattr ? cache_getattr : NULL;
cache_oper->readlink = oper->oper.readlink ? cache_readlink : NULL;
cache_oper->getdir = oper->cache_getdir ? cache_getdir : NULL;
cache_oper->mknod = oper->oper.mknod ? cache_mknod : NULL;
cache_oper->mkdir = oper->oper.mkdir ? cache_mkdir : NULL;
cache_oper->symlink = oper->oper.symlink ? cache_symlink : NULL;
cache_oper->unlink = oper->oper.unlink ? cache_unlink : NULL;
cache_oper->rmdir = oper->oper.rmdir ? cache_rmdir : NULL;
cache_oper->rename = oper->oper.rename ? cache_rename : NULL;
cache_oper->link = oper->oper.link ? cache_link : NULL;
cache_oper->chmod = oper->oper.chmod ? cache_chmod : NULL;
cache_oper->chown = oper->oper.chown ? cache_chown : NULL;
cache_oper->truncate = oper->oper.truncate ? cache_truncate : NULL;
cache_oper->utime = oper->oper.utime ? cache_utime : NULL;
cache_oper->write = oper->oper.write ? cache_write : NULL;
#if FUSE_VERSION >= 25
cache_oper->create = oper->oper.create ? cache_create : NULL;
cache_oper->ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL;
cache_oper->fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL;
#endif
#if FUSE_VERSION >= 29
cache_oper->flag_nullpath_ok = 0;
cache_oper->flag_nopath = 0;
#endif
cache_oper->access = oper->access;
cache_oper->chmod = oper->chmod ? cache_chmod : NULL;
cache_oper->chown = oper->chown ? cache_chown : NULL;
cache_oper->create = oper->create ? cache_create : NULL;
cache_oper->flush = oper->flush;
cache_oper->fsync = oper->fsync;
cache_oper->getattr = oper->getattr ? cache_getattr : NULL;
cache_oper->getxattr = oper->getxattr;
cache_oper->init = cache_init;
cache_oper->link = oper->link ? cache_link : NULL;
cache_oper->listxattr = oper->listxattr;
cache_oper->mkdir = oper->mkdir ? cache_mkdir : NULL;
cache_oper->mknod = oper->mknod ? cache_mknod : NULL;
cache_oper->open = oper->open;
cache_oper->opendir = cache_opendir;
cache_oper->read = oper->read;
cache_oper->readdir = oper->readdir ? cache_readdir : NULL;
cache_oper->readlink = oper->readlink ? cache_readlink : NULL;
cache_oper->release = oper->release;
cache_oper->releasedir = cache_releasedir;
cache_oper->removexattr = oper->removexattr;
cache_oper->rename = oper->rename ? cache_rename : NULL;
cache_oper->rmdir = oper->rmdir ? cache_rmdir : NULL;
cache_oper->setxattr = oper->setxattr;
cache_oper->statfs = oper->statfs;
cache_oper->symlink = oper->symlink ? cache_symlink : NULL;
cache_oper->truncate = oper->truncate ? cache_truncate : NULL;
cache_oper->unlink = oper->unlink ? cache_unlink : NULL;
cache_oper->utimens = oper->utimens ? cache_utimens : NULL;
cache_oper->write = oper->write ? cache_write : NULL;
}
struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
struct fuse_operations *cache_wrap(struct fuse_operations *oper)
{
static struct fuse_operations cache_oper;
cache.next_oper = oper;
cache_unity_fill(oper, &cache_oper);
if (cache.on) {
cache_fill(oper, &cache_oper);
pthread_mutex_init(&cache.lock, NULL);
cache.table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, free_node);
if (cache.table == NULL) {
fprintf(stderr, "failed to create cache\n");
return NULL;
}
cache_fill(oper, &cache_oper);
pthread_mutex_init(&cache.lock, NULL);
cache.table = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, free_node);
if (cache.table == NULL) {
fprintf(stderr, "failed to create cache\n");
return NULL;
}
return &cache_oper;
}
static const struct fuse_opt cache_opts[] = {
{ "cache=yes", offsetof(struct cache, on), 1 },
{ "cache=no", offsetof(struct cache, on), 0 },
{ "dcache_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "dcache_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "dcache_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
{ "dcache_stat_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "dcache_dir_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "dcache_link_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
{ "dcache_max_size=%u", offsetof(struct cache, max_size), 0 },
{ "dcache_clean_interval=%u", offsetof(struct cache,
clean_interval_secs), 0 },
{ "dcache_min_clean_interval=%u", offsetof(struct cache,
min_clean_interval_secs), 0 },
/* For backwards compatibility */
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
{ "cache_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
@@ -589,9 +596,9 @@ static const struct fuse_opt cache_opts[] = {
{ "cache_link_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
{ "cache_max_size=%u", offsetof(struct cache, max_size), 0 },
{ "cache_clean_interval=%u", offsetof(struct cache,
clean_interval_secs), 0 },
clean_interval_secs), 0 },
{ "cache_min_clean_interval=%u", offsetof(struct cache,
min_clean_interval_secs), 0 },
min_clean_interval_secs), 0 },
FUSE_OPT_END
};
@@ -603,7 +610,6 @@ int cache_parse_options(struct fuse_args *args)
cache.max_size = DEFAULT_MAX_CACHE_SIZE;
cache.clean_interval_secs = DEFAULT_CACHE_CLEAN_INTERVAL_SECS;
cache.min_clean_interval_secs = DEFAULT_MIN_CACHE_CLEAN_INTERVAL_SECS;
cache.on = 1;
return fuse_opt_parse(args, &cache, cache_opts, NULL);
}
+1 -14
View File
@@ -9,20 +9,7 @@
#include <fuse.h>
#include <fuse_opt.h>
#ifndef FUSE_VERSION
#define FUSE_VERSION (FUSE_MAJOR_VERSION * 10 + FUSE_MINOR_VERSION)
#endif
typedef struct fuse_cache_dirhandle *fuse_cache_dirh_t;
typedef int (*fuse_cache_dirfil_t) (fuse_cache_dirh_t h, const char *name,
const struct stat *stbuf);
struct fuse_cache_operations {
struct fuse_operations oper;
int (*cache_getdir) (const char *, fuse_cache_dirh_t, fuse_cache_dirfil_t);
};
struct fuse_operations *cache_init(struct fuse_cache_operations *oper);
struct fuse_operations *cache_wrap(struct fuse_operations *oper);
int cache_parse_options(struct fuse_args *args);
void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr);
void cache_invalidate(const char *path);
+2 -2
View File
@@ -1,4 +1,4 @@
AC_INIT(sshfs, 2.10)
AC_INIT(sshfs, 3.1.0)
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([foreign subdir-objects])
AM_CONFIG_HEADER(config.h)
@@ -17,7 +17,7 @@ case "$target_os" in
esac
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
PKG_CHECK_MODULES([SSHFS], [fuse >= 2.3 glib-2.0 gthread-2.0])
PKG_CHECK_MODULES([SSHFS], [fuse3 >= 3.1 glib-2.0 gthread-2.0])
have_fuse_opt_parse=no
oldlibs="$LIBS"
LIBS="$LIBS $SSHFS_LIBS"
+3 -3
View File
@@ -1,4 +1,4 @@
project('sshfs', 'c', version: '2.10.0',
project('sshfs', 'c', version: '3.1.0',
meson_version: '>= 0.38',
default_options: [ 'buildtype=plain' ])
@@ -45,14 +45,14 @@ configure_file(input: 'sshfs.1.in',
configure_file(output: 'config.h',
configuration : cfg)
sshfs_deps = [ dependency('fuse', version: '>= 2.3'),
sshfs_deps = [ dependency('fuse3', version: '>= 3.1.0'),
dependency('glib-2.0'),
dependency('gthread-2.0') ]
executable('sshfs', sshfs_sources,
include_directories: include_dirs,
dependencies: sshfs_deps,
c_args: ['-DFUSE_USE_VERSION=26'],
c_args: ['-DFUSE_USE_VERSION=31'],
install: true,
install_dir: get_option('bindir'))
+398 -482
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -2,7 +2,7 @@ test_scripts = [ 'conftest.py', 'pytest.ini', 'test_sshfs.py',
'util.py' ]
custom_target('test_scripts', input: test_scripts,
output: test_scripts, build_by_default: true,
command: ['cp', '-fPp',
command: ['cp', '-fPu', '--preserve=mode',
'@INPUT@', meson.current_build_dir() ])
# Provide something helpful when running 'ninja test'
+9 -4
View File
@@ -30,8 +30,9 @@ def name_generator(__ctr=[0]):
return 'testfile_%d' % __ctr[0]
@pytest.mark.parametrize("debug", (False, True))
@pytest.mark.parametrize("cache_timeout", (0, 1))
def test_sshfs(tmpdir, debug, cache_timeout, capfd):
@pytest.mark.parametrize("cache_timeout", (0,1))
@pytest.mark.parametrize("sync_rd", (True, False))
def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, capfd):
# Avoid false positives from debug messages
#if debug:
@@ -58,11 +59,15 @@ def test_sshfs(tmpdir, debug, cache_timeout, capfd):
if debug:
cmdline += [ '-o', 'sshfs_debug' ]
if sync_rd:
cmdline += [ '-o', 'sync_readdir' ]
# SSHFS Cache
if cache_timeout == 0:
cmdline += [ '-o', 'cache=no' ]
cmdline += [ '-o', 'dir_cache=no' ]
else:
cmdline += [ '-o', 'cache_timeout=%d' % cache_timeout ]
cmdline += [ '-o', 'dcache_timeout=%d' % cache_timeout,
'-o', 'dir_cache=yes' ]
# FUSE Cache
cmdline += [ '-o', 'entry_timeout=0',
-1
View File
@@ -36,7 +36,6 @@ for san in undefined address; do
meson -D b_sanitize=${san} -D b_lundef=false -D werror=true ..
ninja
${TEST_CMD}
sudo ninja install
cd ..
done
+23 -4
View File
@@ -2,15 +2,34 @@
set -e
# Meson 0.45 requires Python 3.5 or newer
sudo python3 -m pip install pytest meson==0.44
sudo ln -svf $(which python3) /usr/bin/python3
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
valgrind --version
ninja --version
meson --version
# Install fuse
wget https://github.com/libfuse/libfuse/archive/master.zip
unzip master.zip
cd libfuse-master
mkdir build
cd build
export CC=gcc-6
meson ..
ninja
sudo ninja install
test -e /usr/local/lib/pkgconfig || sudo mkdir /usr/local/lib/pkgconfig
sudo mv /usr/local/lib/*/pkgconfig/* /usr/local/lib/pkgconfig/
ls -d1 /usr/local/lib/*-linux-gnu | sudo tee /etc/ld.so.conf.d/usrlocal.conf
sudo ldconfig
# Setup ssh
ssh-keygen -b 1024 -t rsa -f ~/.ssh/id_rsa -P ''
ssh-keygen -b 768 -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"