blob: 08427a9270b572927bb9680db4c1a9c6c650d3ac [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2004 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 Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000020static inline unsigned long time_to_jiffies(unsigned long sec,
21 unsigned long nsec)
22{
23 /* prevent wrapping of jiffies */
Miklos Szeredic26c14d2004-04-09 17:48:32 +000024 if (sec + 1 >= LONG_MAX / HZ)
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000025 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +000026
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000027 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
28}
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;
49 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
50 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 Szeredi0fcfa032004-12-13 15:22:28 +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) {
419 make_bad_inode(inode);
420 err = -EIO;
421 } else {
422 struct fuse_inode *fi = get_fuse_inode(inode);
423 fuse_change_attributes(inode, &arg.attr);
424 fi->i_time = time_to_jiffies(arg.attr_valid,
425 arg.attr_valid_nsec);
426 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000427 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000428 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000429}
430
Miklos Szeredife25def2001-12-20 15:38:05 +0000431static int fuse_revalidate(struct dentry *entry)
432{
433 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000434 struct fuse_inode *fi = get_fuse_inode(inode);
435 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000436
Miklos Szeredi039322d2004-12-01 18:39:12 +0000437 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000438 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000439 current->fsuid != fc->uid &&
440 (!(fc->flags & FUSE_ALLOW_ROOT) ||
441 current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000442 return -EACCES;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000443 } else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000444 return 0;
445
Miklos Szeredif85ab242004-01-07 12:16:45 +0000446 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000447}
448
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000449static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000450{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000451 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000452
Miklos Szeredi180ff692004-11-01 16:01:05 +0000453 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
454 (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000455 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000456 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000457#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000458 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000459#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000460 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000461#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000462
463 /* If permission is denied, try to refresh file
464 attributes. This is also needed, because the root
465 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000466 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000467 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000468 if (!err)
469#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000470 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000471#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000472 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000473#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000474 }
475
476 /* FIXME: Need some mechanism to revoke permissions:
477 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000478 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000479 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000480
Miklos Szeredife25def2001-12-20 15:38:05 +0000481 This is actually not so grave, since the user can
482 simply keep access to the file/directory anyway by
483 keeping it open... */
484
485 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000486 } else {
487 int mode = inode->i_mode;
488 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
489 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
490 return -EROFS;
491 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
492 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000493 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000494 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000495}
496
Miklos Szeredib483c932001-10-29 14:57:57 +0000497static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
498 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000499{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000500 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000501 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000502 size_t reclen = FUSE_DIRENT_SIZE(dirent);
503 int over;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000504 if (dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000505 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000506 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000507 break;
508
509 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000510 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000511 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000512 break;
513
Miklos Szeredib483c932001-10-29 14:57:57 +0000514 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000515 file->f_pos += reclen;
516 nbytes -= reclen;
517 }
518
Miklos Szeredib483c932001-10-29 14:57:57 +0000519 return 0;
520}
521
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000522static int fuse_checkdir(struct file *cfile, struct file *file)
523{
524 struct inode *inode;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000525 if (!cfile)
526 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000527 inode = cfile->f_dentry->d_inode;
528 if (!S_ISREG(inode->i_mode)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000529 fput(cfile);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000530 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000531 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000532
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000533 file->private_data = cfile;
534 return 0;
535}
536
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000537static int fuse_getdir(struct file *file)
538{
539 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000540 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000541 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000542 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000543 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000544
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000545 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000546 return -ERESTARTNOINTR;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000547
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000548 req->in.h.opcode = FUSE_GETDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000549 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000550 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000551 req->out.numargs = 1;
552 req->out.args[0].size = sizeof(struct fuse_getdir_out);
553 req->out.args[0].value = &outarg;
554 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000555 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000556 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000557 if (!err)
558 err = fuse_checkdir(outarg.file, file);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000559 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000560}
561
Miklos Szeredib483c932001-10-29 14:57:57 +0000562static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
563{
564 struct file *cfile = file->private_data;
565 char *buf;
566 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000567
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000568 if (!cfile) {
569 ret = fuse_getdir(file);
570 if (ret)
571 return ret;
572
573 cfile = file->private_data;
574 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000575
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000576 buf = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000577 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000578 return -ENOMEM;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000579
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000580 ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000581 if (ret > 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000582 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
583
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000584 free_page((unsigned long) buf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000585 return ret;
586}
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 Szeredie56818b2004-12-12 11:45:24 +0000596 return ERR_PTR(-ERESTARTNOINTR);
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 Szeredi05033042001-11-13 16:11:35 +0000618 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000619}
620
621static void free_link(char *link)
622{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000623 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000624 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000625}
626
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000627static int fuse_readlink(struct dentry *dentry, char __user *buffer,
628 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000629{
630 int ret;
631 char *link;
632
Miklos Szeredi05033042001-11-13 16:11:35 +0000633 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000634 ret = vfs_readlink(dentry, buffer, buflen, link);
635 free_link(link);
636 return ret;
637}
638
639static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
640{
641 int ret;
642 char *link;
643
Miklos Szeredi05033042001-11-13 16:11:35 +0000644 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000645 ret = vfs_follow_link(nd, link);
646 free_link(link);
647 return ret;
648}
649
650static int fuse_dir_open(struct inode *inode, struct file *file)
651{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000652 file->private_data = NULL;
653 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000654}
655
656static int fuse_dir_release(struct inode *inode, struct file *file)
657{
658 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000659
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000660 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000661 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000662
663 return 0;
664}
665
Miklos Szeredi83a07442004-11-30 18:25:20 +0000666static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000668 unsigned ivalid = iattr->ia_valid;
669 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000670
Miklos Szeredi5e183482001-10-31 14:52:35 +0000671 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000672
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000673 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000674 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000675 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000677 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000678 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000679 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000680 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
681 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000682 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000683 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000684#ifdef KERNEL_2_6
685 fattr->atime = iattr->ia_atime.tv_sec;
686 fattr->mtime = iattr->ia_mtime.tv_sec;
687#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000688 fattr->atime = iattr->ia_atime;
689 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000690#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000691 }
692
693 return fvalid;
694}
695
696static int fuse_setattr(struct dentry *entry, struct iattr *attr)
697{
698 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000699 struct fuse_conn *fc = get_fuse_conn(inode);
700 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000701 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000702 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000703 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000704 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000705 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000706
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000707 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
708 err = inode_change_ok(inode, attr);
709 if (err)
710 return err;
711 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000712
Miklos Szeredi069c9502004-07-16 16:17:02 +0000713 if (attr->ia_valid & ATTR_SIZE) {
714 unsigned long limit;
715 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000716#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000717 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000718#else
719 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000720#endif
721 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000722 send_sig(SIGXFSZ, current, 0);
723 return -EFBIG;
724 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000725 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000726
727 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000728 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000729 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000730
Miklos Szeredi43696432001-11-18 19:15:05 +0000731 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000732 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000733 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000734 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000735 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000736 req->in.numargs = 1;
737 req->in.args[0].size = sizeof(inarg);
738 req->in.args[0].value = &inarg;
739 req->out.numargs = 1;
740 req->out.args[0].size = sizeof(outarg);
741 req->out.args[0].value = &outarg;
742 request_send(fc, req);
743 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000744 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000745 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000746 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
747 make_bad_inode(inode);
748 err = -EIO;
749 } else {
750 if (is_truncate) {
751 loff_t origsize = i_size_read(inode);
752 i_size_write(inode, outarg.attr.size);
753 if (origsize > outarg.attr.size)
754 vmtruncate(inode, outarg.attr.size);
755 }
756 fuse_change_attributes(inode, &outarg.attr);
757 fi->i_time = time_to_jiffies(outarg.attr_valid,
758 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000759 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000760 } else if (err == -EINTR)
761 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000762
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000763 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000764}
765
Miklos Szeredif85ab242004-01-07 12:16:45 +0000766#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000767static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
768 struct kstat *stat)
769{
770 struct inode *inode = entry->d_inode;
771 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000772 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000773 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000774
Miklos Szeredif85ab242004-01-07 12:16:45 +0000775 return err;
776}
777
778static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000779 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000780{
Miklos Szeredie815c032004-01-19 18:20:49 +0000781 struct inode *inode;
782 int err = fuse_lookup_iget(dir, entry, &inode);
783 if (err)
784 return ERR_PTR(err);
785 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000786}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000787#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000788static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
789{
790 struct inode *inode;
791 struct dentry *alias;
792
793 int err = fuse_lookup_iget(dir, entry, &inode);
794 if (err)
795 return ERR_PTR(err);
796
797 if (inode && S_ISDIR(inode->i_mode) &&
798 (alias = d_find_alias(inode)) != NULL) {
799 dput(alias);
800 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000801 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000802 }
803
804 d_add(entry, inode);
805 return NULL;
806}
807
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000808static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000809 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000810{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000811 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000812}
813
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000814static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
815{
816 return fuse_create(dir, entry, mode, NULL);
817}
818
819static int fuse_permission_2_4(struct inode *inode, int mask)
820{
821 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000822}
823#endif /* KERNEL_2_6 */
824
825#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000826#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000827static int fuse_setxattr(struct dentry *entry, const char *name,
828 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000829#else
830static int fuse_setxattr(struct dentry *entry, const char *name,
831 void *value, size_t size, int flags)
832#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000833{
834 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000835 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000836 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000837 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000838 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000839
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000840 if (size > FUSE_XATTR_SIZE_MAX)
841 return -E2BIG;
842
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000843 if (fc->no_setxattr)
844 return -EOPNOTSUPP;
845
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000846 req = fuse_get_request(fc);
847 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000848 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000849
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000850 memset(&inarg, 0, sizeof(inarg));
851 inarg.size = size;
852 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000853 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000854 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000855 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000856 req->in.numargs = 3;
857 req->in.args[0].size = sizeof(inarg);
858 req->in.args[0].value = &inarg;
859 req->in.args[1].size = strlen(name) + 1;
860 req->in.args[1].value = name;
861 req->in.args[2].size = size;
862 req->in.args[2].value = value;
863 request_send(fc, req);
864 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000865 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000866 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000867 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000868 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000869 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000870 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000871}
872
873static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
874 void *value, size_t size)
875{
876 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000877 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000878 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000879 struct fuse_getxattr_in inarg;
880 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000881 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000882
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000883 if (fc->no_getxattr)
884 return -EOPNOTSUPP;
885
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000886 req = fuse_get_request(fc);
887 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000888 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000889
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000890 memset(&inarg, 0, sizeof(inarg));
891 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000892 req->in.h.opcode = FUSE_GETXATTR;
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 = 2;
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;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000900 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000901 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000902 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000903 req->out.argvar = 1;
904 req->out.args[0].size = size;
905 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000906 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000907 req->out.args[0].size = sizeof(outarg);
908 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000909 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000910 request_send(fc, req);
911 ret = req->out.h.error;
912 if (!ret)
913 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000914 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000915 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000916 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000917 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000918 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000919 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000920 fuse_put_request(fc, req);
921 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000922}
923
924static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
925{
926 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000927 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000928 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000929 struct fuse_getxattr_in inarg;
930 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000931 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000932
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000933 if (fc->no_listxattr)
934 return -EOPNOTSUPP;
935
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000936 req = fuse_get_request(fc);
937 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000938 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000939
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000940 memset(&inarg, 0, sizeof(inarg));
941 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000943 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000944 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000945 req->in.numargs = 1;
946 req->in.args[0].size = sizeof(inarg);
947 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000948 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000949 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000950 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000951 req->out.argvar = 1;
952 req->out.args[0].size = size;
953 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000954 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 req->out.args[0].size = sizeof(outarg);
956 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000957 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000958 request_send(fc, req);
959 ret = req->out.h.error;
960 if (!ret)
961 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000962 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000963 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000964 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000965 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000966 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000967 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000968 fuse_put_request(fc, req);
969 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000970}
971
972static int fuse_removexattr(struct dentry *entry, const char *name)
973{
974 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000975 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000976 struct fuse_req *req;
977 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000978
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000979 if (fc->no_removexattr)
980 return -EOPNOTSUPP;
981
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000982 req = fuse_get_request(fc);
983 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000984 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000985
986 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000987 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000988 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000989 req->in.numargs = 1;
990 req->in.args[0].size = strlen(name) + 1;
991 req->in.args[0].value = name;
992 request_send(fc, req);
993 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000994 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000995 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000996 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000997 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000998 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000999 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001000}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001001#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001002
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001003static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001004 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001005 .mkdir = fuse_mkdir,
1006 .symlink = fuse_symlink,
1007 .unlink = fuse_unlink,
1008 .rmdir = fuse_rmdir,
1009 .rename = fuse_rename,
1010 .link = fuse_link,
1011 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001012#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001013 .create = fuse_create,
1014 .mknod = fuse_mknod,
1015 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001016 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001017#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001018 .create = fuse_create_2_4,
1019 .mknod = fuse_mknod_2_4,
1020 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001021 .revalidate = fuse_revalidate,
1022#endif
1023#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001024 .setxattr = fuse_setxattr,
1025 .getxattr = fuse_getxattr,
1026 .listxattr = fuse_listxattr,
1027 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001028#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001029};
1030
1031static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001032 .read = generic_read_dir,
1033 .readdir = fuse_readdir,
1034 .open = fuse_dir_open,
1035 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001036};
1037
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001038static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001039 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001040#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001041 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001042 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001043#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001044 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001045 .revalidate = fuse_revalidate,
1046#endif
1047#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001048 .setxattr = fuse_setxattr,
1049 .getxattr = fuse_getxattr,
1050 .listxattr = fuse_listxattr,
1051 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001052#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001053};
1054
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001055static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001056 .setattr = fuse_setattr,
1057 .readlink = fuse_readlink,
1058 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001059#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001060 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001061#else
1062 .revalidate = fuse_revalidate,
1063#endif
1064#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001065 .setxattr = fuse_setxattr,
1066 .getxattr = fuse_getxattr,
1067 .listxattr = fuse_listxattr,
1068 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001069#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001070};
1071
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001072void fuse_init_common(struct inode *inode)
1073{
1074 inode->i_op = &fuse_common_inode_operations;
1075}
1076
1077void fuse_init_dir(struct inode *inode)
1078{
1079 inode->i_op = &fuse_dir_inode_operations;
1080 inode->i_fop = &fuse_dir_operations;
1081}
1082
1083void fuse_init_symlink(struct inode *inode)
1084{
1085 inode->i_op = &fuse_symlink_inode_operations;
1086}