blob: f363a179d8a40c4f718dc815909db56bdcbfe86e [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
Miklos Szeredi149f6072005-01-10 12:29:28 +00003 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredie56818b2004-12-12 11:45:24 +00005 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
9#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000012#include <linux/file.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000013#ifdef KERNEL_2_6
14#include <linux/gfp.h>
15#else
16#include <linux/mm.h>
17#endif
18#include <linux/sched.h>
Miklos Szeredi81394522005-01-11 14:24:18 +000019#ifdef KERNEL_2_6_7_PLUS
20#include <linux/namei.h>
21#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000022
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000023static inline unsigned long time_to_jiffies(unsigned long sec,
24 unsigned long nsec)
25{
Miklos Szeredi81394522005-01-11 14:24:18 +000026 struct timespec ts = {sec, nsec};
27 return jiffies + timespec_to_jiffies(&ts);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +000028}
29
Miklos Szeredi0f62d722005-01-04 12:45:54 +000030static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
31 struct dentry *entry,
32 struct fuse_entry_out *outarg)
33{
34 req->in.h.opcode = FUSE_LOOKUP;
35 req->in.h.nodeid = get_node_id(dir);
36 req->inode = dir;
37 req->in.numargs = 1;
38 req->in.args[0].size = entry->d_name.len + 1;
39 req->in.args[0].value = entry->d_name.name;
40 req->out.numargs = 1;
41 req->out.args[0].size = sizeof(struct fuse_entry_out);
42 req->out.args[0].value = outarg;
43}
44
45static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
46{
47 if (!entry->d_inode || is_bad_inode(entry->d_inode))
48 return 0;
Miklos Szeredi81394522005-01-11 14:24:18 +000049 else if (time_after(jiffies, entry->d_time)) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +000050 int err;
51 int version;
52 struct fuse_entry_out outarg;
53 struct inode *inode = entry->d_inode;
54 struct fuse_inode *fi = get_fuse_inode(inode);
55 struct fuse_conn *fc = get_fuse_conn(inode);
56 struct fuse_req *req = fuse_get_request_nonint(fc);
57 if (!req)
58 return 0;
59
60 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
61 request_send_nonint(fc, req);
62 version = req->out.h.unique;
63 err = req->out.h.error;
64 fuse_put_request(fc, req);
65 if (err || outarg.nodeid != get_node_id(inode) ||
66 (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
67 return 0;
68
69 fuse_change_attributes(inode, &outarg.attr);
70 inode->i_version = version;
71 entry->d_time = time_to_jiffies(outarg.entry_valid,
72 outarg.entry_valid_nsec);
73 fi->i_time = time_to_jiffies(outarg.attr_valid,
74 outarg.attr_valid_nsec);
75 }
76 return 1;
77}
78#ifndef KERNEL_2_6
79static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
80{
81 return fuse_dentry_revalidate(entry, NULL);
82}
83#endif
84
85static struct dentry_operations fuse_dentry_operations = {
86#ifdef KERNEL_2_6
87 .d_revalidate = fuse_dentry_revalidate,
88#else
89 .d_revalidate = fuse_dentry_revalidate_2_4,
90#endif
91};
92
Miklos Szeredie815c032004-01-19 18:20:49 +000093static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
94 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +000095{
Miklos Szeredie815c032004-01-19 18:20:49 +000096 int err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +000097 int version;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +000098 struct fuse_entry_out outarg;
Miklos Szeredie815c032004-01-19 18:20:49 +000099 struct inode *inode = NULL;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000100 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000101 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000102
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000103 if (entry->d_name.len > FUSE_NAME_MAX)
104 return -ENAMETOOLONG;
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000105
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000106 req = fuse_get_request(fc);
107 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000108 return -ERESTARTNOINTR;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000109
Miklos Szeredie56818b2004-12-12 11:45:24 +0000110 fuse_lookup_init(req, dir, entry, &outarg);
111 request_send(fc, req);
112 version = req->out.h.unique;
113 err = req->out.h.error;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000114 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000115 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000116 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000117 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000118 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000119 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000120 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000121 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000122 fuse_put_request(fc, req);
123 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000124 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000125
Miklos Szeredi069c9502004-07-16 16:17:02 +0000126 if (inode) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000127 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000128 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000129 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000130 fi->i_time = time_to_jiffies(outarg.attr_valid,
131 outarg.attr_valid_nsec);
132 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000133
Miklos Szeredi307242f2004-01-26 11:28:44 +0000134 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000135 *inodep = inode;
136 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000137}
138
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000139void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000140{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000141 get_fuse_inode(inode)->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000142}
143
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000144static void fuse_invalidate_entry(struct dentry *entry)
145{
146 d_invalidate(entry);
147 entry->d_time = jiffies - 1;
148}
149
150static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000151 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000152 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000153{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000154 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000155 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000156 struct fuse_inode *fi;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000157 int version;
158 int err;
159
160 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000161 req->inode = dir;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000162 req->out.numargs = 1;
163 req->out.args[0].size = sizeof(outarg);
164 req->out.args[0].value = &outarg;
165 request_send(fc, req);
166 version = req->out.h.unique;
167 err = req->out.h.error;
168 if (err) {
169 fuse_put_request(fc, req);
170 return err;
171 }
172 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
173 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000174 if (!inode) {
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000175 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000176 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000177 }
178 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000179
180 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000181 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000182 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000183 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000184 }
185
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000186 entry->d_time = time_to_jiffies(outarg.entry_valid,
187 outarg.entry_valid_nsec);
Miklos Szerediad051c32004-07-02 09:22:50 +0000188
Miklos Szeredi039322d2004-12-01 18:39:12 +0000189 fi = get_fuse_inode(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000190 fi->i_time = time_to_jiffies(outarg.attr_valid,
191 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000192
Miklos Szeredi76f65782004-02-19 16:55:40 +0000193 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000194 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000195 return 0;
196}
197
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000198static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000199 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000200{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000201 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000202 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000203 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000204 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000205 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000206
207 memset(&inarg, 0, sizeof(inarg));
208 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000209 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000210 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000211 req->in.numargs = 2;
212 req->in.args[0].size = sizeof(inarg);
213 req->in.args[0].value = &inarg;
214 req->in.args[1].size = entry->d_name.len + 1;
215 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000216 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000217}
218
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000219static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
220 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000221{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000222 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000223}
224
Miklos Szeredib483c932001-10-29 14:57:57 +0000225static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
226{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000227 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000228 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000229 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000230 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000231 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000232
233 memset(&inarg, 0, sizeof(inarg));
234 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000235 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000236 req->in.numargs = 2;
237 req->in.args[0].size = sizeof(inarg);
238 req->in.args[0].value = &inarg;
239 req->in.args[1].size = entry->d_name.len + 1;
240 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000241 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000242}
243
244static int fuse_symlink(struct inode *dir, struct dentry *entry,
245 const char *link)
246{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000247 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000248 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000249 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000250
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000251 if (len > FUSE_SYMLINK_MAX)
252 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000253
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000254 req = fuse_get_request(fc);
255 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000256 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000257
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000258 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000259 req->in.numargs = 2;
260 req->in.args[0].size = entry->d_name.len + 1;
261 req->in.args[0].value = entry->d_name.name;
262 req->in.args[1].size = len;
263 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000264 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000265}
266
Miklos Szeredib5958612004-02-20 14:10:49 +0000267static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000268{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000269 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000270 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000271 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000272 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000273 return -ERESTARTNOINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000274
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000275 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000276 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000277 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000278 req->in.numargs = 1;
279 req->in.args[0].size = entry->d_name.len + 1;
280 req->in.args[0].value = entry->d_name.name;
281 request_send(fc, req);
282 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000283 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000284 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000285 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000286
Miklos Szeredib5958612004-02-20 14:10:49 +0000287 /* Set nlink to zero so the inode can be cleared, if
288 the inode does have more links this will be
289 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000290 inode->i_nlink = 0;
291 fuse_invalidate_attr(inode);
292 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000293 } else if (err == -EINTR)
294 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000295 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000296}
297
298static int fuse_rmdir(struct inode *dir, struct dentry *entry)
299{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000300 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000301 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000302 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000303 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000304 return -ERESTARTNOINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000305
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000307 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000308 req->inode = dir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000309 req->in.numargs = 1;
310 req->in.args[0].size = entry->d_name.len + 1;
311 req->in.args[0].value = entry->d_name.name;
312 request_send(fc, req);
313 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000314 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000315 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000316 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000317 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000318 } else if (err == -EINTR)
319 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000320 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000321}
322
323static int fuse_rename(struct inode *olddir, struct dentry *oldent,
324 struct inode *newdir, struct dentry *newent)
325{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000326 int err;
327 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000328 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000329 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000330 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000331 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332
Miklos Szeredi43696432001-11-18 19:15:05 +0000333 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000334 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000336 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000337 req->inode = olddir;
338 req->inode2 = newdir;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000339 req->in.numargs = 3;
340 req->in.args[0].size = sizeof(inarg);
341 req->in.args[0].value = &inarg;
342 req->in.args[1].size = oldent->d_name.len + 1;
343 req->in.args[1].value = oldent->d_name.name;
344 req->in.args[2].size = newent->d_name.len + 1;
345 req->in.args[2].value = newent->d_name.name;
346 request_send(fc, req);
347 err = req->out.h.error;
348 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000349 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000350 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000351 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000352 fuse_invalidate_attr(newdir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000353 } else if (err == -EINTR) {
354 /* If request was interrupted, DEITY only knows if the
355 rename actually took place. If the invalidation
356 fails (e.g. some process has CWD under the renamed
357 directory), then there can be inconsistency between
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000358 the dcache and the real filesystem. Tough luck. */
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000359 fuse_invalidate_entry(oldent);
360 if (newent->d_inode)
361 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000362 }
Miklos Szeredicdae16e2005-01-14 11:43:22 +0000363
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000364 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000365}
366
367static int fuse_link(struct dentry *entry, struct inode *newdir,
368 struct dentry *newent)
369{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000370 int err;
371 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000372 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000373 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000374 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000375 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000376 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000377
Miklos Szeredi43696432001-11-18 19:15:05 +0000378 memset(&inarg, 0, sizeof(inarg));
Miklos 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 Szeredi0f62d722005-01-04 12:45:54 +0000509 if (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 Szeredi83a07442004-11-30 18:25:20 +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 file->f_pos += reclen;
521 nbytes -= reclen;
522 }
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 Szeredi81394522005-01-11 14:24:18 +0000602#ifdef KERNEL_2_6_7_PLUS
603static 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 Szeredi83a07442004-11-30 18:25:20 +0000648static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000649{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000650 unsigned ivalid = iattr->ia_valid;
651 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000652
Miklos Szeredi5e183482001-10-31 14:52:35 +0000653 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000654
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000655 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000656 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000657 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000658 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000659 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000660 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000661 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000662 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
663 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000664 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000665 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000666#ifdef KERNEL_2_6
667 fattr->atime = iattr->ia_atime.tv_sec;
668 fattr->mtime = iattr->ia_mtime.tv_sec;
669#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000670 fattr->atime = iattr->ia_atime;
671 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000672#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000673 }
674
675 return fvalid;
676}
677
678static int fuse_setattr(struct dentry *entry, struct iattr *attr)
679{
680 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000681 struct fuse_conn *fc = get_fuse_conn(inode);
682 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000683 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000684 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000685 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000686 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000687 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000688
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000689 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
690 err = inode_change_ok(inode, attr);
691 if (err)
692 return err;
693 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000694
Miklos Szeredi069c9502004-07-16 16:17:02 +0000695 if (attr->ia_valid & ATTR_SIZE) {
696 unsigned long limit;
697 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000698#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000699 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000700#else
701 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000702#endif
703 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000704 send_sig(SIGXFSZ, current, 0);
705 return -EFBIG;
706 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000707 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000708
709 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000710 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000711 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000712
Miklos Szeredi43696432001-11-18 19:15:05 +0000713 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000714 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000715 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000716 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000717 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000718 req->in.numargs = 1;
719 req->in.args[0].size = sizeof(inarg);
720 req->in.args[0].value = &inarg;
721 req->out.numargs = 1;
722 req->out.args[0].size = sizeof(outarg);
723 req->out.args[0].value = &outarg;
724 request_send(fc, req);
725 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000726 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000727 if (!err) {
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000728 if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000729#ifndef FUSE_MAINLINE
Miklos Szeredidbe0f652005-01-15 14:32:56 +0000730 if (get_node_id(inode) != FUSE_ROOT_ID)
731 make_bad_inode(inode);
Miklos Szeredie22acbe2005-01-20 08:37:30 +0000732#else
733 make_bad_inode(inode);
734#endif
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000735 err = -EIO;
736 } else {
737 if (is_truncate) {
738 loff_t origsize = i_size_read(inode);
739 i_size_write(inode, outarg.attr.size);
740 if (origsize > outarg.attr.size)
741 vmtruncate(inode, outarg.attr.size);
742 }
743 fuse_change_attributes(inode, &outarg.attr);
744 fi->i_time = time_to_jiffies(outarg.attr_valid,
745 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000746 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000747 } else if (err == -EINTR)
748 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000749
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000750 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000751}
752
Miklos Szeredif85ab242004-01-07 12:16:45 +0000753#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000754static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
755 struct kstat *stat)
756{
757 struct inode *inode = entry->d_inode;
758 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000759 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000760 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000761
Miklos Szeredif85ab242004-01-07 12:16:45 +0000762 return err;
763}
764
765static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000766 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000767{
Miklos Szeredie815c032004-01-19 18:20:49 +0000768 struct inode *inode;
769 int err = fuse_lookup_iget(dir, entry, &inode);
770 if (err)
771 return ERR_PTR(err);
772 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000773}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000774#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000775static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
776{
777 struct inode *inode;
778 struct dentry *alias;
779
780 int err = fuse_lookup_iget(dir, entry, &inode);
781 if (err)
782 return ERR_PTR(err);
783
784 if (inode && S_ISDIR(inode->i_mode) &&
785 (alias = d_find_alias(inode)) != NULL) {
786 dput(alias);
787 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000788 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000789 }
790
791 d_add(entry, inode);
792 return NULL;
793}
794
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000795static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000796 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000797{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000798 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000799}
800
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000801static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
802{
803 return fuse_create(dir, entry, mode, NULL);
804}
805
806static int fuse_permission_2_4(struct inode *inode, int mask)
807{
808 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000809}
810#endif /* KERNEL_2_6 */
811
812#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000813#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000814static int fuse_setxattr(struct dentry *entry, const char *name,
815 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000816#else
817static int fuse_setxattr(struct dentry *entry, const char *name,
818 void *value, size_t size, int flags)
819#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000820{
821 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000822 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000823 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000824 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000825 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000826
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000827 if (size > FUSE_XATTR_SIZE_MAX)
828 return -E2BIG;
829
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000830 if (fc->no_setxattr)
831 return -EOPNOTSUPP;
832
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000833 req = fuse_get_request(fc);
834 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000835 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000836
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000837 memset(&inarg, 0, sizeof(inarg));
838 inarg.size = size;
839 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000840 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000841 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000842 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000843 req->in.numargs = 3;
844 req->in.args[0].size = sizeof(inarg);
845 req->in.args[0].value = &inarg;
846 req->in.args[1].size = strlen(name) + 1;
847 req->in.args[1].value = name;
848 req->in.args[2].size = size;
849 req->in.args[2].value = value;
850 request_send(fc, req);
851 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000852 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000853 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000854 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000855 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000856 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000857 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000858}
859
860static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
861 void *value, size_t size)
862{
863 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000864 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000865 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000866 struct fuse_getxattr_in inarg;
867 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000868 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000869
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000870 if (fc->no_getxattr)
871 return -EOPNOTSUPP;
872
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000873 req = fuse_get_request(fc);
874 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000875 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000876
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000877 memset(&inarg, 0, sizeof(inarg));
878 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000879 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000880 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000881 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000882 req->in.numargs = 2;
883 req->in.args[0].size = sizeof(inarg);
884 req->in.args[0].value = &inarg;
885 req->in.args[1].size = strlen(name) + 1;
886 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000887 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000888 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000889 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000890 req->out.argvar = 1;
891 req->out.args[0].size = size;
892 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000893 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000894 req->out.args[0].size = sizeof(outarg);
895 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000896 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000897 request_send(fc, req);
898 ret = req->out.h.error;
899 if (!ret)
900 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000901 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000903 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000904 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000905 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000906 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000907 fuse_put_request(fc, req);
908 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000909}
910
911static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
912{
913 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000914 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000915 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000916 struct fuse_getxattr_in inarg;
917 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000918 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000919
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000920 if (fc->no_listxattr)
921 return -EOPNOTSUPP;
922
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000923 req = fuse_get_request(fc);
924 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000925 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000926
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000927 memset(&inarg, 0, sizeof(inarg));
928 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000929 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000930 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000931 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000932 req->in.numargs = 1;
933 req->in.args[0].size = sizeof(inarg);
934 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000935 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000936 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000937 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000938 req->out.argvar = 1;
939 req->out.args[0].size = size;
940 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000941 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 req->out.args[0].size = sizeof(outarg);
943 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000944 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000945 request_send(fc, req);
946 ret = req->out.h.error;
947 if (!ret)
948 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000949 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000950 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000951 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000952 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000953 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000954 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 fuse_put_request(fc, req);
956 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000957}
958
959static int fuse_removexattr(struct dentry *entry, const char *name)
960{
961 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000962 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000963 struct fuse_req *req;
964 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000965
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000966 if (fc->no_removexattr)
967 return -EOPNOTSUPP;
968
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000969 req = fuse_get_request(fc);
970 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000971 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000972
973 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000974 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi0f62d722005-01-04 12:45:54 +0000975 req->inode = inode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000976 req->in.numargs = 1;
977 req->in.args[0].size = strlen(name) + 1;
978 req->in.args[0].value = name;
979 request_send(fc, req);
980 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000981 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000982 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000983 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000984 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000985 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000986 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000987}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000988#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +0000989
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000990static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000991 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +0000992 .mkdir = fuse_mkdir,
993 .symlink = fuse_symlink,
994 .unlink = fuse_unlink,
995 .rmdir = fuse_rmdir,
996 .rename = fuse_rename,
997 .link = fuse_link,
998 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000999#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001000 .create = fuse_create,
1001 .mknod = fuse_mknod,
1002 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001003 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001004#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001005 .create = fuse_create_2_4,
1006 .mknod = fuse_mknod_2_4,
1007 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001008 .revalidate = fuse_revalidate,
1009#endif
1010#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001011 .setxattr = fuse_setxattr,
1012 .getxattr = fuse_getxattr,
1013 .listxattr = fuse_listxattr,
1014 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001015#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001016};
1017
1018static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001019 .read = generic_read_dir,
1020 .readdir = fuse_readdir,
1021 .open = fuse_dir_open,
1022 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001023};
1024
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001025static struct inode_operations fuse_common_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001026 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001027#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001028 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001029 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001030#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001031 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001032 .revalidate = fuse_revalidate,
1033#endif
1034#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001035 .setxattr = fuse_setxattr,
1036 .getxattr = fuse_getxattr,
1037 .listxattr = fuse_listxattr,
1038 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001039#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001040};
1041
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001042static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001043 .setattr = fuse_setattr,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001044 .follow_link = fuse_follow_link,
Miklos Szeredi81394522005-01-11 14:24:18 +00001045#ifdef KERNEL_2_6_7_PLUS
1046 .put_link = fuse_put_link,
1047 .readlink = generic_readlink,
1048#else
1049 .readlink = fuse_readlink,
1050#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001051#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001052 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001053#else
1054 .revalidate = fuse_revalidate,
1055#endif
1056#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001057 .setxattr = fuse_setxattr,
1058 .getxattr = fuse_getxattr,
1059 .listxattr = fuse_listxattr,
1060 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001061#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001062};
1063
Miklos Szeredi0f62d722005-01-04 12:45:54 +00001064void fuse_init_common(struct inode *inode)
1065{
1066 inode->i_op = &fuse_common_inode_operations;
1067}
1068
1069void fuse_init_dir(struct inode *inode)
1070{
1071 inode->i_op = &fuse_dir_inode_operations;
1072 inode->i_fop = &fuse_dir_operations;
1073}
1074
1075void fuse_init_symlink(struct inode *inode)
1076{
1077 inode->i_op = &fuse_symlink_inode_operations;
1078}