blob: 48df469c119f2b617c254220b39e54690315e923 [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 Szeredi11509ce2005-10-26 16:04:04 +0000841static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000842{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000843 unsigned ivalid = iattr->ia_valid;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000844
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000845 if (ivalid & ATTR_MODE)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000846 arg->valid |= FATTR_MODE, arg->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000847 if (ivalid & ATTR_UID)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000848 arg->valid |= FATTR_UID, arg->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000849 if (ivalid & ATTR_GID)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000850 arg->valid |= FATTR_GID, arg->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000851 if (ivalid & ATTR_SIZE)
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000852 arg->valid |= FATTR_SIZE, arg->size = iattr->ia_size;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000853 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000854 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000855 arg->valid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000856#ifdef KERNEL_2_6
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000857 arg->atime = iattr->ia_atime.tv_sec;
858 arg->mtime = iattr->ia_mtime.tv_sec;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000859#else
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000860 arg->atime = iattr->ia_atime;
861 arg->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000862#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000863 }
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000864#ifdef ATTR_FILE
865 if (ivalid & ATTR_FILE) {
866 struct fuse_file *ff = iattr->ia_file->private_data;
867 arg->valid |= FATTR_FH;
868 arg->fh = ff->fh;
869 }
870#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000871}
872
873static int fuse_setattr(struct dentry *entry, struct iattr *attr)
874{
875 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000876 struct fuse_conn *fc = get_fuse_conn(inode);
877 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000878 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000879 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000880 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000881 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000882 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000883
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000884 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
885 err = inode_change_ok(inode, attr);
886 if (err)
887 return err;
888 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000889
Miklos Szeredi069c9502004-07-16 16:17:02 +0000890 if (attr->ia_valid & ATTR_SIZE) {
891 unsigned long limit;
892 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000893#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000894 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000895#else
896 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000897#endif
898 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000899 send_sig(SIGXFSZ, current, 0);
900 return -EFBIG;
901 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000902 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000903
904 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000905 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000906 return -EINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000907
Miklos Szeredi43696432001-11-18 19:15:05 +0000908 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi11509ce2005-10-26 16:04:04 +0000909 iattr_to_fattr(attr, &inarg);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000910 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000911 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000912 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000913 req->in.numargs = 1;
914 req->in.args[0].size = sizeof(inarg);
915 req->in.args[0].value = &inarg;
916 req->out.numargs = 1;
917 req->out.args[0].size = sizeof(outarg);
918 req->out.args[0].value = &outarg;
919 request_send(fc, req);
920 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000921 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000922 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000923 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000924#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000925 if (get_node_id(inode) != FUSE_ROOT_ID)
926 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000927#else
928 make_bad_inode(inode);
929#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000930 err = -EIO;
931 } else {
932 if (is_truncate) {
933 loff_t origsize = i_size_read(inode);
934 i_size_write(inode, outarg.attr.size);
935 if (origsize > outarg.attr.size)
936 vmtruncate(inode, outarg.attr.size);
937 }
938 fuse_change_attributes(inode, &outarg.attr);
939 fi->i_time = time_to_jiffies(outarg.attr_valid,
940 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000941 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000942 } else if (err == -EINTR)
943 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000944
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000945 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000946}
947
Miklos Szeredif85ab242004-01-07 12:16:45 +0000948#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000949static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
950 struct kstat *stat)
951{
952 struct inode *inode = entry->d_inode;
953 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000954 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000955 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000956
Miklos Szeredif85ab242004-01-07 12:16:45 +0000957 return err;
958}
959
960static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000961 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000962{
Miklos Szeredie815c032004-01-19 18:20:49 +0000963 struct inode *inode;
964 int err = fuse_lookup_iget(dir, entry, &inode);
965 if (err)
966 return ERR_PTR(err);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000967 if (inode && S_ISDIR(inode->i_mode)) {
968 /* Don't allow creating an alias to a directory */
969 struct dentry *alias = d_find_alias(inode);
970 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
971 dput(alias);
972 iput(inode);
973 return ERR_PTR(-EIO);
974 }
Miklos Szeredi42b78252005-09-30 08:47:09 +0000975 dput(alias);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000976 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000977 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000978}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000979#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000980static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
981{
982 struct inode *inode;
983 struct dentry *alias;
984
985 int err = fuse_lookup_iget(dir, entry, &inode);
986 if (err)
987 return ERR_PTR(err);
988
989 if (inode && S_ISDIR(inode->i_mode) &&
990 (alias = d_find_alias(inode)) != NULL) {
991 dput(alias);
992 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000993 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000994 }
995
996 d_add(entry, inode);
997 return NULL;
998}
999
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001000static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +00001001 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001002{
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001003 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001004}
1005
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001006static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
1007{
1008 return fuse_create(dir, entry, mode, NULL);
1009}
1010
1011static int fuse_permission_2_4(struct inode *inode, int mask)
1012{
1013 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001014}
1015#endif /* KERNEL_2_6 */
1016
1017#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +00001018#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001019static int fuse_setxattr(struct dentry *entry, const char *name,
1020 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001021#else
1022static int fuse_setxattr(struct dentry *entry, const char *name,
1023 void *value, size_t size, int flags)
1024#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001025{
1026 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001027 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001028 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001029 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001030 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001031
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001032 if (size > FUSE_XATTR_SIZE_MAX)
1033 return -E2BIG;
1034
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001035 if (fc->no_setxattr)
1036 return -EOPNOTSUPP;
1037
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001038 req = fuse_get_request(fc);
1039 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001040 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001041
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001042 memset(&inarg, 0, sizeof(inarg));
1043 inarg.size = size;
1044 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001045 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001046 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001047 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001048 req->in.numargs = 3;
1049 req->in.args[0].size = sizeof(inarg);
1050 req->in.args[0].value = &inarg;
1051 req->in.args[1].size = strlen(name) + 1;
1052 req->in.args[1].value = name;
1053 req->in.args[2].size = size;
1054 req->in.args[2].value = value;
1055 request_send(fc, req);
1056 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001057 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001058 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001059 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001061 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001062 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001063}
1064
1065static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1066 void *value, size_t size)
1067{
1068 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001069 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001070 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001071 struct fuse_getxattr_in inarg;
1072 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001073 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001074
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001075 if (fc->no_getxattr)
1076 return -EOPNOTSUPP;
1077
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001078 req = fuse_get_request(fc);
1079 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001080 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001081
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001082 memset(&inarg, 0, sizeof(inarg));
1083 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001084 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001085 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001086 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001087 req->in.numargs = 2;
1088 req->in.args[0].size = sizeof(inarg);
1089 req->in.args[0].value = &inarg;
1090 req->in.args[1].size = strlen(name) + 1;
1091 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001092 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001093 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001094 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001095 req->out.argvar = 1;
1096 req->out.args[0].size = size;
1097 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001098 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001099 req->out.args[0].size = sizeof(outarg);
1100 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001101 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001102 request_send(fc, req);
1103 ret = req->out.h.error;
1104 if (!ret)
1105 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001106 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001107 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001108 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001109 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001110 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001111 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001112 fuse_put_request(fc, req);
1113 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001114}
1115
1116static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1117{
1118 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001119 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001120 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001121 struct fuse_getxattr_in inarg;
1122 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001123 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001124
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001125 if (fc->no_listxattr)
1126 return -EOPNOTSUPP;
1127
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001128 req = fuse_get_request(fc);
1129 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001130 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001131
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001132 memset(&inarg, 0, sizeof(inarg));
1133 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001134 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001135 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001136 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001137 req->in.numargs = 1;
1138 req->in.args[0].size = sizeof(inarg);
1139 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001140 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001141 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001142 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001143 req->out.argvar = 1;
1144 req->out.args[0].size = size;
1145 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001146 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001147 req->out.args[0].size = sizeof(outarg);
1148 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001149 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001150 request_send(fc, req);
1151 ret = req->out.h.error;
1152 if (!ret)
1153 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001154 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001155 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001156 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001157 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001158 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001159 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001160 fuse_put_request(fc, req);
1161 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001162}
1163
1164static int fuse_removexattr(struct dentry *entry, const char *name)
1165{
1166 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001167 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001168 struct fuse_req *req;
1169 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001170
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001171 if (fc->no_removexattr)
1172 return -EOPNOTSUPP;
1173
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001174 req = fuse_get_request(fc);
1175 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001176 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001177
1178 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001179 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001180 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001181 req->in.numargs = 1;
1182 req->in.args[0].size = strlen(name) + 1;
1183 req->in.args[0].value = name;
1184 request_send(fc, req);
1185 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001186 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001187 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001188 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001189 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001190 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001191 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001192}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001193#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001194
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001195static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001196 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001197 .mkdir = fuse_mkdir,
1198 .symlink = fuse_symlink,
1199 .unlink = fuse_unlink,
1200 .rmdir = fuse_rmdir,
1201 .rename = fuse_rename,
1202 .link = fuse_link,
1203 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001204#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001205 .create = fuse_create,
1206 .mknod = fuse_mknod,
1207 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001208 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001209#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001210 .create = fuse_create_2_4,
1211 .mknod = fuse_mknod_2_4,
1212 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001213 .revalidate = fuse_revalidate,
1214#endif
1215#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001216 .setxattr = fuse_setxattr,
1217 .getxattr = fuse_getxattr,
1218 .listxattr = fuse_listxattr,
1219 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001220#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001221};
1222
1223static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001224 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001225 .read = generic_read_dir,
1226 .readdir = fuse_readdir,
1227 .open = fuse_dir_open,
1228 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001229 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001230};
1231
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001232static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001233 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001234#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001235 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001236 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001237#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001238 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001239 .revalidate = fuse_revalidate,
1240#endif
1241#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001242 .setxattr = fuse_setxattr,
1243 .getxattr = fuse_getxattr,
1244 .listxattr = fuse_listxattr,
1245 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001246#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001247};
1248
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001249static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001250 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001251 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001252#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001253 .put_link = fuse_put_link,
1254 .readlink = generic_readlink,
1255#else
1256 .readlink = fuse_readlink,
1257#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001258#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001259 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001260#else
1261 .revalidate = fuse_revalidate,
1262#endif
1263#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001264 .setxattr = fuse_setxattr,
1265 .getxattr = fuse_getxattr,
1266 .listxattr = fuse_listxattr,
1267 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001268#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001269};
1270
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001271void fuse_init_common(struct inode *inode)
1272{
1273 inode->i_op = &fuse_common_inode_operations;
1274}
1275
1276void fuse_init_dir(struct inode *inode)
1277{
1278 inode->i_op = &fuse_dir_inode_operations;
1279 inode->i_fop = &fuse_dir_operations;
1280}
1281
1282void fuse_init_symlink(struct inode *inode)
1283{
1284 inode->i_op = &fuse_symlink_inode_operations;
1285}