From 642d16587c952aa5997643be2530fb4a42fe8aff Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 28 Oct 2005 12:12:57 +0000 Subject: fix --- ChangeLog | 7 +++++++ cache.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- sshfs.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index cabc129..d4e52b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2005-10-28 Miklos Szeredi + + * Add atomic create+open and ftruncate operation. This should fix + issues with 'cp' and other programs failing with "Permission + denied". Needs FUSE version 2.5 and kernel version 2.6.15 (just a + guess, since neither of them is released yet). + 2005-10-27 Miklos Szeredi * Add support for SSH protocol version 1. Bug reported by Miklos diff --git a/cache.c b/cache.c index 733a451..40ad0e3 100644 --- a/cache.c +++ b/cache.c @@ -192,26 +192,31 @@ static void cache_add_link(const char *path, const char *link, size_t size) pthread_mutex_unlock(&cache_lock); } -static int cache_getattr(const char *path, struct stat *stbuf) +static int cache_get_attr(const char *path, struct stat *stbuf) { struct node *node; - int err; - + 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; - pthread_mutex_unlock(&cache_lock); - return 0; + err = 0; } } pthread_mutex_unlock(&cache_lock); - err = next_oper->oper.getattr(path, stbuf); - if (!err) - cache_add_attr(path, stbuf); + return err; +} +static int cache_getattr(const char *path, struct stat *stbuf) +{ + int err = cache_get_attr(path, stbuf); + if (err) { + err = next_oper->oper.getattr(path, stbuf); + if (!err) + cache_add_attr(path, stbuf); + } return err; } @@ -403,6 +408,38 @@ static int cache_write(const char *path, const char *buf, size_t size, return res; } +#if FUSE_VERSION >= 25 +static int cache_create(const char *path, mode_t mode, + struct fuse_file_info *fi) +{ + int err = 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 = 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 = next_oper->oper.fgetattr(path, stbuf, fi); + if (!err) + cache_add_attr(path, stbuf); + } + return err; +} +#endif + static void cache_unity_fill(struct fuse_cache_operations *oper, struct fuse_operations *cache_oper) { @@ -434,6 +471,11 @@ static void cache_unity_fill(struct fuse_cache_operations *oper, 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; +#endif } struct fuse_operations *cache_init(struct fuse_cache_operations *oper) @@ -458,6 +500,11 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper) 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; +#endif pthread_mutex_init(&cache_lock, NULL); cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_node); diff --git a/sshfs.c b/sshfs.c index 20540e7..c512f76 100644 --- a/sshfs.c +++ b/sshfs.c @@ -1434,6 +1434,9 @@ static int sshfs_open_common(const char *path, mode_t mode, 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); @@ -1778,6 +1781,61 @@ static int sshfs_statfs(const char *path, struct statfs *buf) return 0; } +#if FUSE_VERSION >= 25 +static int sshfs_create(const char *path, mode_t mode, + struct fuse_file_info *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 = (struct sshfs_file *) fi->fh; + + (void) path; + + if (!sshfs_file_is_conn(sf)) + return -EIO; + + 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; +} + +static int sshfs_fgetattr(const char *path, struct stat *stbuf, + struct fuse_file_info *fi) +{ + int err; + struct buffer buf; + struct buffer outbuf; + struct sshfs_file *sf = (struct sshfs_file *) fi->fh; + + (void) path; + + 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 = -EPROTO; + buf_free(&outbuf); + } + buf_free(&buf); + return err; +} +#endif + static int processing_init(void) { pthread_mutex_init(&lock, NULL); @@ -1813,6 +1871,11 @@ static struct fuse_cache_operations sshfs_oper = { .read = sshfs_read, .write = sshfs_write, .statfs = sshfs_statfs, +#if FUSE_VERSION >= 25 + .create = sshfs_create, + .ftruncate = sshfs_ftruncate, + .fgetattr = sshfs_fgetattr, +#endif }, .cache_getdir = sshfs_getdir, }; -- cgit v1.2.3