blob: bc792cbc0e669a4f9c57aeea28be7c09c0d09ae9 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
Miklos Szeredi149f6072005-01-10 12:29:28 +00003 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredie56818b2004-12-12 11:45:24 +00005 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
9#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000012#include <linux/file.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000013#ifdef KERNEL_2_6
14#include <linux/gfp.h>
15#else
16#include <linux/mm.h>
17#endif
18#include <linux/sched.h>
Miklos Szeredi3b9e53f2005-09-02 16:04:48 +000019#ifdef KERNEL_2_6
Miklos Szeredi81394522005-01-11 14:24:18 +000020#include <linux/namei.h>
21#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000023static inline unsigned long time_to_jiffies(unsigned long sec,
24 unsigned long nsec)
25{
Miklos Szeredi81394522005-01-11 14:24:18 +000026 struct timespec ts = {sec, nsec};
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +000027 return jiffies + timespec_to_jiffies(&ts);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000028}
29
Miklos Szeredi0f62d722005-01-04 12:45:54 +000030static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
31 struct dentry *entry,
32 struct fuse_entry_out *outarg)
33{
34 req->in.h.opcode = FUSE_LOOKUP;
35 req->in.h.nodeid = get_node_id(dir);
36 req->inode = dir;
37 req->in.numargs = 1;
38 req->in.args[0].size = entry->d_name.len + 1;
39 req->in.args[0].value = entry->d_name.name;
40 req->out.numargs = 1;
41 req->out.args[0].size = sizeof(struct fuse_entry_out);
42 req->out.args[0].value = outarg;
43}
44
45static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
46{
47 if (!entry->d_inode || is_bad_inode(entry->d_inode))
48 return 0;
Miklos Szeredi81394522005-01-11 14:24:18 +000049 else if (time_after(jiffies, entry->d_time)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +000050 int err;
Miklos Szeredi0f62d722005-01-04 12:45:54 +000051 struct fuse_entry_out outarg;
52 struct inode *inode = entry->d_inode;
53 struct fuse_inode *fi = get_fuse_inode(inode);
54 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredif94e0102005-05-12 14:56:34 +000055 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi0f62d722005-01-04 12:45:54 +000056 if (!req)
57 return 0;
58
59 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
Miklos Szeredif94e0102005-05-12 14:56:34 +000060 request_send(fc, req);
Miklos Szeredi0f62d722005-01-04 12:45:54 +000061 err = req->out.h.error;
Miklos Szeredi38009022005-05-08 19:47:22 +000062 if (!err) {
63 if (outarg.nodeid != get_node_id(inode)) {
64 fuse_send_forget(fc, req, outarg.nodeid, 1);
65 return 0;
66 }
67 fi->nlookup ++;
68 }
Miklos Szeredi0f62d722005-01-04 12:45:54 +000069 fuse_put_request(fc, req);
Miklos Szeredi38009022005-05-08 19:47:22 +000070 if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
Miklos Szeredi0f62d722005-01-04 12:45:54 +000071 return 0;
72
73 fuse_change_attributes(inode, &outarg.attr);
Miklos Szeredi0f62d722005-01-04 12:45:54 +000074 entry->d_time = time_to_jiffies(outarg.entry_valid,
75 outarg.entry_valid_nsec);
76 fi->i_time = time_to_jiffies(outarg.attr_valid,
77 outarg.attr_valid_nsec);
78 }
79 return 1;
80}
81#ifndef KERNEL_2_6
82static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
83{
84 return fuse_dentry_revalidate(entry, NULL);
85}
86#endif
87
88static struct dentry_operations fuse_dentry_operations = {
89#ifdef KERNEL_2_6
90 .d_revalidate = fuse_dentry_revalidate,
91#else
92 .d_revalidate = fuse_dentry_revalidate_2_4,
93#endif
94};
95
Miklos Szeredie815c032004-01-19 18:20:49 +000096static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
97 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +000098{
Miklos Szeredie815c032004-01-19 18:20:49 +000099 int err;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000100 struct fuse_entry_out outarg;
Miklos Szeredie815c032004-01-19 18:20:49 +0000101 struct inode *inode = NULL;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000102 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000103 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000104
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000105 if (entry->d_name.len > FUSE_NAME_MAX)
106 return -ENAMETOOLONG;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000107
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000108 req = fuse_get_request(fc);
109 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000110 return -EINTR;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000111
Miklos Szeredie56818b2004-12-12 11:45:24 +0000112 fuse_lookup_init(req, dir, entry, &outarg);
113 request_send(fc, req);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000114 err = req->out.h.error;
Miklos Szeredi8722dd22005-09-23 13:34:44 +0000115 if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID))
Miklos Szeredi6becf0b2005-09-23 11:25:28 +0000116 err = -EIO;
Miklos Szeredi8722dd22005-09-23 13:34:44 +0000117 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000118 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000119 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000120 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000121 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredie815c032004-01-19 18:20:49 +0000122 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000123 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000124 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000125 fuse_put_request(fc, req);
126 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000127 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000128
Miklos Szeredi069c9502004-07-16 16:17:02 +0000129 if (inode) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000130 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000131 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000132 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000133 fi->i_time = time_to_jiffies(outarg.attr_valid,
134 outarg.attr_valid_nsec);
135 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000136
Miklos Szeredi307242f2004-01-26 11:28:44 +0000137 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000138 *inodep = inode;
139 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000140}
141
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000142void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000143{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000144 get_fuse_inode(inode)->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000145}
146
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000147static void fuse_invalidate_entry(struct dentry *entry)
148{
149 d_invalidate(entry);
150 entry->d_time = jiffies - 1;
151}
152
Miklos Szeredid9079a72005-10-26 15:29:06 +0000153#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
154static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
155 struct nameidata *nd)
156{
157 int err;
158 struct inode *inode;
159 struct fuse_conn *fc = get_fuse_conn(dir);
160 struct fuse_req *req;
161 struct fuse_open_in inarg;
162 struct fuse_open_out outopen;
163 struct fuse_entry_out outentry;
164 struct fuse_inode *fi;
165 struct fuse_file *ff;
166 struct file *file;
167 int flags = nd->intent.open.flags - 1;
168
169 err = -ENOSYS;
170 if (fc->no_create)
171 goto out;
172
173 err = -ENAMETOOLONG;
174 if (entry->d_name.len > FUSE_NAME_MAX)
175 goto out;
176
177 err = -EINTR;
178 req = fuse_get_request(fc);
179 if (!req)
180 goto out;
181
182 ff = fuse_file_alloc();
183 if (!ff)
184 goto out_put_request;
185
186 flags &= ~O_NOCTTY;
187 memset(&inarg, 0, sizeof(inarg));
188 inarg.flags = flags;
189 inarg.mode = mode;
190 req->in.h.opcode = FUSE_CREATE;
191 req->in.h.nodeid = get_node_id(dir);
192 req->inode = dir;
193 req->in.numargs = 2;
194 req->in.args[0].size = sizeof(inarg);
195 req->in.args[0].value = &inarg;
196 req->in.args[1].size = entry->d_name.len + 1;
197 req->in.args[1].value = entry->d_name.name;
198 req->out.numargs = 2;
199 req->out.args[0].size = sizeof(outentry);
200 req->out.args[0].value = &outentry;
201 req->out.args[1].size = sizeof(outopen);
202 req->out.args[1].value = &outopen;
203 request_send(fc, req);
204 err = req->out.h.error;
205 if (err) {
206 if (err == -ENOSYS)
207 fc->no_create = 1;
208 goto out_free_ff;
209 }
210
211 err = -EIO;
212 if (!S_ISREG(outentry.attr.mode))
213 goto out_free_ff;
214
215 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
216 &outentry.attr);
217 err = -ENOMEM;
218 if (!inode) {
219 flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
220 ff->fh = outopen.fh;
221 fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
222 goto out_put_request;
223 }
224 fuse_put_request(fc, req);
225 entry->d_time = time_to_jiffies(outentry.entry_valid,
226 outentry.entry_valid_nsec);
227 fi = get_fuse_inode(inode);
228 fi->i_time = time_to_jiffies(outentry.attr_valid,
229 outentry.attr_valid_nsec);
230
231 d_instantiate(entry, inode);
232 file = lookup_instantiate_filp(nd, entry, generic_file_open);
233 if (IS_ERR(file)) {
234 ff->fh = outopen.fh;
235 fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
236 return PTR_ERR(file);
237 }
238 fuse_finish_open(inode, file, ff, &outopen);
239 return 0;
240
241 out_free_ff:
242 fuse_file_free(ff);
243 out_put_request:
244 fuse_put_request(fc, req);
245 out:
246 return err;
247}
248#endif
249
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000250static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000251 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000252 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000253{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000254 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000255 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000256 struct fuse_inode *fi;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000257 int err;
258
259 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000260 req->inode = dir;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000261 req->out.numargs = 1;
262 req->out.args[0].size = sizeof(outarg);
263 req->out.args[0].value = &outarg;
264 request_send(fc, req);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000265 err = req->out.h.error;
266 if (err) {
267 fuse_put_request(fc, req);
268 return err;
269 }
Miklos Szeredi6becf0b2005-09-23 11:25:28 +0000270 if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
271 fuse_put_request(fc, req);
272 return -EIO;
273 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000274 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000275 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000276 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000277 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000278 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000279 }
280 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000281
282 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000283 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000284 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000285 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000286 }
287
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000288 entry->d_time = time_to_jiffies(outarg.entry_valid,
289 outarg.entry_valid_nsec);
Miklos Szerediad051c32004-07-02 09:22:50 +0000290
Miklos Szeredi039322d2004-12-01 18:39:12 +0000291 fi = get_fuse_inode(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000292 fi->i_time = time_to_jiffies(outarg.attr_valid,
293 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000294
Miklos Szeredi76f65782004-02-19 16:55:40 +0000295 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000296 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000297 return 0;
298}
299
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000300static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000301 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000302{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000303 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000304 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000305 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000307 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000308
309 memset(&inarg, 0, sizeof(inarg));
310 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000311 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000312 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 req->in.numargs = 2;
314 req->in.args[0].size = sizeof(inarg);
315 req->in.args[0].value = &inarg;
316 req->in.args[1].size = entry->d_name.len + 1;
317 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000318 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000319}
320
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000321static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
322 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000323{
Miklos Szeredid9079a72005-10-26 15:29:06 +0000324#ifdef HAVE_LOOKUP_INSTANTIATE_FILP
325 if (nd && (nd->flags & LOOKUP_CREATE)) {
326 int err = fuse_create_open(dir, entry, mode, nd);
327 if (err != -ENOSYS)
328 return err;
329 /* Fall back on mknod */
330 }
331#endif
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000332 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000333}
334
Miklos Szeredib483c932001-10-29 14:57:57 +0000335static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
336{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000337 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000338 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000339 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000340 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000341 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000342
343 memset(&inarg, 0, sizeof(inarg));
344 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000345 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000346 req->in.numargs = 2;
347 req->in.args[0].size = sizeof(inarg);
348 req->in.args[0].value = &inarg;
349 req->in.args[1].size = entry->d_name.len + 1;
350 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000351 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000352}
353
354static int fuse_symlink(struct inode *dir, struct dentry *entry,
355 const char *link)
356{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000357 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000358 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000359 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000360
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000361 if (len > FUSE_SYMLINK_MAX)
362 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000364 req = fuse_get_request(fc);
365 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000366 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000367
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000368 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000369 req->in.numargs = 2;
370 req->in.args[0].size = entry->d_name.len + 1;
371 req->in.args[0].value = entry->d_name.name;
372 req->in.args[1].size = len;
373 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000374 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000375}
376
Miklos Szeredib5958612004-02-20 14:10:49 +0000377static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000378{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000379 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000380 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000381 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000382 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000383 return -EINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000384
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000385 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000386 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000387 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000388 req->in.numargs = 1;
389 req->in.args[0].size = entry->d_name.len + 1;
390 req->in.args[0].value = entry->d_name.name;
391 request_send(fc, req);
392 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000393 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000394 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000395 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000396
Miklos Szeredib5958612004-02-20 14:10:49 +0000397 /* Set nlink to zero so the inode can be cleared, if
398 the inode does have more links this will be
399 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000400 inode->i_nlink = 0;
401 fuse_invalidate_attr(inode);
402 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000403 } else if (err == -EINTR)
404 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000405 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000406}
407
408static int fuse_rmdir(struct inode *dir, struct dentry *entry)
409{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000410 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000411 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000412 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000413 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000414 return -EINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000415
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000416 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000417 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000418 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000419 req->in.numargs = 1;
420 req->in.args[0].size = entry->d_name.len + 1;
421 req->in.args[0].value = entry->d_name.name;
422 request_send(fc, req);
423 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000424 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000425 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000426 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000427 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000428 } else if (err == -EINTR)
429 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000430 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000431}
432
433static int fuse_rename(struct inode *olddir, struct dentry *oldent,
434 struct inode *newdir, struct dentry *newent)
435{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000436 int err;
437 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000438 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000439 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000440 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000441 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000442
Miklos Szeredi43696432001-11-18 19:15:05 +0000443 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000444 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000445 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000446 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000447 req->inode = olddir;
448 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000449 req->in.numargs = 3;
450 req->in.args[0].size = sizeof(inarg);
451 req->in.args[0].value = &inarg;
452 req->in.args[1].size = oldent->d_name.len + 1;
453 req->in.args[1].value = oldent->d_name.name;
454 req->in.args[2].size = newent->d_name.len + 1;
455 req->in.args[2].value = newent->d_name.name;
456 request_send(fc, req);
457 err = req->out.h.error;
458 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000459 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000460 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000461 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000462 fuse_invalidate_attr(newdir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000463 } else if (err == -EINTR) {
464 /* If request was interrupted, DEITY only knows if the
465 rename actually took place. If the invalidation
466 fails (e.g. some process has CWD under the renamed
467 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000468 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000469 fuse_invalidate_entry(oldent);
470 if (newent->d_inode)
471 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000472 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000473
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000474 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000475}
476
477static int fuse_link(struct dentry *entry, struct inode *newdir,
478 struct dentry *newent)
479{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000480 int err;
481 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000482 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000483 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000484 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000485 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000486 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000487
Miklos Szeredi43696432001-11-18 19:15:05 +0000488 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000489 inarg.oldnodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000490 req->in.h.opcode = FUSE_LINK;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000491 req->inode2 = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000492 req->in.numargs = 2;
493 req->in.args[0].size = sizeof(inarg);
494 req->in.args[0].value = &inarg;
495 req->in.args[1].size = newent->d_name.len + 1;
496 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000497 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
498 /* Contrary to "normal" filesystems it can happen that link
499 makes two "logical" inodes point to the same "physical"
500 inode. We invalidate the attributes of the old one, so it
501 will reflect changes in the backing inode (link count,
502 etc.)
503 */
504 if (!err || err == -EINTR)
505 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000506 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000507}
508
Miklos Szeredif85ab242004-01-07 12:16:45 +0000509int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000510{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000511 int err;
512 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000513 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000514 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000515 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000516 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000517
518 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000519 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000520 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000521 req->out.numargs = 1;
522 req->out.args[0].size = sizeof(arg);
523 req->out.args[0].value = &arg;
524 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000525 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000526 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000527 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000528 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000529#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000530 if (get_node_id(inode) != FUSE_ROOT_ID)
531 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000532#else
533 make_bad_inode(inode);
534#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000535 err = -EIO;
536 } else {
537 struct fuse_inode *fi = get_fuse_inode(inode);
538 fuse_change_attributes(inode, &arg.attr);
539 fi->i_time = time_to_jiffies(arg.attr_valid,
540 arg.attr_valid_nsec);
541 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000542 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000543 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000544}
545
Miklos Szeredi61139db2005-04-29 07:38:25 +0000546/*
547 * Calling into a user-controlled filesystem gives the filesystem
548 * daemon ptrace-like capabilities over the requester process. This
549 * means, that the filesystem daemon is able to record the exact
550 * filesystem operations performed, and can also control the behavior
551 * of the requester process in otherwise impossible ways. For example
552 * it can delay the operation for arbitrary length of time allowing
553 * DoS against the requester.
554 *
555 * For this reason only those processes can call into the filesystem,
556 * for which the owner of the mount has ptrace privilege. This
557 * excludes processes started by other users, suid or sgid processes.
558 */
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000559static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
560{
561 if (fc->flags & FUSE_ALLOW_OTHER)
562 return 1;
563
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000564 if (task->euid == fc->user_id &&
565 task->suid == fc->user_id &&
566 task->uid == fc->user_id &&
567 task->egid == fc->group_id &&
568 task->sgid == fc->group_id &&
569 task->gid == fc->group_id)
570 return 1;
571
572 return 0;
573}
574
Miklos Szeredife25def2001-12-20 15:38:05 +0000575static int fuse_revalidate(struct dentry *entry)
576{
577 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000578 struct fuse_inode *fi = get_fuse_inode(inode);
579 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000580
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000581 if (!fuse_allow_task(fc, current))
582 return -EACCES;
583 if (get_node_id(inode) != FUSE_ROOT_ID &&
584 time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000585 return 0;
586
Miklos Szeredif85ab242004-01-07 12:16:45 +0000587 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000588}
589
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000590#ifdef KERNEL_2_6
591static int fuse_access(struct inode *inode, int mask)
592{
593 struct fuse_conn *fc = get_fuse_conn(inode);
594 struct fuse_req *req;
595 struct fuse_access_in inarg;
596 int err;
597
598 if (fc->no_access)
599 return 0;
600
601 req = fuse_get_request(fc);
602 if (!req)
603 return -EINTR;
604
605 memset(&inarg, 0, sizeof(inarg));
606 inarg.mask = mask;
607 req->in.h.opcode = FUSE_ACCESS;
608 req->in.h.nodeid = get_node_id(inode);
609 req->inode = inode;
610 req->in.numargs = 1;
611 req->in.args[0].size = sizeof(inarg);
612 req->in.args[0].value = &inarg;
613 request_send(fc, req);
614 err = req->out.h.error;
615 fuse_put_request(fc, req);
616 if (err == -ENOSYS) {
617 fc->no_access = 1;
618 err = 0;
619 }
620 return err;
621}
622#endif
623
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000624static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000625{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000626 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000627
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000628 if (!fuse_allow_task(fc, current))
Miklos Szeredife25def2001-12-20 15:38:05 +0000629 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000630 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000631#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000632 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000633#else
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000634 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000635#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000636
637 /* If permission is denied, try to refresh file
638 attributes. This is also needed, because the root
639 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000640 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000641 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000642 if (!err)
643#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000644 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000645#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000646 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000647#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000648 }
649
650 /* FIXME: Need some mechanism to revoke permissions:
651 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000652 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000653 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000654
Miklos Szeredife25def2001-12-20 15:38:05 +0000655 This is actually not so grave, since the user can
656 simply keep access to the file/directory anyway by
657 keeping it open... */
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000658
659 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000660 } else {
661 int mode = inode->i_mode;
662 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
663 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
664 return -EROFS;
665 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
666 return -EACCES;
Miklos Szeredib0b13d12005-10-26 12:53:25 +0000667
668#ifdef KERNEL_2_6
669 if (nd && (nd->flags & LOOKUP_ACCESS))
670 return fuse_access(inode, mask);
671#endif
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000672 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000673 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000674}
675
Miklos Szeredib483c932001-10-29 14:57:57 +0000676static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
677 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000678{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000679 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000680 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000681 size_t reclen = FUSE_DIRENT_SIZE(dirent);
682 int over;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000683 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000684 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000685 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000686 break;
687
688 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi18fce982005-04-01 21:07:35 +0000689 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000690 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000691 break;
692
Miklos Szeredib483c932001-10-29 14:57:57 +0000693 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000694 nbytes -= reclen;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000695 file->f_pos = dirent->off;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000696 }
697
Miklos Szeredib483c932001-10-29 14:57:57 +0000698 return 0;
699}
700
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000701static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
702 struct inode *inode, loff_t pos,
703 size_t count)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000704{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000705 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000706}
707
Miklos Szeredib483c932001-10-29 14:57:57 +0000708static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
709{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000710 int err;
711 size_t nbytes;
712 struct page *page;
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000713 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000714 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredif94e0102005-05-12 14:56:34 +0000715 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000716 if (!req)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000717 return -EINTR;
Miklos Szeredie815c032004-01-19 18:20:49 +0000718
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000719 page = alloc_page(GFP_KERNEL);
720 if (!page) {
721 fuse_put_request(fc, req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000722 return -ENOMEM;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000723 }
724 req->num_pages = 1;
725 req->pages[0] = page;
726 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
727 err = req->out.h.error;
728 fuse_put_request(fc, req);
729 if (!err)
730 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
731 filldir);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000732
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000733 __free_page(page);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000734 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000735 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000736}
737
Miklos Szeredi05033042001-11-13 16:11:35 +0000738static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000739{
740 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000741 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000742 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000743 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000744
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000745 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000746 return ERR_PTR(-EINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000747
Miklos Szeredi05033042001-11-13 16:11:35 +0000748 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000749 if (!link) {
750 link = ERR_PTR(-ENOMEM);
751 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000752 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000753 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000754 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000755 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000756 req->out.argvar = 1;
757 req->out.numargs = 1;
758 req->out.args[0].size = PAGE_SIZE - 1;
759 req->out.args[0].value = link;
760 request_send(fc, req);
761 if (req->out.h.error) {
762 free_page((unsigned long) link);
763 link = ERR_PTR(req->out.h.error);
764 } else
765 link[req->out.args[0].size] = '\0';
766 out:
767 fuse_put_request(fc, req);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000768 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi05033042001-11-13 16:11:35 +0000769 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000770}
771
772static void free_link(char *link)
773{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000774 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000775 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000776}
777
Miklos Szeredi56487812005-09-02 13:05:06 +0000778#ifdef KERNEL_2_6_13_PLUS
779static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
780{
781 nd_set_link(nd, read_link(dentry));
782 return NULL;
783}
784
785static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
786{
787 free_link(nd_get_link(nd));
788}
789#elif defined(KERNEL_2_6_8_PLUS)
Miklos Szeredi81394522005-01-11 14:24:18 +0000790static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
791{
792 nd_set_link(nd, read_link(dentry));
793 return 0;
794}
795
796static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
797{
798 free_link(nd_get_link(nd));
799}
800#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000801static int fuse_readlink(struct dentry *dentry, char __user *buffer,
802 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000803{
804 int ret;
805 char *link;
806
Miklos Szeredi05033042001-11-13 16:11:35 +0000807 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000808 ret = vfs_readlink(dentry, buffer, buflen, link);
809 free_link(link);
810 return ret;
811}
812
813static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
814{
815 int ret;
816 char *link;
817
Miklos Szeredi05033042001-11-13 16:11:35 +0000818 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000819 ret = vfs_follow_link(nd, link);
820 free_link(link);
821 return ret;
822}
Miklos Szeredi81394522005-01-11 14:24:18 +0000823#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000824
825static int fuse_dir_open(struct inode *inode, struct file *file)
826{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000827 return fuse_open_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000828}
829
830static int fuse_dir_release(struct inode *inode, struct file *file)
831{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000832 return fuse_release_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000833}
834
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000835static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
836{
Miklos Szeredib7640d22005-04-08 15:15:28 +0000837 /* nfsd can call this with no file */
838 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000839}
840
Miklos Szeredi83a07442004-11-30 18:25:20 +0000841static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000842{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000843 unsigned ivalid = iattr->ia_valid;
844 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000845
Miklos Szeredi5e183482001-10-31 14:52:35 +0000846 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000847
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000848 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000849 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000850 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000851 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000852 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000854 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000855 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
856 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000857 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000858 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000859#ifdef KERNEL_2_6
860 fattr->atime = iattr->ia_atime.tv_sec;
861 fattr->mtime = iattr->ia_mtime.tv_sec;
862#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000863 fattr->atime = iattr->ia_atime;
864 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000865#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000866 }
867
868 return fvalid;
869}
870
871static int fuse_setattr(struct dentry *entry, struct iattr *attr)
872{
873 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000874 struct fuse_conn *fc = get_fuse_conn(inode);
875 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000876 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000877 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000878 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000880 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000881
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000882 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
883 err = inode_change_ok(inode, attr);
884 if (err)
885 return err;
886 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000887
Miklos Szeredi069c9502004-07-16 16:17:02 +0000888 if (attr->ia_valid & ATTR_SIZE) {
889 unsigned long limit;
890 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000891#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000892 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000893#else
894 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000895#endif
896 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000897 send_sig(SIGXFSZ, current, 0);
898 return -EFBIG;
899 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000900 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000901
902 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000903 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000904 return -EINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000905
Miklos Szeredi43696432001-11-18 19:15:05 +0000906 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000907 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000909 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000910 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000911 req->in.numargs = 1;
912 req->in.args[0].size = sizeof(inarg);
913 req->in.args[0].value = &inarg;
914 req->out.numargs = 1;
915 req->out.args[0].size = sizeof(outarg);
916 req->out.args[0].value = &outarg;
917 request_send(fc, req);
918 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000919 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000920 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000921 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000922#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000923 if (get_node_id(inode) != FUSE_ROOT_ID)
924 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000925#else
926 make_bad_inode(inode);
927#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000928 err = -EIO;
929 } else {
930 if (is_truncate) {
931 loff_t origsize = i_size_read(inode);
932 i_size_write(inode, outarg.attr.size);
933 if (origsize > outarg.attr.size)
934 vmtruncate(inode, outarg.attr.size);
935 }
936 fuse_change_attributes(inode, &outarg.attr);
937 fi->i_time = time_to_jiffies(outarg.attr_valid,
938 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000939 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000940 } else if (err == -EINTR)
941 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000942
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000943 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000944}
945
Miklos Szeredif85ab242004-01-07 12:16:45 +0000946#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000947static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
948 struct kstat *stat)
949{
950 struct inode *inode = entry->d_inode;
951 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000952 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000953 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000954
Miklos Szeredif85ab242004-01-07 12:16:45 +0000955 return err;
956}
957
958static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000959 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000960{
Miklos Szeredie815c032004-01-19 18:20:49 +0000961 struct inode *inode;
962 int err = fuse_lookup_iget(dir, entry, &inode);
963 if (err)
964 return ERR_PTR(err);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000965 if (inode && S_ISDIR(inode->i_mode)) {
966 /* Don't allow creating an alias to a directory */
967 struct dentry *alias = d_find_alias(inode);
968 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
969 dput(alias);
970 iput(inode);
971 return ERR_PTR(-EIO);
972 }
Miklos Szeredi42b78252005-09-30 08:47:09 +0000973 dput(alias);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000974 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000975 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000976}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000977#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000978static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
979{
980 struct inode *inode;
981 struct dentry *alias;
982
983 int err = fuse_lookup_iget(dir, entry, &inode);
984 if (err)
985 return ERR_PTR(err);
986
987 if (inode && S_ISDIR(inode->i_mode) &&
988 (alias = d_find_alias(inode)) != NULL) {
989 dput(alias);
990 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000991 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000992 }
993
994 d_add(entry, inode);
995 return NULL;
996}
997
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000998static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000999 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001000{
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001001 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001002}
1003
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001004static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
1005{
1006 return fuse_create(dir, entry, mode, NULL);
1007}
1008
1009static int fuse_permission_2_4(struct inode *inode, int mask)
1010{
1011 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001012}
1013#endif /* KERNEL_2_6 */
1014
1015#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +00001016#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001017static int fuse_setxattr(struct dentry *entry, const char *name,
1018 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001019#else
1020static int fuse_setxattr(struct dentry *entry, const char *name,
1021 void *value, size_t size, int flags)
1022#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001023{
1024 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001025 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001026 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001027 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001028 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001029
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001030 if (size > FUSE_XATTR_SIZE_MAX)
1031 return -E2BIG;
1032
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001033 if (fc->no_setxattr)
1034 return -EOPNOTSUPP;
1035
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001036 req = fuse_get_request(fc);
1037 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001038 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001039
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001040 memset(&inarg, 0, sizeof(inarg));
1041 inarg.size = size;
1042 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001043 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001044 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001045 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001046 req->in.numargs = 3;
1047 req->in.args[0].size = sizeof(inarg);
1048 req->in.args[0].value = &inarg;
1049 req->in.args[1].size = strlen(name) + 1;
1050 req->in.args[1].value = name;
1051 req->in.args[2].size = size;
1052 req->in.args[2].value = value;
1053 request_send(fc, req);
1054 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001055 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001056 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001057 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001058 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001059 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001061}
1062
1063static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1064 void *value, size_t size)
1065{
1066 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001067 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001068 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001069 struct fuse_getxattr_in inarg;
1070 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001071 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001072
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001073 if (fc->no_getxattr)
1074 return -EOPNOTSUPP;
1075
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001076 req = fuse_get_request(fc);
1077 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001078 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001079
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001080 memset(&inarg, 0, sizeof(inarg));
1081 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001082 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001083 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001084 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001085 req->in.numargs = 2;
1086 req->in.args[0].size = sizeof(inarg);
1087 req->in.args[0].value = &inarg;
1088 req->in.args[1].size = strlen(name) + 1;
1089 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001090 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001091 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001092 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001093 req->out.argvar = 1;
1094 req->out.args[0].size = size;
1095 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001096 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001097 req->out.args[0].size = sizeof(outarg);
1098 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001099 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001100 request_send(fc, req);
1101 ret = req->out.h.error;
1102 if (!ret)
1103 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001104 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001105 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001106 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001107 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001108 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001109 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001110 fuse_put_request(fc, req);
1111 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001112}
1113
1114static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1115{
1116 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001117 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001118 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001119 struct fuse_getxattr_in inarg;
1120 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001121 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001122
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001123 if (fc->no_listxattr)
1124 return -EOPNOTSUPP;
1125
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001126 req = fuse_get_request(fc);
1127 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001128 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001129
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001130 memset(&inarg, 0, sizeof(inarg));
1131 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001132 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001133 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001134 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001135 req->in.numargs = 1;
1136 req->in.args[0].size = sizeof(inarg);
1137 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001138 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001139 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001140 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001141 req->out.argvar = 1;
1142 req->out.args[0].size = size;
1143 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001144 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001145 req->out.args[0].size = sizeof(outarg);
1146 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001147 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001148 request_send(fc, req);
1149 ret = req->out.h.error;
1150 if (!ret)
1151 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001152 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001153 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001154 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001155 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001156 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001157 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001158 fuse_put_request(fc, req);
1159 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001160}
1161
1162static int fuse_removexattr(struct dentry *entry, const char *name)
1163{
1164 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001165 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001166 struct fuse_req *req;
1167 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001168
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001169 if (fc->no_removexattr)
1170 return -EOPNOTSUPP;
1171
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001172 req = fuse_get_request(fc);
1173 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001174 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001175
1176 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001177 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001178 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001179 req->in.numargs = 1;
1180 req->in.args[0].size = strlen(name) + 1;
1181 req->in.args[0].value = name;
1182 request_send(fc, req);
1183 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001184 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001185 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001186 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001187 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001188 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001189 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001190}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001191#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001192
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001193static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001194 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001195 .mkdir = fuse_mkdir,
1196 .symlink = fuse_symlink,
1197 .unlink = fuse_unlink,
1198 .rmdir = fuse_rmdir,
1199 .rename = fuse_rename,
1200 .link = fuse_link,
1201 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001202#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001203 .create = fuse_create,
1204 .mknod = fuse_mknod,
1205 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001206 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001207#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001208 .create = fuse_create_2_4,
1209 .mknod = fuse_mknod_2_4,
1210 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001211 .revalidate = fuse_revalidate,
1212#endif
1213#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001214 .setxattr = fuse_setxattr,
1215 .getxattr = fuse_getxattr,
1216 .listxattr = fuse_listxattr,
1217 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001218#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001219};
1220
1221static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001222 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001223 .read = generic_read_dir,
1224 .readdir = fuse_readdir,
1225 .open = fuse_dir_open,
1226 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001227 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001228};
1229
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001230static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001231 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001232#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001233 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001234 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001235#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001236 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001237 .revalidate = fuse_revalidate,
1238#endif
1239#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001240 .setxattr = fuse_setxattr,
1241 .getxattr = fuse_getxattr,
1242 .listxattr = fuse_listxattr,
1243 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001244#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001245};
1246
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001247static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001248 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001249 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001250#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001251 .put_link = fuse_put_link,
1252 .readlink = generic_readlink,
1253#else
1254 .readlink = fuse_readlink,
1255#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001256#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001257 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001258#else
1259 .revalidate = fuse_revalidate,
1260#endif
1261#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001262 .setxattr = fuse_setxattr,
1263 .getxattr = fuse_getxattr,
1264 .listxattr = fuse_listxattr,
1265 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001266#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001267};
1268
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001269void fuse_init_common(struct inode *inode)
1270{
1271 inode->i_op = &fuse_common_inode_operations;
1272}
1273
1274void fuse_init_dir(struct inode *inode)
1275{
1276 inode->i_op = &fuse_dir_inode_operations;
1277 inode->i_fop = &fuse_dir_operations;
1278}
1279
1280void fuse_init_symlink(struct inode *inode)
1281{
1282 inode->i_op = &fuse_symlink_inode_operations;
1283}