blob: 7e92f67b38955eaff9b81da7dc96c24c13136c88 [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 Szeredi3b9e53f2005-09-02 16:04:48 +000019#ifdef KERNEL_2_6
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};
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +000027 return jiffies + timespec_to_jiffies(&ts);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000028}
29
Miklos Szeredi2b478112005-11-28 13:27:10 +000030static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
31{
32 entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
33 if (entry->d_inode)
34 get_fuse_inode(entry->d_inode)->i_time =
35 time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
36}
37
38void fuse_invalidate_attr(struct inode *inode)
39{
40 get_fuse_inode(inode)->i_time = jiffies - 1;
41}
42
43static void fuse_invalidate_entry_cache(struct dentry *entry)
44{
45 entry->d_time = jiffies - 1;
46}
47
48static void fuse_invalidate_entry(struct dentry *entry)
49{
50 d_invalidate(entry);
51 fuse_invalidate_entry_cache(entry);
52}
53
Miklos Szeredi0f62d722005-01-04 12:45:54 +000054static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
55 struct dentry *entry,
56 struct fuse_entry_out *outarg)
57{
58 req->in.h.opcode = FUSE_LOOKUP;
59 req->in.h.nodeid = get_node_id(dir);
60 req->inode = dir;
61 req->in.numargs = 1;
62 req->in.args[0].size = entry->d_name.len + 1;
63 req->in.args[0].value = entry->d_name.name;
64 req->out.numargs = 1;
65 req->out.args[0].size = sizeof(struct fuse_entry_out);
66 req->out.args[0].value = outarg;
67}
68
69static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
70{
Miklos Szeredi2b478112005-11-28 13:27:10 +000071 struct inode *inode = entry->d_inode;
72
73 if (inode && is_bad_inode(inode))
Miklos Szeredi0f62d722005-01-04 12:45:54 +000074 return 0;
Miklos Szeredi81394522005-01-11 14:24:18 +000075 else if (time_after(jiffies, entry->d_time)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +000076 int err;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000077 struct fuse_entry_out outarg;
Miklos Szeredi2b478112005-11-28 13:27:10 +000078 struct fuse_conn *fc;
79 struct fuse_req *req;
80
81 fuse_invalidate_entry_cache(entry);
82 if (!inode)
83 return 0;
84
85 fc = get_fuse_conn(inode);
86 req = fuse_get_request(fc);
Miklos Szeredi0f62d722005-01-04 12:45:54 +000087 if (!req)
88 return 0;
89
90 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredif94e0102005-05-12 14:56:34 +000091 request_send(fc, req);
Miklos Szeredi0f62d722005-01-04 12:45:54 +000092 err = req->out.h.error;
Miklos Szeredi38009022005-05-08 19:47:22 +000093 if (!err) {
Miklos Szeredi2b478112005-11-28 13:27:10 +000094 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi38009022005-05-08 19:47:22 +000095 if (outarg.nodeid != get_node_id(inode)) {
96 fuse_send_forget(fc, req, outarg.nodeid, 1);
97 return 0;
98 }
99 fi->nlookup ++;
100 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000101 fuse_put_request(fc, req);
Miklos Szeredi38009022005-05-08 19:47:22 +0000102 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000103 return 0;
104
105 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000106 fuse_change_timeout(entry, &outarg);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000107 }
108 return 1;
109}
Miklos Szeredi2b478112005-11-28 13:27:10 +0000110
111static int dir_alias(struct inode *inode)
112{
113 if (S_ISDIR(inode->i_mode)) {
114 /* Don't allow creating an alias to a directory */
115 struct dentry *alias = d_find_alias(inode);
116#if defined(FUSE_MAINLINE) || !defined(KERNEL_2_6)
117 if (alias) {
118 dput(alias);
119 return 1;
120 }
121#else
122 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
123 dput(alias);
124 return 1;
125 }
126 dput(alias);
127#endif
128 }
129 return 0;
130}
131
132static inline int invalid_nodeid(u64 nodeid)
133{
134 return !nodeid || nodeid == FUSE_ROOT_ID;
135}
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000136#ifndef KERNEL_2_6
137static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
138{
139 return fuse_dentry_revalidate(entry, NULL);
140}
141#endif
142
143static struct dentry_operations fuse_dentry_operations = {
144#ifdef KERNEL_2_6
145 .d_revalidate = fuse_dentry_revalidate,
146#else
147 .d_revalidate = fuse_dentry_revalidate_2_4,
148#endif
149};
150
Miklos Szeredi2b478112005-11-28 13:27:10 +0000151static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
152 struct nameidata *nd)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000153{
Miklos Szeredie815c032004-01-19 18:20:49 +0000154 int err;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000155 struct fuse_entry_out outarg;
Miklos Szeredie815c032004-01-19 18:20:49 +0000156 struct inode *inode = NULL;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000157 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000158 struct fuse_req *req;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000159#if !defined(FUSE_MAINLINE) && defined(KERNEL_2_6)
160 struct dentry *newent;
161#endif
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000162
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000163 if (entry->d_name.len > FUSE_NAME_MAX)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000164 return ERR_PTR(-ENAMETOOLONG);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000165
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000166 req = fuse_get_request(fc);
167 if (!req)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000168 return ERR_PTR(-EINTR);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000169
Miklos Szeredie56818b2004-12-12 11:45:24 +0000170 fuse_lookup_init(req, dir, entry, &outarg);
171 request_send(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000172 err = req->out.h.error;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000173 if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid))
Miklos Szeredi6becf0b2005-09-23 11:25:28 +0000174 err = -EIO;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000175 if (!err && outarg.nodeid) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000176 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000177 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000178 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000179 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000180 return ERR_PTR(-ENOMEM);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000181 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000182 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000183 fuse_put_request(fc, req);
184 if (err && err != -ENOENT)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000185 return ERR_PTR(err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000186
Miklos Szeredi2b478112005-11-28 13:27:10 +0000187 if (inode && dir_alias(inode)) {
188 iput(inode);
189 return ERR_PTR(-EIO);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000190 }
Miklos Szeredi2b478112005-11-28 13:27:10 +0000191#if defined(FUSE_MAINLINE) || !defined(KERNEL_2_6)
192 d_add(entry, inode);
193#else
194 newent = d_splice_alias(inode, entry);
195 entry = newent ? newent : entry;
196#endif
Miklos Szeredi307242f2004-01-26 11:28:44 +0000197 entry->d_op = &fuse_dentry_operations;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000198 if (!err)
199 fuse_change_timeout(entry, &outarg);
200 else
201 fuse_invalidate_entry_cache(entry);
202#if defined(FUSE_MAINLINE) || !defined(KERNEL_2_6)
203 return NULL;
204#else
205 return newent;
206#endif
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000207}
208
Miklos Szeredid9079a72005-10-26 15:29:06 +0000209#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
210static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
211 struct nameidata *nd)
212{
213 int err;
214 struct inode *inode;
215 struct fuse_conn *fc = get_fuse_conn(dir);
216 struct fuse_req *req;
217 struct fuse_open_in inarg;
218 struct fuse_open_out outopen;
219 struct fuse_entry_out outentry;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000220 struct fuse_file *ff;
221 struct file *file;
222 int flags = nd->intent.open.flags - 1;
223
224 err = -ENOSYS;
225 if (fc->no_create)
226 goto out;
227
228 err = -ENAMETOOLONG;
229 if (entry->d_name.len > FUSE_NAME_MAX)
230 goto out;
231
232 err = -EINTR;
233 req = fuse_get_request(fc);
234 if (!req)
235 goto out;
236
237 ff = fuse_file_alloc();
238 if (!ff)
239 goto out_put_request;
240
241 flags &= ~O_NOCTTY;
242 memset(&inarg, 0, sizeof(inarg));
243 inarg.flags = flags;
244 inarg.mode = mode;
245 req->in.h.opcode = FUSE_CREATE;
246 req->in.h.nodeid = get_node_id(dir);
247 req->inode = dir;
248 req->in.numargs = 2;
249 req->in.args[0].size = sizeof(inarg);
250 req->in.args[0].value = &inarg;
251 req->in.args[1].size = entry->d_name.len + 1;
252 req->in.args[1].value = entry->d_name.name;
253 req->out.numargs = 2;
254 req->out.args[0].size = sizeof(outentry);
255 req->out.args[0].value = &outentry;
256 req->out.args[1].size = sizeof(outopen);
257 req->out.args[1].value = &outopen;
258 request_send(fc, req);
259 err = req->out.h.error;
260 if (err) {
261 if (err == -ENOSYS)
262 fc->no_create = 1;
263 goto out_free_ff;
264 }
265
266 err = -EIO;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000267 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
Miklos Szeredid9079a72005-10-26 15:29:06 +0000268 goto out_free_ff;
269
270 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
271 &outentry.attr);
272 err = -ENOMEM;
273 if (!inode) {
274 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
Miklos Szeredi1a906122005-11-28 16:31:40 +0000275 ff->fh = outopen.fh;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000276 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
277 goto out_put_request;
278 }
279 fuse_put_request(fc, req);
Miklos Szeredid9079a72005-10-26 15:29:06 +0000280 d_instantiate(entry, inode);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000281 fuse_change_timeout(entry, &outentry);
Miklos Szeredid9079a72005-10-26 15:29:06 +0000282 file = lookup_instantiate_filp(nd, entry, generic_file_open);
283 if (IS_ERR(file)) {
Miklos Szeredi1a906122005-11-28 16:31:40 +0000284 ff->fh = outopen.fh;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000285 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
286 return PTR_ERR(file);
287 }
288 fuse_finish_open(inode, file, ff, &outopen);
289 return 0;
290
291 out_free_ff:
292 fuse_file_free(ff);
293 out_put_request:
294 fuse_put_request(fc, req);
295 out:
296 return err;
297}
298#endif
299
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000300static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000301 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000302 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000303{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000304 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000305 struct inode *inode;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000306 int err;
307
308 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000309 req->inode = dir;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000310 req->out.numargs = 1;
311 req->out.args[0].size = sizeof(outarg);
312 req->out.args[0].value = &outarg;
313 request_send(fc, req);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000314 err = req->out.h.error;
315 if (err) {
316 fuse_put_request(fc, req);
317 return err;
318 }
Miklos Szeredi2b478112005-11-28 13:27:10 +0000319 if (invalid_nodeid(outarg.nodeid)) {
Miklos Szeredi6becf0b2005-09-23 11:25:28 +0000320 fuse_put_request(fc, req);
321 return -EIO;
322 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000323 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000324 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000325 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000326 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000327 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000328 }
329 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000330
331 /* Don't allow userspace to do really stupid things... */
Miklos Szeredi2b478112005-11-28 13:27:10 +0000332 if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000333 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000334 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000335 }
336
337 d_instantiate(entry, inode);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000338 fuse_change_timeout(entry, &outarg);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000339 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000340 return 0;
341}
342
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000343static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000344 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000345{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000346 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000347 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000348 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000349 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000350 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000351
352 memset(&inarg, 0, sizeof(inarg));
353 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000354 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000355 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000356 req->in.numargs = 2;
357 req->in.args[0].size = sizeof(inarg);
358 req->in.args[0].value = &inarg;
359 req->in.args[1].size = entry->d_name.len + 1;
360 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000361 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000362}
363
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000364static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
365 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000366{
Miklos Szeredid9079a72005-10-26 15:29:06 +0000367#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
368 if (nd && (nd->flags & LOOKUP_CREATE)) {
369 int err = fuse_create_open(dir, entry, mode, nd);
370 if (err != -ENOSYS)
371 return err;
372 /* Fall back on mknod */
373 }
374#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000375 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000376}
377
Miklos Szeredib483c932001-10-29 14:57:57 +0000378static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
379{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000380 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000381 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000382 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000383 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000384 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000385
386 memset(&inarg, 0, sizeof(inarg));
387 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000388 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000389 req->in.numargs = 2;
390 req->in.args[0].size = sizeof(inarg);
391 req->in.args[0].value = &inarg;
392 req->in.args[1].size = entry->d_name.len + 1;
393 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000394 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000395}
396
397static int fuse_symlink(struct inode *dir, struct dentry *entry,
398 const char *link)
399{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000400 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000401 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000402 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000403
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000404 if (len > FUSE_SYMLINK_MAX)
405 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000406
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000407 req = fuse_get_request(fc);
408 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000409 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000410
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000411 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000412 req->in.numargs = 2;
413 req->in.args[0].size = entry->d_name.len + 1;
414 req->in.args[0].value = entry->d_name.name;
415 req->in.args[1].size = len;
416 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000417 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000418}
419
Miklos Szeredib5958612004-02-20 14:10:49 +0000420static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000421{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000422 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000423 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000424 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000425 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000426 return -EINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000427
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000428 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000429 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000430 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000431 req->in.numargs = 1;
432 req->in.args[0].size = entry->d_name.len + 1;
433 req->in.args[0].value = entry->d_name.name;
434 request_send(fc, req);
435 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000436 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000437 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000438 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000439
Miklos Szeredib5958612004-02-20 14:10:49 +0000440 /* Set nlink to zero so the inode can be cleared, if
441 the inode does have more links this will be
442 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000443 inode->i_nlink = 0;
444 fuse_invalidate_attr(inode);
445 fuse_invalidate_attr(dir);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000446 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000447 } else if (err == -EINTR)
448 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000449 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000450}
451
452static int fuse_rmdir(struct inode *dir, struct dentry *entry)
453{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000454 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000455 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000456 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000457 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000458 return -EINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000459
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000460 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000461 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000462 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000463 req->in.numargs = 1;
464 req->in.args[0].size = entry->d_name.len + 1;
465 req->in.args[0].value = entry->d_name.name;
466 request_send(fc, req);
467 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000468 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000469 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000470 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000471 fuse_invalidate_attr(dir);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000472 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000473 } else if (err == -EINTR)
474 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000475 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000476}
477
478static int fuse_rename(struct inode *olddir, struct dentry *oldent,
479 struct inode *newdir, struct dentry *newent)
480{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000481 int err;
482 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000483 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000484 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000485 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000486 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000487
Miklos Szeredi43696432001-11-18 19:15:05 +0000488 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000489 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000490 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000491 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000492 req->inode = olddir;
493 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000494 req->in.numargs = 3;
495 req->in.args[0].size = sizeof(inarg);
496 req->in.args[0].value = &inarg;
497 req->in.args[1].size = oldent->d_name.len + 1;
498 req->in.args[1].value = oldent->d_name.name;
499 req->in.args[2].size = newent->d_name.len + 1;
500 req->in.args[2].value = newent->d_name.name;
501 request_send(fc, req);
502 err = req->out.h.error;
503 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000504 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000505 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000506 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000507 fuse_invalidate_attr(newdir);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000508
509 /* newent will end up negative */
510 fuse_invalidate_entry_cache(newent);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000511 } else if (err == -EINTR) {
512 /* If request was interrupted, DEITY only knows if the
513 rename actually took place. If the invalidation
514 fails (e.g. some process has CWD under the renamed
515 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000516 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000517 fuse_invalidate_entry(oldent);
518 if (newent->d_inode)
519 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000520 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000521
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000522 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000523}
524
525static int fuse_link(struct dentry *entry, struct inode *newdir,
526 struct dentry *newent)
527{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000528 int err;
529 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000530 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000531 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000532 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000533 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000534 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000535
Miklos Szeredi43696432001-11-18 19:15:05 +0000536 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000537 inarg.oldnodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000538 req->in.h.opcode = FUSE_LINK;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000539 req->inode2 = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000540 req->in.numargs = 2;
541 req->in.args[0].size = sizeof(inarg);
542 req->in.args[0].value = &inarg;
543 req->in.args[1].size = newent->d_name.len + 1;
544 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000545 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
546 /* Contrary to "normal" filesystems it can happen that link
547 makes two "logical" inodes point to the same "physical"
548 inode. We invalidate the attributes of the old one, so it
549 will reflect changes in the backing inode (link count,
550 etc.)
551 */
552 if (!err || err == -EINTR)
553 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000554 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000555}
556
Miklos Szeredif85ab242004-01-07 12:16:45 +0000557int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000558{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000559 int err;
560 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000561 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000562 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000563 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000564 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000565
566 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000567 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000568 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000569 req->out.numargs = 1;
570 req->out.args[0].size = sizeof(arg);
571 req->out.args[0].value = &arg;
572 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000573 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000574 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000575 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000576 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000577#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000578 if (get_node_id(inode) != FUSE_ROOT_ID)
579 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000580#else
581 make_bad_inode(inode);
582#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000583 err = -EIO;
584 } else {
585 struct fuse_inode *fi = get_fuse_inode(inode);
586 fuse_change_attributes(inode, &arg.attr);
587 fi->i_time = time_to_jiffies(arg.attr_valid,
588 arg.attr_valid_nsec);
589 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000590 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000591 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000592}
593
Miklos Szeredi61139db2005-04-29 07:38:25 +0000594/*
595 * Calling into a user-controlled filesystem gives the filesystem
596 * daemon ptrace-like capabilities over the requester process. This
597 * means, that the filesystem daemon is able to record the exact
598 * filesystem operations performed, and can also control the behavior
599 * of the requester process in otherwise impossible ways. For example
600 * it can delay the operation for arbitrary length of time allowing
601 * DoS against the requester.
602 *
603 * For this reason only those processes can call into the filesystem,
604 * for which the owner of the mount has ptrace privilege. This
605 * excludes processes started by other users, suid or sgid processes.
606 */
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000607static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
608{
609 if (fc->flags & FUSE_ALLOW_OTHER)
610 return 1;
611
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000612 if (task->euid == fc->user_id &&
613 task->suid == fc->user_id &&
614 task->uid == fc->user_id &&
615 task->egid == fc->group_id &&
616 task->sgid == fc->group_id &&
617 task->gid == fc->group_id)
618 return 1;
619
620 return 0;
621}
622
Miklos Szeredife25def2001-12-20 15:38:05 +0000623static int fuse_revalidate(struct dentry *entry)
624{
625 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000626 struct fuse_inode *fi = get_fuse_inode(inode);
627 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000628
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000629 if (!fuse_allow_task(fc, current))
630 return -EACCES;
631 if (get_node_id(inode) != FUSE_ROOT_ID &&
632 time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000633 return 0;
634
Miklos Szeredif85ab242004-01-07 12:16:45 +0000635 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000636}
637
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000638#ifdef KERNEL_2_6
639static int fuse_access(struct inode *inode, int mask)
640{
641 struct fuse_conn *fc = get_fuse_conn(inode);
642 struct fuse_req *req;
643 struct fuse_access_in inarg;
644 int err;
645
646 if (fc->no_access)
647 return 0;
648
649 req = fuse_get_request(fc);
650 if (!req)
651 return -EINTR;
652
653 memset(&inarg, 0, sizeof(inarg));
654 inarg.mask = mask;
655 req->in.h.opcode = FUSE_ACCESS;
656 req->in.h.nodeid = get_node_id(inode);
657 req->inode = inode;
658 req->in.numargs = 1;
659 req->in.args[0].size = sizeof(inarg);
660 req->in.args[0].value = &inarg;
661 request_send(fc, req);
662 err = req->out.h.error;
663 fuse_put_request(fc, req);
664 if (err == -ENOSYS) {
665 fc->no_access = 1;
666 err = 0;
667 }
668 return err;
669}
670#endif
671
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000672static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000673{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000674 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000675
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000676 if (!fuse_allow_task(fc, current))
Miklos Szeredife25def2001-12-20 15:38:05 +0000677 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000678 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000679#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000680 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000681#else
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000682 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000683#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000684
685 /* If permission is denied, try to refresh file
686 attributes. This is also needed, because the root
687 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000688 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000689 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000690 if (!err)
691#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000692 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000693#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000694 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000695#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000696 }
697
698 /* FIXME: Need some mechanism to revoke permissions:
699 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000700 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000701 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000702
Miklos Szeredife25def2001-12-20 15:38:05 +0000703 This is actually not so grave, since the user can
704 simply keep access to the file/directory anyway by
705 keeping it open... */
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000706
707 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000708 } else {
709 int mode = inode->i_mode;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000710#ifndef KERNEL_2_6_11_PLUS
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000711 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
712 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
713 return -EROFS;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000714#endif
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000715 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
716 return -EACCES;
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000717
718#ifdef KERNEL_2_6
719 if (nd && (nd->flags & LOOKUP_ACCESS))
720 return fuse_access(inode, mask);
721#endif
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000722 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000723 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000724}
725
Miklos Szeredib483c932001-10-29 14:57:57 +0000726static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
727 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000728{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000729 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000730 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000731 size_t reclen = FUSE_DIRENT_SIZE(dirent);
732 int over;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000733 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000734 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000735 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000736 break;
737
738 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi18fce982005-04-01 21:07:35 +0000739 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000740 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000741 break;
742
Miklos Szeredib483c932001-10-29 14:57:57 +0000743 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000744 nbytes -= reclen;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000745 file->f_pos = dirent->off;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000746 }
747
Miklos Szeredib483c932001-10-29 14:57:57 +0000748 return 0;
749}
750
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000751static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
752 struct inode *inode, loff_t pos,
753 size_t count)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000754{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000755 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000756}
757
Miklos Szeredib483c932001-10-29 14:57:57 +0000758static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
759{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000760 int err;
761 size_t nbytes;
762 struct page *page;
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000763 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000764 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredif94e0102005-05-12 14:56:34 +0000765 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000766 if (!req)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000767 return -EINTR;
Miklos Szeredie815c032004-01-19 18:20:49 +0000768
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000769 page = alloc_page(GFP_KERNEL);
770 if (!page) {
771 fuse_put_request(fc, req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000772 return -ENOMEM;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000773 }
774 req->num_pages = 1;
775 req->pages[0] = page;
776 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
777 err = req->out.h.error;
778 fuse_put_request(fc, req);
779 if (!err)
780 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
781 filldir);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000782
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000783 __free_page(page);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000784 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000785 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000786}
787
Miklos Szeredi05033042001-11-13 16:11:35 +0000788static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000789{
790 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000791 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000792 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000793 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000794
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000795 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000796 return ERR_PTR(-EINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000797
Miklos Szeredi05033042001-11-13 16:11:35 +0000798 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000799 if (!link) {
800 link = ERR_PTR(-ENOMEM);
801 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000802 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000803 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000804 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000805 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000806 req->out.argvar = 1;
807 req->out.numargs = 1;
808 req->out.args[0].size = PAGE_SIZE - 1;
809 req->out.args[0].value = link;
810 request_send(fc, req);
811 if (req->out.h.error) {
812 free_page((unsigned long) link);
813 link = ERR_PTR(req->out.h.error);
814 } else
815 link[req->out.args[0].size] = '\0';
816 out:
817 fuse_put_request(fc, req);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000818 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi05033042001-11-13 16:11:35 +0000819 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000820}
821
822static void free_link(char *link)
823{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000824 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000825 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000826}
827
Miklos Szeredi56487812005-09-02 13:05:06 +0000828#ifdef KERNEL_2_6_13_PLUS
829static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
830{
831 nd_set_link(nd, read_link(dentry));
832 return NULL;
833}
834
835static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
836{
837 free_link(nd_get_link(nd));
838}
839#elif defined(KERNEL_2_6_8_PLUS)
Miklos Szeredi81394522005-01-11 14:24:18 +0000840static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
841{
842 nd_set_link(nd, read_link(dentry));
843 return 0;
844}
845
846static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
847{
848 free_link(nd_get_link(nd));
849}
850#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000851static int fuse_readlink(struct dentry *dentry, char __user *buffer,
852 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000853{
854 int ret;
855 char *link;
856
Miklos Szeredi05033042001-11-13 16:11:35 +0000857 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000858 ret = vfs_readlink(dentry, buffer, buflen, link);
859 free_link(link);
860 return ret;
861}
862
863static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
864{
865 int ret;
866 char *link;
867
Miklos Szeredi05033042001-11-13 16:11:35 +0000868 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000869 ret = vfs_follow_link(nd, link);
870 free_link(link);
871 return ret;
872}
Miklos Szeredi81394522005-01-11 14:24:18 +0000873#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000874
875static int fuse_dir_open(struct inode *inode, struct file *file)
876{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000877 return fuse_open_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000878}
879
880static int fuse_dir_release(struct inode *inode, struct file *file)
881{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000882 return fuse_release_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000883}
884
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000885static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
886{
Miklos Szeredib7640d22005-04-08 15:15:28 +0000887 /* nfsd can call this with no file */
888 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000889}
890
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000891static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000892{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000893 unsigned ivalid = iattr->ia_valid;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000894
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000895 if (ivalid & ATTR_MODE)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000896 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000897 if (ivalid & ATTR_UID)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000898 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000899 if (ivalid & ATTR_GID)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000900 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000901 if (ivalid & ATTR_SIZE)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000902 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000903 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000904 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000905 arg->valid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000906#ifdef KERNEL_2_6
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000907 arg->atime = iattr->ia_atime.tv_sec;
908 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000909#else
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000910 arg->atime = iattr->ia_atime;
911 arg->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000912#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000913 }
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000914#ifdef ATTR_FILE
915 if (ivalid & ATTR_FILE) {
916 struct fuse_file *ff = iattr->ia_file->private_data;
917 arg->valid |= FATTR_FH;
918 arg->fh = ff->fh;
919 }
920#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000921}
922
923static int fuse_setattr(struct dentry *entry, struct iattr *attr)
924{
925 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000926 struct fuse_conn *fc = get_fuse_conn(inode);
927 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000928 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000929 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000930 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000931 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000932 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000933
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000934 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
935 err = inode_change_ok(inode, attr);
936 if (err)
937 return err;
938 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000939
Miklos Szeredi069c9502004-07-16 16:17:02 +0000940 if (attr->ia_valid & ATTR_SIZE) {
941 unsigned long limit;
942 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000943#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000944 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000945#else
946 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000947#endif
948 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000949 send_sig(SIGXFSZ, current, 0);
950 return -EFBIG;
951 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000952 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000953
954 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000956 return -EINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000957
Miklos Szeredi43696432001-11-18 19:15:05 +0000958 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000959 iattr_to_fattr(attr, &inarg);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000960 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000961 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000962 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000963 req->in.numargs = 1;
964 req->in.args[0].size = sizeof(inarg);
965 req->in.args[0].value = &inarg;
966 req->out.numargs = 1;
967 req->out.args[0].size = sizeof(outarg);
968 req->out.args[0].value = &outarg;
969 request_send(fc, req);
970 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000971 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000972 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000973 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000974#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000975 if (get_node_id(inode) != FUSE_ROOT_ID)
976 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000977#else
978 make_bad_inode(inode);
979#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000980 err = -EIO;
981 } else {
982 if (is_truncate) {
983 loff_t origsize = i_size_read(inode);
984 i_size_write(inode, outarg.attr.size);
985 if (origsize > outarg.attr.size)
986 vmtruncate(inode, outarg.attr.size);
987 }
988 fuse_change_attributes(inode, &outarg.attr);
989 fi->i_time = time_to_jiffies(outarg.attr_valid,
990 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000991 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000992 } else if (err == -EINTR)
993 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000994
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000995 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000996}
997
Miklos Szeredif85ab242004-01-07 12:16:45 +0000998#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000999static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1000 struct kstat *stat)
1001{
1002 struct inode *inode = entry->d_inode;
1003 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001004 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +00001005 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001006
Miklos Szeredif85ab242004-01-07 12:16:45 +00001007 return err;
1008}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001009#else /* KERNEL_2_6 */
Miklos Szeredi2b478112005-11-28 13:27:10 +00001010static struct dentry *fuse_lookup_2_4(struct inode *dir, struct dentry *entry)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001011{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001012 return fuse_lookup(dir, entry, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001013}
1014
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001015static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +00001016 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001017{
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001018 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001019}
1020
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001021static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
1022{
1023 return fuse_create(dir, entry, mode, NULL);
1024}
1025
1026static int fuse_permission_2_4(struct inode *inode, int mask)
1027{
1028 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001029}
1030#endif /* KERNEL_2_6 */
1031
1032#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +00001033#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001034static int fuse_setxattr(struct dentry *entry, const char *name,
1035 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001036#else
1037static int fuse_setxattr(struct dentry *entry, const char *name,
1038 void *value, size_t size, int flags)
1039#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001040{
1041 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001042 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001043 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001044 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001045 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001046
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001047 if (size > FUSE_XATTR_SIZE_MAX)
1048 return -E2BIG;
1049
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001050 if (fc->no_setxattr)
1051 return -EOPNOTSUPP;
1052
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001053 req = fuse_get_request(fc);
1054 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001055 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001056
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001057 memset(&inarg, 0, sizeof(inarg));
1058 inarg.size = size;
1059 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001061 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001062 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001063 req->in.numargs = 3;
1064 req->in.args[0].size = sizeof(inarg);
1065 req->in.args[0].value = &inarg;
1066 req->in.args[1].size = strlen(name) + 1;
1067 req->in.args[1].value = name;
1068 req->in.args[2].size = size;
1069 req->in.args[2].value = value;
1070 request_send(fc, req);
1071 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001072 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001073 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001074 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001075 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001076 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001077 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001078}
1079
1080static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1081 void *value, size_t size)
1082{
1083 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001084 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001085 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001086 struct fuse_getxattr_in inarg;
1087 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001088 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001089
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001090 if (fc->no_getxattr)
1091 return -EOPNOTSUPP;
1092
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001093 req = fuse_get_request(fc);
1094 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001095 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001096
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001097 memset(&inarg, 0, sizeof(inarg));
1098 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001099 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001100 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001101 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001102 req->in.numargs = 2;
1103 req->in.args[0].size = sizeof(inarg);
1104 req->in.args[0].value = &inarg;
1105 req->in.args[1].size = strlen(name) + 1;
1106 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001107 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001108 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001109 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001110 req->out.argvar = 1;
1111 req->out.args[0].size = size;
1112 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001113 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001114 req->out.args[0].size = sizeof(outarg);
1115 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001116 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001117 request_send(fc, req);
1118 ret = req->out.h.error;
1119 if (!ret)
1120 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001121 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001122 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001123 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001124 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001125 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001126 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001127 fuse_put_request(fc, req);
1128 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001129}
1130
1131static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1132{
1133 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001134 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001135 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001136 struct fuse_getxattr_in inarg;
1137 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001138 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001139
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001140 if (fc->no_listxattr)
1141 return -EOPNOTSUPP;
1142
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001143 req = fuse_get_request(fc);
1144 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001145 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001146
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001147 memset(&inarg, 0, sizeof(inarg));
1148 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001149 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001150 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001151 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001152 req->in.numargs = 1;
1153 req->in.args[0].size = sizeof(inarg);
1154 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001155 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001156 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001157 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001158 req->out.argvar = 1;
1159 req->out.args[0].size = size;
1160 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001161 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001162 req->out.args[0].size = sizeof(outarg);
1163 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001164 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001165 request_send(fc, req);
1166 ret = req->out.h.error;
1167 if (!ret)
1168 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001169 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001170 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001171 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001172 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001173 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001174 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001175 fuse_put_request(fc, req);
1176 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001177}
1178
1179static int fuse_removexattr(struct dentry *entry, const char *name)
1180{
1181 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001182 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001183 struct fuse_req *req;
1184 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001185
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001186 if (fc->no_removexattr)
1187 return -EOPNOTSUPP;
1188
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001189 req = fuse_get_request(fc);
1190 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001191 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001192
1193 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001194 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001195 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001196 req->in.numargs = 1;
1197 req->in.args[0].size = strlen(name) + 1;
1198 req->in.args[0].value = name;
1199 request_send(fc, req);
1200 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001201 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001202 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001203 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001204 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001205 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001206 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001207}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001208#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001209
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001210static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001211 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001212 .mkdir = fuse_mkdir,
1213 .symlink = fuse_symlink,
1214 .unlink = fuse_unlink,
1215 .rmdir = fuse_rmdir,
1216 .rename = fuse_rename,
1217 .link = fuse_link,
1218 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001219#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001220 .create = fuse_create,
1221 .mknod = fuse_mknod,
1222 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001223 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001224#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001225 .create = fuse_create_2_4,
1226 .mknod = fuse_mknod_2_4,
1227 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001228 .revalidate = fuse_revalidate,
1229#endif
1230#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001231 .setxattr = fuse_setxattr,
1232 .getxattr = fuse_getxattr,
1233 .listxattr = fuse_listxattr,
1234 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001235#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001236};
1237
1238static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001239 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001240 .read = generic_read_dir,
1241 .readdir = fuse_readdir,
1242 .open = fuse_dir_open,
1243 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001244 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001245};
1246
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001247static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001248 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001249#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001250 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001251 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001252#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001253 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001254 .revalidate = fuse_revalidate,
1255#endif
1256#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001257 .setxattr = fuse_setxattr,
1258 .getxattr = fuse_getxattr,
1259 .listxattr = fuse_listxattr,
1260 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001261#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001262};
1263
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001264static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001265 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001266 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001267#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001268 .put_link = fuse_put_link,
1269 .readlink = generic_readlink,
1270#else
1271 .readlink = fuse_readlink,
1272#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001273#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001274 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001275#else
1276 .revalidate = fuse_revalidate,
1277#endif
1278#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001279 .setxattr = fuse_setxattr,
1280 .getxattr = fuse_getxattr,
1281 .listxattr = fuse_listxattr,
1282 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001283#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001284};
1285
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001286void fuse_init_common(struct inode *inode)
1287{
1288 inode->i_op = &fuse_common_inode_operations;
1289}
1290
1291void fuse_init_dir(struct inode *inode)
1292{
1293 inode->i_op = &fuse_dir_inode_operations;
1294 inode->i_fop = &fuse_dir_operations;
1295}
1296
1297void fuse_init_symlink(struct inode *inode)
1298{
1299 inode->i_op = &fuse_symlink_inode_operations;
1300}