blob: 4f7a83f5bd4ba3ed73125d6d7e94a330fa58f041 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
Miklos Szeredi149f6072005-01-10 12:29:28 +00003 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredie56818b2004-12-12 11:45:24 +00005 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
9#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000012#include <linux/file.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000013#ifdef KERNEL_2_6
14#include <linux/gfp.h>
15#else
16#include <linux/mm.h>
17#endif
18#include <linux/sched.h>
Miklos Szeredi7a983952005-01-28 09:58:19 +000019#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +000020#include <linux/namei.h>
21#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000023static inline unsigned long time_to_jiffies(unsigned long sec,
24 unsigned long nsec)
25{
Miklos Szeredi81394522005-01-11 14:24:18 +000026 struct timespec ts = {sec, nsec};
27 return jiffies + timespec_to_jiffies(&ts);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000028}
29
Miklos Szeredi0f62d722005-01-04 12:45:54 +000030static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
31 struct dentry *entry,
32 struct fuse_entry_out *outarg)
33{
34 req->in.h.opcode = FUSE_LOOKUP;
35 req->in.h.nodeid = get_node_id(dir);
36 req->inode = dir;
37 req->in.numargs = 1;
38 req->in.args[0].size = entry->d_name.len + 1;
39 req->in.args[0].value = entry->d_name.name;
40 req->out.numargs = 1;
41 req->out.args[0].size = sizeof(struct fuse_entry_out);
42 req->out.args[0].value = outarg;
43}
44
45static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
46{
47 if (!entry->d_inode || is_bad_inode(entry->d_inode))
48 return 0;
Miklos Szeredi81394522005-01-11 14:24:18 +000049 else if (time_after(jiffies, entry->d_time)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +000050 int err;
51 int version;
52 struct fuse_entry_out outarg;
53 struct inode *inode = entry->d_inode;
54 struct fuse_inode *fi = get_fuse_inode(inode);
55 struct fuse_conn *fc = get_fuse_conn(inode);
56 struct fuse_req *req = fuse_get_request_nonint(fc);
57 if (!req)
58 return 0;
59
60 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
61 request_send_nonint(fc, req);
62 version = req->out.h.unique;
63 err = req->out.h.error;
64 fuse_put_request(fc, req);
65 if (err || outarg.nodeid != get_node_id(inode) ||
66 (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
67 return 0;
68
69 fuse_change_attributes(inode, &outarg.attr);
70 inode->i_version = version;
71 entry->d_time = time_to_jiffies(outarg.entry_valid,
72 outarg.entry_valid_nsec);
73 fi->i_time = time_to_jiffies(outarg.attr_valid,
74 outarg.attr_valid_nsec);
75 }
76 return 1;
77}
78#ifndef KERNEL_2_6
79static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
80{
81 return fuse_dentry_revalidate(entry, NULL);
82}
83#endif
84
85static struct dentry_operations fuse_dentry_operations = {
86#ifdef KERNEL_2_6
87 .d_revalidate = fuse_dentry_revalidate,
88#else
89 .d_revalidate = fuse_dentry_revalidate_2_4,
90#endif
91};
92
Miklos Szeredie815c032004-01-19 18:20:49 +000093static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
94 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +000095{
Miklos Szeredie815c032004-01-19 18:20:49 +000096 int err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +000097 int version;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +000098 struct fuse_entry_out outarg;
Miklos Szeredie815c032004-01-19 18:20:49 +000099 struct inode *inode = NULL;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000100 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000101 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000102
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000103 if (entry->d_name.len > FUSE_NAME_MAX)
104 return -ENAMETOOLONG;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000105
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000106 req = fuse_get_request(fc);
107 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000108 return -ERESTARTNOINTR;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000109
Miklos Szeredie56818b2004-12-12 11:45:24 +0000110 fuse_lookup_init(req, dir, entry, &outarg);
111 request_send(fc, req);
112 version = req->out.h.unique;
113 err = req->out.h.error;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000114 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000115 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000116 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000117 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000118 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000119 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000120 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000121 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000122 fuse_put_request(fc, req);
123 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000124 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000125
Miklos Szeredi069c9502004-07-16 16:17:02 +0000126 if (inode) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000127 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000128 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000129 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000130 fi->i_time = time_to_jiffies(outarg.attr_valid,
131 outarg.attr_valid_nsec);
132 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000133
Miklos Szeredi307242f2004-01-26 11:28:44 +0000134 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000135 *inodep = inode;
136 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000137}
138
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000139void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000140{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000141 get_fuse_inode(inode)->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000142}
143
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000144static void fuse_invalidate_entry(struct dentry *entry)
145{
146 d_invalidate(entry);
147 entry->d_time = jiffies - 1;
148}
149
150static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000151 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000152 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000153{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000154 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000155 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000156 struct fuse_inode *fi;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000157 int version;
158 int err;
159
160 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000161 req->inode = dir;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000162 req->out.numargs = 1;
163 req->out.args[0].size = sizeof(outarg);
164 req->out.args[0].value = &outarg;
165 request_send(fc, req);
166 version = req->out.h.unique;
167 err = req->out.h.error;
168 if (err) {
169 fuse_put_request(fc, req);
170 return err;
171 }
172 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
173 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000174 if (!inode) {
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000175 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000176 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000177 }
178 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000179
180 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000181 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000182 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000183 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000184 }
185
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000186 entry->d_time = time_to_jiffies(outarg.entry_valid,
187 outarg.entry_valid_nsec);
Miklos Szerediad051c32004-07-02 09:22:50 +0000188
Miklos Szeredi039322d2004-12-01 18:39:12 +0000189 fi = get_fuse_inode(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000190 fi->i_time = time_to_jiffies(outarg.attr_valid,
191 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000192
Miklos Szeredi76f65782004-02-19 16:55:40 +0000193 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000194 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000195 return 0;
196}
197
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000198static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000199 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000200{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000201 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000202 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000203 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000204 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000205 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000206
207 memset(&inarg, 0, sizeof(inarg));
208 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000209 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000210 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000211 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;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000216 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000217}
218
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000219static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
220 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000221{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000222 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000223}
224
Miklos Szeredib483c932001-10-29 14:57:57 +0000225static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
226{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000227 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000228 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000229 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000230 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000231 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000232
233 memset(&inarg, 0, sizeof(inarg));
234 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000235 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000236 req->in.numargs = 2;
237 req->in.args[0].size = sizeof(inarg);
238 req->in.args[0].value = &inarg;
239 req->in.args[1].size = entry->d_name.len + 1;
240 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000241 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000242}
243
244static int fuse_symlink(struct inode *dir, struct dentry *entry,
245 const char *link)
246{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000247 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000248 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000249 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000250
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000251 if (len > FUSE_SYMLINK_MAX)
252 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000253
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000254 req = fuse_get_request(fc);
255 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000256 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000257
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000258 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000259 req->in.numargs = 2;
260 req->in.args[0].size = entry->d_name.len + 1;
261 req->in.args[0].value = entry->d_name.name;
262 req->in.args[1].size = len;
263 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000264 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000265}
266
Miklos Szeredib5958612004-02-20 14:10:49 +0000267static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000268{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000269 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000270 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000271 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000273 return -ERESTARTNOINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000274
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000275 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000276 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000277 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000278 req->in.numargs = 1;
279 req->in.args[0].size = entry->d_name.len + 1;
280 req->in.args[0].value = entry->d_name.name;
281 request_send(fc, req);
282 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000283 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000284 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000285 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000286
Miklos Szeredib5958612004-02-20 14:10:49 +0000287 /* Set nlink to zero so the inode can be cleared, if
288 the inode does have more links this will be
289 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000290 inode->i_nlink = 0;
291 fuse_invalidate_attr(inode);
292 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000293 } else if (err == -EINTR)
294 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000295 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000296}
297
298static int fuse_rmdir(struct inode *dir, struct dentry *entry)
299{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000300 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000301 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000302 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000303 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000304 return -ERESTARTNOINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000305
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000307 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000308 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000309 req->in.numargs = 1;
310 req->in.args[0].size = entry->d_name.len + 1;
311 req->in.args[0].value = entry->d_name.name;
312 request_send(fc, req);
313 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000314 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000315 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000316 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000317 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000318 } else if (err == -EINTR)
319 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000320 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000321}
322
323static int fuse_rename(struct inode *olddir, struct dentry *oldent,
324 struct inode *newdir, struct dentry *newent)
325{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000326 int err;
327 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000328 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000329 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000330 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000331 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332
Miklos Szeredi43696432001-11-18 19:15:05 +0000333 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000334 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000336 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000337 req->inode = olddir;
338 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000339 req->in.numargs = 3;
340 req->in.args[0].size = sizeof(inarg);
341 req->in.args[0].value = &inarg;
342 req->in.args[1].size = oldent->d_name.len + 1;
343 req->in.args[1].value = oldent->d_name.name;
344 req->in.args[2].size = newent->d_name.len + 1;
345 req->in.args[2].value = newent->d_name.name;
346 request_send(fc, req);
347 err = req->out.h.error;
348 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000349 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000350 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000351 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000352 fuse_invalidate_attr(newdir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000353 } else if (err == -EINTR) {
354 /* If request was interrupted, DEITY only knows if the
355 rename actually took place. If the invalidation
356 fails (e.g. some process has CWD under the renamed
357 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000358 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000359 fuse_invalidate_entry(oldent);
360 if (newent->d_inode)
361 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000362 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000364 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000365}
366
367static int fuse_link(struct dentry *entry, struct inode *newdir,
368 struct dentry *newent)
369{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000370 int err;
371 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000372 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000373 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000374 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000375 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000376 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000377
Miklos Szeredi43696432001-11-18 19:15:05 +0000378 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000379 inarg.oldnodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 req->in.h.opcode = FUSE_LINK;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000381 req->inode2 = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000382 req->in.numargs = 2;
383 req->in.args[0].size = sizeof(inarg);
384 req->in.args[0].value = &inarg;
385 req->in.args[1].size = newent->d_name.len + 1;
386 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000387 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
388 /* Contrary to "normal" filesystems it can happen that link
389 makes two "logical" inodes point to the same "physical"
390 inode. We invalidate the attributes of the old one, so it
391 will reflect changes in the backing inode (link count,
392 etc.)
393 */
394 if (!err || err == -EINTR)
395 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000396 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000397}
398
Miklos Szeredif85ab242004-01-07 12:16:45 +0000399int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000401 int err;
402 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000403 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000404 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000405 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000406 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000407
408 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000409 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000410 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000411 req->out.numargs = 1;
412 req->out.args[0].size = sizeof(arg);
413 req->out.args[0].value = &arg;
414 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000415 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000416 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000417 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000418 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000419#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000420 if (get_node_id(inode) != FUSE_ROOT_ID)
421 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000422#else
423 make_bad_inode(inode);
424#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000425 err = -EIO;
426 } else {
427 struct fuse_inode *fi = get_fuse_inode(inode);
428 fuse_change_attributes(inode, &arg.attr);
429 fi->i_time = time_to_jiffies(arg.attr_valid,
430 arg.attr_valid_nsec);
431 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000432 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000433 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434}
435
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000436static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
437{
438 if (fc->flags & FUSE_ALLOW_OTHER)
439 return 1;
440
441 /* Calling into a user-controlled filesystem gives the
442 filesystem daemon ptrace-like capabilities over the
443 requester process. This means, that the filesystem daemon
444 is able to record the exact filesystem operations
445 performed, and can also control the behavior of the
446 requester process in otherwise impossible ways. For
447 example it can delay the operation for arbitrary length of
448 time allowing DoS against the requester.
449
450 For this reason only those processes can call into the
451 filesystem, for which the owner of the mount has ptrace
452 privilege. This excludes processes started by other users,
453 suid or sgid processes. */
454 if (task->euid == fc->user_id &&
455 task->suid == fc->user_id &&
456 task->uid == fc->user_id &&
457 task->egid == fc->group_id &&
458 task->sgid == fc->group_id &&
459 task->gid == fc->group_id)
460 return 1;
461
462 return 0;
463}
464
Miklos Szeredife25def2001-12-20 15:38:05 +0000465static int fuse_revalidate(struct dentry *entry)
466{
467 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000468 struct fuse_inode *fi = get_fuse_inode(inode);
469 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000470
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000471 if (!fuse_allow_task(fc, current))
472 return -EACCES;
473 if (get_node_id(inode) != FUSE_ROOT_ID &&
474 time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000475 return 0;
476
Miklos Szeredif85ab242004-01-07 12:16:45 +0000477 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000478}
479
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000480static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000481{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000482 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000483
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000484 if (!fuse_allow_task(fc, current))
Miklos Szeredife25def2001-12-20 15:38:05 +0000485 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000486 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000487#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000488 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000489#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000490 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000491#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000492
493 /* If permission is denied, try to refresh file
494 attributes. This is also needed, because the root
495 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000496 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000497 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000498 if (!err)
499#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000500 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000501#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000502 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000503#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000504 }
505
506 /* FIXME: Need some mechanism to revoke permissions:
507 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000508 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000509 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000510
Miklos Szeredife25def2001-12-20 15:38:05 +0000511 This is actually not so grave, since the user can
512 simply keep access to the file/directory anyway by
513 keeping it open... */
514
515 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000516 } else {
517 int mode = inode->i_mode;
518 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
519 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
520 return -EROFS;
521 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
522 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000523 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000524 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000525}
526
Miklos Szeredib483c932001-10-29 14:57:57 +0000527static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
528 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000529{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000530 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000531 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000532 size_t reclen = FUSE_DIRENT_SIZE(dirent);
533 int over;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000534 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000535 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000536 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000537 break;
538
539 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi18fce982005-04-01 21:07:35 +0000540 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000541 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000542 break;
543
Miklos Szeredib483c932001-10-29 14:57:57 +0000544 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000545 nbytes -= reclen;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000546 file->f_pos = dirent->off;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000547 }
548
Miklos Szeredib483c932001-10-29 14:57:57 +0000549 return 0;
550}
551
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000552static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
553 struct inode *inode, loff_t pos,
554 size_t count)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000555{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000556 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000557}
558
Miklos Szeredib483c932001-10-29 14:57:57 +0000559static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
560{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000561 int err;
562 size_t nbytes;
563 struct page *page;
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000564 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000565 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000566 struct fuse_req *req = fuse_get_request_nonint(fc);
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000567 if (!req)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000568 return -EINTR;
Miklos Szeredie815c032004-01-19 18:20:49 +0000569
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000570 page = alloc_page(GFP_KERNEL);
571 if (!page) {
572 fuse_put_request(fc, req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000573 return -ENOMEM;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000574 }
575 req->num_pages = 1;
576 req->pages[0] = page;
577 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
578 err = req->out.h.error;
579 fuse_put_request(fc, req);
580 if (!err)
581 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
582 filldir);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000583
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000584 __free_page(page);
585 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000586}
587
Miklos Szeredi05033042001-11-13 16:11:35 +0000588static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000589{
590 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000591 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000592 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000593 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000594
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000595 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000596 return ERR_PTR(-ERESTARTNOINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000597
Miklos Szeredi05033042001-11-13 16:11:35 +0000598 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000599 if (!link) {
600 link = ERR_PTR(-ENOMEM);
601 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000602 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000603 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000604 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000605 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000606 req->out.argvar = 1;
607 req->out.numargs = 1;
608 req->out.args[0].size = PAGE_SIZE - 1;
609 req->out.args[0].value = link;
610 request_send(fc, req);
611 if (req->out.h.error) {
612 free_page((unsigned long) link);
613 link = ERR_PTR(req->out.h.error);
614 } else
615 link[req->out.args[0].size] = '\0';
616 out:
617 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000618 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000619}
620
621static void free_link(char *link)
622{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000623 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000624 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000625}
626
Miklos Szeredi7a983952005-01-28 09:58:19 +0000627#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +0000628static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
629{
630 nd_set_link(nd, read_link(dentry));
631 return 0;
632}
633
634static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
635{
636 free_link(nd_get_link(nd));
637}
638#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000639static int fuse_readlink(struct dentry *dentry, char __user *buffer,
640 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000641{
642 int ret;
643 char *link;
644
Miklos Szeredi05033042001-11-13 16:11:35 +0000645 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000646 ret = vfs_readlink(dentry, buffer, buflen, link);
647 free_link(link);
648 return ret;
649}
650
651static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
652{
653 int ret;
654 char *link;
655
Miklos Szeredi05033042001-11-13 16:11:35 +0000656 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000657 ret = vfs_follow_link(nd, link);
658 free_link(link);
659 return ret;
660}
Miklos Szeredi81394522005-01-11 14:24:18 +0000661#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000662
663static int fuse_dir_open(struct inode *inode, struct file *file)
664{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000665 return fuse_open_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000666}
667
668static int fuse_dir_release(struct inode *inode, struct file *file)
669{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000670 return fuse_release_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000671}
672
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000673static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
674{
Miklos Szeredib7640d22005-04-08 15:15:28 +0000675 /* nfsd can call this with no file */
676 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000677}
678
Miklos Szeredi83a07442004-11-30 18:25:20 +0000679static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000680{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000681 unsigned ivalid = iattr->ia_valid;
682 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000683
Miklos Szeredi5e183482001-10-31 14:52:35 +0000684 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000685
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000686 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000687 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000688 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000689 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000690 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000691 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000692 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000693 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
694 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000695 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000696 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000697#ifdef KERNEL_2_6
698 fattr->atime = iattr->ia_atime.tv_sec;
699 fattr->mtime = iattr->ia_mtime.tv_sec;
700#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 fattr->atime = iattr->ia_atime;
702 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000703#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704 }
705
706 return fvalid;
707}
708
709static int fuse_setattr(struct dentry *entry, struct iattr *attr)
710{
711 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000712 struct fuse_conn *fc = get_fuse_conn(inode);
713 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000714 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000715 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000716 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000717 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000718 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000719
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000720 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
721 err = inode_change_ok(inode, attr);
722 if (err)
723 return err;
724 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000725
Miklos Szeredi069c9502004-07-16 16:17:02 +0000726 if (attr->ia_valid & ATTR_SIZE) {
727 unsigned long limit;
728 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000729#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000730 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000731#else
732 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000733#endif
734 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000735 send_sig(SIGXFSZ, current, 0);
736 return -EFBIG;
737 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000738 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000739
740 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000741 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000742 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000743
Miklos Szeredi43696432001-11-18 19:15:05 +0000744 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000745 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000746 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000747 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000748 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000749 req->in.numargs = 1;
750 req->in.args[0].size = sizeof(inarg);
751 req->in.args[0].value = &inarg;
752 req->out.numargs = 1;
753 req->out.args[0].size = sizeof(outarg);
754 req->out.args[0].value = &outarg;
755 request_send(fc, req);
756 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000757 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000758 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000759 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000760#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000761 if (get_node_id(inode) != FUSE_ROOT_ID)
762 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000763#else
764 make_bad_inode(inode);
765#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000766 err = -EIO;
767 } else {
768 if (is_truncate) {
769 loff_t origsize = i_size_read(inode);
770 i_size_write(inode, outarg.attr.size);
771 if (origsize > outarg.attr.size)
772 vmtruncate(inode, outarg.attr.size);
773 }
774 fuse_change_attributes(inode, &outarg.attr);
775 fi->i_time = time_to_jiffies(outarg.attr_valid,
776 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000777 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000778 } else if (err == -EINTR)
779 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000780
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000781 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782}
783
Miklos Szeredif85ab242004-01-07 12:16:45 +0000784#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000785static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
786 struct kstat *stat)
787{
788 struct inode *inode = entry->d_inode;
789 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000790 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000791 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000792
Miklos Szeredif85ab242004-01-07 12:16:45 +0000793 return err;
794}
795
796static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000797 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000798{
Miklos Szeredie815c032004-01-19 18:20:49 +0000799 struct inode *inode;
800 int err = fuse_lookup_iget(dir, entry, &inode);
801 if (err)
802 return ERR_PTR(err);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000803 if (inode && S_ISDIR(inode->i_mode)) {
804 /* Don't allow creating an alias to a directory */
805 struct dentry *alias = d_find_alias(inode);
806 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
807 dput(alias);
808 iput(inode);
809 return ERR_PTR(-EIO);
810 }
811 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000812 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000813}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000814#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000815static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
816{
817 struct inode *inode;
818 struct dentry *alias;
819
820 int err = fuse_lookup_iget(dir, entry, &inode);
821 if (err)
822 return ERR_PTR(err);
823
824 if (inode && S_ISDIR(inode->i_mode) &&
825 (alias = d_find_alias(inode)) != NULL) {
826 dput(alias);
827 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000828 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000829 }
830
831 d_add(entry, inode);
832 return NULL;
833}
834
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000835static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000836 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000837{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000838 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000839}
840
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000841static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
842{
843 return fuse_create(dir, entry, mode, NULL);
844}
845
846static int fuse_permission_2_4(struct inode *inode, int mask)
847{
848 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000849}
850#endif /* KERNEL_2_6 */
851
852#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000853#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000854static int fuse_setxattr(struct dentry *entry, const char *name,
855 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000856#else
857static int fuse_setxattr(struct dentry *entry, const char *name,
858 void *value, size_t size, int flags)
859#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000860{
861 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000862 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000863 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000864 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000865 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000866
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000867 if (size > FUSE_XATTR_SIZE_MAX)
868 return -E2BIG;
869
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000870 if (fc->no_setxattr)
871 return -EOPNOTSUPP;
872
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000873 req = fuse_get_request(fc);
874 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000875 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000876
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000877 memset(&inarg, 0, sizeof(inarg));
878 inarg.size = size;
879 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000880 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000881 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000882 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000883 req->in.numargs = 3;
884 req->in.args[0].size = sizeof(inarg);
885 req->in.args[0].value = &inarg;
886 req->in.args[1].size = strlen(name) + 1;
887 req->in.args[1].value = name;
888 req->in.args[2].size = size;
889 req->in.args[2].value = value;
890 request_send(fc, req);
891 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000892 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000893 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000894 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000896 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000897 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000898}
899
900static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
901 void *value, size_t size)
902{
903 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000904 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000905 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000906 struct fuse_getxattr_in inarg;
907 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000909
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000910 if (fc->no_getxattr)
911 return -EOPNOTSUPP;
912
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000913 req = fuse_get_request(fc);
914 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000915 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000916
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000917 memset(&inarg, 0, sizeof(inarg));
918 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000919 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000920 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000921 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000922 req->in.numargs = 2;
923 req->in.args[0].size = sizeof(inarg);
924 req->in.args[0].value = &inarg;
925 req->in.args[1].size = strlen(name) + 1;
926 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000927 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000928 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000929 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000930 req->out.argvar = 1;
931 req->out.args[0].size = size;
932 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000933 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000934 req->out.args[0].size = sizeof(outarg);
935 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000936 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 request_send(fc, req);
938 ret = req->out.h.error;
939 if (!ret)
940 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000941 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000943 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000944 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000945 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000946 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000947 fuse_put_request(fc, req);
948 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000949}
950
951static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
952{
953 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000954 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000956 struct fuse_getxattr_in inarg;
957 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000958 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000959
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000960 if (fc->no_listxattr)
961 return -EOPNOTSUPP;
962
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000963 req = fuse_get_request(fc);
964 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000965 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000966
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000967 memset(&inarg, 0, sizeof(inarg));
968 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000969 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000970 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000971 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000972 req->in.numargs = 1;
973 req->in.args[0].size = sizeof(inarg);
974 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000975 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000976 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000977 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000978 req->out.argvar = 1;
979 req->out.args[0].size = size;
980 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000981 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000982 req->out.args[0].size = sizeof(outarg);
983 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000984 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000985 request_send(fc, req);
986 ret = req->out.h.error;
987 if (!ret)
988 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000989 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000990 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000991 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000992 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000993 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000994 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000995 fuse_put_request(fc, req);
996 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000997}
998
999static int fuse_removexattr(struct dentry *entry, const char *name)
1000{
1001 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001002 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001003 struct fuse_req *req;
1004 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001005
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001006 if (fc->no_removexattr)
1007 return -EOPNOTSUPP;
1008
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001009 req = fuse_get_request(fc);
1010 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +00001011 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001012
1013 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001014 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001015 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001016 req->in.numargs = 1;
1017 req->in.args[0].size = strlen(name) + 1;
1018 req->in.args[0].value = name;
1019 request_send(fc, req);
1020 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001021 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001022 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001023 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001024 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001025 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001026 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001027}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001028#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001029
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001030static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001031 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001032 .mkdir = fuse_mkdir,
1033 .symlink = fuse_symlink,
1034 .unlink = fuse_unlink,
1035 .rmdir = fuse_rmdir,
1036 .rename = fuse_rename,
1037 .link = fuse_link,
1038 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001039#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001040 .create = fuse_create,
1041 .mknod = fuse_mknod,
1042 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001043 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001044#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001045 .create = fuse_create_2_4,
1046 .mknod = fuse_mknod_2_4,
1047 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001048 .revalidate = fuse_revalidate,
1049#endif
1050#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001051 .setxattr = fuse_setxattr,
1052 .getxattr = fuse_getxattr,
1053 .listxattr = fuse_listxattr,
1054 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001055#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001056};
1057
1058static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001059 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001060 .read = generic_read_dir,
1061 .readdir = fuse_readdir,
1062 .open = fuse_dir_open,
1063 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001064 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001065};
1066
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001067static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001068 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001069#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001070 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001071 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001072#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001073 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001074 .revalidate = fuse_revalidate,
1075#endif
1076#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001077 .setxattr = fuse_setxattr,
1078 .getxattr = fuse_getxattr,
1079 .listxattr = fuse_listxattr,
1080 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001081#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001082};
1083
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001084static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001085 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001086 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001087#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001088 .put_link = fuse_put_link,
1089 .readlink = generic_readlink,
1090#else
1091 .readlink = fuse_readlink,
1092#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001093#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001094 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001095#else
1096 .revalidate = fuse_revalidate,
1097#endif
1098#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001099 .setxattr = fuse_setxattr,
1100 .getxattr = fuse_getxattr,
1101 .listxattr = fuse_listxattr,
1102 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001103#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001104};
1105
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001106void fuse_init_common(struct inode *inode)
1107{
1108 inode->i_op = &fuse_common_inode_operations;
1109}
1110
1111void fuse_init_dir(struct inode *inode)
1112{
1113 inode->i_op = &fuse_dir_inode_operations;
1114 inode->i_fop = &fuse_dir_operations;
1115}
1116
1117void fuse_init_symlink(struct inode *inode)
1118{
1119 inode->i_op = &fuse_symlink_inode_operations;
1120}