blob: 093bbb9fe59689d0e4052407208cff7d297778b3 [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 Szeredi7a983952005-01-28 09:58:19 +000019#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +000020#include <linux/namei.h>
21#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000023static inline unsigned long time_to_jiffies(unsigned long sec,
24 unsigned long nsec)
25{
Miklos Szeredi81394522005-01-11 14:24:18 +000026 struct timespec ts = {sec, nsec};
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 Szeredied6b5dd2005-01-26 17:07:59 +0000379 inarg.oldnodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 req->in.h.opcode = FUSE_LINK;
Miklos Szeredied6b5dd2005-01-26 17:07:59 +0000381 req->inode2 = inode;
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 Szeredie22acbe2005-01-20 08:37:30 +0000419#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000420 if (get_node_id(inode) != FUSE_ROOT_ID)
421 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000422#else
423 make_bad_inode(inode);
424#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000425 err = -EIO;
426 } else {
427 struct fuse_inode *fi = get_fuse_inode(inode);
428 fuse_change_attributes(inode, &arg.attr);
429 fi->i_time = time_to_jiffies(arg.attr_valid,
430 arg.attr_valid_nsec);
431 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000432 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000433 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434}
435
Miklos Szeredife25def2001-12-20 15:38:05 +0000436static int fuse_revalidate(struct dentry *entry)
437{
438 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000439 struct fuse_inode *fi = get_fuse_inode(inode);
440 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000441
Miklos Szeredi039322d2004-12-01 18:39:12 +0000442 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000443 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000444 current->fsuid != fc->user_id &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000445 (!(fc->flags & FUSE_ALLOW_ROOT) ||
Miklos Szeredi9ed69ba2005-01-13 12:11:49 +0000446 !capable(CAP_DAC_OVERRIDE)))
Miklos Szeredife25def2001-12-20 15:38:05 +0000447 return -EACCES;
Miklos Szeredi81394522005-01-11 14:24:18 +0000448 } else if (time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000449 return 0;
450
Miklos Szeredif85ab242004-01-07 12:16:45 +0000451 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000452}
453
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000454static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000455{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000456 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000457
Miklos Szeredi3c7d41b2005-01-09 20:05:27 +0000458 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->user_id &&
Miklos Szeredi9ed69ba2005-01-13 12:11:49 +0000459 (!(fc->flags & FUSE_ALLOW_ROOT) || !capable(CAP_DAC_OVERRIDE)))
Miklos Szeredife25def2001-12-20 15:38:05 +0000460 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000461 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000462#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000463 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000464#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000465 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000466#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000467
468 /* If permission is denied, try to refresh file
469 attributes. This is also needed, because the root
470 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000471 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000472 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000473 if (!err)
474#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000475 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000476#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000477 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000478#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000479 }
480
481 /* FIXME: Need some mechanism to revoke permissions:
482 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000483 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000484 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000485
Miklos Szeredife25def2001-12-20 15:38:05 +0000486 This is actually not so grave, since the user can
487 simply keep access to the file/directory anyway by
488 keeping it open... */
489
490 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000491 } else {
492 int mode = inode->i_mode;
493 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
494 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
495 return -EROFS;
496 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
497 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000498 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000499 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000500}
501
Miklos Szeredib483c932001-10-29 14:57:57 +0000502static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
503 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000504{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000505 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000506 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000507 size_t reclen = FUSE_DIRENT_SIZE(dirent);
508 int over;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000509 if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000510 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000511 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000512 break;
513
514 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi18fce982005-04-01 21:07:35 +0000515 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000516 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000517 break;
518
Miklos Szeredib483c932001-10-29 14:57:57 +0000519 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000520 nbytes -= reclen;
Miklos Szeredi18fce982005-04-01 21:07:35 +0000521 file->f_pos = dirent->off;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000522 }
523
Miklos Szeredib483c932001-10-29 14:57:57 +0000524 return 0;
525}
526
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000527static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
528 struct inode *inode, loff_t pos,
529 size_t count)
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000530{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000531 return fuse_send_read_common(req, file, inode, pos, count, 1);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000532}
533
Miklos Szeredib483c932001-10-29 14:57:57 +0000534static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
535{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000536 int err;
537 size_t nbytes;
538 struct page *page;
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000539 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000540 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000541 struct fuse_req *req = fuse_get_request_nonint(fc);
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000542 if (!req)
Miklos Szeredi3ead28e2005-01-18 21:23:41 +0000543 return -EINTR;
Miklos Szeredie815c032004-01-19 18:20:49 +0000544
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000545 page = alloc_page(GFP_KERNEL);
546 if (!page) {
547 fuse_put_request(fc, req);
Miklos Szeredib483c932001-10-29 14:57:57 +0000548 return -ENOMEM;
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000549 }
550 req->num_pages = 1;
551 req->pages[0] = page;
552 nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
553 err = req->out.h.error;
554 fuse_put_request(fc, req);
555 if (!err)
556 err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
557 filldir);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000558
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000559 __free_page(page);
560 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000561}
562
Miklos Szeredi05033042001-11-13 16:11:35 +0000563static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000564{
565 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000566 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000567 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000568 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000569
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000570 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000571 return ERR_PTR(-ERESTARTNOINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000572
Miklos Szeredi05033042001-11-13 16:11:35 +0000573 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000574 if (!link) {
575 link = ERR_PTR(-ENOMEM);
576 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000577 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000578 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000579 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000580 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000581 req->out.argvar = 1;
582 req->out.numargs = 1;
583 req->out.args[0].size = PAGE_SIZE - 1;
584 req->out.args[0].value = link;
585 request_send(fc, req);
586 if (req->out.h.error) {
587 free_page((unsigned long) link);
588 link = ERR_PTR(req->out.h.error);
589 } else
590 link[req->out.args[0].size] = '\0';
591 out:
592 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000593 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000594}
595
596static void free_link(char *link)
597{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000598 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000599 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000600}
601
Miklos Szeredi7a983952005-01-28 09:58:19 +0000602#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +0000603static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
604{
605 nd_set_link(nd, read_link(dentry));
606 return 0;
607}
608
609static void fuse_put_link(struct dentry *dentry, struct nameidata *nd)
610{
611 free_link(nd_get_link(nd));
612}
613#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000614static int fuse_readlink(struct dentry *dentry, char __user *buffer,
615 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000616{
617 int ret;
618 char *link;
619
Miklos Szeredi05033042001-11-13 16:11:35 +0000620 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000621 ret = vfs_readlink(dentry, buffer, buflen, link);
622 free_link(link);
623 return ret;
624}
625
626static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
627{
628 int ret;
629 char *link;
630
Miklos Szeredi05033042001-11-13 16:11:35 +0000631 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000632 ret = vfs_follow_link(nd, link);
633 free_link(link);
634 return ret;
635}
Miklos Szeredi81394522005-01-11 14:24:18 +0000636#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000637
638static int fuse_dir_open(struct inode *inode, struct file *file)
639{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000640 return fuse_open_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000641}
642
643static int fuse_dir_release(struct inode *inode, struct file *file)
644{
Miklos Szeredi1adb2272005-01-18 21:19:58 +0000645 return fuse_release_common(inode, file, 1);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000646}
647
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000648static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
649{
650 return fuse_fsync_common(file, de, datasync, 1);
651}
652
Miklos Szeredi83a07442004-11-30 18:25:20 +0000653static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000654{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000655 unsigned ivalid = iattr->ia_valid;
656 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000657
Miklos Szeredi5e183482001-10-31 14:52:35 +0000658 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000659
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000660 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000661 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000662 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000663 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000664 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000665 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000666 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000667 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
668 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000669 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000670 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000671#ifdef KERNEL_2_6
672 fattr->atime = iattr->ia_atime.tv_sec;
673 fattr->mtime = iattr->ia_mtime.tv_sec;
674#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000675 fattr->atime = iattr->ia_atime;
676 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000677#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000678 }
679
680 return fvalid;
681}
682
683static int fuse_setattr(struct dentry *entry, struct iattr *attr)
684{
685 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000686 struct fuse_conn *fc = get_fuse_conn(inode);
687 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000688 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000689 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000690 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000691 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000692 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000693
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000694 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
695 err = inode_change_ok(inode, attr);
696 if (err)
697 return err;
698 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000699
Miklos Szeredi069c9502004-07-16 16:17:02 +0000700 if (attr->ia_valid & ATTR_SIZE) {
701 unsigned long limit;
702 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000703#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000704 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000705#else
706 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000707#endif
708 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000709 send_sig(SIGXFSZ, current, 0);
710 return -EFBIG;
711 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000712 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000713
714 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000715 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000716 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000717
Miklos Szeredi43696432001-11-18 19:15:05 +0000718 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000719 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000720 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000721 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000722 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000723 req->in.numargs = 1;
724 req->in.args[0].size = sizeof(inarg);
725 req->in.args[0].value = &inarg;
726 req->out.numargs = 1;
727 req->out.args[0].size = sizeof(outarg);
728 req->out.args[0].value = &outarg;
729 request_send(fc, req);
730 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000731 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000732 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000733 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000734#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000735 if (get_node_id(inode) != FUSE_ROOT_ID)
736 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000737#else
738 make_bad_inode(inode);
739#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000740 err = -EIO;
741 } else {
742 if (is_truncate) {
743 loff_t origsize = i_size_read(inode);
744 i_size_write(inode, outarg.attr.size);
745 if (origsize > outarg.attr.size)
746 vmtruncate(inode, outarg.attr.size);
747 }
748 fuse_change_attributes(inode, &outarg.attr);
749 fi->i_time = time_to_jiffies(outarg.attr_valid,
750 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000751 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000752 } else if (err == -EINTR)
753 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000754
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000755 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000756}
757
Miklos Szeredif85ab242004-01-07 12:16:45 +0000758#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000759static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
760 struct kstat *stat)
761{
762 struct inode *inode = entry->d_inode;
763 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000764 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000765 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000766
Miklos Szeredif85ab242004-01-07 12:16:45 +0000767 return err;
768}
769
770static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000771 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000772{
Miklos Szeredie815c032004-01-19 18:20:49 +0000773 struct inode *inode;
774 int err = fuse_lookup_iget(dir, entry, &inode);
775 if (err)
776 return ERR_PTR(err);
777 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000778}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000779#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000780static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
781{
782 struct inode *inode;
783 struct dentry *alias;
784
785 int err = fuse_lookup_iget(dir, entry, &inode);
786 if (err)
787 return ERR_PTR(err);
788
789 if (inode && S_ISDIR(inode->i_mode) &&
790 (alias = d_find_alias(inode)) != NULL) {
791 dput(alias);
792 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000793 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000794 }
795
796 d_add(entry, inode);
797 return NULL;
798}
799
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000800static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000801 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000802{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000803 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000804}
805
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000806static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
807{
808 return fuse_create(dir, entry, mode, NULL);
809}
810
811static int fuse_permission_2_4(struct inode *inode, int mask)
812{
813 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000814}
815#endif /* KERNEL_2_6 */
816
817#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000818#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000819static int fuse_setxattr(struct dentry *entry, const char *name,
820 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000821#else
822static int fuse_setxattr(struct dentry *entry, const char *name,
823 void *value, size_t size, int flags)
824#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000825{
826 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000827 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000828 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000829 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000830 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000831
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000832 if (size > FUSE_XATTR_SIZE_MAX)
833 return -E2BIG;
834
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000835 if (fc->no_setxattr)
836 return -EOPNOTSUPP;
837
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000838 req = fuse_get_request(fc);
839 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000840 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000841
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000842 memset(&inarg, 0, sizeof(inarg));
843 inarg.size = size;
844 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000845 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000846 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000847 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000848 req->in.numargs = 3;
849 req->in.args[0].size = sizeof(inarg);
850 req->in.args[0].value = &inarg;
851 req->in.args[1].size = strlen(name) + 1;
852 req->in.args[1].value = name;
853 req->in.args[2].size = size;
854 req->in.args[2].value = value;
855 request_send(fc, req);
856 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000857 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000858 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000859 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000860 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000861 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000862 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000863}
864
865static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
866 void *value, size_t size)
867{
868 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000869 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000870 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000871 struct fuse_getxattr_in inarg;
872 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000873 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000874
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000875 if (fc->no_getxattr)
876 return -EOPNOTSUPP;
877
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000878 req = fuse_get_request(fc);
879 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000880 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000881
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000882 memset(&inarg, 0, sizeof(inarg));
883 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000884 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000885 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000886 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000887 req->in.numargs = 2;
888 req->in.args[0].size = sizeof(inarg);
889 req->in.args[0].value = &inarg;
890 req->in.args[1].size = strlen(name) + 1;
891 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000892 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000893 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000894 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 req->out.argvar = 1;
896 req->out.args[0].size = size;
897 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000898 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000899 req->out.args[0].size = sizeof(outarg);
900 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000901 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 request_send(fc, req);
903 ret = req->out.h.error;
904 if (!ret)
905 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000906 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000907 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000908 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000909 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000910 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000911 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000912 fuse_put_request(fc, req);
913 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000914}
915
916static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
917{
918 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000919 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000920 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000921 struct fuse_getxattr_in inarg;
922 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000923 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000924
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000925 if (fc->no_listxattr)
926 return -EOPNOTSUPP;
927
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000928 req = fuse_get_request(fc);
929 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000930 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000931
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000932 memset(&inarg, 0, sizeof(inarg));
933 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000934 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000935 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000936 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 req->in.numargs = 1;
938 req->in.args[0].size = sizeof(inarg);
939 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000940 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000941 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000942 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000943 req->out.argvar = 1;
944 req->out.args[0].size = size;
945 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000946 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000947 req->out.args[0].size = sizeof(outarg);
948 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000949 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000950 request_send(fc, req);
951 ret = req->out.h.error;
952 if (!ret)
953 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000954 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000956 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000957 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000958 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000959 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000960 fuse_put_request(fc, req);
961 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000962}
963
964static int fuse_removexattr(struct dentry *entry, const char *name)
965{
966 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000967 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000968 struct fuse_req *req;
969 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000970
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000971 if (fc->no_removexattr)
972 return -EOPNOTSUPP;
973
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000974 req = fuse_get_request(fc);
975 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000976 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000977
978 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000979 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000980 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000981 req->in.numargs = 1;
982 req->in.args[0].size = strlen(name) + 1;
983 req->in.args[0].value = name;
984 request_send(fc, req);
985 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000986 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000987 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000988 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000989 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000990 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000991 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000992}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000993#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +0000994
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000995static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000996 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000997 .mkdir = fuse_mkdir,
998 .symlink = fuse_symlink,
999 .unlink = fuse_unlink,
1000 .rmdir = fuse_rmdir,
1001 .rename = fuse_rename,
1002 .link = fuse_link,
1003 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001004#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001005 .create = fuse_create,
1006 .mknod = fuse_mknod,
1007 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001008 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001009#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001010 .create = fuse_create_2_4,
1011 .mknod = fuse_mknod_2_4,
1012 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001013 .revalidate = fuse_revalidate,
1014#endif
1015#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001016 .setxattr = fuse_setxattr,
1017 .getxattr = fuse_getxattr,
1018 .listxattr = fuse_listxattr,
1019 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001020#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001021};
1022
1023static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001024 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001025 .read = generic_read_dir,
1026 .readdir = fuse_readdir,
1027 .open = fuse_dir_open,
1028 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001029 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001030};
1031
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001032static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001033 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001034#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001035 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001036 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001037#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001038 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001039 .revalidate = fuse_revalidate,
1040#endif
1041#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001042 .setxattr = fuse_setxattr,
1043 .getxattr = fuse_getxattr,
1044 .listxattr = fuse_listxattr,
1045 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001046#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001047};
1048
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001049static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001050 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001051 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001052#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001053 .put_link = fuse_put_link,
1054 .readlink = generic_readlink,
1055#else
1056 .readlink = fuse_readlink,
1057#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001058#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001059 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001060#else
1061 .revalidate = fuse_revalidate,
1062#endif
1063#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001064 .setxattr = fuse_setxattr,
1065 .getxattr = fuse_getxattr,
1066 .listxattr = fuse_listxattr,
1067 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001068#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001069};
1070
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001071void fuse_init_common(struct inode *inode)
1072{
1073 inode->i_op = &fuse_common_inode_operations;
1074}
1075
1076void fuse_init_dir(struct inode *inode)
1077{
1078 inode->i_op = &fuse_dir_inode_operations;
1079 inode->i_fop = &fuse_dir_operations;
1080}
1081
1082void fuse_init_symlink(struct inode *inode)
1083{
1084 inode->i_op = &fuse_symlink_inode_operations;
1085}