|
|
|
@@ -1,3 +1,12 @@
|
|
|
|
|
/*
|
|
|
|
|
SSH file system
|
|
|
|
|
Copyright (C) 2004 Miklos Szeredi <miklos@szeredi.hu>
|
|
|
|
|
|
|
|
|
|
This program can be distributed under the terms of the GNU GPL.
|
|
|
|
|
See the file COPYING.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define FUSE_USE_VERSION 22
|
|
|
|
|
#include <fuse.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
@@ -6,7 +15,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 +78,15 @@
|
|
|
|
|
|
|
|
|
|
#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 = 0;
|
|
|
|
|
static char *base_path;
|
|
|
|
|
|
|
|
|
|
struct buffer {
|
|
|
|
|
uint8_t *p;
|
|
|
|
@@ -72,10 +94,74 @@ 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) {
|
|
|
|
|
buf->p = malloc(size);
|
|
|
|
|
buf->p = (uint8_t *) malloc(size);
|
|
|
|
|
if (!buf->p)
|
|
|
|
|
exit(1);
|
|
|
|
|
} else
|
|
|
|
@@ -127,6 +213,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);
|
|
|
|
@@ -158,6 +249,13 @@ static inline void buf_add_string(struct buffer *buf, const char *str)
|
|
|
|
|
buf_add_data(buf, &data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void buf_add_path(struct buffer *buf, const char *path)
|
|
|
|
|
{
|
|
|
|
|
char *realpath = g_strdup_printf("%s%s", base_path, path[1] ? path+1 : ".");
|
|
|
|
|
buf_add_string(buf, realpath);
|
|
|
|
|
g_free(realpath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int buf_check_get(struct buffer *buf, size_t len)
|
|
|
|
|
{
|
|
|
|
|
if (buf->len + len > buf->size) {
|
|
|
|
@@ -277,8 +375,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 (struct node *) 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 +461,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[1] ? "" : path, name);
|
|
|
|
|
cache_add_attr(fullpath, &stbuf);
|
|
|
|
|
g_free(fullpath);
|
|
|
|
|
err = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -307,7 +476,7 @@ static int buf_get_entries(struct buffer *buf, fuse_dirh_t h,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int start_ssh(const char *host)
|
|
|
|
|
static int start_ssh(const char *host, const char *port)
|
|
|
|
|
{
|
|
|
|
|
int inpipe[2];
|
|
|
|
|
int outpipe[2];
|
|
|
|
@@ -334,7 +503,7 @@ static int start_ssh(const char *host)
|
|
|
|
|
close(outpipe[0]);
|
|
|
|
|
close(outpipe[1]);
|
|
|
|
|
execlp("ssh", "ssh", "-2", "-x", "-a", "-oClearAllForwardings=yes",
|
|
|
|
|
host, "-s", "sftp", NULL);
|
|
|
|
|
host, "-s", "sftp", port ? "-p" : NULL, port, NULL);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
close(inpipe[1]);
|
|
|
|
@@ -342,6 +511,39 @@ static int start_ssh(const char *host)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int connect_to(char *host, char *port)
|
|
|
|
|
{
|
|
|
|
|
int err;
|
|
|
|
|
int sock;
|
|
|
|
|
struct addrinfo *ai;
|
|
|
|
|
struct addrinfo hint;
|
|
|
|
|
|
|
|
|
|
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 +577,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 +615,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 +627,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 = (struct request *) 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,24 +762,27 @@ 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;
|
|
|
|
|
struct buffer outbuf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
err = sftp_request(SSH_FXP_LSTAT, &buf, SSH_FXP_ATTRS, &outbuf);
|
|
|
|
|
if (!err) {
|
|
|
|
|
if (buf_get_attrs(&outbuf, stbuf) == -1)
|
|
|
|
@@ -501,16 +790,36 @@ 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;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
struct buffer name;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
err = sftp_request(SSH_FXP_READLINK, &buf, SSH_FXP_NAME, &name);
|
|
|
|
|
if (!err) {
|
|
|
|
|
uint32_t count;
|
|
|
|
@@ -535,7 +844,7 @@ static int sshfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
struct buffer handle;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
err = sftp_request(SSH_FXP_OPENDIR, &buf, SSH_FXP_HANDLE, &handle);
|
|
|
|
|
if (!err) {
|
|
|
|
|
int err2;
|
|
|
|
@@ -544,7 +853,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);
|
|
|
|
|
}
|
|
|
|
@@ -552,8 +861,7 @@ static int sshfs_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
|
|
|
|
|
if (err == MY_EOF)
|
|
|
|
|
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);
|
|
|
|
@@ -567,7 +875,7 @@ static int sshfs_mkdir(const char *path, mode_t mode)
|
|
|
|
|
int err;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
|
|
|
|
|
buf_add_uint32(&buf, mode);
|
|
|
|
|
err = sftp_request(SSH_FXP_MKDIR, &buf, SSH_FXP_STATUS, NULL);
|
|
|
|
@@ -579,14 +887,13 @@ 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)
|
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
buf_add_uint32(&buf, SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_EXCL);
|
|
|
|
|
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS);
|
|
|
|
|
buf_add_uint32(&buf, mode);
|
|
|
|
@@ -607,11 +914,11 @@ 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);
|
|
|
|
|
buf_add_path(&buf, to);
|
|
|
|
|
err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL);
|
|
|
|
|
buf_free(&buf);
|
|
|
|
|
return err;
|
|
|
|
@@ -622,8 +929,10 @@ static int sshfs_unlink(const char *path)
|
|
|
|
|
int err;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL);
|
|
|
|
|
if (!err)
|
|
|
|
|
cache_remove(path);
|
|
|
|
|
buf_free(&buf);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
@@ -633,8 +942,10 @@ static int sshfs_rmdir(const char *path)
|
|
|
|
|
int err;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL);
|
|
|
|
|
if (!err)
|
|
|
|
|
cache_remove(path);
|
|
|
|
|
buf_free(&buf);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
@@ -644,9 +955,11 @@ static int sshfs_rename(const char *from, const char *to)
|
|
|
|
|
int err;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, from);
|
|
|
|
|
buf_add_string(&buf, to);
|
|
|
|
|
buf_add_path(&buf, from);
|
|
|
|
|
buf_add_path(&buf, to);
|
|
|
|
|
err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL);
|
|
|
|
|
if (!err)
|
|
|
|
|
cache_rename(from, to);
|
|
|
|
|
buf_free(&buf);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
@@ -656,10 +969,12 @@ static int sshfs_chmod(const char *path, mode_t mode)
|
|
|
|
|
int err;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
@@ -669,7 +984,7 @@ static int sshfs_chown(const char *path, uid_t uid, gid_t gid)
|
|
|
|
|
int err;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID);
|
|
|
|
|
buf_add_uint32(&buf, uid);
|
|
|
|
|
buf_add_uint32(&buf, gid);
|
|
|
|
@@ -683,10 +998,12 @@ static int sshfs_truncate(const char *path, off_t size)
|
|
|
|
|
int err;
|
|
|
|
|
struct buffer buf;
|
|
|
|
|
buf_init(&buf, 0);
|
|
|
|
|
buf_add_string(&buf, path);
|
|
|
|
|
buf_add_path(&buf, path);
|
|
|
|
|
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 +1012,108 @@ 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_path(&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_path(&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);
|
|
|
|
|
} else if (err == MY_EOF)
|
|
|
|
|
err = 0;
|
|
|
|
|
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;
|
|
|
|
|
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);
|
|
|
|
|
if (!err)
|
|
|
|
|
cache_invalidate(path);
|
|
|
|
|
buf_free(&buf);
|
|
|
|
|
return err;
|
|
|
|
|
return err ? err : (int) size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sftp_init()
|
|
|
|
@@ -833,6 +1146,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,40 +1173,103 @@ static struct fuse_operations sshfs_oper = {
|
|
|
|
|
.truncate = sshfs_truncate,
|
|
|
|
|
.utime = sshfs_utime,
|
|
|
|
|
.open = sshfs_open,
|
|
|
|
|
.release = sshfs_release,
|
|
|
|
|
.read = sshfs_read,
|
|
|
|
|
.write = sshfs_write,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void usage(const char *progname)
|
|
|
|
|
{
|
|
|
|
|
const char *fusehelp[] = { progname, "-ho", NULL };
|
|
|
|
|
|
|
|
|
|
fprintf(stderr,
|
|
|
|
|
"usage: %s [user@]host:[dir]] mountpoint [options]\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"SSH Options:\n"
|
|
|
|
|
" -p port remote port\n"
|
|
|
|
|
" -c port directly connect to port bypassing ssh\n"
|
|
|
|
|
"\n", progname);
|
|
|
|
|
fuse_main(2, (char **) fusehelp, &sshfs_oper);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
char *host;
|
|
|
|
|
char *host = NULL;
|
|
|
|
|
char *port = NULL;
|
|
|
|
|
char *fsname;
|
|
|
|
|
int res;
|
|
|
|
|
int argctr;
|
|
|
|
|
char **newargv;
|
|
|
|
|
|
|
|
|
|
int direct = 0;
|
|
|
|
|
int newargc = 0;
|
|
|
|
|
char **newargv = (char **) malloc((argc + 10) * sizeof(char *));
|
|
|
|
|
newargv[newargc++] = argv[0];
|
|
|
|
|
|
|
|
|
|
if (argc < 3) {
|
|
|
|
|
fprintf(stderr, "usage: %s [user@]host mountpoint [mount options]\n",
|
|
|
|
|
argv[0]);
|
|
|
|
|
for (argctr = 1; argctr < argc; argctr++) {
|
|
|
|
|
char *arg = argv[argctr];
|
|
|
|
|
if (arg[0] == '-') {
|
|
|
|
|
switch (arg[1]) {
|
|
|
|
|
case 'c':
|
|
|
|
|
direct = 1;
|
|
|
|
|
/* fallthrough */
|
|
|
|
|
|
|
|
|
|
case 'p':
|
|
|
|
|
if (arg[2])
|
|
|
|
|
port = &arg[2];
|
|
|
|
|
else if (argctr + 1 < argc)
|
|
|
|
|
port = argv[++argctr];
|
|
|
|
|
else {
|
|
|
|
|
fprintf(stderr, "missing argument to %s option\n", arg);
|
|
|
|
|
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
|
usage(argv[0]);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
newargv[newargc++] = arg;
|
|
|
|
|
}
|
|
|
|
|
} else if (!host && strchr(arg, ':'))
|
|
|
|
|
host = g_strdup(arg);
|
|
|
|
|
else
|
|
|
|
|
newargv[newargc++] = arg;
|
|
|
|
|
}
|
|
|
|
|
if (!host) {
|
|
|
|
|
fprintf(stderr, "missing host\n");
|
|
|
|
|
fprintf(stderr, "see `%s -h' for usage\n", argv[0]);
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host = argv[1];
|
|
|
|
|
|
|
|
|
|
res = start_ssh(host);
|
|
|
|
|
fsname = g_strdup(host);
|
|
|
|
|
base_path = strchr(host, ':');
|
|
|
|
|
*base_path++ = '\0';
|
|
|
|
|
if (base_path[0] && base_path[strlen(base_path)-1] != '/')
|
|
|
|
|
base_path = g_strdup_printf("%s/", base_path);
|
|
|
|
|
else
|
|
|
|
|
base_path = g_strdup(base_path);
|
|
|
|
|
|
|
|
|
|
if (!direct)
|
|
|
|
|
res = start_ssh(host, port);
|
|
|
|
|
else
|
|
|
|
|
res = connect_to(host, port);
|
|
|
|
|
if (res == -1)
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
g_free(host);
|
|
|
|
|
res = sftp_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);
|
|
|
|
|
|
|
|
|
|
res = processing_init();
|
|
|
|
|
if (res == -1)
|
|
|
|
|
exit(1);
|
|
|
|
|
|
|
|
|
|
newargv[newargc++] = "-omax_read=65536";
|
|
|
|
|
newargv[newargc++] = g_strdup_printf("-ofsname=sshfs#%s", fsname);
|
|
|
|
|
g_free(fsname);
|
|
|
|
|
newargv[newargc] = NULL;
|
|
|
|
|
return fuse_main(newargc, newargv, &sshfs_oper);
|
|
|
|
|
}
|
|
|
|
|