*** empty log message ***

This commit is contained in:
Miklos Szeredi 2004-12-04 21:20:50 +00:00
parent b3483b6bb9
commit 7fb3a02ec5
5 changed files with 179 additions and 45 deletions

View File

@ -0,0 +1 @@
Miklos Szeredi <miklos@szeredi.hu>

View File

@ -0,0 +1,3 @@
2004-12-04 Miklos Szeredi <miklos@szeredi.hu>
* Started ChangeLog

4
NEWS
View File

@ -0,0 +1,4 @@
What is new in 1.0
------------------
* Initial release

62
README
View File

@ -0,0 +1,62 @@
Abstract
========
This is a filesystem client based on the SSH File Transfer Protocol.
Since most SSH servers already support this protocol it is very easy
to set up: i.e. on the server side there's nothing to do. On the
client side mounting the filesystem is as easy as logging into the
server with ssh.
The idea of sshfs was taken from the SSHFS filesystem distributed with
LUFS, which I found very useful. There were some limitations of that
codebase, so I rewrote it. Features of this implementation are:
- Based on FUSE (the best userspace filesystem framework for linux ;)
- Multithreading: more than one request can be on it's way to the
server
- Allowing large reads (max 64k)
- Caching directory contents
How to mount a filesystem
=========================
Once sshfs is installed (see next section) running it is very simple:
sshfs hostname: /mountpoint
Note, that it's recommended to run it as user, not as root. For this
to work the mountpoint must be owned by the user. If the username is
different on the host you are connecting to, then use the
"username@host:" form. If you need to enter a password sshfs will ask
for it (actually it just runs ssh which ask for the password if
needed). You can also specify a directory after the ":". The default
is the home directory.
Installing
==========
First you need to download FUSE 2.2 or later from:
http://fuse.sourceforge.net
After installing FUSE, compile sshfs the usual way:
./configure
make
make install (as root)
And you are ready to go.
Bugs and feature requests
=========================
Send bug reports to <miklos@szeredi.hu>.
Good luck!
Miklos Szeredi

154
sshfs.c
View File

@ -1,3 +1,11 @@
/*
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>
@ -78,6 +86,7 @@
static int infd;
static int outfd;
static int debug = 0;
static char *base_path;
struct buffer {
uint8_t *p;
@ -152,7 +161,7 @@ static const char *type_name(uint8_t type)
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
@ -240,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) {
@ -380,7 +396,7 @@ static void cache_clean(void)
static struct node *cache_lookup(const char *path)
{
return g_hash_table_lookup(cache, path);
return (struct node *) g_hash_table_lookup(cache, path);
}
static void cache_remove(const char *path)
@ -447,7 +463,7 @@ static int buf_get_entries(struct buffer *buf, fuse_dirh_t h,
if (buf_get_attrs(buf, &stbuf) != -1) {
char *fullpath;
filler(h, name, stbuf.st_mode >> 12, 0);
fullpath = g_strdup_printf("%s/%s", path, name);
fullpath = g_strdup_printf("%s/%s", !path[1] ? "" : path, name);
cache_add_attr(fullpath, &stbuf);
g_free(fullpath);
err = 0;
@ -460,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];
@ -487,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]);
@ -495,18 +511,12 @@ static int start_ssh(const char *host)
return 0;
}
static int connect_to(char *host)
static int connect_to(char *host, char *port)
{
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;
@ -636,7 +646,7 @@ static void *process_requests(void *_data)
break;
pthread_mutex_lock(&lock);
req = g_hash_table_lookup(reqtab, (gpointer) id);
req = (struct request *) g_hash_table_lookup(reqtab, (gpointer) id);
if (req == NULL)
fprintf(stderr, "request %i not found\n", id);
else
@ -772,7 +782,7 @@ static int sshfs_send_getattr(const char *path, struct stat *stbuf)
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)
@ -809,7 +819,7 @@ static int sshfs_readlink(const char *path, char *linkbuf, size_t size)
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;
@ -834,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;
@ -865,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);
@ -883,7 +893,7 @@ static int sshfs_mknod(const char *path, mode_t mode, dev_t rdev)
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);
@ -908,7 +918,7 @@ static int sshfs_symlink(const char *from, const char *to)
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;
@ -919,7 +929,7 @@ 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);
@ -932,7 +942,7 @@ 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);
@ -945,8 +955,8 @@ 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);
@ -959,7 +969,7 @@ 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);
@ -974,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);
@ -988,7 +998,7 @@ 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);
@ -1004,7 +1014,7 @@ static int sshfs_utime(const char *path, struct utimbuf *ubuf)
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);
@ -1032,7 +1042,7 @@ static int sshfs_open(const char *path, struct fuse_file_info *fi)
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);
@ -1168,27 +1178,85 @@ static struct fuse_operations sshfs_oper = {
.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;
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[:port] 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];
if (host[0] == '+')
res = connect_to(host+1);
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
res = start_ssh(host);
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);
@ -1197,11 +1265,7 @@ int main(int argc, char *argv[])
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++] = "-omax_read=65536";
newargv[argctr] = NULL;
return fuse_main(argctr, newargv, &sshfs_oper);
newargv[newargc++] = "-omax_read=65536";
newargv[newargc] = NULL;
return fuse_main(newargc, newargv, &sshfs_oper);
}