From 7fb3a02ec51a8df16bd79d05d277310e0f5bfbee Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Sat, 4 Dec 2004 21:20:50 +0000 Subject: [PATCH] *** empty log message *** --- AUTHORS | 1 + ChangeLog | 3 ++ NEWS | 4 ++ README | 62 ++++++++++++++++++++++ sshfs.c | 156 ++++++++++++++++++++++++++++++++++++++---------------- 5 files changed, 180 insertions(+), 46 deletions(-) diff --git a/AUTHORS b/AUTHORS index e69de29b..221392d9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -0,0 +1 @@ +Miklos Szeredi diff --git a/ChangeLog b/ChangeLog index e69de29b..40354aa2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -0,0 +1,3 @@ +2004-12-04 Miklos Szeredi + + * Started ChangeLog diff --git a/NEWS b/NEWS index e69de29b..5d9d5032 100644 --- a/NEWS +++ b/NEWS @@ -0,0 +1,4 @@ +What is new in 1.0 +------------------ + +* Initial release diff --git a/README b/README index e69de29b..6905b854 100644 --- a/README +++ b/README @@ -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 . + +Good luck! +Miklos Szeredi diff --git a/sshfs.c b/sshfs.c index fce536c7..a2d1671d 100644 --- a/sshfs.c +++ b/sshfs.c @@ -1,3 +1,11 @@ +/* + SSH file system + Copyright (C) 2004 Miklos Szeredi + + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. +*/ + #define FUSE_USE_VERSION 22 #include #include @@ -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; - - if (argc < 3) { - fprintf(stderr, "usage: %s [+][user@]host[:port] mountpoint [mount options]\n", - argv[0]); + int direct = 0; + int newargc = 0; + char **newargv = (char **) malloc((argc + 10) * sizeof(char *)); + newargv[newargc++] = 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); }