blob: 1ae265a403ec64949338c956dbb09165ac66a7b6 [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 Szeredic26c14d2004-04-09 17:48:32 +0000115 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000116 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000117 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000118 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000119 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredie815c032004-01-19 18:20:49 +0000120 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000121 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000122 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000123 fuse_put_request(fc, req);
124 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000125 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000126
Miklos Szeredi069c9502004-07-16 16:17:02 +0000127 if (inode) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000128 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000129 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000130 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000131 fi->i_time = time_to_jiffies(outarg.attr_valid,
132 outarg.attr_valid_nsec);
133 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000134
Miklos Szeredi307242f2004-01-26 11:28:44 +0000135 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000136 *inodep = inode;
137 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000138}
139
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000140void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000141{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000142 get_fuse_inode(inode)->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000143}
144
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000145static void fuse_invalidate_entry(struct dentry *entry)
146{
147 d_invalidate(entry);
148 entry->d_time = jiffies - 1;
149}
150
151static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000152 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000153 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000154{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000155 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000156 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000157 struct fuse_inode *fi;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000158 int err;
159
160 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000161 req->inode = dir;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000162 req->out.numargs = 1;
163 req->out.args[0].size = sizeof(outarg);
164 req->out.args[0].value = &outarg;
165 request_send(fc, req);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000166 err = req->out.h.error;
167 if (err) {
168 fuse_put_request(fc, req);
169 return err;
170 }
171 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi38009022005-05-08 19:47:22 +0000172 &outarg.attr);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000173 if (!inode) {
Miklos Szeredi38009022005-05-08 19:47:22 +0000174 fuse_send_forget(fc, req, outarg.nodeid, 1);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000175 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000176 }
177 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000178
179 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000180 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000181 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000182 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000183 }
184
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000185 entry->d_time = time_to_jiffies(outarg.entry_valid,
186 outarg.entry_valid_nsec);
Miklos Szerediad051c32004-07-02 09:22:50 +0000187
Miklos Szeredi039322d2004-12-01 18:39:12 +0000188 fi = get_fuse_inode(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000189 fi->i_time = time_to_jiffies(outarg.attr_valid,
190 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000191
Miklos Szeredi76f65782004-02-19 16:55:40 +0000192 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000193 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000194 return 0;
195}
196
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000197static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000198 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000199{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000200 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000201 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000202 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000203 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000204 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000205
206 memset(&inarg, 0, sizeof(inarg));
207 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000208 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000209 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000210 req->in.numargs = 2;
211 req->in.args[0].size = sizeof(inarg);
212 req->in.args[0].value = &inarg;
213 req->in.args[1].size = entry->d_name.len + 1;
214 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000215 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000216}
217
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000218static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
219 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000220{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000221 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000222}
223
Miklos Szeredib483c932001-10-29 14:57:57 +0000224static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
225{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000226 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000227 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000228 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000229 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000230 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000231
232 memset(&inarg, 0, sizeof(inarg));
233 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000234 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000235 req->in.numargs = 2;
236 req->in.args[0].size = sizeof(inarg);
237 req->in.args[0].value = &inarg;
238 req->in.args[1].size = entry->d_name.len + 1;
239 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000240 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000241}
242
243static int fuse_symlink(struct inode *dir, struct dentry *entry,
244 const char *link)
245{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000246 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000247 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000248 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000249
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000250 if (len > FUSE_SYMLINK_MAX)
251 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000252
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000253 req = fuse_get_request(fc);
254 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000255 return -EINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000256
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000257 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000258 req->in.numargs = 2;
259 req->in.args[0].size = entry->d_name.len + 1;
260 req->in.args[0].value = entry->d_name.name;
261 req->in.args[1].size = len;
262 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000263 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000264}
265
Miklos Szeredib5958612004-02-20 14:10:49 +0000266static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000267{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000268 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000269 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000270 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000271 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000272 return -EINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000273
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000274 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000275 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000276 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000277 req->in.numargs = 1;
278 req->in.args[0].size = entry->d_name.len + 1;
279 req->in.args[0].value = entry->d_name.name;
280 request_send(fc, req);
281 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000282 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000283 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000284 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000285
Miklos Szeredib5958612004-02-20 14:10:49 +0000286 /* Set nlink to zero so the inode can be cleared, if
287 the inode does have more links this will be
288 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000289 inode->i_nlink = 0;
290 fuse_invalidate_attr(inode);
291 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000292 } else if (err == -EINTR)
293 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000294 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000295}
296
297static int fuse_rmdir(struct inode *dir, struct dentry *entry)
298{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000299 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000300 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000301 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000302 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000303 return -EINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000304
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000305 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000306 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000307 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000308 req->in.numargs = 1;
309 req->in.args[0].size = entry->d_name.len + 1;
310 req->in.args[0].value = entry->d_name.name;
311 request_send(fc, req);
312 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000313 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000314 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000315 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000316 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000317 } else if (err == -EINTR)
318 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000319 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000320}
321
322static int fuse_rename(struct inode *olddir, struct dentry *oldent,
323 struct inode *newdir, struct dentry *newent)
324{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000325 int err;
326 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000327 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000328 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000329 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000330 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000331
Miklos Szeredi43696432001-11-18 19:15:05 +0000332 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000333 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000334 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000335 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000336 req->inode = olddir;
337 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000338 req->in.numargs = 3;
339 req->in.args[0].size = sizeof(inarg);
340 req->in.args[0].value = &inarg;
341 req->in.args[1].size = oldent->d_name.len + 1;
342 req->in.args[1].value = oldent->d_name.name;
343 req->in.args[2].size = newent->d_name.len + 1;
344 req->in.args[2].value = newent->d_name.name;
345 request_send(fc, req);
346 err = req->out.h.error;
347 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000348 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000349 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000350 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000351 fuse_invalidate_attr(newdir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000352 } else if (err == -EINTR) {
353 /* If request was interrupted, DEITY only knows if the
354 rename actually took place. If the invalidation
355 fails (e.g. some process has CWD under the renamed
356 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000357 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000358 fuse_invalidate_entry(oldent);
359 if (newent->d_inode)
360 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000361 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000362
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000363 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000364}
365
366static int fuse_link(struct dentry *entry, struct inode *newdir,
367 struct dentry *newent)
368{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000369 int err;
370 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000371 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000372 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000373 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000374 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000375 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000376
Miklos Szeredi43696432001-11-18 19:15:05 +0000377 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000378 inarg.oldnodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000379 req->in.h.opcode = FUSE_LINK;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000380 req->inode2 = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000381 req->in.numargs = 2;
382 req->in.args[0].size = sizeof(inarg);
383 req->in.args[0].value = &inarg;
384 req->in.args[1].size = newent->d_name.len + 1;
385 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000386 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
387 /* Contrary to "normal" filesystems it can happen that link
388 makes two "logical" inodes point to the same "physical"
389 inode. We invalidate the attributes of the old one, so it
390 will reflect changes in the backing inode (link count,
391 etc.)
392 */
393 if (!err || err == -EINTR)
394 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000395 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000396}
397
Miklos Szeredif85ab242004-01-07 12:16:45 +0000398int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000399{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000400 int err;
401 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000402 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000403 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000404 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000405 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000406
407 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000408 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000409 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000410 req->out.numargs = 1;
411 req->out.args[0].size = sizeof(arg);
412 req->out.args[0].value = &arg;
413 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000414 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000415 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000416 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000417 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000418#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000419 if (get_node_id(inode) != FUSE_ROOT_ID)
420 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000421#else
422 make_bad_inode(inode);
423#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000424 err = -EIO;
425 } else {
426 struct fuse_inode *fi = get_fuse_inode(inode);
427 fuse_change_attributes(inode, &arg.attr);
428 fi->i_time = time_to_jiffies(arg.attr_valid,
429 arg.attr_valid_nsec);
430 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000431 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000432 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000433}
434
Miklos Szeredi61139db2005-04-29 07:38:25 +0000435/*
436 * Calling into a user-controlled filesystem gives the filesystem
437 * daemon ptrace-like capabilities over the requester process. This
438 * means, that the filesystem daemon is able to record the exact
439 * filesystem operations performed, and can also control the behavior
440 * of the requester process in otherwise impossible ways. For example
441 * it can delay the operation for arbitrary length of time allowing
442 * DoS against the requester.
443 *
444 * For this reason only those processes can call into the filesystem,
445 * for which the owner of the mount has ptrace privilege. This
446 * excludes processes started by other users, suid or sgid processes.
447 */
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000448static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
449{
450 if (fc->flags & FUSE_ALLOW_OTHER)
451 return 1;
452
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000453 if (task->euid == fc->user_id &&
454 task->suid == fc->user_id &&
455 task->uid == fc->user_id &&
456 task->egid == fc->group_id &&
457 task->sgid == fc->group_id &&
458 task->gid == fc->group_id)
459 return 1;
460
461 return 0;
462}
463
Miklos Szeredife25def2001-12-20 15:38:05 +0000464static int fuse_revalidate(struct dentry *entry)
465{
466 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000467 struct fuse_inode *fi = get_fuse_inode(inode);
468 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000469
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000470 if (!fuse_allow_task(fc, current))
471 return -EACCES;
472 if (get_node_id(inode) != FUSE_ROOT_ID &&
473 time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000474 return 0;
475
Miklos Szeredif85ab242004-01-07 12:16:45 +0000476 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000477}
478
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000479static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000480{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000481 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000482
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000483 if (!fuse_allow_task(fc, current))
Miklos Szeredife25def2001-12-20 15:38:05 +0000484 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000485 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000486#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000487 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000488#else
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000489 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000490#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000491
492 /* If permission is denied, try to refresh file
493 attributes. This is also needed, because the root
494 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000495 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000496 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000497 if (!err)
498#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000499 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000500#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000501 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000502#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000503 }
504
505 /* FIXME: Need some mechanism to revoke permissions:
506 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000507 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000508 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000509
Miklos Szeredife25def2001-12-20 15:38:05 +0000510 This is actually not so grave, since the user can
511 simply keep access to the file/directory anyway by
512 keeping it open... */
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000513
514 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000515 } else {
516 int mode = inode->i_mode;
517 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
518 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
519 return -EROFS;
520 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
521 return -EACCES;
Miklos Szeredifcf9f8d2005-09-08 14:28:54 +0000522 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000523 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000524}
525
Miklos Szeredib483c932001-10-29 14:57:57 +0000526static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
527 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000528{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000529 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000530 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000531 size_t reclen = FUSE_DIRENT_SIZE(dirent);
532 int over;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000533 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000534 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000535 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000536 break;
537
538 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi18fce982005-04-01 21:07:35 +0000539 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000540 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000541 break;
542
Miklos Szeredib483c932001-10-29 14:57:57 +0000543 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000544 nbytes -= reclen;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000545 file->f_pos = dirent->off;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000546 }
547
Miklos Szeredib483c932001-10-29 14:57:57 +0000548 return 0;
549}
550
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000551static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
552 struct inode *inode, loff_t pos,
553 size_t count)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000554{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000555 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000556}
557
Miklos Szeredib483c932001-10-29 14:57:57 +0000558static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
559{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000560 int err;
561 size_t nbytes;
562 struct page *page;
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000563 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000564 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredif94e0102005-05-12 14:56:34 +0000565 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000566 if (!req)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000567 return -EINTR;
Miklos Szeredie815c032004-01-19 18:20:49 +0000568
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000569 page = alloc_page(GFP_KERNEL);
570 if (!page) {
571 fuse_put_request(fc, req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000572 return -ENOMEM;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000573 }
574 req->num_pages = 1;
575 req->pages[0] = page;
576 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
577 err = req->out.h.error;
578 fuse_put_request(fc, req);
579 if (!err)
580 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
581 filldir);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000582
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000583 __free_page(page);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000584 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000585 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000586}
587
Miklos Szeredi05033042001-11-13 16:11:35 +0000588static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000589{
590 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000591 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000592 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000593 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000594
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000595 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000596 return ERR_PTR(-EINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000597
Miklos Szeredi05033042001-11-13 16:11:35 +0000598 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000599 if (!link) {
600 link = ERR_PTR(-ENOMEM);
601 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000602 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000603 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000604 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000605 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000606 req->out.argvar = 1;
607 req->out.numargs = 1;
608 req->out.args[0].size = PAGE_SIZE - 1;
609 req->out.args[0].value = link;
610 request_send(fc, req);
611 if (req->out.h.error) {
612 free_page((unsigned long) link);
613 link = ERR_PTR(req->out.h.error);
614 } else
615 link[req->out.args[0].size] = '\0';
616 out:
617 fuse_put_request(fc, req);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000618 fuse_invalidate_attr(inode); /* atime changed */
Miklos Szeredi05033042001-11-13 16:11:35 +0000619 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000620}
621
622static void free_link(char *link)
623{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000624 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000625 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000626}
627
Miklos Szeredi56487812005-09-02 13:05:06 +0000628#ifdef KERNEL_2_6_13_PLUS
629static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
630{
631 nd_set_link(nd, read_link(dentry));
632 return NULL;
633}
634
635static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
636{
637 free_link(nd_get_link(nd));
638}
639#elif defined(KERNEL_2_6_8_PLUS)
Miklos Szeredi81394522005-01-11 14:24:18 +0000640static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
641{
642 nd_set_link(nd, read_link(dentry));
643 return 0;
644}
645
646static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
647{
648 free_link(nd_get_link(nd));
649}
650#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000651static int fuse_readlink(struct dentry *dentry, char __user *buffer,
652 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000653{
654 int ret;
655 char *link;
656
Miklos Szeredi05033042001-11-13 16:11:35 +0000657 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000658 ret = vfs_readlink(dentry, buffer, buflen, link);
659 free_link(link);
660 return ret;
661}
662
663static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
664{
665 int ret;
666 char *link;
667
Miklos Szeredi05033042001-11-13 16:11:35 +0000668 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000669 ret = vfs_follow_link(nd, link);
670 free_link(link);
671 return ret;
672}
Miklos Szeredi81394522005-01-11 14:24:18 +0000673#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000674
675static int fuse_dir_open(struct inode *inode, struct file *file)
676{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000677 return fuse_open_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000678}
679
680static int fuse_dir_release(struct inode *inode, struct file *file)
681{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000682 return fuse_release_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000683}
684
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000685static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
686{
Miklos Szeredib7640d22005-04-08 15:15:28 +0000687 /* nfsd can call this with no file */
688 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000689}
690
Miklos Szeredi83a07442004-11-30 18:25:20 +0000691static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000693 unsigned ivalid = iattr->ia_valid;
694 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000695
Miklos Szeredi5e183482001-10-31 14:52:35 +0000696 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000697
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000698 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000699 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000700 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000701 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000702 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000703 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000704 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000705 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
706 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000707 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000708 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000709#ifdef KERNEL_2_6
710 fattr->atime = iattr->ia_atime.tv_sec;
711 fattr->mtime = iattr->ia_mtime.tv_sec;
712#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000713 fattr->atime = iattr->ia_atime;
714 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000715#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000716 }
717
718 return fvalid;
719}
720
721static int fuse_setattr(struct dentry *entry, struct iattr *attr)
722{
723 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000724 struct fuse_conn *fc = get_fuse_conn(inode);
725 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000726 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000727 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000728 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000729 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000730 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000731
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000732 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
733 err = inode_change_ok(inode, attr);
734 if (err)
735 return err;
736 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000737
Miklos Szeredi069c9502004-07-16 16:17:02 +0000738 if (attr->ia_valid & ATTR_SIZE) {
739 unsigned long limit;
740 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000741#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000742 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000743#else
744 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000745#endif
746 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000747 send_sig(SIGXFSZ, current, 0);
748 return -EFBIG;
749 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000750 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000751
752 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000753 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000754 return -EINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000755
Miklos Szeredi43696432001-11-18 19:15:05 +0000756 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000757 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000758 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000759 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000760 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000761 req->in.numargs = 1;
762 req->in.args[0].size = sizeof(inarg);
763 req->in.args[0].value = &inarg;
764 req->out.numargs = 1;
765 req->out.args[0].size = sizeof(outarg);
766 req->out.args[0].value = &outarg;
767 request_send(fc, req);
768 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000769 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000770 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000771 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000772#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000773 if (get_node_id(inode) != FUSE_ROOT_ID)
774 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000775#else
776 make_bad_inode(inode);
777#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000778 err = -EIO;
779 } else {
780 if (is_truncate) {
781 loff_t origsize = i_size_read(inode);
782 i_size_write(inode, outarg.attr.size);
783 if (origsize > outarg.attr.size)
784 vmtruncate(inode, outarg.attr.size);
785 }
786 fuse_change_attributes(inode, &outarg.attr);
787 fi->i_time = time_to_jiffies(outarg.attr_valid,
788 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000789 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000790 } else if (err == -EINTR)
791 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000792
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000793 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000794}
795
Miklos Szeredif85ab242004-01-07 12:16:45 +0000796#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000797static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
798 struct kstat *stat)
799{
800 struct inode *inode = entry->d_inode;
801 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000802 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000803 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000804
Miklos Szeredif85ab242004-01-07 12:16:45 +0000805 return err;
806}
807
808static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000809 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000810{
Miklos Szeredie815c032004-01-19 18:20:49 +0000811 struct inode *inode;
812 int err = fuse_lookup_iget(dir, entry, &inode);
813 if (err)
814 return ERR_PTR(err);
Miklos Szeredi9c1b68d2005-04-28 09:55:09 +0000815 if (inode && S_ISDIR(inode->i_mode)) {
816 /* Don't allow creating an alias to a directory */
817 struct dentry *alias = d_find_alias(inode);
818 if (alias && !(alias->d_flags & DCACHE_DISCONNECTED)) {
819 dput(alias);
820 iput(inode);
821 return ERR_PTR(-EIO);
822 }
823 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000824 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000825}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000826#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000827static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
828{
829 struct inode *inode;
830 struct dentry *alias;
831
832 int err = fuse_lookup_iget(dir, entry, &inode);
833 if (err)
834 return ERR_PTR(err);
835
836 if (inode && S_ISDIR(inode->i_mode) &&
837 (alias = d_find_alias(inode)) != NULL) {
838 dput(alias);
839 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000840 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000841 }
842
843 d_add(entry, inode);
844 return NULL;
845}
846
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000847static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000848 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000849{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000850 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000851}
852
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000853static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
854{
855 return fuse_create(dir, entry, mode, NULL);
856}
857
858static int fuse_permission_2_4(struct inode *inode, int mask)
859{
860 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000861}
862#endif /* KERNEL_2_6 */
863
864#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000865#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000866static int fuse_setxattr(struct dentry *entry, const char *name,
867 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000868#else
869static int fuse_setxattr(struct dentry *entry, const char *name,
870 void *value, size_t size, int flags)
871#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000872{
873 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000874 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000875 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000876 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000877 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000878
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000879 if (size > FUSE_XATTR_SIZE_MAX)
880 return -E2BIG;
881
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000882 if (fc->no_setxattr)
883 return -EOPNOTSUPP;
884
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000885 req = fuse_get_request(fc);
886 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000887 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000888
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000889 memset(&inarg, 0, sizeof(inarg));
890 inarg.size = size;
891 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000892 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000893 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000894 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 req->in.numargs = 3;
896 req->in.args[0].size = sizeof(inarg);
897 req->in.args[0].value = &inarg;
898 req->in.args[1].size = strlen(name) + 1;
899 req->in.args[1].value = name;
900 req->in.args[2].size = size;
901 req->in.args[2].value = value;
902 request_send(fc, req);
903 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000904 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000905 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000906 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000907 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000908 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000909 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000910}
911
912static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
913 void *value, size_t size)
914{
915 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000916 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000917 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000918 struct fuse_getxattr_in inarg;
919 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000920 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000921
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000922 if (fc->no_getxattr)
923 return -EOPNOTSUPP;
924
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000925 req = fuse_get_request(fc);
926 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000927 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000928
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000929 memset(&inarg, 0, sizeof(inarg));
930 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000931 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000932 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000933 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000934 req->in.numargs = 2;
935 req->in.args[0].size = sizeof(inarg);
936 req->in.args[0].value = &inarg;
937 req->in.args[1].size = strlen(name) + 1;
938 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000939 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000940 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000941 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 req->out.argvar = 1;
943 req->out.args[0].size = size;
944 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000945 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000946 req->out.args[0].size = sizeof(outarg);
947 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000948 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000949 request_send(fc, req);
950 ret = req->out.h.error;
951 if (!ret)
952 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000953 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000954 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000955 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000956 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000957 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000958 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000959 fuse_put_request(fc, req);
960 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000961}
962
963static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
964{
965 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000966 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000967 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000968 struct fuse_getxattr_in inarg;
969 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000970 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000971
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000972 if (fc->no_listxattr)
973 return -EOPNOTSUPP;
974
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000975 req = fuse_get_request(fc);
976 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +0000977 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000978
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000979 memset(&inarg, 0, sizeof(inarg));
980 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000981 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000982 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000983 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000984 req->in.numargs = 1;
985 req->in.args[0].size = sizeof(inarg);
986 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000987 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000988 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000989 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000990 req->out.argvar = 1;
991 req->out.args[0].size = size;
992 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000993 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 req->out.args[0].size = sizeof(outarg);
995 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000996 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000997 request_send(fc, req);
998 ret = req->out.h.error;
999 if (!ret)
1000 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001001 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001002 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001003 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001004 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001005 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001006 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001007 fuse_put_request(fc, req);
1008 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001009}
1010
1011static int fuse_removexattr(struct dentry *entry, const char *name)
1012{
1013 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001014 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001015 struct fuse_req *req;
1016 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001017
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001018 if (fc->no_removexattr)
1019 return -EOPNOTSUPP;
1020
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001021 req = fuse_get_request(fc);
1022 if (!req)
Miklos Szeredif94e0102005-05-12 14:56:34 +00001023 return -EINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001024
1025 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001026 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001027 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001028 req->in.numargs = 1;
1029 req->in.args[0].size = strlen(name) + 1;
1030 req->in.args[0].value = name;
1031 request_send(fc, req);
1032 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001033 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001034 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001035 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001036 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001037 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001038 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001039}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001040#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001041
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001042static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001043 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001044 .mkdir = fuse_mkdir,
1045 .symlink = fuse_symlink,
1046 .unlink = fuse_unlink,
1047 .rmdir = fuse_rmdir,
1048 .rename = fuse_rename,
1049 .link = fuse_link,
1050 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001051#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001052 .create = fuse_create,
1053 .mknod = fuse_mknod,
1054 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001055 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001056#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001057 .create = fuse_create_2_4,
1058 .mknod = fuse_mknod_2_4,
1059 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001060 .revalidate = fuse_revalidate,
1061#endif
1062#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001063 .setxattr = fuse_setxattr,
1064 .getxattr = fuse_getxattr,
1065 .listxattr = fuse_listxattr,
1066 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001067#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001068};
1069
1070static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001071 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001072 .read = generic_read_dir,
1073 .readdir = fuse_readdir,
1074 .open = fuse_dir_open,
1075 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001076 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001077};
1078
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001079static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001080 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001081#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001082 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001083 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001084#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001085 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001086 .revalidate = fuse_revalidate,
1087#endif
1088#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001089 .setxattr = fuse_setxattr,
1090 .getxattr = fuse_getxattr,
1091 .listxattr = fuse_listxattr,
1092 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001093#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001094};
1095
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001096static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001097 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001098 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001099#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001100 .put_link = fuse_put_link,
1101 .readlink = generic_readlink,
1102#else
1103 .readlink = fuse_readlink,
1104#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001105#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001106 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001107#else
1108 .revalidate = fuse_revalidate,
1109#endif
1110#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001111 .setxattr = fuse_setxattr,
1112 .getxattr = fuse_getxattr,
1113 .listxattr = fuse_listxattr,
1114 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001115#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001116};
1117
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001118void fuse_init_common(struct inode *inode)
1119{
1120 inode->i_op = &fuse_common_inode_operations;
1121}
1122
1123void fuse_init_dir(struct inode *inode)
1124{
1125 inode->i_op = &fuse_dir_inode_operations;
1126 inode->i_fop = &fuse_dir_operations;
1127}
1128
1129void fuse_init_symlink(struct inode *inode)
1130{
1131 inode->i_op = &fuse_symlink_inode_operations;
1132}