blob: 6ae498cfd885cff2137dd7a46837ea56d5c4c1fc [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{
Miklos Szeredib7640d22005-04-08 15:15:28 +0000650 /* nfsd can call this with no file */
651 return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
Miklos Szeredi4283ee72005-03-21 12:09:04 +0000652}
653
Miklos Szeredi83a07442004-11-30 18:25:20 +0000654static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000655{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000656 unsigned ivalid = iattr->ia_valid;
657 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000658
Miklos Szeredi5e183482001-10-31 14:52:35 +0000659 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000660
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000661 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000662 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000663 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000664 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000665 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000666 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000667 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000668 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
669 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000670 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000671 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000672#ifdef KERNEL_2_6
673 fattr->atime = iattr->ia_atime.tv_sec;
674 fattr->mtime = iattr->ia_mtime.tv_sec;
675#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000676 fattr->atime = iattr->ia_atime;
677 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000678#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000679 }
680
681 return fvalid;
682}
683
684static int fuse_setattr(struct dentry *entry, struct iattr *attr)
685{
686 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000687 struct fuse_conn *fc = get_fuse_conn(inode);
688 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000689 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000690 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000691 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000692 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000693 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000694
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000695 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
696 err = inode_change_ok(inode, attr);
697 if (err)
698 return err;
699 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000700
Miklos Szeredi069c9502004-07-16 16:17:02 +0000701 if (attr->ia_valid & ATTR_SIZE) {
702 unsigned long limit;
703 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000704#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000705 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000706#else
707 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000708#endif
709 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000710 send_sig(SIGXFSZ, current, 0);
711 return -EFBIG;
712 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000713 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000714
715 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000716 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000717 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000718
Miklos Szeredi43696432001-11-18 19:15:05 +0000719 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000720 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000721 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000722 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000723 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000724 req->in.numargs = 1;
725 req->in.args[0].size = sizeof(inarg);
726 req->in.args[0].value = &inarg;
727 req->out.numargs = 1;
728 req->out.args[0].size = sizeof(outarg);
729 req->out.args[0].value = &outarg;
730 request_send(fc, req);
731 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000732 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000733 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000734 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000735#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000736 if (get_node_id(inode) != FUSE_ROOT_ID)
737 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000738#else
739 make_bad_inode(inode);
740#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000741 err = -EIO;
742 } else {
743 if (is_truncate) {
744 loff_t origsize = i_size_read(inode);
745 i_size_write(inode, outarg.attr.size);
746 if (origsize > outarg.attr.size)
747 vmtruncate(inode, outarg.attr.size);
748 }
749 fuse_change_attributes(inode, &outarg.attr);
750 fi->i_time = time_to_jiffies(outarg.attr_valid,
751 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000752 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000753 } else if (err == -EINTR)
754 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000755
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000756 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000757}
758
Miklos Szeredif85ab242004-01-07 12:16:45 +0000759#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000760static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
761 struct kstat *stat)
762{
763 struct inode *inode = entry->d_inode;
764 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000765 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000766 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000767
Miklos Szeredif85ab242004-01-07 12:16:45 +0000768 return err;
769}
770
771static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000772 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000773{
Miklos Szeredie815c032004-01-19 18:20:49 +0000774 struct inode *inode;
775 int err = fuse_lookup_iget(dir, entry, &inode);
776 if (err)
777 return ERR_PTR(err);
778 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000779}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000780#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000781static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
782{
783 struct inode *inode;
784 struct dentry *alias;
785
786 int err = fuse_lookup_iget(dir, entry, &inode);
787 if (err)
788 return ERR_PTR(err);
789
790 if (inode && S_ISDIR(inode->i_mode) &&
791 (alias = d_find_alias(inode)) != NULL) {
792 dput(alias);
793 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000794 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000795 }
796
797 d_add(entry, inode);
798 return NULL;
799}
800
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000801static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000802 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000803{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000804 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000805}
806
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000807static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
808{
809 return fuse_create(dir, entry, mode, NULL);
810}
811
812static int fuse_permission_2_4(struct inode *inode, int mask)
813{
814 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000815}
816#endif /* KERNEL_2_6 */
817
818#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000819#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000820static int fuse_setxattr(struct dentry *entry, const char *name,
821 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000822#else
823static int fuse_setxattr(struct dentry *entry, const char *name,
824 void *value, size_t size, int flags)
825#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000826{
827 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000828 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000829 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000830 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000831 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000832
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000833 if (size > FUSE_XATTR_SIZE_MAX)
834 return -E2BIG;
835
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000836 if (fc->no_setxattr)
837 return -EOPNOTSUPP;
838
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000839 req = fuse_get_request(fc);
840 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000841 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000842
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000843 memset(&inarg, 0, sizeof(inarg));
844 inarg.size = size;
845 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000846 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000847 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000848 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000849 req->in.numargs = 3;
850 req->in.args[0].size = sizeof(inarg);
851 req->in.args[0].value = &inarg;
852 req->in.args[1].size = strlen(name) + 1;
853 req->in.args[1].value = name;
854 req->in.args[2].size = size;
855 req->in.args[2].value = value;
856 request_send(fc, req);
857 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000858 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000859 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000860 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000861 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000862 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000863 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000864}
865
866static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
867 void *value, size_t size)
868{
869 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000870 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000871 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000872 struct fuse_getxattr_in inarg;
873 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000874 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000875
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000876 if (fc->no_getxattr)
877 return -EOPNOTSUPP;
878
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 req = fuse_get_request(fc);
880 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000881 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000882
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000883 memset(&inarg, 0, sizeof(inarg));
884 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000885 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000886 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000887 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000888 req->in.numargs = 2;
889 req->in.args[0].size = sizeof(inarg);
890 req->in.args[0].value = &inarg;
891 req->in.args[1].size = strlen(name) + 1;
892 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000893 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000894 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000895 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000896 req->out.argvar = 1;
897 req->out.args[0].size = size;
898 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000899 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000900 req->out.args[0].size = sizeof(outarg);
901 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000902 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000903 request_send(fc, req);
904 ret = req->out.h.error;
905 if (!ret)
906 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000907 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000908 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000909 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000910 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000911 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000912 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000913 fuse_put_request(fc, req);
914 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000915}
916
917static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
918{
919 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000920 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000921 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000922 struct fuse_getxattr_in inarg;
923 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000924 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000925
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000926 if (fc->no_listxattr)
927 return -EOPNOTSUPP;
928
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000929 req = fuse_get_request(fc);
930 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000931 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000932
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000933 memset(&inarg, 0, sizeof(inarg));
934 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000935 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000936 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000937 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000938 req->in.numargs = 1;
939 req->in.args[0].size = sizeof(inarg);
940 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000941 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000943 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000944 req->out.argvar = 1;
945 req->out.args[0].size = size;
946 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000947 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000948 req->out.args[0].size = sizeof(outarg);
949 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000950 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000951 request_send(fc, req);
952 ret = req->out.h.error;
953 if (!ret)
954 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000955 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000956 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000957 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000958 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000959 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000960 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000961 fuse_put_request(fc, req);
962 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000963}
964
965static int fuse_removexattr(struct dentry *entry, const char *name)
966{
967 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000968 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000969 struct fuse_req *req;
970 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000971
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000972 if (fc->no_removexattr)
973 return -EOPNOTSUPP;
974
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000975 req = fuse_get_request(fc);
976 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000977 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000978
979 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000980 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000981 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000982 req->in.numargs = 1;
983 req->in.args[0].size = strlen(name) + 1;
984 req->in.args[0].value = name;
985 request_send(fc, req);
986 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000987 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000988 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000989 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000990 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000991 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000992 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000993}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000994#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +0000995
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000996static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000997 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000998 .mkdir = fuse_mkdir,
999 .symlink = fuse_symlink,
1000 .unlink = fuse_unlink,
1001 .rmdir = fuse_rmdir,
1002 .rename = fuse_rename,
1003 .link = fuse_link,
1004 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001005#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001006 .create = fuse_create,
1007 .mknod = fuse_mknod,
1008 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001009 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001010#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001011 .create = fuse_create_2_4,
1012 .mknod = fuse_mknod_2_4,
1013 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001014 .revalidate = fuse_revalidate,
1015#endif
1016#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001017 .setxattr = fuse_setxattr,
1018 .getxattr = fuse_getxattr,
1019 .listxattr = fuse_listxattr,
1020 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001021#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001022};
1023
1024static struct file_operations fuse_dir_operations = {
Miklos Szeredif43f0632005-02-28 11:46:56 +00001025 .llseek = generic_file_llseek,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001026 .read = generic_read_dir,
1027 .readdir = fuse_readdir,
1028 .open = fuse_dir_open,
1029 .release = fuse_dir_release,
Miklos Szeredi4283ee72005-03-21 12:09:04 +00001030 .fsync = fuse_dir_fsync,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001031};
1032
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001033static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001034 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001035#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001036 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001037 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001038#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001039 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001040 .revalidate = fuse_revalidate,
1041#endif
1042#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001043 .setxattr = fuse_setxattr,
1044 .getxattr = fuse_getxattr,
1045 .listxattr = fuse_listxattr,
1046 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001047#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001048};
1049
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001050static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001051 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001052 .follow_link = fuse_follow_link,
Miklos Szeredi7a983952005-01-28 09:58:19 +00001053#ifdef KERNEL_2_6_8_PLUS
Miklos Szeredi81394522005-01-11 14:24:18 +00001054 .put_link = fuse_put_link,
1055 .readlink = generic_readlink,
1056#else
1057 .readlink = fuse_readlink,
1058#endif
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}