Switch to libfuse 3.0.
This commit is contained in:
parent
6cc86fc0bd
commit
34146444ce
|
|
@ -13,9 +13,6 @@ addons:
|
||||||
- clang
|
- clang
|
||||||
- gcc
|
- gcc
|
||||||
- gcc-6
|
- gcc-6
|
||||||
- fuse
|
|
||||||
- libfuse2
|
|
||||||
- libfuse-dev
|
|
||||||
install: test/travis-install.sh
|
install: test/travis-install.sh
|
||||||
script: test/travis-build.sh
|
script: test/travis-build.sh
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
Unreleased Changes
|
Unreleased Changes
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
* sshfs now requires libfuse 3.0.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
|
* 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.
|
* Documented limited hardlink support.
|
||||||
* Added support for building with Meson.
|
* Added support for building with Meson.
|
||||||
* Added support for more SSH options.
|
* Added support for more SSH options.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ endif
|
||||||
|
|
||||||
sshfs_LDADD = $(SSHFS_LIBS)
|
sshfs_LDADD = $(SSHFS_LIBS)
|
||||||
sshfs_CFLAGS = $(SSHFS_CFLAGS)
|
sshfs_CFLAGS = $(SSHFS_CFLAGS)
|
||||||
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\" \
|
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=30 -DLIBDIR=\"$(libdir)\" \
|
||||||
-DIDMAP_DEFAULT="\"$(IDMAP_DEFAULT)\""
|
-DIDMAP_DEFAULT="\"$(IDMAP_DEFAULT)\""
|
||||||
|
|
||||||
EXTRA_DIST = sshfs.1.in meson.build
|
EXTRA_DIST = sshfs.1.in meson.build
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,10 @@ Installation
|
||||||
|
|
||||||
First, download the latest SSHFS release from
|
First, download the latest SSHFS release from
|
||||||
https://github.com/libfuse/sshfs/releases. On Linux and BSD, you will
|
https://github.com/libfuse/sshfs/releases. On Linux and BSD, you will
|
||||||
also need to have libfuse_ installed. On OS-X, you need OSXFUSE_
|
also need to install libfuse_ 3.0.0 or newer. On OS-X, you need
|
||||||
instead. Finally, you need the Glib_ development package (which should
|
OSXFUSE_ instead. Finally, you need the Glib_ library with development
|
||||||
be available from your operating system's package manager).
|
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
|
To build and install, we recommend to use Meson_ (version 0.38 or
|
||||||
newer) and Ninja_. After extracting the sshfs tarball, create a
|
newer) and Ninja_. After extracting the sshfs tarball, create a
|
||||||
|
|
|
||||||
107
cache.c
107
cache.c
|
|
@ -251,12 +251,25 @@ uint64_t cache_get_write_ctr(void)
|
||||||
return res;
|
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);
|
int err = cache_get_attr(path, stbuf);
|
||||||
if (err) {
|
if (err) {
|
||||||
uint64_t wrctr = cache_get_write_ctr();
|
uint64_t wrctr = cache_get_write_ctr();
|
||||||
err = cache.next_oper->getattr(path, stbuf);
|
err = cache.next_oper->getattr(path, stbuf, fi);
|
||||||
if (!err)
|
if (!err)
|
||||||
cache_add_attr(path, stbuf, wrctr);
|
cache_add_attr(path, stbuf, wrctr);
|
||||||
}
|
}
|
||||||
|
|
@ -319,13 +332,14 @@ static int cache_releasedir(const char *path, struct fuse_file_info *fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cache_dirfill (void *buf, const char *name,
|
static int cache_dirfill (void *buf, const char *name,
|
||||||
const struct stat *stbuf, off_t off)
|
const struct stat *stbuf, off_t off,
|
||||||
|
enum fuse_fill_dir_flags flags)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct readdir_handle *ch;
|
struct readdir_handle *ch;
|
||||||
|
|
||||||
ch = (struct readdir_handle*) buf;
|
ch = (struct readdir_handle*) buf;
|
||||||
err = ch->filler(ch->buf, name, stbuf, off);
|
err = ch->filler(ch->buf, name, stbuf, off, flags);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
g_ptr_array_add(ch->dir, g_strdup(name));
|
g_ptr_array_add(ch->dir, g_strdup(name));
|
||||||
if (stbuf->st_mode & S_IFMT) {
|
if (stbuf->st_mode & S_IFMT) {
|
||||||
|
|
@ -341,7 +355,8 @@ static int cache_dirfill (void *buf, const char *name,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
off_t offset, struct fuse_file_info *fi)
|
off_t offset, struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
struct readdir_handle ch;
|
struct readdir_handle ch;
|
||||||
struct file_handle *cfi;
|
struct file_handle *cfi;
|
||||||
|
|
@ -358,7 +373,7 @@ static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
if (node->dir_valid - now >= 0) {
|
if (node->dir_valid - now >= 0) {
|
||||||
for(dir = node->dir; *dir != NULL; dir++)
|
for(dir = node->dir; *dir != NULL; dir++)
|
||||||
// FIXME: What about st_mode?
|
// FIXME: What about st_mode?
|
||||||
filler(buf, *dir, 0, 0);
|
filler(buf, *dir, NULL, 0, 0);
|
||||||
pthread_mutex_unlock(&cache.lock);
|
pthread_mutex_unlock(&cache.lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -383,7 +398,7 @@ static int cache_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
ch.filler = filler;
|
ch.filler = filler;
|
||||||
ch.dir = g_ptr_array_new();
|
ch.dir = g_ptr_array_new();
|
||||||
ch.wrctr = cache_get_write_ctr();
|
ch.wrctr = cache_get_write_ctr();
|
||||||
err = cache.next_oper->readdir(path, &ch, cache_dirfill, offset, fi);
|
err = cache.next_oper->readdir(path, &ch, cache_dirfill, offset, fi, flags);
|
||||||
g_ptr_array_add(ch.dir, NULL);
|
g_ptr_array_add(ch.dir, NULL);
|
||||||
dir = (char **) ch.dir->pdata;
|
dir = (char **) ch.dir->pdata;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
|
|
@ -436,9 +451,9 @@ static int cache_symlink(const char *from, const char *to)
|
||||||
return err;
|
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->rename(from, to);
|
int err = cache.next_oper->rename(from, to, flags);
|
||||||
if (!err)
|
if (!err)
|
||||||
cache_do_rename(from, to);
|
cache_do_rename(from, to);
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -454,33 +469,28 @@ static int cache_link(const char *from, const char *to)
|
||||||
return err;
|
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->chmod(path, mode);
|
int err = cache.next_oper->chmod(path, mode, fi);
|
||||||
if (!err)
|
if (!err)
|
||||||
cache_invalidate(path);
|
cache_invalidate(path);
|
||||||
return err;
|
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->chown(path, uid, gid);
|
int err = cache.next_oper->chown(path, uid, gid, fi);
|
||||||
if (!err)
|
if (!err)
|
||||||
cache_invalidate(path);
|
cache_invalidate(path);
|
||||||
return err;
|
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->truncate(path, size);
|
int err = cache.next_oper->utimens(path, tv, fi);
|
||||||
if (!err)
|
|
||||||
cache_invalidate(path);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int cache_utime(const char *path, struct utimbuf *buf)
|
|
||||||
{
|
|
||||||
int err = cache.next_oper->utime(path, buf);
|
|
||||||
if (!err)
|
if (!err)
|
||||||
cache_invalidate(path);
|
cache_invalidate(path);
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -504,28 +514,15 @@ static int cache_create(const char *path, mode_t mode,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cache_ftruncate(const char *path, off_t size,
|
static int cache_truncate(const char *path, off_t size,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
int err = cache.next_oper->ftruncate(path, size, fi);
|
int err = cache.next_oper->truncate(path, size, fi);
|
||||||
if (!err)
|
if (!err)
|
||||||
cache_invalidate(path);
|
cache_invalidate(path);
|
||||||
return err;
|
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->fgetattr(path, stbuf, fi);
|
|
||||||
if (!err)
|
|
||||||
cache_add_attr(path, stbuf, wrctr);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cache_fill(struct fuse_operations *oper,
|
static void cache_fill(struct fuse_operations *oper,
|
||||||
struct fuse_operations *cache_oper)
|
struct fuse_operations *cache_oper)
|
||||||
{
|
{
|
||||||
|
|
@ -533,13 +530,11 @@ static void cache_fill(struct fuse_operations *oper,
|
||||||
cache_oper->chmod = oper->chmod ? cache_chmod : NULL;
|
cache_oper->chmod = oper->chmod ? cache_chmod : NULL;
|
||||||
cache_oper->chown = oper->chown ? cache_chown : NULL;
|
cache_oper->chown = oper->chown ? cache_chown : NULL;
|
||||||
cache_oper->create = oper->create ? cache_create : NULL;
|
cache_oper->create = oper->create ? cache_create : NULL;
|
||||||
cache_oper->fgetattr = oper->fgetattr ? cache_fgetattr : NULL;
|
|
||||||
cache_oper->flush = oper->flush;
|
cache_oper->flush = oper->flush;
|
||||||
cache_oper->fsync = oper->fsync;
|
cache_oper->fsync = oper->fsync;
|
||||||
cache_oper->ftruncate = oper->ftruncate ? cache_ftruncate : NULL;
|
|
||||||
cache_oper->getattr = oper->getattr ? cache_getattr : NULL;
|
cache_oper->getattr = oper->getattr ? cache_getattr : NULL;
|
||||||
cache_oper->getxattr = oper->getxattr;
|
cache_oper->getxattr = oper->getxattr;
|
||||||
cache_oper->init = oper->init;
|
cache_oper->init = cache_init;
|
||||||
cache_oper->link = oper->link ? cache_link : NULL;
|
cache_oper->link = oper->link ? cache_link : NULL;
|
||||||
cache_oper->listxattr = oper->listxattr;
|
cache_oper->listxattr = oper->listxattr;
|
||||||
cache_oper->mkdir = oper->mkdir ? cache_mkdir : NULL;
|
cache_oper->mkdir = oper->mkdir ? cache_mkdir : NULL;
|
||||||
|
|
@ -559,13 +554,11 @@ static void cache_fill(struct fuse_operations *oper,
|
||||||
cache_oper->symlink = oper->symlink ? cache_symlink : NULL;
|
cache_oper->symlink = oper->symlink ? cache_symlink : NULL;
|
||||||
cache_oper->truncate = oper->truncate ? cache_truncate : NULL;
|
cache_oper->truncate = oper->truncate ? cache_truncate : NULL;
|
||||||
cache_oper->unlink = oper->unlink ? cache_unlink : NULL;
|
cache_oper->unlink = oper->unlink ? cache_unlink : NULL;
|
||||||
cache_oper->utime = oper->utime ? cache_utime : NULL;
|
cache_oper->utimens = oper->utimens ? cache_utimens : NULL;
|
||||||
cache_oper->write = oper->write ? cache_write : NULL;
|
cache_oper->write = oper->write ? cache_write : NULL;
|
||||||
cache_oper->flag_nopath = 0;
|
|
||||||
cache_oper->flag_nullpath_ok = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct fuse_operations *cache_init(struct fuse_operations *oper)
|
struct fuse_operations *cache_wrap(struct fuse_operations *oper)
|
||||||
{
|
{
|
||||||
static struct fuse_operations cache_oper;
|
static struct fuse_operations cache_oper;
|
||||||
cache.next_oper = oper;
|
cache.next_oper = oper;
|
||||||
|
|
@ -582,17 +575,17 @@ struct fuse_operations *cache_init(struct fuse_operations *oper)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct fuse_opt cache_opts[] = {
|
static const struct fuse_opt cache_opts[] = {
|
||||||
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
|
{ "dcache_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
|
||||||
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
|
{ "dcache_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
|
||||||
{ "cache_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
|
{ "dcache_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
|
||||||
{ "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
|
{ "dcache_stat_timeout=%u", offsetof(struct cache, stat_timeout_secs), 0 },
|
||||||
{ "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
|
{ "dcache_dir_timeout=%u", offsetof(struct cache, dir_timeout_secs), 0 },
|
||||||
{ "cache_link_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
|
{ "dcache_link_timeout=%u", offsetof(struct cache, link_timeout_secs), 0 },
|
||||||
{ "cache_max_size=%u", offsetof(struct cache, max_size), 0 },
|
{ "dcache_max_size=%u", offsetof(struct cache, max_size), 0 },
|
||||||
{ "cache_clean_interval=%u", offsetof(struct cache,
|
{ "dcache_clean_interval=%u", offsetof(struct cache,
|
||||||
clean_interval_secs), 0 },
|
clean_interval_secs), 0 },
|
||||||
{ "cache_min_clean_interval=%u", offsetof(struct cache,
|
{ "dcache_min_clean_interval=%u", offsetof(struct cache,
|
||||||
min_clean_interval_secs), 0 },
|
min_clean_interval_secs), 0 },
|
||||||
FUSE_OPT_END
|
FUSE_OPT_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
2
cache.h
2
cache.h
|
|
@ -9,7 +9,7 @@
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
#include <fuse_opt.h>
|
#include <fuse_opt.h>
|
||||||
|
|
||||||
struct fuse_operations *cache_init(struct fuse_operations *oper);
|
struct fuse_operations *cache_wrap(struct fuse_operations *oper);
|
||||||
int cache_parse_options(struct fuse_args *args);
|
int cache_parse_options(struct fuse_args *args);
|
||||||
void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr);
|
void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr);
|
||||||
void cache_invalidate(const char *path);
|
void cache_invalidate(const char *path);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ case "$target_os" in
|
||||||
esac
|
esac
|
||||||
|
|
||||||
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
|
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], [fuse >= 3.0 glib-2.0 gthread-2.0])
|
||||||
have_fuse_opt_parse=no
|
have_fuse_opt_parse=no
|
||||||
oldlibs="$LIBS"
|
oldlibs="$LIBS"
|
||||||
LIBS="$LIBS $SSHFS_LIBS"
|
LIBS="$LIBS $SSHFS_LIBS"
|
||||||
|
|
|
||||||
|
|
@ -45,14 +45,14 @@ configure_file(input: 'sshfs.1.in',
|
||||||
configure_file(output: 'config.h',
|
configure_file(output: 'config.h',
|
||||||
configuration : cfg)
|
configuration : cfg)
|
||||||
|
|
||||||
sshfs_deps = [ dependency('fuse', version: '>= 2.9'),
|
sshfs_deps = [ dependency('fuse3', version: '>= 3.0.0'),
|
||||||
dependency('glib-2.0'),
|
dependency('glib-2.0'),
|
||||||
dependency('gthread-2.0') ]
|
dependency('gthread-2.0') ]
|
||||||
|
|
||||||
executable('sshfs', sshfs_sources,
|
executable('sshfs', sshfs_sources,
|
||||||
include_directories: include_dirs,
|
include_directories: include_dirs,
|
||||||
dependencies: sshfs_deps,
|
dependencies: sshfs_deps,
|
||||||
c_args: ['-DFUSE_USE_VERSION=26'],
|
c_args: ['-DFUSE_USE_VERSION=30'],
|
||||||
install: true,
|
install: true,
|
||||||
install_dir: get_option('bindir'))
|
install_dir: get_option('bindir'))
|
||||||
|
|
||||||
|
|
|
||||||
576
sshfs.c
576
sshfs.c
|
|
@ -224,7 +224,12 @@ struct sshfs {
|
||||||
int idmap;
|
int idmap;
|
||||||
int nomap;
|
int nomap;
|
||||||
int disable_hardlink;
|
int disable_hardlink;
|
||||||
int cache;
|
int dir_cache;
|
||||||
|
int writeback_cache;
|
||||||
|
int show_version;
|
||||||
|
int show_help;
|
||||||
|
int singlethread;
|
||||||
|
char *mountpoint;
|
||||||
char *uid_file;
|
char *uid_file;
|
||||||
char *gid_file;
|
char *gid_file;
|
||||||
GHashTable *uid_map;
|
GHashTable *uid_map;
|
||||||
|
|
@ -357,9 +362,6 @@ static const char *ssh_opts[] = {
|
||||||
enum {
|
enum {
|
||||||
KEY_PORT,
|
KEY_PORT,
|
||||||
KEY_COMPRESS,
|
KEY_COMPRESS,
|
||||||
KEY_HELP,
|
|
||||||
KEY_VERSION,
|
|
||||||
KEY_FOREGROUND,
|
|
||||||
KEY_CONFIGFILE,
|
KEY_CONFIGFILE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -404,18 +406,22 @@ static struct fuse_opt sshfs_opts[] = {
|
||||||
SSHFS_OPT("delay_connect", delay_connect, 1),
|
SSHFS_OPT("delay_connect", delay_connect, 1),
|
||||||
SSHFS_OPT("slave", slave, 1),
|
SSHFS_OPT("slave", slave, 1),
|
||||||
SSHFS_OPT("disable_hardlink", disable_hardlink, 1),
|
SSHFS_OPT("disable_hardlink", disable_hardlink, 1),
|
||||||
SSHFS_OPT("cache=yes", cache, 1),
|
SSHFS_OPT("dir_cache=yes", dir_cache, 1),
|
||||||
SSHFS_OPT("cache=no", cache, 0),
|
SSHFS_OPT("dir_cache=no", dir_cache, 0),
|
||||||
|
SSHFS_OPT("writeback_cache=yes", writeback_cache, 1),
|
||||||
|
SSHFS_OPT("writeback_cache=no", writeback_cache, 0),
|
||||||
|
|
||||||
|
SSHFS_OPT("-h", show_help, 1),
|
||||||
|
SSHFS_OPT("--help", show_help, 1),
|
||||||
|
SSHFS_OPT("-V", show_version, 1),
|
||||||
|
SSHFS_OPT("--version", show_version, 1),
|
||||||
|
SSHFS_OPT("-d", debug, 1),
|
||||||
|
SSHFS_OPT("debug", debug, 1),
|
||||||
|
SSHFS_OPT("-f", foreground, 1),
|
||||||
|
SSHFS_OPT("-s", singlethread, 1),
|
||||||
|
|
||||||
FUSE_OPT_KEY("-p ", KEY_PORT),
|
FUSE_OPT_KEY("-p ", KEY_PORT),
|
||||||
FUSE_OPT_KEY("-C", KEY_COMPRESS),
|
FUSE_OPT_KEY("-C", KEY_COMPRESS),
|
||||||
FUSE_OPT_KEY("-V", KEY_VERSION),
|
|
||||||
FUSE_OPT_KEY("--version", KEY_VERSION),
|
|
||||||
FUSE_OPT_KEY("-h", KEY_HELP),
|
|
||||||
FUSE_OPT_KEY("--help", KEY_HELP),
|
|
||||||
FUSE_OPT_KEY("debug", KEY_FOREGROUND),
|
|
||||||
FUSE_OPT_KEY("-d", KEY_FOREGROUND),
|
|
||||||
FUSE_OPT_KEY("-f", KEY_FOREGROUND),
|
|
||||||
FUSE_OPT_KEY("-F ", KEY_CONFIGFILE),
|
FUSE_OPT_KEY("-F ", KEY_CONFIGFILE),
|
||||||
FUSE_OPT_END
|
FUSE_OPT_END
|
||||||
};
|
};
|
||||||
|
|
@ -863,7 +869,7 @@ static int buf_get_entries(struct buffer *buf, void *dbuf,
|
||||||
S_ISLNK(stbuf.st_mode)) {
|
S_ISLNK(stbuf.st_mode)) {
|
||||||
stbuf.st_mode = 0;
|
stbuf.st_mode = 0;
|
||||||
}
|
}
|
||||||
filler(dbuf, name, &stbuf, 0);
|
filler(dbuf, name, &stbuf, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(name);
|
free(name);
|
||||||
|
|
@ -1715,15 +1721,29 @@ static int start_processing_thread(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *sshfs_init(struct fuse_conn_info *conn)
|
static void *sshfs_init(struct fuse_conn_info *conn,
|
||||||
|
struct fuse_config *cfg)
|
||||||
{
|
{
|
||||||
/* Readahead should be done by kernel or sshfs but not both */
|
/* Readahead should be done by kernel or sshfs but not both */
|
||||||
if (conn->async_read)
|
if (conn->capable & FUSE_CAP_ASYNC_READ)
|
||||||
sshfs.sync_read = 1;
|
sshfs.sync_read = 1;
|
||||||
|
|
||||||
|
// These workarounds require the "path" argument.
|
||||||
|
cfg->nullpath_ok = ~(sshfs.truncate_workaround || sshfs.fstat_workaround);
|
||||||
|
|
||||||
|
// Lookup of . and .. is supported
|
||||||
|
conn->capable |= FUSE_CAP_EXPORT_SUPPORT;
|
||||||
|
|
||||||
|
// Enable writeback cache if supported
|
||||||
|
if (sshfs.writeback_cache && (conn->capable & FUSE_CAP_WRITEBACK_CACHE))
|
||||||
|
conn->want |= FUSE_CAP_WRITEBACK_CACHE;
|
||||||
|
|
||||||
if (!sshfs.delay_connect)
|
if (!sshfs.delay_connect)
|
||||||
start_processing_thread();
|
start_processing_thread();
|
||||||
|
|
||||||
|
// SFTP only supports 1-second time resolution
|
||||||
|
conn->time_gran = 1000000000;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1883,30 +1903,13 @@ static int sftp_request(uint8_t type, const struct buffer *buf,
|
||||||
return sftp_request_iov(type, &iov, 1, expect_type, outbuf);
|
return sftp_request_iov(type, &iov, 1, expect_type, outbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_getattr(const char *path, struct stat *stbuf)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct buffer buf;
|
|
||||||
struct buffer outbuf;
|
|
||||||
buf_init(&buf, 0);
|
|
||||||
buf_add_path(&buf, path);
|
|
||||||
err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT,
|
|
||||||
&buf, SSH_FXP_ATTRS, &outbuf);
|
|
||||||
if (!err) {
|
|
||||||
err = buf_get_attrs(&outbuf, stbuf, NULL);
|
|
||||||
buf_free(&outbuf);
|
|
||||||
}
|
|
||||||
buf_free(&buf);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sshfs_access(const char *path, int mask)
|
static int sshfs_access(const char *path, int mask)
|
||||||
{
|
{
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
if (mask & X_OK) {
|
if (mask & X_OK) {
|
||||||
err = sshfs.op->getattr(path, &stbuf);
|
err = sshfs.op->getattr(path, &stbuf, NULL);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (S_ISREG(stbuf.st_mode) &&
|
if (S_ISREG(stbuf.st_mode) &&
|
||||||
!(stbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
|
!(stbuf.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
|
||||||
|
|
@ -2146,9 +2149,10 @@ static int sshfs_opendir(const char *path, struct fuse_file_info *fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_readdir(const char *path, void *dbuf, fuse_fill_dir_t filler,
|
static int sshfs_readdir(const char *path, void *dbuf, fuse_fill_dir_t filler,
|
||||||
off_t offset, struct fuse_file_info *fi)
|
off_t offset, struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
(void) path;
|
(void) path; (void) flags;
|
||||||
int err;
|
int err;
|
||||||
struct buffer *handle;
|
struct buffer *handle;
|
||||||
|
|
||||||
|
|
@ -2291,9 +2295,13 @@ static void random_string(char *str, int length)
|
||||||
*str = '\0';
|
*str = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_rename(const char *from, const char *to)
|
static int sshfs_rename(const char *from, const char *to, unsigned int flags)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if(flags != 0)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
if (sshfs.ext_posix_rename)
|
if (sshfs.ext_posix_rename)
|
||||||
err = sshfs_ext_posix_rename(from, to);
|
err = sshfs_ext_posix_rename(from, to);
|
||||||
else
|
else
|
||||||
|
|
@ -2337,24 +2345,65 @@ static int sshfs_link(const char *from, const char *to)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_chmod(const char *path, mode_t mode)
|
static inline int sshfs_file_is_conn(struct sshfs_file *sf)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&sshfs.lock);
|
||||||
|
ret = (sf->connver == sshfs.connver);
|
||||||
|
pthread_mutex_unlock(&sshfs.lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct sshfs_file *get_sshfs_file(struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
return (struct sshfs_file *) (uintptr_t) fi->fh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sshfs_chmod(const char *path, mode_t mode,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
(void) fi;
|
||||||
int err;
|
int err;
|
||||||
struct buffer buf;
|
struct buffer buf;
|
||||||
|
struct sshfs_file *sf = NULL;
|
||||||
|
|
||||||
|
if (fi != NULL) {
|
||||||
|
sf = get_sshfs_file(fi);
|
||||||
|
if (!sshfs_file_is_conn(sf))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
buf_init(&buf, 0);
|
buf_init(&buf, 0);
|
||||||
buf_add_path(&buf, path);
|
if (sf == NULL)
|
||||||
|
buf_add_path(&buf, path);
|
||||||
|
else
|
||||||
|
buf_add_buf(&buf, &sf->handle);
|
||||||
|
|
||||||
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
|
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
|
||||||
buf_add_uint32(&buf, mode);
|
buf_add_uint32(&buf, mode);
|
||||||
|
|
||||||
/* FIXME: really needs LSETSTAT extension (debian Bug#640038) */
|
/* FIXME: really needs LSETSTAT extension (debian Bug#640038) */
|
||||||
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
|
err = sftp_request(sf == NULL ? SSH_FXP_SETSTAT : SSH_FXP_FSETSTAT,
|
||||||
|
&buf, SSH_FXP_STATUS, NULL);
|
||||||
buf_free(&buf);
|
buf_free(&buf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
|
static int sshfs_chown(const char *path, uid_t uid, gid_t gid,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void) fi;
|
||||||
int err;
|
int err;
|
||||||
struct buffer buf;
|
struct buffer buf;
|
||||||
|
struct sshfs_file *sf = NULL;
|
||||||
|
|
||||||
|
if (fi != NULL) {
|
||||||
|
sf = get_sshfs_file(fi);
|
||||||
|
if (!sshfs_file_is_conn(sf))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (sshfs.remote_uid_detected) {
|
if (sshfs.remote_uid_detected) {
|
||||||
|
|
@ -2375,11 +2424,16 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
buf_init(&buf, 0);
|
buf_init(&buf, 0);
|
||||||
buf_add_path(&buf, path);
|
if (sf == NULL)
|
||||||
|
buf_add_path(&buf, path);
|
||||||
|
else
|
||||||
|
buf_add_buf(&buf, &sf->handle);
|
||||||
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID);
|
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID);
|
||||||
buf_add_uint32(&buf, uid);
|
buf_add_uint32(&buf, uid);
|
||||||
buf_add_uint32(&buf, gid);
|
buf_add_uint32(&buf, gid);
|
||||||
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
|
|
||||||
|
err = sftp_request(sf == NULL ? SSH_FXP_SETSTAT : SSH_FXP_FSETSTAT,
|
||||||
|
&buf, SSH_FXP_STATUS, NULL);
|
||||||
buf_free(&buf);
|
buf_free(&buf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -2394,49 +2448,35 @@ static void sshfs_inc_modifver(void)
|
||||||
pthread_mutex_unlock(&sshfs.lock);
|
pthread_mutex_unlock(&sshfs.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_truncate(const char *path, off_t size)
|
static int sshfs_utimens(const char *path, const struct timespec tv[2],
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void) fi;
|
||||||
int err;
|
int err;
|
||||||
struct buffer buf;
|
struct buffer buf;
|
||||||
|
struct sshfs_file *sf = NULL;
|
||||||
|
|
||||||
sshfs_inc_modifver();
|
if (fi != NULL) {
|
||||||
if (size == 0 || sshfs.truncate_workaround)
|
sf = get_sshfs_file(fi);
|
||||||
return sshfs_truncate_workaround(path, size, NULL);
|
if (!sshfs_file_is_conn(sf))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
buf_init(&buf, 0);
|
buf_init(&buf, 0);
|
||||||
buf_add_path(&buf, path);
|
if (sf == NULL)
|
||||||
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
|
buf_add_path(&buf, path);
|
||||||
buf_add_uint64(&buf, size);
|
else
|
||||||
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
|
buf_add_buf(&buf, &sf->handle);
|
||||||
buf_free(&buf);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sshfs_utime(const char *path, struct utimbuf *ubuf)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct buffer buf;
|
|
||||||
buf_init(&buf, 0);
|
|
||||||
buf_add_path(&buf, path);
|
|
||||||
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
|
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
|
||||||
buf_add_uint32(&buf, ubuf->actime);
|
buf_add_uint32(&buf, tv[0].tv_sec);
|
||||||
buf_add_uint32(&buf, ubuf->modtime);
|
buf_add_uint32(&buf, tv[1].tv_sec);
|
||||||
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
|
|
||||||
|
err = sftp_request(sf == NULL ? SSH_FXP_SETSTAT : SSH_FXP_FSETSTAT,
|
||||||
|
&buf, SSH_FXP_STATUS, NULL);
|
||||||
buf_free(&buf);
|
buf_free(&buf);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int sshfs_file_is_conn(struct sshfs_file *sf)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&sshfs.lock);
|
|
||||||
ret = (sf->connver == sshfs.connver);
|
|
||||||
pthread_mutex_unlock(&sshfs.lock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sshfs_open_common(const char *path, mode_t mode,
|
static int sshfs_open_common(const char *path, mode_t mode,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
|
@ -2450,9 +2490,9 @@ static int sshfs_open_common(const char *path, mode_t mode,
|
||||||
uint32_t pflags = 0;
|
uint32_t pflags = 0;
|
||||||
struct iovec iov;
|
struct iovec iov;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint64_t wrctr = 0;
|
uint64_t wrctr;
|
||||||
|
|
||||||
if (sshfs.cache)
|
if (sshfs.dir_cache)
|
||||||
wrctr = cache_get_write_ctr();
|
wrctr = cache_get_write_ctr();
|
||||||
|
|
||||||
if ((fi->flags & O_ACCMODE) == O_RDONLY)
|
if ((fi->flags & O_ACCMODE) == O_RDONLY)
|
||||||
|
|
@ -2510,12 +2550,12 @@ static int sshfs_open_common(const char *path, mode_t mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
if (sshfs.cache)
|
if (sshfs.dir_cache)
|
||||||
cache_add_attr(path, &stbuf, wrctr);
|
cache_add_attr(path, &stbuf, wrctr);
|
||||||
buf_finish(&sf->handle);
|
buf_finish(&sf->handle);
|
||||||
fi->fh = (unsigned long) sf;
|
fi->fh = (unsigned long) sf;
|
||||||
} else {
|
} else {
|
||||||
if (sshfs.cache)
|
if (sshfs.dir_cache)
|
||||||
cache_invalidate(path);
|
cache_invalidate(path);
|
||||||
g_free(sf);
|
g_free(sf);
|
||||||
}
|
}
|
||||||
|
|
@ -2528,11 +2568,6 @@ static int sshfs_open(const char *path, struct fuse_file_info *fi)
|
||||||
return sshfs_open_common(path, 0, fi);
|
return sshfs_open_common(path, 0, fi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct sshfs_file *get_sshfs_file(struct fuse_file_info *fi)
|
|
||||||
{
|
|
||||||
return (struct sshfs_file *) (uintptr_t) fi->fh;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sshfs_flush(const char *path, struct fuse_file_info *fi)
|
static int sshfs_flush(const char *path, struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
@ -2575,16 +2610,14 @@ static int sshfs_fsync(const char *path, int isdatasync,
|
||||||
if (!sshfs.ext_fsync)
|
if (!sshfs.ext_fsync)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
{
|
struct buffer buf;
|
||||||
struct buffer buf;
|
struct sshfs_file *sf = get_sshfs_file(fi);
|
||||||
struct sshfs_file *sf = get_sshfs_file(fi);
|
buf_init(&buf, 0);
|
||||||
buf_init(&buf, 0);
|
buf_add_string(&buf, SFTP_EXT_FSYNC);
|
||||||
buf_add_string(&buf, SFTP_EXT_FSYNC);
|
buf_add_buf(&buf, &sf->handle);
|
||||||
buf_add_buf(&buf, &sf->handle);
|
err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS, NULL);
|
||||||
err = sftp_request(SSH_FXP_EXTENDED, &buf, SSH_FXP_STATUS, NULL);
|
buf_free(&buf);
|
||||||
buf_free(&buf);
|
return err;
|
||||||
return err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sshfs_file_put(struct sshfs_file *sf)
|
static void sshfs_file_put(struct sshfs_file *sf)
|
||||||
|
|
@ -3052,51 +3085,64 @@ static int sshfs_create(const char *path, mode_t mode,
|
||||||
return sshfs_open_common(path, mode, fi);
|
return sshfs_open_common(path, mode, fi);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_ftruncate(const char *path, off_t size,
|
static int sshfs_truncate(const char *path, off_t size,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct buffer buf;
|
struct buffer buf;
|
||||||
struct sshfs_file *sf = get_sshfs_file(fi);
|
struct sshfs_file *sf = NULL;
|
||||||
|
|
||||||
(void) path;
|
if (fi != NULL) {
|
||||||
|
sf = get_sshfs_file(fi);
|
||||||
if (!sshfs_file_is_conn(sf))
|
if (!sshfs_file_is_conn(sf))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
sshfs_inc_modifver();
|
sshfs_inc_modifver();
|
||||||
if (sshfs.truncate_workaround)
|
if (sshfs.truncate_workaround)
|
||||||
return sshfs_truncate_workaround(path, size, fi);
|
return sshfs_truncate_workaround(path, size, fi);
|
||||||
|
|
||||||
buf_init(&buf, 0);
|
buf_init(&buf, 0);
|
||||||
buf_add_buf(&buf, &sf->handle);
|
|
||||||
|
if (sf != NULL)
|
||||||
|
buf_add_buf(&buf, &sf->handle);
|
||||||
|
else
|
||||||
|
buf_add_path(&buf, path);
|
||||||
|
|
||||||
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
|
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
|
||||||
buf_add_uint64(&buf, size);
|
buf_add_uint64(&buf, size);
|
||||||
err = sftp_request(SSH_FXP_FSETSTAT, &buf, SSH_FXP_STATUS, NULL);
|
err = sftp_request(sf == NULL ? SSH_FXP_SETSTAT : SSH_FXP_FSETSTAT,
|
||||||
|
&buf, SSH_FXP_STATUS, NULL);
|
||||||
buf_free(&buf);
|
buf_free(&buf);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_fgetattr(const char *path, struct stat *stbuf,
|
static int sshfs_getattr(const char *path, struct stat *stbuf,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct buffer buf;
|
struct buffer buf;
|
||||||
struct buffer outbuf;
|
struct buffer outbuf;
|
||||||
struct sshfs_file *sf = get_sshfs_file(fi);
|
struct sshfs_file *sf = NULL;
|
||||||
|
|
||||||
(void) path;
|
if (fi != NULL || sshfs.fstat_workaround) {
|
||||||
|
sf = get_sshfs_file(fi);
|
||||||
|
if (!sshfs_file_is_conn(sf))
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sshfs_file_is_conn(sf))
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
if (sshfs.fstat_workaround)
|
|
||||||
return sshfs_getattr(path, stbuf);
|
|
||||||
|
|
||||||
buf_init(&buf, 0);
|
buf_init(&buf, 0);
|
||||||
buf_add_buf(&buf, &sf->handle);
|
if(sf == NULL) {
|
||||||
err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
|
buf_add_path(&buf, path);
|
||||||
|
err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT,
|
||||||
|
&buf, SSH_FXP_ATTRS, &outbuf);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
buf_add_buf(&buf, &sf->handle);
|
||||||
|
err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
|
||||||
|
}
|
||||||
if (!err) {
|
if (!err) {
|
||||||
err = buf_get_attrs(&outbuf, stbuf, NULL);
|
err = buf_get_attrs(&outbuf, stbuf, NULL);
|
||||||
buf_free(&outbuf);
|
buf_free(&outbuf);
|
||||||
|
|
@ -3212,10 +3258,7 @@ static int sshfs_truncate_workaround(const char *path, off_t size,
|
||||||
else {
|
else {
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
int err;
|
int err;
|
||||||
if (fi)
|
err = sshfs_getattr(path, &stbuf, fi);
|
||||||
err = sshfs_fgetattr(path, &stbuf, fi);
|
|
||||||
else
|
|
||||||
err = sshfs_getattr(path, &stbuf);
|
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
if (stbuf.st_size == size)
|
if (stbuf.st_size == size)
|
||||||
|
|
@ -3260,7 +3303,7 @@ static struct fuse_operations sshfs_oper = {
|
||||||
.chmod = sshfs_chmod,
|
.chmod = sshfs_chmod,
|
||||||
.chown = sshfs_chown,
|
.chown = sshfs_chown,
|
||||||
.truncate = sshfs_truncate,
|
.truncate = sshfs_truncate,
|
||||||
.utime = sshfs_utime,
|
.utimens = sshfs_utimens,
|
||||||
.open = sshfs_open,
|
.open = sshfs_open,
|
||||||
.flush = sshfs_flush,
|
.flush = sshfs_flush,
|
||||||
.fsync = sshfs_fsync,
|
.fsync = sshfs_fsync,
|
||||||
|
|
@ -3269,10 +3312,6 @@ static struct fuse_operations sshfs_oper = {
|
||||||
.write = sshfs_write,
|
.write = sshfs_write,
|
||||||
.statfs = sshfs_statfs,
|
.statfs = sshfs_statfs,
|
||||||
.create = sshfs_create,
|
.create = sshfs_create,
|
||||||
.ftruncate = sshfs_ftruncate,
|
|
||||||
.fgetattr = sshfs_fgetattr,
|
|
||||||
.flag_nullpath_ok = 1,
|
|
||||||
.flag_nopath = 1,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void usage(const char *progname)
|
static void usage(const char *progname)
|
||||||
|
|
@ -3280,30 +3319,32 @@ static void usage(const char *progname)
|
||||||
printf(
|
printf(
|
||||||
"usage: %s [user@]host:[dir] mountpoint [options]\n"
|
"usage: %s [user@]host:[dir] mountpoint [options]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"general options:\n"
|
|
||||||
" -o opt,[opt...] mount options\n"
|
|
||||||
" -h --help print help\n"
|
" -h --help print help\n"
|
||||||
" -V --version print version\n"
|
" -V --version print version\n"
|
||||||
"\n"
|
" -f foreground operation\n"
|
||||||
"SSHFS options:\n"
|
" -s disable multi-threaded operation\n"
|
||||||
" -p PORT equivalent to '-o port=PORT'\n"
|
" -p PORT equivalent to '-o port=PORT'\n"
|
||||||
" -C equivalent to '-o compression=yes'\n"
|
" -C equivalent to '-o compression=yes'\n"
|
||||||
" -F ssh_configfile specifies alternative ssh configuration file\n"
|
" -F ssh_configfile specifies alternative ssh configuration file\n"
|
||||||
" -1 equivalent to '-o ssh_protocol=1'\n"
|
" -1 equivalent to '-o ssh_protocol=1'\n"
|
||||||
|
" -o opt,[opt...] mount options\n"
|
||||||
" -o reconnect reconnect to server\n"
|
" -o reconnect reconnect to server\n"
|
||||||
" -o delay_connect delay connection to server\n"
|
" -o delay_connect delay connection to server\n"
|
||||||
" -o sshfs_sync synchronous writes\n"
|
" -o sshfs_sync synchronous writes\n"
|
||||||
" -o no_readahead synchronous reads (no speculative readahead)\n"
|
" -o no_readahead synchronous reads (no speculative readahead)\n"
|
||||||
" -o sync_readdir synchronous readdir\n"
|
" -o sync_readdir synchronous readdir\n"
|
||||||
" -o sshfs_debug print some debugging information\n"
|
" -d, --debug print some debugging information (implies -f)\n"
|
||||||
" -o cache=BOOL enable caching {yes,no} (default: yes)\n"
|
" -o writeback_cache=BOOL enable writeback cache {yes,no} (default: yes)\n"
|
||||||
" -o cache_max_size=N sets the maximum size of the cache (default: 10000)\n"
|
" -o dir_cache=BOOL enable caching of directory contents (names,\n"
|
||||||
" -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n"
|
" attributes, symlink targets) {yes,no} (default: yes)\n"
|
||||||
" -o cache_X_timeout=N sets timeout for {stat,dir,link} cache\n"
|
" -o dcache_max_size=N sets the maximum size of the directory cache (default: 10000)\n"
|
||||||
" -o cache_clean_interval=N\n"
|
" -o dcache_timeout=N sets timeout for directory cache in seconds (default: 20)\n"
|
||||||
|
" -o dcache_{stat,link,dir}_timeout=N\n"
|
||||||
|
" sets separate timeout for {attributes, symlinks, names}\n"
|
||||||
|
" -o dcache_clean_interval=N\n"
|
||||||
" sets the interval for automatic cleaning of the\n"
|
" sets the interval for automatic cleaning of the\n"
|
||||||
" cache (default: 60)\n"
|
" cache (default: 60)\n"
|
||||||
" -o cache_min_clean_interval=N\n"
|
" -o dcache_min_clean_interval=N\n"
|
||||||
" sets the interval for forced cleaning of the\n"
|
" sets the interval for forced cleaning of the\n"
|
||||||
" cache if full (default: 5)\n"
|
" cache if full (default: 5)\n"
|
||||||
" -o workaround=LIST colon separated list of workarounds\n"
|
" -o workaround=LIST colon separated list of workarounds\n"
|
||||||
|
|
@ -3311,7 +3352,7 @@ static void usage(const char *progname)
|
||||||
" [no]rename fix renaming to existing file (default: off)\n"
|
" [no]rename fix renaming to existing file (default: off)\n"
|
||||||
" [no]truncate fix truncate for old servers (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]buflimit fix buffer fillup bug in server (default: on)\n"
|
||||||
" [no]fstat fix fstat for old servers (default: off)\n"
|
" [no]fstat always use stat() instead of fstat() (default: off)\n"
|
||||||
" -o idmap=TYPE user/group ID mapping (default: " IDMAP_DEFAULT ")\n"
|
" -o idmap=TYPE user/group ID mapping (default: " IDMAP_DEFAULT ")\n"
|
||||||
" none no translation of the ID space\n"
|
" none no translation of the ID space\n"
|
||||||
" user only translate UID/GID of connecting user\n"
|
" user only translate UID/GID of connecting user\n"
|
||||||
|
|
@ -3332,7 +3373,9 @@ static void usage(const char *progname)
|
||||||
" -o no_check_root don't check for existence of 'dir' on server\n"
|
" -o no_check_root don't check for existence of 'dir' on server\n"
|
||||||
" -o password_stdin read password from stdin (only for pam_mount!)\n"
|
" -o password_stdin read password from stdin (only for pam_mount!)\n"
|
||||||
" -o SSHOPT=VAL ssh options (see man ssh_config)\n"
|
" -o SSHOPT=VAL ssh options (see man ssh_config)\n"
|
||||||
"\n", progname);
|
"\n"
|
||||||
|
"FUSE Options:\n",
|
||||||
|
progname);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_ssh_opt(const char *arg)
|
static int is_ssh_opt(const char *arg)
|
||||||
|
|
@ -3350,17 +3393,11 @@ static int is_ssh_opt(const char *arg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sshfs_fuse_main(struct fuse_args *args)
|
|
||||||
{
|
|
||||||
sshfs.op = cache_init(&sshfs_oper);
|
|
||||||
return fuse_main(args->argc, args->argv, sshfs.op, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int sshfs_opt_proc(void *data, const char *arg, int key,
|
static int sshfs_opt_proc(void *data, const char *arg, int key,
|
||||||
struct fuse_args *outargs)
|
struct fuse_args *outargs)
|
||||||
{
|
{
|
||||||
|
(void) outargs; (void) data;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
(void) data;
|
|
||||||
|
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case FUSE_OPT_KEY_OPT:
|
case FUSE_OPT_KEY_OPT:
|
||||||
|
|
@ -3370,6 +3407,7 @@ static int sshfs_opt_proc(void *data, const char *arg, int key,
|
||||||
g_free(tmp);
|
g_free(tmp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
/* Pass through */
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case FUSE_OPT_KEY_NONOPT:
|
case FUSE_OPT_KEY_NONOPT:
|
||||||
|
|
@ -3377,7 +3415,18 @@ static int sshfs_opt_proc(void *data, const char *arg, int key,
|
||||||
sshfs.host = strdup(arg);
|
sshfs.host = strdup(arg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 1;
|
else if (!sshfs.mountpoint) {
|
||||||
|
sshfs.mountpoint = realpath(arg, NULL);
|
||||||
|
if (!sshfs.mountpoint) {
|
||||||
|
fprintf(stderr, "sshfs: bad mount point `%s': %s\n",
|
||||||
|
arg, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "sshfs: invalid argument `%s'\n", arg);
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
|
||||||
case KEY_PORT:
|
case KEY_PORT:
|
||||||
tmp = g_strdup_printf("-oPort=%s", arg + 2);
|
tmp = g_strdup_printf("-oPort=%s", arg + 2);
|
||||||
|
|
@ -3395,22 +3444,6 @@ static int sshfs_opt_proc(void *data, const char *arg, int key,
|
||||||
g_free(tmp);
|
g_free(tmp);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
case KEY_HELP:
|
|
||||||
usage(outargs->argv[0]);
|
|
||||||
fuse_opt_add_arg(outargs, "-ho");
|
|
||||||
sshfs_fuse_main(outargs);
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
case KEY_VERSION:
|
|
||||||
printf("SSHFS version %s\n", PACKAGE_VERSION);
|
|
||||||
fuse_opt_add_arg(outargs, "--version");
|
|
||||||
sshfs_fuse_main(outargs);
|
|
||||||
exit(0);
|
|
||||||
|
|
||||||
case KEY_FOREGROUND:
|
|
||||||
sshfs.foreground = 1;
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "internal error\n");
|
fprintf(stderr, "internal error\n");
|
||||||
abort();
|
abort();
|
||||||
|
|
@ -3448,15 +3481,6 @@ static int parse_workarounds(void)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_large_read(struct fuse_args *args)
|
|
||||||
{
|
|
||||||
struct utsname buf;
|
|
||||||
int err = uname(&buf);
|
|
||||||
if (!err && strcmp(buf.sysname, "Linux") == 0 &&
|
|
||||||
strncmp(buf.release, "2.4.", 4) == 0)
|
|
||||||
fuse_opt_insert_arg(args, 1, "-olarge_read");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int read_password(void)
|
static int read_password(void)
|
||||||
{
|
{
|
||||||
int size = getpagesize();
|
int size = getpagesize();
|
||||||
|
|
@ -3794,6 +3818,11 @@ int main(int argc, char *argv[])
|
||||||
char *tmp;
|
char *tmp;
|
||||||
char *fsname;
|
char *fsname;
|
||||||
const char *sftp_server;
|
const char *sftp_server;
|
||||||
|
struct fuse *fuse;
|
||||||
|
struct fuse_session *se;
|
||||||
|
#if !defined(__CYGWIN__)
|
||||||
|
struct stat st;
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
if (!realpath(*exec_path, sshfs_program_path)) {
|
if (!realpath(*exec_path, sshfs_program_path)) {
|
||||||
|
|
@ -3817,7 +3846,12 @@ int main(int argc, char *argv[])
|
||||||
sshfs.rfd = -1;
|
sshfs.rfd = -1;
|
||||||
sshfs.wfd = -1;
|
sshfs.wfd = -1;
|
||||||
sshfs.ptyfd = -1;
|
sshfs.ptyfd = -1;
|
||||||
sshfs.cache = 1;
|
sshfs.dir_cache = 1;
|
||||||
|
sshfs.writeback_cache = 1;
|
||||||
|
sshfs.show_help = 0;
|
||||||
|
sshfs.show_version = 0;
|
||||||
|
sshfs.singlethread = 0;
|
||||||
|
sshfs.foreground = 0;
|
||||||
sshfs.ptyslavefd = -1;
|
sshfs.ptyslavefd = -1;
|
||||||
sshfs.delay_connect = 0;
|
sshfs.delay_connect = 0;
|
||||||
sshfs.slave = 0;
|
sshfs.slave = 0;
|
||||||
|
|
@ -3841,10 +3875,29 @@ int main(int argc, char *argv[])
|
||||||
parse_workarounds() == -1)
|
parse_workarounds() == -1)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
// These workarounds require the "path" argument.
|
if (sshfs.show_version) {
|
||||||
if (sshfs.truncate_workaround || sshfs.fstat_workaround) {
|
printf("SSHFS version %s\n", PACKAGE_VERSION);
|
||||||
sshfs_oper.flag_nullpath_ok = 0;
|
printf("FUSE library version %s\n", fuse_pkgversion());
|
||||||
sshfs_oper.flag_nopath = 0;
|
fuse_lowlevel_version();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sshfs.show_help) {
|
||||||
|
usage(args.argv[0]);
|
||||||
|
/* Re-add --help */
|
||||||
|
if (fuse_opt_add_arg(&args, "--help") == -1)
|
||||||
|
exit(1);
|
||||||
|
/* Print FUSE help text */
|
||||||
|
assert(fuse_new(&args, NULL, 0, NULL) == NULL);
|
||||||
|
exit(0);
|
||||||
|
} else if (!sshfs.host) {
|
||||||
|
fprintf(stderr, "missing host\n");
|
||||||
|
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
} else if (!sshfs.mountpoint) {
|
||||||
|
fprintf(stderr, "error: no mountpoint specified\n");
|
||||||
|
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sshfs.idmap == IDMAP_USER)
|
if (sshfs.idmap == IDMAP_USER)
|
||||||
|
|
@ -3868,10 +3921,10 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
DEBUG("SSHFS version %s\n", PACKAGE_VERSION);
|
DEBUG("SSHFS version %s\n", PACKAGE_VERSION);
|
||||||
|
|
||||||
if (sshfs.slave) {
|
/* Force sshfs to the foreground when using stdin+stdout */
|
||||||
/* Force sshfs to the foreground when using stdin+stdout */
|
if (sshfs.slave)
|
||||||
sshfs.foreground = 1;
|
sshfs.foreground = 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (sshfs.slave && sshfs.password_stdin) {
|
if (sshfs.slave && sshfs.password_stdin) {
|
||||||
fprintf(stderr, "the password_stdin and slave options cannot both be specified\n");
|
fprintf(stderr, "the password_stdin and slave options cannot both be specified\n");
|
||||||
|
|
@ -3884,6 +3937,9 @@ int main(int argc, char *argv[])
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sshfs.debug)
|
||||||
|
sshfs.foreground = 1;
|
||||||
|
|
||||||
if (sshfs.buflimit_workaround)
|
if (sshfs.buflimit_workaround)
|
||||||
/* Work around buggy sftp-server in OpenSSH. Without this on
|
/* Work around buggy sftp-server in OpenSSH. Without this on
|
||||||
a slow server a 10Mbyte buffer would fill up and the server
|
a slow server a 10Mbyte buffer would fill up and the server
|
||||||
|
|
@ -3892,12 +3948,6 @@ int main(int argc, char *argv[])
|
||||||
else
|
else
|
||||||
sshfs.max_outstanding_len = ~0;
|
sshfs.max_outstanding_len = ~0;
|
||||||
|
|
||||||
if (!sshfs.host) {
|
|
||||||
fprintf(stderr, "missing host\n");
|
|
||||||
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
fsname = g_strdup(sshfs.host);
|
fsname = g_strdup(sshfs.host);
|
||||||
sshfs.base_path = g_strdup(find_base_path());
|
sshfs.base_path = g_strdup(find_base_path());
|
||||||
|
|
||||||
|
|
@ -3921,7 +3971,6 @@ int main(int argc, char *argv[])
|
||||||
ssh_add_arg(sftp_server);
|
ssh_add_arg(sftp_server);
|
||||||
free(sshfs.sftp_server);
|
free(sshfs.sftp_server);
|
||||||
|
|
||||||
|
|
||||||
res = cache_parse_options(&args);
|
res = cache_parse_options(&args);
|
||||||
if (res == -1)
|
if (res == -1)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
@ -3933,107 +3982,82 @@ int main(int argc, char *argv[])
|
||||||
if (sshfs.max_write > 65536)
|
if (sshfs.max_write > 65536)
|
||||||
sshfs.max_write = 65536;
|
sshfs.max_write = 65536;
|
||||||
|
|
||||||
if (fuse_is_lib_option("ac_attr_timeout="))
|
|
||||||
fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0");
|
|
||||||
fsname = fsname_escape_commas(fsname);
|
fsname = fsname_escape_commas(fsname);
|
||||||
tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname);
|
tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname);
|
||||||
fuse_opt_insert_arg(&args, 1, tmp);
|
fuse_opt_insert_arg(&args, 1, tmp);
|
||||||
g_free(tmp);
|
g_free(tmp);
|
||||||
g_free(fsname);
|
g_free(fsname);
|
||||||
check_large_read(&args);
|
|
||||||
|
|
||||||
{
|
|
||||||
struct fuse *fuse;
|
|
||||||
struct fuse_chan *ch;
|
|
||||||
char *mountpoint;
|
|
||||||
int multithreaded;
|
|
||||||
int foreground;
|
|
||||||
#if !defined(__CYGWIN__)
|
|
||||||
struct stat st;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
res = fuse_parse_cmdline(&args, &mountpoint, &multithreaded,
|
|
||||||
&foreground);
|
|
||||||
if (res == -1)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
if (sshfs.slave) {
|
|
||||||
/* Force sshfs to the foreground when using stdin+stdout */
|
|
||||||
foreground = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(__CYGWIN__)
|
#if !defined(__CYGWIN__)
|
||||||
res = stat(mountpoint, &st);
|
res = stat(sshfs.mountpoint, &st);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
perror(mountpoint);
|
perror(sshfs.mountpoint);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
|
||||||
sshfs.mnt_mode = st.st_mode;
|
|
||||||
#elif defined(__CYGWIN__)
|
|
||||||
sshfs.mnt_mode = S_IFDIR | 0755;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ch = fuse_mount(mountpoint, &args);
|
|
||||||
if (!ch)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
#if !defined(__CYGWIN__)
|
|
||||||
res = fcntl(fuse_chan_fd(ch), F_SETFD, FD_CLOEXEC);
|
|
||||||
if (res == -1)
|
|
||||||
perror("WARNING: failed to set FD_CLOEXEC on fuse device");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(sshfs.cache)
|
|
||||||
sshfs.op = cache_init(&sshfs_oper);
|
|
||||||
else
|
|
||||||
sshfs.op = &sshfs_oper;
|
|
||||||
fuse = fuse_new(ch, &args, sshfs.op,
|
|
||||||
sizeof(struct fuse_operations), NULL);
|
|
||||||
if (fuse == NULL) {
|
|
||||||
fuse_unmount(mountpoint, ch);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = fuse_set_signal_handlers(fuse_get_session(fuse));
|
|
||||||
if (res == -1) {
|
|
||||||
fuse_unmount(mountpoint, ch);
|
|
||||||
fuse_destroy(fuse);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FIXME: trim $PATH so it doesn't contain anything inside the
|
|
||||||
* mountpoint, which would deadlock.
|
|
||||||
*/
|
|
||||||
res = ssh_connect();
|
|
||||||
if (res == -1) {
|
|
||||||
fuse_unmount(mountpoint, ch);
|
|
||||||
fuse_destroy(fuse);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
res = fuse_daemonize(foreground);
|
|
||||||
if (res == -1) {
|
|
||||||
fuse_unmount(mountpoint, ch);
|
|
||||||
fuse_destroy(fuse);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (multithreaded)
|
|
||||||
res = fuse_loop_mt(fuse);
|
|
||||||
else
|
|
||||||
res = fuse_loop(fuse);
|
|
||||||
|
|
||||||
if (res == -1)
|
|
||||||
res = 1;
|
|
||||||
else
|
|
||||||
res = 0;
|
|
||||||
|
|
||||||
fuse_remove_signal_handlers(fuse_get_session(fuse));
|
|
||||||
fuse_unmount(mountpoint, ch);
|
|
||||||
fuse_destroy(fuse);
|
|
||||||
free(mountpoint);
|
|
||||||
}
|
}
|
||||||
|
sshfs.mnt_mode = st.st_mode;
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
sshfs.mnt_mode = S_IFDIR | 0755;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(sshfs.dir_cache)
|
||||||
|
sshfs.op = cache_wrap(&sshfs_oper);
|
||||||
|
else
|
||||||
|
sshfs.op = &sshfs_oper;
|
||||||
|
fuse = fuse_new(&args, sshfs.op,
|
||||||
|
sizeof(struct fuse_operations), NULL);
|
||||||
|
if(fuse == NULL)
|
||||||
|
exit(1);
|
||||||
|
se = fuse_get_session(fuse);
|
||||||
|
res = fuse_set_signal_handlers(se);
|
||||||
|
if (res != 0) {
|
||||||
|
fuse_destroy(fuse);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = fuse_mount(fuse, sshfs.mountpoint);
|
||||||
|
if (res != 0) {
|
||||||
|
fuse_destroy(fuse);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(__CYGWIN__)
|
||||||
|
res = fcntl(fuse_session_fd(se), F_SETFD, FD_CLOEXEC);
|
||||||
|
if (res == -1)
|
||||||
|
perror("WARNING: failed to set FD_CLOEXEC on fuse device");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: trim $PATH so it doesn't contain anything inside the
|
||||||
|
* mountpoint, which would deadlock.
|
||||||
|
*/
|
||||||
|
res = ssh_connect();
|
||||||
|
if (res == -1) {
|
||||||
|
fuse_unmount(fuse);
|
||||||
|
fuse_destroy(fuse);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = fuse_daemonize(sshfs.foreground);
|
||||||
|
if (res == -1) {
|
||||||
|
fuse_unmount(fuse);
|
||||||
|
fuse_destroy(fuse);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sshfs.singlethread)
|
||||||
|
res = fuse_loop(fuse);
|
||||||
|
else
|
||||||
|
res = fuse_loop_mt(fuse, 0);
|
||||||
|
|
||||||
|
if (res != 0)
|
||||||
|
res = 1;
|
||||||
|
else
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
fuse_remove_signal_handlers(se);
|
||||||
|
fuse_unmount(fuse);
|
||||||
|
fuse_destroy(fuse);
|
||||||
|
|
||||||
if (sshfs.debug) {
|
if (sshfs.debug) {
|
||||||
unsigned int avg_rtt = 0;
|
unsigned int avg_rtt = 0;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ def name_generator(__ctr=[0]):
|
||||||
return 'testfile_%d' % __ctr[0]
|
return 'testfile_%d' % __ctr[0]
|
||||||
|
|
||||||
@pytest.mark.parametrize("debug", (False, True))
|
@pytest.mark.parametrize("debug", (False, True))
|
||||||
@pytest.mark.parametrize("cache_timeout", (0, 1))
|
@pytest.mark.parametrize("cache_timeout", (0,1))
|
||||||
@pytest.mark.parametrize("sync_rd", (True, False))
|
@pytest.mark.parametrize("sync_rd", (True, False))
|
||||||
def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, capfd):
|
def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, capfd):
|
||||||
|
|
||||||
|
|
@ -64,10 +64,10 @@ def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, capfd):
|
||||||
|
|
||||||
# SSHFS Cache
|
# SSHFS Cache
|
||||||
if cache_timeout == 0:
|
if cache_timeout == 0:
|
||||||
cmdline += [ '-o', 'cache=no' ]
|
cmdline += [ '-o', 'dir_cache=no' ]
|
||||||
else:
|
else:
|
||||||
cmdline += [ '-o', 'cache_timeout=%d' % cache_timeout,
|
cmdline += [ '-o', 'dcache_timeout=%d' % cache_timeout,
|
||||||
'-o', 'cache=yes' ]
|
'-o', 'dir_cache=yes' ]
|
||||||
|
|
||||||
# FUSE Cache
|
# FUSE Cache
|
||||||
cmdline += [ '-o', 'entry_timeout=0',
|
cmdline += [ '-o', 'entry_timeout=0',
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,20 @@ valgrind --version
|
||||||
ninja --version
|
ninja --version
|
||||||
meson --version
|
meson --version
|
||||||
|
|
||||||
|
# Install fuse
|
||||||
|
wget https://github.com/libfuse/libfuse/releases/download/fuse-3.0.2/fuse-3.0.2.tar.gz
|
||||||
|
tar xzf fuse-3.0.2.tar.gz
|
||||||
|
cd fuse-3.0.2
|
||||||
|
mkdir build
|
||||||
|
cd build
|
||||||
|
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/
|
||||||
|
|
||||||
# Setup ssh
|
# Setup ssh
|
||||||
ssh-keygen -b 768 -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
|
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
|
||||||
chmod 600 ~/.ssh/authorized_keys
|
chmod 600 ~/.ssh/authorized_keys
|
||||||
ssh -o "StrictHostKeyChecking=no" localhost echo "SSH connection succeeded"
|
ssh -o "StrictHostKeyChecking=no" localhost echo "SSH connection succeeded"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue