blob: 4c127f2bc814dcc53670d5b7b0beba4fcfef50d6 [file] [log] [blame]
Miklos Szeredie5e55582005-09-09 13:10:28 -07001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.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
11#include <linux/pagemap.h>
12#include <linux/file.h>
13#include <linux/gfp.h>
14#include <linux/sched.h>
15#include <linux/namei.h>
16
17static inline unsigned long time_to_jiffies(unsigned long sec,
18 unsigned long nsec)
19{
20 struct timespec ts = {sec, nsec};
21 return jiffies + timespec_to_jiffies(&ts);
22}
23
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080024static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
25{
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080026 entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080027 if (entry->d_inode)
28 get_fuse_inode(entry->d_inode)->i_time =
29 time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
30}
31
32void fuse_invalidate_attr(struct inode *inode)
33{
34 get_fuse_inode(inode)->i_time = jiffies - 1;
35}
36
37static void fuse_invalidate_entry_cache(struct dentry *entry)
38{
39 entry->d_time = jiffies - 1;
40}
41
42static void fuse_invalidate_entry(struct dentry *entry)
43{
44 d_invalidate(entry);
45 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080046}
47
Miklos Szeredie5e55582005-09-09 13:10:28 -070048static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
49 struct dentry *entry,
50 struct fuse_entry_out *outarg)
51{
52 req->in.h.opcode = FUSE_LOOKUP;
53 req->in.h.nodeid = get_node_id(dir);
54 req->inode = dir;
55 req->in.numargs = 1;
56 req->in.args[0].size = entry->d_name.len + 1;
57 req->in.args[0].value = entry->d_name.name;
58 req->out.numargs = 1;
59 req->out.args[0].size = sizeof(struct fuse_entry_out);
60 req->out.args[0].value = outarg;
61}
62
63static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
64{
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080065 struct inode *inode = entry->d_inode;
66
67 if (inode && is_bad_inode(inode))
Miklos Szeredie5e55582005-09-09 13:10:28 -070068 return 0;
69 else if (time_after(jiffies, entry->d_time)) {
70 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -070071 struct fuse_entry_out outarg;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080072 struct fuse_conn *fc;
73 struct fuse_req *req;
74
75 fuse_invalidate_entry_cache(entry);
76 if (!inode)
77 return 0;
78
79 fc = get_fuse_conn(inode);
80 req = fuse_get_request(fc);
Miklos Szeredie5e55582005-09-09 13:10:28 -070081 if (!req)
82 return 0;
83
84 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -070085 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -070086 err = req->out.h.error;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -070087 if (!err) {
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080088 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -070089 if (outarg.nodeid != get_node_id(inode)) {
90 fuse_send_forget(fc, req, outarg.nodeid, 1);
91 return 0;
92 }
93 fi->nlookup ++;
94 }
Miklos Szeredie5e55582005-09-09 13:10:28 -070095 fuse_put_request(fc, req);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -070096 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredie5e55582005-09-09 13:10:28 -070097 return 0;
98
99 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800100 fuse_change_timeout(entry, &outarg);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700101 }
102 return 1;
103}
104
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800105static int dir_alias(struct inode *inode)
106{
107 if (S_ISDIR(inode->i_mode)) {
108 /* Don't allow creating an alias to a directory */
109 struct dentry *alias = d_find_alias(inode);
110 if (alias) {
111 dput(alias);
112 return 1;
113 }
114 }
115 return 0;
116}
117
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800118static inline int invalid_nodeid(u64 nodeid)
119{
120 return !nodeid || nodeid == FUSE_ROOT_ID;
121}
122
Miklos Szeredie5e55582005-09-09 13:10:28 -0700123static struct dentry_operations fuse_dentry_operations = {
124 .d_revalidate = fuse_dentry_revalidate,
125};
126
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800127static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
128 struct nameidata *nd)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700129{
130 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700131 struct fuse_entry_out outarg;
132 struct inode *inode = NULL;
133 struct fuse_conn *fc = get_fuse_conn(dir);
134 struct fuse_req *req;
135
136 if (entry->d_name.len > FUSE_NAME_MAX)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800137 return ERR_PTR(-ENAMETOOLONG);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700138
139 req = fuse_get_request(fc);
140 if (!req)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800141 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700142
143 fuse_lookup_init(req, dir, entry, &outarg);
144 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700145 err = req->out.h.error;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800146 if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid))
Miklos Szerediee4e5272005-09-27 21:45:21 -0700147 err = -EIO;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800148 if (!err && outarg.nodeid) {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700149 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700150 &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700151 if (!inode) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700152 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800153 return ERR_PTR(-ENOMEM);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700154 }
155 }
156 fuse_put_request(fc, req);
157 if (err && err != -ENOENT)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800158 return ERR_PTR(err);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700159
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800160 if (inode && dir_alias(inode)) {
161 iput(inode);
162 return ERR_PTR(-EIO);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700163 }
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800164 d_add(entry, inode);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700165 entry->d_op = &fuse_dentry_operations;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800166 if (!err)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800167 fuse_change_timeout(entry, &outarg);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800168 else
169 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800170 return NULL;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700171}
172
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800173static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
174 struct nameidata *nd)
175{
176 int err;
177 struct inode *inode;
178 struct fuse_conn *fc = get_fuse_conn(dir);
179 struct fuse_req *req;
180 struct fuse_open_in inarg;
181 struct fuse_open_out outopen;
182 struct fuse_entry_out outentry;
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800183 struct fuse_file *ff;
184 struct file *file;
185 int flags = nd->intent.open.flags - 1;
186
187 err = -ENOSYS;
188 if (fc->no_create)
189 goto out;
190
191 err = -ENAMETOOLONG;
192 if (entry->d_name.len > FUSE_NAME_MAX)
193 goto out;
194
195 err = -EINTR;
196 req = fuse_get_request(fc);
197 if (!req)
198 goto out;
199
200 ff = fuse_file_alloc();
201 if (!ff)
202 goto out_put_request;
203
204 flags &= ~O_NOCTTY;
205 memset(&inarg, 0, sizeof(inarg));
206 inarg.flags = flags;
207 inarg.mode = mode;
208 req->in.h.opcode = FUSE_CREATE;
209 req->in.h.nodeid = get_node_id(dir);
210 req->inode = dir;
211 req->in.numargs = 2;
212 req->in.args[0].size = sizeof(inarg);
213 req->in.args[0].value = &inarg;
214 req->in.args[1].size = entry->d_name.len + 1;
215 req->in.args[1].value = entry->d_name.name;
216 req->out.numargs = 2;
217 req->out.args[0].size = sizeof(outentry);
218 req->out.args[0].value = &outentry;
219 req->out.args[1].size = sizeof(outopen);
220 req->out.args[1].value = &outopen;
221 request_send(fc, req);
222 err = req->out.h.error;
223 if (err) {
224 if (err == -ENOSYS)
225 fc->no_create = 1;
226 goto out_free_ff;
227 }
228
229 err = -EIO;
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800230 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800231 goto out_free_ff;
232
233 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
234 &outentry.attr);
235 err = -ENOMEM;
236 if (!inode) {
237 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
238 ff->fh = outopen.fh;
239 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
240 goto out_put_request;
241 }
242 fuse_put_request(fc, req);
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800243 d_instantiate(entry, inode);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800244 fuse_change_timeout(entry, &outentry);
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800245 file = lookup_instantiate_filp(nd, entry, generic_file_open);
246 if (IS_ERR(file)) {
247 ff->fh = outopen.fh;
248 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
249 return PTR_ERR(file);
250 }
251 fuse_finish_open(inode, file, ff, &outopen);
252 return 0;
253
254 out_free_ff:
255 fuse_file_free(ff);
256 out_put_request:
257 fuse_put_request(fc, req);
258 out:
259 return err;
260}
261
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700262static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
263 struct inode *dir, struct dentry *entry,
264 int mode)
265{
266 struct fuse_entry_out outarg;
267 struct inode *inode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700268 int err;
269
270 req->in.h.nodeid = get_node_id(dir);
271 req->inode = dir;
272 req->out.numargs = 1;
273 req->out.args[0].size = sizeof(outarg);
274 req->out.args[0].value = &outarg;
275 request_send(fc, req);
276 err = req->out.h.error;
277 if (err) {
278 fuse_put_request(fc, req);
279 return err;
280 }
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800281 if (invalid_nodeid(outarg.nodeid)) {
Miklos Szerediee4e5272005-09-27 21:45:21 -0700282 fuse_put_request(fc, req);
283 return -EIO;
284 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700285 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
286 &outarg.attr);
287 if (!inode) {
288 fuse_send_forget(fc, req, outarg.nodeid, 1);
289 return -ENOMEM;
290 }
291 fuse_put_request(fc, req);
292
293 /* Don't allow userspace to do really stupid things... */
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800294 if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700295 iput(inode);
296 return -EIO;
297 }
298
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700299 d_instantiate(entry, inode);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800300 fuse_change_timeout(entry, &outarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700301 fuse_invalidate_attr(dir);
302 return 0;
303}
304
305static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
306 dev_t rdev)
307{
308 struct fuse_mknod_in inarg;
309 struct fuse_conn *fc = get_fuse_conn(dir);
310 struct fuse_req *req = fuse_get_request(fc);
311 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700312 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700313
314 memset(&inarg, 0, sizeof(inarg));
315 inarg.mode = mode;
316 inarg.rdev = new_encode_dev(rdev);
317 req->in.h.opcode = FUSE_MKNOD;
318 req->in.numargs = 2;
319 req->in.args[0].size = sizeof(inarg);
320 req->in.args[0].value = &inarg;
321 req->in.args[1].size = entry->d_name.len + 1;
322 req->in.args[1].value = entry->d_name.name;
323 return create_new_entry(fc, req, dir, entry, mode);
324}
325
326static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
327 struct nameidata *nd)
328{
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800329 if (nd && (nd->flags & LOOKUP_CREATE)) {
330 int err = fuse_create_open(dir, entry, mode, nd);
331 if (err != -ENOSYS)
332 return err;
333 /* Fall back on mknod */
334 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700335 return fuse_mknod(dir, entry, mode, 0);
336}
337
338static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
339{
340 struct fuse_mkdir_in inarg;
341 struct fuse_conn *fc = get_fuse_conn(dir);
342 struct fuse_req *req = fuse_get_request(fc);
343 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700344 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700345
346 memset(&inarg, 0, sizeof(inarg));
347 inarg.mode = mode;
348 req->in.h.opcode = FUSE_MKDIR;
349 req->in.numargs = 2;
350 req->in.args[0].size = sizeof(inarg);
351 req->in.args[0].value = &inarg;
352 req->in.args[1].size = entry->d_name.len + 1;
353 req->in.args[1].value = entry->d_name.name;
354 return create_new_entry(fc, req, dir, entry, S_IFDIR);
355}
356
357static int fuse_symlink(struct inode *dir, struct dentry *entry,
358 const char *link)
359{
360 struct fuse_conn *fc = get_fuse_conn(dir);
361 unsigned len = strlen(link) + 1;
362 struct fuse_req *req;
363
364 if (len > FUSE_SYMLINK_MAX)
365 return -ENAMETOOLONG;
366
367 req = fuse_get_request(fc);
368 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700369 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700370
371 req->in.h.opcode = FUSE_SYMLINK;
372 req->in.numargs = 2;
373 req->in.args[0].size = entry->d_name.len + 1;
374 req->in.args[0].value = entry->d_name.name;
375 req->in.args[1].size = len;
376 req->in.args[1].value = link;
377 return create_new_entry(fc, req, dir, entry, S_IFLNK);
378}
379
380static int fuse_unlink(struct inode *dir, struct dentry *entry)
381{
382 int err;
383 struct fuse_conn *fc = get_fuse_conn(dir);
384 struct fuse_req *req = fuse_get_request(fc);
385 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700386 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700387
388 req->in.h.opcode = FUSE_UNLINK;
389 req->in.h.nodeid = get_node_id(dir);
390 req->inode = dir;
391 req->in.numargs = 1;
392 req->in.args[0].size = entry->d_name.len + 1;
393 req->in.args[0].value = entry->d_name.name;
394 request_send(fc, req);
395 err = req->out.h.error;
396 fuse_put_request(fc, req);
397 if (!err) {
398 struct inode *inode = entry->d_inode;
399
400 /* Set nlink to zero so the inode can be cleared, if
401 the inode does have more links this will be
402 discovered at the next lookup/getattr */
403 inode->i_nlink = 0;
404 fuse_invalidate_attr(inode);
405 fuse_invalidate_attr(dir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800406 fuse_invalidate_entry_cache(entry);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700407 } else if (err == -EINTR)
408 fuse_invalidate_entry(entry);
409 return err;
410}
411
412static int fuse_rmdir(struct inode *dir, struct dentry *entry)
413{
414 int err;
415 struct fuse_conn *fc = get_fuse_conn(dir);
416 struct fuse_req *req = fuse_get_request(fc);
417 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700418 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700419
420 req->in.h.opcode = FUSE_RMDIR;
421 req->in.h.nodeid = get_node_id(dir);
422 req->inode = dir;
423 req->in.numargs = 1;
424 req->in.args[0].size = entry->d_name.len + 1;
425 req->in.args[0].value = entry->d_name.name;
426 request_send(fc, req);
427 err = req->out.h.error;
428 fuse_put_request(fc, req);
429 if (!err) {
430 entry->d_inode->i_nlink = 0;
431 fuse_invalidate_attr(dir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800432 fuse_invalidate_entry_cache(entry);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700433 } else if (err == -EINTR)
434 fuse_invalidate_entry(entry);
435 return err;
436}
437
438static int fuse_rename(struct inode *olddir, struct dentry *oldent,
439 struct inode *newdir, struct dentry *newent)
440{
441 int err;
442 struct fuse_rename_in inarg;
443 struct fuse_conn *fc = get_fuse_conn(olddir);
444 struct fuse_req *req = fuse_get_request(fc);
445 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700446 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700447
448 memset(&inarg, 0, sizeof(inarg));
449 inarg.newdir = get_node_id(newdir);
450 req->in.h.opcode = FUSE_RENAME;
451 req->in.h.nodeid = get_node_id(olddir);
452 req->inode = olddir;
453 req->inode2 = newdir;
454 req->in.numargs = 3;
455 req->in.args[0].size = sizeof(inarg);
456 req->in.args[0].value = &inarg;
457 req->in.args[1].size = oldent->d_name.len + 1;
458 req->in.args[1].value = oldent->d_name.name;
459 req->in.args[2].size = newent->d_name.len + 1;
460 req->in.args[2].value = newent->d_name.name;
461 request_send(fc, req);
462 err = req->out.h.error;
463 fuse_put_request(fc, req);
464 if (!err) {
465 fuse_invalidate_attr(olddir);
466 if (olddir != newdir)
467 fuse_invalidate_attr(newdir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800468
469 /* newent will end up negative */
470 if (newent->d_inode)
471 fuse_invalidate_entry_cache(newent);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700472 } else if (err == -EINTR) {
473 /* If request was interrupted, DEITY only knows if the
474 rename actually took place. If the invalidation
475 fails (e.g. some process has CWD under the renamed
476 directory), then there can be inconsistency between
477 the dcache and the real filesystem. Tough luck. */
478 fuse_invalidate_entry(oldent);
479 if (newent->d_inode)
480 fuse_invalidate_entry(newent);
481 }
482
483 return err;
484}
485
486static int fuse_link(struct dentry *entry, struct inode *newdir,
487 struct dentry *newent)
488{
489 int err;
490 struct fuse_link_in inarg;
491 struct inode *inode = entry->d_inode;
492 struct fuse_conn *fc = get_fuse_conn(inode);
493 struct fuse_req *req = fuse_get_request(fc);
494 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700495 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700496
497 memset(&inarg, 0, sizeof(inarg));
498 inarg.oldnodeid = get_node_id(inode);
499 req->in.h.opcode = FUSE_LINK;
500 req->inode2 = inode;
501 req->in.numargs = 2;
502 req->in.args[0].size = sizeof(inarg);
503 req->in.args[0].value = &inarg;
504 req->in.args[1].size = newent->d_name.len + 1;
505 req->in.args[1].value = newent->d_name.name;
506 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
507 /* Contrary to "normal" filesystems it can happen that link
508 makes two "logical" inodes point to the same "physical"
509 inode. We invalidate the attributes of the old one, so it
510 will reflect changes in the backing inode (link count,
511 etc.)
512 */
513 if (!err || err == -EINTR)
514 fuse_invalidate_attr(inode);
515 return err;
516}
517
Miklos Szeredie5e55582005-09-09 13:10:28 -0700518int fuse_do_getattr(struct inode *inode)
519{
520 int err;
521 struct fuse_attr_out arg;
522 struct fuse_conn *fc = get_fuse_conn(inode);
523 struct fuse_req *req = fuse_get_request(fc);
524 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700525 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700526
527 req->in.h.opcode = FUSE_GETATTR;
528 req->in.h.nodeid = get_node_id(inode);
529 req->inode = inode;
530 req->out.numargs = 1;
531 req->out.args[0].size = sizeof(arg);
532 req->out.args[0].value = &arg;
533 request_send(fc, req);
534 err = req->out.h.error;
535 fuse_put_request(fc, req);
536 if (!err) {
537 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
538 make_bad_inode(inode);
539 err = -EIO;
540 } else {
541 struct fuse_inode *fi = get_fuse_inode(inode);
542 fuse_change_attributes(inode, &arg.attr);
543 fi->i_time = time_to_jiffies(arg.attr_valid,
544 arg.attr_valid_nsec);
545 }
546 }
547 return err;
548}
549
Miklos Szeredi87729a52005-09-09 13:10:34 -0700550/*
551 * Calling into a user-controlled filesystem gives the filesystem
552 * daemon ptrace-like capabilities over the requester process. This
553 * means, that the filesystem daemon is able to record the exact
554 * filesystem operations performed, and can also control the behavior
555 * of the requester process in otherwise impossible ways. For example
556 * it can delay the operation for arbitrary length of time allowing
557 * DoS against the requester.
558 *
559 * For this reason only those processes can call into the filesystem,
560 * for which the owner of the mount has ptrace privilege. This
561 * excludes processes started by other users, suid or sgid processes.
562 */
563static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
564{
565 if (fc->flags & FUSE_ALLOW_OTHER)
566 return 1;
567
568 if (task->euid == fc->user_id &&
569 task->suid == fc->user_id &&
570 task->uid == fc->user_id &&
571 task->egid == fc->group_id &&
572 task->sgid == fc->group_id &&
573 task->gid == fc->group_id)
574 return 1;
575
576 return 0;
577}
578
Miklos Szeredie5e55582005-09-09 13:10:28 -0700579static int fuse_revalidate(struct dentry *entry)
580{
581 struct inode *inode = entry->d_inode;
582 struct fuse_inode *fi = get_fuse_inode(inode);
583 struct fuse_conn *fc = get_fuse_conn(inode);
584
Miklos Szeredi87729a52005-09-09 13:10:34 -0700585 if (!fuse_allow_task(fc, current))
586 return -EACCES;
587 if (get_node_id(inode) != FUSE_ROOT_ID &&
588 time_before_eq(jiffies, fi->i_time))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700589 return 0;
590
591 return fuse_do_getattr(inode);
592}
593
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800594static int fuse_access(struct inode *inode, int mask)
595{
596 struct fuse_conn *fc = get_fuse_conn(inode);
597 struct fuse_req *req;
598 struct fuse_access_in inarg;
599 int err;
600
601 if (fc->no_access)
602 return 0;
603
604 req = fuse_get_request(fc);
605 if (!req)
606 return -EINTR;
607
608 memset(&inarg, 0, sizeof(inarg));
609 inarg.mask = mask;
610 req->in.h.opcode = FUSE_ACCESS;
611 req->in.h.nodeid = get_node_id(inode);
612 req->inode = inode;
613 req->in.numargs = 1;
614 req->in.args[0].size = sizeof(inarg);
615 req->in.args[0].value = &inarg;
616 request_send(fc, req);
617 err = req->out.h.error;
618 fuse_put_request(fc, req);
619 if (err == -ENOSYS) {
620 fc->no_access = 1;
621 err = 0;
622 }
623 return err;
624}
625
Miklos Szeredie5e55582005-09-09 13:10:28 -0700626static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
627{
628 struct fuse_conn *fc = get_fuse_conn(inode);
629
Miklos Szeredi87729a52005-09-09 13:10:34 -0700630 if (!fuse_allow_task(fc, current))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700631 return -EACCES;
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700632 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
633 int err = generic_permission(inode, mask, NULL);
634
635 /* If permission is denied, try to refresh file
636 attributes. This is also needed, because the root
637 node will at first have no permissions */
638 if (err == -EACCES) {
639 err = fuse_do_getattr(inode);
640 if (!err)
641 err = generic_permission(inode, mask, NULL);
642 }
643
644 /* FIXME: Need some mechanism to revoke permissions:
645 currently if the filesystem suddenly changes the
646 file mode, we will not be informed about it, and
647 continue to allow access to the file/directory.
648
649 This is actually not so grave, since the user can
650 simply keep access to the file/directory anyway by
651 keeping it open... */
652
653 return err;
654 } else {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700655 int mode = inode->i_mode;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700656 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
657 return -EACCES;
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800658
659 if (nd && (nd->flags & LOOKUP_ACCESS))
660 return fuse_access(inode, mask);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700661 return 0;
662 }
663}
664
665static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
666 void *dstbuf, filldir_t filldir)
667{
668 while (nbytes >= FUSE_NAME_OFFSET) {
669 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
670 size_t reclen = FUSE_DIRENT_SIZE(dirent);
671 int over;
672 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
673 return -EIO;
674 if (reclen > nbytes)
675 break;
676
677 over = filldir(dstbuf, dirent->name, dirent->namelen,
678 file->f_pos, dirent->ino, dirent->type);
679 if (over)
680 break;
681
682 buf += reclen;
683 nbytes -= reclen;
684 file->f_pos = dirent->off;
685 }
686
687 return 0;
688}
689
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700690static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
691 struct inode *inode, loff_t pos,
692 size_t count)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700693{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700694 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700695}
696
697static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
698{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700699 int err;
700 size_t nbytes;
701 struct page *page;
702 struct inode *inode = file->f_dentry->d_inode;
703 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700704 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700705 if (!req)
706 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700707
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700708 page = alloc_page(GFP_KERNEL);
709 if (!page) {
710 fuse_put_request(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700711 return -ENOMEM;
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700712 }
713 req->num_pages = 1;
714 req->pages[0] = page;
715 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
716 err = req->out.h.error;
717 fuse_put_request(fc, req);
718 if (!err)
719 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
720 filldir);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700721
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700722 __free_page(page);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700723 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700724 return err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700725}
726
727static char *read_link(struct dentry *dentry)
728{
729 struct inode *inode = dentry->d_inode;
730 struct fuse_conn *fc = get_fuse_conn(inode);
731 struct fuse_req *req = fuse_get_request(fc);
732 char *link;
733
734 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700735 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700736
737 link = (char *) __get_free_page(GFP_KERNEL);
738 if (!link) {
739 link = ERR_PTR(-ENOMEM);
740 goto out;
741 }
742 req->in.h.opcode = FUSE_READLINK;
743 req->in.h.nodeid = get_node_id(inode);
744 req->inode = inode;
745 req->out.argvar = 1;
746 req->out.numargs = 1;
747 req->out.args[0].size = PAGE_SIZE - 1;
748 req->out.args[0].value = link;
749 request_send(fc, req);
750 if (req->out.h.error) {
751 free_page((unsigned long) link);
752 link = ERR_PTR(req->out.h.error);
753 } else
754 link[req->out.args[0].size] = '\0';
755 out:
756 fuse_put_request(fc, req);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700757 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700758 return link;
759}
760
761static void free_link(char *link)
762{
763 if (!IS_ERR(link))
764 free_page((unsigned long) link);
765}
766
767static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
768{
769 nd_set_link(nd, read_link(dentry));
770 return NULL;
771}
772
773static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
774{
775 free_link(nd_get_link(nd));
776}
777
778static int fuse_dir_open(struct inode *inode, struct file *file)
779{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700780 return fuse_open_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700781}
782
783static int fuse_dir_release(struct inode *inode, struct file *file)
784{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700785 return fuse_release_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700786}
787
Miklos Szeredi82547982005-09-09 13:10:38 -0700788static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
789{
790 /* nfsd can call this with no file */
791 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
792}
793
Miklos Szeredibefc6492005-11-07 00:59:52 -0800794static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700795{
796 unsigned ivalid = iattr->ia_valid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700797
798 if (ivalid & ATTR_MODE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800799 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700800 if (ivalid & ATTR_UID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800801 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700802 if (ivalid & ATTR_GID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800803 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700804 if (ivalid & ATTR_SIZE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800805 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700806 /* You can only _set_ these together (they may change by themselves) */
807 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredibefc6492005-11-07 00:59:52 -0800808 arg->valid |= FATTR_ATIME | FATTR_MTIME;
809 arg->atime = iattr->ia_atime.tv_sec;
810 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700811 }
Miklos Szeredibefc6492005-11-07 00:59:52 -0800812 if (ivalid & ATTR_FILE) {
813 struct fuse_file *ff = iattr->ia_file->private_data;
814 arg->valid |= FATTR_FH;
815 arg->fh = ff->fh;
816 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700817}
818
819static int fuse_setattr(struct dentry *entry, struct iattr *attr)
820{
821 struct inode *inode = entry->d_inode;
822 struct fuse_conn *fc = get_fuse_conn(inode);
823 struct fuse_inode *fi = get_fuse_inode(inode);
824 struct fuse_req *req;
825 struct fuse_setattr_in inarg;
826 struct fuse_attr_out outarg;
827 int err;
828 int is_truncate = 0;
829
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700830 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
831 err = inode_change_ok(inode, attr);
832 if (err)
833 return err;
834 }
835
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700836 if (attr->ia_valid & ATTR_SIZE) {
837 unsigned long limit;
838 is_truncate = 1;
839 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
840 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
841 send_sig(SIGXFSZ, current, 0);
842 return -EFBIG;
843 }
844 }
845
846 req = fuse_get_request(fc);
847 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700848 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700849
850 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredibefc6492005-11-07 00:59:52 -0800851 iattr_to_fattr(attr, &inarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700852 req->in.h.opcode = FUSE_SETATTR;
853 req->in.h.nodeid = get_node_id(inode);
854 req->inode = inode;
855 req->in.numargs = 1;
856 req->in.args[0].size = sizeof(inarg);
857 req->in.args[0].value = &inarg;
858 req->out.numargs = 1;
859 req->out.args[0].size = sizeof(outarg);
860 req->out.args[0].value = &outarg;
861 request_send(fc, req);
862 err = req->out.h.error;
863 fuse_put_request(fc, req);
864 if (!err) {
865 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
866 make_bad_inode(inode);
867 err = -EIO;
868 } else {
869 if (is_truncate) {
870 loff_t origsize = i_size_read(inode);
871 i_size_write(inode, outarg.attr.size);
872 if (origsize > outarg.attr.size)
873 vmtruncate(inode, outarg.attr.size);
874 }
875 fuse_change_attributes(inode, &outarg.attr);
876 fi->i_time = time_to_jiffies(outarg.attr_valid,
877 outarg.attr_valid_nsec);
878 }
879 } else if (err == -EINTR)
880 fuse_invalidate_attr(inode);
881
882 return err;
883}
884
Miklos Szeredie5e55582005-09-09 13:10:28 -0700885static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
886 struct kstat *stat)
887{
888 struct inode *inode = entry->d_inode;
889 int err = fuse_revalidate(entry);
890 if (!err)
891 generic_fillattr(inode, stat);
892
893 return err;
894}
895
Miklos Szeredi92a87802005-09-09 13:10:31 -0700896static int fuse_setxattr(struct dentry *entry, const char *name,
897 const void *value, size_t size, int flags)
898{
899 struct inode *inode = entry->d_inode;
900 struct fuse_conn *fc = get_fuse_conn(inode);
901 struct fuse_req *req;
902 struct fuse_setxattr_in inarg;
903 int err;
904
905 if (size > FUSE_XATTR_SIZE_MAX)
906 return -E2BIG;
907
908 if (fc->no_setxattr)
909 return -EOPNOTSUPP;
910
911 req = fuse_get_request(fc);
912 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700913 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700914
915 memset(&inarg, 0, sizeof(inarg));
916 inarg.size = size;
917 inarg.flags = flags;
918 req->in.h.opcode = FUSE_SETXATTR;
919 req->in.h.nodeid = get_node_id(inode);
920 req->inode = inode;
921 req->in.numargs = 3;
922 req->in.args[0].size = sizeof(inarg);
923 req->in.args[0].value = &inarg;
924 req->in.args[1].size = strlen(name) + 1;
925 req->in.args[1].value = name;
926 req->in.args[2].size = size;
927 req->in.args[2].value = value;
928 request_send(fc, req);
929 err = req->out.h.error;
930 fuse_put_request(fc, req);
931 if (err == -ENOSYS) {
932 fc->no_setxattr = 1;
933 err = -EOPNOTSUPP;
934 }
935 return err;
936}
937
938static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
939 void *value, size_t size)
940{
941 struct inode *inode = entry->d_inode;
942 struct fuse_conn *fc = get_fuse_conn(inode);
943 struct fuse_req *req;
944 struct fuse_getxattr_in inarg;
945 struct fuse_getxattr_out outarg;
946 ssize_t ret;
947
948 if (fc->no_getxattr)
949 return -EOPNOTSUPP;
950
951 req = fuse_get_request(fc);
952 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700953 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700954
955 memset(&inarg, 0, sizeof(inarg));
956 inarg.size = size;
957 req->in.h.opcode = FUSE_GETXATTR;
958 req->in.h.nodeid = get_node_id(inode);
959 req->inode = inode;
960 req->in.numargs = 2;
961 req->in.args[0].size = sizeof(inarg);
962 req->in.args[0].value = &inarg;
963 req->in.args[1].size = strlen(name) + 1;
964 req->in.args[1].value = name;
965 /* This is really two different operations rolled into one */
966 req->out.numargs = 1;
967 if (size) {
968 req->out.argvar = 1;
969 req->out.args[0].size = size;
970 req->out.args[0].value = value;
971 } else {
972 req->out.args[0].size = sizeof(outarg);
973 req->out.args[0].value = &outarg;
974 }
975 request_send(fc, req);
976 ret = req->out.h.error;
977 if (!ret)
978 ret = size ? req->out.args[0].size : outarg.size;
979 else {
980 if (ret == -ENOSYS) {
981 fc->no_getxattr = 1;
982 ret = -EOPNOTSUPP;
983 }
984 }
985 fuse_put_request(fc, req);
986 return ret;
987}
988
989static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
990{
991 struct inode *inode = entry->d_inode;
992 struct fuse_conn *fc = get_fuse_conn(inode);
993 struct fuse_req *req;
994 struct fuse_getxattr_in inarg;
995 struct fuse_getxattr_out outarg;
996 ssize_t ret;
997
998 if (fc->no_listxattr)
999 return -EOPNOTSUPP;
1000
1001 req = fuse_get_request(fc);
1002 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001003 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001004
1005 memset(&inarg, 0, sizeof(inarg));
1006 inarg.size = size;
1007 req->in.h.opcode = FUSE_LISTXATTR;
1008 req->in.h.nodeid = get_node_id(inode);
1009 req->inode = inode;
1010 req->in.numargs = 1;
1011 req->in.args[0].size = sizeof(inarg);
1012 req->in.args[0].value = &inarg;
1013 /* This is really two different operations rolled into one */
1014 req->out.numargs = 1;
1015 if (size) {
1016 req->out.argvar = 1;
1017 req->out.args[0].size = size;
1018 req->out.args[0].value = list;
1019 } else {
1020 req->out.args[0].size = sizeof(outarg);
1021 req->out.args[0].value = &outarg;
1022 }
1023 request_send(fc, req);
1024 ret = req->out.h.error;
1025 if (!ret)
1026 ret = size ? req->out.args[0].size : outarg.size;
1027 else {
1028 if (ret == -ENOSYS) {
1029 fc->no_listxattr = 1;
1030 ret = -EOPNOTSUPP;
1031 }
1032 }
1033 fuse_put_request(fc, req);
1034 return ret;
1035}
1036
1037static int fuse_removexattr(struct dentry *entry, const char *name)
1038{
1039 struct inode *inode = entry->d_inode;
1040 struct fuse_conn *fc = get_fuse_conn(inode);
1041 struct fuse_req *req;
1042 int err;
1043
1044 if (fc->no_removexattr)
1045 return -EOPNOTSUPP;
1046
1047 req = fuse_get_request(fc);
1048 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001049 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001050
1051 req->in.h.opcode = FUSE_REMOVEXATTR;
1052 req->in.h.nodeid = get_node_id(inode);
1053 req->inode = inode;
1054 req->in.numargs = 1;
1055 req->in.args[0].size = strlen(name) + 1;
1056 req->in.args[0].value = name;
1057 request_send(fc, req);
1058 err = req->out.h.error;
1059 fuse_put_request(fc, req);
1060 if (err == -ENOSYS) {
1061 fc->no_removexattr = 1;
1062 err = -EOPNOTSUPP;
1063 }
1064 return err;
1065}
1066
Miklos Szeredie5e55582005-09-09 13:10:28 -07001067static struct inode_operations fuse_dir_inode_operations = {
1068 .lookup = fuse_lookup,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001069 .mkdir = fuse_mkdir,
1070 .symlink = fuse_symlink,
1071 .unlink = fuse_unlink,
1072 .rmdir = fuse_rmdir,
1073 .rename = fuse_rename,
1074 .link = fuse_link,
1075 .setattr = fuse_setattr,
1076 .create = fuse_create,
1077 .mknod = fuse_mknod,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001078 .permission = fuse_permission,
1079 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001080 .setxattr = fuse_setxattr,
1081 .getxattr = fuse_getxattr,
1082 .listxattr = fuse_listxattr,
1083 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001084};
1085
1086static struct file_operations fuse_dir_operations = {
Miklos Szeredib6aeade2005-09-09 13:10:30 -07001087 .llseek = generic_file_llseek,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001088 .read = generic_read_dir,
1089 .readdir = fuse_readdir,
1090 .open = fuse_dir_open,
1091 .release = fuse_dir_release,
Miklos Szeredi82547982005-09-09 13:10:38 -07001092 .fsync = fuse_dir_fsync,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001093};
1094
1095static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001096 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001097 .permission = fuse_permission,
1098 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001099 .setxattr = fuse_setxattr,
1100 .getxattr = fuse_getxattr,
1101 .listxattr = fuse_listxattr,
1102 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001103};
1104
1105static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001106 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001107 .follow_link = fuse_follow_link,
1108 .put_link = fuse_put_link,
1109 .readlink = generic_readlink,
1110 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001111 .setxattr = fuse_setxattr,
1112 .getxattr = fuse_getxattr,
1113 .listxattr = fuse_listxattr,
1114 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001115};
1116
1117void fuse_init_common(struct inode *inode)
1118{
1119 inode->i_op = &fuse_common_inode_operations;
1120}
1121
1122void fuse_init_dir(struct inode *inode)
1123{
1124 inode->i_op = &fuse_dir_inode_operations;
1125 inode->i_fop = &fuse_dir_operations;
1126}
1127
1128void fuse_init_symlink(struct inode *inode)
1129{
1130 inode->i_op = &fuse_symlink_inode_operations;
1131}