aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fuse/dir.c4
-rw-r--r--fs/fuse/fuse_i.h4
-rw-r--r--fs/fuse/inode.c12
3 files changed, 18 insertions, 2 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 9ee2a6bbfa37..8ea4ea13ec5f 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1054,8 +1054,10 @@ static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1054 if (fi->i_time < get_jiffies_64()) 1054 if (fi->i_time < get_jiffies_64())
1055 err = fuse_do_getattr(inode); 1055 err = fuse_do_getattr(inode);
1056 1056
1057 if (!err) 1057 if (!err) {
1058 generic_fillattr(inode, stat); 1058 generic_fillattr(inode, stat);
1059 stat->mode = fi->orig_i_mode;
1060 }
1059 1061
1060 return err; 1062 return err;
1061} 1063}
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index e0555d68b4a7..1764506fdd11 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -63,6 +63,10 @@ struct fuse_inode {
63 63
64 /** Time in jiffies until the file attributes are valid */ 64 /** Time in jiffies until the file attributes are valid */
65 u64 i_time; 65 u64 i_time;
66
67 /** The sticky bit in inode->i_mode may have been removed, so
68 preserve the original mode */
69 mode_t orig_i_mode;
66}; 70};
67 71
68/** FUSE specific file data */ 72/** FUSE specific file data */
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 951e760d5c5a..fd0735715c14 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -120,10 +120,11 @@ static void fuse_truncate(struct address_space *mapping, loff_t offset)
120void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) 120void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
121{ 121{
122 struct fuse_conn *fc = get_fuse_conn(inode); 122 struct fuse_conn *fc = get_fuse_conn(inode);
123 struct fuse_inode *fi = get_fuse_inode(inode);
123 loff_t oldsize; 124 loff_t oldsize;
124 125
125 inode->i_ino = attr->ino; 126 inode->i_ino = attr->ino;
126 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); 127 inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777);
127 inode->i_nlink = attr->nlink; 128 inode->i_nlink = attr->nlink;
128 inode->i_uid = attr->uid; 129 inode->i_uid = attr->uid;
129 inode->i_gid = attr->gid; 130 inode->i_gid = attr->gid;
@@ -135,6 +136,15 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
135 inode->i_ctime.tv_sec = attr->ctime; 136 inode->i_ctime.tv_sec = attr->ctime;
136 inode->i_ctime.tv_nsec = attr->ctimensec; 137 inode->i_ctime.tv_nsec = attr->ctimensec;
137 138
139 /*
140 * Don't set the sticky bit in i_mode, unless we want the VFS
141 * to check permissions. This prevents failures due to the
142 * check in may_delete().
143 */
144 fi->orig_i_mode = inode->i_mode;
145 if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
146 inode->i_mode &= ~S_ISVTX;
147
138 spin_lock(&fc->lock); 148 spin_lock(&fc->lock);
139 oldsize = inode->i_size; 149 oldsize = inode->i_size;
140 i_size_write(inode, attr->size); 150 i_size_write(inode, attr->size);