blob: 91fa22cab73ab7d424206d3ca27c4b0f5eec2059 [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 Szeredi81394522005-01-11 14:24:18 +000019#ifdef KERNEL_2_6_7_PLUS
20#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};
27 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;
51 int version;
52 struct fuse_entry_out outarg;
53 struct inode *inode = entry->d_inode;
54 struct fuse_inode *fi = get_fuse_inode(inode);
55 struct fuse_conn *fc = get_fuse_conn(inode);
56 struct fuse_req *req = fuse_get_request_nonint(fc);
57 if (!req)
58 return 0;
59
60 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
61 request_send_nonint(fc, req);
62 version = req->out.h.unique;
63 err = req->out.h.error;
64 fuse_put_request(fc, req);
65 if (err || outarg.nodeid != get_node_id(inode) ||
66 (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
67 return 0;
68
69 fuse_change_attributes(inode, &outarg.attr);
70 inode->i_version = version;
71 entry->d_time = time_to_jiffies(outarg.entry_valid,
72 outarg.entry_valid_nsec);
73 fi->i_time = time_to_jiffies(outarg.attr_valid,
74 outarg.attr_valid_nsec);
75 }
76 return 1;
77}
78#ifndef KERNEL_2_6
79static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
80{
81 return fuse_dentry_revalidate(entry, NULL);
82}
83#endif
84
85static struct dentry_operations fuse_dentry_operations = {
86#ifdef KERNEL_2_6
87 .d_revalidate = fuse_dentry_revalidate,
88#else
89 .d_revalidate = fuse_dentry_revalidate_2_4,
90#endif
91};
92
Miklos Szeredie815c032004-01-19 18:20:49 +000093static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
94 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +000095{
Miklos Szeredie815c032004-01-19 18:20:49 +000096 int err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +000097 int version;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +000098 struct fuse_entry_out outarg;
Miklos Szeredie815c032004-01-19 18:20:49 +000099 struct inode *inode = NULL;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000100 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000101 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000102
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000103 if (entry->d_name.len > FUSE_NAME_MAX)
104 return -ENAMETOOLONG;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000105
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000106 req = fuse_get_request(fc);
107 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000108 return -ERESTARTNOINTR;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000109
Miklos Szeredie56818b2004-12-12 11:45:24 +0000110 fuse_lookup_init(req, dir, entry, &outarg);
111 request_send(fc, req);
112 version = req->out.h.unique;
113 err = req->out.h.error;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000114 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000115 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000116 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000117 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000118 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000119 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000120 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000121 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000122 fuse_put_request(fc, req);
123 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000124 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000125
Miklos Szeredi069c9502004-07-16 16:17:02 +0000126 if (inode) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000127 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000128 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000129 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000130 fi->i_time = time_to_jiffies(outarg.attr_valid,
131 outarg.attr_valid_nsec);
132 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000133
Miklos Szeredi307242f2004-01-26 11:28:44 +0000134 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000135 *inodep = inode;
136 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000137}
138
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000139void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000140{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000141 get_fuse_inode(inode)->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000142}
143
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000144static void fuse_invalidate_entry(struct dentry *entry)
145{
146 d_invalidate(entry);
147 entry->d_time = jiffies - 1;
148}
149
150static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000151 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000152 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000153{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000154 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000155 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000156 struct fuse_inode *fi;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000157 int version;
158 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);
166 version = req->out.h.unique;
167 err = req->out.h.error;
168 if (err) {
169 fuse_put_request(fc, req);
170 return err;
171 }
172 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
173 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000174 if (!inode) {
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000175 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000176 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000177 }
178 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000179
180 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000181 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000182 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000183 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000184 }
185
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000186 entry->d_time = time_to_jiffies(outarg.entry_valid,
187 outarg.entry_valid_nsec);
Miklos Szerediad051c32004-07-02 09:22:50 +0000188
Miklos Szeredi039322d2004-12-01 18:39:12 +0000189 fi = get_fuse_inode(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000190 fi->i_time = time_to_jiffies(outarg.attr_valid,
191 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000192
Miklos Szeredi76f65782004-02-19 16:55:40 +0000193 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000194 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000195 return 0;
196}
197
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000198static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000199 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000200{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000201 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000202 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000203 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000204 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000205 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000206
207 memset(&inarg, 0, sizeof(inarg));
208 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000209 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000210 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000211 req->in.numargs = 2;
212 req->in.args[0].size = sizeof(inarg);
213 req->in.args[0].value = &inarg;
214 req->in.args[1].size = entry->d_name.len + 1;
215 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000216 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000217}
218
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000219static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
220 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000221{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000222 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000223}
224
Miklos Szeredib483c932001-10-29 14:57:57 +0000225static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
226{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000227 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000228 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000229 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000230 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000231 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000232
233 memset(&inarg, 0, sizeof(inarg));
234 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000235 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000236 req->in.numargs = 2;
237 req->in.args[0].size = sizeof(inarg);
238 req->in.args[0].value = &inarg;
239 req->in.args[1].size = entry->d_name.len + 1;
240 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000241 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000242}
243
244static int fuse_symlink(struct inode *dir, struct dentry *entry,
245 const char *link)
246{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000247 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000248 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000249 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000250
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000251 if (len > FUSE_SYMLINK_MAX)
252 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000253
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000254 req = fuse_get_request(fc);
255 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000256 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000257
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000258 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000259 req->in.numargs = 2;
260 req->in.args[0].size = entry->d_name.len + 1;
261 req->in.args[0].value = entry->d_name.name;
262 req->in.args[1].size = len;
263 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000264 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000265}
266
Miklos Szeredib5958612004-02-20 14:10:49 +0000267static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000268{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000269 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000270 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000271 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000273 return -ERESTARTNOINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000274
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000275 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000276 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000277 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000278 req->in.numargs = 1;
279 req->in.args[0].size = entry->d_name.len + 1;
280 req->in.args[0].value = entry->d_name.name;
281 request_send(fc, req);
282 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000283 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000284 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000285 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000286
Miklos Szeredib5958612004-02-20 14:10:49 +0000287 /* Set nlink to zero so the inode can be cleared, if
288 the inode does have more links this will be
289 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000290 inode->i_nlink = 0;
291 fuse_invalidate_attr(inode);
292 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000293 } else if (err == -EINTR)
294 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000295 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000296}
297
298static int fuse_rmdir(struct inode *dir, struct dentry *entry)
299{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000300 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000301 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000302 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000303 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000304 return -ERESTARTNOINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000305
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000307 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000308 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000309 req->in.numargs = 1;
310 req->in.args[0].size = entry->d_name.len + 1;
311 req->in.args[0].value = entry->d_name.name;
312 request_send(fc, req);
313 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000314 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000315 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000316 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000317 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000318 } else if (err == -EINTR)
319 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000320 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000321}
322
323static int fuse_rename(struct inode *olddir, struct dentry *oldent,
324 struct inode *newdir, struct dentry *newent)
325{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000326 int err;
327 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000328 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000329 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000330 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000331 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332
Miklos Szeredi43696432001-11-18 19:15:05 +0000333 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000334 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000336 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000337 req->inode = olddir;
338 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000339 req->in.numargs = 3;
340 req->in.args[0].size = sizeof(inarg);
341 req->in.args[0].value = &inarg;
342 req->in.args[1].size = oldent->d_name.len + 1;
343 req->in.args[1].value = oldent->d_name.name;
344 req->in.args[2].size = newent->d_name.len + 1;
345 req->in.args[2].value = newent->d_name.name;
346 request_send(fc, req);
347 err = req->out.h.error;
348 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000349 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000350 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000351 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000352 fuse_invalidate_attr(newdir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000353 } else if (err == -EINTR) {
354 /* If request was interrupted, DEITY only knows if the
355 rename actually took place. If the invalidation
356 fails (e.g. some process has CWD under the renamed
357 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000358 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000359 fuse_invalidate_entry(oldent);
360 if (newent->d_inode)
361 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000362 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000364 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000365}
366
367static int fuse_link(struct dentry *entry, struct inode *newdir,
368 struct dentry *newent)
369{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000370 int err;
371 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000372 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000373 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000374 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000375 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000376 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000377
Miklos Szeredi43696432001-11-18 19:15:05 +0000378 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000379 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 req->in.h.opcode = FUSE_LINK;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000381 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000382 req->in.numargs = 2;
383 req->in.args[0].size = sizeof(inarg);
384 req->in.args[0].value = &inarg;
385 req->in.args[1].size = newent->d_name.len + 1;
386 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000387 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
388 /* Contrary to "normal" filesystems it can happen that link
389 makes two "logical" inodes point to the same "physical"
390 inode. We invalidate the attributes of the old one, so it
391 will reflect changes in the backing inode (link count,
392 etc.)
393 */
394 if (!err || err == -EINTR)
395 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000396 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000397}
398
Miklos Szeredif85ab242004-01-07 12:16:45 +0000399int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000400{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000401 int err;
402 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000403 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000404 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000405 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000406 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000407
408 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000409 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000410 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000411 req->out.numargs = 1;
412 req->out.args[0].size = sizeof(arg);
413 req->out.args[0].value = &arg;
414 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000415 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000416 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000417 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000418 if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000419 if (get_node_id(inode) != FUSE_ROOT_ID)
420 make_bad_inode(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000421 err = -EIO;
422 } else {
423 struct fuse_inode *fi = get_fuse_inode(inode);
424 fuse_change_attributes(inode, &arg.attr);
425 fi->i_time = time_to_jiffies(arg.attr_valid,
426 arg.attr_valid_nsec);
427 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000428 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000429 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000430}
431
Miklos Szeredife25def2001-12-20 15:38:05 +0000432static int fuse_revalidate(struct dentry *entry)
433{
434 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000435 struct fuse_inode *fi = get_fuse_inode(inode);
436 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000437
Miklos Szeredi039322d2004-12-01 18:39:12 +0000438 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000439 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000440 current->fsuid != fc->user_id &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000441 (!(fc->flags & FUSE_ALLOW_ROOT) ||
Miklos Szeredi9ed69ba2005-01-13 12:11:49 +0000442 !capable(CAP_DAC_OVERRIDE)))
Miklos Szeredife25def2001-12-20 15:38:05 +0000443 return -EACCES;
Miklos Szeredi81394522005-01-11 14:24:18 +0000444 } else if (time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000445 return 0;
446
Miklos Szeredif85ab242004-01-07 12:16:45 +0000447 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000448}
449
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000450static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000451{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000452 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000453
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000454 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id &&
Miklos Szeredi9ed69ba2005-01-13 12:11:49 +0000455 (!(fc->flags & FUSE_ALLOW_ROOT) || !capable(CAP_DAC_OVERRIDE)))
Miklos Szeredife25def2001-12-20 15:38:05 +0000456 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000457 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000458#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000459 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000460#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000461 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000462#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000463
464 /* If permission is denied, try to refresh file
465 attributes. This is also needed, because the root
466 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000467 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000468 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000469 if (!err)
470#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000471 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000472#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000473 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000474#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000475 }
476
477 /* FIXME: Need some mechanism to revoke permissions:
478 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000479 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000480 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000481
Miklos Szeredife25def2001-12-20 15:38:05 +0000482 This is actually not so grave, since the user can
483 simply keep access to the file/directory anyway by
484 keeping it open... */
485
486 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000487 } else {
488 int mode = inode->i_mode;
489 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
490 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
491 return -EROFS;
492 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
493 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000494 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000495 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000496}
497
Miklos Szeredib483c932001-10-29 14:57:57 +0000498static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
499 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000500{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000501 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000502 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000503 size_t reclen = FUSE_DIRENT_SIZE(dirent);
504 int over;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000505 if (dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000506 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000507 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000508 break;
509
510 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000511 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000512 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000513 break;
514
Miklos Szeredib483c932001-10-29 14:57:57 +0000515 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000516 file->f_pos += reclen;
517 nbytes -= reclen;
518 }
519
Miklos Szeredib483c932001-10-29 14:57:57 +0000520 return 0;
521}
522
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000523static int fuse_checkdir(struct file *cfile, struct file *file)
524{
525 struct inode *inode;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000526 if (!cfile)
527 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000528 inode = cfile->f_dentry->d_inode;
529 if (!S_ISREG(inode->i_mode)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000530 fput(cfile);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000531 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000532 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000533
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000534 file->private_data = cfile;
535 return 0;
536}
537
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000538static int fuse_getdir(struct file *file)
539{
540 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000541 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000542 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000543 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000544 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000545
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000546 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000547 return -ERESTARTNOINTR;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000548
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000549 req->in.h.opcode = FUSE_GETDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000550 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000551 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000552 req->out.numargs = 1;
553 req->out.args[0].size = sizeof(struct fuse_getdir_out);
554 req->out.args[0].value = &outarg;
555 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000556 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000557 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000558 if (!err)
559 err = fuse_checkdir(outarg.file, file);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000560 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000561}
562
Miklos Szeredib483c932001-10-29 14:57:57 +0000563static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
564{
565 struct file *cfile = file->private_data;
566 char *buf;
567 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000568
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000569 if (!cfile) {
570 ret = fuse_getdir(file);
571 if (ret)
572 return ret;
573
574 cfile = file->private_data;
575 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000576
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000577 buf = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000578 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000579 return -ENOMEM;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000580
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000581 ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000582 if (ret > 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000583 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
584
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000585 free_page((unsigned long) buf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000586 return ret;
587}
588
Miklos Szeredi05033042001-11-13 16:11:35 +0000589static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000590{
591 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000592 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000593 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000594 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000595
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000596 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000597 return ERR_PTR(-ERESTARTNOINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000598
Miklos Szeredi05033042001-11-13 16:11:35 +0000599 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000600 if (!link) {
601 link = ERR_PTR(-ENOMEM);
602 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000603 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000604 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000605 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000606 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000607 req->out.argvar = 1;
608 req->out.numargs = 1;
609 req->out.args[0].size = PAGE_SIZE - 1;
610 req->out.args[0].value = link;
611 request_send(fc, req);
612 if (req->out.h.error) {
613 free_page((unsigned long) link);
614 link = ERR_PTR(req->out.h.error);
615 } else
616 link[req->out.args[0].size] = '\0';
617 out:
618 fuse_put_request(fc, req);
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 Szeredi81394522005-01-11 14:24:18 +0000628#ifdef KERNEL_2_6_7_PLUS
629static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
630{
631 nd_set_link(nd, read_link(dentry));
632 return 0;
633}
634
635static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
636{
637 free_link(nd_get_link(nd));
638}
639#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000640static int fuse_readlink(struct dentry *dentry, char __user *buffer,
641 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000642{
643 int ret;
644 char *link;
645
Miklos Szeredi05033042001-11-13 16:11:35 +0000646 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000647 ret = vfs_readlink(dentry, buffer, buflen, link);
648 free_link(link);
649 return ret;
650}
651
652static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
653{
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_follow_link(nd, link);
659 free_link(link);
660 return ret;
661}
Miklos Szeredi81394522005-01-11 14:24:18 +0000662#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000663
664static int fuse_dir_open(struct inode *inode, struct file *file)
665{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000666 file->private_data = NULL;
667 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000668}
669
670static int fuse_dir_release(struct inode *inode, struct file *file)
671{
672 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000673
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000674 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000675 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000676
677 return 0;
678}
679
Miklos Szeredi83a07442004-11-30 18:25:20 +0000680static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000681{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000682 unsigned ivalid = iattr->ia_valid;
683 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000684
Miklos Szeredi5e183482001-10-31 14:52:35 +0000685 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000686
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000687 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000688 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000689 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000691 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000693 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000694 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
695 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000696 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000697 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000698#ifdef KERNEL_2_6
699 fattr->atime = iattr->ia_atime.tv_sec;
700 fattr->mtime = iattr->ia_mtime.tv_sec;
701#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000702 fattr->atime = iattr->ia_atime;
703 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000704#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000705 }
706
707 return fvalid;
708}
709
710static int fuse_setattr(struct dentry *entry, struct iattr *attr)
711{
712 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000713 struct fuse_conn *fc = get_fuse_conn(inode);
714 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000715 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000716 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000717 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000718 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000719 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000720
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000721 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
722 err = inode_change_ok(inode, attr);
723 if (err)
724 return err;
725 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000726
Miklos Szeredi069c9502004-07-16 16:17:02 +0000727 if (attr->ia_valid & ATTR_SIZE) {
728 unsigned long limit;
729 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000730#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000731 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000732#else
733 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000734#endif
735 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000736 send_sig(SIGXFSZ, current, 0);
737 return -EFBIG;
738 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000739 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000740
741 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000742 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000743 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000744
Miklos Szeredi43696432001-11-18 19:15:05 +0000745 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000746 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000747 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000748 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000749 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000750 req->in.numargs = 1;
751 req->in.args[0].size = sizeof(inarg);
752 req->in.args[0].value = &inarg;
753 req->out.numargs = 1;
754 req->out.args[0].size = sizeof(outarg);
755 req->out.args[0].value = &outarg;
756 request_send(fc, req);
757 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000758 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000759 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000760 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000761 if (get_node_id(inode) != FUSE_ROOT_ID)
762 make_bad_inode(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000763 err = -EIO;
764 } else {
765 if (is_truncate) {
766 loff_t origsize = i_size_read(inode);
767 i_size_write(inode, outarg.attr.size);
768 if (origsize > outarg.attr.size)
769 vmtruncate(inode, outarg.attr.size);
770 }
771 fuse_change_attributes(inode, &outarg.attr);
772 fi->i_time = time_to_jiffies(outarg.attr_valid,
773 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000774 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000775 } else if (err == -EINTR)
776 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000777
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000778 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000779}
780
Miklos Szeredif85ab242004-01-07 12:16:45 +0000781#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000782static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
783 struct kstat *stat)
784{
785 struct inode *inode = entry->d_inode;
786 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000787 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000788 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000789
Miklos Szeredif85ab242004-01-07 12:16:45 +0000790 return err;
791}
792
793static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000794 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000795{
Miklos Szeredie815c032004-01-19 18:20:49 +0000796 struct inode *inode;
797 int err = fuse_lookup_iget(dir, entry, &inode);
798 if (err)
799 return ERR_PTR(err);
800 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000801}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000802#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000803static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
804{
805 struct inode *inode;
806 struct dentry *alias;
807
808 int err = fuse_lookup_iget(dir, entry, &inode);
809 if (err)
810 return ERR_PTR(err);
811
812 if (inode && S_ISDIR(inode->i_mode) &&
813 (alias = d_find_alias(inode)) != NULL) {
814 dput(alias);
815 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000816 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000817 }
818
819 d_add(entry, inode);
820 return NULL;
821}
822
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000823static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000824 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000825{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000826 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000827}
828
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000829static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
830{
831 return fuse_create(dir, entry, mode, NULL);
832}
833
834static int fuse_permission_2_4(struct inode *inode, int mask)
835{
836 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000837}
838#endif /* KERNEL_2_6 */
839
840#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000841#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000842static int fuse_setxattr(struct dentry *entry, const char *name,
843 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000844#else
845static int fuse_setxattr(struct dentry *entry, const char *name,
846 void *value, size_t size, int flags)
847#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000848{
849 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000850 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000851 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000852 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000853 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000854
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000855 if (size > FUSE_XATTR_SIZE_MAX)
856 return -E2BIG;
857
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000858 if (fc->no_setxattr)
859 return -EOPNOTSUPP;
860
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000861 req = fuse_get_request(fc);
862 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000863 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000864
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000865 memset(&inarg, 0, sizeof(inarg));
866 inarg.size = size;
867 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000868 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000869 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000870 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000871 req->in.numargs = 3;
872 req->in.args[0].size = sizeof(inarg);
873 req->in.args[0].value = &inarg;
874 req->in.args[1].size = strlen(name) + 1;
875 req->in.args[1].value = name;
876 req->in.args[2].size = size;
877 req->in.args[2].value = value;
878 request_send(fc, req);
879 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000880 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000881 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000882 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000883 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000884 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000885 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000886}
887
888static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
889 void *value, size_t size)
890{
891 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000892 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000893 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000894 struct fuse_getxattr_in inarg;
895 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000896 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000897
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000898 if (fc->no_getxattr)
899 return -EOPNOTSUPP;
900
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000901 req = fuse_get_request(fc);
902 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000903 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000904
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000905 memset(&inarg, 0, sizeof(inarg));
906 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000907 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000908 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000909 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000910 req->in.numargs = 2;
911 req->in.args[0].size = sizeof(inarg);
912 req->in.args[0].value = &inarg;
913 req->in.args[1].size = strlen(name) + 1;
914 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000915 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000916 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000917 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000918 req->out.argvar = 1;
919 req->out.args[0].size = size;
920 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000921 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000922 req->out.args[0].size = sizeof(outarg);
923 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000924 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000925 request_send(fc, req);
926 ret = req->out.h.error;
927 if (!ret)
928 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000929 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000930 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000931 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000932 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000933 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000934 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000935 fuse_put_request(fc, req);
936 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000937}
938
939static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
940{
941 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000942 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000943 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000944 struct fuse_getxattr_in inarg;
945 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000946 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000947
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000948 if (fc->no_listxattr)
949 return -EOPNOTSUPP;
950
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000951 req = fuse_get_request(fc);
952 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000953 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000954
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000955 memset(&inarg, 0, sizeof(inarg));
956 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000957 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000958 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000959 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000960 req->in.numargs = 1;
961 req->in.args[0].size = sizeof(inarg);
962 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000963 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000964 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000965 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000966 req->out.argvar = 1;
967 req->out.args[0].size = size;
968 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000969 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000970 req->out.args[0].size = sizeof(outarg);
971 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000972 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000973 request_send(fc, req);
974 ret = req->out.h.error;
975 if (!ret)
976 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000977 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000978 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000979 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000980 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000981 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000982 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000983 fuse_put_request(fc, req);
984 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000985}
986
987static int fuse_removexattr(struct dentry *entry, const char *name)
988{
989 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000990 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000991 struct fuse_req *req;
992 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000993
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000994 if (fc->no_removexattr)
995 return -EOPNOTSUPP;
996
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000997 req = fuse_get_request(fc);
998 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000999 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001000
1001 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001002 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001003 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001004 req->in.numargs = 1;
1005 req->in.args[0].size = strlen(name) + 1;
1006 req->in.args[0].value = name;
1007 request_send(fc, req);
1008 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001009 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001010 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001011 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001012 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001013 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001014 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001015}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001016#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001017
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001018static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001019 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001020 .mkdir = fuse_mkdir,
1021 .symlink = fuse_symlink,
1022 .unlink = fuse_unlink,
1023 .rmdir = fuse_rmdir,
1024 .rename = fuse_rename,
1025 .link = fuse_link,
1026 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001027#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001028 .create = fuse_create,
1029 .mknod = fuse_mknod,
1030 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001031 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001032#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001033 .create = fuse_create_2_4,
1034 .mknod = fuse_mknod_2_4,
1035 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001036 .revalidate = fuse_revalidate,
1037#endif
1038#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001039 .setxattr = fuse_setxattr,
1040 .getxattr = fuse_getxattr,
1041 .listxattr = fuse_listxattr,
1042 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001043#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001044};
1045
1046static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001047 .read = generic_read_dir,
1048 .readdir = fuse_readdir,
1049 .open = fuse_dir_open,
1050 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001051};
1052
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001053static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001054 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001055#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001056 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001057 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001058#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001059 .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
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001070static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001071 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001072 .follow_link = fuse_follow_link,
Miklos Szeredi81394522005-01-11 14:24:18 +00001073#ifdef KERNEL_2_6_7_PLUS
1074 .put_link = fuse_put_link,
1075 .readlink = generic_readlink,
1076#else
1077 .readlink = fuse_readlink,
1078#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001079#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001080 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001081#else
1082 .revalidate = fuse_revalidate,
1083#endif
1084#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001085 .setxattr = fuse_setxattr,
1086 .getxattr = fuse_getxattr,
1087 .listxattr = fuse_listxattr,
1088 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001089#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001090};
1091
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001092void fuse_init_common(struct inode *inode)
1093{
1094 inode->i_op = &fuse_common_inode_operations;
1095}
1096
1097void fuse_init_dir(struct inode *inode)
1098{
1099 inode->i_op = &fuse_dir_inode_operations;
1100 inode->i_fop = &fuse_dir_operations;
1101}
1102
1103void fuse_init_symlink(struct inode *inode)
1104{
1105 inode->i_op = &fuse_symlink_inode_operations;
1106}