optimizations
This commit is contained in:
parent
fc170be8c6
commit
5dc1d26e70
14
Makefile
14
Makefile
|
|
@ -4,16 +4,12 @@ CFLAGS := -Wall -W -g
|
|||
LDLIBS := -lpthread -ldl -rdynamic
|
||||
|
||||
PKGCONFIG := env PKG_CONFIG_PATH=/usr/local/lib/pkgconfig pkg-config
|
||||
FUSEVER := $(shell $(PKGCONFIG) --modversion fuse 2> /dev/null)
|
||||
ifeq ($(FUSEVER),)
|
||||
LDLIBS += -lfuse
|
||||
else
|
||||
CFLAGS += $(shell $(PKGCONFIG) --cflags fuse)
|
||||
LDLIBS += $(shell $(PKGCONFIG) --libs fuse)
|
||||
endif
|
||||
CFLAGS += $(shell $(PKGCONFIG) --cflags fuse)
|
||||
LDLIBS += $(shell $(PKGCONFIG) --libs fuse)
|
||||
CFLAGS += $(shell $(PKGCONFIG) --cflags glib-2.0)
|
||||
LDLIBS += $(shell $(PKGCONFIG) --libs glib-2.0)
|
||||
|
||||
CPPFLAGS := -D_FILE_OFFSET_BITS=64
|
||||
#CPPFLAGS += -DDEBUG
|
||||
CPPFLAGS := -D_FILE_OFFSET_BITS=64 -D_REENTRANT
|
||||
|
||||
sshfs: sshfs.o
|
||||
|
||||
|
|
|
|||
504
sshfs.c
504
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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue