Compare commits

...

32 Commits

Author SHA1 Message Date
Miklos Szeredi fd52ef3e51 Released 2.1 2008-07-11 10:59:12 +00:00
Miklos Szeredi 1abdbe64a3 Add '-F' option to specify the ssh config file 2008-06-24 15:24:01 +00:00
Miklos Szeredi 4b28b15c34 Fix bug in caching which could cause file corruption for append mode writes 2008-05-06 15:10:28 +00:00
Miklos Szeredi 1a76a16bd9 man page update from Bartosz 2008-04-25 06:39:37 +00:00
Miklos Szeredi b1748d87aa Add manual page 2008-04-23 12:12:25 +00:00
Miklos Szeredi ff1a5c7a71 Add manual page 2008-04-23 12:07:39 +00:00
Miklos Szeredi 09579af980 Released 2.0 2008-04-22 16:01:59 +00:00
Miklos Szeredi eeea0ff5a6 Support "statvfs@openssh.com" extension... 2008-04-22 14:25:19 +00:00
Miklos Szeredi 4b88fc4731 Limit write requests to 64kB 2008-04-22 13:36:26 +00:00
Miklos Szeredi b246ad3da0 Allow the '-ossh_command=CMD' command to contain parameters... 2008-04-22 13:00:14 +00:00
Miklos Szeredi c61e700aab Fix incorrect disk usage reported by 'du' for files of size 4GB or above 2008-04-22 10:20:05 +00:00
Miklos Szeredi 4d6e5a03da Support "posix-rename@openssh.com" extension... 2008-03-31 11:30:43 +00:00
Miklos Szeredi 4802b14791 Add support for password authentication with pam_mount. 2008-03-28 19:22:19 +00:00
Miklos Szeredi 03381402b2 *** empty log message *** 2008-03-27 16:18:09 +00:00
Miklos Szeredi e83b2e61d1 Released 1.9 2007-12-17 14:32:22 +00:00
Miklos Szeredi ad9f0cf2a3 Released 1.9 2007-12-11 19:39:58 +00:00
Miklos Szeredi 501b9f712f Fix crash on writing files 2007-12-10 20:25:25 +00:00
Miklos Szeredi 37b408459a change indenting 2007-12-10 18:21:52 +00:00
Miklos Szeredi 1af7516f1e Released 1.8 2007-05-16 11:20:35 +00:00
Miklos Szeredi 15f911853e fixes 2007-05-15 20:09:29 +00:00
Miklos Szeredi eff1631428 Fix spurious cache entries remaining after renaming a directory 2007-04-18 10:24:10 +00:00
Miklos Szeredi 4399cfca84 Fix crash within gdb 2007-04-18 09:44:08 +00:00
Miklos Szeredi dd258a5117 Don't set DISPLAY environment variable to empty string 2007-03-16 13:15:16 +00:00
Miklos Szeredi feeaf76340 fix 2007-02-19 16:04:03 +00:00
Miklos Szeredi b3ffcfe3ac Work around write performace issues due to missing TCP_NODELAY in sshd 2006-12-20 17:48:08 +00:00
Miklos Szeredi d045a9be5e fix 2006-11-11 10:11:55 +00:00
Miklos Szeredi 09d5ee2eee fix segfault 2006-09-29 14:22:54 +00:00
Miklos Szeredi b917f9a420 *** empty log message *** 2006-08-18 10:38:37 +00:00
Miklos Szeredi 2d2ad5176a new release 2006-08-17 10:13:02 +00:00
Miklos Szeredi 006aa04ff4 fix 2006-08-17 09:12:55 +00:00
Miklos Szeredi 4046be4487 fixes 2006-08-16 12:57:23 +00:00
Miklos Szeredi d8c313ff85 fix 2006-04-13 07:44:30 +00:00
11 changed files with 3325 additions and 2039 deletions
+1
View File
@@ -1,6 +1,7 @@
.deps
COPYING
INSTALL
FAQ.txt
Makefile
Makefile.in
aclocal.m4
+189
View File
@@ -1,3 +1,192 @@
2008-07-11 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.1
2008-07-11 Miklos Szeredi <miklos@szeredi.hu>
* Fix statvfs extension to match the current protocol in
opensshfs
* Check version numbers of extensions, so such changes wouldn't
cause stupid behavior
2008-06-24 Miklos Szeredi <miklos@szeredi.hu>
* Add '-F' option to specify the ssh config file. Patch by Pat
Pascal.
2008-05-06 Miklos Szeredi <miklos@szeredi.hu>
* Fix bug in caching which could cause file corruption for append
mode writes. Reported by Jose Alonso
2008-05-05 Miklos Szeredi <miklos@szeredi.hu>
* Fix compile on OS X. Original patch from Michael G Schwern
* Fix compile on Solaris. Reported by Jean-Jacques Sarton
2008-04-23 Miklos Szeredi <miklos@szeredi.hu>
* Released 2.0
2008-04-23 Miklos Szeredi <miklos@szeredi.hu>
* Add manual page. Written by Bartosz Fenski
2008-04-22 Miklos Szeredi <miklos@szeredi.hu>
* Add missing ssh options: ControlMaster, ControlPath,
KbdInteractiveAuthentication, KbdInteractiveDevices, LocalCommand,
RekeyLimit (Debian bug #430225).
* Allow the '-ossh_command=CMD' command to contain parameters.
Escape charater is backslash.
* Limit write requests to 64kB.
* Support "statvfs@openssh.com" extension, which will be available
in OpenSSH 5.1.
2008-04-21 Miklos Szeredi <miklos@szeredi.hu>
* Fix incorrect disk usage reported by 'du' for files of size 4GB
or above. Reported by Christian Boltz.
2008-04-16 Miklos Szeredi <miklos@szeredi.hu>
* If debugging is enabled, print some statistics at exit about the
number of bytes transferred, etc..
2008-03-31 Miklos Szeredi <miklos@szeredi.hu>
* Support "posix-rename@openssh.com" extension available in
OpenSSH 4.9. This allows rename to be atomic even when target
file or directory exists. If available, the extension will be
used instead of the rename operation in the original protocol and
the "-oworkaround=rename" option will be ignored.
2008-03-28 Miklos Szeredi <miklos@szeredi.hu>
* Add support for password authentication with pam_mount.
Original patch and help with testing: John S. Skogtvedt
2008-03-03 Miklos Szeredi <miklos@szeredi.hu>
* Fix ssh debug only appearing if "-d" is used. Reported by
Michael Gorbach
2008-01-03 Miklos Szeredi <miklos@szeredi.hu>
* Fix condition for building of sshnodelay.so
2007-12-17 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.9
2007-12-12 Miklos Szeredi <miklos@szeredi.hu>
* Fix checking for fuse_opt_parse in configure
2007-12-11 Miklos Szeredi <miklos@szeredi.hu>
* Fill in st_ctime attribute with st_mtime, instead of leaving it
zero
* Check for OpenSSH version >= 4.4, and if found, don't build the
sshnodelay.so workaround
2007-12-10 Miklos Szeredi <miklos@szeredi.hu>
* Fix crash on writing files, caused by missing locking around
sshfs_file_get()
* Don't time requests when not debugging
* Add subtype support with libfuse >= 2.7.0
* Abort on allocation failure instead of exit
* Correctly show default of nodelaysrv workaround in help message
2007-05-16 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.8
2007-05-15 Miklos Szeredi <miklos@szeredi.hu>
* Add needed g_thread_init() to fix rare crashes. Reported by
Dimitrios Apostolou
* Fix memory leak in sshfs_open_common()
2007-04-18 Miklos Szeredi <miklos@szeredi.hu>
* Fix crash within gdb, caused by sem_wait() returning with an
error on interrupt. Reported by Dimitrios Apostolou
* Fix spurious cache entries remaining after renaming a directory
2007-02-28 Miklos Szeredi <miklos@szeredi.hu>
* Don't set DISPLAY environment variable to "", because it breaks
ssh-askpass. Make nodelaysrv_workaround default to off, because
with this change it may have security implications.
2007-02-19 Miklos Szeredi <miklos@szeredi.hu>
* OpenSSH sftp-server can read requests faster, than it processes
them, when it's buffer is full it aborts. This can happen on a
large upload to a slow server. Work around this by limiting the
total size of outstanding reqests. Debian bug #365541. Tracked
down by Thue Janus Kristensen
* Add --disable-sshnodelay configure option. The sshnodelay.so
hack shouldnt be needed with OpenSSH client versions >= 4.3
2006-12-20 Miklos Szeredi <miklos@szeredi.hu>
* Work around write performace issues due to missing TCP_NODELAY
in sshd. Reported by Justin Searle
2006-11-10 Miklos Szeredi <miklos@szeredi.hu>
* Fix bug which ommitted directory entries for symlinks with the
-ofollow_symlinks option. Bug reported by Mikael Ståldal
2006-09-29 Miklos Szeredi <miklos@szeredi.hu>
* Fix segfault if there are outstanding writes to the server after
release on the file descriptor. This only happened on FreeBSD.
Reported by Andriy Gapon
2006-08-18 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.7
2006-08-17 Miklos Szeredi <miklos@szeredi.hu>
* Cosmetics on bogus statfs numbers
2006-08-16 Miklos Szeredi <miklos@szeredi.hu>
* Add option 'follow_symlinks' to resolve symlinks on the server.
* On setups where the login shell prints a banner, the sftp
protocol was confused, and bailed out with "reply len too large:
...". So iterate over any rubbish read immediately after login
until a valid reply is found.
* Check remote directory for existence before mounting. Closes
Ubuntu bug #46633
2006-03-10 Miklos Szeredi <miklos@szeredi.hu>
* Use socketpair() instead of pipe() for communication between ssh
and sshfs. Patch from Csaba Henk
* Update to FUSE interface version 26
2006-03-09 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.6
+5 -1
View File
@@ -11,9 +11,12 @@ sshfs_LDADD = $(SSHFS_LIBS)
sshfs_CFLAGS = $(SSHFS_CFLAGS)
sshfs_CPPFLAGS = -D_REENTRANT -DFUSE_USE_VERSION=26 -DLIBDIR=\"$(libdir)\"
EXTRA_DIST = sshnodelay.c
EXTRA_DIST = sshnodelay.c FAQ.txt
CLEANFILES = sshnodelay.so
dist_man_MANS = sshfs.1
if SSH_NODELAY_SO
all-local: sshnodelay.so
install-exec-local: sshnodelay.so
@@ -25,3 +28,4 @@ uninstall-local:
sshnodelay.so:
$(CC) -Wall -W -s --shared -fPIC $(sshnodelay_libs) sshnodelay.c -o sshnodelay.so
endif
+29
View File
@@ -1,3 +1,32 @@
What is new in 2.0
------------------
* Support password authentication with pam_mount
* Support atomic renames if server is OpenSSH 4.9 or later
* Support getting disk usage if server is OpenSSH 5.1 or later
* Small enhancements and bug fixes
What is new in 1.9
------------------
* Fix a serious bug, that could result in sshfs hanging, crashing, or
reporting out-of-memory
What is new in 1.8
------------------
* Bug fixes
What is new in 1.7
------------------
* Tolerate servers which print a banner on login
* Small improvements
What is new in 1.6
------------------
+381 -333
View File
@@ -1,9 +1,9 @@
/*
Caching file system proxy
Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
Caching file system proxy
Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
#include "cache.h"
@@ -20,425 +20,466 @@
#define CACHE_CLEAN_INTERVAL 60
struct cache {
int on;
unsigned stat_timeout;
unsigned dir_timeout;
unsigned link_timeout;
struct fuse_cache_operations *next_oper;
GHashTable *table;
pthread_mutex_t lock;
time_t last_cleaned;
int on;
unsigned stat_timeout;
unsigned dir_timeout;
unsigned link_timeout;
struct fuse_cache_operations *next_oper;
GHashTable *table;
pthread_mutex_t lock;
time_t last_cleaned;
uint64_t write_ctr;
};
static struct cache cache;
struct node {
struct stat stat;
time_t stat_valid;
char **dir;
time_t dir_valid;
char *link;
time_t link_valid;
time_t valid;
struct stat stat;
time_t stat_valid;
char **dir;
time_t dir_valid;
char *link;
time_t link_valid;
time_t valid;
};
struct fuse_cache_dirhandle {
const char *path;
fuse_dirh_t h;
fuse_dirfil_t filler;
GPtrArray *dir;
const char *path;
fuse_dirh_t h;
fuse_dirfil_t filler;
GPtrArray *dir;
uint64_t wrctr;
};
static void free_node(gpointer node_)
{
struct node *node = (struct node *) node_;
g_strfreev(node->dir);
g_free(node);
struct node *node = (struct node *) node_;
g_strfreev(node->dir);
g_free(node);
}
static int cache_clean_entry(void *key_, struct node *node, time_t *now)
{
(void) key_;
if (*now > node->valid)
return TRUE;
else
return FALSE;
(void) key_;
if (*now > node->valid)
return TRUE;
else
return FALSE;
}
static void cache_clean(void)
{
time_t now = time(NULL);
if (now > cache.last_cleaned + MIN_CACHE_CLEAN_INTERVAL &&
(g_hash_table_size(cache.table) > MAX_CACHE_SIZE ||
now > cache.last_cleaned + CACHE_CLEAN_INTERVAL)) {
g_hash_table_foreach_remove(cache.table,
(GHRFunc) cache_clean_entry, &now);
cache.last_cleaned = now;
}
time_t now = time(NULL);
if (now > cache.last_cleaned + MIN_CACHE_CLEAN_INTERVAL &&
(g_hash_table_size(cache.table) > MAX_CACHE_SIZE ||
now > cache.last_cleaned + CACHE_CLEAN_INTERVAL)) {
g_hash_table_foreach_remove(cache.table,
(GHRFunc) cache_clean_entry, &now);
cache.last_cleaned = now;
}
}
static struct node *cache_lookup(const char *path)
{
return (struct node *) g_hash_table_lookup(cache.table, path);
return (struct node *) g_hash_table_lookup(cache.table, path);
}
static void cache_purge(const char *path)
{
g_hash_table_remove(cache.table, path);
g_hash_table_remove(cache.table, path);
}
static void cache_purge_parent(const char *path)
{
const char *s = strrchr(path, '/');
if (s) {
if (s == path)
g_hash_table_remove(cache.table, "/");
else {
char *parent = g_strndup(path, s - path);
cache_purge(parent);
g_free(parent);
}
}
const char *s = strrchr(path, '/');
if (s) {
if (s == path)
g_hash_table_remove(cache.table, "/");
else {
char *parent = g_strndup(path, s - path);
cache_purge(parent);
g_free(parent);
}
}
}
void cache_invalidate(const char *path)
{
pthread_mutex_lock(&cache.lock);
cache_purge(path);
pthread_mutex_unlock(&cache.lock);
pthread_mutex_lock(&cache.lock);
cache_purge(path);
pthread_mutex_unlock(&cache.lock);
}
void cache_invalidate_write(const char *path)
{
pthread_mutex_lock(&cache.lock);
cache_purge(path);
cache.write_ctr++;
pthread_mutex_unlock(&cache.lock);
}
static void cache_invalidate_dir(const char *path)
{
pthread_mutex_lock(&cache.lock);
cache_purge(path);
cache_purge_parent(path);
pthread_mutex_unlock(&cache.lock);
pthread_mutex_lock(&cache.lock);
cache_purge(path);
cache_purge_parent(path);
pthread_mutex_unlock(&cache.lock);
}
static int cache_del_children(const char *key, void *val_, const char *path)
{
(void) val_;
if (strncmp(key, path, strlen(path)) == 0)
return TRUE;
else
return FALSE;
}
static void cache_do_rename(const char *from, const char *to)
{
pthread_mutex_lock(&cache.lock);
cache_purge(from);
cache_purge(to);
cache_purge_parent(from);
cache_purge_parent(to);
pthread_mutex_unlock(&cache.lock);
pthread_mutex_lock(&cache.lock);
g_hash_table_foreach_remove(cache.table, (GHRFunc) cache_del_children,
(char *) from);
cache_purge(from);
cache_purge(to);
cache_purge_parent(from);
cache_purge_parent(to);
pthread_mutex_unlock(&cache.lock);
}
static struct node *cache_get(const char *path)
{
struct node *node = cache_lookup(path);
if (node == NULL) {
char *pathcopy = g_strdup(path);
node = g_new0(struct node, 1);
g_hash_table_insert(cache.table, pathcopy, node);
}
return node;
struct node *node = cache_lookup(path);
if (node == NULL) {
char *pathcopy = g_strdup(path);
node = g_new0(struct node, 1);
g_hash_table_insert(cache.table, pathcopy, node);
}
return node;
}
void cache_add_attr(const char *path, const struct stat *stbuf)
void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr)
{
struct node *node;
time_t now;
struct node *node;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
node->stat = *stbuf;
node->stat_valid = time(NULL) + cache.stat_timeout;
if (node->stat_valid > node->valid)
node->valid = node->stat_valid;
cache_clean();
pthread_mutex_unlock(&cache.lock);
pthread_mutex_lock(&cache.lock);
if (wrctr == cache.write_ctr) {
node = cache_get(path);
now = time(NULL);
node->stat = *stbuf;
node->stat_valid = time(NULL) + cache.stat_timeout;
if (node->stat_valid > node->valid)
node->valid = node->stat_valid;
cache_clean();
}
pthread_mutex_unlock(&cache.lock);
}
static void cache_add_dir(const char *path, char **dir)
{
struct node *node;
time_t now;
struct node *node;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_strfreev(node->dir);
node->dir = dir;
node->dir_valid = time(NULL) + cache.dir_timeout;
if (node->dir_valid > node->valid)
node->valid = node->dir_valid;
cache_clean();
pthread_mutex_unlock(&cache.lock);
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_strfreev(node->dir);
node->dir = dir;
node->dir_valid = time(NULL) + cache.dir_timeout;
if (node->dir_valid > node->valid)
node->valid = node->dir_valid;
cache_clean();
pthread_mutex_unlock(&cache.lock);
}
static size_t my_strnlen(const char *s, size_t maxsize)
{
const char *p;
for (p = s; maxsize && *p; maxsize--, p++);
return p - s;
const char *p;
for (p = s; maxsize && *p; maxsize--, p++);
return p - s;
}
static void cache_add_link(const char *path, const char *link, size_t size)
{
struct node *node;
time_t now;
struct node *node;
time_t now;
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_free(node->link);
node->link = g_strndup(link, my_strnlen(link, size-1));
node->link_valid = time(NULL) + cache.link_timeout;
if (node->link_valid > node->valid)
node->valid = node->link_valid;
cache_clean();
pthread_mutex_unlock(&cache.lock);
pthread_mutex_lock(&cache.lock);
node = cache_get(path);
now = time(NULL);
g_free(node->link);
node->link = g_strndup(link, my_strnlen(link, size-1));
node->link_valid = time(NULL) + cache.link_timeout;
if (node->link_valid > node->valid)
node->valid = node->link_valid;
cache_clean();
pthread_mutex_unlock(&cache.lock);
}
static int cache_get_attr(const char *path, struct stat *stbuf)
{
struct node *node;
int err = -EAGAIN;
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->stat_valid - now >= 0) {
*stbuf = node->stat;
err = 0;
}
}
pthread_mutex_unlock(&cache.lock);
return err;
struct node *node;
int err = -EAGAIN;
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->stat_valid - now >= 0) {
*stbuf = node->stat;
err = 0;
}
}
pthread_mutex_unlock(&cache.lock);
return err;
}
uint64_t cache_get_write_ctr(void)
{
uint64_t res;
pthread_mutex_lock(&cache.lock);
res = cache.write_ctr;
pthread_mutex_unlock(&cache.lock);
return res;
}
static int cache_getattr(const char *path, struct stat *stbuf)
{
int err = cache_get_attr(path, stbuf);
if (err) {
err = cache.next_oper->oper.getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf);
}
return err;
int err = cache_get_attr(path, stbuf);
if (err) {
uint64_t wrctr = cache_get_write_ctr();
err = cache.next_oper->oper.getattr(path, stbuf);
if (!err)
cache_add_attr(path, stbuf, wrctr);
}
return err;
}
static int cache_readlink(const char *path, char *buf, size_t size)
{
struct node *node;
int err;
struct node *node;
int err;
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->link_valid - now >= 0) {
strncpy(buf, node->link, size-1);
buf[size-1] = '\0';
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
err = cache.next_oper->oper.readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
pthread_mutex_lock(&cache.lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
if (node->link_valid - now >= 0) {
strncpy(buf, node->link, size-1);
buf[size-1] = '\0';
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
err = cache.next_oper->oper.readlink(path, buf, size);
if (!err)
cache_add_link(path, buf, size);
return err;
return err;
}
static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
const struct stat *stbuf)
{
int err = ch->filler(ch->h, name, 0, 0);
if (!err) {
char *fullpath;
g_ptr_array_add(ch->dir, g_strdup(name));
fullpath = g_strdup_printf("%s/%s", !ch->path[1] ? "" : ch->path, name);
cache_add_attr(fullpath, stbuf);
g_free(fullpath);
}
return err;
int err = ch->filler(ch->h, name, 0, 0);
if (!err) {
g_ptr_array_add(ch->dir, g_strdup(name));
if (stbuf->st_mode & S_IFMT) {
char *fullpath;
const char *basepath = !ch->path[1] ? "" : ch->path;
fullpath = g_strdup_printf("%s/%s", basepath, name);
cache_add_attr(fullpath, stbuf, ch->wrctr);
g_free(fullpath);
}
}
return err;
}
static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
struct fuse_cache_dirhandle ch;
int err;
char **dir;
struct node *node;
struct fuse_cache_dirhandle ch;
int err;
char **dir;
struct node *node;
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);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
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);
pthread_mutex_unlock(&cache.lock);
return 0;
}
}
pthread_mutex_unlock(&cache.lock);
ch.path = path;
ch.h = h;
ch.filler = filler;
ch.dir = g_ptr_array_new();
err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill);
g_ptr_array_add(ch.dir, NULL);
dir = (char **) ch.dir->pdata;
if (!err)
cache_add_dir(path, dir);
else
g_strfreev(dir);
g_ptr_array_free(ch.dir, FALSE);
return err;
ch.path = path;
ch.h = h;
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);
g_ptr_array_add(ch.dir, NULL);
dir = (char **) ch.dir->pdata;
if (!err)
cache_add_dir(path, dir);
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);
(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);
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);
if (!err)
cache_invalidate_dir(path);
return err;
int err = cache.next_oper->oper.mknod(path, mode, rdev);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_mkdir(const char *path, mode_t mode)
{
int err = cache.next_oper->oper.mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
int err = cache.next_oper->oper.mkdir(path, mode);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_unlink(const char *path)
{
int err = cache.next_oper->oper.unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
int err = cache.next_oper->oper.unlink(path);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_rmdir(const char *path)
{
int err = cache.next_oper->oper.rmdir(path);
if (!err)
cache_invalidate_dir(path);
return err;
int err = cache.next_oper->oper.rmdir(path);
if (!err)
cache_invalidate_dir(path);
return err;
}
static int cache_symlink(const char *from, const char *to)
{
int err = cache.next_oper->oper.symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
int err = cache.next_oper->oper.symlink(from, to);
if (!err)
cache_invalidate_dir(to);
return err;
}
static int cache_rename(const char *from, const char *to)
{
int err = cache.next_oper->oper.rename(from, to);
if (!err)
cache_do_rename(from, to);
return err;
int err = cache.next_oper->oper.rename(from, to);
if (!err)
cache_do_rename(from, to);
return err;
}
static int cache_link(const char *from, const char *to)
{
int err = cache.next_oper->oper.link(from, to);
if (!err) {
cache_invalidate(from);
cache_invalidate_dir(to);
}
return err;
int err = cache.next_oper->oper.link(from, to);
if (!err) {
cache_invalidate(from);
cache_invalidate_dir(to);
}
return err;
}
static int cache_chmod(const char *path, mode_t mode)
{
int err = cache.next_oper->oper.chmod(path, mode);
if (!err)
cache_invalidate(path);
return err;
int err = cache.next_oper->oper.chmod(path, mode);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_chown(const char *path, uid_t uid, gid_t gid)
{
int err = cache.next_oper->oper.chown(path, uid, gid);
if (!err)
cache_invalidate(path);
return err;
int err = cache.next_oper->oper.chown(path, uid, gid);
if (!err)
cache_invalidate(path);
return err;
}
static int cache_truncate(const char *path, off_t size)
{
int err = cache.next_oper->oper.truncate(path, size);
if (!err)
cache_invalidate(path);
return err;
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);
if (!err)
cache_invalidate(path);
return err;
int err = cache.next_oper->oper.utime(path, buf);
if (!err)
cache_invalidate(path);
return err;
}
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);
if (res >= 0)
cache_invalidate(path);
return res;
int res = cache.next_oper->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);
if (!err)
cache_invalidate_dir(path);
return err;
int err = cache.next_oper->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)
{
int err = cache.next_oper->oper.ftruncate(path, size, fi);
if (!err)
cache_invalidate(path);
return err;
int err = cache.next_oper->oper.ftruncate(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) {
err = cache.next_oper->oper.fgetattr(path, stbuf, fi);
if (!err)
cache_add_attr(path, stbuf);
}
return err;
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
@@ -446,96 +487,103 @@ 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;
cache_oper->init = oper->oper.init;
#endif
cache_oper->getattr = oper->oper.getattr;
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;
cache_oper->getattr = oper->oper.getattr;
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;
cache_oper->create = oper->oper.create;
cache_oper->ftruncate = oper->oper.ftruncate;
cache_oper->fgetattr = oper->oper.fgetattr;
#endif
}
static void cache_fill(struct fuse_cache_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
}
struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
{
static struct fuse_operations cache_oper;
cache.next_oper = oper;
static struct fuse_operations cache_oper;
cache.next_oper = oper;
cache_unity_fill(oper, &cache_oper);
if (cache.on) {
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
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;
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;
}
}
return &cache_oper;
}
static const struct fuse_opt cache_opts[] = {
{ "cache=yes", offsetof(struct cache, on), 1 },
{ "cache=no", offsetof(struct cache, on), 0 },
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, link_timeout), 0 },
{ "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_link_timeout=%u", offsetof(struct cache, link_timeout), 0 },
FUSE_OPT_END
{ "cache=yes", offsetof(struct cache, on), 1 },
{ "cache=no", offsetof(struct cache, on), 0 },
{ "cache_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_timeout=%u", offsetof(struct cache, link_timeout), 0 },
{ "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout), 0 },
{ "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout), 0 },
{ "cache_link_timeout=%u", offsetof(struct cache, link_timeout), 0 },
FUSE_OPT_END
};
int cache_parse_options(struct fuse_args *args)
{
cache.stat_timeout = DEFAULT_CACHE_TIMEOUT;
cache.dir_timeout = DEFAULT_CACHE_TIMEOUT;
cache.link_timeout = DEFAULT_CACHE_TIMEOUT;
cache.on = 1;
cache.stat_timeout = DEFAULT_CACHE_TIMEOUT;
cache.dir_timeout = DEFAULT_CACHE_TIMEOUT;
cache.link_timeout = DEFAULT_CACHE_TIMEOUT;
cache.on = 1;
return fuse_opt_parse(args, &cache, cache_opts, NULL);
return fuse_opt_parse(args, &cache, cache_opts, NULL);
}
+2 -1
View File
@@ -24,5 +24,6 @@ struct fuse_cache_operations {
struct fuse_operations *cache_init(struct fuse_cache_operations *oper);
int cache_parse_options(struct fuse_args *args);
void cache_add_attr(const char *path, const struct stat *stbuf);
void cache_add_attr(const char *path, const struct stat *stbuf, uint64_t wrctr);
void cache_invalidate(const char *path);
uint64_t cache_get_write_ctr(void);
+31 -2
View File
@@ -1,8 +1,9 @@
AC_INIT(sshfs-fuse, 1.6)
AC_INIT(sshfs-fuse, 2.1)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
AC_PROG_CC
AM_PROG_CC_C_O
CFLAGS="$CFLAGS -Wall -W"
LIBS=
AC_SEARCH_LIBS(dlsym, [dl])
@@ -10,10 +11,38 @@ sshnodelay_libs=$LIBS
AC_SUBST(sshnodelay_libs)
LIBS=
AC_ARG_ENABLE(sshnodelay,
[ --disable-sshnodelay Don't compile NODELAY workaround for ssh])
if test -z "$enable_sshnodelay"; then
AC_MSG_CHECKING([OpenSSH version])
[eval `ssh -V 2>&1 | sed -n 's/^OpenSSH_\([1-9][0-9]*\)\.\([0-9][0-9]*\).*/ssh_major=\1 ssh_minor=\2/p'`]
if test "x$ssh_major" != x -a "x$ssh_minor" != x; then
if test $ssh_major -gt 4 -o \( $ssh_major = 4 -a $ssh_minor -ge 4 \); then
AC_MSG_RESULT([$ssh_major.$ssh_minor >= 4.4, disabling NODELAY workaround])
enable_sshnodelay=no
else
AC_MSG_RESULT([$ssh_major.$ssh_minor < 4.4, enabling NODELAY workaround])
enable_sshnodelay=yes
fi
else
AC_MSG_RESULT([not found])
fi
fi
if test "$enable_sshnodelay" = "yes"; then
AC_DEFINE(SSH_NODELAY_WORKAROUND, 1, [Compile ssh NODELAY workaround])
fi
AM_CONDITIONAL(SSH_NODELAY_SO, test "$enable_sshnodelay" = "yes")
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH
PKG_CHECK_MODULES(SSHFS, [fuse >= 2.2 glib-2.0])
PKG_CHECK_MODULES(SSHFS, [fuse >= 2.2 glib-2.0 gthread-2.0])
have_fuse_opt_parse=no
oldlibs="$LIBS"
LIBS="$LIBS $SSHFS_LIBS"
AC_CHECK_FUNC([fuse_opt_parse], [have_fuse_opt_parse=yes])
LIBS="$oldlibs"
if test "$have_fuse_opt_parse" = no; then
CFLAGS="$CFLAGS -Icompat"
fi
+11
View File
@@ -0,0 +1,11 @@
#! /bin/bash
(
echo "See http://fuse.sourceforge.net/wiki/index.php/SshfsFaq for the latest"
echo "version of this FAQ"
echo "---"
echo
lynx -nolist -dump http://fuse.sourceforge.net/wiki/index.php/SshfsFaq \
| sed -e '1,12d' -e '/____/,$d'
) > FAQ.txt
+246
View File
@@ -0,0 +1,246 @@
.TH SSHFS "1" "April 2008" "SSHFS version 2.0" "User Commands"
.SH NAME
SSHFS \- filesystem client based on ssh
.SH SYNOPSIS
.SS mounting
.TP
\fBsshfs\fP [\fIuser\fP@]\fBhost\fP:[\fIdir\fP] \fBmountpoint\fP [\fIoptions\fP]
.SS unmounting
.TP
\fBfusermount -u mountpoint\fP
.SH DESCRIPTION
SSHFS (Secure SHell FileSystem) is a file system for Linux (and other
operating systems with a FUSE implementation, such as Mac OS X or FreeBSD)
capable of operating on files on a remote computer using just a secure
shell login on the remote computer. On the local computer where the SSHFS
is mounted, the implementation makes use of the FUSE (Filesystem in
Userspace) kernel module. The practical effect of this is that the end user
can seamlessly interact with remote files being securely served over SSH
just as if they were local files on his/her computer. On the remote
computer the SFTP subsystem of SSH is used.
.SH OPTIONS
.SS "general options:"
.TP
\fB\-o\fR opt,[opt...]
mount options
.TP
\fB\-h\fR \fB\-\-help\fR
print help
.TP
\fB\-V\fR \fB\-\-version\fR
print version
.SS "SSHFS options:"
.TP
\fB\-p\fR PORT
equivalent to '\-o port=PORT'
.TP
\fB\-C\fR
equivalent to '\-o compression=yes'
.TP
\fB\-F\fR ssh_configfile
specifies alternative ssh configuration file
.TP
\fB\-1\fR
equivalent to '\-o ssh_protocol=1'
.TP
\fB\-o\fR reconnect
reconnect to server
.TP
\fB\-o\fR sshfs_sync
synchronous writes
.TP
\fB\-o\fR no_readahead
synchronous reads (no speculative readahead)
.TP
\fB\-o\fR sshfs_debug
print some debugging information
.TP
\fB\-o\fR cache=YESNO
enable caching {yes,no} (default: yes)
.TP
\fB\-o\fR cache_timeout=N
sets timeout for caches in seconds (default: 20)
.TP
\fB\-o\fR cache_X_timeout=N
sets timeout for {stat,dir,link} cache
.TP
\fB\-o\fR workaround=LIST
colon separated list of workarounds
.RS 8
.TP
none
no workarounds enabled
.TP
all
all workarounds enabled
.TP
[no]rename
fix renaming to existing file (default: off)
.TP
[no]nodelaysrv
set nodelay tcp flag in ssh (default: off)
.TP
[no]truncate
fix truncate for old servers (default: off)
.TP
[no]buflimit
fix buffer fillup bug in server (default: on)
.RE
.TP
\fB\-o\fR idmap=TYPE
user/group ID mapping, possible types are:
.RS 8
.TP
none
no translation of the ID space (default)
.TP
user
only translate UID of connecting user
.RE
.TP
\fB\-o\fR ssh_command=CMD
execute CMD instead of 'ssh'
.TP
\fB\-o\fR ssh_protocol=N
ssh protocol to use (default: 2)
.TP
\fB\-o\fR sftp_server=SERV
path to sftp server or subsystem (default: sftp)
.TP
\fB\-o\fR directport=PORT
directly connect to PORT bypassing ssh
.TP
\fB\-o\fR transform_symlinks
transform absolute symlinks to relative
.TP
\fB\-o\fR follow_symlinks
follow symlinks on the server
.TP
\fB\-o\fR no_check_root
don't check for existence of 'dir' on server
.TP
\fB\-o\fR password_stdin
read password from stdin (only for pam_mount!)
.TP
\fB\-o\fR SSHOPT=VAL
ssh options (see man ssh_config)
.SS "FUSE options:"
.TP
\fB\-d\fR \fB\-o\fR debug
enable debug output (implies \fB\-f\fR)
.TP
\fB\-f\fR
foreground operation
.TP
\fB\-s\fR
disable multi\-threaded operation
.TP
\fB\-o\fR allow_other
allow access to other users
.TP
\fB\-o\fR allow_root
allow access to root
.TP
\fB\-o\fR nonempty
allow mounts over non\-empty file/dir
.HP
\fB\-o\fR default_permissions
enable permission checking by kernel
.TP
\fB\-o\fR fsname=NAME
set filesystem name
.TP
\fB\-o\fR subtype=NAME
set filesystem type
.TP
\fB\-o\fR large_read
issue large read requests (2.4 only)
.TP
\fB\-o\fR max_read=N
set maximum size of read requests
.TP
\fB\-o\fR hard_remove
immediate removal (don't hide files)
.TP
\fB\-o\fR use_ino
let filesystem set inode numbers
.TP
\fB\-o\fR readdir_ino
try to fill in d_ino in readdir
.TP
\fB\-o\fR direct_io
use direct I/O
.TP
\fB\-o\fR kernel_cache
cache files in kernel
.TP
\fB\-o\fR [no]auto_cache
enable caching based on modification times
.TP
\fB\-o\fR umask=M
set file permissions (octal)
.TP
\fB\-o\fR uid=N
set file owner
.TP
\fB\-o\fR gid=N
set file group
.TP
\fB\-o\fR entry_timeout=T
cache timeout for names (1.0s)
.TP
\fB\-o\fR negative_timeout=T
cache timeout for deleted names (0.0s)
.TP
\fB\-o\fR attr_timeout=T
cache timeout for attributes (1.0s)
.TP
\fB\-o\fR ac_attr_timeout=T
auto cache timeout for attributes (attr_timeout)
.TP
\fB\-o\fR intr
allow requests to be interrupted
.TP
\fB\-o\fR intr_signal=NUM
signal to send on interrupt (10)
.TP
\fB\-o\fR modules=M1[:M2...]
names of modules to push onto filesystem stack
.TP
\fB\-o\fR max_write=N
set maximum size of write requests
.TP
\fB\-o\fR max_readahead=N
set maximum readahead
.TP
\fB\-o\fR async_read
perform reads asynchronously (default)
.TP
\fB\-o\fR sync_read
perform reads synchronously
.SS "Module options:"
.TP
[subdir]
.TP
\fB\-o\fR subdir=DIR
prepend this directory to all paths (mandatory)
.TP
\fB\-o\fR [no]rellinksa
transform absolute symlinks to relative
.TP
[iconv]
.TP
\fB\-o\fR from_code=CHARSET
original encoding of file names (default: UTF-8)
.TP
\fB\-o\fR to_code=CHARSET
new encoding of the file names (default: ISO-8859-2)
.PD
.SH "AUTHORS"
.LP
SSHFS has been written by Miklos Seredi <miklos@szeredi.hu>.
.LP
This man page was written by Bartosz Fenski <fenio@debian.org> for the
Debian GNU/Linux distribution (but it may be used by others).
+2422 -1694
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -7,12 +7,12 @@
int connect(int sock, const struct sockaddr *addr, socklen_t addrlen)
{
int (*next_connect)(int, const struct sockaddr *, socklen_t) =
dlsym(RTLD_NEXT, "connect");
int res = next_connect(sock, addr, addrlen);
if (!res && addr->sa_family == AF_INET) {
int opt = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
}
return res;
int (*next_connect)(int, const struct sockaddr *, socklen_t) =
dlsym(RTLD_NEXT, "connect");
int res = next_connect(sock, addr, addrlen);
if (!res && addr->sa_family == AF_INET) {
int opt = 1;
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
}
return res;
}