blob: 21fd59c7bc24d5d25728114ed4c4d0824ea6fb61 [file] [log] [blame]
Miklos Szeredie5e55582005-09-09 13:10:28 -07001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
11#include <linux/pagemap.h>
12#include <linux/file.h>
13#include <linux/gfp.h>
14#include <linux/sched.h>
15#include <linux/namei.h>
16
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080017/*
18 * FUSE caches dentries and attributes with separate timeout. The
19 * time in jiffies until the dentry/attributes are valid is stored in
20 * dentry->d_time and fuse_inode->i_time respectively.
21 */
22
23/*
24 * Calculate the time in jiffies until a dentry/attributes are valid
25 */
Miklos Szeredi8bfc0162006-01-16 22:14:28 -080026static unsigned long time_to_jiffies(unsigned long sec, unsigned long nsec)
Miklos Szeredie5e55582005-09-09 13:10:28 -070027{
28 struct timespec ts = {sec, nsec};
29 return jiffies + timespec_to_jiffies(&ts);
30}
31
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080032/*
33 * Set dentry and possibly attribute timeouts from the lookup/mk*
34 * replies
35 */
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080036static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
37{
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080038 entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080039 if (entry->d_inode)
40 get_fuse_inode(entry->d_inode)->i_time =
41 time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
42}
43
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080044/*
45 * Mark the attributes as stale, so that at the next call to
46 * ->getattr() they will be fetched from userspace
47 */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080048void fuse_invalidate_attr(struct inode *inode)
49{
50 get_fuse_inode(inode)->i_time = jiffies - 1;
51}
52
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080053/*
54 * Just mark the entry as stale, so that a next attempt to look it up
55 * will result in a new lookup call to userspace
56 *
57 * This is called when a dentry is about to become negative and the
58 * timeout is unknown (unlink, rmdir, rename and in some cases
59 * lookup)
60 */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080061static void fuse_invalidate_entry_cache(struct dentry *entry)
62{
63 entry->d_time = jiffies - 1;
64}
65
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080066/*
67 * Same as fuse_invalidate_entry_cache(), but also try to remove the
68 * dentry from the hash
69 */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -080070static void fuse_invalidate_entry(struct dentry *entry)
71{
72 d_invalidate(entry);
73 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -080074}
75
Miklos Szeredie5e55582005-09-09 13:10:28 -070076static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
77 struct dentry *entry,
78 struct fuse_entry_out *outarg)
79{
80 req->in.h.opcode = FUSE_LOOKUP;
81 req->in.h.nodeid = get_node_id(dir);
82 req->inode = dir;
83 req->in.numargs = 1;
84 req->in.args[0].size = entry->d_name.len + 1;
85 req->in.args[0].value = entry->d_name.name;
86 req->out.numargs = 1;
87 req->out.args[0].size = sizeof(struct fuse_entry_out);
88 req->out.args[0].value = outarg;
89}
90
Miklos Szeredi6f9f1182006-01-06 00:19:39 -080091/*
92 * Check whether the dentry is still valid
93 *
94 * If the entry validity timeout has expired and the dentry is
95 * positive, try to redo the lookup. If the lookup results in a
96 * different inode, then let the VFS invalidate the dentry and redo
97 * the lookup once more. If the lookup results in the same inode,
98 * then refresh the attributes, timeouts and mark the dentry valid.
99 */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700100static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
101{
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800102 struct inode *inode = entry->d_inode;
103
104 if (inode && is_bad_inode(inode))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700105 return 0;
106 else if (time_after(jiffies, entry->d_time)) {
107 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700108 struct fuse_entry_out outarg;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800109 struct fuse_conn *fc;
110 struct fuse_req *req;
111
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800112 /* Doesn't hurt to "reset" the validity timeout */
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800113 fuse_invalidate_entry_cache(entry);
114 if (!inode)
115 return 0;
116
117 fc = get_fuse_conn(inode);
118 req = fuse_get_request(fc);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700119 if (!req)
120 return 0;
121
122 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700123 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700124 err = req->out.h.error;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700125 if (!err) {
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800126 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700127 if (outarg.nodeid != get_node_id(inode)) {
128 fuse_send_forget(fc, req, outarg.nodeid, 1);
129 return 0;
130 }
131 fi->nlookup ++;
132 }
Miklos Szeredie5e55582005-09-09 13:10:28 -0700133 fuse_put_request(fc, req);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700134 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700135 return 0;
136
137 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800138 fuse_change_timeout(entry, &outarg);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700139 }
140 return 1;
141}
142
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800143/*
144 * Check if there's already a hashed alias of this directory inode.
145 * If yes, then lookup and mkdir must not create a new alias.
146 */
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800147static int dir_alias(struct inode *inode)
148{
149 if (S_ISDIR(inode->i_mode)) {
Miklos Szeredif007d5c2005-11-28 13:44:16 -0800150 struct dentry *alias = d_find_alias(inode);
151 if (alias) {
152 dput(alias);
153 return 1;
154 }
155 }
156 return 0;
157}
158
Miklos Szeredi8bfc0162006-01-16 22:14:28 -0800159static int invalid_nodeid(u64 nodeid)
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800160{
161 return !nodeid || nodeid == FUSE_ROOT_ID;
162}
163
Miklos Szeredie5e55582005-09-09 13:10:28 -0700164static struct dentry_operations fuse_dentry_operations = {
165 .d_revalidate = fuse_dentry_revalidate,
166};
167
Miklos Szeredi8bfc0162006-01-16 22:14:28 -0800168static int valid_mode(int m)
Miklos Szeredi39ee0592006-01-06 00:19:43 -0800169{
170 return S_ISREG(m) || S_ISDIR(m) || S_ISLNK(m) || S_ISCHR(m) ||
171 S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
172}
173
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800174static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
175 struct nameidata *nd)
Miklos Szeredie5e55582005-09-09 13:10:28 -0700176{
177 int err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700178 struct fuse_entry_out outarg;
179 struct inode *inode = NULL;
180 struct fuse_conn *fc = get_fuse_conn(dir);
181 struct fuse_req *req;
182
183 if (entry->d_name.len > FUSE_NAME_MAX)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800184 return ERR_PTR(-ENAMETOOLONG);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700185
186 req = fuse_get_request(fc);
187 if (!req)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800188 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700189
190 fuse_lookup_init(req, dir, entry, &outarg);
191 request_send(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700192 err = req->out.h.error;
Miklos Szeredi39ee0592006-01-06 00:19:43 -0800193 if (!err && ((outarg.nodeid && invalid_nodeid(outarg.nodeid)) ||
194 !valid_mode(outarg.attr.mode)))
Miklos Szerediee4e5272005-09-27 21:45:21 -0700195 err = -EIO;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800196 if (!err && outarg.nodeid) {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700197 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700198 &outarg.attr);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700199 if (!inode) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700200 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800201 return ERR_PTR(-ENOMEM);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700202 }
203 }
204 fuse_put_request(fc, req);
205 if (err && err != -ENOENT)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800206 return ERR_PTR(err);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700207
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800208 if (inode && dir_alias(inode)) {
209 iput(inode);
210 return ERR_PTR(-EIO);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700211 }
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800212 d_add(entry, inode);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700213 entry->d_op = &fuse_dentry_operations;
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800214 if (!err)
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800215 fuse_change_timeout(entry, &outarg);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800216 else
217 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800218 return NULL;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700219}
220
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800221/*
222 * Atomic create+open operation
223 *
224 * If the filesystem doesn't support this, then fall back to separate
225 * 'mknod' + 'open' requests.
226 */
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800227static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
228 struct nameidata *nd)
229{
230 int err;
231 struct inode *inode;
232 struct fuse_conn *fc = get_fuse_conn(dir);
233 struct fuse_req *req;
234 struct fuse_open_in inarg;
235 struct fuse_open_out outopen;
236 struct fuse_entry_out outentry;
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800237 struct fuse_file *ff;
238 struct file *file;
239 int flags = nd->intent.open.flags - 1;
240
241 err = -ENOSYS;
242 if (fc->no_create)
243 goto out;
244
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800245 err = -EINTR;
246 req = fuse_get_request(fc);
247 if (!req)
248 goto out;
249
250 ff = fuse_file_alloc();
251 if (!ff)
252 goto out_put_request;
253
254 flags &= ~O_NOCTTY;
255 memset(&inarg, 0, sizeof(inarg));
256 inarg.flags = flags;
257 inarg.mode = mode;
258 req->in.h.opcode = FUSE_CREATE;
259 req->in.h.nodeid = get_node_id(dir);
260 req->inode = dir;
261 req->in.numargs = 2;
262 req->in.args[0].size = sizeof(inarg);
263 req->in.args[0].value = &inarg;
264 req->in.args[1].size = entry->d_name.len + 1;
265 req->in.args[1].value = entry->d_name.name;
266 req->out.numargs = 2;
267 req->out.args[0].size = sizeof(outentry);
268 req->out.args[0].value = &outentry;
269 req->out.args[1].size = sizeof(outopen);
270 req->out.args[1].value = &outopen;
271 request_send(fc, req);
272 err = req->out.h.error;
273 if (err) {
274 if (err == -ENOSYS)
275 fc->no_create = 1;
276 goto out_free_ff;
277 }
278
279 err = -EIO;
Miklos Szeredi2827d0b22005-11-28 13:44:16 -0800280 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800281 goto out_free_ff;
282
283 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
284 &outentry.attr);
285 err = -ENOMEM;
286 if (!inode) {
287 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
288 ff->fh = outopen.fh;
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800289 /* Special release, with inode = NULL, this will
290 trigger a 'forget' request when the release is
291 complete */
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800292 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
293 goto out_put_request;
294 }
295 fuse_put_request(fc, req);
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800296 d_instantiate(entry, inode);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800297 fuse_change_timeout(entry, &outentry);
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800298 file = lookup_instantiate_filp(nd, entry, generic_file_open);
299 if (IS_ERR(file)) {
300 ff->fh = outopen.fh;
301 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
302 return PTR_ERR(file);
303 }
304 fuse_finish_open(inode, file, ff, &outopen);
305 return 0;
306
307 out_free_ff:
308 fuse_file_free(ff);
309 out_put_request:
310 fuse_put_request(fc, req);
311 out:
312 return err;
313}
314
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800315/*
316 * Code shared between mknod, mkdir, symlink and link
317 */
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700318static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
319 struct inode *dir, struct dentry *entry,
320 int mode)
321{
322 struct fuse_entry_out outarg;
323 struct inode *inode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700324 int err;
325
326 req->in.h.nodeid = get_node_id(dir);
327 req->inode = dir;
328 req->out.numargs = 1;
329 req->out.args[0].size = sizeof(outarg);
330 req->out.args[0].value = &outarg;
331 request_send(fc, req);
332 err = req->out.h.error;
333 if (err) {
334 fuse_put_request(fc, req);
335 return err;
336 }
Miklos Szeredi39ee0592006-01-06 00:19:43 -0800337 err = -EIO;
338 if (invalid_nodeid(outarg.nodeid))
339 goto out_put_request;
340
341 if ((outarg.attr.mode ^ mode) & S_IFMT)
342 goto out_put_request;
343
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700344 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
345 &outarg.attr);
346 if (!inode) {
347 fuse_send_forget(fc, req, outarg.nodeid, 1);
348 return -ENOMEM;
349 }
350 fuse_put_request(fc, req);
351
Miklos Szeredi39ee0592006-01-06 00:19:43 -0800352 if (dir_alias(inode)) {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700353 iput(inode);
354 return -EIO;
355 }
356
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700357 d_instantiate(entry, inode);
Miklos Szeredi0aa7c692006-01-06 00:19:34 -0800358 fuse_change_timeout(entry, &outarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700359 fuse_invalidate_attr(dir);
360 return 0;
Miklos Szeredi39ee0592006-01-06 00:19:43 -0800361
362 out_put_request:
363 fuse_put_request(fc, req);
364 return err;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700365}
366
367static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
368 dev_t rdev)
369{
370 struct fuse_mknod_in inarg;
371 struct fuse_conn *fc = get_fuse_conn(dir);
372 struct fuse_req *req = fuse_get_request(fc);
373 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700374 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700375
376 memset(&inarg, 0, sizeof(inarg));
377 inarg.mode = mode;
378 inarg.rdev = new_encode_dev(rdev);
379 req->in.h.opcode = FUSE_MKNOD;
380 req->in.numargs = 2;
381 req->in.args[0].size = sizeof(inarg);
382 req->in.args[0].value = &inarg;
383 req->in.args[1].size = entry->d_name.len + 1;
384 req->in.args[1].value = entry->d_name.name;
385 return create_new_entry(fc, req, dir, entry, mode);
386}
387
388static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
389 struct nameidata *nd)
390{
Miklos Szeredifd72faa2005-11-07 00:59:51 -0800391 if (nd && (nd->flags & LOOKUP_CREATE)) {
392 int err = fuse_create_open(dir, entry, mode, nd);
393 if (err != -ENOSYS)
394 return err;
395 /* Fall back on mknod */
396 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700397 return fuse_mknod(dir, entry, mode, 0);
398}
399
400static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
401{
402 struct fuse_mkdir_in inarg;
403 struct fuse_conn *fc = get_fuse_conn(dir);
404 struct fuse_req *req = fuse_get_request(fc);
405 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700406 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700407
408 memset(&inarg, 0, sizeof(inarg));
409 inarg.mode = mode;
410 req->in.h.opcode = FUSE_MKDIR;
411 req->in.numargs = 2;
412 req->in.args[0].size = sizeof(inarg);
413 req->in.args[0].value = &inarg;
414 req->in.args[1].size = entry->d_name.len + 1;
415 req->in.args[1].value = entry->d_name.name;
416 return create_new_entry(fc, req, dir, entry, S_IFDIR);
417}
418
419static int fuse_symlink(struct inode *dir, struct dentry *entry,
420 const char *link)
421{
422 struct fuse_conn *fc = get_fuse_conn(dir);
423 unsigned len = strlen(link) + 1;
Miklos Szeredi1d3d7522006-01-06 00:19:40 -0800424 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700425 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700426 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700427
428 req->in.h.opcode = FUSE_SYMLINK;
429 req->in.numargs = 2;
430 req->in.args[0].size = entry->d_name.len + 1;
431 req->in.args[0].value = entry->d_name.name;
432 req->in.args[1].size = len;
433 req->in.args[1].value = link;
434 return create_new_entry(fc, req, dir, entry, S_IFLNK);
435}
436
437static int fuse_unlink(struct inode *dir, struct dentry *entry)
438{
439 int err;
440 struct fuse_conn *fc = get_fuse_conn(dir);
441 struct fuse_req *req = fuse_get_request(fc);
442 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700443 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700444
445 req->in.h.opcode = FUSE_UNLINK;
446 req->in.h.nodeid = get_node_id(dir);
447 req->inode = dir;
448 req->in.numargs = 1;
449 req->in.args[0].size = entry->d_name.len + 1;
450 req->in.args[0].value = entry->d_name.name;
451 request_send(fc, req);
452 err = req->out.h.error;
453 fuse_put_request(fc, req);
454 if (!err) {
455 struct inode *inode = entry->d_inode;
456
457 /* Set nlink to zero so the inode can be cleared, if
458 the inode does have more links this will be
459 discovered at the next lookup/getattr */
460 inode->i_nlink = 0;
461 fuse_invalidate_attr(inode);
462 fuse_invalidate_attr(dir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800463 fuse_invalidate_entry_cache(entry);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700464 } else if (err == -EINTR)
465 fuse_invalidate_entry(entry);
466 return err;
467}
468
469static int fuse_rmdir(struct inode *dir, struct dentry *entry)
470{
471 int err;
472 struct fuse_conn *fc = get_fuse_conn(dir);
473 struct fuse_req *req = fuse_get_request(fc);
474 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700475 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700476
477 req->in.h.opcode = FUSE_RMDIR;
478 req->in.h.nodeid = get_node_id(dir);
479 req->inode = dir;
480 req->in.numargs = 1;
481 req->in.args[0].size = entry->d_name.len + 1;
482 req->in.args[0].value = entry->d_name.name;
483 request_send(fc, req);
484 err = req->out.h.error;
485 fuse_put_request(fc, req);
486 if (!err) {
487 entry->d_inode->i_nlink = 0;
488 fuse_invalidate_attr(dir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800489 fuse_invalidate_entry_cache(entry);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700490 } else if (err == -EINTR)
491 fuse_invalidate_entry(entry);
492 return err;
493}
494
495static int fuse_rename(struct inode *olddir, struct dentry *oldent,
496 struct inode *newdir, struct dentry *newent)
497{
498 int err;
499 struct fuse_rename_in inarg;
500 struct fuse_conn *fc = get_fuse_conn(olddir);
501 struct fuse_req *req = fuse_get_request(fc);
502 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700503 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700504
505 memset(&inarg, 0, sizeof(inarg));
506 inarg.newdir = get_node_id(newdir);
507 req->in.h.opcode = FUSE_RENAME;
508 req->in.h.nodeid = get_node_id(olddir);
509 req->inode = olddir;
510 req->inode2 = newdir;
511 req->in.numargs = 3;
512 req->in.args[0].size = sizeof(inarg);
513 req->in.args[0].value = &inarg;
514 req->in.args[1].size = oldent->d_name.len + 1;
515 req->in.args[1].value = oldent->d_name.name;
516 req->in.args[2].size = newent->d_name.len + 1;
517 req->in.args[2].value = newent->d_name.name;
518 request_send(fc, req);
519 err = req->out.h.error;
520 fuse_put_request(fc, req);
521 if (!err) {
522 fuse_invalidate_attr(olddir);
523 if (olddir != newdir)
524 fuse_invalidate_attr(newdir);
Miklos Szeredi8cbdf1e2006-01-06 00:19:38 -0800525
526 /* newent will end up negative */
527 if (newent->d_inode)
528 fuse_invalidate_entry_cache(newent);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700529 } else if (err == -EINTR) {
530 /* If request was interrupted, DEITY only knows if the
531 rename actually took place. If the invalidation
532 fails (e.g. some process has CWD under the renamed
533 directory), then there can be inconsistency between
534 the dcache and the real filesystem. Tough luck. */
535 fuse_invalidate_entry(oldent);
536 if (newent->d_inode)
537 fuse_invalidate_entry(newent);
538 }
539
540 return err;
541}
542
543static int fuse_link(struct dentry *entry, struct inode *newdir,
544 struct dentry *newent)
545{
546 int err;
547 struct fuse_link_in inarg;
548 struct inode *inode = entry->d_inode;
549 struct fuse_conn *fc = get_fuse_conn(inode);
550 struct fuse_req *req = fuse_get_request(fc);
551 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700552 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700553
554 memset(&inarg, 0, sizeof(inarg));
555 inarg.oldnodeid = get_node_id(inode);
556 req->in.h.opcode = FUSE_LINK;
557 req->inode2 = inode;
558 req->in.numargs = 2;
559 req->in.args[0].size = sizeof(inarg);
560 req->in.args[0].value = &inarg;
561 req->in.args[1].size = newent->d_name.len + 1;
562 req->in.args[1].value = newent->d_name.name;
563 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
564 /* Contrary to "normal" filesystems it can happen that link
565 makes two "logical" inodes point to the same "physical"
566 inode. We invalidate the attributes of the old one, so it
567 will reflect changes in the backing inode (link count,
568 etc.)
569 */
570 if (!err || err == -EINTR)
571 fuse_invalidate_attr(inode);
572 return err;
573}
574
Miklos Szeredie5e55582005-09-09 13:10:28 -0700575int fuse_do_getattr(struct inode *inode)
576{
577 int err;
578 struct fuse_attr_out arg;
579 struct fuse_conn *fc = get_fuse_conn(inode);
580 struct fuse_req *req = fuse_get_request(fc);
581 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700582 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700583
584 req->in.h.opcode = FUSE_GETATTR;
585 req->in.h.nodeid = get_node_id(inode);
586 req->inode = inode;
587 req->out.numargs = 1;
588 req->out.args[0].size = sizeof(arg);
589 req->out.args[0].value = &arg;
590 request_send(fc, req);
591 err = req->out.h.error;
592 fuse_put_request(fc, req);
593 if (!err) {
594 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
595 make_bad_inode(inode);
596 err = -EIO;
597 } else {
598 struct fuse_inode *fi = get_fuse_inode(inode);
599 fuse_change_attributes(inode, &arg.attr);
600 fi->i_time = time_to_jiffies(arg.attr_valid,
601 arg.attr_valid_nsec);
602 }
603 }
604 return err;
605}
606
Miklos Szeredi87729a52005-09-09 13:10:34 -0700607/*
608 * Calling into a user-controlled filesystem gives the filesystem
609 * daemon ptrace-like capabilities over the requester process. This
610 * means, that the filesystem daemon is able to record the exact
611 * filesystem operations performed, and can also control the behavior
612 * of the requester process in otherwise impossible ways. For example
613 * it can delay the operation for arbitrary length of time allowing
614 * DoS against the requester.
615 *
616 * For this reason only those processes can call into the filesystem,
617 * for which the owner of the mount has ptrace privilege. This
618 * excludes processes started by other users, suid or sgid processes.
619 */
620static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
621{
622 if (fc->flags & FUSE_ALLOW_OTHER)
623 return 1;
624
625 if (task->euid == fc->user_id &&
626 task->suid == fc->user_id &&
627 task->uid == fc->user_id &&
628 task->egid == fc->group_id &&
629 task->sgid == fc->group_id &&
630 task->gid == fc->group_id)
631 return 1;
632
633 return 0;
634}
635
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800636/*
637 * Check whether the inode attributes are still valid
638 *
639 * If the attribute validity timeout has expired, then fetch the fresh
640 * attributes with a 'getattr' request
641 *
642 * I'm not sure why cached attributes are never returned for the root
643 * inode, this is probably being too cautious.
644 */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700645static int fuse_revalidate(struct dentry *entry)
646{
647 struct inode *inode = entry->d_inode;
648 struct fuse_inode *fi = get_fuse_inode(inode);
649 struct fuse_conn *fc = get_fuse_conn(inode);
650
Miklos Szeredi87729a52005-09-09 13:10:34 -0700651 if (!fuse_allow_task(fc, current))
652 return -EACCES;
653 if (get_node_id(inode) != FUSE_ROOT_ID &&
654 time_before_eq(jiffies, fi->i_time))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700655 return 0;
656
657 return fuse_do_getattr(inode);
658}
659
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800660static int fuse_access(struct inode *inode, int mask)
661{
662 struct fuse_conn *fc = get_fuse_conn(inode);
663 struct fuse_req *req;
664 struct fuse_access_in inarg;
665 int err;
666
667 if (fc->no_access)
668 return 0;
669
670 req = fuse_get_request(fc);
671 if (!req)
672 return -EINTR;
673
674 memset(&inarg, 0, sizeof(inarg));
675 inarg.mask = mask;
676 req->in.h.opcode = FUSE_ACCESS;
677 req->in.h.nodeid = get_node_id(inode);
678 req->inode = inode;
679 req->in.numargs = 1;
680 req->in.args[0].size = sizeof(inarg);
681 req->in.args[0].value = &inarg;
682 request_send(fc, req);
683 err = req->out.h.error;
684 fuse_put_request(fc, req);
685 if (err == -ENOSYS) {
686 fc->no_access = 1;
687 err = 0;
688 }
689 return err;
690}
691
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800692/*
693 * Check permission. The two basic access models of FUSE are:
694 *
695 * 1) Local access checking ('default_permissions' mount option) based
696 * on file mode. This is the plain old disk filesystem permission
697 * modell.
698 *
699 * 2) "Remote" access checking, where server is responsible for
700 * checking permission in each inode operation. An exception to this
701 * is if ->permission() was invoked from sys_access() in which case an
702 * access request is sent. Execute permission is still checked
703 * locally based on file mode.
704 */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700705static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
706{
707 struct fuse_conn *fc = get_fuse_conn(inode);
708
Miklos Szeredi87729a52005-09-09 13:10:34 -0700709 if (!fuse_allow_task(fc, current))
Miklos Szeredie5e55582005-09-09 13:10:28 -0700710 return -EACCES;
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700711 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
712 int err = generic_permission(inode, mask, NULL);
713
714 /* If permission is denied, try to refresh file
715 attributes. This is also needed, because the root
716 node will at first have no permissions */
717 if (err == -EACCES) {
718 err = fuse_do_getattr(inode);
719 if (!err)
720 err = generic_permission(inode, mask, NULL);
721 }
722
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800723 /* Note: the opposite of the above test does not
724 exist. So if permissions are revoked this won't be
725 noticed immediately, only after the attribute
726 timeout has expired */
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700727
728 return err;
729 } else {
Miklos Szeredie5e55582005-09-09 13:10:28 -0700730 int mode = inode->i_mode;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700731 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
732 return -EACCES;
Miklos Szeredi31d40d72005-11-07 00:59:50 -0800733
734 if (nd && (nd->flags & LOOKUP_ACCESS))
735 return fuse_access(inode, mask);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700736 return 0;
737 }
738}
739
740static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
741 void *dstbuf, filldir_t filldir)
742{
743 while (nbytes >= FUSE_NAME_OFFSET) {
744 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
745 size_t reclen = FUSE_DIRENT_SIZE(dirent);
746 int over;
747 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
748 return -EIO;
749 if (reclen > nbytes)
750 break;
751
752 over = filldir(dstbuf, dirent->name, dirent->namelen,
753 file->f_pos, dirent->ino, dirent->type);
754 if (over)
755 break;
756
757 buf += reclen;
758 nbytes -= reclen;
759 file->f_pos = dirent->off;
760 }
761
762 return 0;
763}
764
Miklos Szeredie5e55582005-09-09 13:10:28 -0700765static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
766{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700767 int err;
768 size_t nbytes;
769 struct page *page;
770 struct inode *inode = file->f_dentry->d_inode;
771 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi248d86e2006-01-06 00:19:39 -0800772 struct fuse_req *req;
773
774 if (is_bad_inode(inode))
775 return -EIO;
776
777 req = fuse_get_request(fc);
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700778 if (!req)
779 return -EINTR;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700780
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700781 page = alloc_page(GFP_KERNEL);
782 if (!page) {
783 fuse_put_request(fc, req);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700784 return -ENOMEM;
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700785 }
786 req->num_pages = 1;
787 req->pages[0] = page;
Miklos Szeredi361b1eb52006-01-16 22:14:45 -0800788 fuse_read_fill(req, file, inode, file->f_pos, PAGE_SIZE, FUSE_READDIR);
789 request_send(fc, req);
790 nbytes = req->out.args[0].size;
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700791 err = req->out.h.error;
792 fuse_put_request(fc, req);
793 if (!err)
794 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
795 filldir);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700796
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700797 __free_page(page);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700798 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700799 return err;
Miklos Szeredie5e55582005-09-09 13:10:28 -0700800}
801
802static char *read_link(struct dentry *dentry)
803{
804 struct inode *inode = dentry->d_inode;
805 struct fuse_conn *fc = get_fuse_conn(inode);
806 struct fuse_req *req = fuse_get_request(fc);
807 char *link;
808
809 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700810 return ERR_PTR(-EINTR);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700811
812 link = (char *) __get_free_page(GFP_KERNEL);
813 if (!link) {
814 link = ERR_PTR(-ENOMEM);
815 goto out;
816 }
817 req->in.h.opcode = FUSE_READLINK;
818 req->in.h.nodeid = get_node_id(inode);
819 req->inode = inode;
820 req->out.argvar = 1;
821 req->out.numargs = 1;
822 req->out.args[0].size = PAGE_SIZE - 1;
823 req->out.args[0].value = link;
824 request_send(fc, req);
825 if (req->out.h.error) {
826 free_page((unsigned long) link);
827 link = ERR_PTR(req->out.h.error);
828 } else
829 link[req->out.args[0].size] = '\0';
830 out:
831 fuse_put_request(fc, req);
Miklos Szeredib36c31b2005-09-09 13:10:38 -0700832 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredie5e55582005-09-09 13:10:28 -0700833 return link;
834}
835
836static void free_link(char *link)
837{
838 if (!IS_ERR(link))
839 free_page((unsigned long) link);
840}
841
842static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
843{
844 nd_set_link(nd, read_link(dentry));
845 return NULL;
846}
847
848static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
849{
850 free_link(nd_get_link(nd));
851}
852
853static int fuse_dir_open(struct inode *inode, struct file *file)
854{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700855 return fuse_open_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700856}
857
858static int fuse_dir_release(struct inode *inode, struct file *file)
859{
Miklos Szeredi04730fe2005-09-09 13:10:36 -0700860 return fuse_release_common(inode, file, 1);
Miklos Szeredie5e55582005-09-09 13:10:28 -0700861}
862
Miklos Szeredi82547982005-09-09 13:10:38 -0700863static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
864{
865 /* nfsd can call this with no file */
866 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
867}
868
Miklos Szeredibefc6492005-11-07 00:59:52 -0800869static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700870{
871 unsigned ivalid = iattr->ia_valid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700872
873 if (ivalid & ATTR_MODE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800874 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700875 if (ivalid & ATTR_UID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800876 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700877 if (ivalid & ATTR_GID)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800878 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700879 if (ivalid & ATTR_SIZE)
Miklos Szeredibefc6492005-11-07 00:59:52 -0800880 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700881 /* You can only _set_ these together (they may change by themselves) */
882 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredibefc6492005-11-07 00:59:52 -0800883 arg->valid |= FATTR_ATIME | FATTR_MTIME;
884 arg->atime = iattr->ia_atime.tv_sec;
885 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700886 }
Miklos Szeredibefc6492005-11-07 00:59:52 -0800887 if (ivalid & ATTR_FILE) {
888 struct fuse_file *ff = iattr->ia_file->private_data;
889 arg->valid |= FATTR_FH;
890 arg->fh = ff->fh;
891 }
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700892}
893
Miklos Szeredi6f9f1182006-01-06 00:19:39 -0800894/*
895 * Set attributes, and at the same time refresh them.
896 *
897 * Truncation is slightly complicated, because the 'truncate' request
898 * may fail, in which case we don't want to touch the mapping.
899 * vmtruncate() doesn't allow for this case. So do the rlimit
900 * checking by hand and call vmtruncate() only after the file has
901 * actually been truncated.
902 */
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700903static int fuse_setattr(struct dentry *entry, struct iattr *attr)
904{
905 struct inode *inode = entry->d_inode;
906 struct fuse_conn *fc = get_fuse_conn(inode);
907 struct fuse_inode *fi = get_fuse_inode(inode);
908 struct fuse_req *req;
909 struct fuse_setattr_in inarg;
910 struct fuse_attr_out outarg;
911 int err;
912 int is_truncate = 0;
913
Miklos Szeredi1e9a4ed2005-09-09 13:10:31 -0700914 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
915 err = inode_change_ok(inode, attr);
916 if (err)
917 return err;
918 }
919
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700920 if (attr->ia_valid & ATTR_SIZE) {
921 unsigned long limit;
922 is_truncate = 1;
923 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
924 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
925 send_sig(SIGXFSZ, current, 0);
926 return -EFBIG;
927 }
928 }
929
930 req = fuse_get_request(fc);
931 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700932 return -EINTR;
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700933
934 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredibefc6492005-11-07 00:59:52 -0800935 iattr_to_fattr(attr, &inarg);
Miklos Szeredi9e6268d2005-09-09 13:10:29 -0700936 req->in.h.opcode = FUSE_SETATTR;
937 req->in.h.nodeid = get_node_id(inode);
938 req->inode = inode;
939 req->in.numargs = 1;
940 req->in.args[0].size = sizeof(inarg);
941 req->in.args[0].value = &inarg;
942 req->out.numargs = 1;
943 req->out.args[0].size = sizeof(outarg);
944 req->out.args[0].value = &outarg;
945 request_send(fc, req);
946 err = req->out.h.error;
947 fuse_put_request(fc, req);
948 if (!err) {
949 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
950 make_bad_inode(inode);
951 err = -EIO;
952 } else {
953 if (is_truncate) {
954 loff_t origsize = i_size_read(inode);
955 i_size_write(inode, outarg.attr.size);
956 if (origsize > outarg.attr.size)
957 vmtruncate(inode, outarg.attr.size);
958 }
959 fuse_change_attributes(inode, &outarg.attr);
960 fi->i_time = time_to_jiffies(outarg.attr_valid,
961 outarg.attr_valid_nsec);
962 }
963 } else if (err == -EINTR)
964 fuse_invalidate_attr(inode);
965
966 return err;
967}
968
Miklos Szeredie5e55582005-09-09 13:10:28 -0700969static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
970 struct kstat *stat)
971{
972 struct inode *inode = entry->d_inode;
973 int err = fuse_revalidate(entry);
974 if (!err)
975 generic_fillattr(inode, stat);
976
977 return err;
978}
979
Miklos Szeredi92a87802005-09-09 13:10:31 -0700980static int fuse_setxattr(struct dentry *entry, const char *name,
981 const void *value, size_t size, int flags)
982{
983 struct inode *inode = entry->d_inode;
984 struct fuse_conn *fc = get_fuse_conn(inode);
985 struct fuse_req *req;
986 struct fuse_setxattr_in inarg;
987 int err;
988
Miklos Szeredi92a87802005-09-09 13:10:31 -0700989 if (fc->no_setxattr)
990 return -EOPNOTSUPP;
991
992 req = fuse_get_request(fc);
993 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -0700994 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -0700995
996 memset(&inarg, 0, sizeof(inarg));
997 inarg.size = size;
998 inarg.flags = flags;
999 req->in.h.opcode = FUSE_SETXATTR;
1000 req->in.h.nodeid = get_node_id(inode);
1001 req->inode = inode;
1002 req->in.numargs = 3;
1003 req->in.args[0].size = sizeof(inarg);
1004 req->in.args[0].value = &inarg;
1005 req->in.args[1].size = strlen(name) + 1;
1006 req->in.args[1].value = name;
1007 req->in.args[2].size = size;
1008 req->in.args[2].value = value;
1009 request_send(fc, req);
1010 err = req->out.h.error;
1011 fuse_put_request(fc, req);
1012 if (err == -ENOSYS) {
1013 fc->no_setxattr = 1;
1014 err = -EOPNOTSUPP;
1015 }
1016 return err;
1017}
1018
1019static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1020 void *value, size_t size)
1021{
1022 struct inode *inode = entry->d_inode;
1023 struct fuse_conn *fc = get_fuse_conn(inode);
1024 struct fuse_req *req;
1025 struct fuse_getxattr_in inarg;
1026 struct fuse_getxattr_out outarg;
1027 ssize_t ret;
1028
1029 if (fc->no_getxattr)
1030 return -EOPNOTSUPP;
1031
1032 req = fuse_get_request(fc);
1033 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001034 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001035
1036 memset(&inarg, 0, sizeof(inarg));
1037 inarg.size = size;
1038 req->in.h.opcode = FUSE_GETXATTR;
1039 req->in.h.nodeid = get_node_id(inode);
1040 req->inode = inode;
1041 req->in.numargs = 2;
1042 req->in.args[0].size = sizeof(inarg);
1043 req->in.args[0].value = &inarg;
1044 req->in.args[1].size = strlen(name) + 1;
1045 req->in.args[1].value = name;
1046 /* This is really two different operations rolled into one */
1047 req->out.numargs = 1;
1048 if (size) {
1049 req->out.argvar = 1;
1050 req->out.args[0].size = size;
1051 req->out.args[0].value = value;
1052 } else {
1053 req->out.args[0].size = sizeof(outarg);
1054 req->out.args[0].value = &outarg;
1055 }
1056 request_send(fc, req);
1057 ret = req->out.h.error;
1058 if (!ret)
1059 ret = size ? req->out.args[0].size : outarg.size;
1060 else {
1061 if (ret == -ENOSYS) {
1062 fc->no_getxattr = 1;
1063 ret = -EOPNOTSUPP;
1064 }
1065 }
1066 fuse_put_request(fc, req);
1067 return ret;
1068}
1069
1070static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1071{
1072 struct inode *inode = entry->d_inode;
1073 struct fuse_conn *fc = get_fuse_conn(inode);
1074 struct fuse_req *req;
1075 struct fuse_getxattr_in inarg;
1076 struct fuse_getxattr_out outarg;
1077 ssize_t ret;
1078
1079 if (fc->no_listxattr)
1080 return -EOPNOTSUPP;
1081
1082 req = fuse_get_request(fc);
1083 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001084 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001085
1086 memset(&inarg, 0, sizeof(inarg));
1087 inarg.size = size;
1088 req->in.h.opcode = FUSE_LISTXATTR;
1089 req->in.h.nodeid = get_node_id(inode);
1090 req->inode = inode;
1091 req->in.numargs = 1;
1092 req->in.args[0].size = sizeof(inarg);
1093 req->in.args[0].value = &inarg;
1094 /* This is really two different operations rolled into one */
1095 req->out.numargs = 1;
1096 if (size) {
1097 req->out.argvar = 1;
1098 req->out.args[0].size = size;
1099 req->out.args[0].value = list;
1100 } else {
1101 req->out.args[0].size = sizeof(outarg);
1102 req->out.args[0].value = &outarg;
1103 }
1104 request_send(fc, req);
1105 ret = req->out.h.error;
1106 if (!ret)
1107 ret = size ? req->out.args[0].size : outarg.size;
1108 else {
1109 if (ret == -ENOSYS) {
1110 fc->no_listxattr = 1;
1111 ret = -EOPNOTSUPP;
1112 }
1113 }
1114 fuse_put_request(fc, req);
1115 return ret;
1116}
1117
1118static int fuse_removexattr(struct dentry *entry, const char *name)
1119{
1120 struct inode *inode = entry->d_inode;
1121 struct fuse_conn *fc = get_fuse_conn(inode);
1122 struct fuse_req *req;
1123 int err;
1124
1125 if (fc->no_removexattr)
1126 return -EOPNOTSUPP;
1127
1128 req = fuse_get_request(fc);
1129 if (!req)
Miklos Szeredi7c352bd2005-09-09 13:10:39 -07001130 return -EINTR;
Miklos Szeredi92a87802005-09-09 13:10:31 -07001131
1132 req->in.h.opcode = FUSE_REMOVEXATTR;
1133 req->in.h.nodeid = get_node_id(inode);
1134 req->inode = inode;
1135 req->in.numargs = 1;
1136 req->in.args[0].size = strlen(name) + 1;
1137 req->in.args[0].value = name;
1138 request_send(fc, req);
1139 err = req->out.h.error;
1140 fuse_put_request(fc, req);
1141 if (err == -ENOSYS) {
1142 fc->no_removexattr = 1;
1143 err = -EOPNOTSUPP;
1144 }
1145 return err;
1146}
1147
Miklos Szeredie5e55582005-09-09 13:10:28 -07001148static struct inode_operations fuse_dir_inode_operations = {
1149 .lookup = fuse_lookup,
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001150 .mkdir = fuse_mkdir,
1151 .symlink = fuse_symlink,
1152 .unlink = fuse_unlink,
1153 .rmdir = fuse_rmdir,
1154 .rename = fuse_rename,
1155 .link = fuse_link,
1156 .setattr = fuse_setattr,
1157 .create = fuse_create,
1158 .mknod = fuse_mknod,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001159 .permission = fuse_permission,
1160 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001161 .setxattr = fuse_setxattr,
1162 .getxattr = fuse_getxattr,
1163 .listxattr = fuse_listxattr,
1164 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001165};
1166
1167static struct file_operations fuse_dir_operations = {
Miklos Szeredib6aeade2005-09-09 13:10:30 -07001168 .llseek = generic_file_llseek,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001169 .read = generic_read_dir,
1170 .readdir = fuse_readdir,
1171 .open = fuse_dir_open,
1172 .release = fuse_dir_release,
Miklos Szeredi82547982005-09-09 13:10:38 -07001173 .fsync = fuse_dir_fsync,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001174};
1175
1176static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001177 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001178 .permission = fuse_permission,
1179 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001180 .setxattr = fuse_setxattr,
1181 .getxattr = fuse_getxattr,
1182 .listxattr = fuse_listxattr,
1183 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001184};
1185
1186static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredi9e6268d2005-09-09 13:10:29 -07001187 .setattr = fuse_setattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001188 .follow_link = fuse_follow_link,
1189 .put_link = fuse_put_link,
1190 .readlink = generic_readlink,
1191 .getattr = fuse_getattr,
Miklos Szeredi92a87802005-09-09 13:10:31 -07001192 .setxattr = fuse_setxattr,
1193 .getxattr = fuse_getxattr,
1194 .listxattr = fuse_listxattr,
1195 .removexattr = fuse_removexattr,
Miklos Szeredie5e55582005-09-09 13:10:28 -07001196};
1197
1198void fuse_init_common(struct inode *inode)
1199{
1200 inode->i_op = &fuse_common_inode_operations;
1201}
1202
1203void fuse_init_dir(struct inode *inode)
1204{
1205 inode->i_op = &fuse_dir_inode_operations;
1206 inode->i_fop = &fuse_dir_operations;
1207}
1208
1209void fuse_init_symlink(struct inode *inode)
1210{
1211 inode->i_op = &fuse_symlink_inode_operations;
1212}