aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Fleischer <fleiben@gmail.com>2014-02-02 23:16:13 +0100
committerBenjamin Fleischer <fleiben@gmail.com>2014-02-02 23:16:13 +0100
commitb42f84218c0a463c9a708eb0eb8c9469d92c63d5 (patch)
tree560a99721bdb1ac28c7c6d06ac22331166d0cda1
parent990f30d767063c086710ea52ad2c70237338434a (diff)
parent6b4415ada44e0cbf1924f534cd04d117a5a4dbd3 (diff)
downloadsshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.tar
sshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.tar.gz
sshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.tar.bz2
sshfs-b42f84218c0a463c9a708eb0eb8c9469d92c63d5.zip
Merge tag 'sshfs_2_5'
Conflicts: sshfs.c
-rw-r--r--ChangeLog18
-rw-r--r--configure.ac2
-rw-r--r--sshfs.1.in10
-rw-r--r--sshfs.c143
4 files changed, 160 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index c855c7d..7919f7b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2014-01-14 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Released 2.5
+
+2014-01-08 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Add -o disable_hardlink option (debian bug #670926). Reported
+ by Louis-David Mitterrand
+
+ * Optimize readdir by sending multiple requests in parallel. Add
+ -o sync_readdir to restore old behavior. Patch by Alexander
+ Neumann
+
+2014-01-07 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Map SSH2_FX_FAILURE to ENOTEMPTY for rmdir. Reported by Ross
+ Lagerwall
+
2012-05-14 Miklos Szeredi <miklos@szeredi.hu>
* When checking root directory use LSTAT not STAT. This prevents
diff --git a/configure.ac b/configure.ac
index 8089111..b64b8d1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT(sshfs-fuse, 2.4)
+AC_INIT(sshfs-fuse, 2.5)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
diff --git a/sshfs.1.in b/sshfs.1.in
index 0ba406d..124729b 100644
--- a/sshfs.1.in
+++ b/sshfs.1.in
@@ -62,6 +62,9 @@ synchronous writes
\fB\-o\fR no_readahead
synchronous reads (no speculative readahead)
.TP
+\fB\-o\fR sync_readdir
+synchronous readdir
+.TP
\fB\-o\fR sshfs_debug
print some debugging information
.TP
@@ -156,6 +159,11 @@ communicate over stdin and stdout bypassing network
\fB\-o\fR slave
communicate over stdin and stdout bypassing network
.TP
+\fB\-o\fR disable_hardlink
+link(2) will return with errno set to ENOSYS. Hard links don't currently work
+perfectly on sshfs, and this confuses some programs. If that happens try
+disabling hard links with this option.
+.TP
\fB\-o\fR transform_symlinks
transform absolute symlinks to relative
.TP
@@ -271,7 +279,7 @@ perform reads synchronously
\fB\-o\fR subdir=DIR
prepend this directory to all paths (mandatory)
.TP
-\fB\-o\fR [no]rellinksa
+\fB\-o\fR [no]rellinks
transform absolute symlinks to relative
.TP
[iconv]
diff --git a/sshfs.c b/sshfs.c
index f0a1608..d43ebc5 100644
--- a/sshfs.c
+++ b/sshfs.c
@@ -135,6 +135,10 @@
#define SSHNODELAY_SO "sshnodelay.so"
+/* Asynchronous readdir parameters */
+#define READDIR_START 2
+#define READDIR_MAX 32
+
#ifdef __APPLE__
#ifndef LIBDIR
@@ -163,6 +167,7 @@ struct request {
unsigned int want_reply;
sem_t ready;
uint8_t reply_type;
+ uint32_t id;
int replied;
int error;
struct buffer reply;
@@ -230,6 +235,7 @@ struct sshfs {
int detect_uid;
int idmap;
int nomap;
+ int disable_hardlink;
char *uid_file;
char *gid_file;
GHashTable *uid_map;
@@ -241,6 +247,7 @@ struct sshfs {
unsigned ssh_ver;
int sync_write;
int sync_read;
+ int sync_readdir;
int debug;
int foreground;
int reconnect;
@@ -381,6 +388,7 @@ static struct fuse_opt sshfs_opts[] = {
SSHFS_OPT("nomap=error", nomap, NOMAP_ERROR),
SSHFS_OPT("sshfs_sync", sync_write, 1),
SSHFS_OPT("no_readahead", sync_read, 1),
+ SSHFS_OPT("sync_readdir", sync_readdir, 1),
SSHFS_OPT("sshfs_debug", debug, 1),
SSHFS_OPT("reconnect", reconnect, 1),
SSHFS_OPT("transform_symlinks", transform_symlinks, 1),
@@ -389,6 +397,7 @@ static struct fuse_opt sshfs_opts[] = {
SSHFS_OPT("password_stdin", password_stdin, 1),
SSHFS_OPT("delay_connect", delay_connect, 1),
SSHFS_OPT("slave", slave, 1),
+ SSHFS_OPT("disable_hardlink", disable_hardlink, 1),
FUSE_OPT_KEY("-p ", KEY_PORT),
FUSE_OPT_KEY("-C", KEY_COMPRESS),
@@ -1867,6 +1876,13 @@ static int sftp_request_wait(struct request *req, uint8_t type,
err = -EIO;
break;
+ case SSH_FX_FAILURE:
+ if (type == SSH_FXP_RMDIR)
+ err = -ENOTEMPTY;
+ else
+ err = -EPERM;
+ break;
+
default:
err = -sftp_error_to_errno(serr);
}
@@ -1904,6 +1920,7 @@ static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count,
if (begin_func)
begin_func(req);
id = sftp_get_id();
+ req->id = id;
err = start_processing_thread();
if (err) {
pthread_mutex_unlock(&sshfs.lock);
@@ -2091,6 +2108,113 @@ static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
return err;
}
+static int sftp_readdir_send(struct request **req, struct buffer *handle)
+{
+ struct iovec iov;
+
+ buf_to_iov(handle, &iov);
+ return sftp_request_send(SSH_FXP_READDIR, &iov, 1, NULL, NULL,
+ SSH_FXP_NAME, NULL, req);
+}
+
+static int sshfs_req_pending(struct request *req)
+{
+ if (g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(req->id)))
+ return 1;
+ else
+ return 0;
+}
+
+static int sftp_readdir_async(struct buffer *handle, fuse_cache_dirh_t h,
+ fuse_cache_dirfil_t filler)
+{
+ int err = 0;
+ int outstanding = 0;
+ int max = READDIR_START;
+ GList *list = NULL;
+
+ int done = 0;
+
+ while (!done || outstanding) {
+ struct request *req;
+ struct buffer name;
+ int tmperr;
+
+ while (!done && outstanding < max) {
+ tmperr = sftp_readdir_send(&req, handle);
+
+ if (tmperr && !done) {
+ err = tmperr;
+ done = 1;
+ break;
+ }
+
+ list = g_list_append(list, req);
+ outstanding++;
+ }
+
+ if (outstanding) {
+ GList *first;
+ /* wait for response to next request */
+ first = g_list_first(list);
+ req = first->data;
+ list = g_list_delete_link(list, first);
+ outstanding--;
+
+ if (done) {
+ pthread_mutex_lock(&sshfs.lock);
+ if (sshfs_req_pending(req))
+ req->want_reply = 0;
+ pthread_mutex_unlock(&sshfs.lock);
+ if (!req->want_reply)
+ continue;
+ }
+
+ tmperr = sftp_request_wait(req, SSH_FXP_READDIR,
+ SSH_FXP_NAME, &name);
+
+ if (tmperr && !done) {
+ err = tmperr;
+ if (err == MY_EOF)
+ err = 0;
+ done = 1;
+ }
+ if (!done) {
+ err = buf_get_entries(&name, h, filler);
+ buf_free(&name);
+
+ /* increase number of outstanding requests */
+ if (max < READDIR_MAX)
+ max++;
+
+ if (err)
+ done = 1;
+ }
+ }
+ }
+ assert(list == NULL);
+
+ return err;
+}
+
+static int sftp_readdir_sync(struct buffer *handle, fuse_cache_dirh_t h,
+ fuse_cache_dirfil_t filler)
+{
+ int err;
+ do {
+ struct buffer name;
+ err = sftp_request(SSH_FXP_READDIR, handle, SSH_FXP_NAME, &name);
+ if (!err) {
+ err = buf_get_entries(&name, h, filler);
+ buf_free(&name);
+ }
+ } while (!err);
+ if (err == MY_EOF)
+ err = 0;
+
+ return err;
+}
+
static int sshfs_getdir(const char *path, fuse_cache_dirh_t h,
fuse_cache_dirfil_t filler)
{
@@ -2103,16 +2227,11 @@ static int sshfs_getdir(const char *path, fuse_cache_dirh_t h,
if (!err) {
int err2;
buf_finish(&handle);
- do {
- struct buffer name;
- err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name);
- if (!err) {
- err = buf_get_entries(&name, h, filler);
- buf_free(&name);
- }
- } while (!err);
- if (err == MY_EOF)
- err = 0;
+
+ if (sshfs.sync_readdir)
+ err = sftp_readdir_sync(&handle, h, filler);
+ else
+ err = sftp_readdir_async(&handle, h, filler);
err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL);
if (!err)
@@ -2269,7 +2388,7 @@ static int sshfs_link(const char *from, const char *to)
{
int err = -ENOSYS;
- if (sshfs.ext_hardlink) {
+ if (sshfs.ext_hardlink && !sshfs.disable_hardlink) {
struct buffer buf;
buf_init(&buf, 0);
@@ -3279,6 +3398,7 @@ static void usage(const char *progname)
" -o delay_connect delay connection to server\n"
" -o sshfs_sync synchronous writes\n"
" -o no_readahead synchronous reads (no speculative readahead)\n"
+" -o sync_readdir synchronous readdir\n"
" -o sshfs_debug print some debugging information\n"
" -o cache=BOOL enable caching {yes,no} (default: yes)\n"
" -o cache_timeout=N sets timeout for caches in seconds (default: 20)\n"
@@ -3312,6 +3432,7 @@ static void usage(const char *progname)
" -o sftp_server=SERV path to sftp server or subsystem (default: sftp)\n"
" -o directport=PORT directly connect to PORT bypassing ssh\n"
" -o slave communicate over stdin and stdout bypassing network\n"
+" -o disable_hardlink link(2) will return with errno set to ENOSYS\n"
" -o transform_symlinks transform absolute symlinks to relative\n"
" -o follow_symlinks follow symlinks on the server\n"
" -o no_check_root don't check for existence of 'dir' on server\n"