blob: 124bf867e46087bb8c2c93338c8e0c470b409ee0 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi2e6b6f22004-07-07 19:19:53 +00003 Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
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 Szeredi5e183482001-10-31 14:52:35 +000012#include <linux/file.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000013#ifdef KERNEL_2_6
14#include <linux/gfp.h>
15#else
16#include <linux/mm.h>
17#endif
18#include <linux/sched.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000019
Miklos Szeredib483c932001-10-29 14:57:57 +000020static struct inode_operations fuse_dir_inode_operations;
21static struct inode_operations fuse_file_inode_operations;
22static struct inode_operations fuse_symlink_inode_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000023static struct file_operations fuse_dir_operations;
Miklos Szeredi307242f2004-01-26 11:28:44 +000024static struct dentry_operations fuse_dentry_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000025
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000026#ifndef KERNEL_2_6
27#define new_decode_dev(x) (x)
28#define new_encode_dev(x) (x)
29#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000030static void change_attributes(struct inode *inode, struct fuse_attr *attr)
31{
Miklos Szeredic26c14d2004-04-09 17:48:32 +000032 if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) {
Miklos Szeredif85ab242004-01-07 12:16:45 +000033#ifdef KERNEL_2_6
34 invalidate_inode_pages(inode->i_mapping);
35#else
Miklos Szeredia181e612001-11-06 12:03:23 +000036 invalidate_inode_pages(inode);
Miklos Szeredif85ab242004-01-07 12:16:45 +000037#endif
38 }
Miklos Szeredia181e612001-11-06 12:03:23 +000039
Miklos Szeredia13d9002004-11-02 17:32:03 +000040 inode->i_ino = attr->ino;
Miklos Szeredi5e183482001-10-31 14:52:35 +000041 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000042 inode->i_nlink = attr->nlink;
43 inode->i_uid = attr->uid;
44 inode->i_gid = attr->gid;
Miklos Szeredid1199f82004-02-06 15:29:22 +000045 i_size_write(inode, attr->size);
Miklos Szeredi05033042001-11-13 16:11:35 +000046 inode->i_blksize = PAGE_CACHE_SIZE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000047 inode->i_blocks = attr->blocks;
Miklos Szeredif85ab242004-01-07 12:16:45 +000048#ifdef KERNEL_2_6
49 inode->i_atime.tv_sec = attr->atime;
Miklos Szeredib5958612004-02-20 14:10:49 +000050 inode->i_atime.tv_nsec = attr->atimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000051 inode->i_mtime.tv_sec = attr->mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +000052 inode->i_mtime.tv_nsec = attr->mtimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000053 inode->i_ctime.tv_sec = attr->ctime;
Miklos Szeredib5958612004-02-20 14:10:49 +000054 inode->i_ctime.tv_nsec = attr->ctimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000055#else
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000056 inode->i_atime = attr->atime;
57 inode->i_mtime = attr->mtime;
58 inode->i_ctime = attr->ctime;
Miklos Szeredif85ab242004-01-07 12:16:45 +000059#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000060}
61
Miklos Szeredia181e612001-11-06 12:03:23 +000062static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000063{
Miklos Szeredia181e612001-11-06 12:03:23 +000064 inode->i_mode = attr->mode & S_IFMT;
Miklos Szeredid1199f82004-02-06 15:29:22 +000065 i_size_write(inode, attr->size);
Miklos Szeredic26c14d2004-04-09 17:48:32 +000066 if (S_ISREG(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000067 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000068 fuse_init_file_inode(inode);
Miklos Szeredib483c932001-10-29 14:57:57 +000069 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000070 else if (S_ISDIR(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000071 inode->i_op = &fuse_dir_inode_operations;
72 inode->i_fop = &fuse_dir_operations;
73 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000074 else if (S_ISLNK(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000075 inode->i_op = &fuse_symlink_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000076 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +000077 else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
Miklos Szeredi064efb02004-11-09 17:30:29 +000078 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
Miklos Szeredia181e612001-11-06 12:03:23 +000079 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000080 init_special_inode(inode, inode->i_mode,
81 new_decode_dev(attr->rdev));
Miklos Szeredi064efb02004-11-09 17:30:29 +000082 } else {
83 /* Don't let user create weird files */
Miklos Szeredi76f65782004-02-19 16:55:40 +000084 printk("fuse_init_inode: bad file type: %o\n", inode->i_mode);
Miklos Szeredi064efb02004-11-09 17:30:29 +000085 inode->i_mode = S_IFREG;
86 inode->i_op = &fuse_file_inode_operations;
87 fuse_init_file_inode(inode);
88 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000089}
90
Miklos Szeredia13d9002004-11-02 17:32:03 +000091#ifdef KERNEL_2_6
92static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
93{
94 unsigned long nodeid = *(unsigned long *) _nodeidp;
95 struct fuse_inode *fi = INO_FI(inode);
96 if (fi->nodeid == nodeid)
97 return 1;
98 else
99 return 0;
100}
101
102static int fuse_inode_set(struct inode *inode, void *_nodeidp)
103{
104 unsigned long nodeid = *(unsigned long *) _nodeidp;
105 struct fuse_inode *fi = INO_FI(inode);
106 fi->nodeid = nodeid;
107 return 0;
108}
109
110struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
111 int generation, struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000112{
113 struct inode *inode;
114
Miklos Szeredia13d9002004-11-02 17:32:03 +0000115 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
116 if (!inode)
117 return NULL;
Miklos Szeredie815c032004-01-19 18:20:49 +0000118
Miklos Szeredia13d9002004-11-02 17:32:03 +0000119 if ((inode->i_state & I_NEW)) {
120 inode->i_generation = generation;
121 fuse_init_inode(inode, attr);
122 unlock_new_inode(inode);
123 } else if (inode->i_generation != generation)
124 printk("fuse_iget: bad generation for node %lu\n", nodeid);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000125
Miklos Szeredia13d9002004-11-02 17:32:03 +0000126 change_attributes(inode, attr);
127 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000128 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000129}
130
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000131struct inode *fuse_ilookup(struct super_block *sb, unsigned long nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000132{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000133 return ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000134}
135#else
136static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
137 unsigned long nodeid = *(unsigned long *) _nodeidp;
138 struct fuse_inode *fi = INO_FI(inode);
139 if (inode->u.generic_ip && fi->nodeid == nodeid)
140 return 1;
141 else
142 return 0;
143}
144
145struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
146 int generation, struct fuse_attr *attr, int version)
147{
148 struct inode *inode;
149
150 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
151 if (!inode)
152 return NULL;
153
154 if (!inode->u.generic_ip) {
155 struct fuse_inode *fi = INO_FI(inode);
156 fi->nodeid = nodeid;
157 inode->u.generic_ip = inode;
158 inode->i_generation = generation;
159 fuse_init_inode(inode, attr);
160 } else if (inode->i_generation != generation)
161 printk("fuse_iget: bad generation for node %lu\n", nodeid);
162
163 change_attributes(inode, attr);
164 inode->i_version = version;
165 return inode;
166}
167
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000168struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000169{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000170 struct inode *inode = iget4(sb, ino, fuse_inode_eq, &nodeid);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000171 if (inode && !inode->u.generic_ip) {
172 iput(inode);
173 inode = NULL;
174 }
175 return inode;
176}
Miklos Szeredia13d9002004-11-02 17:32:03 +0000177#endif
178
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000179static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req,
180 struct inode *dir, struct dentry *entry,
181 struct fuse_entry_out *outarg, int *version)
182{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000183 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000184 req->in.h.opcode = FUSE_LOOKUP;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000185 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000186 req->in.numargs = 1;
187 req->in.args[0].size = entry->d_name.len + 1;
188 req->in.args[0].value = entry->d_name.name;
189 req->out.numargs = 1;
190 req->out.args[0].size = sizeof(struct fuse_entry_out);
191 req->out.args[0].value = outarg;
192 request_send(fc, req);
193 *version = req->out.h.unique;
194 return req->out.h.error;
195}
196
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000197static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000198 struct fuse_entry_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000199{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000200 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000201 struct fuse_req *req;
202 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000203
204 if (entry->d_name.len > FUSE_NAME_MAX)
205 return -ENAMETOOLONG;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000206 req = fuse_get_request(fc);
207 if (!req)
208 return -ERESTARTSYS;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000209
210 err = fuse_send_lookup(fc, req, dir, entry, outarg, version);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000211 fuse_put_request(fc, req);
212 return err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000213}
214
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000215static inline unsigned long time_to_jiffies(unsigned long sec,
216 unsigned long nsec)
217{
218 /* prevent wrapping of jiffies */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000219 if (sec + 1 >= LONG_MAX / HZ)
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000220 return 0;
221
222 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
223}
224
Miklos Szeredie815c032004-01-19 18:20:49 +0000225static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
226 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000227{
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000228 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredie815c032004-01-19 18:20:49 +0000229 int err;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000230 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000231 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000232 struct inode *inode = NULL;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000233 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000234
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000235 if (entry->d_name.len > FUSE_NAME_MAX)
236 return -ENAMETOOLONG;
237 req = fuse_get_request(fc);
238 if (!req)
239 return -ERESTARTSYS;
240
241 err = fuse_send_lookup(fc, req, dir, entry, &outarg, &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000242 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000243 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000244 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000245 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000246 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000247 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000248 }
249 }
250 fuse_put_request(fc, req);
251 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000252 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000253
Miklos Szeredi069c9502004-07-16 16:17:02 +0000254 if (inode) {
255 struct fuse_inode *fi = INO_FI(inode);
256 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000257 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000258 fi->i_time = time_to_jiffies(outarg.attr_valid,
259 outarg.attr_valid_nsec);
260 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000261
Miklos Szeredi307242f2004-01-26 11:28:44 +0000262 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000263 *inodep = inode;
264 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000265}
266
Miklos Szeredi069c9502004-07-16 16:17:02 +0000267static void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000268{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000269 struct fuse_inode *fi = INO_FI(inode);
270 fi->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000271}
272
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000273static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
274 struct inode *dir, struct dentry *entry,
275 struct fuse_entry_out *outarg, int version,
276 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000277{
278 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000279 struct fuse_inode *fi;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000280 inode = fuse_iget(dir->i_sb, outarg->nodeid, outarg->generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000281 &outarg->attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000282 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000283 fuse_send_forget(fc, req, outarg->nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000284 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000285 }
286 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000287
288 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000289 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000290 iput(inode);
291 printk("fuse_mknod: inode has wrong type\n");
Miklos Szeredi064efb02004-11-09 17:30:29 +0000292 return -EPROTO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000293 }
294
Miklos Szerediad051c32004-07-02 09:22:50 +0000295 entry->d_time = time_to_jiffies(outarg->entry_valid,
296 outarg->entry_valid_nsec);
297
Miklos Szeredi069c9502004-07-16 16:17:02 +0000298 fi = INO_FI(inode);
299 fi->i_time = time_to_jiffies(outarg->attr_valid,
300 outarg->attr_valid_nsec);
301
Miklos Szeredi76f65782004-02-19 16:55:40 +0000302 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000303 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000304 return 0;
305}
306
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000307static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000308 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000309{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000310 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000311 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000312 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000313 struct fuse_mknod_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000314 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000315 int err;
316
317 if (!req)
318 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000319
320 memset(&inarg, 0, sizeof(inarg));
321 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000322 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000323 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000324 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 req->in.numargs = 2;
326 req->in.args[0].size = sizeof(inarg);
327 req->in.args[0].value = &inarg;
328 req->in.args[1].size = entry->d_name.len + 1;
329 req->in.args[1].value = entry->d_name.name;
330 req->out.numargs = 1;
331 req->out.args[0].size = sizeof(outarg);
332 req->out.args[0].value = &outarg;
333 request_send(fc, req);
334 err = req->out.h.error;
335 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000336 err = lookup_new_entry(fc, req, dir, entry, &outarg,
337 req->out.h.unique, mode);
338 else
339 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000340 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000341}
342
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000343static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
344 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000345{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000346 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347}
348
Miklos Szeredib483c932001-10-29 14:57:57 +0000349static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
350{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000351 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000352 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000353 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000354 struct fuse_mkdir_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000355 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000356 int err;
357
358 if (!req)
359 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000360
361 memset(&inarg, 0, sizeof(inarg));
362 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000363 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000364 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000365 req->in.numargs = 2;
366 req->in.args[0].size = sizeof(inarg);
367 req->in.args[0].value = &inarg;
368 req->in.args[1].size = entry->d_name.len + 1;
369 req->in.args[1].value = entry->d_name.name;
370 req->out.numargs = 1;
371 req->out.args[0].size = sizeof(outarg);
372 req->out.args[0].value = &outarg;
373 request_send(fc, req);
374 err = req->out.h.error;
375 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000376 err = lookup_new_entry(fc, req, dir, entry, &outarg,
377 req->out.h.unique, S_IFDIR);
378 else
379 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000381}
382
383static int fuse_symlink(struct inode *dir, struct dentry *entry,
384 const char *link)
385{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000386 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000387 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000388 struct fuse_req *req;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000389 struct fuse_entry_out outarg;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000390 unsigned int len = strlen(link) + 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000391 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000392
393 if (len > FUSE_SYMLINK_MAX)
394 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000395
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000396 req = fuse_get_request(fc);
397 if (!req)
398 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000399
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000400 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000401 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000402 req->in.numargs = 2;
403 req->in.args[0].size = entry->d_name.len + 1;
404 req->in.args[0].value = entry->d_name.name;
405 req->in.args[1].size = len;
406 req->in.args[1].value = link;
407 req->out.numargs = 1;
408 req->out.args[0].size = sizeof(outarg);
409 req->out.args[0].value = &outarg;
410 request_send(fc, req);
411 err = req->out.h.error;
412 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000413 err = lookup_new_entry(fc, req, dir, entry, &outarg,
414 req->out.h.unique, S_IFLNK);
415 else
416 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000417 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000418}
419
Miklos Szeredib5958612004-02-20 14:10:49 +0000420static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000421{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000422 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000423 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000424 struct fuse_req *req = fuse_get_request(fc);
425 int err;
426
427 if (!req)
428 return -ERESTARTSYS;
Miklos Szeredib483c932001-10-29 14:57:57 +0000429
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000430 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000431 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000432 req->in.numargs = 1;
433 req->in.args[0].size = entry->d_name.len + 1;
434 req->in.args[0].value = entry->d_name.name;
435 request_send(fc, req);
436 err = req->out.h.error;
437 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000438 struct inode *inode = entry->d_inode;
439
Miklos Szeredib5958612004-02-20 14:10:49 +0000440 /* Set nlink to zero so the inode can be cleared, if
441 the inode does have more links this will be
442 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000443 inode->i_nlink = 0;
444 fuse_invalidate_attr(inode);
445 fuse_invalidate_attr(dir);
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000446 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000447 fuse_put_request(fc, req);
448 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000449}
450
451static int fuse_rmdir(struct inode *dir, struct dentry *entry)
452{
Miklos Szeredib5958612004-02-20 14:10:49 +0000453 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000454 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000455 struct fuse_req *req = fuse_get_request(fc);
456 int err;
457
458 if (!req)
459 return -ERESTARTSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000460
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000461 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000462 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000463 req->in.numargs = 1;
464 req->in.args[0].size = entry->d_name.len + 1;
465 req->in.args[0].value = entry->d_name.name;
466 request_send(fc, req);
467 err = req->out.h.error;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000468 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000469 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000470 fuse_invalidate_attr(dir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000471 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000472 fuse_put_request(fc, req);
473 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000474}
475
476static int fuse_rename(struct inode *olddir, struct dentry *oldent,
477 struct inode *newdir, struct dentry *newent)
478{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000479 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000480 struct fuse_inode *oldfi = INO_FI(olddir);
481 struct fuse_inode *newfi = INO_FI(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000482 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000483 struct fuse_rename_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000484 int err;
485
486 if (!req)
487 return -ERESTARTSYS;
488
Miklos Szeredi43696432001-11-18 19:15:05 +0000489 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia13d9002004-11-02 17:32:03 +0000490 inarg.newdir = newfi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000491 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000492 req->in.h.nodeid = oldfi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000493 req->in.numargs = 3;
494 req->in.args[0].size = sizeof(inarg);
495 req->in.args[0].value = &inarg;
496 req->in.args[1].size = oldent->d_name.len + 1;
497 req->in.args[1].value = oldent->d_name.name;
498 req->in.args[2].size = newent->d_name.len + 1;
499 req->in.args[2].value = newent->d_name.name;
500 request_send(fc, req);
501 err = req->out.h.error;
502 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000503 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000504 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000505 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000506 fuse_invalidate_attr(newdir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000507 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000508 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000509}
510
511static int fuse_link(struct dentry *entry, struct inode *newdir,
512 struct dentry *newent)
513{
514 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000515 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000516 struct fuse_inode *fi = INO_FI(inode);
517 struct fuse_inode *newfi = INO_FI(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000518 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000519 struct fuse_link_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000520 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000521 int err;
522
523 if (!req)
524 return -ERESTARTSYS;
525
Miklos Szeredi43696432001-11-18 19:15:05 +0000526 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia13d9002004-11-02 17:32:03 +0000527 inarg.newdir = newfi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000528 req->in.h.opcode = FUSE_LINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000529 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000530 req->in.numargs = 2;
531 req->in.args[0].size = sizeof(inarg);
532 req->in.args[0].value = &inarg;
533 req->in.args[1].size = newent->d_name.len + 1;
534 req->in.args[1].value = newent->d_name.name;
535 req->out.numargs = 1;
536 req->out.args[0].size = sizeof(outarg);
537 req->out.args[0].value = &outarg;
538 request_send(fc, req);
539 err = req->out.h.error;
540 if (!err) {
541 /* Invalidate old entry, so attributes are refreshed */
542 d_invalidate(entry);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000543 err = lookup_new_entry(fc, req, newdir, newent, &outarg,
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000544 req->out.h.unique, inode->i_mode);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000545 } else
546 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000547 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000548}
549
Miklos Szeredif85ab242004-01-07 12:16:45 +0000550int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000551{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000552 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000553 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000554 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000555 struct fuse_attr_out arg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000556 int err;
557
558 if (!req)
559 return -ERESTARTSYS;
560
561 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000562 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000563 req->out.numargs = 1;
564 req->out.args[0].size = sizeof(arg);
565 req->out.args[0].value = &arg;
566 request_send(fc, req);
567 err = req->out.h.error;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000568 if (!err) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000569 change_attributes(inode, &arg.attr);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000570 fi->i_time = time_to_jiffies(arg.attr_valid,
571 arg.attr_valid_nsec);
572 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000573 fuse_put_request(fc, req);
574 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000575}
576
Miklos Szeredife25def2001-12-20 15:38:05 +0000577static int fuse_revalidate(struct dentry *entry)
578{
579 struct inode *inode = entry->d_inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000580 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000581 struct fuse_conn *fc = INO_FC(inode);
582
Miklos Szeredia13d9002004-11-02 17:32:03 +0000583 if (fi->nodeid == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000584 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000585 current->fsuid != fc->uid &&
586 (!(fc->flags & FUSE_ALLOW_ROOT) ||
587 current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000588 return -EACCES;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000589 } else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000590 return 0;
591
Miklos Szeredif85ab242004-01-07 12:16:45 +0000592 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000593}
594
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000595static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000596{
597 struct fuse_conn *fc = INO_FC(inode);
598
Miklos Szeredi180ff692004-11-01 16:01:05 +0000599 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
600 (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000601 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000602 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000603 int err;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000604#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000605 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000606#else
607 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000608#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000609
610 /* If permission is denied, try to refresh file
611 attributes. This is also needed, because the root
612 node will at first have no permissions */
613
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000614 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000615 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000616 if (!err)
617#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000618 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000619#else
620 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000621#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000622 }
623
624 /* FIXME: Need some mechanism to revoke permissions:
625 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000626 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000627 continue to allow access to the file/directory.
628
629 This is actually not so grave, since the user can
630 simply keep access to the file/directory anyway by
631 keeping it open... */
632
633 return err;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000634 } else
Miklos Szeredife25def2001-12-20 15:38:05 +0000635 return 0;
636}
637
Miklos Szeredib483c932001-10-29 14:57:57 +0000638static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
639 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000640{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000641 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000642 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000643 size_t reclen = FUSE_DIRENT_SIZE(dirent);
644 int over;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000645 if (dirent->namelen > NAME_MAX) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000646 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000647 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000648 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000649 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000650 break;
651
652 over = filldir(dstbuf, dirent->name, dirent->namelen,
653 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000654 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000655 break;
656
Miklos Szeredib483c932001-10-29 14:57:57 +0000657 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000658 file->f_pos += reclen;
659 nbytes -= reclen;
660 }
661
Miklos Szeredib483c932001-10-29 14:57:57 +0000662 return 0;
663}
664
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000665static int fuse_checkdir(struct file *cfile, struct file *file)
666{
667 struct inode *inode;
668 if (!cfile) {
669 printk("fuse_getdir: invalid file\n");
670 return -EPROTO;
671 }
672 inode = cfile->f_dentry->d_inode;
673 if (!S_ISREG(inode->i_mode)) {
674 printk("fuse_getdir: not a regular file\n");
675 fput(cfile);
676 return -EPROTO;
677 }
678
679 file->private_data = cfile;
680 return 0;
681}
682
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000683static int fuse_getdir(struct file *file)
684{
685 struct inode *inode = file->f_dentry->d_inode;
686 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000687 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000688 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000689 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000690 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000691
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000692 if (!req)
693 return -ERESTARTSYS;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000694
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000695 req->in.h.opcode = FUSE_GETDIR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000696 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000697 req->out.numargs = 1;
698 req->out.args[0].size = sizeof(struct fuse_getdir_out);
699 req->out.args[0].value = &outarg;
700 request_send(fc, req);
701 err = req->out.h.error;
702 if (!err)
703 err = fuse_checkdir(outarg.file, file);
704 fuse_put_request(fc, req);
705 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000706}
707
Miklos Szeredib483c932001-10-29 14:57:57 +0000708static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
709{
710 struct file *cfile = file->private_data;
711 char *buf;
712 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000713
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000714 if (!cfile) {
715 ret = fuse_getdir(file);
716 if (ret)
717 return ret;
718
719 cfile = file->private_data;
720 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000721
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000722 buf = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000723 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000724 return -ENOMEM;
Miklos Szeredie815c032004-01-19 18:20:49 +0000725
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000726 ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000727 if (ret < 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000728 printk("fuse_readdir: failed to read container file\n");
729 else
730 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
731
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000732 free_page((unsigned long) buf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000733 return ret;
734}
735
Miklos Szeredi05033042001-11-13 16:11:35 +0000736static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000737{
738 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000739 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000740 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000741 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000742 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000743
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000744 if (!req)
745 return ERR_PTR(-ERESTARTSYS);
746
Miklos Szeredi05033042001-11-13 16:11:35 +0000747 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000748 if (!link) {
749 link = ERR_PTR(-ENOMEM);
750 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000751 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000752 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000753 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000754 req->out.argvar = 1;
755 req->out.numargs = 1;
756 req->out.args[0].size = PAGE_SIZE - 1;
757 req->out.args[0].value = link;
758 request_send(fc, req);
759 if (req->out.h.error) {
760 free_page((unsigned long) link);
761 link = ERR_PTR(req->out.h.error);
762 } else
763 link[req->out.args[0].size] = '\0';
764 out:
765 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000766 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000767}
768
769static void free_link(char *link)
770{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000771 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000772 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000773}
774
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000775static int fuse_readlink(struct dentry *dentry, char __user *buffer,
776 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000777{
778 int ret;
779 char *link;
780
Miklos Szeredi05033042001-11-13 16:11:35 +0000781 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000782 ret = vfs_readlink(dentry, buffer, buflen, link);
783 free_link(link);
784 return ret;
785}
786
787static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
788{
789 int ret;
790 char *link;
791
Miklos Szeredi05033042001-11-13 16:11:35 +0000792 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000793 ret = vfs_follow_link(nd, link);
794 free_link(link);
795 return ret;
796}
797
798static int fuse_dir_open(struct inode *inode, struct file *file)
799{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000800 file->private_data = NULL;
801 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000802}
803
804static int fuse_dir_release(struct inode *inode, struct file *file)
805{
806 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000807
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000808 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000809 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000810
811 return 0;
812}
813
Miklos Szeredi5e183482001-10-31 14:52:35 +0000814static unsigned int iattr_to_fattr(struct iattr *iattr,
815 struct fuse_attr *fattr)
816{
817 unsigned int ivalid = iattr->ia_valid;
818 unsigned int fvalid = 0;
819
820 memset(fattr, 0, sizeof(*fattr));
821
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000822 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000823 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000824 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000825 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000826 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000827 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000828 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000829 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
830 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000831 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000832 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000833#ifdef KERNEL_2_6
834 fattr->atime = iattr->ia_atime.tv_sec;
835 fattr->mtime = iattr->ia_mtime.tv_sec;
836#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000837 fattr->atime = iattr->ia_atime;
838 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000839#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000840 }
841
842 return fvalid;
843}
844
845static int fuse_setattr(struct dentry *entry, struct iattr *attr)
846{
847 struct inode *inode = entry->d_inode;
848 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000849 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000850 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000851 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000852 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000853 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000854 int is_truncate = 0;
855
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000856 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
857 err = inode_change_ok(inode, attr);
858 if (err)
859 return err;
860 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000861
Miklos Szeredi069c9502004-07-16 16:17:02 +0000862 if (attr->ia_valid & ATTR_SIZE) {
863 unsigned long limit;
864 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000865#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000866 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000867#else
868 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000869#endif
870 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000871 send_sig(SIGXFSZ, current, 0);
872 return -EFBIG;
873 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000874 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000875
876 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000877 if (!req)
878 return -ERESTARTSYS;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000879
Miklos Szeredi069c9502004-07-16 16:17:02 +0000880 if (is_truncate)
881 down_write(&fi->write_sem);
882
Miklos Szeredi43696432001-11-18 19:15:05 +0000883 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000884 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000885 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000886 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000887 req->in.numargs = 1;
888 req->in.args[0].size = sizeof(inarg);
889 req->in.args[0].value = &inarg;
890 req->out.numargs = 1;
891 req->out.args[0].size = sizeof(outarg);
892 req->out.args[0].value = &outarg;
893 request_send(fc, req);
894 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000896
897 if (!err) {
898 if (is_truncate) {
899 loff_t origsize = i_size_read(inode);
900 i_size_write(inode, outarg.attr.size);
901 up_write(&fi->write_sem);
902 if (origsize > outarg.attr.size)
903 vmtruncate(inode, outarg.attr.size);
904 }
905 change_attributes(inode, &outarg.attr);
906 fi->i_time = time_to_jiffies(outarg.attr_valid,
907 outarg.attr_valid_nsec);
908 } else if (is_truncate)
909 up_write(&fi->write_sem);
910
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000911 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000912}
913
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000914static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000915{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000916 if (!entry->d_inode)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000917 return 0;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000918 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000919 struct inode *inode = entry->d_inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000920 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000921 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000922 int version;
923 int ret;
924
925 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
926 &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000927 if (ret)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000928 return 0;
929
Miklos Szeredia13d9002004-11-02 17:32:03 +0000930 if (outarg.nodeid != fi->nodeid)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000931 return 0;
932
933 change_attributes(inode, &outarg.attr);
934 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000935 entry->d_time = time_to_jiffies(outarg.entry_valid,
936 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000937 fi->i_time = time_to_jiffies(outarg.attr_valid,
938 outarg.attr_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000939 }
940 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000941}
942
Miklos Szeredif85ab242004-01-07 12:16:45 +0000943#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000944static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
945 struct kstat *stat)
946{
947 struct inode *inode = entry->d_inode;
948 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000949 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000950 generic_fillattr(inode, stat);
951
952 return err;
953}
954
955static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
956 struct nameidata *nd)
957{
Miklos Szeredie815c032004-01-19 18:20:49 +0000958 struct inode *inode;
959 int err = fuse_lookup_iget(dir, entry, &inode);
960 if (err)
961 return ERR_PTR(err);
962 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000963}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000964#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000965static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
966{
967 struct inode *inode;
968 struct dentry *alias;
969
970 int err = fuse_lookup_iget(dir, entry, &inode);
971 if (err)
972 return ERR_PTR(err);
973
974 if (inode && S_ISDIR(inode->i_mode) &&
975 (alias = d_find_alias(inode)) != NULL) {
976 dput(alias);
977 iput(inode);
978 printk("fuse: cannot assign an existing directory\n");
979 return ERR_PTR(-EPROTO);
980 }
981
982 d_add(entry, inode);
983 return NULL;
984}
985
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000986static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi689f5632004-05-04 08:49:16 +0000987 int rdev)
988{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000989 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000990}
991
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000992static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000993{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000994 return fuse_dentry_revalidate(entry, NULL);
995}
996
997static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
998{
999 return fuse_create(dir, entry, mode, NULL);
1000}
1001
1002static int fuse_permission_2_4(struct inode *inode, int mask)
1003{
1004 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001005}
1006#endif /* KERNEL_2_6 */
1007
1008#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +00001009#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001010static int fuse_setxattr(struct dentry *entry, const char *name,
1011 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001012#else
1013static int fuse_setxattr(struct dentry *entry, const char *name,
1014 void *value, size_t size, int flags)
1015#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001016{
1017 struct inode *inode = entry->d_inode;
1018 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001019 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001020 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001021 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001022 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001023
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001024 if (size > FUSE_XATTR_SIZE_MAX)
1025 return -E2BIG;
1026
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001027 if (fc->no_setxattr)
1028 return -EOPNOTSUPP;
1029
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001030 req = fuse_get_request(fc);
1031 if (!req)
1032 return -ERESTARTSYS;
1033
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001034 memset(&inarg, 0, sizeof(inarg));
1035 inarg.size = size;
1036 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001037 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001038 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001039 req->in.numargs = 3;
1040 req->in.args[0].size = sizeof(inarg);
1041 req->in.args[0].value = &inarg;
1042 req->in.args[1].size = strlen(name) + 1;
1043 req->in.args[1].value = name;
1044 req->in.args[2].size = size;
1045 req->in.args[2].value = value;
1046 request_send(fc, req);
1047 err = req->out.h.error;
1048 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001049 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001050 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001051 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001052 fuse_put_request(fc, req);
1053 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001054}
1055
1056static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1057 void *value, size_t size)
1058{
1059 struct inode *inode = entry->d_inode;
1060 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001061 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001062 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001063 struct fuse_getxattr_in inarg;
1064 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001065 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001066
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001067 if (fc->no_getxattr)
1068 return -EOPNOTSUPP;
1069
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001070 req = fuse_get_request(fc);
1071 if (!req)
1072 return -ERESTARTSYS;
1073
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001074 memset(&inarg, 0, sizeof(inarg));
1075 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001076 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001077 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001078 req->in.numargs = 2;
1079 req->in.args[0].size = sizeof(inarg);
1080 req->in.args[0].value = &inarg;
1081 req->in.args[1].size = strlen(name) + 1;
1082 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001083 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001084 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001085 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001086 req->out.argvar = 1;
1087 req->out.args[0].size = size;
1088 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001089 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001090 req->out.args[0].size = sizeof(outarg);
1091 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001092 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001093 request_send(fc, req);
1094 ret = req->out.h.error;
1095 if (!ret)
1096 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001097 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001098 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001099 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001100 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001101 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001102 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001103 fuse_put_request(fc, req);
1104 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001105}
1106
1107static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1108{
1109 struct inode *inode = entry->d_inode;
1110 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001111 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001112 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001113 struct fuse_getxattr_in inarg;
1114 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001115 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001116
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001117 if (fc->no_listxattr)
1118 return -EOPNOTSUPP;
1119
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001120 req = fuse_get_request(fc);
1121 if (!req)
1122 return -ERESTARTSYS;
1123
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001124 memset(&inarg, 0, sizeof(inarg));
1125 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001126 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001127 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001128 req->in.numargs = 1;
1129 req->in.args[0].size = sizeof(inarg);
1130 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001131 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001132 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001133 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001134 req->out.argvar = 1;
1135 req->out.args[0].size = size;
1136 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001137 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001138 req->out.args[0].size = sizeof(outarg);
1139 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001140 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001141 request_send(fc, req);
1142 ret = req->out.h.error;
1143 if (!ret)
1144 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001145 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001146 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001147 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001148 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001149 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001150 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001151 fuse_put_request(fc, req);
1152 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001153}
1154
1155static int fuse_removexattr(struct dentry *entry, const char *name)
1156{
1157 struct inode *inode = entry->d_inode;
1158 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001159 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001160 struct fuse_req *req;
1161 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001162
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001163 if (fc->no_removexattr)
1164 return -EOPNOTSUPP;
1165
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001166 req = fuse_get_request(fc);
1167 if (!req)
1168 return -ERESTARTSYS;
1169
1170 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001171 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001172 req->in.numargs = 1;
1173 req->in.args[0].size = strlen(name) + 1;
1174 req->in.args[0].value = name;
1175 request_send(fc, req);
1176 err = req->out.h.error;
1177 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001178 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001179 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001180 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001181 fuse_put_request(fc, req);
1182 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001183}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001184#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001185
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001186static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001187 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001188 .mkdir = fuse_mkdir,
1189 .symlink = fuse_symlink,
1190 .unlink = fuse_unlink,
1191 .rmdir = fuse_rmdir,
1192 .rename = fuse_rename,
1193 .link = fuse_link,
1194 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001195#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001196 .create = fuse_create,
1197 .mknod = fuse_mknod,
1198 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001199 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001200#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001201 .create = fuse_create_2_4,
1202 .mknod = fuse_mknod_2_4,
1203 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001204 .revalidate = fuse_revalidate,
1205#endif
1206#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001207 .setxattr = fuse_setxattr,
1208 .getxattr = fuse_getxattr,
1209 .listxattr = fuse_listxattr,
1210 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001211#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001212};
1213
1214static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001215 .read = generic_read_dir,
1216 .readdir = fuse_readdir,
1217 .open = fuse_dir_open,
1218 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001219};
1220
1221static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001222 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001223#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001224 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001225 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001226#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001227 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001228 .revalidate = fuse_revalidate,
1229#endif
1230#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001231 .setxattr = fuse_setxattr,
1232 .getxattr = fuse_getxattr,
1233 .listxattr = fuse_listxattr,
1234 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001235#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001236};
1237
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001238static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001239 .setattr = fuse_setattr,
1240 .readlink = fuse_readlink,
1241 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001242#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001243 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001244#else
1245 .revalidate = fuse_revalidate,
1246#endif
1247#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001248 .setxattr = fuse_setxattr,
1249 .getxattr = fuse_getxattr,
1250 .listxattr = fuse_listxattr,
1251 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001252#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001253};
1254
Miklos Szeredi307242f2004-01-26 11:28:44 +00001255static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001256#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001257 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001258#else
1259 .d_revalidate = fuse_dentry_revalidate_2_4,
1260#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001261};