aboutsummaryrefslogtreecommitdiff
path: root/sshfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sshfs.c')
-rw-r--r--sshfs.c504
1 files changed, 411 insertions, 93 deletions
diff --git a/sshfs.c b/sshfs.c
index 263e6b6..6439693 100644
--- a/sshfs.c
+++ b/sshfs.c
@@ -6,7 +6,13 @@
#include <string.h>
#include <stdint.h>
#include <errno.h>
+#include <semaphore.h>
+#include <pthread.h>
+#include <netdb.h>
+#include <signal.h>
+#include <sys/time.h>
#include <netinet/in.h>
+#include <glib.h>
#define SSH_FXP_INIT 1
#define SSH_FXP_VERSION 2
@@ -63,8 +69,14 @@
#define MY_EOF 1
+#define MAX_REPLY_LEN (1 << 17)
+#define CACHE_TIMEOUT 20
+#define MAX_CACHE_SIZE 10000
+#define CACHE_CLEAN_INTERVAL 60
+
static int infd;
static int outfd;
+static int debug = 1;
struct buffer {
uint8_t *p;
@@ -72,6 +84,70 @@ struct buffer {
size_t size;
};
+struct request {
+ unsigned int want_reply;
+ sem_t ready;
+ uint8_t reply_type;
+ struct buffer reply;
+ struct timeval start;
+};
+
+struct openfile {
+ unsigned int read_ctr;
+ unsigned int write_ctr;
+ int rw;
+ struct buffer read_handle;
+ struct buffer write_handle;
+};
+
+struct node {
+ struct stat stat;
+ time_t updated;
+};
+
+static GHashTable *reqtab;
+static GHashTable *cache;
+static time_t last_cleaned;
+static pthread_mutex_t lock;
+static int processing_thread_started;
+
+#define DEBUG(format, args...) \
+ do { if (debug) fprintf(stderr, format, args); } while(0)
+
+static const char *type_name(uint8_t type)
+{
+ switch(type) {
+ case SSH_FXP_INIT: return "INIT";
+ case SSH_FXP_VERSION: return "VERSION";
+ case SSH_FXP_OPEN: return "OPEN";
+ case SSH_FXP_CLOSE: return "CLOSE";
+ case SSH_FXP_READ: return "READ";
+ case SSH_FXP_WRITE: return "WRITE";
+ case SSH_FXP_LSTAT: return "LSTAT";
+ case SSH_FXP_FSTAT: return "FSTAT";
+ case SSH_FXP_SETSTAT: return "SETSTAT";
+ case SSH_FXP_FSETSTAT: return "FSETSTAT";
+ case SSH_FXP_OPENDIR: return "OPENDIR";
+ case SSH_FXP_READDIR: return "READDIR";
+ case SSH_FXP_REMOVE: return "REMOVE";
+ case SSH_FXP_MKDIR: return "MKDIR";
+ case SSH_FXP_RMDIR: return "RMDIR";
+ case SSH_FXP_REALPATH: return "REALPATH";
+ case SSH_FXP_STAT: return "STAT";
+ case SSH_FXP_RENAME: return "RENAME";
+ case SSH_FXP_READLINK: return "READLINK";
+ case SSH_FXP_SYMLINK: return "SYMLINK";
+ case SSH_FXP_STATUS: return "STATUS";
+ case SSH_FXP_HANDLE: return "HANDLE";
+ case SSH_FXP_DATA: return "DATA";
+ case SSH_FXP_NAME: return "NAME";
+ case SSH_FXP_ATTRS: return "ATTRS";
+ case SSH_FXP_EXTENDED: return "EXTENDED";
+ case SSH_FXP_EXTENDED_REPLY: return "EXTENDED_REPLY";
+ default: return "???";
+ }
+}
+
static inline void buf_init(struct buffer *buf, size_t size)
{
if (size) {
@@ -127,6 +203,11 @@ static inline void buf_add_mem(struct buffer *buf, const void *data,
_buf_add_mem(buf, data, len);
}
+static inline void buf_add_buf(struct buffer *buf, const struct buffer *bufa)
+{
+ _buf_add_mem(buf, bufa->p, bufa->len);
+}
+
static inline void buf_add_uint8(struct buffer *buf, uint8_t val)
{
_buf_add_mem(buf, &val, 1);
@@ -277,8 +358,75 @@ static int buf_get_attrs(struct buffer *buf, struct stat *stbuf)
return 0;
}
+static int cache_clean_entry(void *_key, struct node *node, time_t *now)
+{
+ (void) _key;
+ if (*now > node->updated + CACHE_TIMEOUT)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+static void cache_clean(void)
+{
+ time_t now = time(NULL);
+ if (g_hash_table_size(cache) > MAX_CACHE_SIZE ||
+ now > last_cleaned + CACHE_CLEAN_INTERVAL) {
+ g_hash_table_foreach_remove(cache, (GHRFunc) cache_clean_entry, &now);
+ last_cleaned = now;
+ }
+}
+
+static struct node *cache_lookup(const char *path)
+{
+ return g_hash_table_lookup(cache, path);
+}
+
+static void cache_remove(const char *path)
+{
+ pthread_mutex_lock(&lock);
+ g_hash_table_remove(cache, path);
+ pthread_mutex_unlock(&lock);
+}
+
+static void cache_invalidate(const char *path)
+{
+ cache_remove(path);
+}
+
+static void cache_rename(const char *from, const char *to)
+{
+ cache_remove(from);
+ cache_remove(to);
+}
+
+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, pathcopy, node);
+ }
+ return node;
+}
+
+static void cache_add_attr(const char *path, const struct stat *stbuf)
+{
+ struct node *node;
+ time_t now;
+
+ pthread_mutex_lock(&lock);
+ node = cache_get(path);
+ now = time(NULL);
+ node->stat = *stbuf;
+ node->updated = time(NULL);
+ cache_clean();
+ pthread_mutex_unlock(&lock);
+}
+
static int buf_get_entries(struct buffer *buf, fuse_dirh_t h,
- fuse_dirfil_t filler)
+ fuse_dirfil_t filler, const char *path)
{
uint32_t count;
unsigned i;
@@ -296,7 +444,11 @@ static int buf_get_entries(struct buffer *buf, fuse_dirh_t h,
if (buf_get_string(buf, &longname) != -1) {
free(longname);
if (buf_get_attrs(buf, &stbuf) != -1) {
- filler(h, name, stbuf.st_mode >> 12);
+ char *fullpath;
+ filler(h, name, stbuf.st_mode >> 12, 0);
+ fullpath = g_strdup_printf("%s/%s", path, name);
+ cache_add_attr(fullpath, &stbuf);
+ g_free(fullpath);
err = 0;
}
}
@@ -342,6 +494,45 @@ static int start_ssh(const char *host)
return 0;
}
+static int connect_to(char *host)
+{
+ int err;
+ int sock;
+ struct addrinfo *ai;
+ struct addrinfo hint;
+ char *port = strchr(host, ':');
+ if (port == NULL) {
+ fprintf(stderr, "destination format must be: `.host:port'\n");
+ return -1;
+ }
+ *port++ = '\0';
+
+ memset(&hint, 0, sizeof(hint));
+ hint.ai_family = PF_INET;
+ hint.ai_socktype = SOCK_STREAM;
+ err = getaddrinfo(host, port, &hint, &ai);
+ if (err) {
+ fprintf(stderr, "failed to resolve %s:%s: %s\n", host, port,
+ gai_strerror(err));
+ return -1;
+ }
+ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (sock == -1) {
+ perror("failed to create socket");
+ return -1;
+ }
+ err = connect(sock, ai->ai_addr, ai->ai_addrlen);
+ if (err == -1) {
+ perror("failed to connect");
+ return -1;
+ }
+ freeaddrinfo(ai);
+
+ infd = sock;
+ outfd = sock;
+ return 0;
+}
+
static int do_write(struct buffer *buf)
{
uint8_t *p = buf->p;
@@ -375,9 +566,11 @@ static int sftp_send(uint8_t type, struct buffer *buf)
buf_init(&buf2, 5);
buf_add_uint32(&buf2, buf->len + 1);
buf_add_uint8(&buf2, type);
+ pthread_mutex_lock(&lock);
res = do_write(&buf2);
if (res != -1)
res = do_write(buf);
+ pthread_mutex_unlock(&lock);
buf_free(&buf2);
return res;
}
@@ -411,6 +604,10 @@ static int sftp_read(uint8_t *type, struct buffer *buf)
res = do_read(&buf2);
if (res != -1) {
buf_get_uint32(&buf2, &len);
+ if (len > MAX_REPLY_LEN) {
+ fprintf(stderr, "reply len too large: %u\n", len);
+ return -1;
+ }
buf_get_uint8(&buf2, type);
buf_init(buf, len - 1);
res = do_read(buf);
@@ -419,39 +616,117 @@ static int sftp_read(uint8_t *type, struct buffer *buf)
return res;
}
+static void *process_requests(void *_data)
+{
+ (void) _data;
+
+ while (1) {
+ int res;
+ struct buffer buf;
+ uint8_t type;
+ struct request *req;
+ uint32_t id;
+
+ buf_init(&buf, 0);
+ res = sftp_read(&type, &buf);
+ if (res == -1)
+ break;
+ if (buf_get_uint32(&buf, &id) == -1)
+ break;
+
+ pthread_mutex_lock(&lock);
+ req = g_hash_table_lookup(reqtab, (gpointer) id);
+ if (req == NULL)
+ fprintf(stderr, "request %i not found\n", id);
+ else
+ g_hash_table_remove(reqtab, (gpointer) id);
+ pthread_mutex_unlock(&lock);
+ if (req != NULL) {
+ struct timeval now;
+ unsigned int difftime;
+ gettimeofday(&now, NULL);
+ difftime = (now.tv_sec - req->start.tv_sec) * 1000;
+ difftime += (now.tv_usec - req->start.tv_usec) / 1000;
+ DEBUG(" [%05i] %14s %8ibytes (%ims)\n", id, type_name(type),
+ buf.size+5, difftime);
+ req->reply = buf;
+ if (req->want_reply) {
+ req->reply_type = type;
+ sem_post(&req->ready);
+ } else {
+ buf_free(&req->reply);
+ sem_destroy(&req->ready);
+ free(req);
+ }
+ } else
+ buf_free(&buf);
+ }
+ kill(getpid(), SIGTERM);
+ return NULL;
+}
+
+static int start_processing_thread(void)
+{
+ int err;
+ pthread_t thread_id;
+ if (processing_thread_started)
+ return 0;
+
+ err = pthread_create(&thread_id, NULL, process_requests, NULL);
+ if (err) {
+ fprintf(stderr, "failed to create thread: %s\n", strerror(err));
+ return -EPERM;
+ }
+ pthread_detach(thread_id);
+ processing_thread_started = 1;
+ return 0;
+}
+
static int sftp_request(uint8_t type, const struct buffer *buf,
uint8_t expect_type, struct buffer *outbuf)
{
int err;
struct buffer buf2;
uint32_t id = sftp_get_id();
- uint32_t idback;
- uint8_t typeback;
+ struct request *req = (struct request *) malloc(sizeof(struct request));
buf_init(&buf2, buf->len + 4);
buf_add_uint32(&buf2, id);
buf_add_mem(&buf2, buf->p, buf->len);
+
+ req->want_reply = expect_type != 0 ? 1 : 0;
+ sem_init(&req->ready, 0, 0);
+ buf_init(&req->reply, 0);
+ pthread_mutex_lock(&lock);
+ err = start_processing_thread();
+ g_hash_table_insert(reqtab, (gpointer) id, req);
+ gettimeofday(&req->start, NULL);
+ DEBUG("[%05i] %s\n", id, type_name(type));
+ pthread_mutex_unlock(&lock);
+ if (err)
+ goto out;
err = -EIO;
- if (sftp_send(type, &buf2) == -1)
- goto out;
- buf_clear(&buf2);
- if (sftp_read(&typeback, &buf2) == -1)
+ if (sftp_send(type, &buf2) == -1) {
+ pthread_mutex_lock(&lock);
+ g_hash_table_remove(reqtab, (gpointer) id);
+ pthread_mutex_unlock(&lock);
goto out;
+ }
+ if (expect_type == 0) {
+ buf_free(&buf2);
+ return 0;
+ }
+
+ sem_wait(&req->ready);
err = -EPROTO;
- if (typeback != expect_type && typeback != SSH_FXP_STATUS) {
+ if (req->reply_type != expect_type && req->reply_type != SSH_FXP_STATUS) {
fprintf(stderr, "protocol error\n");
goto out;
}
- if (buf_get_uint32(&buf2, &idback) == -1)
- goto out;
- if (idback != id) {
- fprintf(stderr, "Invalid ID received\n");
- goto out;
- }
- if (typeback == SSH_FXP_STATUS) {
+ if (req->reply_type == SSH_FXP_STATUS) {
uint32_t serr;
- if (buf_get_uint32(&buf2, &serr) == -1)
+ if (buf_get_uint32(&req->reply, &serr) == -1)
goto out;
switch (serr) {
@@ -476,18 +751,21 @@ static int sftp_request(uint8_t type, const struct buffer *buf,
default: err = -EPROTO; break;
}
} else {
- buf_init(outbuf, buf2.size - buf2.len);
- buf_get_mem(&buf2, outbuf->p, outbuf->size);
+ buf_init(outbuf, req->reply.size - req->reply.len);
+ buf_get_mem(&req->reply, outbuf->p, outbuf->size);
err = 0;
}
out:
buf_free(&buf2);
+ buf_free(&req->reply);
+ sem_destroy(&req->ready);
+ free(req);
return err;
}
-static int sshfs_getattr(const char *path, struct stat *stbuf)
+static int sshfs_send_getattr(const char *path, struct stat *stbuf)
{
int err;
struct buffer buf;
@@ -501,9 +779,29 @@ static int sshfs_getattr(const char *path, struct stat *stbuf)
buf_free(&outbuf);
}
buf_free(&buf);
+ if (!err)
+ cache_add_attr(path, stbuf);
return err;
}
+static int sshfs_getattr(const char *path, struct stat *stbuf)
+{
+ struct node *node;
+
+ pthread_mutex_lock(&lock);
+ node = cache_lookup(path);
+ if (node != NULL) {
+ time_t now = time(NULL);
+ if (now - node->updated < CACHE_TIMEOUT) {
+ *stbuf = node->stat;
+ pthread_mutex_unlock(&lock);
+ return 0;
+ }
+ }
+ pthread_mutex_unlock(&lock);
+ return sshfs_send_getattr(path, stbuf);
+}
+
static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
{
int err;
@@ -544,7 +842,7 @@ static int sshfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
struct buffer name;
err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name);
if (!err) {
- if (buf_get_entries(&name, h, filler) == -1)
+ if (buf_get_entries(&name, h, filler, path) == -1)
err = -EPROTO;
buf_free(&name);
}
@@ -553,7 +851,7 @@ static int sshfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
err = 0;
- err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS, NULL);
+ err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL);
if (!err)
err = err2;
buf_free(&handle);
@@ -579,7 +877,6 @@ static int sshfs_mknod(const char *path, mode_t mode, dev_t rdev)
int err;
struct buffer buf;
struct buffer handle;
-
(void) rdev;
if ((mode & S_IFMT) != S_IFREG)
@@ -607,9 +904,9 @@ static int sshfs_symlink(const char *from, const char *to)
{
int err;
struct buffer buf;
- buf_init(&buf, 0);
/* openssh sftp server doesn't follow standard: link target and
link name are mixed up, so we must also be non-standard :( */
+ buf_init(&buf, 0);
buf_add_string(&buf, from);
buf_add_string(&buf, to);
err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL);
@@ -624,6 +921,8 @@ static int sshfs_unlink(const char *path)
buf_init(&buf, 0);
buf_add_string(&buf, path);
err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL);
+ if (!err)
+ cache_remove(path);
buf_free(&buf);
return err;
}
@@ -635,6 +934,8 @@ static int sshfs_rmdir(const char *path)
buf_init(&buf, 0);
buf_add_string(&buf, path);
err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL);
+ if (!err)
+ cache_remove(path);
buf_free(&buf);
return err;
}
@@ -647,6 +948,8 @@ static int sshfs_rename(const char *from, const char *to)
buf_add_string(&buf, from);
buf_add_string(&buf, to);
err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL);
+ if (!err)
+ cache_rename(from, to);
buf_free(&buf);
return err;
}
@@ -660,6 +963,8 @@ static int sshfs_chmod(const char *path, mode_t mode)
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
buf_add_uint32(&buf, mode);
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
+ if (!err)
+ cache_invalidate(path);
buf_free(&buf);
return err;
}
@@ -687,6 +992,8 @@ static int sshfs_truncate(const char *path, off_t size)
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
buf_add_uint64(&buf, size);
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
+ if (!err)
+ cache_invalidate(path);
buf_free(&buf);
return err;
}
@@ -695,112 +1002,106 @@ static int sshfs_utime(const char *path, struct utimbuf *ubuf)
{
int err;
struct buffer buf;
+ cache_remove(path);
buf_init(&buf, 0);
buf_add_string(&buf, path);
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_ACMODTIME);
buf_add_uint32(&buf, ubuf->actime);
buf_add_uint32(&buf, ubuf->modtime);
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
+ if (!err)
+ cache_invalidate(path);
buf_free(&buf);
return err;
}
-static int sshfs_open(const char *path, int flags)
+static int sshfs_open(const char *path, struct fuse_file_info *fi)
{
int err;
struct buffer buf;
- struct buffer handle;
- uint32_t pflags;
- if ((flags & O_ACCMODE) == O_RDONLY)
+ struct buffer *handle;
+ uint32_t pflags = 0;
+ if ((fi->flags & O_ACCMODE) == O_RDONLY)
pflags = SSH_FXF_READ;
- else if((flags & O_ACCMODE) == O_WRONLY)
+ else if((fi->flags & O_ACCMODE) == O_WRONLY)
pflags = SSH_FXF_WRITE;
- else
+ else if ((fi->flags & O_ACCMODE) == O_RDWR)
pflags = SSH_FXF_READ | SSH_FXF_WRITE;
-
+ else
+ return -EINVAL;
+
+ handle = g_new0(struct buffer, 1);
buf_init(&buf, 0);
buf_add_string(&buf, path);
buf_add_uint32(&buf, pflags);
buf_add_uint32(&buf, 0);
- err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
+ err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, handle);
if (!err) {
- int err2;
- buf_finish(&handle);
- err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS, NULL);
- if (!err)
- err = err2;
- buf_free(&handle);
- }
+ buf_finish(handle);
+ fi->fh = (unsigned long) handle;
+ } else
+ g_free(handle);
buf_free(&buf);
return err;
}
-static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset)
+static int sshfs_release(const char *path, struct fuse_file_info *fi)
+{
+ struct buffer *handle = (struct buffer *) fi->fh;
+ (void) path;
+ sftp_request(SSH_FXP_CLOSE, handle, 0, NULL);
+ buf_free(handle);
+ g_free(handle);
+ return 0;
+}
+
+static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset,
+ struct fuse_file_info *fi)
{
int err;
struct buffer buf;
- struct buffer handle;
+ struct buffer data;
+ struct buffer *handle = (struct buffer *) fi->fh;
+ (void) path;
buf_init(&buf, 0);
- buf_add_string(&buf, path);
- buf_add_uint32(&buf, SSH_FXF_READ);
- buf_add_uint32(&buf, 0);
- err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
+ buf_add_buf(&buf, handle);
+ buf_add_uint64(&buf, offset);
+ buf_add_uint32(&buf, size);
+ err = sftp_request(SSH_FXP_READ, &buf, SSH_FXP_DATA, &data);
if (!err) {
- struct buffer data;
- int err2;
- buf_finish(&handle);
- buf_add_uint64(&handle, offset);
- buf_add_uint32(&handle, size);
- err = sftp_request(SSH_FXP_READ, &handle, SSH_FXP_DATA, &data);
- if (!err) {
- uint32_t retsize;
- err = -EPROTO;
- if (buf_get_uint32(&data, &retsize) != -1) {
- if (retsize > size)
- fprintf(stderr, "long read\n");
- else {
- buf_get_mem(&data, rbuf, retsize);
- err = retsize;
- }
+ uint32_t retsize;
+ err = -EPROTO;
+ if (buf_get_uint32(&data, &retsize) != -1) {
+ if (retsize > size)
+ fprintf(stderr, "long read\n");
+ else {
+ buf_get_mem(&data, rbuf, retsize);
+ err = retsize;
}
- buf_free(&data);
}
- err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS, NULL);
- if (err2 && err >= 0)
- err = err2;
- buf_free(&handle);
+ buf_free(&data);
}
buf_free(&buf);
return err;
}
static int sshfs_write(const char *path, const char *wbuf, size_t size,
- off_t offset)
+ off_t offset, struct fuse_file_info *fi)
{
int err;
struct buffer buf;
- struct buffer handle;
+ struct buffer data;
+ struct buffer *handle = (struct buffer *) fi->fh;
+ (void) path;
+ data.p = (uint8_t *) wbuf;
+ data.len = size;
buf_init(&buf, 0);
- buf_add_string(&buf, path);
- buf_add_uint32(&buf, SSH_FXF_WRITE);
- buf_add_uint32(&buf, 0);
- err = sftp_request(SSH_FXP_OPEN, &buf, SSH_FXP_HANDLE, &handle);
- if (!err) {
- struct buffer data;
- int err2;
- data.p = (uint8_t *) wbuf;
- data.len = size;
- buf_finish(&handle);
- buf_add_uint64(&handle, offset);
- buf_add_data(&handle, &data);
- err = sftp_request(SSH_FXP_WRITE, &handle, SSH_FXP_STATUS, NULL);
- err2 = sftp_request(SSH_FXP_CLOSE, &handle, SSH_FXP_STATUS, NULL);
- if (err2 && err >= 0)
- err = err2;
- buf_free(&handle);
- }
+ buf_add_buf(&buf, handle);
+ buf_add_uint64(&buf, offset);
+ buf_add_data(&buf, &data);
+ err = sftp_request(SSH_FXP_WRITE, &buf, SSH_FXP_STATUS, NULL);
buf_free(&buf);
- return err;
+ return err ? err : (int) size;
}
static int sftp_init()
@@ -833,6 +1134,18 @@ static int sftp_init()
return res;
}
+static int processing_init(void)
+{
+ pthread_mutex_init(&lock, NULL);
+ reqtab = g_hash_table_new(NULL, NULL);
+ cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ if (!reqtab || !cache) {
+ fprintf(stderr, "failed to create hash tables\n");
+ return -1;
+ }
+ return 0;
+}
+
static struct fuse_operations sshfs_oper = {
.getattr = sshfs_getattr,
.readlink = sshfs_readlink,
@@ -848,6 +1161,7 @@ static struct fuse_operations sshfs_oper = {
.truncate = sshfs_truncate,
.utime = sshfs_utime,
.open = sshfs_open,
+ .release = sshfs_release,
.read = sshfs_read,
.write = sshfs_write,
};
@@ -858,29 +1172,33 @@ int main(int argc, char *argv[])
int res;
int argctr;
char **newargv;
-
if (argc < 3) {
- fprintf(stderr, "usage: %s [user@]host mountpoint [mount options]\n",
+ fprintf(stderr, "usage: %s [+][user@]host[:port] mountpoint [mount options]\n",
argv[0]);
exit(1);
}
host = argv[1];
-
- res = start_ssh(host);
+ if (host[0] == '+')
+ res = connect_to(host+1);
+ else
+ res = start_ssh(host);
if (res == -1)
exit(1);
res = sftp_init();
if (res == -1)
exit(1);
-
+
+ res = processing_init();
+ if (res == -1)
+ exit(1);
+
newargv = (char **) malloc((argc + 10) * sizeof(char *));
newargv[0] = argv[0];
for (argctr = 1; argctr < argc - 1; argctr++)
newargv[argctr] = argv[argctr + 1];
- newargv[argctr++] = "-s";
newargv[argctr++] = "-omax_read=65536";
newargv[argctr] = NULL;
return fuse_main(argctr, newargv, &sshfs_oper);