blob: 34286687274167dd2a4872c57389e57f3adad6d8 [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 Szeredi6becf0b2005-09-23 11:25:28 +0000115 if (!err && outarg.nodeid == FUSE_ROOT_ID)
116 err = -EIO;
117 else if (!err && outarg.nodeid) {
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
153static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000154 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000155 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000156{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000157 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000158 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000159 struct fuse_inode *fi;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000160 int err;
161
162 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000163 req->inode = dir;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000164 req->out.numargs = 1;
165 req->out.args[0].size = sizeof(outarg);
166 req->out.args[0].value = &outarg;
167 request_send(fc, req);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000168 err = req->out.h.error;
169 if (err) {
170 fuse_put_request(fc, req);
171 return err;
172 }
Miklos Szeredi6becf0b2005-09-23 11:25:28 +0000173 if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
174 fuse_put_request(fc, req);
175 return -EIO;
176 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000177 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000178 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000179 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000180 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000181 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000182 }
183 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000184
185 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000186 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000187 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000188 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000189 }
190
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000191 entry->d_time = time_to_jiffies(outarg.entry_valid,
192 outarg.entry_valid_nsec);
Miklos Szerediad051c32004-07-02 09:22:50 +0000193
Miklos Szeredi039322d2004-12-01 18:39:12 +0000194 fi = get_fuse_inode(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000195 fi->i_time = time_to_jiffies(outarg.attr_valid,
196 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000197
Miklos Szeredi76f65782004-02-19 16:55:40 +0000198 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000199 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000200 return 0;
201}
202
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000203static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000204 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000205{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000206 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000207 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000208 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000209 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000210 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000211
212 memset(&inarg, 0, sizeof(inarg));
213 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000214 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000215 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000216 req->in.numargs = 2;
217 req->in.args[0].size = sizeof(inarg);
218 req->in.args[0].value = &inarg;
219 req->in.args[1].size = entry->d_name.len + 1;
220 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000221 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000222}
223
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000224static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
225 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000226{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000227 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000228}
229
Miklos Szeredib483c932001-10-29 14:57:57 +0000230static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
231{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000232 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000233 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000234 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000235 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000236 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000237
238 memset(&inarg, 0, sizeof(inarg));
239 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000240 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000241 req->in.numargs = 2;
242 req->in.args[0].size = sizeof(inarg);
243 req->in.args[0].value = &inarg;
244 req->in.args[1].size = entry->d_name.len + 1;
245 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000246 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000247}
248
249static int fuse_symlink(struct inode *dir, struct dentry *entry,
250 const char *link)
251{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000252 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000253 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000254 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000255
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000256 if (len > FUSE_SYMLINK_MAX)
257 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000258
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000259 req = fuse_get_request(fc);
260 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000261 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000262
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000263 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000264 req->in.numargs = 2;
265 req->in.args[0].size = entry->d_name.len + 1;
266 req->in.args[0].value = entry->d_name.name;
267 req->in.args[1].size = len;
268 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000269 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000270}
271
Miklos Szeredib5958612004-02-20 14:10:49 +0000272static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000273{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000274 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000275 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000276 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000277 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000278 return -EINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000279
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000280 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000281 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000282 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000283 req->in.numargs = 1;
284 req->in.args[0].size = entry->d_name.len + 1;
285 req->in.args[0].value = entry->d_name.name;
286 request_send(fc, req);
287 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000288 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000289 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000290 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000291
Miklos Szeredib5958612004-02-20 14:10:49 +0000292 /* Set nlink to zero so the inode can be cleared, if
293 the inode does have more links this will be
294 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000295 inode->i_nlink = 0;
296 fuse_invalidate_attr(inode);
297 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000298 } else if (err == -EINTR)
299 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000300 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000301}
302
303static int fuse_rmdir(struct inode *dir, struct dentry *entry)
304{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000305 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000306 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000307 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000308 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000309 return -EINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000310
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000311 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000312 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000313 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000314 req->in.numargs = 1;
315 req->in.args[0].size = entry->d_name.len + 1;
316 req->in.args[0].value = entry->d_name.name;
317 request_send(fc, req);
318 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000319 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000320 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000321 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000322 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000323 } else if (err == -EINTR)
324 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000326}
327
328static int fuse_rename(struct inode *olddir, struct dentry *oldent,
329 struct inode *newdir, struct dentry *newent)
330{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000331 int err;
332 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000333 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000334 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000336 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000337
Miklos Szeredi43696432001-11-18 19:15:05 +0000338 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000339 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000340 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000341 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000342 req->inode = olddir;
343 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000344 req->in.numargs = 3;
345 req->in.args[0].size = sizeof(inarg);
346 req->in.args[0].value = &inarg;
347 req->in.args[1].size = oldent->d_name.len + 1;
348 req->in.args[1].value = oldent->d_name.name;
349 req->in.args[2].size = newent->d_name.len + 1;
350 req->in.args[2].value = newent->d_name.name;
351 request_send(fc, req);
352 err = req->out.h.error;
353 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000354 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000355 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000356 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000357 fuse_invalidate_attr(newdir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000358 } else if (err == -EINTR) {
359 /* If request was interrupted, DEITY only knows if the
360 rename actually took place. If the invalidation
361 fails (e.g. some process has CWD under the renamed
362 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000363 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000364 fuse_invalidate_entry(oldent);
365 if (newent->d_inode)
366 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000367 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000368
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000369 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000370}
371
372static int fuse_link(struct dentry *entry, struct inode *newdir,
373 struct dentry *newent)
374{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000375 int err;
376 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000377 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000378 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000379 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000381 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000382
Miklos Szeredi43696432001-11-18 19:15:05 +0000383 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000384 inarg.oldnodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000385 req->in.h.opcode = FUSE_LINK;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000386 req->inode2 = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000387 req->in.numargs = 2;
388 req->in.args[0].size = sizeof(inarg);
389 req->in.args[0].value = &inarg;
390 req->in.args[1].size = newent->d_name.len + 1;
391 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000392 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
393 /* Contrary to "normal" filesystems it can happen that link
394 makes two "logical" inodes point to the same "physical"
395 inode. We invalidate the attributes of the old one, so it
396 will reflect changes in the backing inode (link count,
397 etc.)
398 */
399 if (!err || err == -EINTR)
400 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000401 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000402}
403
Miklos Szeredif85ab242004-01-07 12:16:45 +0000404int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000405{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000406 int err;
407 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000408 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000409 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000410 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000411 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000412
413 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000414 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000415 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000416 req->out.numargs = 1;
417 req->out.args[0].size = sizeof(arg);
418 req->out.args[0].value = &arg;
419 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000420 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000421 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000422 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000423 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000424#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000425 if (get_node_id(inode) != FUSE_ROOT_ID)
426 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000427#else
428 make_bad_inode(inode);
429#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000430 err = -EIO;
431 } else {
432 struct fuse_inode *fi = get_fuse_inode(inode);
433 fuse_change_attributes(inode, &arg.attr);
434 fi->i_time = time_to_jiffies(arg.attr_valid,
435 arg.attr_valid_nsec);
436 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000437 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000438 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000439}
440
Miklos Szeredi61139db2005-04-29 07:38:25 +0000441/*
442 * Calling into a user-controlled filesystem gives the filesystem
443 * daemon ptrace-like capabilities over the requester process. This
444 * means, that the filesystem daemon is able to record the exact
445 * filesystem operations performed, and can also control the behavior
446 * of the requester process in otherwise impossible ways. For example
447 * it can delay the operation for arbitrary length of time allowing
448 * DoS against the requester.
449 *
450 * For this reason only those processes can call into the filesystem,
451 * for which the owner of the mount has ptrace privilege. This
452 * excludes processes started by other users, suid or sgid processes.
453 */
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000454static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
455{
456 if (fc->flags & FUSE_ALLOW_OTHER)
457 return 1;
458
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000459 if (task->euid == fc->user_id &&
460 task->suid == fc->user_id &&
461 task->uid == fc->user_id &&
462 task->egid == fc->group_id &&
463 task->sgid == fc->group_id &&
464 task->gid == fc->group_id)
465 return 1;
466
467 return 0;
468}
469
Miklos Szeredife25def2001-12-20 15:38:05 +0000470static int fuse_revalidate(struct dentry *entry)
471{
472 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000473 struct fuse_inode *fi = get_fuse_inode(inode);
474 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000475
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000476 if (!fuse_allow_task(fc, current))
477 return -EACCES;
478 if (get_node_id(inode) != FUSE_ROOT_ID &&
479 time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000480 return 0;
481
Miklos Szeredif85ab242004-01-07 12:16:45 +0000482 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000483}
484
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000485static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000486{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000487 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000488
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000489 if (!fuse_allow_task(fc, current))
Miklos Szeredife25def2001-12-20 15:38:05 +0000490 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000491 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000492#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000493 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000494#else
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000495 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000496#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000497
498 /* If permission is denied, try to refresh file
499 attributes. This is also needed, because the root
500 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000501 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000502 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000503 if (!err)
504#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000505 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000506#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000507 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000508#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000509 }
510
511 /* FIXME: Need some mechanism to revoke permissions:
512 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000513 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000514 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000515
Miklos Szeredife25def2001-12-20 15:38:05 +0000516 This is actually not so grave, since the user can
517 simply keep access to the file/directory anyway by
518 keeping it open... */
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000519
520 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000521 } else {
522 int mode = inode->i_mode;
523 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
524 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
525 return -EROFS;
526 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
527 return -EACCES;
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000528 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000529 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000530}
531
Miklos Szeredib483c932001-10-29 14:57:57 +0000532static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
533 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000534{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000535 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000536 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000537 size_t reclen = FUSE_DIRENT_SIZE(dirent);
538 int over;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000539 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000540 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000541 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000542 break;
543
544 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi18fce982005-04-01 21:07:35 +0000545 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000546 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000547 break;
548
Miklos Szeredib483c932001-10-29 14:57:57 +0000549 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000550 nbytes -= reclen;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000551 file->f_pos = dirent->off;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000552 }
553
Miklos Szeredib483c932001-10-29 14:57:57 +0000554 return 0;
555}
556
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000557static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
558 struct inode *inode, loff_t pos,
559 size_t count)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000560{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000561 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000562}
563
Miklos Szeredib483c932001-10-29 14:57:57 +0000564static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
565{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000566 int err;
567 size_t nbytes;
568 struct page *page;
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000569 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000570 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredif94e0102005-05-12 14:56:34 +0000571 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000572 if (!req)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000573 return -EINTR;
Miklos Szeredie815c032004-01-19 18:20:49 +0000574
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000575 page = alloc_page(GFP_KERNEL);
576 if (!page) {
577 fuse_put_request(fc, req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000578 return -ENOMEM;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000579 }
580 req->num_pages = 1;
581 req->pages[0] = page;
582 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
583 err = req->out.h.error;
584 fuse_put_request(fc, req);
585 if (!err)
586 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
587 filldir);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000588
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000589 __free_page(page);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000590 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000591 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000592}
593
Miklos Szeredi05033042001-11-13 16:11:35 +0000594static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000595{
596 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000597 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000598 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000599 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000600
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000601 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000602 return ERR_PTR(-EINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000603
Miklos Szeredi05033042001-11-13 16:11:35 +0000604 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000605 if (!link) {
606 link = ERR_PTR(-ENOMEM);
607 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000608 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000609 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000610 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000611 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000612 req->out.argvar = 1;
613 req->out.numargs = 1;
614 req->out.args[0].size = PAGE_SIZE - 1;
615 req->out.args[0].value = link;
616 request_send(fc, req);
617 if (req->out.h.error) {
618 free_page((unsigned long) link);
619 link = ERR_PTR(req->out.h.error);
620 } else
621 link[req->out.args[0].size] = '\0';
622 out:
623 fuse_put_request(fc, req);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000624 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi05033042001-11-13 16:11:35 +0000625 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000626}
627
628static void free_link(char *link)
629{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000630 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000631 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000632}
633
Miklos Szeredi56487812005-09-02 13:05:06 +0000634#ifdef KERNEL_2_6_13_PLUS
635static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
636{
637 nd_set_link(nd, read_link(dentry));
638 return NULL;
639}
640
641static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
642{
643 free_link(nd_get_link(nd));
644}
645#elif defined(KERNEL_2_6_8_PLUS)
Miklos Szeredi81394522005-01-11 14:24:18 +0000646static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
647{
648 nd_set_link(nd, read_link(dentry));
649 return 0;
650}
651
652static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
653{
654 free_link(nd_get_link(nd));
655}
656#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000657static int fuse_readlink(struct dentry *dentry, char __user *buffer,
658 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000659{
660 int ret;
661 char *link;
662
Miklos Szeredi05033042001-11-13 16:11:35 +0000663 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000664 ret = vfs_readlink(dentry, buffer, buflen, link);
665 free_link(link);
666 return ret;
667}
668
669static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
670{
671 int ret;
672 char *link;
673
Miklos Szeredi05033042001-11-13 16:11:35 +0000674 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000675 ret = vfs_follow_link(nd, link);
676 free_link(link);
677 return ret;
678}
Miklos Szeredi81394522005-01-11 14:24:18 +0000679#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000680
681static int fuse_dir_open(struct inode *inode, struct file *file)
682{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000683 return fuse_open_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000684}
685
686static int fuse_dir_release(struct inode *inode, struct file *file)
687{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000688 return fuse_release_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000689}
690
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000691static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
692{
Miklos Szeredib7640d22005-04-08 15:15:28 +0000693 /* nfsd can call this with no file */
694 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000695}
696
Miklos Szeredi83a07442004-11-30 18:25:20 +0000697static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000698{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000699 unsigned ivalid = iattr->ia_valid;
700 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000701
Miklos Szeredi5e183482001-10-31 14:52:35 +0000702 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000703
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000704 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000705 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000706 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000707 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000708 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000709 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000710 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000711 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
712 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000713 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000714 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000715#ifdef KERNEL_2_6
716 fattr->atime = iattr->ia_atime.tv_sec;
717 fattr->mtime = iattr->ia_mtime.tv_sec;
718#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000719 fattr->atime = iattr->ia_atime;
720 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000721#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000722 }
723
724 return fvalid;
725}
726
727static int fuse_setattr(struct dentry *entry, struct iattr *attr)
728{
729 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000730 struct fuse_conn *fc = get_fuse_conn(inode);
731 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000732 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000733 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000734 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000735 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000736 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000737
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000738 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
739 err = inode_change_ok(inode, attr);
740 if (err)
741 return err;
742 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000743
Miklos Szeredi069c9502004-07-16 16:17:02 +0000744 if (attr->ia_valid & ATTR_SIZE) {
745 unsigned long limit;
746 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000747#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000748 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000749#else
750 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000751#endif
752 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000753 send_sig(SIGXFSZ, current, 0);
754 return -EFBIG;
755 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000756 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000757
758 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000759 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000760 return -EINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000761
Miklos Szeredi43696432001-11-18 19:15:05 +0000762 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000763 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000764 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000765 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000766 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000767 req->in.numargs = 1;
768 req->in.args[0].size = sizeof(inarg);
769 req->in.args[0].value = &inarg;
770 req->out.numargs = 1;
771 req->out.args[0].size = sizeof(outarg);
772 req->out.args[0].value = &outarg;
773 request_send(fc, req);
774 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000775 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000776 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000777 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredi9f60c492005-09-08 14:34:48 +0000778#ifndef KERNEL_2_6_12_PLUS
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000779 if (get_node_id(inode) != FUSE_ROOT_ID)
780 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000781#else
782 make_bad_inode(inode);
783#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000784 err = -EIO;
785 } else {
786 if (is_truncate) {
787 loff_t origsize = i_size_read(inode);
788 i_size_write(inode, outarg.attr.size);
789 if (origsize > outarg.attr.size)
790 vmtruncate(inode, outarg.attr.size);
791 }
792 fuse_change_attributes(inode, &outarg.attr);
793 fi->i_time = time_to_jiffies(outarg.attr_valid,
794 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000795 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000796 } else if (err == -EINTR)
797 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000798
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000799 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000800}
801
Miklos Szeredif85ab242004-01-07 12:16:45 +0000802#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000803static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
804 struct kstat *stat)
805{
806 struct inode *inode = entry->d_inode;
807 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000808 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000809 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000810
Miklos Szeredif85ab242004-01-07 12:16:45 +0000811 return err;
812}
813
814static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000815 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000816{
Miklos Szeredie815c032004-01-19 18:20:49 +0000817 struct inode *inode;
818 int err = fuse_lookup_iget(dir, entry, &inode);
819 if (err)
820 return ERR_PTR(err);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000821 if (inode && S_ISDIR(inode->i_mode)) {
822 /* Don't allow creating an alias to a directory */
823 struct dentry *alias = d_find_alias(inode);
824 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
825 dput(alias);
826 iput(inode);
827 return ERR_PTR(-EIO);
828 }
829 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000830 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000831}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000832#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000833static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
834{
835 struct inode *inode;
836 struct dentry *alias;
837
838 int err = fuse_lookup_iget(dir, entry, &inode);
839 if (err)
840 return ERR_PTR(err);
841
842 if (inode && S_ISDIR(inode->i_mode) &&
843 (alias = d_find_alias(inode)) != NULL) {
844 dput(alias);
845 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000846 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000847 }
848
849 d_add(entry, inode);
850 return NULL;
851}
852
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000853static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000854 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000855{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000856 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000857}
858
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000859static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
860{
861 return fuse_create(dir, entry, mode, NULL);
862}
863
864static int fuse_permission_2_4(struct inode *inode, int mask)
865{
866 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000867}
868#endif /* KERNEL_2_6 */
869
870#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000871#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000872static int fuse_setxattr(struct dentry *entry, const char *name,
873 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000874#else
875static int fuse_setxattr(struct dentry *entry, const char *name,
876 void *value, size_t size, int flags)
877#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000878{
879 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000880 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000881 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000882 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000883 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000884
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000885 if (size > FUSE_XATTR_SIZE_MAX)
886 return -E2BIG;
887
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000888 if (fc->no_setxattr)
889 return -EOPNOTSUPP;
890
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000891 req = fuse_get_request(fc);
892 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000893 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000894
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000895 memset(&inarg, 0, sizeof(inarg));
896 inarg.size = size;
897 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000898 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000899 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000900 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000901 req->in.numargs = 3;
902 req->in.args[0].size = sizeof(inarg);
903 req->in.args[0].value = &inarg;
904 req->in.args[1].size = strlen(name) + 1;
905 req->in.args[1].value = name;
906 req->in.args[2].size = size;
907 req->in.args[2].value = value;
908 request_send(fc, req);
909 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000910 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000911 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000912 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000913 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000914 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000915 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000916}
917
918static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
919 void *value, size_t size)
920{
921 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000922 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000923 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000924 struct fuse_getxattr_in inarg;
925 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000926 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000927
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000928 if (fc->no_getxattr)
929 return -EOPNOTSUPP;
930
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000931 req = fuse_get_request(fc);
932 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000933 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000934
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000935 memset(&inarg, 0, sizeof(inarg));
936 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000938 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000939 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000940 req->in.numargs = 2;
941 req->in.args[0].size = sizeof(inarg);
942 req->in.args[0].value = &inarg;
943 req->in.args[1].size = strlen(name) + 1;
944 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000945 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000946 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000947 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000948 req->out.argvar = 1;
949 req->out.args[0].size = size;
950 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000951 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000952 req->out.args[0].size = sizeof(outarg);
953 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000954 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 request_send(fc, req);
956 ret = req->out.h.error;
957 if (!ret)
958 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000959 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000960 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000961 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000962 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000963 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000964 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000965 fuse_put_request(fc, req);
966 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000967}
968
969static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
970{
971 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000972 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000973 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000974 struct fuse_getxattr_in inarg;
975 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000976 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000977
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000978 if (fc->no_listxattr)
979 return -EOPNOTSUPP;
980
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000981 req = fuse_get_request(fc);
982 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000983 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000984
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000985 memset(&inarg, 0, sizeof(inarg));
986 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000987 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000988 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000989 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000990 req->in.numargs = 1;
991 req->in.args[0].size = sizeof(inarg);
992 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000993 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000995 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000996 req->out.argvar = 1;
997 req->out.args[0].size = size;
998 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000999 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001000 req->out.args[0].size = sizeof(outarg);
1001 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001002 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001003 request_send(fc, req);
1004 ret = req->out.h.error;
1005 if (!ret)
1006 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001007 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001008 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001009 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001010 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001011 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001012 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001013 fuse_put_request(fc, req);
1014 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001015}
1016
1017static int fuse_removexattr(struct dentry *entry, const char *name)
1018{
1019 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001020 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001021 struct fuse_req *req;
1022 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001023
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001024 if (fc->no_removexattr)
1025 return -EOPNOTSUPP;
1026
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001027 req = fuse_get_request(fc);
1028 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001029 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001030
1031 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001032 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001033 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001034 req->in.numargs = 1;
1035 req->in.args[0].size = strlen(name) + 1;
1036 req->in.args[0].value = name;
1037 request_send(fc, req);
1038 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001039 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001040 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001041 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001042 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001043 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001044 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001045}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001046#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001047
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001048static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001049 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001050 .mkdir = fuse_mkdir,
1051 .symlink = fuse_symlink,
1052 .unlink = fuse_unlink,
1053 .rmdir = fuse_rmdir,
1054 .rename = fuse_rename,
1055 .link = fuse_link,
1056 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001057#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001058 .create = fuse_create,
1059 .mknod = fuse_mknod,
1060 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001061 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001062#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001063 .create = fuse_create_2_4,
1064 .mknod = fuse_mknod_2_4,
1065 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001066 .revalidate = fuse_revalidate,
1067#endif
1068#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001069 .setxattr = fuse_setxattr,
1070 .getxattr = fuse_getxattr,
1071 .listxattr = fuse_listxattr,
1072 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001073#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001074};
1075
1076static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001077 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001078 .read = generic_read_dir,
1079 .readdir = fuse_readdir,
1080 .open = fuse_dir_open,
1081 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001082 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001083};
1084
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001085static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001086 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001087#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001088 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001089 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001090#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001091 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001092 .revalidate = fuse_revalidate,
1093#endif
1094#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001095 .setxattr = fuse_setxattr,
1096 .getxattr = fuse_getxattr,
1097 .listxattr = fuse_listxattr,
1098 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001099#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001100};
1101
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001102static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001103 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001104 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001105#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001106 .put_link = fuse_put_link,
1107 .readlink = generic_readlink,
1108#else
1109 .readlink = fuse_readlink,
1110#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001111#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001112 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001113#else
1114 .revalidate = fuse_revalidate,
1115#endif
1116#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001117 .setxattr = fuse_setxattr,
1118 .getxattr = fuse_getxattr,
1119 .listxattr = fuse_listxattr,
1120 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001121#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001122};
1123
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001124void fuse_init_common(struct inode *inode)
1125{
1126 inode->i_op = &fuse_common_inode_operations;
1127}
1128
1129void fuse_init_dir(struct inode *inode)
1130{
1131 inode->i_op = &fuse_dir_inode_operations;
1132 inode->i_fop = &fuse_dir_operations;
1133}
1134
1135void fuse_init_symlink(struct inode *inode)
1136{
1137 inode->i_op = &fuse_symlink_inode_operations;
1138}