blob: 2cf0676286bbfcccb577cf1f4ca0b7bc9e28c290 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000012#include <linux/slab.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000013#include <linux/file.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014
Miklos Szeredib483c932001-10-29 14:57:57 +000015static struct inode_operations fuse_dir_inode_operations;
16static struct inode_operations fuse_file_inode_operations;
17static struct inode_operations fuse_symlink_inode_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000018
19static struct file_operations fuse_dir_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000020
Miklos Szeredi307242f2004-01-26 11:28:44 +000021static struct dentry_operations fuse_dentry_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000022
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000023#ifndef KERNEL_2_6
24#define new_decode_dev(x) (x)
25#define new_encode_dev(x) (x)
26#endif
27
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000028static void change_attributes(struct inode *inode, struct fuse_attr *attr)
29{
Miklos Szeredic26c14d2004-04-09 17:48:32 +000030 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) {
Miklos Szeredif85ab242004-01-07 12:16:45 +000031#ifdef KERNEL_2_6
32 invalidate_inode_pages(inode->i_mapping);
33#else
Miklos Szeredia181e612001-11-06 12:03:23 +000034 invalidate_inode_pages(inode);
Miklos Szeredif85ab242004-01-07 12:16:45 +000035#endif
36 }
Miklos Szeredia181e612001-11-06 12:03:23 +000037
Miklos Szeredi5e183482001-10-31 14:52:35 +000038 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000039 inode->i_nlink = attr->nlink;
40 inode->i_uid = attr->uid;
41 inode->i_gid = attr->gid;
Miklos Szeredid1199f82004-02-06 15:29:22 +000042 i_size_write(inode, attr->size);
Miklos Szeredi05033042001-11-13 16:11:35 +000043 inode->i_blksize = PAGE_CACHE_SIZE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000044 inode->i_blocks = attr->blocks;
Miklos Szeredif85ab242004-01-07 12:16:45 +000045#ifdef KERNEL_2_6
46 inode->i_atime.tv_sec = attr->atime;
Miklos Szeredib5958612004-02-20 14:10:49 +000047 inode->i_atime.tv_nsec = attr->atimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000048 inode->i_mtime.tv_sec = attr->mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +000049 inode->i_mtime.tv_nsec = attr->mtimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000050 inode->i_ctime.tv_sec = attr->ctime;
Miklos Szeredib5958612004-02-20 14:10:49 +000051 inode->i_ctime.tv_nsec = attr->ctimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000052#else
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000053 inode->i_atime = attr->atime;
54 inode->i_mtime = attr->mtime;
55 inode->i_ctime = attr->ctime;
Miklos Szeredif85ab242004-01-07 12:16:45 +000056#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000057}
58
Miklos Szeredia181e612001-11-06 12:03:23 +000059static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000060{
Miklos Szeredia181e612001-11-06 12:03:23 +000061 inode->i_mode = attr->mode & S_IFMT;
Miklos Szeredid1199f82004-02-06 15:29:22 +000062 i_size_write(inode, attr->size);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000063 if (S_ISREG(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000064 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000065 fuse_init_file_inode(inode);
Miklos Szeredib483c932001-10-29 14:57:57 +000066 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000067 else if (S_ISDIR(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000068 inode->i_op = &fuse_dir_inode_operations;
69 inode->i_fop = &fuse_dir_operations;
70 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000071 else if (S_ISLNK(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000072 inode->i_op = &fuse_symlink_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000073 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000074 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
75 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)){
Miklos Szeredia181e612001-11-06 12:03:23 +000076 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000077 init_special_inode(inode, inode->i_mode,
78 new_decode_dev(attr->rdev));
Miklos Szeredi76f65782004-02-19 16:55:40 +000079 } else
80 printk("fuse_init_inode: bad file type: %o\n", inode->i_mode);
81
Miklos Szeredi5e183482001-10-31 14:52:35 +000082 inode->u.generic_ip = inode;
83}
84
Miklos Szeredi76f65782004-02-19 16:55:40 +000085struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
Miklos Szeredia181e612001-11-06 12:03:23 +000086 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +000087{
88 struct inode *inode;
89
90 inode = iget(sb, ino);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000091 if (inode) {
92 if (!inode->u.generic_ip) {
Miklos Szeredi76f65782004-02-19 16:55:40 +000093 inode->i_generation = generation;
Miklos Szeredia181e612001-11-06 12:03:23 +000094 fuse_init_inode(inode, attr);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000095 } else if (inode->i_generation != generation)
Miklos Szeredi76f65782004-02-19 16:55:40 +000096 printk("fuse_iget: bad generation for ino %lu\n", ino);
Miklos Szeredie815c032004-01-19 18:20:49 +000097
Miklos Szeredi5e183482001-10-31 14:52:35 +000098 change_attributes(inode, attr);
Miklos Szeredia181e612001-11-06 12:03:23 +000099 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000100 }
101
102 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000103}
104
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000105static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000106 struct fuse_entry_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000107{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000108 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000109 struct fuse_req *req;
110 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000111
112 if (entry->d_name.len > FUSE_NAME_MAX)
113 return -ENAMETOOLONG;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000114 req = fuse_get_request(fc);
115 if (!req)
116 return -ERESTARTSYS;
117 req->in.h.opcode = FUSE_LOOKUP;
118 req->in.h.ino = dir->i_ino;
119 req->in.numargs = 1;
120 req->in.args[0].size = entry->d_name.len + 1;
121 req->in.args[0].value = entry->d_name.name;
122 req->out.numargs = 1;
123 req->out.args[0].size = sizeof(struct fuse_entry_out);
124 req->out.args[0].value = outarg;
125 request_send(fc, req);
126 *version = req->out.h.unique;
127 err = req->out.h.error;
128 fuse_put_request(fc, req);
129 return err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000130}
131
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000132static inline unsigned long time_to_jiffies(unsigned long sec,
133 unsigned long nsec)
134{
135 /* prevent wrapping of jiffies */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000136 if (sec + 1 >= LONG_MAX / HZ)
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000137 return 0;
138
139 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
140}
141
Miklos Szeredie815c032004-01-19 18:20:49 +0000142static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
143 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000144{
Miklos Szeredie815c032004-01-19 18:20:49 +0000145 int err;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000146 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000147 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000148 struct inode *inode = NULL;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000149
Miklos Szeredie815c032004-01-19 18:20:49 +0000150 err = fuse_do_lookup(dir, entry, &outarg, &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000151 if (!err) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000152 inode = fuse_iget(dir->i_sb, outarg.ino, outarg.generation,
153 &outarg.attr, version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000154 if (!inode)
Miklos Szeredie815c032004-01-19 18:20:49 +0000155 return -ENOMEM;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000156 } else if (err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000157 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000158
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000159 entry->d_time = time_to_jiffies(outarg.entry_valid,
160 outarg.entry_valid_nsec);
Miklos Szeredi307242f2004-01-26 11:28:44 +0000161 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000162 *inodep = inode;
163 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000164}
165
Miklos Szeredi76f65782004-02-19 16:55:40 +0000166static int lookup_new_entry(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000167 struct fuse_entry_out *outarg, int version,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000168 int mode)
169{
170 struct inode *inode;
171 inode = fuse_iget(dir->i_sb, outarg->ino, outarg->generation,
172 &outarg->attr, version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000173 if (!inode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000174 return -ENOMEM;
175
176 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000177 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000178 iput(inode);
179 printk("fuse_mknod: inode has wrong type\n");
180 return -EINVAL;
181 }
182
183 d_instantiate(entry, inode);
184 return 0;
185}
186
187
Miklos Szeredif85ab242004-01-07 12:16:45 +0000188static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
189 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000190{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000191 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000192 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000193 struct fuse_mknod_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000194 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000195 int err;
196
197 if (!req)
198 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000199
200 memset(&inarg, 0, sizeof(inarg));
201 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000202 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000203 req->in.h.opcode = FUSE_MKNOD;
204 req->in.h.ino = dir->i_ino;
205 req->in.numargs = 2;
206 req->in.args[0].size = sizeof(inarg);
207 req->in.args[0].value = &inarg;
208 req->in.args[1].size = entry->d_name.len + 1;
209 req->in.args[1].value = entry->d_name.name;
210 req->out.numargs = 1;
211 req->out.args[0].size = sizeof(outarg);
212 req->out.args[0].value = &outarg;
213 request_send(fc, req);
214 err = req->out.h.error;
215 if (!err)
216 err = lookup_new_entry(dir, entry, &outarg, req->out.h.unique,
217 mode);
218 fuse_put_request(fc, req);
219 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000220}
221
Miklos Szeredif85ab242004-01-07 12:16:45 +0000222static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000223{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000224 return _fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000225}
226
Miklos Szeredie815c032004-01-19 18:20:49 +0000227
Miklos Szeredib483c932001-10-29 14:57:57 +0000228static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
229{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000230 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000231 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000232 struct fuse_mkdir_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000233 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000234 int err;
235
236 if (!req)
237 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000238
239 memset(&inarg, 0, sizeof(inarg));
240 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000241 req->in.h.opcode = FUSE_MKDIR;
242 req->in.h.ino = dir->i_ino;
243 req->in.numargs = 2;
244 req->in.args[0].size = sizeof(inarg);
245 req->in.args[0].value = &inarg;
246 req->in.args[1].size = entry->d_name.len + 1;
247 req->in.args[1].value = entry->d_name.name;
248 req->out.numargs = 1;
249 req->out.args[0].size = sizeof(outarg);
250 req->out.args[0].value = &outarg;
251 request_send(fc, req);
252 err = req->out.h.error;
253 if (!err)
254 err = lookup_new_entry(dir, entry, &outarg, req->out.h.unique,
255 S_IFDIR);
256 fuse_put_request(fc, req);
257 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000258}
259
260static int fuse_symlink(struct inode *dir, struct dentry *entry,
261 const char *link)
262{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000263 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000264 struct fuse_req *req;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000265 struct fuse_entry_out outarg;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000266 unsigned int len = strlen(link) + 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000267 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000268
269 if (len > FUSE_SYMLINK_MAX)
270 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000271
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 req = fuse_get_request(fc);
273 if (!req)
274 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000275
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000276 req->in.h.opcode = FUSE_SYMLINK;
277 req->in.h.ino = dir->i_ino;
278 req->in.numargs = 2;
279 req->in.args[0].size = entry->d_name.len + 1;
280 req->in.args[0].value = entry->d_name.name;
281 req->in.args[1].size = len;
282 req->in.args[1].value = link;
283 req->out.numargs = 1;
284 req->out.args[0].size = sizeof(outarg);
285 req->out.args[0].value = &outarg;
286 request_send(fc, req);
287 err = req->out.h.error;
288 if (!err)
289 err = lookup_new_entry(dir, entry, &outarg, req->out.h.unique,
290 S_IFLNK);
291 fuse_put_request(fc, req);
292 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000293}
294
Miklos Szeredib5958612004-02-20 14:10:49 +0000295static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000296{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000297 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000298 struct fuse_req *req = fuse_get_request(fc);
299 int err;
300
301 if (!req)
302 return -ERESTARTSYS;
Miklos Szeredib483c932001-10-29 14:57:57 +0000303
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000304 req->in.h.opcode = FUSE_UNLINK;
305 req->in.h.ino = dir->i_ino;
306 req->in.numargs = 1;
307 req->in.args[0].size = entry->d_name.len + 1;
308 req->in.args[0].value = entry->d_name.name;
309 request_send(fc, req);
310 err = req->out.h.error;
311 if (!err) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000312 /* Set nlink to zero so the inode can be cleared, if
313 the inode does have more links this will be
314 discovered at the next lookup/getattr */
315 /* FIXME: mark inode "not uptodate" */
316 entry->d_inode->i_nlink = 0;
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000317 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000318 fuse_put_request(fc, req);
319 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000320}
321
322static int fuse_rmdir(struct inode *dir, struct dentry *entry)
323{
Miklos Szeredib5958612004-02-20 14:10:49 +0000324 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 struct fuse_req *req = fuse_get_request(fc);
326 int err;
327
328 if (!req)
329 return -ERESTARTSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000330
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000331 req->in.h.opcode = FUSE_RMDIR;
332 req->in.h.ino = dir->i_ino;
333 req->in.numargs = 1;
334 req->in.args[0].size = entry->d_name.len + 1;
335 req->in.args[0].value = entry->d_name.name;
336 request_send(fc, req);
337 err = req->out.h.error;
338 if (!err)
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000339 entry->d_inode->i_nlink = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000340 fuse_put_request(fc, req);
341 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000342}
343
344static int fuse_rename(struct inode *olddir, struct dentry *oldent,
345 struct inode *newdir, struct dentry *newent)
346{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000347 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000348 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000349 struct fuse_rename_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000350 int err;
351
352 if (!req)
353 return -ERESTARTSYS;
354
Miklos Szeredi43696432001-11-18 19:15:05 +0000355 memset(&inarg, 0, sizeof(inarg));
356 inarg.newdir = newdir->i_ino;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000357 req->in.h.opcode = FUSE_RENAME;
358 req->in.h.ino = olddir->i_ino;
359 req->in.numargs = 3;
360 req->in.args[0].size = sizeof(inarg);
361 req->in.args[0].value = &inarg;
362 req->in.args[1].size = oldent->d_name.len + 1;
363 req->in.args[1].value = oldent->d_name.name;
364 req->in.args[2].size = newent->d_name.len + 1;
365 req->in.args[2].value = newent->d_name.name;
366 request_send(fc, req);
367 err = req->out.h.error;
368 fuse_put_request(fc, req);
369 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000370}
371
372static int fuse_link(struct dentry *entry, struct inode *newdir,
373 struct dentry *newent)
374{
375 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000376 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000377 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000378 struct fuse_link_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000379 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 int err;
381
382 if (!req)
383 return -ERESTARTSYS;
384
Miklos Szeredi43696432001-11-18 19:15:05 +0000385 memset(&inarg, 0, sizeof(inarg));
386 inarg.newdir = newdir->i_ino;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000387 req->in.h.opcode = FUSE_LINK;
388 req->in.h.ino = inode->i_ino;
389 req->in.numargs = 2;
390 req->in.args[0].size = sizeof(inarg);
391 req->in.args[0].value = &inarg;
392 req->in.args[1].size = newent->d_name.len + 1;
393 req->in.args[1].value = newent->d_name.name;
394 req->out.numargs = 1;
395 req->out.args[0].size = sizeof(outarg);
396 req->out.args[0].value = &outarg;
397 request_send(fc, req);
398 err = req->out.h.error;
399 if (!err) {
400 /* Invalidate old entry, so attributes are refreshed */
401 d_invalidate(entry);
402 err = lookup_new_entry(newdir, newent, &outarg,
403 req->out.h.unique, inode->i_mode);
404 }
405 fuse_put_request(fc, req);
406 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000407}
408
Miklos Szeredif85ab242004-01-07 12:16:45 +0000409int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000410{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000411 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000412 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000413 struct fuse_attr_out arg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000414 int err;
415
416 if (!req)
417 return -ERESTARTSYS;
418
419 req->in.h.opcode = FUSE_GETATTR;
420 req->in.h.ino = inode->i_ino;
421 req->out.numargs = 1;
422 req->out.args[0].size = sizeof(arg);
423 req->out.args[0].value = &arg;
424 request_send(fc, req);
425 err = req->out.h.error;
426 if (!err)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000427 change_attributes(inode, &arg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000428 fuse_put_request(fc, req);
429 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430}
431
Miklos Szeredife25def2001-12-20 15:38:05 +0000432static int fuse_revalidate(struct dentry *entry)
433{
434 struct inode *inode = entry->d_inode;
435 struct fuse_conn *fc = INO_FC(inode);
436
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000437 if (inode->i_ino == FUSE_ROOT_INO) {
438 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
439 current->fsuid != fc->uid)
Miklos Szeredife25def2001-12-20 15:38:05 +0000440 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000441 } else if (!entry->d_time || time_before_eq(jiffies, entry->d_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000442 return 0;
443
Miklos Szeredif85ab242004-01-07 12:16:45 +0000444 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000445}
446
Miklos Szeredif85ab242004-01-07 12:16:45 +0000447static int _fuse_permission(struct inode *inode, int mask)
Miklos Szeredife25def2001-12-20 15:38:05 +0000448{
449 struct fuse_conn *fc = INO_FC(inode);
450
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000451 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
Miklos Szeredife25def2001-12-20 15:38:05 +0000452 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000453 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredife25def2001-12-20 15:38:05 +0000454 int err = vfs_permission(inode, mask);
455
456 /* If permission is denied, try to refresh file
457 attributes. This is also needed, because the root
458 node will at first have no permissions */
459
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000460 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000461 err = fuse_do_getattr(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000462 if (!err)
Miklos Szeredife25def2001-12-20 15:38:05 +0000463 err = vfs_permission(inode, mask);
464 }
465
466 /* FIXME: Need some mechanism to revoke permissions:
467 currently if the filesystem suddenly changes the
468 file mode, we will not be informed abot that, and
469 continue to allow access to the file/directory.
470
471 This is actually not so grave, since the user can
472 simply keep access to the file/directory anyway by
473 keeping it open... */
474
475 return err;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000476 } else
Miklos Szeredife25def2001-12-20 15:38:05 +0000477 return 0;
478}
479
Miklos Szeredib483c932001-10-29 14:57:57 +0000480static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
481 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000482{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000483 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000484 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000485 size_t reclen = FUSE_DIRENT_SIZE(dirent);
486 int over;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000487 if (dirent->namelen > NAME_MAX) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000488 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000489 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000490 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000491 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000492 break;
493
494 over = filldir(dstbuf, dirent->name, dirent->namelen,
495 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000496 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000497 break;
498
Miklos Szeredib483c932001-10-29 14:57:57 +0000499 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000500 file->f_pos += reclen;
501 nbytes -= reclen;
502 }
503
Miklos Szeredib483c932001-10-29 14:57:57 +0000504 return 0;
505}
506
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000507static int fuse_checkdir(struct file *cfile, struct file *file)
508{
509 struct inode *inode;
510 if (!cfile) {
511 printk("fuse_getdir: invalid file\n");
512 return -EPROTO;
513 }
514 inode = cfile->f_dentry->d_inode;
515 if (!S_ISREG(inode->i_mode)) {
516 printk("fuse_getdir: not a regular file\n");
517 fput(cfile);
518 return -EPROTO;
519 }
520
521 file->private_data = cfile;
522 return 0;
523}
524
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000525static int fuse_getdir(struct file *file)
526{
527 struct inode *inode = file->f_dentry->d_inode;
528 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000529 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000530 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000531 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000532
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000533 if (!req)
534 return -ERESTARTSYS;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000535
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000536 req->in.h.opcode = FUSE_GETDIR;
537 req->in.h.ino = inode->i_ino;
538 req->out.numargs = 1;
539 req->out.args[0].size = sizeof(struct fuse_getdir_out);
540 req->out.args[0].value = &outarg;
541 request_send(fc, req);
542 err = req->out.h.error;
543 if (!err)
544 err = fuse_checkdir(outarg.file, file);
545 fuse_put_request(fc, req);
546 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000547}
548
Miklos Szeredib483c932001-10-29 14:57:57 +0000549#define DIR_BUFSIZE 2048
550static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
551{
552 struct file *cfile = file->private_data;
553 char *buf;
554 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000555
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000556 if (!cfile) {
557 ret = fuse_getdir(file);
558 if (ret)
559 return ret;
560
561 cfile = file->private_data;
562 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000563
Miklos Szeredib483c932001-10-29 14:57:57 +0000564 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000565 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000566 return -ENOMEM;
Miklos Szeredie815c032004-01-19 18:20:49 +0000567
Miklos Szeredib483c932001-10-29 14:57:57 +0000568 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000569 if (ret < 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000570 printk("fuse_readdir: failed to read container file\n");
571 else
572 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
573
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000574 kfree(buf);
575 return ret;
576}
577
Miklos Szeredi05033042001-11-13 16:11:35 +0000578static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000579{
580 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000581 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000582 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000583 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000584
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000585 if (!req)
586 return ERR_PTR(-ERESTARTSYS);
587
Miklos Szeredi05033042001-11-13 16:11:35 +0000588 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000589 if (!link) {
590 link = ERR_PTR(-ENOMEM);
591 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000592 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000593 req->in.h.opcode = FUSE_READLINK;
594 req->in.h.ino = inode->i_ino;
595 req->out.argvar = 1;
596 req->out.numargs = 1;
597 req->out.args[0].size = PAGE_SIZE - 1;
598 req->out.args[0].value = link;
599 request_send(fc, req);
600 if (req->out.h.error) {
601 free_page((unsigned long) link);
602 link = ERR_PTR(req->out.h.error);
603 } else
604 link[req->out.args[0].size] = '\0';
605 out:
606 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000607 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000608}
609
610static void free_link(char *link)
611{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000612 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000613 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000614}
615
616static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
617{
618 int ret;
619 char *link;
620
Miklos Szeredi05033042001-11-13 16:11:35 +0000621 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000622 ret = vfs_readlink(dentry, buffer, buflen, link);
623 free_link(link);
624 return ret;
625}
626
627static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
628{
629 int ret;
630 char *link;
631
Miklos Szeredi05033042001-11-13 16:11:35 +0000632 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000633 ret = vfs_follow_link(nd, link);
634 free_link(link);
635 return ret;
636}
637
638static int fuse_dir_open(struct inode *inode, struct file *file)
639{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000640 file->private_data = NULL;
641 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000642}
643
644static int fuse_dir_release(struct inode *inode, struct file *file)
645{
646 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000647
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000648 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000649 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000650
651 return 0;
652}
653
Miklos Szeredi5e183482001-10-31 14:52:35 +0000654static unsigned int iattr_to_fattr(struct iattr *iattr,
655 struct fuse_attr *fattr)
656{
657 unsigned int ivalid = iattr->ia_valid;
658 unsigned int fvalid = 0;
659
660 memset(fattr, 0, sizeof(*fattr));
661
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000662 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000663 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000664 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000666 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000668 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000669 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
670 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000671 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000672 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000673#ifdef KERNEL_2_6
674 fattr->atime = iattr->ia_atime.tv_sec;
675 fattr->mtime = iattr->ia_mtime.tv_sec;
676#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000677 fattr->atime = iattr->ia_atime;
678 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000679#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000680 }
681
682 return fvalid;
683}
684
685static int fuse_setattr(struct dentry *entry, struct iattr *attr)
686{
687 struct inode *inode = entry->d_inode;
688 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000689 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredia181e612001-11-06 12:03:23 +0000690 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000691 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000692 int err;
693
694 if (!req)
695 return -ERESTARTSYS;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000696
Miklos Szeredi43696432001-11-18 19:15:05 +0000697 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000698 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000699 req->in.h.opcode = FUSE_SETATTR;
700 req->in.h.ino = inode->i_ino;
701 req->in.numargs = 1;
702 req->in.args[0].size = sizeof(inarg);
703 req->in.args[0].value = &inarg;
704 req->out.numargs = 1;
705 req->out.args[0].size = sizeof(outarg);
706 req->out.args[0].value = &outarg;
707 request_send(fc, req);
708 err = req->out.h.error;
709 if (!err) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000710 if (attr->ia_valid & ATTR_SIZE &&
711 outarg.attr.size < i_size_read(inode))
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000712 vmtruncate(inode, outarg.attr.size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000713
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000714 change_attributes(inode, &outarg.attr);
715 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000716 fuse_put_request(fc, req);
717 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000718}
719
Miklos Szeredif85ab242004-01-07 12:16:45 +0000720static int _fuse_dentry_revalidate(struct dentry *entry)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000721{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000722 if (!entry->d_inode)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000723 return 0;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000724 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000725 struct inode *inode = entry->d_inode;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000726 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000727 int version;
728 int ret;
729
730 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
731 &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000732 if (ret)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000733 return 0;
734
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000735 if (outarg.ino != inode->i_ino)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000736 return 0;
737
738 change_attributes(inode, &outarg.attr);
739 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000740 entry->d_time = time_to_jiffies(outarg.entry_valid,
741 outarg.entry_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000742 }
743 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000744}
745
Miklos Szeredif85ab242004-01-07 12:16:45 +0000746#ifdef KERNEL_2_6
747
748#define fuse_mknod _fuse_mknod
749
750static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
751 struct kstat *stat)
752{
753 struct inode *inode = entry->d_inode;
754 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000755 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000756 generic_fillattr(inode, stat);
757
758 return err;
759}
760
761static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
762 struct nameidata *nd)
763{
Miklos Szeredie815c032004-01-19 18:20:49 +0000764 struct inode *inode;
765 int err = fuse_lookup_iget(dir, entry, &inode);
766 if (err)
767 return ERR_PTR(err);
768 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000769}
770
771static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
772 struct nameidata *nd)
773{
774 return _fuse_create(dir, entry, mode);
775}
776
777static int fuse_permission(struct inode *inode, int mask,
778 struct nameidata *nd)
779{
780 return _fuse_permission(inode, mask);
781}
782
783static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
784{
785 return _fuse_dentry_revalidate(entry);
786}
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000787
Miklos Szeredi689f5632004-05-04 08:49:16 +0000788#else /* KERNEL_2_6 */
789
790#define fuse_create _fuse_create
791#define fuse_permission _fuse_permission
792
793static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
794{
795 struct inode *inode;
796 struct dentry *alias;
797
798 int err = fuse_lookup_iget(dir, entry, &inode);
799 if (err)
800 return ERR_PTR(err);
801
802 if (inode && S_ISDIR(inode->i_mode) &&
803 (alias = d_find_alias(inode)) != NULL) {
804 dput(alias);
805 iput(inode);
806 printk("fuse: cannot assign an existing directory\n");
807 return ERR_PTR(-EPROTO);
808 }
809
810 d_add(entry, inode);
811 return NULL;
812}
813
814static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
815 int rdev)
816{
817 return fuse_mknod(dir, entry, mode, rdev);
818}
819
820static int fuse_dentry_revalidate(struct dentry *entry, int flags)
821{
822 return _fuse_dentry_revalidate(entry);
823}
824#endif /* KERNEL_2_6 */
825
826#ifdef HAVE_KERNEL_XATTR
827
828#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000829static int fuse_setxattr(struct dentry *entry, const char *name,
830 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000831#else
832static int fuse_setxattr(struct dentry *entry, const char *name,
833 void *value, size_t size, int flags)
834#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000835{
836 struct inode *inode = entry->d_inode;
837 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000838 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000839 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000840 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000841
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000842 if (size > FUSE_XATTR_SIZE_MAX)
843 return -E2BIG;
844
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000845 if (fc->no_setxattr)
846 return -EOPNOTSUPP;
847
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000848 req = fuse_get_request(fc);
849 if (!req)
850 return -ERESTARTSYS;
851
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000852 memset(&inarg, 0, sizeof(inarg));
853 inarg.size = size;
854 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000855 req->in.h.opcode = FUSE_SETXATTR;
856 req->in.h.ino = inode->i_ino;
857 req->in.numargs = 3;
858 req->in.args[0].size = sizeof(inarg);
859 req->in.args[0].value = &inarg;
860 req->in.args[1].size = strlen(name) + 1;
861 req->in.args[1].value = name;
862 req->in.args[2].size = size;
863 req->in.args[2].value = value;
864 request_send(fc, req);
865 err = req->out.h.error;
866 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000867 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000868 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000869 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000870 fuse_put_request(fc, req);
871 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000872}
873
874static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
875 void *value, size_t size)
876{
877 struct inode *inode = entry->d_inode;
878 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000880 struct fuse_getxattr_in inarg;
881 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000882 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000883
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000884 if (fc->no_getxattr)
885 return -EOPNOTSUPP;
886
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000887 req = fuse_get_request(fc);
888 if (!req)
889 return -ERESTARTSYS;
890
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000891 memset(&inarg, 0, sizeof(inarg));
892 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000893 req->in.h.opcode = FUSE_GETXATTR;
894 req->in.h.ino = inode->i_ino;
895 req->in.numargs = 2;
896 req->in.args[0].size = sizeof(inarg);
897 req->in.args[0].value = &inarg;
898 req->in.args[1].size = strlen(name) + 1;
899 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000900 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000901 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000902 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000903 req->out.argvar = 1;
904 req->out.args[0].size = size;
905 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000906 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000907 req->out.args[0].size = sizeof(outarg);
908 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000909 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000910 request_send(fc, req);
911 ret = req->out.h.error;
912 if (!ret)
913 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000914 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000915 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000916 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000917 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000918 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000919 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000920 fuse_put_request(fc, req);
921 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000922}
923
924static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
925{
926 struct inode *inode = entry->d_inode;
927 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000928 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000929 struct fuse_getxattr_in inarg;
930 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000931 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000932
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000933 if (fc->no_listxattr)
934 return -EOPNOTSUPP;
935
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000936 req = fuse_get_request(fc);
937 if (!req)
938 return -ERESTARTSYS;
939
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000940 memset(&inarg, 0, sizeof(inarg));
941 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 req->in.h.opcode = FUSE_LISTXATTR;
943 req->in.h.ino = inode->i_ino;
944 req->in.numargs = 1;
945 req->in.args[0].size = sizeof(inarg);
946 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000947 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000948 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000949 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000950 req->out.argvar = 1;
951 req->out.args[0].size = size;
952 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000953 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000954 req->out.args[0].size = sizeof(outarg);
955 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000956 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000957 request_send(fc, req);
958 ret = req->out.h.error;
959 if (!ret)
960 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000961 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000962 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000963 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000964 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000965 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000966 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000967 fuse_put_request(fc, req);
968 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000969}
970
971static int fuse_removexattr(struct dentry *entry, const char *name)
972{
973 struct inode *inode = entry->d_inode;
974 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000975 struct fuse_req *req;
976 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000977
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000978 if (fc->no_removexattr)
979 return -EOPNOTSUPP;
980
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000981 req = fuse_get_request(fc);
982 if (!req)
983 return -ERESTARTSYS;
984
985 req->in.h.opcode = FUSE_REMOVEXATTR;
986 req->in.h.ino = inode->i_ino;
987 req->in.numargs = 1;
988 req->in.args[0].size = strlen(name) + 1;
989 req->in.args[0].value = name;
990 request_send(fc, req);
991 err = req->out.h.error;
992 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000993 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000995 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000996 fuse_put_request(fc, req);
997 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000998}
999
Miklos Szeredi689f5632004-05-04 08:49:16 +00001000#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001001
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001002static struct inode_operations fuse_dir_inode_operations =
1003{
Miklos Szeredie8663f32004-01-13 15:33:12 +00001004 .lookup = fuse_lookup,
1005 .create = fuse_create,
1006 .mknod = fuse_mknod,
1007 .mkdir = fuse_mkdir,
1008 .symlink = fuse_symlink,
1009 .unlink = fuse_unlink,
1010 .rmdir = fuse_rmdir,
1011 .rename = fuse_rename,
1012 .link = fuse_link,
1013 .setattr = fuse_setattr,
1014 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001015#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001016 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001017#else
1018 .revalidate = fuse_revalidate,
1019#endif
1020#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001021 .setxattr = fuse_setxattr,
1022 .getxattr = fuse_getxattr,
1023 .listxattr = fuse_listxattr,
1024 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001025#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001026};
1027
1028static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001029 .read = generic_read_dir,
1030 .readdir = fuse_readdir,
1031 .open = fuse_dir_open,
1032 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001033};
1034
1035static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001036 .setattr = fuse_setattr,
1037 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001038#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001039 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001040#else
1041 .revalidate = fuse_revalidate,
1042#endif
1043#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001044 .setxattr = fuse_setxattr,
1045 .getxattr = fuse_getxattr,
1046 .listxattr = fuse_listxattr,
1047 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001048#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001049};
1050
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001051static struct inode_operations fuse_symlink_inode_operations =
1052{
Miklos Szeredie8663f32004-01-13 15:33:12 +00001053 .setattr = fuse_setattr,
1054 .readlink = fuse_readlink,
1055 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001056#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001057 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001058#else
1059 .revalidate = fuse_revalidate,
1060#endif
1061#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001062 .setxattr = fuse_setxattr,
1063 .getxattr = fuse_getxattr,
1064 .listxattr = fuse_listxattr,
1065 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001066#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001067};
1068
Miklos Szeredi307242f2004-01-26 11:28:44 +00001069static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001070 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001071};
1072
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001073/*
1074 * Local Variables:
1075 * indent-tabs-mode: t
1076 * c-basic-offset: 8
1077 * End:
1078 */