blob: 59cab49a9e34956e65b0231a08242da868b67b11 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000012#include <linux/slab.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000013#include <linux/file.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014
Miklos Szeredib483c932001-10-29 14:57:57 +000015static struct inode_operations fuse_dir_inode_operations;
16static struct inode_operations fuse_file_inode_operations;
17static struct inode_operations fuse_symlink_inode_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000018
19static struct file_operations fuse_dir_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000020
Miklos Szeredi307242f2004-01-26 11:28:44 +000021static struct dentry_operations fuse_dentry_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000022
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000023#ifndef KERNEL_2_6
24#define new_decode_dev(x) (x)
25#define new_encode_dev(x) (x)
26#endif
27
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000028static void change_attributes(struct inode *inode, struct fuse_attr *attr)
29{
Miklos Szeredic26c14d2004-04-09 17:48:32 +000030 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) {
Miklos Szeredif85ab242004-01-07 12:16:45 +000031#ifdef KERNEL_2_6
32 invalidate_inode_pages(inode->i_mapping);
33#else
Miklos Szeredia181e612001-11-06 12:03:23 +000034 invalidate_inode_pages(inode);
Miklos Szeredif85ab242004-01-07 12:16:45 +000035#endif
36 }
Miklos Szeredia181e612001-11-06 12:03:23 +000037
Miklos Szeredi5e183482001-10-31 14:52:35 +000038 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000039 inode->i_nlink = attr->nlink;
40 inode->i_uid = attr->uid;
41 inode->i_gid = attr->gid;
Miklos Szeredid1199f82004-02-06 15:29:22 +000042 i_size_write(inode, attr->size);
Miklos Szeredi05033042001-11-13 16:11:35 +000043 inode->i_blksize = PAGE_CACHE_SIZE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000044 inode->i_blocks = attr->blocks;
Miklos Szeredif85ab242004-01-07 12:16:45 +000045#ifdef KERNEL_2_6
46 inode->i_atime.tv_sec = attr->atime;
Miklos Szeredib5958612004-02-20 14:10:49 +000047 inode->i_atime.tv_nsec = attr->atimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000048 inode->i_mtime.tv_sec = attr->mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +000049 inode->i_mtime.tv_nsec = attr->mtimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000050 inode->i_ctime.tv_sec = attr->ctime;
Miklos Szeredib5958612004-02-20 14:10:49 +000051 inode->i_ctime.tv_nsec = attr->ctimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000052#else
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000053 inode->i_atime = attr->atime;
54 inode->i_mtime = attr->mtime;
55 inode->i_ctime = attr->ctime;
Miklos Szeredif85ab242004-01-07 12:16:45 +000056#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000057}
58
Miklos Szeredia181e612001-11-06 12:03:23 +000059static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000060{
Miklos Szeredia181e612001-11-06 12:03:23 +000061 inode->i_mode = attr->mode & S_IFMT;
Miklos Szeredid1199f82004-02-06 15:29:22 +000062 i_size_write(inode, attr->size);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000063 if (S_ISREG(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000064 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000065 fuse_init_file_inode(inode);
Miklos Szeredib483c932001-10-29 14:57:57 +000066 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000067 else if (S_ISDIR(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000068 inode->i_op = &fuse_dir_inode_operations;
69 inode->i_fop = &fuse_dir_operations;
70 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000071 else if (S_ISLNK(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000072 inode->i_op = &fuse_symlink_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000073 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000074 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
75 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)){
Miklos Szeredia181e612001-11-06 12:03:23 +000076 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000077 init_special_inode(inode, inode->i_mode,
78 new_decode_dev(attr->rdev));
Miklos Szeredi76f65782004-02-19 16:55:40 +000079 } else
80 printk("fuse_init_inode: bad file type: %o\n", inode->i_mode);
81
Miklos Szeredi5e183482001-10-31 14:52:35 +000082 inode->u.generic_ip = inode;
83}
84
Miklos Szeredi76f65782004-02-19 16:55:40 +000085struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
Miklos Szeredia181e612001-11-06 12:03:23 +000086 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +000087{
88 struct inode *inode;
89
90 inode = iget(sb, ino);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000091 if (inode) {
92 if (!inode->u.generic_ip) {
Miklos Szeredi76f65782004-02-19 16:55:40 +000093 inode->i_generation = generation;
Miklos Szeredia181e612001-11-06 12:03:23 +000094 fuse_init_inode(inode, attr);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000095 } else if (inode->i_generation != generation)
Miklos Szeredi76f65782004-02-19 16:55:40 +000096 printk("fuse_iget: bad generation for ino %lu\n", ino);
Miklos Szeredie815c032004-01-19 18:20:49 +000097
Miklos Szeredi5e183482001-10-31 14:52:35 +000098 change_attributes(inode, attr);
Miklos Szeredia181e612001-11-06 12:03:23 +000099 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000100 }
101
102 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000103}
104
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000105static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req,
106 struct inode *dir, struct dentry *entry,
107 struct fuse_entry_out *outarg, int *version)
108{
109 req->in.h.opcode = FUSE_LOOKUP;
110 req->in.h.ino = dir->i_ino;
111 req->in.numargs = 1;
112 req->in.args[0].size = entry->d_name.len + 1;
113 req->in.args[0].value = entry->d_name.name;
114 req->out.numargs = 1;
115 req->out.args[0].size = sizeof(struct fuse_entry_out);
116 req->out.args[0].value = outarg;
117 request_send(fc, req);
118 *version = req->out.h.unique;
119 return req->out.h.error;
120}
121
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000122static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000123 struct fuse_entry_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000124{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000125 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000126 struct fuse_req *req;
127 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000128
129 if (entry->d_name.len > FUSE_NAME_MAX)
130 return -ENAMETOOLONG;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000131 req = fuse_get_request(fc);
132 if (!req)
133 return -ERESTARTSYS;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000134
135 err = fuse_send_lookup(fc, req, dir, entry, outarg, version);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000136 fuse_put_request(fc, req);
137 return err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000138}
139
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000140static inline unsigned long time_to_jiffies(unsigned long sec,
141 unsigned long nsec)
142{
143 /* prevent wrapping of jiffies */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000144 if (sec + 1 >= LONG_MAX / HZ)
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000145 return 0;
146
147 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
148}
149
Miklos Szeredie815c032004-01-19 18:20:49 +0000150static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
151 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000152{
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000153 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredie815c032004-01-19 18:20:49 +0000154 int err;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000155 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000156 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000157 struct inode *inode = NULL;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000158 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000159
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000160 if (entry->d_name.len > FUSE_NAME_MAX)
161 return -ENAMETOOLONG;
162 req = fuse_get_request(fc);
163 if (!req)
164 return -ERESTARTSYS;
165
166 err = fuse_send_lookup(fc, req, dir, entry, &outarg, &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000167 if (!err) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000168 inode = fuse_iget(dir->i_sb, outarg.ino, outarg.generation,
169 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000170 if (!inode) {
171 fuse_send_forget(fc, req, outarg.ino, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000172 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000173 }
174 }
175 fuse_put_request(fc, req);
176 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000177 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000178
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000179 entry->d_time = time_to_jiffies(outarg.entry_valid,
180 outarg.entry_valid_nsec);
Miklos Szeredi307242f2004-01-26 11:28:44 +0000181 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000182 *inodep = inode;
183 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000184}
185
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000186static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
187 struct inode *dir, struct dentry *entry,
188 struct fuse_entry_out *outarg, int version,
189 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000190{
191 struct inode *inode;
192 inode = fuse_iget(dir->i_sb, outarg->ino, outarg->generation,
193 &outarg->attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000194 if (!inode) {
195 fuse_send_forget(fc, req, outarg->ino, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000196 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000197 }
198 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000199
200 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000201 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000202 iput(inode);
203 printk("fuse_mknod: inode has wrong type\n");
204 return -EINVAL;
205 }
206
207 d_instantiate(entry, inode);
208 return 0;
209}
210
211
Miklos Szeredif85ab242004-01-07 12:16:45 +0000212static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
213 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000214{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000215 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000216 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000217 struct fuse_mknod_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000218 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000219 int err;
220
221 if (!req)
222 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000223
224 memset(&inarg, 0, sizeof(inarg));
225 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000226 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000227 req->in.h.opcode = FUSE_MKNOD;
228 req->in.h.ino = dir->i_ino;
229 req->in.numargs = 2;
230 req->in.args[0].size = sizeof(inarg);
231 req->in.args[0].value = &inarg;
232 req->in.args[1].size = entry->d_name.len + 1;
233 req->in.args[1].value = entry->d_name.name;
234 req->out.numargs = 1;
235 req->out.args[0].size = sizeof(outarg);
236 req->out.args[0].value = &outarg;
237 request_send(fc, req);
238 err = req->out.h.error;
239 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000240 err = lookup_new_entry(fc, req, dir, entry, &outarg,
241 req->out.h.unique, mode);
242 else
243 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000244 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000245}
246
Miklos Szeredif85ab242004-01-07 12:16:45 +0000247static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000248{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000249 return _fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000250}
251
Miklos Szeredie815c032004-01-19 18:20:49 +0000252
Miklos Szeredib483c932001-10-29 14:57:57 +0000253static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
254{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000255 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000256 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000257 struct fuse_mkdir_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000258 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000259 int err;
260
261 if (!req)
262 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000263
264 memset(&inarg, 0, sizeof(inarg));
265 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000266 req->in.h.opcode = FUSE_MKDIR;
267 req->in.h.ino = dir->i_ino;
268 req->in.numargs = 2;
269 req->in.args[0].size = sizeof(inarg);
270 req->in.args[0].value = &inarg;
271 req->in.args[1].size = entry->d_name.len + 1;
272 req->in.args[1].value = entry->d_name.name;
273 req->out.numargs = 1;
274 req->out.args[0].size = sizeof(outarg);
275 req->out.args[0].value = &outarg;
276 request_send(fc, req);
277 err = req->out.h.error;
278 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000279 err = lookup_new_entry(fc, req, dir, entry, &outarg,
280 req->out.h.unique, S_IFDIR);
281 else
282 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000283 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000284}
285
286static int fuse_symlink(struct inode *dir, struct dentry *entry,
287 const char *link)
288{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000289 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000290 struct fuse_req *req;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000291 struct fuse_entry_out outarg;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000292 unsigned int len = strlen(link) + 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000293 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000294
295 if (len > FUSE_SYMLINK_MAX)
296 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000297
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000298 req = fuse_get_request(fc);
299 if (!req)
300 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000301
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000302 req->in.h.opcode = FUSE_SYMLINK;
303 req->in.h.ino = dir->i_ino;
304 req->in.numargs = 2;
305 req->in.args[0].size = entry->d_name.len + 1;
306 req->in.args[0].value = entry->d_name.name;
307 req->in.args[1].size = len;
308 req->in.args[1].value = link;
309 req->out.numargs = 1;
310 req->out.args[0].size = sizeof(outarg);
311 req->out.args[0].value = &outarg;
312 request_send(fc, req);
313 err = req->out.h.error;
314 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000315 err = lookup_new_entry(fc, req, dir, entry, &outarg,
316 req->out.h.unique, S_IFLNK);
317 else
318 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000319 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000320}
321
Miklos Szeredib5958612004-02-20 14:10:49 +0000322static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000323{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000324 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 struct fuse_req *req = fuse_get_request(fc);
326 int err;
327
328 if (!req)
329 return -ERESTARTSYS;
Miklos Szeredib483c932001-10-29 14:57:57 +0000330
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000331 req->in.h.opcode = FUSE_UNLINK;
332 req->in.h.ino = dir->i_ino;
333 req->in.numargs = 1;
334 req->in.args[0].size = entry->d_name.len + 1;
335 req->in.args[0].value = entry->d_name.name;
336 request_send(fc, req);
337 err = req->out.h.error;
338 if (!err) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000339 /* Set nlink to zero so the inode can be cleared, if
340 the inode does have more links this will be
341 discovered at the next lookup/getattr */
342 /* FIXME: mark inode "not uptodate" */
343 entry->d_inode->i_nlink = 0;
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000344 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000345 fuse_put_request(fc, req);
346 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000347}
348
349static int fuse_rmdir(struct inode *dir, struct dentry *entry)
350{
Miklos Szeredib5958612004-02-20 14:10:49 +0000351 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000352 struct fuse_req *req = fuse_get_request(fc);
353 int err;
354
355 if (!req)
356 return -ERESTARTSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000357
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000358 req->in.h.opcode = FUSE_RMDIR;
359 req->in.h.ino = dir->i_ino;
360 req->in.numargs = 1;
361 req->in.args[0].size = entry->d_name.len + 1;
362 req->in.args[0].value = entry->d_name.name;
363 request_send(fc, req);
364 err = req->out.h.error;
365 if (!err)
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000366 entry->d_inode->i_nlink = 0;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000367 fuse_put_request(fc, req);
368 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000369}
370
371static int fuse_rename(struct inode *olddir, struct dentry *oldent,
372 struct inode *newdir, struct dentry *newent)
373{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000374 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000375 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000376 struct fuse_rename_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000377 int err;
378
379 if (!req)
380 return -ERESTARTSYS;
381
Miklos Szeredi43696432001-11-18 19:15:05 +0000382 memset(&inarg, 0, sizeof(inarg));
383 inarg.newdir = newdir->i_ino;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000384 req->in.h.opcode = FUSE_RENAME;
385 req->in.h.ino = olddir->i_ino;
386 req->in.numargs = 3;
387 req->in.args[0].size = sizeof(inarg);
388 req->in.args[0].value = &inarg;
389 req->in.args[1].size = oldent->d_name.len + 1;
390 req->in.args[1].value = oldent->d_name.name;
391 req->in.args[2].size = newent->d_name.len + 1;
392 req->in.args[2].value = newent->d_name.name;
393 request_send(fc, req);
394 err = req->out.h.error;
395 fuse_put_request(fc, req);
396 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000397}
398
399static int fuse_link(struct dentry *entry, struct inode *newdir,
400 struct dentry *newent)
401{
402 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000403 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000404 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000405 struct fuse_link_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000406 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000407 int err;
408
409 if (!req)
410 return -ERESTARTSYS;
411
Miklos Szeredi43696432001-11-18 19:15:05 +0000412 memset(&inarg, 0, sizeof(inarg));
413 inarg.newdir = newdir->i_ino;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000414 req->in.h.opcode = FUSE_LINK;
415 req->in.h.ino = inode->i_ino;
416 req->in.numargs = 2;
417 req->in.args[0].size = sizeof(inarg);
418 req->in.args[0].value = &inarg;
419 req->in.args[1].size = newent->d_name.len + 1;
420 req->in.args[1].value = newent->d_name.name;
421 req->out.numargs = 1;
422 req->out.args[0].size = sizeof(outarg);
423 req->out.args[0].value = &outarg;
424 request_send(fc, req);
425 err = req->out.h.error;
426 if (!err) {
427 /* Invalidate old entry, so attributes are refreshed */
428 d_invalidate(entry);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000429 err = lookup_new_entry(fc, req, newdir, newent, &outarg,
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000430 req->out.h.unique, inode->i_mode);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000431 } else
432 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000433 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000434}
435
Miklos Szeredif85ab242004-01-07 12:16:45 +0000436int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000437{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000438 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000439 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000440 struct fuse_attr_out arg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000441 int err;
442
443 if (!req)
444 return -ERESTARTSYS;
445
446 req->in.h.opcode = FUSE_GETATTR;
447 req->in.h.ino = inode->i_ino;
448 req->out.numargs = 1;
449 req->out.args[0].size = sizeof(arg);
450 req->out.args[0].value = &arg;
451 request_send(fc, req);
452 err = req->out.h.error;
453 if (!err)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000454 change_attributes(inode, &arg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000455 fuse_put_request(fc, req);
456 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000457}
458
Miklos Szeredife25def2001-12-20 15:38:05 +0000459static int fuse_revalidate(struct dentry *entry)
460{
461 struct inode *inode = entry->d_inode;
462 struct fuse_conn *fc = INO_FC(inode);
463
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000464 if (inode->i_ino == FUSE_ROOT_INO) {
465 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
466 current->fsuid != fc->uid)
Miklos Szeredife25def2001-12-20 15:38:05 +0000467 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000468 } else if (!entry->d_time || time_before_eq(jiffies, entry->d_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000469 return 0;
470
Miklos Szeredif85ab242004-01-07 12:16:45 +0000471 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000472}
473
Miklos Szeredif85ab242004-01-07 12:16:45 +0000474static int _fuse_permission(struct inode *inode, int mask)
Miklos Szeredife25def2001-12-20 15:38:05 +0000475{
476 struct fuse_conn *fc = INO_FC(inode);
477
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000478 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
Miklos Szeredife25def2001-12-20 15:38:05 +0000479 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000480 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredife25def2001-12-20 15:38:05 +0000481 int err = vfs_permission(inode, mask);
482
483 /* If permission is denied, try to refresh file
484 attributes. This is also needed, because the root
485 node will at first have no permissions */
486
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000487 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000488 err = fuse_do_getattr(inode);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000489 if (!err)
Miklos Szeredife25def2001-12-20 15:38:05 +0000490 err = vfs_permission(inode, mask);
491 }
492
493 /* FIXME: Need some mechanism to revoke permissions:
494 currently if the filesystem suddenly changes the
495 file mode, we will not be informed abot that, and
496 continue to allow access to the file/directory.
497
498 This is actually not so grave, since the user can
499 simply keep access to the file/directory anyway by
500 keeping it open... */
501
502 return err;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000503 } else
Miklos Szeredife25def2001-12-20 15:38:05 +0000504 return 0;
505}
506
Miklos Szeredib483c932001-10-29 14:57:57 +0000507static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
508 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000509{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000510 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000511 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000512 size_t reclen = FUSE_DIRENT_SIZE(dirent);
513 int over;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000514 if (dirent->namelen > NAME_MAX) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000515 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000516 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000517 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000518 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000519 break;
520
521 over = filldir(dstbuf, dirent->name, dirent->namelen,
522 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000523 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000524 break;
525
Miklos Szeredib483c932001-10-29 14:57:57 +0000526 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000527 file->f_pos += reclen;
528 nbytes -= reclen;
529 }
530
Miklos Szeredib483c932001-10-29 14:57:57 +0000531 return 0;
532}
533
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000534static int fuse_checkdir(struct file *cfile, struct file *file)
535{
536 struct inode *inode;
537 if (!cfile) {
538 printk("fuse_getdir: invalid file\n");
539 return -EPROTO;
540 }
541 inode = cfile->f_dentry->d_inode;
542 if (!S_ISREG(inode->i_mode)) {
543 printk("fuse_getdir: not a regular file\n");
544 fput(cfile);
545 return -EPROTO;
546 }
547
548 file->private_data = cfile;
549 return 0;
550}
551
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000552static int fuse_getdir(struct file *file)
553{
554 struct inode *inode = file->f_dentry->d_inode;
555 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000556 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000557 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000558 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000559
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000560 if (!req)
561 return -ERESTARTSYS;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000562
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000563 req->in.h.opcode = FUSE_GETDIR;
564 req->in.h.ino = inode->i_ino;
565 req->out.numargs = 1;
566 req->out.args[0].size = sizeof(struct fuse_getdir_out);
567 req->out.args[0].value = &outarg;
568 request_send(fc, req);
569 err = req->out.h.error;
570 if (!err)
571 err = fuse_checkdir(outarg.file, file);
572 fuse_put_request(fc, req);
573 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000574}
575
Miklos Szeredib483c932001-10-29 14:57:57 +0000576#define DIR_BUFSIZE 2048
577static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
578{
579 struct file *cfile = file->private_data;
580 char *buf;
581 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000582
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000583 if (!cfile) {
584 ret = fuse_getdir(file);
585 if (ret)
586 return ret;
587
588 cfile = file->private_data;
589 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000590
Miklos Szeredib483c932001-10-29 14:57:57 +0000591 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000592 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000593 return -ENOMEM;
Miklos Szeredie815c032004-01-19 18:20:49 +0000594
Miklos Szeredib483c932001-10-29 14:57:57 +0000595 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000596 if (ret < 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000597 printk("fuse_readdir: failed to read container file\n");
598 else
599 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
600
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000601 kfree(buf);
602 return ret;
603}
604
Miklos Szeredi05033042001-11-13 16:11:35 +0000605static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000606{
607 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000608 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000609 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000610 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000611
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000612 if (!req)
613 return ERR_PTR(-ERESTARTSYS);
614
Miklos Szeredi05033042001-11-13 16:11:35 +0000615 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000616 if (!link) {
617 link = ERR_PTR(-ENOMEM);
618 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000619 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000620 req->in.h.opcode = FUSE_READLINK;
621 req->in.h.ino = inode->i_ino;
622 req->out.argvar = 1;
623 req->out.numargs = 1;
624 req->out.args[0].size = PAGE_SIZE - 1;
625 req->out.args[0].value = link;
626 request_send(fc, req);
627 if (req->out.h.error) {
628 free_page((unsigned long) link);
629 link = ERR_PTR(req->out.h.error);
630 } else
631 link[req->out.args[0].size] = '\0';
632 out:
633 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000634 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000635}
636
637static void free_link(char *link)
638{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000639 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000640 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000641}
642
643static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
644{
645 int ret;
646 char *link;
647
Miklos Szeredi05033042001-11-13 16:11:35 +0000648 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000649 ret = vfs_readlink(dentry, buffer, buflen, link);
650 free_link(link);
651 return ret;
652}
653
654static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
655{
656 int ret;
657 char *link;
658
Miklos Szeredi05033042001-11-13 16:11:35 +0000659 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000660 ret = vfs_follow_link(nd, link);
661 free_link(link);
662 return ret;
663}
664
665static int fuse_dir_open(struct inode *inode, struct file *file)
666{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000667 file->private_data = NULL;
668 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000669}
670
671static int fuse_dir_release(struct inode *inode, struct file *file)
672{
673 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000674
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000675 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000676 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000677
678 return 0;
679}
680
Miklos Szeredi5e183482001-10-31 14:52:35 +0000681static unsigned int iattr_to_fattr(struct iattr *iattr,
682 struct fuse_attr *fattr)
683{
684 unsigned int ivalid = iattr->ia_valid;
685 unsigned int fvalid = 0;
686
687 memset(fattr, 0, sizeof(*fattr));
688
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000689 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000690 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000691 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000692 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000693 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000694 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000695 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000696 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
697 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000698 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000699 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000700#ifdef KERNEL_2_6
701 fattr->atime = iattr->ia_atime.tv_sec;
702 fattr->mtime = iattr->ia_mtime.tv_sec;
703#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000704 fattr->atime = iattr->ia_atime;
705 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000706#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000707 }
708
709 return fvalid;
710}
711
712static int fuse_setattr(struct dentry *entry, struct iattr *attr)
713{
714 struct inode *inode = entry->d_inode;
715 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000716 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredia181e612001-11-06 12:03:23 +0000717 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000718 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000719 int err;
720
721 if (!req)
722 return -ERESTARTSYS;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000723
Miklos Szeredi43696432001-11-18 19:15:05 +0000724 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000725 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000726 req->in.h.opcode = FUSE_SETATTR;
727 req->in.h.ino = inode->i_ino;
728 req->in.numargs = 1;
729 req->in.args[0].size = sizeof(inarg);
730 req->in.args[0].value = &inarg;
731 req->out.numargs = 1;
732 req->out.args[0].size = sizeof(outarg);
733 req->out.args[0].value = &outarg;
734 request_send(fc, req);
735 err = req->out.h.error;
736 if (!err) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000737 if (attr->ia_valid & ATTR_SIZE &&
738 outarg.attr.size < i_size_read(inode))
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000739 vmtruncate(inode, outarg.attr.size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000740
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000741 change_attributes(inode, &outarg.attr);
742 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000743 fuse_put_request(fc, req);
744 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000745}
746
Miklos Szeredif85ab242004-01-07 12:16:45 +0000747static int _fuse_dentry_revalidate(struct dentry *entry)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000748{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000749 if (!entry->d_inode)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000750 return 0;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000751 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000752 struct inode *inode = entry->d_inode;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000753 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000754 int version;
755 int ret;
756
757 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
758 &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000759 if (ret)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000760 return 0;
761
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000762 if (outarg.ino != inode->i_ino)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000763 return 0;
764
765 change_attributes(inode, &outarg.attr);
766 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000767 entry->d_time = time_to_jiffies(outarg.entry_valid,
768 outarg.entry_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000769 }
770 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000771}
772
Miklos Szeredif85ab242004-01-07 12:16:45 +0000773#ifdef KERNEL_2_6
774
775#define fuse_mknod _fuse_mknod
776
777static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
778 struct kstat *stat)
779{
780 struct inode *inode = entry->d_inode;
781 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000782 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000783 generic_fillattr(inode, stat);
784
785 return err;
786}
787
788static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
789 struct nameidata *nd)
790{
Miklos Szeredie815c032004-01-19 18:20:49 +0000791 struct inode *inode;
792 int err = fuse_lookup_iget(dir, entry, &inode);
793 if (err)
794 return ERR_PTR(err);
795 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000796}
797
798static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
799 struct nameidata *nd)
800{
801 return _fuse_create(dir, entry, mode);
802}
803
804static int fuse_permission(struct inode *inode, int mask,
805 struct nameidata *nd)
806{
807 return _fuse_permission(inode, mask);
808}
809
810static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
811{
812 return _fuse_dentry_revalidate(entry);
813}
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000814
Miklos Szeredi689f5632004-05-04 08:49:16 +0000815#else /* KERNEL_2_6 */
816
817#define fuse_create _fuse_create
818#define fuse_permission _fuse_permission
819
820static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
821{
822 struct inode *inode;
823 struct dentry *alias;
824
825 int err = fuse_lookup_iget(dir, entry, &inode);
826 if (err)
827 return ERR_PTR(err);
828
829 if (inode && S_ISDIR(inode->i_mode) &&
830 (alias = d_find_alias(inode)) != NULL) {
831 dput(alias);
832 iput(inode);
833 printk("fuse: cannot assign an existing directory\n");
834 return ERR_PTR(-EPROTO);
835 }
836
837 d_add(entry, inode);
838 return NULL;
839}
840
841static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
842 int rdev)
843{
844 return fuse_mknod(dir, entry, mode, rdev);
845}
846
847static int fuse_dentry_revalidate(struct dentry *entry, int flags)
848{
849 return _fuse_dentry_revalidate(entry);
850}
851#endif /* KERNEL_2_6 */
852
853#ifdef HAVE_KERNEL_XATTR
854
855#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000856static int fuse_setxattr(struct dentry *entry, const char *name,
857 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000858#else
859static int fuse_setxattr(struct dentry *entry, const char *name,
860 void *value, size_t size, int flags)
861#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000862{
863 struct inode *inode = entry->d_inode;
864 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000865 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000866 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000867 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000868
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000869 if (size > FUSE_XATTR_SIZE_MAX)
870 return -E2BIG;
871
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000872 if (fc->no_setxattr)
873 return -EOPNOTSUPP;
874
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000875 req = fuse_get_request(fc);
876 if (!req)
877 return -ERESTARTSYS;
878
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000879 memset(&inarg, 0, sizeof(inarg));
880 inarg.size = size;
881 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000882 req->in.h.opcode = FUSE_SETXATTR;
883 req->in.h.ino = inode->i_ino;
884 req->in.numargs = 3;
885 req->in.args[0].size = sizeof(inarg);
886 req->in.args[0].value = &inarg;
887 req->in.args[1].size = strlen(name) + 1;
888 req->in.args[1].value = name;
889 req->in.args[2].size = size;
890 req->in.args[2].value = value;
891 request_send(fc, req);
892 err = req->out.h.error;
893 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000894 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000896 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000897 fuse_put_request(fc, req);
898 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000899}
900
901static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
902 void *value, size_t size)
903{
904 struct inode *inode = entry->d_inode;
905 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000906 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000907 struct fuse_getxattr_in inarg;
908 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000909 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000910
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000911 if (fc->no_getxattr)
912 return -EOPNOTSUPP;
913
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000914 req = fuse_get_request(fc);
915 if (!req)
916 return -ERESTARTSYS;
917
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000918 memset(&inarg, 0, sizeof(inarg));
919 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000920 req->in.h.opcode = FUSE_GETXATTR;
921 req->in.h.ino = inode->i_ino;
922 req->in.numargs = 2;
923 req->in.args[0].size = sizeof(inarg);
924 req->in.args[0].value = &inarg;
925 req->in.args[1].size = strlen(name) + 1;
926 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000927 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000928 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000929 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000930 req->out.argvar = 1;
931 req->out.args[0].size = size;
932 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000933 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000934 req->out.args[0].size = sizeof(outarg);
935 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000936 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000937 request_send(fc, req);
938 ret = req->out.h.error;
939 if (!ret)
940 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000941 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000942 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000943 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000944 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000945 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000946 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000947 fuse_put_request(fc, req);
948 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000949}
950
951static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
952{
953 struct inode *inode = entry->d_inode;
954 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000955 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000956 struct fuse_getxattr_in inarg;
957 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000958 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000959
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000960 if (fc->no_listxattr)
961 return -EOPNOTSUPP;
962
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000963 req = fuse_get_request(fc);
964 if (!req)
965 return -ERESTARTSYS;
966
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000967 memset(&inarg, 0, sizeof(inarg));
968 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000969 req->in.h.opcode = FUSE_LISTXATTR;
970 req->in.h.ino = inode->i_ino;
971 req->in.numargs = 1;
972 req->in.args[0].size = sizeof(inarg);
973 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000974 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000975 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000976 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000977 req->out.argvar = 1;
978 req->out.args[0].size = size;
979 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000980 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000981 req->out.args[0].size = sizeof(outarg);
982 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +0000983 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000984 request_send(fc, req);
985 ret = req->out.h.error;
986 if (!ret)
987 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000988 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000989 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000990 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000991 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000992 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000993 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000994 fuse_put_request(fc, req);
995 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000996}
997
998static int fuse_removexattr(struct dentry *entry, const char *name)
999{
1000 struct inode *inode = entry->d_inode;
1001 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001002 struct fuse_req *req;
1003 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001004
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001005 if (fc->no_removexattr)
1006 return -EOPNOTSUPP;
1007
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001008 req = fuse_get_request(fc);
1009 if (!req)
1010 return -ERESTARTSYS;
1011
1012 req->in.h.opcode = FUSE_REMOVEXATTR;
1013 req->in.h.ino = inode->i_ino;
1014 req->in.numargs = 1;
1015 req->in.args[0].size = strlen(name) + 1;
1016 req->in.args[0].value = name;
1017 request_send(fc, req);
1018 err = req->out.h.error;
1019 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001020 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001021 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001022 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001023 fuse_put_request(fc, req);
1024 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001025}
1026
Miklos Szeredi689f5632004-05-04 08:49:16 +00001027#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001028
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001029static struct inode_operations fuse_dir_inode_operations =
1030{
Miklos Szeredie8663f32004-01-13 15:33:12 +00001031 .lookup = fuse_lookup,
1032 .create = fuse_create,
1033 .mknod = fuse_mknod,
1034 .mkdir = fuse_mkdir,
1035 .symlink = fuse_symlink,
1036 .unlink = fuse_unlink,
1037 .rmdir = fuse_rmdir,
1038 .rename = fuse_rename,
1039 .link = fuse_link,
1040 .setattr = fuse_setattr,
1041 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001042#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001043 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001044#else
1045 .revalidate = fuse_revalidate,
1046#endif
1047#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001048 .setxattr = fuse_setxattr,
1049 .getxattr = fuse_getxattr,
1050 .listxattr = fuse_listxattr,
1051 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001052#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001053};
1054
1055static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001056 .read = generic_read_dir,
1057 .readdir = fuse_readdir,
1058 .open = fuse_dir_open,
1059 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001060};
1061
1062static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001063 .setattr = fuse_setattr,
1064 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001065#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001066 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001067#else
1068 .revalidate = fuse_revalidate,
1069#endif
1070#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001071 .setxattr = fuse_setxattr,
1072 .getxattr = fuse_getxattr,
1073 .listxattr = fuse_listxattr,
1074 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001075#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001076};
1077
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001078static struct inode_operations fuse_symlink_inode_operations =
1079{
Miklos Szeredie8663f32004-01-13 15:33:12 +00001080 .setattr = fuse_setattr,
1081 .readlink = fuse_readlink,
1082 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001083#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001084 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001085#else
1086 .revalidate = fuse_revalidate,
1087#endif
1088#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001089 .setxattr = fuse_setxattr,
1090 .getxattr = fuse_getxattr,
1091 .listxattr = fuse_listxattr,
1092 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001093#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001094};
1095
Miklos Szeredi307242f2004-01-26 11:28:44 +00001096static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001097 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001098};
1099
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001100/*
1101 * Local Variables:
1102 * indent-tabs-mode: t
1103 * c-basic-offset: 8
1104 * End:
1105 */