blob: 8c161b6a133768951f8bdb31ae2494e476c7196a [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 Szeredifb02fec2005-11-29 15:24:02 +000023/*
24 * FUSE caches dentries and attributes with separate timeout. The
25 * time in jiffies until the dentry/attributes are valid is stored in
26 * dentry->d_time and fuse_inode->i_time respectively.
27 */
28
29/*
30 * Calcualte the time in jiffies until a dentry/attributes are valid
31 */
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000032static inline unsigned long time_to_jiffies(unsigned long sec,
33 unsigned long nsec)
34{
Miklos Szeredi81394522005-01-11 14:24:18 +000035 struct timespec ts = {sec, nsec};
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +000036 return jiffies + timespec_to_jiffies(&ts);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000037}
38
Miklos Szeredifb02fec2005-11-29 15:24:02 +000039/*
40 * Set dentry and possibly attribute timeouts from the lookup/mk*
41 * replies
42 */
Miklos Szeredi2b478112005-11-28 13:27:10 +000043static void fuse_change_timeout(struct dentry *entry, struct fuse_entry_out *o)
44{
45 entry->d_time = time_to_jiffies(o->entry_valid, o->entry_valid_nsec);
46 if (entry->d_inode)
47 get_fuse_inode(entry->d_inode)->i_time =
48 time_to_jiffies(o->attr_valid, o->attr_valid_nsec);
49}
50
Miklos Szeredifb02fec2005-11-29 15:24:02 +000051/*
52 * Mark the attributes as stale, so that at the next call to
53 * ->getattr() they will be fetched from userspace
54 */
Miklos Szeredi2b478112005-11-28 13:27:10 +000055void fuse_invalidate_attr(struct inode *inode)
56{
57 get_fuse_inode(inode)->i_time = jiffies - 1;
58}
59
Miklos Szeredifb02fec2005-11-29 15:24:02 +000060/*
61 * Just mark the entry as stale, so that a next attempt to look it up
62 * will result in a new lookup call to userspace
63 *
64 * This is called when a dentry is about to become negative and the
65 * timeout is unknown (unlink, rmdir, rename and in some cases
66 * lookup)
67 */
Miklos Szeredi2b478112005-11-28 13:27:10 +000068static void fuse_invalidate_entry_cache(struct dentry *entry)
69{
70 entry->d_time = jiffies - 1;
71}
72
Miklos Szeredifb02fec2005-11-29 15:24:02 +000073/*
74 * Same as fuse_invalidate_entry_cache(), but also try to remove the
75 * dentry from the hash
76 */
Miklos Szeredi2b478112005-11-28 13:27:10 +000077static void fuse_invalidate_entry(struct dentry *entry)
78{
79 d_invalidate(entry);
80 fuse_invalidate_entry_cache(entry);
81}
82
Miklos Szeredi0f62d722005-01-04 12:45:54 +000083static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
84 struct dentry *entry,
85 struct fuse_entry_out *outarg)
86{
87 req->in.h.opcode = FUSE_LOOKUP;
88 req->in.h.nodeid = get_node_id(dir);
89 req->inode = dir;
90 req->in.numargs = 1;
91 req->in.args[0].size = entry->d_name.len + 1;
92 req->in.args[0].value = entry->d_name.name;
93 req->out.numargs = 1;
94 req->out.args[0].size = sizeof(struct fuse_entry_out);
95 req->out.args[0].value = outarg;
96}
97
Miklos Szeredifb02fec2005-11-29 15:24:02 +000098/*
99 * Check whether the dentry is still valid
100 *
101 * If the entry validity timeout has expired and the dentry is
102 * positive, try to redo the lookup. If the lookup results in a
103 * different inode, then let the VFS invalidate the dentry and redo
104 * the lookup once more. If the lookup results in the same inode,
105 * then refresh the attributes, timeouts and mark the dentry valid.
106 */
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000107static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
108{
Miklos Szeredi2b478112005-11-28 13:27:10 +0000109 struct inode *inode = entry->d_inode;
110
111 if (inode && is_bad_inode(inode))
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000112 return 0;
Miklos Szeredi81394522005-01-11 14:24:18 +0000113 else if (time_after(jiffies, entry->d_time)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000114 int err;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000115 struct fuse_entry_out outarg;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000116 struct fuse_conn *fc;
117 struct fuse_req *req;
118
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000119 /* Doesn't hurt to "reset" the validity timeout */
Miklos Szeredi2b478112005-11-28 13:27:10 +0000120 fuse_invalidate_entry_cache(entry);
121 if (!inode)
122 return 0;
123
124 fc = get_fuse_conn(inode);
125 req = fuse_get_request(fc);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000126 if (!req)
127 return 0;
128
129 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredif94e0102005-05-12 14:56:34 +0000130 request_send(fc, req);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000131 err = req->out.h.error;
Miklos Szeredi38009022005-05-08 19:47:22 +0000132 if (!err) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000133 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi38009022005-05-08 19:47:22 +0000134 if (outarg.nodeid != get_node_id(inode)) {
135 fuse_send_forget(fc, req, outarg.nodeid, 1);
136 return 0;
137 }
138 fi->nlookup ++;
139 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000140 fuse_put_request(fc, req);
Miklos Szeredi38009022005-05-08 19:47:22 +0000141 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000142 return 0;
143
144 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000145 fuse_change_timeout(entry, &outarg);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000146 }
147 return 1;
148}
Miklos Szeredi2b478112005-11-28 13:27:10 +0000149
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000150/*
151 * Check if there's already a hashed alias of this directory inode.
152 * If yes, then lookup and mkdir must not create a new alias.
153 */
Miklos Szeredi2b478112005-11-28 13:27:10 +0000154static int dir_alias(struct inode *inode)
155{
156 if (S_ISDIR(inode->i_mode)) {
Miklos Szeredi2b478112005-11-28 13:27:10 +0000157 struct dentry *alias = d_find_alias(inode);
158#if defined(FUSE_MAINLINE) || !defined(KERNEL_2_6)
159 if (alias) {
160 dput(alias);
161 return 1;
162 }
163#else
164 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
165 dput(alias);
166 return 1;
167 }
168 dput(alias);
169#endif
170 }
171 return 0;
172}
173
174static inline int invalid_nodeid(u64 nodeid)
175{
176 return !nodeid || nodeid == FUSE_ROOT_ID;
177}
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000178#ifndef KERNEL_2_6
179static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
180{
181 return fuse_dentry_revalidate(entry, NULL);
182}
183#endif
184
185static struct dentry_operations fuse_dentry_operations = {
186#ifdef KERNEL_2_6
187 .d_revalidate = fuse_dentry_revalidate,
188#else
189 .d_revalidate = fuse_dentry_revalidate_2_4,
190#endif
191};
192
Miklos Szeredi2b478112005-11-28 13:27:10 +0000193static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
194 struct nameidata *nd)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000195{
Miklos Szeredie815c032004-01-19 18:20:49 +0000196 int err;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000197 struct fuse_entry_out outarg;
Miklos Szeredie815c032004-01-19 18:20:49 +0000198 struct inode *inode = NULL;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000199 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000200 struct fuse_req *req;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000201#if !defined(FUSE_MAINLINE) && defined(KERNEL_2_6)
202 struct dentry *newent;
203#endif
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000204
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000205 if (entry->d_name.len > fc->name_max)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000206 return ERR_PTR(-ENAMETOOLONG);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000207
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000208 req = fuse_get_request(fc);
209 if (!req)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000210 return ERR_PTR(-EINTR);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000211
Miklos Szeredie56818b2004-12-12 11:45:24 +0000212 fuse_lookup_init(req, dir, entry, &outarg);
213 request_send(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000214 err = req->out.h.error;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000215 if (!err && outarg.nodeid && invalid_nodeid(outarg.nodeid))
Miklos Szeredi6becf0b2005-09-23 11:25:28 +0000216 err = -EIO;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000217 if (!err && outarg.nodeid) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000218 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000219 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000220 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000221 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000222 return ERR_PTR(-ENOMEM);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000223 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000224 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000225 fuse_put_request(fc, req);
226 if (err && err != -ENOENT)
Miklos Szeredi2b478112005-11-28 13:27:10 +0000227 return ERR_PTR(err);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000228
Miklos Szeredi2b478112005-11-28 13:27:10 +0000229 if (inode && dir_alias(inode)) {
230 iput(inode);
231 return ERR_PTR(-EIO);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000232 }
Miklos Szeredi2b478112005-11-28 13:27:10 +0000233#if defined(FUSE_MAINLINE) || !defined(KERNEL_2_6)
234 d_add(entry, inode);
235#else
236 newent = d_splice_alias(inode, entry);
237 entry = newent ? newent : entry;
238#endif
Miklos Szeredi307242f2004-01-26 11:28:44 +0000239 entry->d_op = &fuse_dentry_operations;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000240 if (!err)
241 fuse_change_timeout(entry, &outarg);
242 else
243 fuse_invalidate_entry_cache(entry);
244#if defined(FUSE_MAINLINE) || !defined(KERNEL_2_6)
245 return NULL;
246#else
247 return newent;
248#endif
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000249}
250
Miklos Szeredid9079a72005-10-26 15:29:06 +0000251#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000252/*
253 * Atomic create+open operation
254 *
255 * If the filesystem doesn't support this, then fall back to separate
256 * 'mknod' + 'open' requests.
257 */
Miklos Szeredid9079a72005-10-26 15:29:06 +0000258static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
259 struct nameidata *nd)
260{
261 int err;
262 struct inode *inode;
263 struct fuse_conn *fc = get_fuse_conn(dir);
264 struct fuse_req *req;
265 struct fuse_open_in inarg;
266 struct fuse_open_out outopen;
267 struct fuse_entry_out outentry;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000268 struct fuse_file *ff;
269 struct file *file;
270 int flags = nd->intent.open.flags - 1;
271
272 err = -ENOSYS;
273 if (fc->no_create)
274 goto out;
275
276 err = -ENAMETOOLONG;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000277 if (entry->d_name.len > fc->name_max)
Miklos Szeredid9079a72005-10-26 15:29:06 +0000278 goto out;
279
280 err = -EINTR;
281 req = fuse_get_request(fc);
282 if (!req)
283 goto out;
284
285 ff = fuse_file_alloc();
286 if (!ff)
287 goto out_put_request;
288
289 flags &= ~O_NOCTTY;
290 memset(&inarg, 0, sizeof(inarg));
291 inarg.flags = flags;
292 inarg.mode = mode;
293 req->in.h.opcode = FUSE_CREATE;
294 req->in.h.nodeid = get_node_id(dir);
295 req->inode = dir;
296 req->in.numargs = 2;
297 req->in.args[0].size = sizeof(inarg);
298 req->in.args[0].value = &inarg;
299 req->in.args[1].size = entry->d_name.len + 1;
300 req->in.args[1].value = entry->d_name.name;
301 req->out.numargs = 2;
302 req->out.args[0].size = sizeof(outentry);
303 req->out.args[0].value = &outentry;
304 req->out.args[1].size = sizeof(outopen);
305 req->out.args[1].value = &outopen;
306 request_send(fc, req);
307 err = req->out.h.error;
308 if (err) {
309 if (err == -ENOSYS)
310 fc->no_create = 1;
311 goto out_free_ff;
312 }
313
314 err = -EIO;
Miklos Szeredi2b478112005-11-28 13:27:10 +0000315 if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
Miklos Szeredid9079a72005-10-26 15:29:06 +0000316 goto out_free_ff;
317
318 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
319 &outentry.attr);
320 err = -ENOMEM;
321 if (!inode) {
322 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
Miklos Szeredi1a906122005-11-28 16:31:40 +0000323 ff->fh = outopen.fh;
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000324 /* Special release, with inode = NULL, this will
325 trigger a 'forget' request when the release is
326 complete */
Miklos Szeredid9079a72005-10-26 15:29:06 +0000327 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
328 goto out_put_request;
329 }
330 fuse_put_request(fc, req);
Miklos Szeredid9079a72005-10-26 15:29:06 +0000331 d_instantiate(entry, inode);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000332 fuse_change_timeout(entry, &outentry);
Miklos Szeredid9079a72005-10-26 15:29:06 +0000333 file = lookup_instantiate_filp(nd, entry, generic_file_open);
334 if (IS_ERR(file)) {
Miklos Szeredi1a906122005-11-28 16:31:40 +0000335 ff->fh = outopen.fh;
Miklos Szeredid9079a72005-10-26 15:29:06 +0000336 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
337 return PTR_ERR(file);
338 }
339 fuse_finish_open(inode, file, ff, &outopen);
340 return 0;
341
342 out_free_ff:
343 fuse_file_free(ff);
344 out_put_request:
345 fuse_put_request(fc, req);
346 out:
347 return err;
348}
349#endif
350
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000351/*
352 * Code shared between mknod, mkdir, symlink and link
353 */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000354static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000355 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000356 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000357{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000358 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000359 struct inode *inode;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000360 int err;
361
362 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000363 req->inode = dir;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000364 req->out.numargs = 1;
365 req->out.args[0].size = sizeof(outarg);
366 req->out.args[0].value = &outarg;
367 request_send(fc, req);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000368 err = req->out.h.error;
369 if (err) {
370 fuse_put_request(fc, req);
371 return err;
372 }
Miklos Szeredi2b478112005-11-28 13:27:10 +0000373 if (invalid_nodeid(outarg.nodeid)) {
Miklos Szeredi6becf0b2005-09-23 11:25:28 +0000374 fuse_put_request(fc, req);
375 return -EIO;
376 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000377 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000378 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000379 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000380 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000381 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000382 }
383 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000384
385 /* Don't allow userspace to do really stupid things... */
Miklos Szeredi2b478112005-11-28 13:27:10 +0000386 if (((inode->i_mode ^ mode) & S_IFMT) || dir_alias(inode)) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000387 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000388 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000389 }
390
391 d_instantiate(entry, inode);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000392 fuse_change_timeout(entry, &outarg);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000393 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000394 return 0;
395}
396
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000397static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000398 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000399{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000400 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000401 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000402 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000403 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000404 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000405
406 memset(&inarg, 0, sizeof(inarg));
407 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000408 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000409 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000410 req->in.numargs = 2;
411 req->in.args[0].size = sizeof(inarg);
412 req->in.args[0].value = &inarg;
413 req->in.args[1].size = entry->d_name.len + 1;
414 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000415 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000416}
417
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000418static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
419 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000420{
Miklos Szeredid9079a72005-10-26 15:29:06 +0000421#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
422 if (nd && (nd->flags & LOOKUP_CREATE)) {
423 int err = fuse_create_open(dir, entry, mode, nd);
424 if (err != -ENOSYS)
425 return err;
426 /* Fall back on mknod */
427 }
428#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000429 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430}
431
Miklos Szeredib483c932001-10-29 14:57:57 +0000432static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
433{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000434 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000435 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000436 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000437 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000438 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000439
440 memset(&inarg, 0, sizeof(inarg));
441 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000442 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000443 req->in.numargs = 2;
444 req->in.args[0].size = sizeof(inarg);
445 req->in.args[0].value = &inarg;
446 req->in.args[1].size = entry->d_name.len + 1;
447 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000448 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000449}
450
451static int fuse_symlink(struct inode *dir, struct dentry *entry,
452 const char *link)
453{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000454 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000455 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000456 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000457
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000458 if (len > fc->symlink_max)
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000459 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000460
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000461 req = fuse_get_request(fc);
462 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000463 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000464
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000465 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000466 req->in.numargs = 2;
467 req->in.args[0].size = entry->d_name.len + 1;
468 req->in.args[0].value = entry->d_name.name;
469 req->in.args[1].size = len;
470 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000471 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000472}
473
Miklos Szeredib5958612004-02-20 14:10:49 +0000474static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000475{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000476 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000477 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000478 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000479 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000480 return -EINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000481
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000482 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000483 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000484 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000485 req->in.numargs = 1;
486 req->in.args[0].size = entry->d_name.len + 1;
487 req->in.args[0].value = entry->d_name.name;
488 request_send(fc, req);
489 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000490 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000491 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000492 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000493
Miklos Szeredib5958612004-02-20 14:10:49 +0000494 /* Set nlink to zero so the inode can be cleared, if
495 the inode does have more links this will be
496 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000497 inode->i_nlink = 0;
498 fuse_invalidate_attr(inode);
499 fuse_invalidate_attr(dir);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000500 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000501 } else if (err == -EINTR)
502 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000503 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000504}
505
506static int fuse_rmdir(struct inode *dir, struct dentry *entry)
507{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000508 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000509 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000510 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000511 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000512 return -EINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000513
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000514 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000515 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000516 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000517 req->in.numargs = 1;
518 req->in.args[0].size = entry->d_name.len + 1;
519 req->in.args[0].value = entry->d_name.name;
520 request_send(fc, req);
521 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000522 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000523 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000524 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000525 fuse_invalidate_attr(dir);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000526 fuse_invalidate_entry_cache(entry);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000527 } else if (err == -EINTR)
528 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000529 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000530}
531
532static int fuse_rename(struct inode *olddir, struct dentry *oldent,
533 struct inode *newdir, struct dentry *newent)
534{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000535 int err;
536 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000537 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000538 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000539 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000540 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000541
Miklos Szeredi43696432001-11-18 19:15:05 +0000542 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000543 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000544 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000545 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000546 req->inode = olddir;
547 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000548 req->in.numargs = 3;
549 req->in.args[0].size = sizeof(inarg);
550 req->in.args[0].value = &inarg;
551 req->in.args[1].size = oldent->d_name.len + 1;
552 req->in.args[1].value = oldent->d_name.name;
553 req->in.args[2].size = newent->d_name.len + 1;
554 req->in.args[2].value = newent->d_name.name;
555 request_send(fc, req);
556 err = req->out.h.error;
557 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000558 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000559 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000560 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000561 fuse_invalidate_attr(newdir);
Miklos Szeredi2b478112005-11-28 13:27:10 +0000562
563 /* newent will end up negative */
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000564 if (newent->d_inode)
565 fuse_invalidate_entry_cache(newent);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000566 } else if (err == -EINTR) {
567 /* If request was interrupted, DEITY only knows if the
568 rename actually took place. If the invalidation
569 fails (e.g. some process has CWD under the renamed
570 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000571 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000572 fuse_invalidate_entry(oldent);
573 if (newent->d_inode)
574 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000575 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000576
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000577 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000578}
579
580static int fuse_link(struct dentry *entry, struct inode *newdir,
581 struct dentry *newent)
582{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000583 int err;
584 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000585 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000586 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000587 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000588 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000589 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000590
Miklos Szeredi43696432001-11-18 19:15:05 +0000591 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000592 inarg.oldnodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000593 req->in.h.opcode = FUSE_LINK;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000594 req->inode2 = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000595 req->in.numargs = 2;
596 req->in.args[0].size = sizeof(inarg);
597 req->in.args[0].value = &inarg;
598 req->in.args[1].size = newent->d_name.len + 1;
599 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000600 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
601 /* Contrary to "normal" filesystems it can happen that link
602 makes two "logical" inodes point to the same "physical"
603 inode. We invalidate the attributes of the old one, so it
604 will reflect changes in the backing inode (link count,
605 etc.)
606 */
607 if (!err || err == -EINTR)
608 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000609 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000610}
611
Miklos Szeredif85ab242004-01-07 12:16:45 +0000612int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000613{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000614 int err;
615 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000616 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000617 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000618 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000619 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000620
621 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000622 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000623 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000624 req->out.numargs = 1;
625 req->out.args[0].size = sizeof(arg);
626 req->out.args[0].value = &arg;
627 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000628 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000629 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000630 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000631 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000632#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000633 if (get_node_id(inode) != FUSE_ROOT_ID)
634 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000635#else
636 make_bad_inode(inode);
637#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000638 err = -EIO;
639 } else {
640 struct fuse_inode *fi = get_fuse_inode(inode);
641 fuse_change_attributes(inode, &arg.attr);
642 fi->i_time = time_to_jiffies(arg.attr_valid,
643 arg.attr_valid_nsec);
644 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000645 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000646 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000647}
648
Miklos Szeredi61139db2005-04-29 07:38:25 +0000649/*
650 * Calling into a user-controlled filesystem gives the filesystem
651 * daemon ptrace-like capabilities over the requester process. This
652 * means, that the filesystem daemon is able to record the exact
653 * filesystem operations performed, and can also control the behavior
654 * of the requester process in otherwise impossible ways. For example
655 * it can delay the operation for arbitrary length of time allowing
656 * DoS against the requester.
657 *
658 * For this reason only those processes can call into the filesystem,
659 * for which the owner of the mount has ptrace privilege. This
660 * excludes processes started by other users, suid or sgid processes.
661 */
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000662static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
663{
664 if (fc->flags & FUSE_ALLOW_OTHER)
665 return 1;
666
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000667 if (task->euid == fc->user_id &&
668 task->suid == fc->user_id &&
669 task->uid == fc->user_id &&
670 task->egid == fc->group_id &&
671 task->sgid == fc->group_id &&
672 task->gid == fc->group_id)
673 return 1;
674
675 return 0;
676}
677
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000678/*
679 * Check whether the inode attributes are still valid
680 *
681 * If the attribute validity timeout has expired, then fetch the fresh
682 * attributes with a 'getattr' request
683 *
684 * I'm not sure why cached attributes are never returned for the root
685 * inode, this is probably being too cautious.
686 */
Miklos Szeredife25def2001-12-20 15:38:05 +0000687static int fuse_revalidate(struct dentry *entry)
688{
689 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000690 struct fuse_inode *fi = get_fuse_inode(inode);
691 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000692
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000693 if (!fuse_allow_task(fc, current))
694 return -EACCES;
695 if (get_node_id(inode) != FUSE_ROOT_ID &&
696 time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000697 return 0;
698
Miklos Szeredif85ab242004-01-07 12:16:45 +0000699 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000700}
701
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000702#ifdef KERNEL_2_6
703static int fuse_access(struct inode *inode, int mask)
704{
705 struct fuse_conn *fc = get_fuse_conn(inode);
706 struct fuse_req *req;
707 struct fuse_access_in inarg;
708 int err;
709
710 if (fc->no_access)
711 return 0;
712
713 req = fuse_get_request(fc);
714 if (!req)
715 return -EINTR;
716
717 memset(&inarg, 0, sizeof(inarg));
718 inarg.mask = mask;
719 req->in.h.opcode = FUSE_ACCESS;
720 req->in.h.nodeid = get_node_id(inode);
721 req->inode = inode;
722 req->in.numargs = 1;
723 req->in.args[0].size = sizeof(inarg);
724 req->in.args[0].value = &inarg;
725 request_send(fc, req);
726 err = req->out.h.error;
727 fuse_put_request(fc, req);
728 if (err == -ENOSYS) {
729 fc->no_access = 1;
730 err = 0;
731 }
732 return err;
733}
734#endif
735
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000736/*
737 * Check permission. The two basic access models of FUSE are:
738 *
739 * 1) Local access checking ('default_permissions' mount option) based
740 * on file mode. This is the plain old disk filesystem permission
741 * modell.
742 *
743 * 2) "Remote" access checking, where server is responsible for
744 * checking permission in each inode operation. An exception to this
745 * is if ->permission() was invoked from sys_access() in which case an
746 * access request is sent. Execute permission is still checked
747 * locally based on file mode.
748 */
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000749static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000750{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000751 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000752
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000753 if (!fuse_allow_task(fc, current))
Miklos Szeredife25def2001-12-20 15:38:05 +0000754 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000755 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000756#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000757 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000758#else
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000759 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000760#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000761
762 /* If permission is denied, try to refresh file
763 attributes. This is also needed, because the root
764 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000765 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000766 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000767 if (!err)
768#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000769 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000770#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000771 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000772#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000773 }
774
Miklos Szeredifb02fec2005-11-29 15:24:02 +0000775 /* Note: the opposite of the above test does not
776 exist. So if permissions are revoked this won't be
777 noticed immediately, only after the attribute
778 timeout has expired */
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000779
780 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000781 } else {
782 int mode = inode->i_mode;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000783#ifndef KERNEL_2_6_11_PLUS
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000784 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
785 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
786 return -EROFS;
Miklos Szeredi52cb09d2005-11-07 11:59:00 +0000787#endif
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000788 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
789 return -EACCES;
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000790
791#ifdef KERNEL_2_6
792 if (nd && (nd->flags & LOOKUP_ACCESS))
793 return fuse_access(inode, mask);
794#endif
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000795 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000796 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000797}
798
Miklos Szeredib483c932001-10-29 14:57:57 +0000799static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
800 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000801{
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000802 struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode);
803
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000804 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000805 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000806 size_t reclen = FUSE_DIRENT_SIZE(dirent);
807 int over;
Miklos Szeredi044da2e2005-12-06 17:59:55 +0000808 if (!dirent->namelen || dirent->namelen > fc->name_max)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000809 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000810 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000811 break;
812
813 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi18fce982005-04-01 21:07:35 +0000814 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000815 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000816 break;
817
Miklos Szeredib483c932001-10-29 14:57:57 +0000818 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000819 nbytes -= reclen;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000820 file->f_pos = dirent->off;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000821 }
822
Miklos Szeredib483c932001-10-29 14:57:57 +0000823 return 0;
824}
825
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000826static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
827 struct inode *inode, loff_t pos,
828 size_t count)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000829{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000830 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000831}
832
Miklos Szeredib483c932001-10-29 14:57:57 +0000833static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
834{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000835 int err;
836 size_t nbytes;
837 struct page *page;
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000838 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000839 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredic53cddd2005-12-07 12:57:59 +0000840 struct fuse_req *req;
841
842 if (is_bad_inode(inode))
843 return -EIO;
844
845 req = fuse_get_request(fc);
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000846 if (!req)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000847 return -EINTR;
Miklos Szeredie815c032004-01-19 18:20:49 +0000848
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000849 page = alloc_page(GFP_KERNEL);
850 if (!page) {
851 fuse_put_request(fc, req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000852 return -ENOMEM;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000853 }
854 req->num_pages = 1;
855 req->pages[0] = page;
856 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
857 err = req->out.h.error;
858 fuse_put_request(fc, req);
859 if (!err)
860 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
861 filldir);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000862
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000863 __free_page(page);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000864 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000865 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000866}
867
Miklos Szeredi05033042001-11-13 16:11:35 +0000868static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000869{
870 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000871 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000872 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000873 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000874
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000875 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000876 return ERR_PTR(-EINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000877
Miklos Szeredi05033042001-11-13 16:11:35 +0000878 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 if (!link) {
880 link = ERR_PTR(-ENOMEM);
881 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000882 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000883 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000884 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000885 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000886 req->out.argvar = 1;
887 req->out.numargs = 1;
888 req->out.args[0].size = PAGE_SIZE - 1;
889 req->out.args[0].value = link;
890 request_send(fc, req);
891 if (req->out.h.error) {
892 free_page((unsigned long) link);
893 link = ERR_PTR(req->out.h.error);
894 } else
895 link[req->out.args[0].size] = '\0';
896 out:
897 fuse_put_request(fc, req);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000898 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi05033042001-11-13 16:11:35 +0000899 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000900}
901
902static void free_link(char *link)
903{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000904 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000905 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000906}
907
Miklos Szeredi56487812005-09-02 13:05:06 +0000908#ifdef KERNEL_2_6_13_PLUS
909static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
910{
911 nd_set_link(nd, read_link(dentry));
912 return NULL;
913}
914
915static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
916{
917 free_link(nd_get_link(nd));
918}
919#elif defined(KERNEL_2_6_8_PLUS)
Miklos Szeredi81394522005-01-11 14:24:18 +0000920static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
921{
922 nd_set_link(nd, read_link(dentry));
923 return 0;
924}
925
926static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
927{
928 free_link(nd_get_link(nd));
929}
930#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000931static int fuse_readlink(struct dentry *dentry, char __user *buffer,
932 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000933{
934 int ret;
935 char *link;
936
Miklos Szeredi05033042001-11-13 16:11:35 +0000937 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000938 ret = vfs_readlink(dentry, buffer, buflen, link);
939 free_link(link);
940 return ret;
941}
942
943static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
944{
945 int ret;
946 char *link;
947
Miklos Szeredi05033042001-11-13 16:11:35 +0000948 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000949 ret = vfs_follow_link(nd, link);
950 free_link(link);
951 return ret;
952}
Miklos Szeredi81394522005-01-11 14:24:18 +0000953#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000954
955static int fuse_dir_open(struct inode *inode, struct file *file)
956{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000957 return fuse_open_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000958}
959
960static int fuse_dir_release(struct inode *inode, struct file *file)
961{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000962 return fuse_release_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000963}
964
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000965static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
966{
Miklos Szeredib7640d22005-04-08 15:15:28 +0000967 /* nfsd can call this with no file */
968 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000969}
970
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000971static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000972{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000973 unsigned ivalid = iattr->ia_valid;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000974
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000975 if (ivalid & ATTR_MODE)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000976 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000977 if (ivalid & ATTR_UID)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000978 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000979 if (ivalid & ATTR_GID)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000980 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000981 if (ivalid & ATTR_SIZE)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000982 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000983 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000984 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000985 arg->valid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000986#ifdef KERNEL_2_6
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000987 arg->atime = iattr->ia_atime.tv_sec;
988 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000989#else
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000990 arg->atime = iattr->ia_atime;
991 arg->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000992#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000993 }
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000994#ifdef ATTR_FILE
995 if (ivalid & ATTR_FILE) {
996 struct fuse_file *ff = iattr->ia_file->private_data;
997 arg->valid |= FATTR_FH;
998 arg->fh = ff->fh;
999 }
1000#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +00001001}
1002
Miklos Szeredifb02fec2005-11-29 15:24:02 +00001003/*
1004 * Set attributes, and at the same time refresh them.
1005 *
1006 * Truncation is slightly complicated, because the 'truncate' request
1007 * may fail, in which case we don't want to touch the mapping.
1008 * vmtruncate() doesn't allow for this case. So do the rlimit
1009 * checking by hand and call vmtruncate() only after the file has
1010 * actually been truncated.
1011 */
Miklos Szeredi5e183482001-10-31 14:52:35 +00001012static int fuse_setattr(struct dentry *entry, struct iattr *attr)
1013{
1014 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001015 struct fuse_conn *fc = get_fuse_conn(inode);
1016 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +00001017 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +00001018 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +00001019 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001020 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +00001021 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001022
Miklos Szeredi94ed76a2004-07-26 19:38:45 +00001023 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
1024 err = inode_change_ok(inode, attr);
1025 if (err)
1026 return err;
1027 }
Miklos Szeredi58615e02004-07-04 21:21:08 +00001028
Miklos Szeredi069c9502004-07-16 16:17:02 +00001029 if (attr->ia_valid & ATTR_SIZE) {
1030 unsigned long limit;
1031 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001032#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +00001033 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001034#else
1035 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +00001036#endif
1037 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +00001038 send_sig(SIGXFSZ, current, 0);
1039 return -EFBIG;
1040 }
Miklos Szeredi069c9502004-07-16 16:17:02 +00001041 }
Miklos Szeredi58615e02004-07-04 21:21:08 +00001042
1043 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001044 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001045 return -EINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +00001046
Miklos Szeredi43696432001-11-18 19:15:05 +00001047 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi11509ce2005-10-26 16:04:04 +00001048 iattr_to_fattr(attr, &inarg);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001049 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001050 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001051 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001052 req->in.numargs = 1;
1053 req->in.args[0].size = sizeof(inarg);
1054 req->in.args[0].value = &inarg;
1055 req->out.numargs = 1;
1056 req->out.args[0].size = sizeof(outarg);
1057 req->out.args[0].value = &outarg;
1058 request_send(fc, req);
1059 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +00001061 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001062 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +00001063#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +00001064 if (get_node_id(inode) != FUSE_ROOT_ID)
1065 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +00001066#else
1067 make_bad_inode(inode);
1068#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001069 err = -EIO;
1070 } else {
1071 if (is_truncate) {
1072 loff_t origsize = i_size_read(inode);
1073 i_size_write(inode, outarg.attr.size);
1074 if (origsize > outarg.attr.size)
1075 vmtruncate(inode, outarg.attr.size);
1076 }
1077 fuse_change_attributes(inode, &outarg.attr);
1078 fi->i_time = time_to_jiffies(outarg.attr_valid,
1079 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +00001080 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001081 } else if (err == -EINTR)
1082 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001083
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001084 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +00001085}
1086
Miklos Szeredif85ab242004-01-07 12:16:45 +00001087#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +00001088static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
1089 struct kstat *stat)
1090{
1091 struct inode *inode = entry->d_inode;
1092 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001093 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +00001094 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001095
Miklos Szeredif85ab242004-01-07 12:16:45 +00001096 return err;
1097}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001098#else /* KERNEL_2_6 */
Miklos Szeredi2b478112005-11-28 13:27:10 +00001099static struct dentry *fuse_lookup_2_4(struct inode *dir, struct dentry *entry)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001100{
Miklos Szeredi2b478112005-11-28 13:27:10 +00001101 return fuse_lookup(dir, entry, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001102}
1103
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001104static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +00001105 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001106{
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001107 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001108}
1109
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001110static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
1111{
1112 return fuse_create(dir, entry, mode, NULL);
1113}
1114
1115static int fuse_permission_2_4(struct inode *inode, int mask)
1116{
1117 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001118}
1119#endif /* KERNEL_2_6 */
1120
1121#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +00001122#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001123static int fuse_setxattr(struct dentry *entry, const char *name,
1124 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001125#else
1126static int fuse_setxattr(struct dentry *entry, const char *name,
1127 void *value, size_t size, int flags)
1128#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001129{
1130 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001131 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001132 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001133 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001134 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001135
Miklos Szeredi044da2e2005-12-06 17:59:55 +00001136 if (size > fc->xattr_size_max)
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001137 return -E2BIG;
1138
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001139 if (fc->no_setxattr)
1140 return -EOPNOTSUPP;
1141
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001142 req = fuse_get_request(fc);
1143 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001144 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001145
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001146 memset(&inarg, 0, sizeof(inarg));
1147 inarg.size = size;
1148 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001149 req->in.h.opcode = FUSE_SETXATTR;
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 = 3;
1153 req->in.args[0].size = sizeof(inarg);
1154 req->in.args[0].value = &inarg;
1155 req->in.args[1].size = strlen(name) + 1;
1156 req->in.args[1].value = name;
1157 req->in.args[2].size = size;
1158 req->in.args[2].value = value;
1159 request_send(fc, req);
1160 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001161 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001162 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001163 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001164 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001165 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001166 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001167}
1168
1169static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1170 void *value, size_t size)
1171{
1172 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001173 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001174 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001175 struct fuse_getxattr_in inarg;
1176 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001177 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001178
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001179 if (fc->no_getxattr)
1180 return -EOPNOTSUPP;
1181
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001182 req = fuse_get_request(fc);
1183 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001184 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001185
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001186 memset(&inarg, 0, sizeof(inarg));
1187 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001188 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001189 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001190 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001191 req->in.numargs = 2;
1192 req->in.args[0].size = sizeof(inarg);
1193 req->in.args[0].value = &inarg;
1194 req->in.args[1].size = strlen(name) + 1;
1195 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001196 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001197 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001198 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001199 req->out.argvar = 1;
1200 req->out.args[0].size = size;
1201 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001202 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001203 req->out.args[0].size = sizeof(outarg);
1204 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001205 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001206 request_send(fc, req);
1207 ret = req->out.h.error;
1208 if (!ret)
1209 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001210 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001211 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001212 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001213 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001214 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001215 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001216 fuse_put_request(fc, req);
1217 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001218}
1219
1220static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1221{
1222 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001223 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001224 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001225 struct fuse_getxattr_in inarg;
1226 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001227 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001228
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001229 if (fc->no_listxattr)
1230 return -EOPNOTSUPP;
1231
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001232 req = fuse_get_request(fc);
1233 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001234 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001235
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001236 memset(&inarg, 0, sizeof(inarg));
1237 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001238 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001239 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001240 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001241 req->in.numargs = 1;
1242 req->in.args[0].size = sizeof(inarg);
1243 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001244 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001245 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001246 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001247 req->out.argvar = 1;
1248 req->out.args[0].size = size;
1249 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001250 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001251 req->out.args[0].size = sizeof(outarg);
1252 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001253 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001254 request_send(fc, req);
1255 ret = req->out.h.error;
1256 if (!ret)
1257 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001258 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001259 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001260 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001261 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001262 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001263 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001264 fuse_put_request(fc, req);
1265 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001266}
1267
1268static int fuse_removexattr(struct dentry *entry, const char *name)
1269{
1270 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001271 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001272 struct fuse_req *req;
1273 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001274
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001275 if (fc->no_removexattr)
1276 return -EOPNOTSUPP;
1277
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001278 req = fuse_get_request(fc);
1279 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001280 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001281
1282 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001283 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001284 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001285 req->in.numargs = 1;
1286 req->in.args[0].size = strlen(name) + 1;
1287 req->in.args[0].value = name;
1288 request_send(fc, req);
1289 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001290 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001291 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001292 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001293 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001294 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001295 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001296}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001297#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001298
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001299static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredibb4b9742005-11-29 11:29:44 +00001300#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001301 .lookup = fuse_lookup,
Miklos Szeredibb4b9742005-11-29 11:29:44 +00001302#else
1303 .lookup = fuse_lookup_2_4,
1304#endif
Miklos Szeredie8663f32004-01-13 15:33:12 +00001305 .mkdir = fuse_mkdir,
1306 .symlink = fuse_symlink,
1307 .unlink = fuse_unlink,
1308 .rmdir = fuse_rmdir,
1309 .rename = fuse_rename,
1310 .link = fuse_link,
1311 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001312#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001313 .create = fuse_create,
1314 .mknod = fuse_mknod,
1315 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001316 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001317#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001318 .create = fuse_create_2_4,
1319 .mknod = fuse_mknod_2_4,
1320 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001321 .revalidate = fuse_revalidate,
1322#endif
1323#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001324 .setxattr = fuse_setxattr,
1325 .getxattr = fuse_getxattr,
1326 .listxattr = fuse_listxattr,
1327 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001328#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001329};
1330
1331static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001332 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001333 .read = generic_read_dir,
1334 .readdir = fuse_readdir,
1335 .open = fuse_dir_open,
1336 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001337 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001338};
1339
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001340static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001341 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001342#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001343 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001344 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001345#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001346 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001347 .revalidate = fuse_revalidate,
1348#endif
1349#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001350 .setxattr = fuse_setxattr,
1351 .getxattr = fuse_getxattr,
1352 .listxattr = fuse_listxattr,
1353 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001354#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001355};
1356
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001357static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001358 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001359 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001360#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001361 .put_link = fuse_put_link,
1362 .readlink = generic_readlink,
1363#else
1364 .readlink = fuse_readlink,
1365#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001366#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001367 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001368#else
1369 .revalidate = fuse_revalidate,
1370#endif
1371#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001372 .setxattr = fuse_setxattr,
1373 .getxattr = fuse_getxattr,
1374 .listxattr = fuse_listxattr,
1375 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001376#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001377};
1378
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001379void fuse_init_common(struct inode *inode)
1380{
1381 inode->i_op = &fuse_common_inode_operations;
1382}
1383
1384void fuse_init_dir(struct inode *inode)
1385{
1386 inode->i_op = &fuse_dir_inode_operations;
1387 inode->i_fop = &fuse_dir_operations;
1388}
1389
1390void fuse_init_symlink(struct inode *inode)
1391{
1392 inode->i_op = &fuse_symlink_inode_operations;
1393}