Compare commits

...

8 Commits

Author SHA1 Message Date
Miklos Szeredi adf379b056 fix 2005-08-15 09:07:44 +00:00
Miklos Szeredi 82d15b68d4 release 1.2 2005-08-15 08:58:26 +00:00
Miklos Szeredi 2d959740ea fix 2005-08-13 21:33:42 +00:00
Miklos Szeredi 28495b3bb2 reconnection 2005-08-13 21:17:11 +00:00
Miklos Szeredi 61a154807b fix 2005-05-05 11:55:53 +00:00
Miklos Szeredi c67cf9b98b fix 2005-05-05 11:33:39 +00:00
Miklos Szeredi effd586502 fix 2005-04-13 11:38:40 +00:00
Miklos Szeredi b1ddd5f430 fix 2005-03-08 13:11:12 +00:00
7 changed files with 257 additions and 62 deletions
+31
View File
@@ -1,3 +1,34 @@
2005-08-15 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.2
2005-08-13 Miklos Szeredi <miklos@szeredi.hu>
* Add 'reconnect' option, which tries to reconnect to the server
when the connection is broken. If a password is required for
connection, it is recommended that you install ssh-askpass, and
set the SSH_ASKPASS environment variable (see 'man ssh' for more
details).
2005-05-05 Miklos Szeredi <miklos@szeredi.hu>
* Work around missing truncate() support in some older sftp
servers (only works for zero size truncate). Thanks to Eduard
Czimbalmos for the bug report and help with testing
2005-04-13 Miklos Szeredi <miklos@szeredi.hu>
* Fix compilation with gcc-2.95. Reported by David A. Gershman
2005-03-08 Miklos Szeredi <miklos@szeredi.hu>
* Make it work on server version 2 (e.g. Sun_SSH_1.0.1). Report
and testing by Pieter J. Kersten
2005-03-04 Miklos Szeredi <miklos@szeredi.hu>
* Released 1.1
2005-03-03 Miklos Szeredi <miklos@szeredi.hu>
* Slightly optimize readahead. Still not clever enough to always
+7
View File
@@ -1,3 +1,10 @@
What is new in 1.2
------------------
* Better compatibility with different sftp servers
* Automatic reconnect (optional)
What is new in 1.1
------------------
+2
View File
@@ -20,6 +20,8 @@ codebase, so I rewrote it. Features of this implementation are:
- Caching directory contents
- Reconnect on failure
How to mount a filesystem
=========================
+5 -2
View File
@@ -244,9 +244,9 @@ static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
{
int err = ch->filler(ch->h, name, 0, 0);
if (!err) {
char *fullpath;
g_ptr_array_add(ch->dir, g_strdup(name));
char *fullpath = g_strdup_printf("%s/%s",
!ch->path[1] ? "" : ch->path, name);
fullpath = g_strdup_printf("%s/%s", !ch->path[1] ? "" : ch->path, name);
cache_add_attr(fullpath, stbuf);
g_free(fullpath);
}
@@ -406,6 +406,9 @@ static int cache_write(const char *path, const char *buf, size_t size,
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;
#endif
cache_oper->getattr = oper->oper.getattr;
cache_oper->readlink = oper->oper.readlink;
cache_oper->getdir = cache_unity_getdir;
+4
View File
@@ -8,6 +8,10 @@
#include <fuse.h>
#ifndef FUSE_VERSION
#define FUSE_VERSION (FUSE_MAJOR_VERSION * 10 + FUSE_MINOR_VERSION)
#endif
typedef struct fuse_cache_dirhandle *fuse_cache_dirh_t;
typedef int (*fuse_cache_dirfil_t) (fuse_cache_dirh_t h, const char *name,
const struct stat *stbuf);
+1 -1
View File
@@ -1,4 +1,4 @@
AC_INIT(sshfs-fuse, 1.1)
AC_INIT(sshfs-fuse, 1.2)
AM_INIT_AUTOMAKE
AM_CONFIG_HEADER(config.h)
+207 -59
View File
@@ -21,6 +21,7 @@
#include <netdb.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <glib.h>
@@ -86,10 +87,14 @@
static int infd;
static int outfd;
static int connver;
static int server_version;
static int debug = 0;
static int reconnect = 0;
static int sync_write = 0;
static int sync_read = 0;
static char *base_path;
static char *host;
struct buffer {
uint8_t *p;
@@ -110,6 +115,7 @@ struct request {
sem_t ready;
uint8_t reply_type;
int replied;
int error;
struct buffer reply;
struct timeval start;
void *data;
@@ -134,6 +140,7 @@ struct sshfs_file {
struct read_chunk *readahead;
off_t next_pos;
int is_seq;
int connver;
};
static GHashTable *reqtab;
@@ -191,6 +198,7 @@ enum {
SOPT_SYNC_READ,
SOPT_MAX_READ,
SOPT_DEBUG,
SOPT_RECONNECT,
SOPT_LAST /* Last entry in this list! */
};
@@ -201,6 +209,7 @@ static struct opt sshfs_opts[] = {
[SOPT_SYNC_READ] = { .optname = "no_readahead" },
[SOPT_MAX_READ] = { .optname = "max_read" },
[SOPT_DEBUG] = { .optname = "sshfs_debug" },
[SOPT_RECONNECT] = { .optname = "reconnect" },
[SOPT_LAST] = { .optname = NULL }
};
@@ -544,9 +553,13 @@ static int start_ssh(char *host)
perror("failed to fork");
return -1;
} else if (pid == 0) {
int devnull;
int argctr = 0;
char *ssh_args[sizeof(ssh_opts)/sizeof(struct opt) + 32];
char *ssh_cmd;
devnull = open("/dev/null", O_WRONLY);
if (sshfs_opts[SOPT_SSHCMD].present)
ssh_cmd = sshfs_opts[SOPT_SSHCMD].value;
else
@@ -554,13 +567,28 @@ static int start_ssh(char *host)
if (dup2(outpipe[0], 0) == -1 || dup2(inpipe[1], 1) == -1) {
perror("failed to redirect input/output");
exit(1);
_exit(1);
}
if (!debug && devnull != -1)
dup2(devnull, 2);
close(devnull);
close(inpipe[0]);
close(inpipe[1]);
close(outpipe[0]);
close(outpipe[1]);
switch (fork()) {
case -1:
perror("failed to fork");
_exit(1);
case 0:
break;
default:
_exit(0);
}
chdir("/");
ssh_args[argctr++] = ssh_cmd;
ssh_args[argctr++] = "-2";
ssh_args[argctr++] = "-x";
@@ -580,8 +608,9 @@ static int start_ssh(char *host)
ssh_args[argctr++] = NULL;
execvp(ssh_cmd, ssh_args);
exit(1);
_exit(1);
}
waitpid(pid, NULL, 0);
close(inpipe[1]);
close(outpipe[0]);
return 0;
@@ -653,11 +682,9 @@ 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;
}
@@ -673,7 +700,7 @@ static int do_read(struct buffer *buf)
perror("read");
return -1;
} else if (res == 0) {
fprintf(stderr, "end of file read\n");
fprintf(stderr, "remote host has disconnected\n");
return -1;
}
size -= res;
@@ -690,12 +717,14 @@ static int sftp_read(uint8_t *type, struct buffer *buf)
buf_init(&buf2, 5);
res = do_read(&buf2);
if (res != -1) {
buf_get_uint32(&buf2, &len);
if (buf_get_uint32(&buf2, &len) == -1)
return -1;
if (len > MAX_REPLY_LEN) {
fprintf(stderr, "reply len too large: %u\n", len);
return -1;
}
buf_get_uint8(&buf2, type);
if (buf_get_uint8(&buf2, type) == -1)
return -1;
buf_init(buf, len - 1);
res = do_read(buf);
}
@@ -733,12 +762,27 @@ static void chunk_put_locked(struct read_chunk *chunk)
pthread_mutex_unlock(&lock);
}
static void *process_requests(void *_data)
static int clean_req(void *key_, struct request *req)
{
(void) _data;
(void) key_;
req->error = -EIO;
if (req->want_reply)
sem_post(&req->ready);
else {
if (req->end_func)
req->end_func(req);
request_free(req);
}
return TRUE;
}
static void *process_requests(void *data_)
{
int res;
(void) data_;
while (1) {
int res;
struct buffer buf;
uint8_t type;
struct request *req;
@@ -772,17 +816,80 @@ static void *process_requests(void *_data)
if (req->want_reply)
sem_post(&req->ready);
else {
if (req->end_func)
if (req->end_func) {
pthread_mutex_lock(&lock);
req->end_func(req);
pthread_mutex_unlock(&lock);
}
request_free(req);
}
} else
buf_free(&buf);
}
kill(getpid(), SIGTERM);
if (!reconnect) {
/* harakiri */
kill(getpid(), SIGTERM);
} else {
pthread_mutex_lock(&lock);
processing_thread_started = 0;
close(infd);
infd = -1;
close(outfd);
outfd = -1;
g_hash_table_foreach_remove(reqtab, (GHRFunc) clean_req, NULL);
connver ++;
pthread_mutex_unlock(&lock);
}
return NULL;
}
static int sftp_init()
{
int res = -1;
uint8_t type;
uint32_t version;
struct buffer buf;
buf_init(&buf, 4);
buf_add_uint32(&buf, PROTO_VERSION);
if (sftp_send(SSH_FXP_INIT, &buf) == -1)
goto out;
buf_clear(&buf);
if (sftp_read(&type, &buf) == -1)
goto out;
if (type != SSH_FXP_VERSION) {
fprintf(stderr, "protocol error\n");
goto out;
}
if (buf_get_uint32(&buf, &version) == -1)
goto out;
server_version = version;
DEBUG("Server version: %i\n", server_version);
if (version > PROTO_VERSION)
fprintf(stderr, "Warning: server uses version: %i, we support: %i\n",
version, PROTO_VERSION);
res = 0;
out:
buf_free(&buf);
return res;
}
static int connect_remote(void)
{
int err;
if (sshfs_opts[SOPT_DIRECTPORT].present)
err = connect_to(host, sshfs_opts[SOPT_DIRECTPORT].value);
else
err = start_ssh(host);
if (!err)
err = sftp_init();
return err;
}
static int start_processing_thread(void)
{
int err;
@@ -790,16 +897,30 @@ static int start_processing_thread(void)
if (processing_thread_started)
return 0;
if (outfd == -1) {
err = connect_remote();
if (err)
return -EIO;
}
err = pthread_create(&thread_id, NULL, process_requests, NULL);
if (err) {
fprintf(stderr, "failed to create thread: %s\n", strerror(err));
return -EPERM;
return -EIO;
}
pthread_detach(thread_id);
processing_thread_started = 1;
return 0;
}
#if FUSE_VERSION >= 23
static void *sshfs_init(void)
{
start_processing_thread();
return NULL;
}
#endif
static int sftp_request_common(uint8_t type, const struct buffer *buf,
uint8_t expect_type, struct buffer *outbuf,
request_func begin_func, request_func end_func,
@@ -823,26 +944,32 @@ static int sftp_request_common(uint8_t type, const struct buffer *buf,
begin_func(req);
pthread_mutex_lock(&lock);
err = start_processing_thread();
if (err) {
pthread_mutex_unlock(&lock);
goto out;
}
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) {
pthread_mutex_lock(&lock);
g_hash_table_remove(reqtab, (gpointer) id);
pthread_mutex_unlock(&lock);
goto out;
}
pthread_mutex_unlock(&lock);
if (expect_type == 0) {
buf_free(&buf2);
return 0;
}
sem_wait(&req->ready);
if (req->error) {
err = req->error;
goto out;
}
err = -EPROTO;
if (req->reply_type != expect_type && req->reply_type != SSH_FXP_STATUS) {
fprintf(stderr, "protocol error\n");
@@ -924,6 +1051,10 @@ static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
int err;
struct buffer buf;
struct buffer name;
if (server_version < 3)
return -EPERM;
buf_init(&buf, 0);
buf_add_path(&buf, path);
err = sftp_request(SSH_FXP_READLINK, &buf, SSH_FXP_NAME, &name);
@@ -1022,6 +1153,10 @@ static int sshfs_symlink(const char *from, const char *to)
{
int err;
struct buffer buf;
if (server_version < 3)
return -EPERM;
/* 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);
@@ -1099,9 +1234,26 @@ static int sshfs_truncate(const char *path, off_t size)
struct buffer buf;
buf_init(&buf, 0);
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 (size == 0) {
/* If size is zero, use open(..., O_TRUNC), to work around
broken sftp servers */
struct buffer handle;
buf_add_uint32(&buf, SSH_FXF_WRITE | SSH_FXF_TRUNC);
buf_add_uint32(&buf, 0);
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, 0, NULL);
if (!err)
err = err2;
buf_free(&handle);
}
} else {
buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE);
buf_add_uint64(&buf, size);
err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL);
}
buf_free(&buf);
return err;
}
@@ -1120,6 +1272,11 @@ static int sshfs_utime(const char *path, struct utimbuf *ubuf)
return err;
}
static inline int sshfs_file_is_conn(struct sshfs_file *sf)
{
return sf->connver == connver;
}
static int sshfs_open(const char *path, struct fuse_file_info *fi)
{
int err;
@@ -1141,6 +1298,7 @@ static int sshfs_open(const char *path, struct fuse_file_info *fi)
/* Assume random read after open */
sf->is_seq = 0;
sf->next_pos = 0;
sf->connver = connver;
buf_init(&buf, 0);
buf_add_path(&buf, path);
buf_add_uint32(&buf, pflags);
@@ -1162,6 +1320,9 @@ static int sshfs_flush(const char *path, struct fuse_file_info *fi)
struct list_head write_reqs;
struct list_head *curr_list;
if (!sshfs_file_is_conn(sf))
return -EIO;
if (sync_write)
return 0;
@@ -1192,8 +1353,10 @@ static int sshfs_release(const char *path, struct fuse_file_info *fi)
{
struct sshfs_file *sf = (struct sshfs_file *) fi->fh;
struct buffer *handle = &sf->handle;
sshfs_flush(path, fi);
sftp_request(SSH_FXP_CLOSE, handle, 0, NULL);
if (sshfs_file_is_conn(sf)) {
sshfs_flush(path, fi);
sftp_request(SSH_FXP_CLOSE, handle, 0, NULL);
}
buf_free(handle);
chunk_put_locked(sf->readahead);
g_free(sf);
@@ -1233,7 +1396,9 @@ static int sshfs_sync_read(struct sshfs_file *sf, char *rbuf, size_t size,
static void sshfs_read_end(struct request *req)
{
struct read_chunk *chunk = (struct read_chunk *) req->data;
if (req->replied) {
if (req->error)
chunk->res = req->error;
else if (req->replied) {
chunk->res = -EPROTO;
if (req->reply_type == SSH_FXP_STATUS) {
@@ -1259,8 +1424,9 @@ static void sshfs_read_end(struct request *req)
chunk->res = -EIO;
sem_post(&chunk->ready);
chunk_put_locked(chunk);
chunk_put(chunk);
}
static void sshfs_read_begin(struct request *req)
{
struct read_chunk *chunk = (struct read_chunk *) req->data;
@@ -1390,6 +1556,10 @@ static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset,
{
struct sshfs_file *sf = (struct sshfs_file *) fi->fh;
(void) path;
if (!sshfs_file_is_conn(sf))
return -EIO;
if (sync_read)
return sshfs_sync_read(sf, rbuf, size, offset);
else
@@ -1409,8 +1579,9 @@ static void sshfs_write_end(struct request *req)
uint32_t serr;
struct sshfs_file *sf = (struct sshfs_file *) req->data;
pthread_mutex_lock(&lock);
if (req->replied) {
if (req->error)
sf->write_error = req->error;
else if (req->replied) {
if (req->reply_type != SSH_FXP_STATUS)
fprintf(stderr, "protocol error\n");
else if (buf_get_uint32(&req->reply, &serr) != -1 && serr != SSH_FX_OK)
@@ -1418,7 +1589,6 @@ static void sshfs_write_end(struct request *req)
}
list_del(&req->list);
pthread_cond_broadcast(&sf->write_finished);
pthread_mutex_unlock(&lock);
}
static int sshfs_write(const char *path, const char *wbuf, size_t size,
@@ -1431,6 +1601,10 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size,
struct buffer *handle = &sf->handle;
(void) path;
if (!sshfs_file_is_conn(sf))
return -EIO;
data.p = (uint8_t *) wbuf;
data.len = size;
buf_init(&buf, 0);
@@ -1446,36 +1620,6 @@ static int sshfs_write(const char *path, const char *wbuf, size_t size,
return err ? err : (int) size;
}
static int sftp_init()
{
int res = -1;
uint8_t type;
uint32_t version;
struct buffer buf;
buf_init(&buf, 4);
buf_add_uint32(&buf, PROTO_VERSION);
if (sftp_send(SSH_FXP_INIT, &buf) == -1)
goto out;
buf_clear(&buf);
if (sftp_read(&type, &buf) == -1)
goto out;
if (type != SSH_FXP_VERSION) {
fprintf(stderr, "protocol error\n");
goto out;
}
if (buf_get_uint32(&buf, &version) == -1)
goto out;
if (version != PROTO_VERSION) {
fprintf(stderr, "server version: %i, we need: %i\n",
version, PROTO_VERSION);
goto out;
}
res = 0;
out:
buf_free(&buf);
return res;
}
static int processing_init(void)
{
pthread_mutex_init(&lock, NULL);
@@ -1489,6 +1633,9 @@ static int processing_init(void)
static struct fuse_cache_operations sshfs_oper = {
.oper = {
#if FUSE_VERSION >= 23
.init = sshfs_init,
#endif
.getattr = sshfs_getattr,
.readlink = sshfs_readlink,
.mknod = sshfs_mknod,
@@ -1522,6 +1669,7 @@ static void usage(const char *progname)
" -V show version information\n"
" -p PORT equivalent to '-o port=PORT'\n"
" -C equivalent to '-o compression=yes'\n"
" -o reconnect reconnect to server\n"
" -o sshfs_sync synchronous writes\n"
" -o no_readahead synchronous reads (no speculative readahead)\n"
" -o sshfs_debug print some debugging information\n"
@@ -1538,7 +1686,6 @@ static void usage(const char *progname)
int main(int argc, char *argv[])
{
char *host = NULL;
char *fsname;
int res;
int argctr;
@@ -1614,6 +1761,8 @@ int main(int argc, char *argv[])
sync_read = 1;
if (sshfs_opts[SOPT_DEBUG].present)
debug = 1;
if (sshfs_opts[SOPT_RECONNECT].present)
reconnect = 1;
if (sshfs_opts[SOPT_MAX_READ].present) {
unsigned val;
if (opt_get_unsigned(&sshfs_opts[SOPT_MAX_READ], &val) == -1)
@@ -1631,7 +1780,6 @@ int main(int argc, char *argv[])
if (res == -1)
exit(1);
g_free(host);
res = sftp_init();
if (res == -1)
exit(1);