From 37b408459af343a4b7bff9f05eca8e110204eb47 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 10 Dec 2007 18:21:52 +0000 Subject: change indenting --- ChangeLog | 6 + cache.c | 697 ++++++----- sshfs.c | 3942 +++++++++++++++++++++++++++++----------------------------- sshnodelay.c | 16 +- 4 files changed, 2365 insertions(+), 2296 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2ebc2a0..2080999 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-12-10 Miklos Szeredi u + + * Add subtype support with libfuse >= 2.7.0 + + * Abort on allocation failure instead of exit + 2007-05-16 Miklos Szeredi * Released 1.8 diff --git a/cache.c b/cache.c index ab378a3..8908835 100644 --- a/cache.c +++ b/cache.c @@ -1,9 +1,9 @@ /* - Caching file system proxy - Copyright (C) 2004 Miklos Szeredi + Caching file system proxy + Copyright (C) 2004 Miklos Szeredi - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. */ #include "cache.h" @@ -20,438 +20,440 @@ #define CACHE_CLEAN_INTERVAL 60 struct cache { - int on; - unsigned stat_timeout; - unsigned dir_timeout; - unsigned link_timeout; - struct fuse_cache_operations *next_oper; - GHashTable *table; - pthread_mutex_t lock; - time_t last_cleaned; + int on; + unsigned stat_timeout; + unsigned dir_timeout; + unsigned link_timeout; + struct fuse_cache_operations *next_oper; + GHashTable *table; + pthread_mutex_t lock; + time_t last_cleaned; }; static struct cache cache; struct node { - struct stat stat; - time_t stat_valid; - char **dir; - time_t dir_valid; - char *link; - time_t link_valid; - time_t valid; + struct stat stat; + time_t stat_valid; + char **dir; + time_t dir_valid; + char *link; + time_t link_valid; + time_t valid; }; struct fuse_cache_dirhandle { - const char *path; - fuse_dirh_t h; - fuse_dirfil_t filler; - GPtrArray *dir; + const char *path; + fuse_dirh_t h; + fuse_dirfil_t filler; + GPtrArray *dir; }; static void free_node(gpointer node_) { - struct node *node = (struct node *) node_; - g_strfreev(node->dir); - g_free(node); + struct node *node = (struct node *) node_; + g_strfreev(node->dir); + g_free(node); } static int cache_clean_entry(void *key_, struct node *node, time_t *now) { - (void) key_; - if (*now > node->valid) - return TRUE; - else - return FALSE; + (void) key_; + if (*now > node->valid) + return TRUE; + else + return FALSE; } static void cache_clean(void) { - time_t now = time(NULL); - if (now > cache.last_cleaned + MIN_CACHE_CLEAN_INTERVAL && - (g_hash_table_size(cache.table) > MAX_CACHE_SIZE || - now > cache.last_cleaned + CACHE_CLEAN_INTERVAL)) { - g_hash_table_foreach_remove(cache.table, - (GHRFunc) cache_clean_entry, &now); - cache.last_cleaned = now; - } + time_t now = time(NULL); + if (now > cache.last_cleaned + MIN_CACHE_CLEAN_INTERVAL && + (g_hash_table_size(cache.table) > MAX_CACHE_SIZE || + now > cache.last_cleaned + CACHE_CLEAN_INTERVAL)) { + g_hash_table_foreach_remove(cache.table, + (GHRFunc) cache_clean_entry, &now); + cache.last_cleaned = now; + } } static struct node *cache_lookup(const char *path) { - return (struct node *) g_hash_table_lookup(cache.table, path); + return (struct node *) g_hash_table_lookup(cache.table, path); } static void cache_purge(const char *path) { - g_hash_table_remove(cache.table, path); + g_hash_table_remove(cache.table, path); } static void cache_purge_parent(const char *path) { - const char *s = strrchr(path, '/'); - if (s) { - if (s == path) - g_hash_table_remove(cache.table, "/"); - else { - char *parent = g_strndup(path, s - path); - cache_purge(parent); - g_free(parent); - } - } + const char *s = strrchr(path, '/'); + if (s) { + if (s == path) + g_hash_table_remove(cache.table, "/"); + else { + char *parent = g_strndup(path, s - path); + cache_purge(parent); + g_free(parent); + } + } } void cache_invalidate(const char *path) { - pthread_mutex_lock(&cache.lock); - cache_purge(path); - pthread_mutex_unlock(&cache.lock); + pthread_mutex_lock(&cache.lock); + cache_purge(path); + pthread_mutex_unlock(&cache.lock); } static void cache_invalidate_dir(const char *path) { - pthread_mutex_lock(&cache.lock); - cache_purge(path); - cache_purge_parent(path); - pthread_mutex_unlock(&cache.lock); + pthread_mutex_lock(&cache.lock); + cache_purge(path); + cache_purge_parent(path); + pthread_mutex_unlock(&cache.lock); } static int cache_del_children(const char *key, void *val_, const char *path) { - (void) val_; - if (strncmp(key, path, strlen(path)) == 0) - return TRUE; - else - return FALSE; + (void) val_; + if (strncmp(key, path, strlen(path)) == 0) + return TRUE; + else + return FALSE; } static void cache_do_rename(const char *from, const char *to) { - pthread_mutex_lock(&cache.lock); - g_hash_table_foreach_remove(cache.table, (GHRFunc) cache_del_children, - (char *) from); - cache_purge(from); - cache_purge(to); - cache_purge_parent(from); - cache_purge_parent(to); - pthread_mutex_unlock(&cache.lock); + pthread_mutex_lock(&cache.lock); + g_hash_table_foreach_remove(cache.table, (GHRFunc) cache_del_children, + (char *) from); + cache_purge(from); + cache_purge(to); + cache_purge_parent(from); + cache_purge_parent(to); + pthread_mutex_unlock(&cache.lock); } 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.table, pathcopy, node); - } - return node; + 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.table, pathcopy, node); + } + return node; } void cache_add_attr(const char *path, const struct stat *stbuf) { - struct node *node; - time_t now; + struct node *node; + time_t now; - pthread_mutex_lock(&cache.lock); - node = cache_get(path); - now = time(NULL); - node->stat = *stbuf; - node->stat_valid = time(NULL) + cache.stat_timeout; - if (node->stat_valid > node->valid) - node->valid = node->stat_valid; - cache_clean(); - pthread_mutex_unlock(&cache.lock); + pthread_mutex_lock(&cache.lock); + node = cache_get(path); + now = time(NULL); + node->stat = *stbuf; + node->stat_valid = time(NULL) + cache.stat_timeout; + if (node->stat_valid > node->valid) + node->valid = node->stat_valid; + cache_clean(); + pthread_mutex_unlock(&cache.lock); } static void cache_add_dir(const char *path, char **dir) { - struct node *node; - time_t now; + struct node *node; + time_t now; - pthread_mutex_lock(&cache.lock); - node = cache_get(path); - now = time(NULL); - g_strfreev(node->dir); - node->dir = dir; - node->dir_valid = time(NULL) + cache.dir_timeout; - if (node->dir_valid > node->valid) - node->valid = node->dir_valid; - cache_clean(); - pthread_mutex_unlock(&cache.lock); + pthread_mutex_lock(&cache.lock); + node = cache_get(path); + now = time(NULL); + g_strfreev(node->dir); + node->dir = dir; + node->dir_valid = time(NULL) + cache.dir_timeout; + if (node->dir_valid > node->valid) + node->valid = node->dir_valid; + cache_clean(); + pthread_mutex_unlock(&cache.lock); } static size_t my_strnlen(const char *s, size_t maxsize) { - const char *p; - for (p = s; maxsize && *p; maxsize--, p++); - return p - s; + const char *p; + for (p = s; maxsize && *p; maxsize--, p++); + return p - s; } static void cache_add_link(const char *path, const char *link, size_t size) { - struct node *node; - time_t now; + struct node *node; + time_t now; - pthread_mutex_lock(&cache.lock); - node = cache_get(path); - now = time(NULL); - g_free(node->link); - node->link = g_strndup(link, my_strnlen(link, size-1)); - node->link_valid = time(NULL) + cache.link_timeout; - if (node->link_valid > node->valid) - node->valid = node->link_valid; - cache_clean(); - pthread_mutex_unlock(&cache.lock); + pthread_mutex_lock(&cache.lock); + node = cache_get(path); + now = time(NULL); + g_free(node->link); + node->link = g_strndup(link, my_strnlen(link, size-1)); + node->link_valid = time(NULL) + cache.link_timeout; + if (node->link_valid > node->valid) + node->valid = node->link_valid; + cache_clean(); + pthread_mutex_unlock(&cache.lock); } static int cache_get_attr(const char *path, struct stat *stbuf) { - struct node *node; - int err = -EAGAIN; - pthread_mutex_lock(&cache.lock); - node = cache_lookup(path); - if (node != NULL) { - time_t now = time(NULL); - if (node->stat_valid - now >= 0) { - *stbuf = node->stat; - err = 0; - } - } - pthread_mutex_unlock(&cache.lock); - return err; + struct node *node; + int err = -EAGAIN; + pthread_mutex_lock(&cache.lock); + node = cache_lookup(path); + if (node != NULL) { + time_t now = time(NULL); + if (node->stat_valid - now >= 0) { + *stbuf = node->stat; + err = 0; + } + } + pthread_mutex_unlock(&cache.lock); + return err; } static int cache_getattr(const char *path, struct stat *stbuf) { - int err = cache_get_attr(path, stbuf); - if (err) { - err = cache.next_oper->oper.getattr(path, stbuf); - if (!err) - cache_add_attr(path, stbuf); - } - return err; + int err = cache_get_attr(path, stbuf); + if (err) { + err = cache.next_oper->oper.getattr(path, stbuf); + if (!err) + cache_add_attr(path, stbuf); + } + return err; } static int cache_readlink(const char *path, char *buf, size_t size) { - struct node *node; - int err; + struct node *node; + int err; - pthread_mutex_lock(&cache.lock); - node = cache_lookup(path); - if (node != NULL) { - time_t now = time(NULL); - if (node->link_valid - now >= 0) { - strncpy(buf, node->link, size-1); - buf[size-1] = '\0'; - pthread_mutex_unlock(&cache.lock); - return 0; - } - } - pthread_mutex_unlock(&cache.lock); - err = cache.next_oper->oper.readlink(path, buf, size); - if (!err) - cache_add_link(path, buf, size); + pthread_mutex_lock(&cache.lock); + node = cache_lookup(path); + if (node != NULL) { + time_t now = time(NULL); + if (node->link_valid - now >= 0) { + strncpy(buf, node->link, size-1); + buf[size-1] = '\0'; + pthread_mutex_unlock(&cache.lock); + return 0; + } + } + pthread_mutex_unlock(&cache.lock); + err = cache.next_oper->oper.readlink(path, buf, size); + if (!err) + cache_add_link(path, buf, size); - return err; + return err; } static int cache_dirfill(fuse_cache_dirh_t ch, const char *name, const struct stat *stbuf) { - int err = ch->filler(ch->h, name, 0, 0); - if (!err) { - g_ptr_array_add(ch->dir, g_strdup(name)); - if (stbuf->st_mode & S_IFMT) { - char *fullpath = - g_strdup_printf("%s/%s", !ch->path[1] ? "" : ch->path, name); - cache_add_attr(fullpath, stbuf); - g_free(fullpath); - } - } - return err; + int err = ch->filler(ch->h, name, 0, 0); + if (!err) { + g_ptr_array_add(ch->dir, g_strdup(name)); + if (stbuf->st_mode & S_IFMT) { + char *fullpath; + const char *basepath = !ch->path[1] ? "" : ch->path; + + fullpath = g_strdup_printf("%s/%s", basepath, name); + cache_add_attr(fullpath, stbuf); + g_free(fullpath); + } + } + return err; } static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) { - struct fuse_cache_dirhandle ch; - int err; - char **dir; - struct node *node; - - pthread_mutex_lock(&cache.lock); - node = cache_lookup(path); - if (node != NULL && node->dir != NULL) { - time_t now = time(NULL); - if (node->dir_valid - now >= 0) { - for(dir = node->dir; *dir != NULL; dir++) - filler(h, *dir, 0, 0); - pthread_mutex_unlock(&cache.lock); - return 0; - } - } - pthread_mutex_unlock(&cache.lock); - - ch.path = path; - ch.h = h; - ch.filler = filler; - ch.dir = g_ptr_array_new(); - err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill); - g_ptr_array_add(ch.dir, NULL); - dir = (char **) ch.dir->pdata; - if (!err) - cache_add_dir(path, dir); - else - g_strfreev(dir); - g_ptr_array_free(ch.dir, FALSE); - return err; + struct fuse_cache_dirhandle ch; + int err; + char **dir; + struct node *node; + + pthread_mutex_lock(&cache.lock); + node = cache_lookup(path); + if (node != NULL && node->dir != NULL) { + time_t now = time(NULL); + if (node->dir_valid - now >= 0) { + for(dir = node->dir; *dir != NULL; dir++) + filler(h, *dir, 0, 0); + pthread_mutex_unlock(&cache.lock); + return 0; + } + } + pthread_mutex_unlock(&cache.lock); + + ch.path = path; + ch.h = h; + ch.filler = filler; + ch.dir = g_ptr_array_new(); + err = cache.next_oper->cache_getdir(path, &ch, cache_dirfill); + g_ptr_array_add(ch.dir, NULL); + dir = (char **) ch.dir->pdata; + if (!err) + cache_add_dir(path, dir); + else + g_strfreev(dir); + g_ptr_array_free(ch.dir, FALSE); + return err; } static int cache_unity_dirfill(fuse_cache_dirh_t ch, const char *name, const struct stat *stbuf) { - (void) stbuf; - return ch->filler(ch->h, name, 0, 0); + (void) stbuf; + return ch->filler(ch->h, name, 0, 0); } static int cache_unity_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler) { - struct fuse_cache_dirhandle ch; - ch.h = h; - ch.filler = filler; - return cache.next_oper->cache_getdir(path, &ch, cache_unity_dirfill); + struct fuse_cache_dirhandle ch; + ch.h = h; + ch.filler = filler; + return cache.next_oper->cache_getdir(path, &ch, cache_unity_dirfill); } static int cache_mknod(const char *path, mode_t mode, dev_t rdev) { - int err = cache.next_oper->oper.mknod(path, mode, rdev); - if (!err) - cache_invalidate_dir(path); - return err; + int err = cache.next_oper->oper.mknod(path, mode, rdev); + if (!err) + cache_invalidate_dir(path); + return err; } static int cache_mkdir(const char *path, mode_t mode) { - int err = cache.next_oper->oper.mkdir(path, mode); - if (!err) - cache_invalidate_dir(path); - return err; + int err = cache.next_oper->oper.mkdir(path, mode); + if (!err) + cache_invalidate_dir(path); + return err; } static int cache_unlink(const char *path) { - int err = cache.next_oper->oper.unlink(path); - if (!err) - cache_invalidate_dir(path); - return err; + int err = cache.next_oper->oper.unlink(path); + if (!err) + cache_invalidate_dir(path); + return err; } static int cache_rmdir(const char *path) { - int err = cache.next_oper->oper.rmdir(path); - if (!err) - cache_invalidate_dir(path); - return err; + int err = cache.next_oper->oper.rmdir(path); + if (!err) + cache_invalidate_dir(path); + return err; } static int cache_symlink(const char *from, const char *to) { - int err = cache.next_oper->oper.symlink(from, to); - if (!err) - cache_invalidate_dir(to); - return err; + int err = cache.next_oper->oper.symlink(from, to); + if (!err) + cache_invalidate_dir(to); + return err; } static int cache_rename(const char *from, const char *to) { - int err = cache.next_oper->oper.rename(from, to); - if (!err) - cache_do_rename(from, to); - return err; + int err = cache.next_oper->oper.rename(from, to); + if (!err) + cache_do_rename(from, to); + return err; } static int cache_link(const char *from, const char *to) { - int err = cache.next_oper->oper.link(from, to); - if (!err) { - cache_invalidate(from); - cache_invalidate_dir(to); - } - return err; + int err = cache.next_oper->oper.link(from, to); + if (!err) { + cache_invalidate(from); + cache_invalidate_dir(to); + } + return err; } static int cache_chmod(const char *path, mode_t mode) { - int err = cache.next_oper->oper.chmod(path, mode); - if (!err) - cache_invalidate(path); - return err; + int err = cache.next_oper->oper.chmod(path, mode); + if (!err) + cache_invalidate(path); + return err; } static int cache_chown(const char *path, uid_t uid, gid_t gid) { - int err = cache.next_oper->oper.chown(path, uid, gid); - if (!err) - cache_invalidate(path); - return err; + int err = cache.next_oper->oper.chown(path, uid, gid); + if (!err) + cache_invalidate(path); + return err; } static int cache_truncate(const char *path, off_t size) { - int err = cache.next_oper->oper.truncate(path, size); - if (!err) - cache_invalidate(path); - return err; + int err = cache.next_oper->oper.truncate(path, size); + if (!err) + cache_invalidate(path); + return err; } static int cache_utime(const char *path, struct utimbuf *buf) { - int err = cache.next_oper->oper.utime(path, buf); - if (!err) - cache_invalidate(path); - return err; + int err = cache.next_oper->oper.utime(path, buf); + if (!err) + cache_invalidate(path); + return err; } static int cache_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { - int res = cache.next_oper->oper.write(path, buf, size, offset, fi); - if (res >= 0) - cache_invalidate(path); - return res; + int res = cache.next_oper->oper.write(path, buf, size, offset, fi); + if (res >= 0) + cache_invalidate(path); + return res; } #if FUSE_VERSION >= 25 static int cache_create(const char *path, mode_t mode, struct fuse_file_info *fi) { - int err = cache.next_oper->oper.create(path, mode, fi); - if (!err) - cache_invalidate_dir(path); - return err; + int err = cache.next_oper->oper.create(path, mode, fi); + if (!err) + cache_invalidate_dir(path); + return err; } static int cache_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) { - int err = cache.next_oper->oper.ftruncate(path, size, fi); - if (!err) - cache_invalidate(path); - return err; + int err = cache.next_oper->oper.ftruncate(path, size, fi); + if (!err) + cache_invalidate(path); + return err; } static int cache_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { - int err = cache_get_attr(path, stbuf); - if (err) { - err = cache.next_oper->oper.fgetattr(path, stbuf, fi); - if (!err) - cache_add_attr(path, stbuf); - } - return err; + int err = cache_get_attr(path, stbuf); + if (err) { + err = cache.next_oper->oper.fgetattr(path, stbuf, fi); + if (!err) + cache_add_attr(path, stbuf); + } + return err; } #endif @@ -459,96 +461,103 @@ 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; + 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; - cache_oper->mknod = oper->oper.mknod; - cache_oper->mkdir = oper->oper.mkdir; - cache_oper->symlink = oper->oper.symlink; - cache_oper->unlink = oper->oper.unlink; - cache_oper->rmdir = oper->oper.rmdir; - cache_oper->rename = oper->oper.rename; - cache_oper->link = oper->oper.link; - cache_oper->chmod = oper->oper.chmod; - cache_oper->chown = oper->oper.chown; - cache_oper->truncate = oper->oper.truncate; - cache_oper->utime = oper->oper.utime; - cache_oper->open = oper->oper.open; - cache_oper->read = oper->oper.read; - cache_oper->write = oper->oper.write; - cache_oper->flush = oper->oper.flush; - cache_oper->release = oper->oper.release; - cache_oper->fsync = oper->oper.fsync; - cache_oper->statfs = oper->oper.statfs; - cache_oper->setxattr = oper->oper.setxattr; - cache_oper->getxattr = oper->oper.getxattr; - cache_oper->listxattr = oper->oper.listxattr; - cache_oper->removexattr = oper->oper.removexattr; + cache_oper->getattr = oper->oper.getattr; + cache_oper->readlink = oper->oper.readlink; + cache_oper->getdir = cache_unity_getdir; + cache_oper->mknod = oper->oper.mknod; + cache_oper->mkdir = oper->oper.mkdir; + cache_oper->symlink = oper->oper.symlink; + cache_oper->unlink = oper->oper.unlink; + cache_oper->rmdir = oper->oper.rmdir; + cache_oper->rename = oper->oper.rename; + cache_oper->link = oper->oper.link; + cache_oper->chmod = oper->oper.chmod; + cache_oper->chown = oper->oper.chown; + cache_oper->truncate = oper->oper.truncate; + cache_oper->utime = oper->oper.utime; + cache_oper->open = oper->oper.open; + cache_oper->read = oper->oper.read; + cache_oper->write = oper->oper.write; + cache_oper->flush = oper->oper.flush; + cache_oper->release = oper->oper.release; + cache_oper->fsync = oper->oper.fsync; + cache_oper->statfs = oper->oper.statfs; + cache_oper->setxattr = oper->oper.setxattr; + cache_oper->getxattr = oper->oper.getxattr; + cache_oper->listxattr = oper->oper.listxattr; + cache_oper->removexattr = oper->oper.removexattr; #if FUSE_VERSION >= 25 - cache_oper->create = oper->oper.create; - cache_oper->ftruncate = oper->oper.ftruncate; - cache_oper->fgetattr = oper->oper.fgetattr; + cache_oper->create = oper->oper.create; + cache_oper->ftruncate = oper->oper.ftruncate; + cache_oper->fgetattr = oper->oper.fgetattr; #endif } -struct fuse_operations *cache_init(struct fuse_cache_operations *oper) -{ - static struct fuse_operations cache_oper; - cache.next_oper = oper; - - cache_unity_fill(oper, &cache_oper); - if (cache.on) { - cache_oper.getattr = oper->oper.getattr ? cache_getattr : NULL; - cache_oper.readlink = oper->oper.readlink ? cache_readlink : NULL; - cache_oper.getdir = oper->cache_getdir ? cache_getdir : NULL; - cache_oper.mknod = oper->oper.mknod ? cache_mknod : NULL; - cache_oper.mkdir = oper->oper.mkdir ? cache_mkdir : NULL; - cache_oper.symlink = oper->oper.symlink ? cache_symlink : NULL; - cache_oper.unlink = oper->oper.unlink ? cache_unlink : NULL; - cache_oper.rmdir = oper->oper.rmdir ? cache_rmdir : NULL; - cache_oper.rename = oper->oper.rename ? cache_rename : NULL; - cache_oper.link = oper->oper.link ? cache_link : NULL; - cache_oper.chmod = oper->oper.chmod ? cache_chmod : NULL; - cache_oper.chown = oper->oper.chown ? cache_chown : NULL; - cache_oper.truncate = oper->oper.truncate ? cache_truncate : NULL; - cache_oper.utime = oper->oper.utime ? cache_utime : NULL; - cache_oper.write = oper->oper.write ? cache_write : NULL; +static void cache_fill(struct fuse_cache_operations *oper, + struct fuse_operations *cache_oper) +{ + cache_oper->getattr = oper->oper.getattr ? cache_getattr : NULL; + cache_oper->readlink = oper->oper.readlink ? cache_readlink : NULL; + cache_oper->getdir = oper->cache_getdir ? cache_getdir : NULL; + cache_oper->mknod = oper->oper.mknod ? cache_mknod : NULL; + cache_oper->mkdir = oper->oper.mkdir ? cache_mkdir : NULL; + cache_oper->symlink = oper->oper.symlink ? cache_symlink : NULL; + cache_oper->unlink = oper->oper.unlink ? cache_unlink : NULL; + cache_oper->rmdir = oper->oper.rmdir ? cache_rmdir : NULL; + cache_oper->rename = oper->oper.rename ? cache_rename : NULL; + cache_oper->link = oper->oper.link ? cache_link : NULL; + cache_oper->chmod = oper->oper.chmod ? cache_chmod : NULL; + cache_oper->chown = oper->oper.chown ? cache_chown : NULL; + cache_oper->truncate = oper->oper.truncate ? cache_truncate : NULL; + cache_oper->utime = oper->oper.utime ? cache_utime : NULL; + cache_oper->write = oper->oper.write ? cache_write : NULL; #if FUSE_VERSION >= 25 - cache_oper.create = oper->oper.create ? cache_create : NULL; - cache_oper.ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL; - cache_oper.fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL; + cache_oper->create = oper->oper.create ? cache_create : NULL; + cache_oper->ftruncate = oper->oper.ftruncate ? cache_ftruncate : NULL; + cache_oper->fgetattr = oper->oper.fgetattr ? cache_fgetattr : NULL; #endif - pthread_mutex_init(&cache.lock, NULL); - cache.table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, - free_node); - if (cache.table == NULL) { - fprintf(stderr, "failed to create cache\n"); - return NULL; - } - } - return &cache_oper; + +} + +struct fuse_operations *cache_init(struct fuse_cache_operations *oper) +{ + static struct fuse_operations cache_oper; + cache.next_oper = oper; + + cache_unity_fill(oper, &cache_oper); + if (cache.on) { + cache_fill(oper, &cache_oper); + pthread_mutex_init(&cache.lock, NULL); + cache.table = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, free_node); + if (cache.table == NULL) { + fprintf(stderr, "failed to create cache\n"); + return NULL; + } + } + return &cache_oper; } static const struct fuse_opt cache_opts[] = { - { "cache=yes", offsetof(struct cache, on), 1 }, - { "cache=no", offsetof(struct cache, on), 0 }, - { "cache_timeout=%u", offsetof(struct cache, stat_timeout), 0 }, - { "cache_timeout=%u", offsetof(struct cache, dir_timeout), 0 }, - { "cache_timeout=%u", offsetof(struct cache, link_timeout), 0 }, - { "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout), 0 }, - { "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout), 0 }, - { "cache_link_timeout=%u", offsetof(struct cache, link_timeout), 0 }, - FUSE_OPT_END + { "cache=yes", offsetof(struct cache, on), 1 }, + { "cache=no", offsetof(struct cache, on), 0 }, + { "cache_timeout=%u", offsetof(struct cache, stat_timeout), 0 }, + { "cache_timeout=%u", offsetof(struct cache, dir_timeout), 0 }, + { "cache_timeout=%u", offsetof(struct cache, link_timeout), 0 }, + { "cache_stat_timeout=%u", offsetof(struct cache, stat_timeout), 0 }, + { "cache_dir_timeout=%u", offsetof(struct cache, dir_timeout), 0 }, + { "cache_link_timeout=%u", offsetof(struct cache, link_timeout), 0 }, + FUSE_OPT_END }; int cache_parse_options(struct fuse_args *args) { - cache.stat_timeout = DEFAULT_CACHE_TIMEOUT; - cache.dir_timeout = DEFAULT_CACHE_TIMEOUT; - cache.link_timeout = DEFAULT_CACHE_TIMEOUT; - cache.on = 1; + cache.stat_timeout = DEFAULT_CACHE_TIMEOUT; + cache.dir_timeout = DEFAULT_CACHE_TIMEOUT; + cache.link_timeout = DEFAULT_CACHE_TIMEOUT; + cache.on = 1; - return fuse_opt_parse(args, &cache, cache_opts, NULL); + return fuse_opt_parse(args, &cache, cache_opts, NULL); } diff --git a/sshfs.c b/sshfs.c index cc168da..305cc90 100644 --- a/sshfs.c +++ b/sshfs.c @@ -1,9 +1,9 @@ /* - SSH file system - Copyright (C) 2004 Miklos Szeredi + SSH file system + Copyright (C) 2004 Miklos Szeredi - This program can be distributed under the terms of the GNU GPL. - See the file COPYING. + This program can be distributed under the terms of the GNU GPL. + See the file COPYING. */ #include "config.h" @@ -101,269 +101,269 @@ #define SSHNODELAY_SO "sshnodelay.so" struct buffer { - uint8_t *p; - size_t len; - size_t size; + uint8_t *p; + size_t len; + size_t size; }; struct list_head { - struct list_head *prev; - struct list_head *next; + struct list_head *prev; + struct list_head *next; }; struct request; typedef void (*request_func)(struct request *); struct request { - unsigned int want_reply; - sem_t ready; - uint8_t reply_type; - int replied; - int error; - struct buffer reply; - struct timeval start; - void *data; - request_func end_func; - size_t len; - struct list_head list; + unsigned int want_reply; + sem_t ready; + uint8_t reply_type; + int replied; + int error; + struct buffer reply; + struct timeval start; + void *data; + request_func end_func; + size_t len; + struct list_head list; }; struct read_chunk { - sem_t ready; - off_t offset; - size_t size; - struct buffer data; - int refs; - int res; - long modifver; + sem_t ready; + off_t offset; + size_t size; + struct buffer data; + int refs; + int res; + long modifver; }; struct sshfs_file { - struct buffer handle; - struct list_head write_reqs; - pthread_cond_t write_finished; - int write_error; - struct read_chunk *readahead; - off_t next_pos; - int is_seq; - int connver; - int modifver; - int refs; + struct buffer handle; + struct list_head write_reqs; + pthread_cond_t write_finished; + int write_error; + struct read_chunk *readahead; + off_t next_pos; + int is_seq; + int connver; + int modifver; + int refs; }; struct sshfs { - char *directport; - char *ssh_command; - char *sftp_server; - struct fuse_args ssh_args; - char *workarounds; - int rename_workaround; - int nodelay_workaround; - int nodelaysrv_workaround; - int truncate_workaround; - int buflimit_workaround; - int transform_symlinks; - int follow_symlinks; - int no_check_root; - int detect_uid; - unsigned max_read; - unsigned ssh_ver; - int sync_write; - int sync_read; - int debug; - int reconnect; - char *host; - char *base_path; - GHashTable *reqtab; - pthread_mutex_t lock; - pthread_mutex_t lock_write; - int processing_thread_started; - unsigned int randseed; - int fd; - int connver; - int server_version; - unsigned remote_uid; - unsigned local_uid; - int remote_uid_detected; - unsigned blksize; - char *progname; - long modifver; - unsigned outstanding_len; - unsigned max_outstanding_len; - pthread_cond_t outstanding_cond; + char *directport; + char *ssh_command; + char *sftp_server; + struct fuse_args ssh_args; + char *workarounds; + int rename_workaround; + int nodelay_workaround; + int nodelaysrv_workaround; + int truncate_workaround; + int buflimit_workaround; + int transform_symlinks; + int follow_symlinks; + int no_check_root; + int detect_uid; + unsigned max_read; + unsigned ssh_ver; + int sync_write; + int sync_read; + int debug; + int reconnect; + char *host; + char *base_path; + GHashTable *reqtab; + pthread_mutex_t lock; + pthread_mutex_t lock_write; + int processing_thread_started; + unsigned int randseed; + int fd; + int connver; + int server_version; + unsigned remote_uid; + unsigned local_uid; + int remote_uid_detected; + unsigned blksize; + char *progname; + long modifver; + unsigned outstanding_len; + unsigned max_outstanding_len; + pthread_cond_t outstanding_cond; }; static struct sshfs sshfs; static const char *ssh_opts[] = { - "AddressFamily", - "BatchMode", - "BindAddress", - "ChallengeResponseAuthentication", - "CheckHostIP", - "Cipher", - "Ciphers", - "Compression", - "CompressionLevel", - "ConnectionAttempts", - "ConnectTimeout", - "GlobalKnownHostsFile", - "GSSAPIAuthentication", - "GSSAPIDelegateCredentials", - "HostbasedAuthentication", - "HostKeyAlgorithms", - "HostKeyAlias", - "HostName", - "IdentityFile", - "IdentitiesOnly", - "LogLevel", - "MACs", - "NoHostAuthenticationForLocalhost", - "NumberOfPasswordPrompts", - "PasswordAuthentication", - "Port", - "PreferredAuthentications", - "ProxyCommand", - "PubkeyAuthentication", - "RhostsRSAAuthentication", - "RSAAuthentication", - "ServerAliveInterval", - "ServerAliveCountMax", - "SmartcardDevice", - "StrictHostKeyChecking", - "TCPKeepAlive", - "UsePrivilegedPort", - "UserKnownHostsFile", - "VerifyHostKeyDNS", - NULL, + "AddressFamily", + "BatchMode", + "BindAddress", + "ChallengeResponseAuthentication", + "CheckHostIP", + "Cipher", + "Ciphers", + "Compression", + "CompressionLevel", + "ConnectionAttempts", + "ConnectTimeout", + "GlobalKnownHostsFile", + "GSSAPIAuthentication", + "GSSAPIDelegateCredentials", + "HostbasedAuthentication", + "HostKeyAlgorithms", + "HostKeyAlias", + "HostName", + "IdentityFile", + "IdentitiesOnly", + "LogLevel", + "MACs", + "NoHostAuthenticationForLocalhost", + "NumberOfPasswordPrompts", + "PasswordAuthentication", + "Port", + "PreferredAuthentications", + "ProxyCommand", + "PubkeyAuthentication", + "RhostsRSAAuthentication", + "RSAAuthentication", + "ServerAliveInterval", + "ServerAliveCountMax", + "SmartcardDevice", + "StrictHostKeyChecking", + "TCPKeepAlive", + "UsePrivilegedPort", + "UserKnownHostsFile", + "VerifyHostKeyDNS", + NULL, }; enum { - KEY_PORT, - KEY_COMPRESS, - KEY_HELP, - KEY_VERSION, + KEY_PORT, + KEY_COMPRESS, + KEY_HELP, + KEY_VERSION, }; #define SSHFS_OPT(t, p, v) { t, offsetof(struct sshfs, p), v } static struct fuse_opt sshfs_opts[] = { - SSHFS_OPT("directport=%s", directport, 0), - SSHFS_OPT("ssh_command=%s", ssh_command, 0), - SSHFS_OPT("sftp_server=%s", sftp_server, 0), - SSHFS_OPT("max_read=%u", max_read, 0), - SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0), - SSHFS_OPT("-1", ssh_ver, 1), - SSHFS_OPT("workaround=%s", workarounds, 0), - SSHFS_OPT("idmap=none", detect_uid, 0), - SSHFS_OPT("idmap=user", detect_uid, 1), - SSHFS_OPT("sshfs_sync", sync_write, 1), - SSHFS_OPT("no_readahead", sync_read, 1), - SSHFS_OPT("sshfs_debug", debug, 1), - SSHFS_OPT("reconnect", reconnect, 1), - SSHFS_OPT("transform_symlinks", transform_symlinks, 1), - SSHFS_OPT("follow_symlinks", follow_symlinks, 1), - SSHFS_OPT("no_check_root", no_check_root, 1), - - FUSE_OPT_KEY("-p ", KEY_PORT), - FUSE_OPT_KEY("-C", KEY_COMPRESS), - FUSE_OPT_KEY("-V", KEY_VERSION), - FUSE_OPT_KEY("--version", KEY_VERSION), - FUSE_OPT_KEY("-h", KEY_HELP), - FUSE_OPT_KEY("--help", KEY_HELP), - FUSE_OPT_END + SSHFS_OPT("directport=%s", directport, 0), + SSHFS_OPT("ssh_command=%s", ssh_command, 0), + SSHFS_OPT("sftp_server=%s", sftp_server, 0), + SSHFS_OPT("max_read=%u", max_read, 0), + SSHFS_OPT("ssh_protocol=%u", ssh_ver, 0), + SSHFS_OPT("-1", ssh_ver, 1), + SSHFS_OPT("workaround=%s", workarounds, 0), + SSHFS_OPT("idmap=none", detect_uid, 0), + SSHFS_OPT("idmap=user", detect_uid, 1), + SSHFS_OPT("sshfs_sync", sync_write, 1), + SSHFS_OPT("no_readahead", sync_read, 1), + SSHFS_OPT("sshfs_debug", debug, 1), + SSHFS_OPT("reconnect", reconnect, 1), + SSHFS_OPT("transform_symlinks", transform_symlinks, 1), + SSHFS_OPT("follow_symlinks", follow_symlinks, 1), + SSHFS_OPT("no_check_root", no_check_root, 1), + + FUSE_OPT_KEY("-p ", KEY_PORT), + FUSE_OPT_KEY("-C", KEY_COMPRESS), + FUSE_OPT_KEY("-V", KEY_VERSION), + FUSE_OPT_KEY("--version", KEY_VERSION), + FUSE_OPT_KEY("-h", KEY_HELP), + FUSE_OPT_KEY("--help", KEY_HELP), + FUSE_OPT_END }; static struct fuse_opt workaround_opts[] = { - SSHFS_OPT("none", rename_workaround, 0), - SSHFS_OPT("none", nodelay_workaround, 0), - SSHFS_OPT("none", nodelaysrv_workaround, 0), - SSHFS_OPT("none", truncate_workaround, 0), - SSHFS_OPT("none", buflimit_workaround, 0), - SSHFS_OPT("all", rename_workaround, 1), - SSHFS_OPT("all", nodelay_workaround, 1), - SSHFS_OPT("all", nodelaysrv_workaround, 1), - SSHFS_OPT("all", truncate_workaround, 1), - SSHFS_OPT("all", buflimit_workaround, 1), - SSHFS_OPT("rename", rename_workaround, 1), - SSHFS_OPT("norename", rename_workaround, 0), - SSHFS_OPT("nodelay", nodelay_workaround, 1), - SSHFS_OPT("nonodelay", nodelay_workaround, 0), - SSHFS_OPT("nodelaysrv", nodelaysrv_workaround, 1), - SSHFS_OPT("nonodelaysrv", nodelaysrv_workaround, 0), - SSHFS_OPT("truncate", truncate_workaround, 1), - SSHFS_OPT("notruncate", truncate_workaround, 0), - SSHFS_OPT("buflimit", buflimit_workaround, 1), - SSHFS_OPT("nobuflimit", buflimit_workaround, 0), - FUSE_OPT_END + SSHFS_OPT("none", rename_workaround, 0), + SSHFS_OPT("none", nodelay_workaround, 0), + SSHFS_OPT("none", nodelaysrv_workaround, 0), + SSHFS_OPT("none", truncate_workaround, 0), + SSHFS_OPT("none", buflimit_workaround, 0), + SSHFS_OPT("all", rename_workaround, 1), + SSHFS_OPT("all", nodelay_workaround, 1), + SSHFS_OPT("all", nodelaysrv_workaround, 1), + SSHFS_OPT("all", truncate_workaround, 1), + SSHFS_OPT("all", buflimit_workaround, 1), + SSHFS_OPT("rename", rename_workaround, 1), + SSHFS_OPT("norename", rename_workaround, 0), + SSHFS_OPT("nodelay", nodelay_workaround, 1), + SSHFS_OPT("nonodelay", nodelay_workaround, 0), + SSHFS_OPT("nodelaysrv", nodelaysrv_workaround, 1), + SSHFS_OPT("nonodelaysrv", nodelaysrv_workaround, 0), + SSHFS_OPT("truncate", truncate_workaround, 1), + SSHFS_OPT("notruncate", truncate_workaround, 0), + SSHFS_OPT("buflimit", buflimit_workaround, 1), + SSHFS_OPT("nobuflimit", buflimit_workaround, 0), + FUSE_OPT_END }; -#define DEBUG(format, args...) \ +#define DEBUG(format, args...) \ do { if (sshfs.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 "???"; - } -} - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#define list_entry(ptr, type, member) \ + 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 "???"; + } +} + +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +#define list_entry(ptr, type, member) \ container_of(ptr, type, member) static void list_init(struct list_head *head) { - head->next = head; - head->prev = head; + head->next = head; + head->prev = head; } static void list_add(struct list_head *new, struct list_head *head) { - struct list_head *prev = head; - struct list_head *next = head->next; - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; + struct list_head *prev = head; + struct list_head *next = head->next; + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; } static void list_del(struct list_head *entry) { - struct list_head *prev = entry->prev; - struct list_head *next = entry->next; - next->prev = prev; - prev->next = next; + struct list_head *prev = entry->prev; + struct list_head *next = entry->next; + next->prev = prev; + prev->next = next; } @@ -374,464 +374,479 @@ static int list_empty(const struct list_head *head) static inline void buf_init(struct buffer *buf, size_t size) { - if (size) { - buf->p = (uint8_t *) malloc(size); - if (!buf->p) { - fprintf(stderr, "sshfs: memory allocation failed\n"); - exit(1); - } - } else - buf->p = NULL; - buf->len = 0; - buf->size = size; + if (size) { + buf->p = (uint8_t *) malloc(size); + if (!buf->p) { + fprintf(stderr, "sshfs: memory allocation failed\n"); + abort(); + } + } else + buf->p = NULL; + buf->len = 0; + buf->size = size; } static inline void buf_free(struct buffer *buf) { - free(buf->p); + free(buf->p); } static inline void buf_finish(struct buffer *buf) { - buf->len = buf->size; + buf->len = buf->size; } static inline void buf_clear(struct buffer *buf) { - buf_free(buf); - buf_init(buf, 0); + buf_free(buf); + buf_init(buf, 0); } static void buf_resize(struct buffer *buf, size_t len) { - buf->size = (buf->len + len + 63) & ~31; - buf->p = (uint8_t *) realloc(buf->p, buf->size); - if (!buf->p) { - fprintf(stderr, "sshfs: memory allocation failed\n"); - exit(1); - } + buf->size = (buf->len + len + 63) & ~31; + buf->p = (uint8_t *) realloc(buf->p, buf->size); + if (!buf->p) { + fprintf(stderr, "sshfs: memory allocation failed\n"); + abort(); + } } static inline void buf_check_add(struct buffer *buf, size_t len) { - if (buf->len + len > buf->size) - buf_resize(buf, len); + if (buf->len + len > buf->size) + buf_resize(buf, len); } -#define _buf_add_mem(b, d, l) \ - buf_check_add(b, l); \ - memcpy(b->p + b->len, d, l); \ - b->len += l; +#define _buf_add_mem(b, d, l) \ + buf_check_add(b, l); \ + memcpy(b->p + b->len, d, l); \ + b->len += l; static inline void buf_add_mem(struct buffer *buf, const void *data, size_t len) { - _buf_add_mem(buf, data, len); + _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); + _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); + _buf_add_mem(buf, &val, 1); } static inline void buf_add_uint32(struct buffer *buf, uint32_t val) { - uint32_t nval = htonl(val); - _buf_add_mem(buf, &nval, 4); + uint32_t nval = htonl(val); + _buf_add_mem(buf, &nval, 4); } static inline void buf_add_uint64(struct buffer *buf, uint64_t val) { - buf_add_uint32(buf, val >> 32); - buf_add_uint32(buf, val & 0xffffffff); + buf_add_uint32(buf, val >> 32); + buf_add_uint32(buf, val & 0xffffffff); } static inline void buf_add_data(struct buffer *buf, const struct buffer *data) { - buf_add_uint32(buf, data->len); - buf_add_mem(buf, data->p, data->len); + buf_add_uint32(buf, data->len); + buf_add_mem(buf, data->p, data->len); } static inline void buf_add_string(struct buffer *buf, const char *str) { - struct buffer data; - data.p = (uint8_t *) str; - data.len = strlen(str); - buf_add_data(buf, &data); + struct buffer data; + data.p = (uint8_t *) str; + data.len = strlen(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", sshfs.base_path, path[1] ? path+1 : "."); - buf_add_string(buf, realpath); - g_free(realpath); + char *realpath; + + realpath = g_strdup_printf("%s%s", sshfs.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) { - fprintf(stderr, "buffer too short\n"); - return -1; - } else - return 0; + if (buf->len + len > buf->size) { + fprintf(stderr, "buffer too short\n"); + return -1; + } else + return 0; } static inline int buf_get_mem(struct buffer *buf, void *data, size_t len) { - if (buf_check_get(buf, len) == -1) - return -1; - memcpy(data, buf->p + buf->len, len); - buf->len += len; - return 0; + if (buf_check_get(buf, len) == -1) + return -1; + memcpy(data, buf->p + buf->len, len); + buf->len += len; + return 0; } static inline int buf_get_uint8(struct buffer *buf, uint8_t *val) { - return buf_get_mem(buf, val, 1); + return buf_get_mem(buf, val, 1); } static inline int buf_get_uint32(struct buffer *buf, uint32_t *val) { - uint32_t nval; - if (buf_get_mem(buf, &nval, 4) == -1) - return -1; - *val = ntohl(nval); - return 0; + uint32_t nval; + if (buf_get_mem(buf, &nval, 4) == -1) + return -1; + *val = ntohl(nval); + return 0; } static inline int buf_get_uint64(struct buffer *buf, uint64_t *val) { - uint32_t val1; - uint32_t val2; - if (buf_get_uint32(buf, &val1) == -1 || buf_get_uint32(buf, &val2) == -1) - return -1; - *val = ((uint64_t) val1 << 32) + val2; - return 0; + uint32_t val1; + uint32_t val2; + if (buf_get_uint32(buf, &val1) == -1 || + buf_get_uint32(buf, &val2) == -1) { + return -1; + } + *val = ((uint64_t) val1 << 32) + val2; + return 0; } static inline int buf_get_data(struct buffer *buf, struct buffer *data) { - uint32_t len; - if (buf_get_uint32(buf, &len) == -1 || len > buf->size - buf->len) - return -1; - buf_init(data, len + 1); - data->size = len; - if (buf_get_mem(buf, data->p, data->size) == -1) { - buf_free(data); - return -1; - } - return 0; + uint32_t len; + if (buf_get_uint32(buf, &len) == -1 || len > buf->size - buf->len) + return -1; + buf_init(data, len + 1); + data->size = len; + if (buf_get_mem(buf, data->p, data->size) == -1) { + buf_free(data); + return -1; + } + return 0; } static inline int buf_get_string(struct buffer *buf, char **str) { - struct buffer data; - if (buf_get_data(buf, &data) == -1) - return -1; - data.p[data.size] = '\0'; - *str = (char *) data.p; - return 0; + struct buffer data; + if (buf_get_data(buf, &data) == -1) + return -1; + data.p[data.size] = '\0'; + *str = (char *) data.p; + return 0; } static int buf_get_attrs(struct buffer *buf, struct stat *stbuf, int *flagsp) { - uint32_t flags; - uint64_t size = 0; - uint32_t uid = 0; - uint32_t gid = 0; - uint32_t atime = 0; - uint32_t mtime = 0; - uint32_t mode = S_IFREG | 0777; - - if (buf_get_uint32(buf, &flags) == -1) - return -1; - if (flagsp) - *flagsp = flags; - if ((flags & SSH_FILEXFER_ATTR_SIZE) && - buf_get_uint64(buf, &size) == -1) - return -1; - if ((flags & SSH_FILEXFER_ATTR_UIDGID) && - (buf_get_uint32(buf, &uid) == -1 || - buf_get_uint32(buf, &gid) == -1)) - return -1; - if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) && - buf_get_uint32(buf, &mode) == -1) - return -1; - if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) { - if (buf_get_uint32(buf, &atime) == -1 || - buf_get_uint32(buf, &mtime) == -1) - return -1; - } - if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) { - uint32_t extcount; - unsigned i; - if (buf_get_uint32(buf, &extcount) == -1) - return -1; - for (i = 0; i < extcount; i++) { - struct buffer tmp; - if (buf_get_data(buf, &tmp) == -1) - return -1; - buf_free(&tmp); - if (buf_get_data(buf, &tmp) == -1) - return -1; - buf_free(&tmp); - } - } - - if (sshfs.remote_uid_detected && uid == sshfs.remote_uid) - uid = sshfs.local_uid; - - memset(stbuf, 0, sizeof(struct stat)); - stbuf->st_mode = mode; - stbuf->st_nlink = 1; - stbuf->st_size = size; - if (sshfs.blksize) { - stbuf->st_blksize = sshfs.blksize; - stbuf->st_blocks = - ((size + sshfs.blksize - 1) & ~(sshfs.blksize - 1)) >> 9; - } - stbuf->st_uid = uid; - stbuf->st_gid = gid; - stbuf->st_atime = atime; - stbuf->st_mtime = mtime; - return 0; + uint32_t flags; + uint64_t size = 0; + uint32_t uid = 0; + uint32_t gid = 0; + uint32_t atime = 0; + uint32_t mtime = 0; + uint32_t mode = S_IFREG | 0777; + + if (buf_get_uint32(buf, &flags) == -1) + return -1; + if (flagsp) + *flagsp = flags; + if ((flags & SSH_FILEXFER_ATTR_SIZE) && + buf_get_uint64(buf, &size) == -1) + return -1; + if ((flags & SSH_FILEXFER_ATTR_UIDGID) && + (buf_get_uint32(buf, &uid) == -1 || + buf_get_uint32(buf, &gid) == -1)) + return -1; + if ((flags & SSH_FILEXFER_ATTR_PERMISSIONS) && + buf_get_uint32(buf, &mode) == -1) + return -1; + if ((flags & SSH_FILEXFER_ATTR_ACMODTIME)) { + if (buf_get_uint32(buf, &atime) == -1 || + buf_get_uint32(buf, &mtime) == -1) + return -1; + } + if ((flags & SSH_FILEXFER_ATTR_EXTENDED)) { + uint32_t extcount; + unsigned i; + if (buf_get_uint32(buf, &extcount) == -1) + return -1; + for (i = 0; i < extcount; i++) { + struct buffer tmp; + if (buf_get_data(buf, &tmp) == -1) + return -1; + buf_free(&tmp); + if (buf_get_data(buf, &tmp) == -1) + return -1; + buf_free(&tmp); + } + } + + if (sshfs.remote_uid_detected && uid == sshfs.remote_uid) + uid = sshfs.local_uid; + + memset(stbuf, 0, sizeof(struct stat)); + stbuf->st_mode = mode; + stbuf->st_nlink = 1; + stbuf->st_size = size; + if (sshfs.blksize) { + stbuf->st_blksize = sshfs.blksize; + stbuf->st_blocks = ((size + sshfs.blksize - 1) & + ~(sshfs.blksize - 1)) >> 9; + } + stbuf->st_uid = uid; + stbuf->st_gid = gid; + stbuf->st_atime = atime; + stbuf->st_mtime = mtime; + return 0; } static int buf_get_entries(struct buffer *buf, fuse_cache_dirh_t h, fuse_cache_dirfil_t filler) { - uint32_t count; - unsigned i; - - if (buf_get_uint32(buf, &count) == -1) - return -1; - - for (i = 0; i < count; i++) { - int err = -1; - char *name; - char *longname; - struct stat stbuf; - if (buf_get_string(buf, &name) == -1) - return -1; - if (buf_get_string(buf, &longname) != -1) { - free(longname); - if (buf_get_attrs(buf, &stbuf, NULL) != -1) { - if (sshfs.follow_symlinks && S_ISLNK(stbuf.st_mode)) - stbuf.st_mode = 0; - filler(h, name, &stbuf); - err = 0; - } - } - free(name); - if (err) - return err; - } - return 0; + uint32_t count; + unsigned i; + + if (buf_get_uint32(buf, &count) == -1) + return -1; + + for (i = 0; i < count; i++) { + int err = -1; + char *name; + char *longname; + struct stat stbuf; + if (buf_get_string(buf, &name) == -1) + return -1; + if (buf_get_string(buf, &longname) != -1) { + free(longname); + if (buf_get_attrs(buf, &stbuf, NULL) != -1) { + if (sshfs.follow_symlinks && + S_ISLNK(stbuf.st_mode)) { + stbuf.st_mode = 0; + } + filler(h, name, &stbuf); + err = 0; + } + } + free(name); + if (err) + return err; + } + return 0; } static void ssh_add_arg(const char *arg) { - if (fuse_opt_add_arg(&sshfs.ssh_args, arg) == -1) - _exit(1); + if (fuse_opt_add_arg(&sshfs.ssh_args, arg) == -1) + _exit(1); } #ifdef SSH_NODELAY_WORKAROUND static int do_ssh_nodelay_workaround(void) { - char *oldpreload = getenv("LD_PRELOAD"); - char *newpreload; - char sopath[PATH_MAX]; - int res; - - snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO); - res = access(sopath, R_OK); - if (res == -1) { - char *s; - if (!realpath(sshfs.progname, sopath)) - return -1; - - s = strrchr(sopath, '/'); - if (!s) - s = sopath; - else - s++; - - if (s + strlen(SSHNODELAY_SO) >= sopath + sizeof(sopath)) - return -1; - - strcpy(s, SSHNODELAY_SO); - res = access(sopath, R_OK); - if (res == -1) { - fprintf(stderr, "sshfs: cannot find %s\n", SSHNODELAY_SO); - return -1; - } - } - - newpreload = g_strdup_printf("%s%s%s", - oldpreload ? oldpreload : "", - oldpreload ? " " : "", - sopath); - - if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) - fprintf(stderr, "warning: failed set LD_PRELOAD for ssh nodelay workaround\n"); - g_free(newpreload); - return 0; + char *oldpreload = getenv("LD_PRELOAD"); + char *newpreload; + char sopath[PATH_MAX]; + int res; + + snprintf(sopath, sizeof(sopath), "%s/%s", LIBDIR, SSHNODELAY_SO); + res = access(sopath, R_OK); + if (res == -1) { + char *s; + if (!realpath(sshfs.progname, sopath)) + return -1; + + s = strrchr(sopath, '/'); + if (!s) + s = sopath; + else + s++; + + if (s + strlen(SSHNODELAY_SO) >= sopath + sizeof(sopath)) + return -1; + + strcpy(s, SSHNODELAY_SO); + res = access(sopath, R_OK); + if (res == -1) { + fprintf(stderr, "sshfs: cannot find %s\n", + SSHNODELAY_SO); + return -1; + } + } + + newpreload = g_strdup_printf("%s%s%s", + oldpreload ? oldpreload : "", + oldpreload ? " " : "", + sopath); + + if (!newpreload || setenv("LD_PRELOAD", newpreload, 1) == -1) { + fprintf(stderr, "warning: failed set LD_PRELOAD " + "for ssh nodelay workaround\n"); + } + g_free(newpreload); + return 0; } #endif static int start_ssh(void) { - int sockpair[2]; - int pid; + int sockpair[2]; + int pid; - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) == -1) { - perror("failed to create socket pair"); - return -1; - } - sshfs.fd = sockpair[0]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair) == -1) { + perror("failed to create socket pair"); + return -1; + } + sshfs.fd = sockpair[0]; - pid = fork(); - if (pid == -1) { - perror("failed to fork"); - return -1; - } else if (pid == 0) { - int devnull; + pid = fork(); + if (pid == -1) { + perror("failed to fork"); + return -1; + } else if (pid == 0) { + int devnull; #ifdef SSH_NODELAY_WORKAROUND - if (sshfs.nodelay_workaround && do_ssh_nodelay_workaround() == -1) - fprintf(stderr, "warning: ssh nodelay workaround disabled\n"); + if (sshfs.nodelay_workaround && + do_ssh_nodelay_workaround() == -1) { + fprintf(stderr, + "warning: ssh nodelay workaround disabled\n"); + } #endif - if (sshfs.nodelaysrv_workaround) { - /* Hack to work around missing TCP_NODELAY setting in sshd */ - sshfs.ssh_args.argv[1] = "-X"; - } - - devnull = open("/dev/null", O_WRONLY); - - if (dup2(sockpair[1], 0) == -1 || dup2(sockpair[1], 1) == -1) { - perror("failed to redirect input/output"); - _exit(1); - } - if (!sshfs.debug && devnull != -1) - dup2(devnull, 2); - - close(devnull); - close(sockpair[0]); - close(sockpair[1]); - - switch (fork()) { - case -1: - perror("failed to fork"); - _exit(1); - case 0: - break; - default: - _exit(0); - } - chdir("/"); - - execvp(sshfs.ssh_args.argv[0], sshfs.ssh_args.argv); - perror("execvp"); - _exit(1); - } - waitpid(pid, NULL, 0); - close(sockpair[1]); - return 0; + if (sshfs.nodelaysrv_workaround) { + /* + * Hack to work around missing TCP_NODELAY + * setting in sshd + */ + sshfs.ssh_args.argv[1] = "-X"; + } + + devnull = open("/dev/null", O_WRONLY); + + if (dup2(sockpair[1], 0) == -1 || dup2(sockpair[1], 1) == -1) { + perror("failed to redirect input/output"); + _exit(1); + } + if (!sshfs.debug && devnull != -1) + dup2(devnull, 2); + + close(devnull); + close(sockpair[0]); + close(sockpair[1]); + + switch (fork()) { + case -1: + perror("failed to fork"); + _exit(1); + case 0: + break; + default: + _exit(0); + } + chdir("/"); + + execvp(sshfs.ssh_args.argv[0], sshfs.ssh_args.argv); + perror("execvp"); + _exit(1); + } + waitpid(pid, NULL, 0); + close(sockpair[1]); + return 0; } static int connect_to(char *host, char *port) { - int err; - int sock; - int opt; - 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; - } - opt = 1; - err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); - if (err == -1) - perror("warning: failed to set TCP_NODELAY"); - - freeaddrinfo(ai); - - sshfs.fd = sock; - return 0; + int err; + int sock; + int opt; + 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; + } + opt = 1; + err = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + if (err == -1) + perror("warning: failed to set TCP_NODELAY"); + + freeaddrinfo(ai); + + sshfs.fd = sock; + return 0; } static int do_write(struct iovec *iov, size_t count) { - int res; - while (count) { - res = writev(sshfs.fd, iov, count); - if (res == -1) { - perror("write"); - return -1; - } else if (res == 0) { - fprintf(stderr, "zero write\n"); - return -1; - } - do { - if ((unsigned) res < iov->iov_len) { - iov->iov_len -= res; - iov->iov_base += res; - break; - } else { - res -= iov->iov_len; - count --; - iov ++; - } - } while(count); - } - return 0; + int res; + while (count) { + res = writev(sshfs.fd, iov, count); + if (res == -1) { + perror("write"); + return -1; + } else if (res == 0) { + fprintf(stderr, "zero write\n"); + return -1; + } + do { + if ((unsigned) res < iov->iov_len) { + iov->iov_len -= res; + iov->iov_base += res; + break; + } else { + res -= iov->iov_len; + count --; + iov ++; + } + } while(count); + } + return 0; } static uint32_t sftp_get_id(void) { - static uint32_t idctr; - return idctr++; + static uint32_t idctr; + return idctr++; } static void buf_to_iov(const struct buffer *buf, struct iovec *iov) { - iov->iov_base = buf->p; - iov->iov_len = buf->len; + iov->iov_base = buf->p; + iov->iov_len = buf->len; } static size_t iov_length(const struct iovec *iov, unsigned long nr_segs) { - unsigned long seg; - size_t ret = 0; + unsigned long seg; + size_t ret = 0; - for (seg = 0; seg < nr_segs; seg++) - ret += iov[seg].iov_len; - return ret; + for (seg = 0; seg < nr_segs; seg++) + ret += iov[seg].iov_len; + return ret; } #define SFTP_MAX_IOV 3 @@ -839,513 +854,532 @@ static size_t iov_length(const struct iovec *iov, unsigned long nr_segs) static int sftp_send_iov(uint8_t type, uint32_t id, struct iovec iov[], size_t count) { - int res; - struct buffer buf; - struct iovec iovout[SFTP_MAX_IOV]; - unsigned i; - unsigned nout = 0; - - assert(count <= SFTP_MAX_IOV - 1); - buf_init(&buf, 9); - buf_add_uint32(&buf, iov_length(iov, count) + 5); - buf_add_uint8(&buf, type); - buf_add_uint32(&buf, id); - buf_to_iov(&buf, &iovout[nout++]); - for (i = 0; i < count; i++) - iovout[nout++] = iov[i]; - pthread_mutex_lock(&sshfs.lock_write); - res = do_write(iovout, nout); - pthread_mutex_unlock(&sshfs.lock_write); - buf_free(&buf); - return res; + int res; + struct buffer buf; + struct iovec iovout[SFTP_MAX_IOV]; + unsigned i; + unsigned nout = 0; + + assert(count <= SFTP_MAX_IOV - 1); + buf_init(&buf, 9); + buf_add_uint32(&buf, iov_length(iov, count) + 5); + buf_add_uint8(&buf, type); + buf_add_uint32(&buf, id); + buf_to_iov(&buf, &iovout[nout++]); + for (i = 0; i < count; i++) + iovout[nout++] = iov[i]; + pthread_mutex_lock(&sshfs.lock_write); + res = do_write(iovout, nout); + pthread_mutex_unlock(&sshfs.lock_write); + buf_free(&buf); + return res; } static int do_read(struct buffer *buf) { - int res; - uint8_t *p = buf->p; - size_t size = buf->size; - while (size) { - res = read(sshfs.fd, p, size); - if (res == -1) { - perror("read"); - return -1; - } else if (res == 0) { - fprintf(stderr, "remote host has disconnected\n"); - return -1; - } - size -= res; - p += res; - } - return 0; + int res; + uint8_t *p = buf->p; + size_t size = buf->size; + while (size) { + res = read(sshfs.fd, p, size); + if (res == -1) { + perror("read"); + return -1; + } else if (res == 0) { + fprintf(stderr, "remote host has disconnected\n"); + return -1; + } + size -= res; + p += res; + } + return 0; } static int sftp_read(uint8_t *type, struct buffer *buf) { - int res; - struct buffer buf2; - uint32_t len; - buf_init(&buf2, 5); - res = do_read(&buf2); - if (res != -1) { - 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; - } - if (buf_get_uint8(&buf2, type) == -1) - return -1; - buf_init(buf, len - 1); - res = do_read(buf); - } - buf_free(&buf2); - return res; + int res; + struct buffer buf2; + uint32_t len; + buf_init(&buf2, 5); + res = do_read(&buf2); + if (res != -1) { + 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; + } + if (buf_get_uint8(&buf2, type) == -1) + return -1; + buf_init(buf, len - 1); + res = do_read(buf); + } + buf_free(&buf2); + return res; } static void request_free(struct request *req) { - buf_free(&req->reply); - sem_destroy(&req->ready); - g_free(req); + buf_free(&req->reply); + sem_destroy(&req->ready); + g_free(req); } static void chunk_free(struct read_chunk *chunk) { - buf_free(&chunk->data); - sem_destroy(&chunk->ready); - g_free(chunk); + buf_free(&chunk->data); + sem_destroy(&chunk->ready); + g_free(chunk); } static void chunk_put(struct read_chunk *chunk) { - if (chunk) { - chunk->refs--; - if (!chunk->refs) - chunk_free(chunk); - } + if (chunk) { + chunk->refs--; + if (!chunk->refs) + chunk_free(chunk); + } } static void chunk_put_locked(struct read_chunk *chunk) { - pthread_mutex_lock(&sshfs.lock); - chunk_put(chunk); - pthread_mutex_unlock(&sshfs.lock); + pthread_mutex_lock(&sshfs.lock); + chunk_put(chunk); + pthread_mutex_unlock(&sshfs.lock); } static int clean_req(void *key_, struct request *req) { - (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; + (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 int process_one_request(void) +{ + 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) + return -1; + if (buf_get_uint32(&buf, &id) == -1) + return -1; + + pthread_mutex_lock(&sshfs.lock); + req = (struct request *) + g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(id)); + if (req == NULL) + fprintf(stderr, "request %i not found\n", id); + else { + int was_over; + + was_over = sshfs.outstanding_len > sshfs.max_outstanding_len; + sshfs.outstanding_len -= req->len; + if (was_over && + sshfs.outstanding_len <= sshfs.max_outstanding_len) { + pthread_cond_broadcast(&sshfs.outstanding_cond); + } + g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); + } + pthread_mutex_unlock(&sshfs.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 %8ubytes (%ims)\n", id, + type_name(type), + (unsigned) buf.size + 5, difftime); + req->reply = buf; + req->reply_type = type; + req->replied = 1; + if (req->want_reply) + sem_post(&req->ready); + else { + if (req->end_func) { + pthread_mutex_lock(&sshfs.lock); + req->end_func(req); + pthread_mutex_unlock(&sshfs.lock); + } + request_free(req); + } + } else + buf_free(&buf); + + return 0; } static void *process_requests(void *data_) { - int res; - (void) data_; - - while (1) { - 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(&sshfs.lock); - req = (struct request *) g_hash_table_lookup(sshfs.reqtab, - GUINT_TO_POINTER(id)); - if (req == NULL) - fprintf(stderr, "request %i not found\n", id); - else { - int was_over = sshfs.outstanding_len > sshfs.max_outstanding_len; - sshfs.outstanding_len -= req->len; - if (was_over && sshfs.outstanding_len <= sshfs.max_outstanding_len) - pthread_cond_broadcast(&sshfs.outstanding_cond); - g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); - } - pthread_mutex_unlock(&sshfs.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 %8ubytes (%ims)\n", id, type_name(type), - (unsigned) buf.size + 5, difftime); - req->reply = buf; - req->reply_type = type; - req->replied = 1; - if (req->want_reply) - sem_post(&req->ready); - else { - if (req->end_func) { - pthread_mutex_lock(&sshfs.lock); - req->end_func(req); - pthread_mutex_unlock(&sshfs.lock); - } - request_free(req); - } - } else - buf_free(&buf); - } - if (!sshfs.reconnect) { - /* harakiri */ - kill(getpid(), SIGTERM); - } else { - pthread_mutex_lock(&sshfs.lock); - sshfs.processing_thread_started = 0; - close(sshfs.fd); - sshfs.fd = -1; - g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req, NULL); - sshfs.connver ++; - pthread_mutex_unlock(&sshfs.lock); - } - return NULL; + (void) data_; + + while (1) { + if (process_one_request() == -1) + break; + } + + if (!sshfs.reconnect) { + /* harakiri */ + kill(getpid(), SIGTERM); + } else { + pthread_mutex_lock(&sshfs.lock); + sshfs.processing_thread_started = 0; + close(sshfs.fd); + sshfs.fd = -1; + g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req, + NULL); + sshfs.connver ++; + pthread_mutex_unlock(&sshfs.lock); + } + return NULL; } static int sftp_init_reply_ok(struct buffer *buf, uint32_t *version) { - uint32_t len; - uint8_t type; + uint32_t len; + uint8_t type; - if (buf_get_uint32(buf, &len) == -1) - return -1; + if (buf_get_uint32(buf, &len) == -1) + return -1; - if (len < 5 || len > MAX_REPLY_LEN) - return 1; + if (len < 5 || len > MAX_REPLY_LEN) + return 1; - if (buf_get_uint8(buf, &type) == -1) - return -1; + if (buf_get_uint8(buf, &type) == -1) + return -1; - if (type != SSH_FXP_VERSION) - return 1; + if (type != SSH_FXP_VERSION) + return 1; - if (buf_get_uint32(buf, version) == -1) - return -1; + if (buf_get_uint32(buf, version) == -1) + return -1; - if (len > 5) { - struct buffer buf2; - buf_init(&buf2, len - 5); - return do_read(&buf2); - } - return 0; + if (len > 5) { + struct buffer buf2; + buf_init(&buf2, len - 5); + return do_read(&buf2); + } + return 0; } static int sftp_find_init_reply(uint32_t *version) { - int res; - struct buffer buf; + int res; + struct buffer buf; - buf_init(&buf, 9); - res = do_read(&buf); - while (res != -1) { - struct buffer buf2; + buf_init(&buf, 9); + res = do_read(&buf); + while (res != -1) { + struct buffer buf2; - res = sftp_init_reply_ok(&buf, version); - if (res <= 0) - break; + res = sftp_init_reply_ok(&buf, version); + if (res <= 0) + break; - /* Iterate over any rubbish until the version reply is found */ - DEBUG("%c", *buf.p); - memmove(buf.p, buf.p + 1, buf.size - 1); - buf.len = 0; - buf2.p = buf.p + buf.size - 1; - buf2.size = 1; - res = do_read(&buf2); - } - buf_free(&buf); - return res; + /* Iterate over any rubbish until the version reply is found */ + DEBUG("%c", *buf.p); + memmove(buf.p, buf.p + 1, buf.size - 1); + buf.len = 0; + buf2.p = buf.p + buf.size - 1; + buf2.size = 1; + res = do_read(&buf2); + } + buf_free(&buf); + return res; } static int sftp_init() { - int res = -1; - uint32_t version = 0; - struct buffer buf; - buf_init(&buf, 0); - if (sftp_send_iov(SSH_FXP_INIT, PROTO_VERSION, NULL, 0) == -1) - goto out; - if (sftp_find_init_reply(&version) == -1) - goto out; - - sshfs.server_version = version; - DEBUG("Server version: %i\n", sshfs.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; + int res = -1; + uint32_t version = 0; + struct buffer buf; + buf_init(&buf, 0); + if (sftp_send_iov(SSH_FXP_INIT, PROTO_VERSION, NULL, 0) == -1) + goto out; + if (sftp_find_init_reply(&version) == -1) + goto out; + + sshfs.server_version = version; + DEBUG("Server version: %i\n", sshfs.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 sftp_error_to_errno(uint32_t error) { - switch (error) { - case SSH_FX_OK: return 0; - case SSH_FX_NO_SUCH_FILE: return ENOENT; - case SSH_FX_PERMISSION_DENIED: return EACCES; - case SSH_FX_FAILURE: return EPERM; - case SSH_FX_BAD_MESSAGE: return EBADMSG; - case SSH_FX_NO_CONNECTION: return ENOTCONN; - case SSH_FX_CONNECTION_LOST: return ECONNABORTED; - case SSH_FX_OP_UNSUPPORTED: return EOPNOTSUPP; - default: return EIO; - } + switch (error) { + case SSH_FX_OK: return 0; + case SSH_FX_NO_SUCH_FILE: return ENOENT; + case SSH_FX_PERMISSION_DENIED: return EACCES; + case SSH_FX_FAILURE: return EPERM; + case SSH_FX_BAD_MESSAGE: return EBADMSG; + case SSH_FX_NO_CONNECTION: return ENOTCONN; + case SSH_FX_CONNECTION_LOST: return ECONNABORTED; + case SSH_FX_OP_UNSUPPORTED: return EOPNOTSUPP; + default: return EIO; + } } static void sftp_detect_uid() { - int flags; - uint32_t id = sftp_get_id(); - uint32_t replid; - uint8_t type; - struct buffer buf; - struct stat stbuf; - struct iovec iov[1]; - - buf_init(&buf, 5); - buf_add_string(&buf, "."); - buf_to_iov(&buf, &iov[0]); - if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1) - goto out; - buf_clear(&buf); - if (sftp_read(&type, &buf) == -1) - goto out; - if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) { - fprintf(stderr, "protocol error\n"); - goto out; - } - if (buf_get_uint32(&buf, &replid) == -1) - goto out; - if (replid != id) { - fprintf(stderr, "bad reply ID\n"); - goto out; - } - if (type == SSH_FXP_STATUS) { - uint32_t serr; - if (buf_get_uint32(&buf, &serr) == -1) - goto out; - - fprintf(stderr, "failed to stat home directory (%i)\n", serr); - goto out; - } - if (buf_get_attrs(&buf, &stbuf, &flags) == -1) - goto out; - - if (!(flags & SSH_FILEXFER_ATTR_UIDGID)) - goto out; - - sshfs.remote_uid = stbuf.st_uid; - sshfs.local_uid = getuid(); - sshfs.remote_uid_detected = 1; - DEBUG("remote_uid = %i\n", sshfs.remote_uid); - - out: - if (!sshfs.remote_uid_detected) - fprintf(stderr, "failed to detect remote user ID\n"); - - buf_free(&buf); + int flags; + uint32_t id = sftp_get_id(); + uint32_t replid; + uint8_t type; + struct buffer buf; + struct stat stbuf; + struct iovec iov[1]; + + buf_init(&buf, 5); + buf_add_string(&buf, "."); + buf_to_iov(&buf, &iov[0]); + if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1) + goto out; + buf_clear(&buf); + if (sftp_read(&type, &buf) == -1) + goto out; + if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) { + fprintf(stderr, "protocol error\n"); + goto out; + } + if (buf_get_uint32(&buf, &replid) == -1) + goto out; + if (replid != id) { + fprintf(stderr, "bad reply ID\n"); + goto out; + } + if (type == SSH_FXP_STATUS) { + uint32_t serr; + if (buf_get_uint32(&buf, &serr) == -1) + goto out; + + fprintf(stderr, "failed to stat home directory (%i)\n", serr); + goto out; + } + if (buf_get_attrs(&buf, &stbuf, &flags) == -1) + goto out; + + if (!(flags & SSH_FILEXFER_ATTR_UIDGID)) + goto out; + + sshfs.remote_uid = stbuf.st_uid; + sshfs.local_uid = getuid(); + sshfs.remote_uid_detected = 1; + DEBUG("remote_uid = %i\n", sshfs.remote_uid); + +out: + if (!sshfs.remote_uid_detected) + fprintf(stderr, "failed to detect remote user ID\n"); + + buf_free(&buf); } static int sftp_check_root(const char *base_path) { - int flags; - uint32_t id = sftp_get_id(); - uint32_t replid; - uint8_t type; - struct buffer buf; - struct stat stbuf; - struct iovec iov[1]; - int err = -1; - const char *remote_dir = base_path[0] ? base_path : "."; - - buf_init(&buf, 0); - buf_add_string(&buf, remote_dir); - buf_to_iov(&buf, &iov[0]); - if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1) - goto out; - buf_clear(&buf); - if (sftp_read(&type, &buf) == -1) - goto out; - if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) { - fprintf(stderr, "protocol error\n"); - goto out; - } - if (buf_get_uint32(&buf, &replid) == -1) - goto out; - if (replid != id) { - fprintf(stderr, "bad reply ID\n"); - goto out; - } - if (type == SSH_FXP_STATUS) { - uint32_t serr; - if (buf_get_uint32(&buf, &serr) == -1) - goto out; - - fprintf(stderr, "%s:%s: %s\n", sshfs.host, remote_dir, - strerror(sftp_error_to_errno(serr))); - - goto out; - } - if (buf_get_attrs(&buf, &stbuf, &flags) == -1) - goto out; - - if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS)) - goto out; - - if (!S_ISDIR(stbuf.st_mode)) { - fprintf(stderr, "%s:%s: Not a directory\n", sshfs.host, remote_dir); - goto out; - } - - err = 0; - - out: - buf_free(&buf); - return err; + int flags; + uint32_t id = sftp_get_id(); + uint32_t replid; + uint8_t type; + struct buffer buf; + struct stat stbuf; + struct iovec iov[1]; + int err = -1; + const char *remote_dir = base_path[0] ? base_path : "."; + + buf_init(&buf, 0); + buf_add_string(&buf, remote_dir); + buf_to_iov(&buf, &iov[0]); + if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1) + goto out; + buf_clear(&buf); + if (sftp_read(&type, &buf) == -1) + goto out; + if (type != SSH_FXP_ATTRS && type != SSH_FXP_STATUS) { + fprintf(stderr, "protocol error\n"); + goto out; + } + if (buf_get_uint32(&buf, &replid) == -1) + goto out; + if (replid != id) { + fprintf(stderr, "bad reply ID\n"); + goto out; + } + if (type == SSH_FXP_STATUS) { + uint32_t serr; + if (buf_get_uint32(&buf, &serr) == -1) + goto out; + + fprintf(stderr, "%s:%s: %s\n", sshfs.host, remote_dir, + strerror(sftp_error_to_errno(serr))); + + goto out; + } + if (buf_get_attrs(&buf, &stbuf, &flags) == -1) + goto out; + + if (!(flags & SSH_FILEXFER_ATTR_PERMISSIONS)) + goto out; + + if (!S_ISDIR(stbuf.st_mode)) { + fprintf(stderr, "%s:%s: Not a directory\n", sshfs.host, + remote_dir); + goto out; + } + + err = 0; + +out: + buf_free(&buf); + return err; } static int connect_remote(void) { - int err; + int err; - if (sshfs.directport) - err = connect_to(sshfs.host, sshfs.directport); - else - err = start_ssh(); - if (!err) - err = sftp_init(); + if (sshfs.directport) + err = connect_to(sshfs.host, sshfs.directport); + else + err = start_ssh(); + if (!err) + err = sftp_init(); - return err; + return err; } static int start_processing_thread(void) { - int err; - pthread_t thread_id; - sigset_t oldset; - sigset_t newset; - - if (sshfs.processing_thread_started) - return 0; - - if (sshfs.fd == -1) { - err = connect_remote(); - if (err) - return -EIO; - } - - sigemptyset(&newset); - sigaddset(&newset, SIGTERM); - sigaddset(&newset, SIGINT); - sigaddset(&newset, SIGHUP); - sigaddset(&newset, SIGQUIT); - pthread_sigmask(SIG_BLOCK, &newset, &oldset); - err = pthread_create(&thread_id, NULL, process_requests, NULL); - if (err) { - fprintf(stderr, "failed to create thread: %s\n", strerror(err)); - return -EIO; - } - pthread_detach(thread_id); - pthread_sigmask(SIG_SETMASK, &oldset, NULL); - sshfs.processing_thread_started = 1; - return 0; + int err; + pthread_t thread_id; + sigset_t oldset; + sigset_t newset; + + if (sshfs.processing_thread_started) + return 0; + + if (sshfs.fd == -1) { + err = connect_remote(); + if (err) + return -EIO; + } + + sigemptyset(&newset); + sigaddset(&newset, SIGTERM); + sigaddset(&newset, SIGINT); + sigaddset(&newset, SIGHUP); + sigaddset(&newset, SIGQUIT); + pthread_sigmask(SIG_BLOCK, &newset, &oldset); + err = pthread_create(&thread_id, NULL, process_requests, NULL); + if (err) { + fprintf(stderr, "failed to create thread: %s\n", strerror(err)); + return -EIO; + } + pthread_detach(thread_id); + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + sshfs.processing_thread_started = 1; + return 0; } #ifdef SSHFS_USE_INIT #if FUSE_VERSION >= 26 static void *sshfs_init(struct fuse_conn_info *conn) #else -static void *sshfs_init(void) + static void *sshfs_init(void) #endif { #if FUSE_VERSION >= 26 - /* Readahead should be done by kernel or sshfs but not both */ - if (conn->async_read) - sshfs.sync_read = 1; + /* Readahead should be done by kernel or sshfs but not both */ + if (conn->async_read) + sshfs.sync_read = 1; #endif - if (sshfs.detect_uid) - sftp_detect_uid(); + if (sshfs.detect_uid) + sftp_detect_uid(); - start_processing_thread(); - return NULL; + start_processing_thread(); + return NULL; } #endif static int sftp_request_wait(struct request *req, uint8_t type, uint8_t expect_type, struct buffer *outbuf) { - int err; - - if (req->error) { - err = req->error; - goto out; - } - while (sem_wait(&req->ready)); - if (req->error) { - err = req->error; - goto out; - } - err = -EIO; - if (req->reply_type != expect_type && req->reply_type != SSH_FXP_STATUS) { - fprintf(stderr, "protocol error\n"); - goto out; - } - if (req->reply_type == SSH_FXP_STATUS) { - uint32_t serr; - if (buf_get_uint32(&req->reply, &serr) == -1) - goto out; - - switch (serr) { - case SSH_FX_OK: - if (expect_type == SSH_FXP_STATUS) - err = 0; - else - err = -EIO; - break; - - case SSH_FX_EOF: - if (type == SSH_FXP_READ || type == SSH_FXP_READDIR) - err = MY_EOF; - else - err = -EIO; - break; - - default: - err = -sftp_error_to_errno(serr); - } - } else { - buf_init(outbuf, req->reply.size - req->reply.len); - buf_get_mem(&req->reply, outbuf->p, outbuf->size); - err = 0; - } - - out: - if (req->end_func) { - pthread_mutex_lock(&sshfs.lock); - req->end_func(req); - pthread_mutex_unlock(&sshfs.lock); - } - request_free(req); - return err; + int err; + + if (req->error) { + err = req->error; + goto out; + } + while (sem_wait(&req->ready)); + if (req->error) { + err = req->error; + goto out; + } + err = -EIO; + if (req->reply_type != expect_type && + req->reply_type != SSH_FXP_STATUS) { + fprintf(stderr, "protocol error\n"); + goto out; + } + if (req->reply_type == SSH_FXP_STATUS) { + uint32_t serr; + if (buf_get_uint32(&req->reply, &serr) == -1) + goto out; + + switch (serr) { + case SSH_FX_OK: + if (expect_type == SSH_FXP_STATUS) + err = 0; + else + err = -EIO; + break; + + case SSH_FX_EOF: + if (type == SSH_FXP_READ || type == SSH_FXP_READDIR) + err = MY_EOF; + else + err = -EIO; + break; + + default: + err = -sftp_error_to_errno(serr); + } + } else { + buf_init(outbuf, req->reply.size - req->reply.len); + buf_get_mem(&req->reply, outbuf->p, outbuf->size); + err = 0; + } + +out: + if (req->end_func) { + pthread_mutex_lock(&sshfs.lock); + req->end_func(req); + pthread_mutex_unlock(&sshfs.lock); + } + request_free(req); + return err; } static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count, @@ -1353,377 +1387,379 @@ static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count, int want_reply, void *data, struct request **reqp) { - int err; - uint32_t id; - struct request *req = g_new0(struct request, 1); - - req->want_reply = want_reply; - req->end_func = end_func; - req->data = data; - sem_init(&req->ready, 0, 0); - buf_init(&req->reply, 0); - pthread_mutex_lock(&sshfs.lock); - if (begin_func) - begin_func(req); - id = sftp_get_id(); - err = start_processing_thread(); - if (err) { - pthread_mutex_unlock(&sshfs.lock); - goto out; - } - req->len = iov_length(iov, count) + 9; - sshfs.outstanding_len += req->len; - while (sshfs.outstanding_len > sshfs.max_outstanding_len) - pthread_cond_wait(&sshfs.outstanding_cond, &sshfs.lock); - - g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req); - gettimeofday(&req->start, NULL); - DEBUG("[%05i] %s\n", id, type_name(type)); - pthread_mutex_unlock(&sshfs.lock); - - err = -EIO; - if (sftp_send_iov(type, id, iov, count) == -1) { - pthread_mutex_lock(&sshfs.lock); - g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); - pthread_mutex_unlock(&sshfs.lock); - goto out; - } - if (want_reply) - *reqp = req; - return 0; - - out: - req->error = err; - if (!want_reply) - sftp_request_wait(req, type, 0, NULL); - else - *reqp = req; - - return err; + int err; + uint32_t id; + struct request *req = g_new0(struct request, 1); + + req->want_reply = want_reply; + req->end_func = end_func; + req->data = data; + sem_init(&req->ready, 0, 0); + buf_init(&req->reply, 0); + pthread_mutex_lock(&sshfs.lock); + if (begin_func) + begin_func(req); + id = sftp_get_id(); + err = start_processing_thread(); + if (err) { + pthread_mutex_unlock(&sshfs.lock); + goto out; + } + req->len = iov_length(iov, count) + 9; + sshfs.outstanding_len += req->len; + while (sshfs.outstanding_len > sshfs.max_outstanding_len) + pthread_cond_wait(&sshfs.outstanding_cond, &sshfs.lock); + + g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req); + gettimeofday(&req->start, NULL); + DEBUG("[%05i] %s\n", id, type_name(type)); + pthread_mutex_unlock(&sshfs.lock); + + err = -EIO; + if (sftp_send_iov(type, id, iov, count) == -1) { + pthread_mutex_lock(&sshfs.lock); + g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); + pthread_mutex_unlock(&sshfs.lock); + goto out; + } + if (want_reply) + *reqp = req; + return 0; + +out: + req->error = err; + if (!want_reply) + sftp_request_wait(req, type, 0, NULL); + else + *reqp = req; + + return err; } static int sftp_request_iov(uint8_t type, struct iovec *iov, size_t count, uint8_t expect_type, struct buffer *outbuf) { - struct request *req; + struct request *req; - sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL, &req); - if (expect_type == 0) - return 0; + sftp_request_send(type, iov, count, NULL, NULL, expect_type, NULL, + &req); + if (expect_type == 0) + return 0; - return sftp_request_wait(req, type, expect_type, outbuf); + return sftp_request_wait(req, type, expect_type, outbuf); } static int sftp_request(uint8_t type, const struct buffer *buf, uint8_t expect_type, struct buffer *outbuf) { - struct iovec iov; + struct iovec iov; - buf_to_iov(buf, &iov); - return sftp_request_iov(type, &iov, 1, expect_type, outbuf); + buf_to_iov(buf, &iov); + return sftp_request_iov(type, &iov, 1, expect_type, outbuf); } static int sshfs_getattr(const char *path, struct stat *stbuf) { - int err; - struct buffer buf; - struct buffer outbuf; - buf_init(&buf, 0); - buf_add_path(&buf, path); - err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT, - &buf, SSH_FXP_ATTRS, &outbuf); - if (!err) { - if (buf_get_attrs(&outbuf, stbuf, NULL) == -1) - err = -EIO; - buf_free(&outbuf); - } - buf_free(&buf); - return err; + int err; + struct buffer buf; + struct buffer outbuf; + buf_init(&buf, 0); + buf_add_path(&buf, path); + err = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT, + &buf, SSH_FXP_ATTRS, &outbuf); + if (!err) { + if (buf_get_attrs(&outbuf, stbuf, NULL) == -1) + err = -EIO; + buf_free(&outbuf); + } + buf_free(&buf); + return err; } static int count_components(const char *p) { - int ctr; + int ctr; - for (; *p == '/'; p++); - for (ctr = 0; *p; ctr++) { - for (; *p && *p != '/'; p++); - for (; *p == '/'; p++); - } - return ctr; + for (; *p == '/'; p++); + for (ctr = 0; *p; ctr++) { + for (; *p && *p != '/'; p++); + for (; *p == '/'; p++); + } + return ctr; } static void strip_common(const char **sp, const char **tp) { - const char *s = *sp; - const char *t = *tp; - do { - for (; *s == '/'; s++); - for (; *t == '/'; t++); - *tp = t; - *sp = s; - for (; *s == *t && *s && *s != '/'; s++, t++); - } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); + const char *s = *sp; + const char *t = *tp; + do { + for (; *s == '/'; s++); + for (; *t == '/'; t++); + *tp = t; + *sp = s; + for (; *s == *t && *s && *s != '/'; s++, t++); + } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t)); } static void transform_symlink(const char *path, char **linkp) { - const char *l = *linkp; - const char *b = sshfs.base_path; - char *newlink; - char *s; - int dotdots; - int i; - - if (l[0] != '/' || b[0] != '/') - return; - - strip_common(&l, &b); - if (*b) - return; - - strip_common(&l, &path); - dotdots = count_components(path); - if (!dotdots) - return; - dotdots--; - - newlink = malloc(dotdots * 3 + strlen(l) + 2); - if (!newlink) { - fprintf(stderr, "sshfs: memory allocation failed\n"); - exit(1); - } - for (s = newlink, i = 0; i < dotdots; i++, s += 3) - strcpy(s, "../"); - - if (l[0]) - strcpy(s, l); - else if (!dotdots) - strcpy(s, "."); - else - s[0] = '\0'; - - free(*linkp); - *linkp = newlink; + const char *l = *linkp; + const char *b = sshfs.base_path; + char *newlink; + char *s; + int dotdots; + int i; + + if (l[0] != '/' || b[0] != '/') + return; + + strip_common(&l, &b); + if (*b) + return; + + strip_common(&l, &path); + dotdots = count_components(path); + if (!dotdots) + return; + dotdots--; + + newlink = malloc(dotdots * 3 + strlen(l) + 2); + if (!newlink) { + fprintf(stderr, "sshfs: memory allocation failed\n"); + abort(); + } + for (s = newlink, i = 0; i < dotdots; i++, s += 3) + strcpy(s, "../"); + + if (l[0]) + strcpy(s, l); + else if (!dotdots) + strcpy(s, "."); + else + s[0] = '\0'; + + free(*linkp); + *linkp = newlink; } static int sshfs_readlink(const char *path, char *linkbuf, size_t size) { - int err; - struct buffer buf; - struct buffer name; - - assert(size > 0); - - if (sshfs.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); - if (!err) { - uint32_t count; - char *link; - err = -EIO; - if(buf_get_uint32(&name, &count) != -1 && count == 1 && - buf_get_string(&name, &link) != -1) { - if (sshfs.transform_symlinks) - transform_symlink(path, &link); - strncpy(linkbuf, link, size - 1); - linkbuf[size - 1] = '\0'; - free(link); - err = 0; - } - buf_free(&name); - } - buf_free(&buf); - return err; + int err; + struct buffer buf; + struct buffer name; + + assert(size > 0); + + if (sshfs.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); + if (!err) { + uint32_t count; + char *link; + err = -EIO; + if(buf_get_uint32(&name, &count) != -1 && count == 1 && + buf_get_string(&name, &link) != -1) { + if (sshfs.transform_symlinks) + transform_symlink(path, &link); + strncpy(linkbuf, link, size - 1); + linkbuf[size - 1] = '\0'; + free(link); + err = 0; + } + buf_free(&name); + } + buf_free(&buf); + return err; } static int sshfs_getdir(const char *path, fuse_cache_dirh_t h, fuse_cache_dirfil_t filler) { - int err; - struct buffer buf; - struct buffer handle; - buf_init(&buf, 0); - buf_add_path(&buf, path); - err = sftp_request(SSH_FXP_OPENDIR, &buf, SSH_FXP_HANDLE, &handle); - if (!err) { - int err2; - buf_finish(&handle); - do { - struct buffer name; - err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name); - if (!err) { - if (buf_get_entries(&name, h, filler) == -1) - err = -EIO; - buf_free(&name); - } - } while (!err); - if (err == MY_EOF) - err = 0; - - err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL); - if (!err) - err = err2; - buf_free(&handle); - } - buf_free(&buf); - return err; + int err; + struct buffer buf; + struct buffer handle; + buf_init(&buf, 0); + buf_add_path(&buf, path); + err = sftp_request(SSH_FXP_OPENDIR, &buf, SSH_FXP_HANDLE, &handle); + if (!err) { + int err2; + buf_finish(&handle); + do { + struct buffer name; + err = sftp_request(SSH_FXP_READDIR, &handle, SSH_FXP_NAME, &name); + if (!err) { + if (buf_get_entries(&name, h, filler) == -1) + err = -EIO; + buf_free(&name); + } + } while (!err); + if (err == MY_EOF) + err = 0; + + err2 = sftp_request(SSH_FXP_CLOSE, &handle, 0, NULL); + if (!err) + err = err2; + buf_free(&handle); + } + buf_free(&buf); + return err; } static int sshfs_mkdir(const char *path, mode_t mode) { - int err; - struct buffer buf; - buf_init(&buf, 0); - 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); - buf_free(&buf); - return err; + int err; + struct buffer buf; + buf_init(&buf, 0); + 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); + buf_free(&buf); + return err; } 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_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); - 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_free(&buf); - return err; + int err; + struct buffer buf; + struct buffer handle; + (void) rdev; + + if ((mode & S_IFMT) != S_IFREG) + return -EPERM; + + buf_init(&buf, 0); + 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); + 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_free(&buf); + return err; } static int sshfs_symlink(const char *from, const char *to) { - int err; - struct buffer buf; + int err; + struct buffer buf; - if (sshfs.server_version < 3) - return -EPERM; + if (sshfs.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); - buf_add_string(&buf, from); - buf_add_path(&buf, to); - err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL); - buf_free(&buf); - return err; + /* 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_path(&buf, to); + err = sftp_request(SSH_FXP_SYMLINK, &buf, SSH_FXP_STATUS, NULL); + buf_free(&buf); + return err; } static int sshfs_unlink(const char *path) { - int err; - struct buffer buf; - buf_init(&buf, 0); - buf_add_path(&buf, path); - err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL); - buf_free(&buf); - return err; + int err; + struct buffer buf; + buf_init(&buf, 0); + buf_add_path(&buf, path); + err = sftp_request(SSH_FXP_REMOVE, &buf, SSH_FXP_STATUS, NULL); + buf_free(&buf); + return err; } static int sshfs_rmdir(const char *path) { - int err; - struct buffer buf; - buf_init(&buf, 0); - buf_add_path(&buf, path); - err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL); - buf_free(&buf); - return err; + int err; + struct buffer buf; + buf_init(&buf, 0); + buf_add_path(&buf, path); + err = sftp_request(SSH_FXP_RMDIR, &buf, SSH_FXP_STATUS, NULL); + buf_free(&buf); + return err; } static int sshfs_do_rename(const char *from, const char *to) { - int err; - struct buffer buf; - buf_init(&buf, 0); - buf_add_path(&buf, from); - buf_add_path(&buf, to); - err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL); - buf_free(&buf); - return err; + int err; + struct buffer buf; + buf_init(&buf, 0); + buf_add_path(&buf, from); + buf_add_path(&buf, to); + err = sftp_request(SSH_FXP_RENAME, &buf, SSH_FXP_STATUS, NULL); + buf_free(&buf); + return err; } static void random_string(char *str, int length) { - int i; - for (i = 0; i < length; i++) - *str++ = (char)('0' + rand_r(&sshfs.randseed) % 10); - *str = '\0'; + int i; + for (i = 0; i < length; i++) + *str++ = (char)('0' + rand_r(&sshfs.randseed) % 10); + *str = '\0'; } static int sshfs_rename(const char *from, const char *to) { - int err; - err = sshfs_do_rename(from, to); - if (err == -EPERM && sshfs.rename_workaround) { - size_t tolen = strlen(to); - if (tolen + RENAME_TEMP_CHARS < PATH_MAX) { - int tmperr; - char totmp[PATH_MAX]; - strcpy(totmp, to); - random_string(totmp + tolen, RENAME_TEMP_CHARS); - tmperr = sshfs_do_rename(to, totmp); - if (!tmperr) { - err = sshfs_do_rename(from, to); - if (!err) - err = sshfs_unlink(totmp); - else - sshfs_do_rename(totmp, to); - } - } - } - return err; + int err; + err = sshfs_do_rename(from, to); + if (err == -EPERM && sshfs.rename_workaround) { + size_t tolen = strlen(to); + if (tolen + RENAME_TEMP_CHARS < PATH_MAX) { + int tmperr; + char totmp[PATH_MAX]; + strcpy(totmp, to); + random_string(totmp + tolen, RENAME_TEMP_CHARS); + tmperr = sshfs_do_rename(to, totmp); + if (!tmperr) { + err = sshfs_do_rename(from, to); + if (!err) + err = sshfs_unlink(totmp); + else + sshfs_do_rename(totmp, to); + } + } + } + return err; } static int sshfs_chmod(const char *path, mode_t mode) { - int err; - struct buffer buf; - buf_init(&buf, 0); - 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); - buf_free(&buf); - return err; + int err; + struct buffer buf; + buf_init(&buf, 0); + 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); + buf_free(&buf); + return err; } static int sshfs_chown(const char *path, uid_t uid, gid_t gid) { - int err; - struct buffer buf; - buf_init(&buf, 0); - buf_add_path(&buf, path); - buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID); - buf_add_uint32(&buf, uid); - buf_add_uint32(&buf, gid); - err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); - buf_free(&buf); - return err; + int err; + struct buffer buf; + buf_init(&buf, 0); + buf_add_path(&buf, path); + buf_add_uint32(&buf, SSH_FILEXFER_ATTR_UIDGID); + buf_add_uint32(&buf, uid); + buf_add_uint32(&buf, gid); + err = sftp_request(SSH_FXP_SETSTAT, &buf, SSH_FXP_STATUS, NULL); + buf_free(&buf); + return err; } static int sshfs_truncate_workaround(const char *path, off_t size, @@ -1731,469 +1767,479 @@ static int sshfs_truncate_workaround(const char *path, off_t size, static int sshfs_truncate(const char *path, off_t size) { - int err; - struct buffer buf; + int err; + struct buffer buf; - sshfs.modifver ++; - if (size == 0 || sshfs.truncate_workaround) - return sshfs_truncate_workaround(path, size, NULL); + sshfs.modifver ++; + if (size == 0 || sshfs.truncate_workaround) + return sshfs_truncate_workaround(path, size, NULL); - 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); - buf_free(&buf); - return err; + 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); + buf_free(&buf); + return err; } static int sshfs_utime(const char *path, struct utimbuf *ubuf) { - int err; - struct buffer buf; - buf_init(&buf, 0); - 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); - buf_free(&buf); - return err; + int err; + struct buffer buf; + buf_init(&buf, 0); + 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); + buf_free(&buf); + return err; } static inline int sshfs_file_is_conn(struct sshfs_file *sf) { - return sf->connver == sshfs.connver; + return sf->connver == sshfs.connver; } static int sshfs_open_common(const char *path, mode_t mode, struct fuse_file_info *fi) { - int err; - int err2; - struct buffer buf; - struct buffer outbuf; - struct stat stbuf; - struct sshfs_file *sf; - struct request *open_req; - uint32_t pflags = 0; - struct iovec iov; - - if ((fi->flags & O_ACCMODE) == O_RDONLY) - pflags = SSH_FXF_READ; - else if((fi->flags & O_ACCMODE) == O_WRONLY) - pflags = SSH_FXF_WRITE; - else if ((fi->flags & O_ACCMODE) == O_RDWR) - pflags = SSH_FXF_READ | SSH_FXF_WRITE; - else - return -EINVAL; - - if (fi->flags & O_CREAT) - pflags |= SSH_FXF_CREAT; - - if (fi->flags & O_EXCL) - pflags |= SSH_FXF_EXCL; - - if (fi->flags & O_TRUNC) - pflags |= SSH_FXF_TRUNC; - - sf = g_new0(struct sshfs_file, 1); - list_init(&sf->write_reqs); - pthread_cond_init(&sf->write_finished, NULL); - /* Assume random read after open */ - sf->is_seq = 0; - sf->refs = 1; - sf->next_pos = 0; - sf->modifver= sshfs.modifver; - sf->connver = sshfs.connver; - buf_init(&buf, 0); - buf_add_path(&buf, path); - buf_add_uint32(&buf, pflags); - buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS); - buf_add_uint32(&buf, mode); - buf_to_iov(&buf, &iov); - sftp_request_send(SSH_FXP_OPEN, &iov, 1, NULL, NULL, 1, NULL, &open_req); - buf_clear(&buf); - buf_add_path(&buf, path); - err2 = sftp_request(sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT, - &buf, SSH_FXP_ATTRS, &outbuf); - if (!err2) { - if (buf_get_attrs(&outbuf, &stbuf, NULL) == -1) - err2 = -EIO; - buf_free(&outbuf); - } - err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE, - &sf->handle); - if (!err && err2) { - buf_finish(&sf->handle); - sftp_request(SSH_FXP_CLOSE, &sf->handle, 0, NULL); - buf_free(&sf->handle); - err = err2; - } - - if (!err) { - cache_add_attr(path, &stbuf); - buf_finish(&sf->handle); - fi->fh = (unsigned long) sf; - } else { - cache_invalidate(path); - g_free(sf); - } - buf_free(&buf); - return err; + int err; + int err2; + struct buffer buf; + struct buffer outbuf; + struct stat stbuf; + struct sshfs_file *sf; + struct request *open_req; + uint32_t pflags = 0; + struct iovec iov; + uint8_t type; + + if ((fi->flags & O_ACCMODE) == O_RDONLY) + pflags = SSH_FXF_READ; + else if((fi->flags & O_ACCMODE) == O_WRONLY) + pflags = SSH_FXF_WRITE; + else if ((fi->flags & O_ACCMODE) == O_RDWR) + pflags = SSH_FXF_READ | SSH_FXF_WRITE; + else + return -EINVAL; + + if (fi->flags & O_CREAT) + pflags |= SSH_FXF_CREAT; + + if (fi->flags & O_EXCL) + pflags |= SSH_FXF_EXCL; + + if (fi->flags & O_TRUNC) + pflags |= SSH_FXF_TRUNC; + + sf = g_new0(struct sshfs_file, 1); + list_init(&sf->write_reqs); + pthread_cond_init(&sf->write_finished, NULL); + /* Assume random read after open */ + sf->is_seq = 0; + sf->refs = 1; + sf->next_pos = 0; + sf->modifver= sshfs.modifver; + sf->connver = sshfs.connver; + buf_init(&buf, 0); + buf_add_path(&buf, path); + buf_add_uint32(&buf, pflags); + buf_add_uint32(&buf, SSH_FILEXFER_ATTR_PERMISSIONS); + buf_add_uint32(&buf, mode); + buf_to_iov(&buf, &iov); + sftp_request_send(SSH_FXP_OPEN, &iov, 1, NULL, NULL, 1, NULL, + &open_req); + buf_clear(&buf); + buf_add_path(&buf, path); + type = sshfs.follow_symlinks ? SSH_FXP_STAT : SSH_FXP_LSTAT; + err2 = sftp_request(type, &buf, SSH_FXP_ATTRS, &outbuf); + if (!err2) { + if (buf_get_attrs(&outbuf, &stbuf, NULL) == -1) + err2 = -EIO; + buf_free(&outbuf); + } + err = sftp_request_wait(open_req, SSH_FXP_OPEN, SSH_FXP_HANDLE, + &sf->handle); + if (!err && err2) { + buf_finish(&sf->handle); + sftp_request(SSH_FXP_CLOSE, &sf->handle, 0, NULL); + buf_free(&sf->handle); + err = err2; + } + + if (!err) { + cache_add_attr(path, &stbuf); + buf_finish(&sf->handle); + fi->fh = (unsigned long) sf; + } else { + cache_invalidate(path); + g_free(sf); + } + buf_free(&buf); + return err; } static int sshfs_open(const char *path, struct fuse_file_info *fi) { - return sshfs_open_common(path, 0, fi); + return sshfs_open_common(path, 0, fi); } static inline struct sshfs_file *get_sshfs_file(struct fuse_file_info *fi) { - return (struct sshfs_file *) (uintptr_t) fi->fh; + return (struct sshfs_file *) (uintptr_t) fi->fh; } static int sshfs_flush(const char *path, struct fuse_file_info *fi) { - int err; - struct sshfs_file *sf = get_sshfs_file(fi); - struct list_head write_reqs; - struct list_head *curr_list; - - if (!sshfs_file_is_conn(sf)) - return -EIO; - - if (sshfs.sync_write) - return 0; - - (void) path; - pthread_mutex_lock(&sshfs.lock); - if (!list_empty(&sf->write_reqs)) { - curr_list = sf->write_reqs.prev; - list_del(&sf->write_reqs); - list_init(&sf->write_reqs); - list_add(&write_reqs, curr_list); - while (!list_empty(&write_reqs)) - pthread_cond_wait(&sf->write_finished, &sshfs.lock); - } - err = sf->write_error; - sf->write_error = 0; - pthread_mutex_unlock(&sshfs.lock); - return err; + int err; + struct sshfs_file *sf = get_sshfs_file(fi); + struct list_head write_reqs; + struct list_head *curr_list; + + if (!sshfs_file_is_conn(sf)) + return -EIO; + + if (sshfs.sync_write) + return 0; + + (void) path; + pthread_mutex_lock(&sshfs.lock); + if (!list_empty(&sf->write_reqs)) { + curr_list = sf->write_reqs.prev; + list_del(&sf->write_reqs); + list_init(&sf->write_reqs); + list_add(&write_reqs, curr_list); + while (!list_empty(&write_reqs)) + pthread_cond_wait(&sf->write_finished, &sshfs.lock); + } + err = sf->write_error; + sf->write_error = 0; + pthread_mutex_unlock(&sshfs.lock); + return err; } static int sshfs_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { - (void) isdatasync; - return sshfs_flush(path, fi); + (void) isdatasync; + return sshfs_flush(path, fi); } static void sshfs_file_put(struct sshfs_file *sf) { - sf->refs--; - if (!sf->refs) - g_free(sf); + sf->refs--; + if (!sf->refs) + g_free(sf); } static struct sshfs_file *sshfs_file_get(struct sshfs_file *sf) { - sf->refs++; - return sf; + sf->refs++; + return sf; } static int sshfs_release(const char *path, struct fuse_file_info *fi) { - struct sshfs_file *sf = get_sshfs_file(fi); - struct buffer *handle = &sf->handle; - 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); - sshfs_file_put(sf); - return 0; + struct sshfs_file *sf = get_sshfs_file(fi); + struct buffer *handle = &sf->handle; + 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); + sshfs_file_put(sf); + return 0; } static int sshfs_sync_read(struct sshfs_file *sf, char *rbuf, size_t size, off_t offset) { - int err; - struct buffer buf; - struct buffer data; - struct buffer *handle = &sf->handle; - buf_init(&buf, 0); - 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) { - uint32_t retsize; - err = -EIO; - 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); - } else if (err == MY_EOF) - err = 0; - buf_free(&buf); - return err; + int err; + struct buffer buf; + struct buffer data; + struct buffer *handle = &sf->handle; + buf_init(&buf, 0); + 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) { + uint32_t retsize; + err = -EIO; + 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); + } else if (err == MY_EOF) + err = 0; + buf_free(&buf); + return err; } static void sshfs_read_end(struct request *req) { - struct read_chunk *chunk = (struct read_chunk *) req->data; - if (req->error) - chunk->res = req->error; - else if (req->replied) { - chunk->res = -EIO; - - if (req->reply_type == SSH_FXP_STATUS) { - uint32_t serr; - if (buf_get_uint32(&req->reply, &serr) != -1) { - if (serr == SSH_FX_EOF) - chunk->res = 0; - } - } else if (req->reply_type == SSH_FXP_DATA) { - uint32_t retsize; - if (buf_get_uint32(&req->reply, &retsize) != -1) { - if (retsize > chunk->size) - fprintf(stderr, "long read\n"); - else { - chunk->res = retsize; - chunk->data = req->reply; - buf_init(&req->reply, 0); - } - } - } else - fprintf(stderr, "protocol error\n"); - } else - chunk->res = -EIO; - - sem_post(&chunk->ready); - chunk_put(chunk); + struct read_chunk *chunk = (struct read_chunk *) req->data; + if (req->error) + chunk->res = req->error; + else if (req->replied) { + chunk->res = -EIO; + + if (req->reply_type == SSH_FXP_STATUS) { + uint32_t serr; + if (buf_get_uint32(&req->reply, &serr) != -1) { + if (serr == SSH_FX_EOF) + chunk->res = 0; + } + } else if (req->reply_type == SSH_FXP_DATA) { + uint32_t retsize; + if (buf_get_uint32(&req->reply, &retsize) != -1) { + if (retsize > chunk->size) + fprintf(stderr, "long read\n"); + else { + chunk->res = retsize; + chunk->data = req->reply; + buf_init(&req->reply, 0); + } + } + } else + fprintf(stderr, "protocol error\n"); + } else + chunk->res = -EIO; + + sem_post(&chunk->ready); + chunk_put(chunk); } static void sshfs_read_begin(struct request *req) { - struct read_chunk *chunk = (struct read_chunk *) req->data; - chunk->refs++; + struct read_chunk *chunk = (struct read_chunk *) req->data; + chunk->refs++; } static void sshfs_send_async_read(struct sshfs_file *sf, struct read_chunk *chunk) { - struct buffer buf; - struct buffer *handle = &sf->handle; - struct iovec iov; + struct buffer buf; + struct buffer *handle = &sf->handle; + struct iovec iov; - buf_init(&buf, 0); - buf_add_buf(&buf, handle); - buf_add_uint64(&buf, chunk->offset); - buf_add_uint32(&buf, chunk->size); - buf_to_iov(&buf, &iov); - sftp_request_send(SSH_FXP_READ, &iov, 1, sshfs_read_begin, sshfs_read_end, - 0, chunk, NULL); - buf_free(&buf); + buf_init(&buf, 0); + buf_add_buf(&buf, handle); + buf_add_uint64(&buf, chunk->offset); + buf_add_uint32(&buf, chunk->size); + buf_to_iov(&buf, &iov); + sftp_request_send(SSH_FXP_READ, &iov, 1, sshfs_read_begin, + sshfs_read_end, 0, chunk, NULL); + buf_free(&buf); } static void submit_read(struct sshfs_file *sf, size_t size, off_t offset, struct read_chunk **chunkp) { - struct read_chunk *chunk = g_new0(struct read_chunk, 1); + struct read_chunk *chunk = g_new0(struct read_chunk, 1); - sem_init(&chunk->ready, 0, 0); - buf_init(&chunk->data, 0); - chunk->offset = offset; - chunk->size = size; - chunk->refs = 1; - chunk->modifver = sshfs.modifver; - sshfs_send_async_read(sf, chunk); - pthread_mutex_lock(&sshfs.lock); - chunk_put(*chunkp); - *chunkp = chunk; - pthread_mutex_unlock(&sshfs.lock); + sem_init(&chunk->ready, 0, 0); + buf_init(&chunk->data, 0); + chunk->offset = offset; + chunk->size = size; + chunk->refs = 1; + chunk->modifver = sshfs.modifver; + sshfs_send_async_read(sf, chunk); + pthread_mutex_lock(&sshfs.lock); + chunk_put(*chunkp); + *chunkp = chunk; + pthread_mutex_unlock(&sshfs.lock); } static int wait_chunk(struct read_chunk *chunk, char *buf, size_t size) { - int res; - while (sem_wait(&chunk->ready)); - res = chunk->res; - if (res > 0) { - if ((size_t) res > size) - res = size; - buf_get_mem(&chunk->data, buf, res); - chunk->offset += res; - chunk->size -= res; - chunk->res -= res; - } - sem_post(&chunk->ready); - chunk_put_locked(chunk); - return res; + int res; + while (sem_wait(&chunk->ready)); + res = chunk->res; + if (res > 0) { + if ((size_t) res > size) + res = size; + buf_get_mem(&chunk->data, buf, res); + chunk->offset += res; + chunk->size -= res; + chunk->res -= res; + } + sem_post(&chunk->ready); + chunk_put_locked(chunk); + return res; } static struct read_chunk *search_read_chunk(struct sshfs_file *sf, off_t offset) { - struct read_chunk *ch = sf->readahead; - if (ch && ch->offset == offset && ch->modifver == sshfs.modifver) { - ch->refs++; - return ch; - } else - return NULL; + struct read_chunk *ch = sf->readahead; + if (ch && ch->offset == offset && ch->modifver == sshfs.modifver) { + ch->refs++; + return ch; + } else + return NULL; } static int sshfs_async_read(struct sshfs_file *sf, char *rbuf, size_t size, off_t offset) { - int res = 0; - size_t total = 0; - struct read_chunk *chunk; - struct read_chunk *chunk_prev = NULL; - size_t origsize = size; - int curr_is_seq; - - pthread_mutex_lock(&sshfs.lock); - curr_is_seq = sf->is_seq; - sf->is_seq = (sf->next_pos == offset && sf->modifver == sshfs.modifver); - sf->next_pos = offset + size; - sf->modifver = sshfs.modifver; - chunk = search_read_chunk(sf, offset); - pthread_mutex_unlock(&sshfs.lock); - - if (chunk && chunk->size < size) { - chunk_prev = chunk; - size -= chunk->size; - offset += chunk->size; - chunk = NULL; - } - - if (!chunk) - submit_read(sf, size, offset, &chunk); - - if (curr_is_seq && chunk && chunk->size <= size) - submit_read(sf, origsize, offset + size, &sf->readahead); - - if (chunk_prev) { - size_t prev_size = chunk_prev->size; - res = wait_chunk(chunk_prev, rbuf, prev_size); - if (res < (int) prev_size) { - chunk_put_locked(chunk); - return res; - } - rbuf += res; - total += res; - } - res = wait_chunk(chunk, rbuf, size); - if (res > 0) - total += res; - if (res < 0) - return res; - - return total; + int res = 0; + size_t total = 0; + struct read_chunk *chunk; + struct read_chunk *chunk_prev = NULL; + size_t origsize = size; + int curr_is_seq; + + pthread_mutex_lock(&sshfs.lock); + curr_is_seq = sf->is_seq; + sf->is_seq = (sf->next_pos == offset && sf->modifver == sshfs.modifver); + sf->next_pos = offset + size; + sf->modifver = sshfs.modifver; + chunk = search_read_chunk(sf, offset); + pthread_mutex_unlock(&sshfs.lock); + + if (chunk && chunk->size < size) { + chunk_prev = chunk; + size -= chunk->size; + offset += chunk->size; + chunk = NULL; + } + + if (!chunk) + submit_read(sf, size, offset, &chunk); + + if (curr_is_seq && chunk && chunk->size <= size) + submit_read(sf, origsize, offset + size, &sf->readahead); + + if (chunk_prev) { + size_t prev_size = chunk_prev->size; + res = wait_chunk(chunk_prev, rbuf, prev_size); + if (res < (int) prev_size) { + chunk_put_locked(chunk); + return res; + } + rbuf += res; + total += res; + } + res = wait_chunk(chunk, rbuf, size); + if (res > 0) + total += res; + if (res < 0) + return res; + + return total; } static int sshfs_read(const char *path, char *rbuf, size_t size, off_t offset, struct fuse_file_info *fi) { - struct sshfs_file *sf = get_sshfs_file(fi); - (void) path; + struct sshfs_file *sf = get_sshfs_file(fi); + (void) path; - if (!sshfs_file_is_conn(sf)) - return -EIO; + if (!sshfs_file_is_conn(sf)) + return -EIO; - if (sshfs.sync_read) - return sshfs_sync_read(sf, rbuf, size, offset); - else - return sshfs_async_read(sf, rbuf, size, offset); + if (sshfs.sync_read) + return sshfs_sync_read(sf, rbuf, size, offset); + else + return sshfs_async_read(sf, rbuf, size, offset); } static void sshfs_write_begin(struct request *req) { - struct sshfs_file *sf = (struct sshfs_file *) req->data; - list_add(&req->list, &sf->write_reqs); + struct sshfs_file *sf = (struct sshfs_file *) req->data; + list_add(&req->list, &sf->write_reqs); } static void sshfs_write_end(struct request *req) { - uint32_t serr; - struct sshfs_file *sf = (struct sshfs_file *) req->data; + uint32_t serr; + struct sshfs_file *sf = (struct sshfs_file *) req->data; - 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) - sf->write_error = -EIO; - } - list_del(&req->list); - pthread_cond_broadcast(&sf->write_finished); - sshfs_file_put(sf); + 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) { + sf->write_error = -EIO; + } + } + list_del(&req->list); + pthread_cond_broadcast(&sf->write_finished); + sshfs_file_put(sf); } static int sshfs_write(const char *path, const char *wbuf, size_t size, off_t offset, struct fuse_file_info *fi) { - int err; - struct buffer buf; - struct sshfs_file *sf = get_sshfs_file(fi); - struct buffer *handle = &sf->handle; - struct iovec iov[2]; - - (void) path; - - if (!sshfs_file_is_conn(sf)) - return -EIO; - - sshfs.modifver ++; - buf_init(&buf, 0); - buf_add_buf(&buf, handle); - buf_add_uint64(&buf, offset); - buf_add_uint32(&buf, size); - buf_to_iov(&buf, &iov[0]); - iov[1].iov_base = (void *) wbuf; - iov[1].iov_len = size; - if (!sshfs.sync_write && !sf->write_error) - err = sftp_request_send(SSH_FXP_WRITE, iov, 2, sshfs_write_begin, - sshfs_write_end, 0, sshfs_file_get(sf), NULL); - else - err = sftp_request_iov(SSH_FXP_WRITE, iov, 2, SSH_FXP_STATUS, NULL); - buf_free(&buf); - return err ? err : (int) size; + int err; + struct buffer buf; + struct sshfs_file *sf = get_sshfs_file(fi); + struct buffer *handle = &sf->handle; + struct iovec iov[2]; + + (void) path; + + if (!sshfs_file_is_conn(sf)) + return -EIO; + + sshfs.modifver ++; + buf_init(&buf, 0); + buf_add_buf(&buf, handle); + buf_add_uint64(&buf, offset); + buf_add_uint32(&buf, size); + buf_to_iov(&buf, &iov[0]); + iov[1].iov_base = (void *) wbuf; + iov[1].iov_len = size; + if (!sshfs.sync_write && !sf->write_error) { + err = sftp_request_send(SSH_FXP_WRITE, iov, 2, + sshfs_write_begin, sshfs_write_end, + 0, sshfs_file_get(sf), NULL); + } else { + err = sftp_request_iov(SSH_FXP_WRITE, iov, 2, SSH_FXP_STATUS, + NULL); + } + buf_free(&buf); + return err ? err : (int) size; } #if FUSE_VERSION >= 25 static int sshfs_statfs(const char *path, struct statvfs *buf) { - (void) path; + (void) path; - buf->f_namemax = 255; - buf->f_bsize = sshfs.blksize; - /* df seems to use f_bsize instead of f_frsize, so make them the same */ - buf->f_frsize = buf->f_bsize; - buf->f_blocks = buf->f_bfree = buf->f_bavail = - 1000ULL * 1024 * 1024 * 1024 / buf->f_frsize; - buf->f_files = buf->f_ffree = 1000000000; - return 0; + buf->f_namemax = 255; + buf->f_bsize = sshfs.blksize; + /* + * df seems to use f_bsize instead of f_frsize, so make them + * the same + */ + buf->f_frsize = buf->f_bsize; + buf->f_blocks = buf->f_bfree = buf->f_bavail = + 1000ULL * 1024 * 1024 * 1024 / buf->f_frsize; + buf->f_files = buf->f_ffree = 1000000000; + return 0; } #else static int sshfs_statfs(const char *path, struct statfs *buf) { - (void) path; + (void) path; - buf->f_namelen = 255; - buf->f_bsize = sshfs.blksize; - buf->f_blocks = buf->f_bfree = buf->f_bavail = - 1000ULL * 1024 * 1024 * 1024 / buf->f_bsize; - buf->f_files = buf->f_ffree = 1000000000; - return 0; + buf->f_namelen = 255; + buf->f_bsize = sshfs.blksize; + buf->f_blocks = buf->f_bfree = buf->f_bavail = + 1000ULL * 1024 * 1024 * 1024 / buf->f_bsize; + buf->f_files = buf->f_ffree = 1000000000; + return 0; } #endif @@ -2201,146 +2247,146 @@ static int sshfs_statfs(const char *path, struct statfs *buf) static int sshfs_create(const char *path, mode_t mode, struct fuse_file_info *fi) { - return sshfs_open_common(path, mode, fi); + return sshfs_open_common(path, mode, fi); } static int sshfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) { - int err; - struct buffer buf; - struct sshfs_file *sf = get_sshfs_file(fi); + int err; + struct buffer buf; + struct sshfs_file *sf = get_sshfs_file(fi); - (void) path; + (void) path; - if (!sshfs_file_is_conn(sf)) - return -EIO; + if (!sshfs_file_is_conn(sf)) + return -EIO; - sshfs.modifver ++; - if (sshfs.truncate_workaround) - return sshfs_truncate_workaround(path, size, fi); + sshfs.modifver ++; + if (sshfs.truncate_workaround) + return sshfs_truncate_workaround(path, size, fi); - buf_init(&buf, 0); - buf_add_buf(&buf, &sf->handle); - buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE); - buf_add_uint64(&buf, size); - err = sftp_request(SSH_FXP_FSETSTAT, &buf, SSH_FXP_STATUS, NULL); - buf_free(&buf); + buf_init(&buf, 0); + buf_add_buf(&buf, &sf->handle); + buf_add_uint32(&buf, SSH_FILEXFER_ATTR_SIZE); + buf_add_uint64(&buf, size); + err = sftp_request(SSH_FXP_FSETSTAT, &buf, SSH_FXP_STATUS, NULL); + buf_free(&buf); - return err; + return err; } #endif static int sshfs_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { - int err; - struct buffer buf; - struct buffer outbuf; - struct sshfs_file *sf = get_sshfs_file(fi); + int err; + struct buffer buf; + struct buffer outbuf; + struct sshfs_file *sf = get_sshfs_file(fi); - (void) path; + (void) path; - if (!sshfs_file_is_conn(sf)) - return -EIO; + if (!sshfs_file_is_conn(sf)) + return -EIO; - buf_init(&buf, 0); - buf_add_buf(&buf, &sf->handle); - err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf); - if (!err) { - if (buf_get_attrs(&outbuf, stbuf, NULL) == -1) - err = -EIO; - buf_free(&outbuf); - } - buf_free(&buf); - return err; + buf_init(&buf, 0); + buf_add_buf(&buf, &sf->handle); + err = sftp_request(SSH_FXP_FSTAT, &buf, SSH_FXP_ATTRS, &outbuf); + if (!err) { + if (buf_get_attrs(&outbuf, stbuf, NULL) == -1) + err = -EIO; + buf_free(&outbuf); + } + buf_free(&buf); + return err; } static int sshfs_truncate_zero(const char *path) { - int err; - struct fuse_file_info fi; + int err; + struct fuse_file_info fi; - fi.flags = O_WRONLY | O_TRUNC; - err = sshfs_open(path, &fi); - if (!err) - sshfs_release(path, &fi); + fi.flags = O_WRONLY | O_TRUNC; + err = sshfs_open(path, &fi); + if (!err) + sshfs_release(path, &fi); - return err; + return err; } static size_t calc_buf_size(off_t size, off_t offset) { - return offset + sshfs.max_read < size ? sshfs.max_read : size - offset; + return offset + sshfs.max_read < size ? sshfs.max_read : size - offset; } static int sshfs_truncate_shrink(const char *path, off_t size) { - int res; - char *data; - off_t offset; - struct fuse_file_info fi; - - data = calloc(size, 1); - if (!data) - return -ENOMEM; - - fi.flags = O_RDONLY; - res = sshfs_open(path, &fi); - if (res) - goto out; - - for (offset = 0; offset < size; offset += res) { - size_t bufsize = calc_buf_size(size, offset); - res = sshfs_read(path, data + offset, bufsize, offset, &fi); - if (res <= 0) - break; - } - sshfs_release(path, &fi); - if (res < 0) - goto out; - - fi.flags = O_WRONLY | O_TRUNC; - res = sshfs_open(path, &fi); - if (res) - goto out; - - for (offset = 0; offset < size; offset += res) { - size_t bufsize = calc_buf_size(size, offset); - res = sshfs_write(path, data + offset, bufsize, offset, &fi); - if (res < 0) - break; - } - if (res >= 0) - res = sshfs_flush(path, &fi); - sshfs_release(path, &fi); - - out: - free(data); - return res; + int res; + char *data; + off_t offset; + struct fuse_file_info fi; + + data = calloc(size, 1); + if (!data) + return -ENOMEM; + + fi.flags = O_RDONLY; + res = sshfs_open(path, &fi); + if (res) + goto out; + + for (offset = 0; offset < size; offset += res) { + size_t bufsize = calc_buf_size(size, offset); + res = sshfs_read(path, data + offset, bufsize, offset, &fi); + if (res <= 0) + break; + } + sshfs_release(path, &fi); + if (res < 0) + goto out; + + fi.flags = O_WRONLY | O_TRUNC; + res = sshfs_open(path, &fi); + if (res) + goto out; + + for (offset = 0; offset < size; offset += res) { + size_t bufsize = calc_buf_size(size, offset); + res = sshfs_write(path, data + offset, bufsize, offset, &fi); + if (res < 0) + break; + } + if (res >= 0) + res = sshfs_flush(path, &fi); + sshfs_release(path, &fi); + +out: + free(data); + return res; } static int sshfs_truncate_extend(const char *path, off_t size, struct fuse_file_info *fi) { - int res; - char c = 0; - struct fuse_file_info tmpfi; - struct fuse_file_info *openfi = fi; - if (!fi) { - openfi = &tmpfi; - openfi->flags = O_WRONLY; - res = sshfs_open(path, openfi); - if (res) - return res; - } - res = sshfs_write(path, &c, 1, size - 1, openfi); - if (res == 1) - res = sshfs_flush(path, openfi); - if (!fi) - sshfs_release(path, openfi); - - return res; + int res; + char c = 0; + struct fuse_file_info tmpfi; + struct fuse_file_info *openfi = fi; + if (!fi) { + openfi = &tmpfi; + openfi->flags = O_WRONLY; + res = sshfs_open(path, openfi); + if (res) + return res; + } + res = sshfs_write(path, &c, 1, size - 1, openfi); + if (res == 1) + res = sshfs_flush(path, openfi); + if (!fi) + sshfs_release(path, openfi); + + return res; } /* @@ -2358,75 +2404,75 @@ static int sshfs_truncate_extend(const char *path, off_t size, static int sshfs_truncate_workaround(const char *path, off_t size, struct fuse_file_info *fi) { - if (size == 0) - return sshfs_truncate_zero(path); - else { - struct stat stbuf; - int err; - if (fi) - err = sshfs_fgetattr(path, &stbuf, fi); - else - err = sshfs_getattr(path, &stbuf); - if (err) - return err; - if (stbuf.st_size == size) - return 0; - else if (stbuf.st_size > size) - return sshfs_truncate_shrink(path, size); - else - return sshfs_truncate_extend(path, size, fi); - } + if (size == 0) + return sshfs_truncate_zero(path); + else { + struct stat stbuf; + int err; + if (fi) + err = sshfs_fgetattr(path, &stbuf, fi); + else + err = sshfs_getattr(path, &stbuf); + if (err) + return err; + if (stbuf.st_size == size) + return 0; + else if (stbuf.st_size > size) + return sshfs_truncate_shrink(path, size); + else + return sshfs_truncate_extend(path, size, fi); + } } static int processing_init(void) { - pthread_mutex_init(&sshfs.lock, NULL); - pthread_mutex_init(&sshfs.lock_write, NULL); - pthread_cond_init(&sshfs.outstanding_cond, NULL); - sshfs.reqtab = g_hash_table_new(NULL, NULL); - if (!sshfs.reqtab) { - fprintf(stderr, "failed to create hash table\n"); - return -1; - } - return 0; + pthread_mutex_init(&sshfs.lock, NULL); + pthread_mutex_init(&sshfs.lock_write, NULL); + pthread_cond_init(&sshfs.outstanding_cond, NULL); + sshfs.reqtab = g_hash_table_new(NULL, NULL); + if (!sshfs.reqtab) { + fprintf(stderr, "failed to create hash table\n"); + return -1; + } + return 0; } static struct fuse_cache_operations sshfs_oper = { - .oper = { + .oper = { #ifdef SSHFS_USE_INIT - .init = sshfs_init, + .init = sshfs_init, #endif - .getattr = sshfs_getattr, - .readlink = sshfs_readlink, - .mknod = sshfs_mknod, - .mkdir = sshfs_mkdir, - .symlink = sshfs_symlink, - .unlink = sshfs_unlink, - .rmdir = sshfs_rmdir, - .rename = sshfs_rename, - .chmod = sshfs_chmod, - .chown = sshfs_chown, - .truncate = sshfs_truncate, - .utime = sshfs_utime, - .open = sshfs_open, - .flush = sshfs_flush, - .fsync = sshfs_fsync, - .release = sshfs_release, - .read = sshfs_read, - .write = sshfs_write, - .statfs = sshfs_statfs, + .getattr = sshfs_getattr, + .readlink = sshfs_readlink, + .mknod = sshfs_mknod, + .mkdir = sshfs_mkdir, + .symlink = sshfs_symlink, + .unlink = sshfs_unlink, + .rmdir = sshfs_rmdir, + .rename = sshfs_rename, + .chmod = sshfs_chmod, + .chown = sshfs_chown, + .truncate = sshfs_truncate, + .utime = sshfs_utime, + .open = sshfs_open, + .flush = sshfs_flush, + .fsync = sshfs_fsync, + .release = sshfs_release, + .read = sshfs_read, + .write = sshfs_write, + .statfs = sshfs_statfs, #if FUSE_VERSION >= 25 - .create = sshfs_create, - .ftruncate = sshfs_ftruncate, - .fgetattr = sshfs_fgetattr, + .create = sshfs_create, + .ftruncate = sshfs_ftruncate, + .fgetattr = sshfs_fgetattr, #endif - }, - .cache_getdir = sshfs_getdir, + }, + .cache_getdir = sshfs_getdir, }; static void usage(const char *progname) { - fprintf(stderr, + fprintf(stderr, "usage: %s [user@]host:[dir] mountpoint [options]\n" "\n" "general options:\n" @@ -2471,245 +2517,253 @@ static void usage(const char *progname) static int is_ssh_opt(const char *arg) { - if (arg[0] != '-') { - unsigned arglen = strlen(arg); - const char **o; - for (o = ssh_opts; *o; o++) { - unsigned olen = strlen(*o); - if (arglen > olen && arg[olen] == '=' && - strncasecmp(arg, *o, olen) == 0) - return 1; - } - } - return 0; + if (arg[0] != '-') { + unsigned arglen = strlen(arg); + const char **o; + for (o = ssh_opts; *o; o++) { + unsigned olen = strlen(*o); + if (arglen > olen && arg[olen] == '=' && + strncasecmp(arg, *o, olen) == 0) + return 1; + } + } + return 0; } static int sshfs_fuse_main(struct fuse_args *args) { #if FUSE_VERSION >= 26 - return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper), NULL); + return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper), NULL); #else - return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper)); + return fuse_main(args->argc, args->argv, cache_init(&sshfs_oper)); #endif } static int sshfs_opt_proc(void *data, const char *arg, int key, struct fuse_args *outargs) { - char *tmp; - (void) data; - - switch (key) { - case FUSE_OPT_KEY_OPT: - if (is_ssh_opt(arg)) { - tmp = g_strdup_printf("-o%s", arg); - ssh_add_arg(tmp); - g_free(tmp); - return 0; - } - return 1; - - case FUSE_OPT_KEY_NONOPT: - if (!sshfs.host && strchr(arg, ':')) { - sshfs.host = strdup(arg); - return 0; - } - return 1; - - case KEY_PORT: - tmp = g_strdup_printf("-oPort=%s", arg + 2); - ssh_add_arg(tmp); - g_free(tmp); - return 0; - - case KEY_COMPRESS: - ssh_add_arg("-oCompression=yes"); - return 0; - - case KEY_HELP: - usage(outargs->argv[0]); - fuse_opt_add_arg(outargs, "-ho"); - sshfs_fuse_main(outargs); - exit(1); - - case KEY_VERSION: - fprintf(stderr, "SSHFS version %s\n", PACKAGE_VERSION); + char *tmp; + (void) data; + + switch (key) { + case FUSE_OPT_KEY_OPT: + if (is_ssh_opt(arg)) { + tmp = g_strdup_printf("-o%s", arg); + ssh_add_arg(tmp); + g_free(tmp); + return 0; + } + return 1; + + case FUSE_OPT_KEY_NONOPT: + if (!sshfs.host && strchr(arg, ':')) { + sshfs.host = strdup(arg); + return 0; + } + return 1; + + case KEY_PORT: + tmp = g_strdup_printf("-oPort=%s", arg + 2); + ssh_add_arg(tmp); + g_free(tmp); + return 0; + + case KEY_COMPRESS: + ssh_add_arg("-oCompression=yes"); + return 0; + + case KEY_HELP: + usage(outargs->argv[0]); + fuse_opt_add_arg(outargs, "-ho"); + sshfs_fuse_main(outargs); + exit(1); + + case KEY_VERSION: + fprintf(stderr, "SSHFS version %s\n", PACKAGE_VERSION); #if FUSE_VERSION >= 25 - fuse_opt_add_arg(outargs, "--version"); - sshfs_fuse_main(outargs); + fuse_opt_add_arg(outargs, "--version"); + sshfs_fuse_main(outargs); #endif - exit(0); + exit(0); - default: - fprintf(stderr, "internal error\n"); - abort(); - } + default: + fprintf(stderr, "internal error\n"); + abort(); + } } static int workaround_opt_proc(void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { - (void) data; (void) key; (void) outargs; - fprintf(stderr, "unknown workaround: '%s'\n", arg); - return -1; + (void) data; (void) key; (void) outargs; + fprintf(stderr, "unknown workaround: '%s'\n", arg); + return -1; } int parse_workarounds(void) { - int res; - char *argv[] = { "", "-o", sshfs.workarounds, NULL }; - struct fuse_args args = FUSE_ARGS_INIT(3, argv); - char *s = sshfs.workarounds; - if (!s) - return 0; + int res; + char *argv[] = { "", "-o", sshfs.workarounds, NULL }; + struct fuse_args args = FUSE_ARGS_INIT(3, argv); + char *s = sshfs.workarounds; + if (!s) + return 0; - while ((s = strchr(s, ':'))) - *s = ','; + while ((s = strchr(s, ':'))) + *s = ','; - res = fuse_opt_parse(&args, &sshfs, workaround_opts, workaround_opt_proc); - fuse_opt_free_args(&args); + res = fuse_opt_parse(&args, &sshfs, workaround_opts, + workaround_opt_proc); + fuse_opt_free_args(&args); - return res; + return res; } #if FUSE_VERSION == 25 static int fuse_opt_insert_arg(struct fuse_args *args, int pos, const char *arg) { - assert(pos <= args->argc); - if (fuse_opt_add_arg(args, arg) == -1) - return -1; + assert(pos <= args->argc); + if (fuse_opt_add_arg(args, arg) == -1) + return -1; - if (pos != args->argc - 1) { - char *newarg = args->argv[args->argc - 1]; - memmove(&args->argv[pos + 1], &args->argv[pos], - sizeof(char *) * (args->argc - pos - 1)); - args->argv[pos] = newarg; - } - return 0; + if (pos != args->argc - 1) { + char *newarg = args->argv[args->argc - 1]; + memmove(&args->argv[pos + 1], &args->argv[pos], + sizeof(char *) * (args->argc - pos - 1)); + args->argv[pos] = newarg; + } + return 0; } #endif void check_large_read(struct fuse_args *args) { - struct utsname buf; - int err = uname(&buf); - if (!err && strcmp(buf.sysname, "Linux") == 0 && - strncmp(buf.release, "2.4.", 4) == 0) - fuse_opt_insert_arg(args, 1, "-olarge_read"); + struct utsname buf; + int err = uname(&buf); + if (!err && strcmp(buf.sysname, "Linux") == 0 && + strncmp(buf.release, "2.4.", 4) == 0) + fuse_opt_insert_arg(args, 1, "-olarge_read"); } int main(int argc, char *argv[]) { - int res; - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - char *tmp; - char *fsname; - char *base_path; - const char *sftp_server; - - g_thread_init(NULL); - - sshfs.blksize = 4096; - sshfs.max_read = 65536; - sshfs.nodelay_workaround = 1; - sshfs.nodelaysrv_workaround = 0; - sshfs.rename_workaround = 0; - sshfs.truncate_workaround = 0; - sshfs.buflimit_workaround = 1; - sshfs.ssh_ver = 2; - sshfs.progname = argv[0]; - ssh_add_arg("ssh"); - ssh_add_arg("-x"); - ssh_add_arg("-a"); - ssh_add_arg("-oClearAllForwardings=yes"); - - if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1 || - parse_workarounds() == -1) - exit(1); - - if (sshfs.buflimit_workaround) - /* Work around buggy sftp-server in OpenSSH. Without this on - a slow server a 10Mbyte buffer would fill up and the server - would abort */ - sshfs.max_outstanding_len = 8388608; - else - sshfs.max_outstanding_len = ~0; - - if (!sshfs.host) { - fprintf(stderr, "missing host\n"); - fprintf(stderr, "see `%s -h' for usage\n", argv[0]); - exit(1); - } - - fsname = g_strdup(sshfs.host); - base_path = strchr(sshfs.host, ':'); - *base_path++ = '\0'; - if (base_path[0] && base_path[strlen(base_path)-1] != '/') - sshfs.base_path = g_strdup_printf("%s/", base_path); - else - sshfs.base_path = g_strdup(base_path); - - if (sshfs.ssh_command) { - free(sshfs.ssh_args.argv[0]); - sshfs.ssh_args.argv[0] = sshfs.ssh_command; - } - - tmp = g_strdup_printf("-%i", sshfs.ssh_ver); - ssh_add_arg(tmp); - g_free(tmp); - ssh_add_arg(sshfs.host); - if (sshfs.sftp_server) - sftp_server = sshfs.sftp_server; - else if (sshfs.ssh_ver == 1) - sftp_server = SFTP_SERVER_PATH; - else - sftp_server = "sftp"; - - if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL) - ssh_add_arg("-s"); - - ssh_add_arg(sftp_server); - free(sshfs.sftp_server); - - res = processing_init(); - if (res == -1) - exit(1); - - if (connect_remote() == -1) - exit(1); + int res; + struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + char *tmp; + char *fsname; + char *base_path; + const char *sftp_server; + int libver; + + g_thread_init(NULL); + + sshfs.blksize = 4096; + sshfs.max_read = 65536; + sshfs.nodelay_workaround = 1; + sshfs.nodelaysrv_workaround = 0; + sshfs.rename_workaround = 0; + sshfs.truncate_workaround = 0; + sshfs.buflimit_workaround = 1; + sshfs.ssh_ver = 2; + sshfs.progname = argv[0]; + ssh_add_arg("ssh"); + ssh_add_arg("-x"); + ssh_add_arg("-a"); + ssh_add_arg("-oClearAllForwardings=yes"); + + if (fuse_opt_parse(&args, &sshfs, sshfs_opts, sshfs_opt_proc) == -1 || + parse_workarounds() == -1) + exit(1); + + if (sshfs.buflimit_workaround) + /* Work around buggy sftp-server in OpenSSH. Without this on + a slow server a 10Mbyte buffer would fill up and the server + would abort */ + sshfs.max_outstanding_len = 8388608; + else + sshfs.max_outstanding_len = ~0; + + if (!sshfs.host) { + fprintf(stderr, "missing host\n"); + fprintf(stderr, "see `%s -h' for usage\n", argv[0]); + exit(1); + } + + fsname = g_strdup(sshfs.host); + base_path = strchr(sshfs.host, ':'); + *base_path++ = '\0'; + if (base_path[0] && base_path[strlen(base_path)-1] != '/') + sshfs.base_path = g_strdup_printf("%s/", base_path); + else + sshfs.base_path = g_strdup(base_path); + + if (sshfs.ssh_command) { + free(sshfs.ssh_args.argv[0]); + sshfs.ssh_args.argv[0] = sshfs.ssh_command; + } + + tmp = g_strdup_printf("-%i", sshfs.ssh_ver); + ssh_add_arg(tmp); + g_free(tmp); + ssh_add_arg(sshfs.host); + if (sshfs.sftp_server) + sftp_server = sshfs.sftp_server; + else if (sshfs.ssh_ver == 1) + sftp_server = SFTP_SERVER_PATH; + else + sftp_server = "sftp"; + + if (sshfs.ssh_ver != 1 && strchr(sftp_server, '/') == NULL) + ssh_add_arg("-s"); + + ssh_add_arg(sftp_server); + free(sshfs.sftp_server); + + res = processing_init(); + if (res == -1) + exit(1); + + if (connect_remote() == -1) + exit(1); #ifndef SSHFS_USE_INIT - if (sshfs.detect_uid) - sftp_detect_uid(); + if (sshfs.detect_uid) + sftp_detect_uid(); #endif - if (!sshfs.no_check_root && sftp_check_root(base_path) == -1) - exit(1); - - res = cache_parse_options(&args); - if (res == -1) - exit(1); - - sshfs.randseed = time(0); - - if (sshfs.max_read > 65536) - sshfs.max_read = 65536; - - if (fuse_is_lib_option("ac_attr_timeout=")) - fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0"); - tmp = g_strdup_printf("-omax_read=%u", sshfs.max_read); - fuse_opt_insert_arg(&args, 1, tmp); - g_free(tmp); - tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname); - fuse_opt_insert_arg(&args, 1, tmp); - check_large_read(&args); - g_free(tmp); - g_free(fsname); - res = sshfs_fuse_main(&args); - fuse_opt_free_args(&args); - fuse_opt_free_args(&sshfs.ssh_args); - free(sshfs.directport); - - return res; + if (!sshfs.no_check_root && sftp_check_root(base_path) == -1) + exit(1); + + res = cache_parse_options(&args); + if (res == -1) + exit(1); + + sshfs.randseed = time(0); + + if (sshfs.max_read > 65536) + sshfs.max_read = 65536; + + if (fuse_is_lib_option("ac_attr_timeout=")) + fuse_opt_insert_arg(&args, 1, "-oauto_cache,ac_attr_timeout=0"); + tmp = g_strdup_printf("-omax_read=%u", sshfs.max_read); + fuse_opt_insert_arg(&args, 1, tmp); + g_free(tmp); +#if FUSE_VERSION >= 27 + libver = fuse_version(); + assert(libver >= 27); + tmp = g_strdup_printf("-osubtype=sshfs,fsname=%s", fsname); +#else + tmp = g_strdup_printf("-ofsname=sshfs#%s", fsname); +#endif + fuse_opt_insert_arg(&args, 1, tmp); + g_free(tmp); + g_free(fsname); + check_large_read(&args); + res = sshfs_fuse_main(&args); + fuse_opt_free_args(&args); + fuse_opt_free_args(&sshfs.ssh_args); + free(sshfs.directport); + + return res; } diff --git a/sshnodelay.c b/sshnodelay.c index 03a4756..7518089 100644 --- a/sshnodelay.c +++ b/sshnodelay.c @@ -7,12 +7,12 @@ int connect(int sock, const struct sockaddr *addr, socklen_t addrlen) { - int (*next_connect)(int, const struct sockaddr *, socklen_t) = - dlsym(RTLD_NEXT, "connect"); - int res = next_connect(sock, addr, addrlen); - if (!res && addr->sa_family == AF_INET) { - int opt = 1; - setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); - } - return res; + int (*next_connect)(int, const struct sockaddr *, socklen_t) = + dlsym(RTLD_NEXT, "connect"); + int res = next_connect(sock, addr, addrlen); + if (!res && addr->sa_family == AF_INET) { + int opt = 1; + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + } + return res; } -- cgit v1.2.3