blob: a56f51393ec4a40ee79143b289440a97ee783e2a [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;
Miklos Szeredi039322d2004-12-01 18:39:12 +000095 if (get_node_id(inode) == nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +000096 return 1;
97 else
98 return 0;
99}
100
101static int fuse_inode_set(struct inode *inode, void *_nodeidp)
102{
103 unsigned long nodeid = *(unsigned long *) _nodeidp;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000104 get_fuse_inode(inode)->nodeid = nodeid;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000105 return 0;
106}
107
108struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
109 int generation, struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000110{
111 struct inode *inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000112 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000113
Miklos Szeredia13d9002004-11-02 17:32:03 +0000114 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
115 if (!inode)
116 return NULL;
Miklos Szeredie815c032004-01-19 18:20:49 +0000117
Miklos Szeredia13d9002004-11-02 17:32:03 +0000118 if ((inode->i_state & I_NEW)) {
119 inode->i_generation = generation;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000120 inode->i_data.backing_dev_info = &fc->bdi;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000121 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;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000138 if (inode->u.generic_ip && get_node_id(inode) == nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000139 return 1;
140 else
141 return 0;
142}
143
144struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
145 int generation, struct fuse_attr *attr, int version)
146{
147 struct inode *inode;
148
149 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
150 if (!inode)
151 return NULL;
152
153 if (!inode->u.generic_ip) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000154 get_fuse_inode(inode)->nodeid = nodeid;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000155 inode->u.generic_ip = inode;
156 inode->i_generation = generation;
157 fuse_init_inode(inode, attr);
158 } else if (inode->i_generation != generation)
159 printk("fuse_iget: bad generation for node %lu\n", nodeid);
160
161 change_attributes(inode, attr);
162 inode->i_version = version;
163 return inode;
164}
165
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000166struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000167{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000168 struct inode *inode = iget4(sb, ino, fuse_inode_eq, &nodeid);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000169 if (inode && !inode->u.generic_ip) {
170 iput(inode);
171 inode = NULL;
172 }
173 return inode;
174}
Miklos Szeredia13d9002004-11-02 17:32:03 +0000175#endif
176
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000177static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req,
178 struct inode *dir, struct dentry *entry,
179 struct fuse_entry_out *outarg, int *version)
180{
181 req->in.h.opcode = FUSE_LOOKUP;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000182 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000183 req->in.numargs = 1;
184 req->in.args[0].size = entry->d_name.len + 1;
185 req->in.args[0].value = entry->d_name.name;
186 req->out.numargs = 1;
187 req->out.args[0].size = sizeof(struct fuse_entry_out);
188 req->out.args[0].value = outarg;
189 request_send(fc, req);
190 *version = req->out.h.unique;
191 return req->out.h.error;
192}
193
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000194static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000195 struct fuse_entry_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000197 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000198 struct fuse_req *req;
199 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000200
201 if (entry->d_name.len > FUSE_NAME_MAX)
202 return -ENAMETOOLONG;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000203 req = fuse_get_request(fc);
204 if (!req)
205 return -ERESTARTSYS;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000206
207 err = fuse_send_lookup(fc, req, dir, entry, outarg, version);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000208 fuse_put_request(fc, req);
209 return err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000210}
211
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000212static inline unsigned long time_to_jiffies(unsigned long sec,
213 unsigned long nsec)
214{
215 /* prevent wrapping of jiffies */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000216 if (sec + 1 >= LONG_MAX / HZ)
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000217 return 0;
218
219 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
220}
221
Miklos Szeredie815c032004-01-19 18:20:49 +0000222static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
223 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000224{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000225 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredie815c032004-01-19 18:20:49 +0000226 int err;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000227 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000228 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000229 struct inode *inode = NULL;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000230 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000231
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000232 if (entry->d_name.len > FUSE_NAME_MAX)
233 return -ENAMETOOLONG;
234 req = fuse_get_request(fc);
235 if (!req)
236 return -ERESTARTSYS;
237
238 err = fuse_send_lookup(fc, req, dir, entry, &outarg, &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000239 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000240 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000241 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000242 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000243 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000244 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000245 }
246 }
247 fuse_put_request(fc, req);
248 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000249 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000250
Miklos Szeredi069c9502004-07-16 16:17:02 +0000251 if (inode) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000252 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000253 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000254 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000255 fi->i_time = time_to_jiffies(outarg.attr_valid,
256 outarg.attr_valid_nsec);
257 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000258
Miklos Szeredi307242f2004-01-26 11:28:44 +0000259 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000260 *inodep = inode;
261 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000262}
263
Miklos Szeredi069c9502004-07-16 16:17:02 +0000264static void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000265{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000266 get_fuse_inode(inode)->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000267}
268
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000269static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
270 struct inode *dir, struct dentry *entry,
271 struct fuse_entry_out *outarg, int version,
272 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000273{
274 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000275 struct fuse_inode *fi;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000276 inode = fuse_iget(dir->i_sb, outarg->nodeid, outarg->generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000277 &outarg->attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000278 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000279 fuse_send_forget(fc, req, outarg->nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000280 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000281 }
282 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000283
284 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000285 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000286 iput(inode);
287 printk("fuse_mknod: inode has wrong type\n");
Miklos Szeredi064efb02004-11-09 17:30:29 +0000288 return -EPROTO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000289 }
290
Miklos Szerediad051c32004-07-02 09:22:50 +0000291 entry->d_time = time_to_jiffies(outarg->entry_valid,
292 outarg->entry_valid_nsec);
293
Miklos Szeredi039322d2004-12-01 18:39:12 +0000294 fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000295 fi->i_time = time_to_jiffies(outarg->attr_valid,
296 outarg->attr_valid_nsec);
297
Miklos Szeredi76f65782004-02-19 16:55:40 +0000298 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000299 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000300 return 0;
301}
302
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000303static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000304 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000305{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000306 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000307 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000308 struct fuse_mknod_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000309 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000310 int err;
311
312 if (!req)
313 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000314
315 memset(&inarg, 0, sizeof(inarg));
316 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000317 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000318 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000319 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000320 req->in.numargs = 2;
321 req->in.args[0].size = sizeof(inarg);
322 req->in.args[0].value = &inarg;
323 req->in.args[1].size = entry->d_name.len + 1;
324 req->in.args[1].value = entry->d_name.name;
325 req->out.numargs = 1;
326 req->out.args[0].size = sizeof(outarg);
327 req->out.args[0].value = &outarg;
328 request_send(fc, req);
329 err = req->out.h.error;
330 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000331 err = lookup_new_entry(fc, req, dir, entry, &outarg,
332 req->out.h.unique, mode);
333 else
334 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000336}
337
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000338static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
339 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000340{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000341 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342}
343
Miklos Szeredib483c932001-10-29 14:57:57 +0000344static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
345{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000346 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000347 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000348 struct fuse_mkdir_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000349 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000350 int err;
351
352 if (!req)
353 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000354
355 memset(&inarg, 0, sizeof(inarg));
356 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000357 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000358 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000359 req->in.numargs = 2;
360 req->in.args[0].size = sizeof(inarg);
361 req->in.args[0].value = &inarg;
362 req->in.args[1].size = entry->d_name.len + 1;
363 req->in.args[1].value = entry->d_name.name;
364 req->out.numargs = 1;
365 req->out.args[0].size = sizeof(outarg);
366 req->out.args[0].value = &outarg;
367 request_send(fc, req);
368 err = req->out.h.error;
369 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000370 err = lookup_new_entry(fc, req, dir, entry, &outarg,
371 req->out.h.unique, S_IFDIR);
372 else
373 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000374 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000375}
376
377static int fuse_symlink(struct inode *dir, struct dentry *entry,
378 const char *link)
379{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000380 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000381 struct fuse_req *req;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000382 struct fuse_entry_out outarg;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000383 unsigned len = strlen(link) + 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000384 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000385
386 if (len > FUSE_SYMLINK_MAX)
387 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000388
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000389 req = fuse_get_request(fc);
390 if (!req)
391 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000392
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000393 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000394 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000395 req->in.numargs = 2;
396 req->in.args[0].size = entry->d_name.len + 1;
397 req->in.args[0].value = entry->d_name.name;
398 req->in.args[1].size = len;
399 req->in.args[1].value = link;
400 req->out.numargs = 1;
401 req->out.args[0].size = sizeof(outarg);
402 req->out.args[0].value = &outarg;
403 request_send(fc, req);
404 err = req->out.h.error;
405 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000406 err = lookup_new_entry(fc, req, dir, entry, &outarg,
407 req->out.h.unique, S_IFLNK);
408 else
409 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000410 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000411}
412
Miklos Szeredib5958612004-02-20 14:10:49 +0000413static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000414{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000415 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000416 struct fuse_req *req = fuse_get_request(fc);
417 int err;
418
419 if (!req)
420 return -ERESTARTSYS;
Miklos Szeredib483c932001-10-29 14:57:57 +0000421
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000422 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000423 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000424 req->in.numargs = 1;
425 req->in.args[0].size = entry->d_name.len + 1;
426 req->in.args[0].value = entry->d_name.name;
427 request_send(fc, req);
428 err = req->out.h.error;
429 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000430 struct inode *inode = entry->d_inode;
431
Miklos Szeredib5958612004-02-20 14:10:49 +0000432 /* Set nlink to zero so the inode can be cleared, if
433 the inode does have more links this will be
434 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000435 inode->i_nlink = 0;
436 fuse_invalidate_attr(inode);
437 fuse_invalidate_attr(dir);
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000438 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000439 fuse_put_request(fc, req);
440 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000441}
442
443static int fuse_rmdir(struct inode *dir, struct dentry *entry)
444{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000445 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000446 struct fuse_req *req = fuse_get_request(fc);
447 int err;
448
449 if (!req)
450 return -ERESTARTSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000451
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000452 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000453 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000454 req->in.numargs = 1;
455 req->in.args[0].size = entry->d_name.len + 1;
456 req->in.args[0].value = entry->d_name.name;
457 request_send(fc, req);
458 err = req->out.h.error;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000459 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000460 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000461 fuse_invalidate_attr(dir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000462 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000463 fuse_put_request(fc, req);
464 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000465}
466
467static int fuse_rename(struct inode *olddir, struct dentry *oldent,
468 struct inode *newdir, struct dentry *newent)
469{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000470 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000471 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000472 struct fuse_rename_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000473 int err;
474
475 if (!req)
476 return -ERESTARTSYS;
477
Miklos Szeredi43696432001-11-18 19:15:05 +0000478 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000479 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000480 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000481 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000482 req->in.numargs = 3;
483 req->in.args[0].size = sizeof(inarg);
484 req->in.args[0].value = &inarg;
485 req->in.args[1].size = oldent->d_name.len + 1;
486 req->in.args[1].value = oldent->d_name.name;
487 req->in.args[2].size = newent->d_name.len + 1;
488 req->in.args[2].value = newent->d_name.name;
489 request_send(fc, req);
490 err = req->out.h.error;
491 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000492 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000493 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000494 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000495 fuse_invalidate_attr(newdir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000496 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000497 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000498}
499
500static int fuse_link(struct dentry *entry, struct inode *newdir,
501 struct dentry *newent)
502{
503 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000504 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000505 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000506 struct fuse_link_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000507 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000508 int err;
509
510 if (!req)
511 return -ERESTARTSYS;
512
Miklos Szeredi43696432001-11-18 19:15:05 +0000513 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000514 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000515 req->in.h.opcode = FUSE_LINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000516 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000517 req->in.numargs = 2;
518 req->in.args[0].size = sizeof(inarg);
519 req->in.args[0].value = &inarg;
520 req->in.args[1].size = newent->d_name.len + 1;
521 req->in.args[1].value = newent->d_name.name;
522 req->out.numargs = 1;
523 req->out.args[0].size = sizeof(outarg);
524 req->out.args[0].value = &outarg;
525 request_send(fc, req);
526 err = req->out.h.error;
527 if (!err) {
528 /* Invalidate old entry, so attributes are refreshed */
529 d_invalidate(entry);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000530 err = lookup_new_entry(fc, req, newdir, newent, &outarg,
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000531 req->out.h.unique, inode->i_mode);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000532 } else
533 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000534 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000535}
536
Miklos Szeredif85ab242004-01-07 12:16:45 +0000537int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000538{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000539 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000540 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000541 struct fuse_attr_out arg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000542 int err;
543
544 if (!req)
545 return -ERESTARTSYS;
546
547 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000548 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000549 req->out.numargs = 1;
550 req->out.args[0].size = sizeof(arg);
551 req->out.args[0].value = &arg;
552 request_send(fc, req);
553 err = req->out.h.error;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000554 if (!err) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000555 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000556 change_attributes(inode, &arg.attr);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000557 fi->i_time = time_to_jiffies(arg.attr_valid,
558 arg.attr_valid_nsec);
559 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000560 fuse_put_request(fc, req);
561 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000562}
563
Miklos Szeredife25def2001-12-20 15:38:05 +0000564static int fuse_revalidate(struct dentry *entry)
565{
566 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000567 struct fuse_inode *fi = get_fuse_inode(inode);
568 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000569
Miklos Szeredi039322d2004-12-01 18:39:12 +0000570 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000571 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000572 current->fsuid != fc->uid &&
573 (!(fc->flags & FUSE_ALLOW_ROOT) ||
574 current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000575 return -EACCES;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000576 } else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000577 return 0;
578
Miklos Szeredif85ab242004-01-07 12:16:45 +0000579 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000580}
581
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000582static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000583{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000584 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000585
Miklos Szeredi180ff692004-11-01 16:01:05 +0000586 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
587 (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000588 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000589 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000590 int err;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000591#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000592 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000593#else
594 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000595#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000596
597 /* If permission is denied, try to refresh file
598 attributes. This is also needed, because the root
599 node will at first have no permissions */
600
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000601 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000602 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000603 if (!err)
604#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
Miklos Szeredi83a07442004-11-30 18:25:20 +0000607 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000608#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000609 }
610
611 /* FIXME: Need some mechanism to revoke permissions:
612 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000613 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000614 continue to allow access to the file/directory.
615
616 This is actually not so grave, since the user can
617 simply keep access to the file/directory anyway by
618 keeping it open... */
619
620 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000621 } else {
622 int mode = inode->i_mode;
623 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
624 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
625 return -EROFS;
626 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
627 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000628 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000629 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000630}
631
Miklos Szeredib483c932001-10-29 14:57:57 +0000632static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
633 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000634{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000635 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000636 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000637 size_t reclen = FUSE_DIRENT_SIZE(dirent);
638 int over;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000639 if (dirent->namelen > NAME_MAX) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000640 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000641 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000642 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000643 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000644 break;
645
646 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000647 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000648 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000649 break;
650
Miklos Szeredib483c932001-10-29 14:57:57 +0000651 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000652 file->f_pos += reclen;
653 nbytes -= reclen;
654 }
655
Miklos Szeredib483c932001-10-29 14:57:57 +0000656 return 0;
657}
658
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000659static int fuse_checkdir(struct file *cfile, struct file *file)
660{
661 struct inode *inode;
662 if (!cfile) {
663 printk("fuse_getdir: invalid file\n");
664 return -EPROTO;
665 }
666 inode = cfile->f_dentry->d_inode;
667 if (!S_ISREG(inode->i_mode)) {
668 printk("fuse_getdir: not a regular file\n");
669 fput(cfile);
670 return -EPROTO;
671 }
672
673 file->private_data = cfile;
674 return 0;
675}
676
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000677static int fuse_getdir(struct file *file)
678{
679 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000680 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000681 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000682 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000683 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000684
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000685 if (!req)
686 return -ERESTARTSYS;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000687
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000688 req->in.h.opcode = FUSE_GETDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000689 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000690 req->out.numargs = 1;
691 req->out.args[0].size = sizeof(struct fuse_getdir_out);
692 req->out.args[0].value = &outarg;
693 request_send(fc, req);
694 err = req->out.h.error;
695 if (!err)
696 err = fuse_checkdir(outarg.file, file);
697 fuse_put_request(fc, req);
698 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000699}
700
Miklos Szeredib483c932001-10-29 14:57:57 +0000701static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
702{
703 struct file *cfile = file->private_data;
704 char *buf;
705 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000706
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000707 if (!cfile) {
708 ret = fuse_getdir(file);
709 if (ret)
710 return ret;
711
712 cfile = file->private_data;
713 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000714
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000715 buf = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000716 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000717 return -ENOMEM;
Miklos Szeredie815c032004-01-19 18:20:49 +0000718
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000719 ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000720 if (ret < 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000721 printk("fuse_readdir: failed to read container file\n");
722 else
723 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
724
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000725 free_page((unsigned long) buf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000726 return ret;
727}
728
Miklos Szeredi05033042001-11-13 16:11:35 +0000729static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000730{
731 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000732 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000733 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000734 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000735
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000736 if (!req)
737 return ERR_PTR(-ERESTARTSYS);
738
Miklos Szeredi05033042001-11-13 16:11:35 +0000739 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000740 if (!link) {
741 link = ERR_PTR(-ENOMEM);
742 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000743 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000744 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000745 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000746 req->out.argvar = 1;
747 req->out.numargs = 1;
748 req->out.args[0].size = PAGE_SIZE - 1;
749 req->out.args[0].value = link;
750 request_send(fc, req);
751 if (req->out.h.error) {
752 free_page((unsigned long) link);
753 link = ERR_PTR(req->out.h.error);
754 } else
755 link[req->out.args[0].size] = '\0';
756 out:
757 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000758 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000759}
760
761static void free_link(char *link)
762{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000763 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000764 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000765}
766
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000767static int fuse_readlink(struct dentry *dentry, char __user *buffer,
768 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000769{
770 int ret;
771 char *link;
772
Miklos Szeredi05033042001-11-13 16:11:35 +0000773 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000774 ret = vfs_readlink(dentry, buffer, buflen, link);
775 free_link(link);
776 return ret;
777}
778
779static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
780{
781 int ret;
782 char *link;
783
Miklos Szeredi05033042001-11-13 16:11:35 +0000784 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000785 ret = vfs_follow_link(nd, link);
786 free_link(link);
787 return ret;
788}
789
790static int fuse_dir_open(struct inode *inode, struct file *file)
791{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000792 file->private_data = NULL;
793 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000794}
795
796static int fuse_dir_release(struct inode *inode, struct file *file)
797{
798 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000799
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000800 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000801 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000802
803 return 0;
804}
805
Miklos Szeredi83a07442004-11-30 18:25:20 +0000806static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000807{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000808 unsigned ivalid = iattr->ia_valid;
809 unsigned fvalid = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000810
811 memset(fattr, 0, sizeof(*fattr));
812
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000813 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000814 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000815 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000816 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000817 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000818 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000819 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000820 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
821 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000822 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000823 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000824#ifdef KERNEL_2_6
825 fattr->atime = iattr->ia_atime.tv_sec;
826 fattr->mtime = iattr->ia_mtime.tv_sec;
827#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000828 fattr->atime = iattr->ia_atime;
829 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000830#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000831 }
832
833 return fvalid;
834}
835
836static int fuse_setattr(struct dentry *entry, struct iattr *attr)
837{
838 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000839 struct fuse_conn *fc = get_fuse_conn(inode);
840 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000841 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000842 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000843 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000844 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000845 int is_truncate = 0;
846
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000847 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
848 err = inode_change_ok(inode, attr);
849 if (err)
850 return err;
851 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000852
Miklos Szeredi069c9502004-07-16 16:17:02 +0000853 if (attr->ia_valid & ATTR_SIZE) {
854 unsigned long limit;
855 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000856#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000857 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000858#else
859 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000860#endif
861 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000862 send_sig(SIGXFSZ, current, 0);
863 return -EFBIG;
864 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000865 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000866
867 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000868 if (!req)
869 return -ERESTARTSYS;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000870
Miklos Szeredi069c9502004-07-16 16:17:02 +0000871 if (is_truncate)
872 down_write(&fi->write_sem);
873
Miklos Szeredi43696432001-11-18 19:15:05 +0000874 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000875 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000876 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000877 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000878 req->in.numargs = 1;
879 req->in.args[0].size = sizeof(inarg);
880 req->in.args[0].value = &inarg;
881 req->out.numargs = 1;
882 req->out.args[0].size = sizeof(outarg);
883 req->out.args[0].value = &outarg;
884 request_send(fc, req);
885 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000886 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000887
888 if (!err) {
889 if (is_truncate) {
890 loff_t origsize = i_size_read(inode);
891 i_size_write(inode, outarg.attr.size);
892 up_write(&fi->write_sem);
893 if (origsize > outarg.attr.size)
894 vmtruncate(inode, outarg.attr.size);
895 }
896 change_attributes(inode, &outarg.attr);
897 fi->i_time = time_to_jiffies(outarg.attr_valid,
898 outarg.attr_valid_nsec);
899 } else if (is_truncate)
900 up_write(&fi->write_sem);
901
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000902 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000903}
904
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000905static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000906{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000907 if (!entry->d_inode)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000908 return 0;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000909 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000910 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000911 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000912 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000913 int version;
914 int ret;
915
916 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
917 &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000918 if (ret)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000919 return 0;
920
Miklos Szeredi039322d2004-12-01 18:39:12 +0000921 if (outarg.nodeid != get_node_id(inode))
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000922 return 0;
923
924 change_attributes(inode, &outarg.attr);
925 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000926 entry->d_time = time_to_jiffies(outarg.entry_valid,
927 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000928 fi->i_time = time_to_jiffies(outarg.attr_valid,
929 outarg.attr_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000930 }
931 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000932}
933
Miklos Szeredif85ab242004-01-07 12:16:45 +0000934#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000935static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
936 struct kstat *stat)
937{
938 struct inode *inode = entry->d_inode;
939 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000940 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000941 generic_fillattr(inode, stat);
942
943 return err;
944}
945
946static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000947 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000948{
Miklos Szeredie815c032004-01-19 18:20:49 +0000949 struct inode *inode;
950 int err = fuse_lookup_iget(dir, entry, &inode);
951 if (err)
952 return ERR_PTR(err);
953 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000954}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000955#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000956static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
957{
958 struct inode *inode;
959 struct dentry *alias;
960
961 int err = fuse_lookup_iget(dir, entry, &inode);
962 if (err)
963 return ERR_PTR(err);
964
965 if (inode && S_ISDIR(inode->i_mode) &&
966 (alias = d_find_alias(inode)) != NULL) {
967 dput(alias);
968 iput(inode);
969 printk("fuse: cannot assign an existing directory\n");
970 return ERR_PTR(-EPROTO);
971 }
972
973 d_add(entry, inode);
974 return NULL;
975}
976
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000977static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000978 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000979{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000980 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000981}
982
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000983static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000984{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000985 return fuse_dentry_revalidate(entry, NULL);
986}
987
988static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
989{
990 return fuse_create(dir, entry, mode, NULL);
991}
992
993static int fuse_permission_2_4(struct inode *inode, int mask)
994{
995 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000996}
997#endif /* KERNEL_2_6 */
998
999#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +00001000#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001001static int fuse_setxattr(struct dentry *entry, const char *name,
1002 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001003#else
1004static int fuse_setxattr(struct dentry *entry, const char *name,
1005 void *value, size_t size, int flags)
1006#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001007{
1008 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001009 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001010 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001011 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001012 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001013
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001014 if (size > FUSE_XATTR_SIZE_MAX)
1015 return -E2BIG;
1016
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001017 if (fc->no_setxattr)
1018 return -EOPNOTSUPP;
1019
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001020 req = fuse_get_request(fc);
1021 if (!req)
1022 return -ERESTARTSYS;
1023
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001024 memset(&inarg, 0, sizeof(inarg));
1025 inarg.size = size;
1026 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001027 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001028 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001029 req->in.numargs = 3;
1030 req->in.args[0].size = sizeof(inarg);
1031 req->in.args[0].value = &inarg;
1032 req->in.args[1].size = strlen(name) + 1;
1033 req->in.args[1].value = name;
1034 req->in.args[2].size = size;
1035 req->in.args[2].value = value;
1036 request_send(fc, req);
1037 err = req->out.h.error;
1038 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001039 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001040 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001041 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001042 fuse_put_request(fc, req);
1043 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001044}
1045
1046static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1047 void *value, size_t size)
1048{
1049 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001050 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001051 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001052 struct fuse_getxattr_in inarg;
1053 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001054 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001055
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001056 if (fc->no_getxattr)
1057 return -EOPNOTSUPP;
1058
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001059 req = fuse_get_request(fc);
1060 if (!req)
1061 return -ERESTARTSYS;
1062
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001063 memset(&inarg, 0, sizeof(inarg));
1064 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001065 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001066 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001067 req->in.numargs = 2;
1068 req->in.args[0].size = sizeof(inarg);
1069 req->in.args[0].value = &inarg;
1070 req->in.args[1].size = strlen(name) + 1;
1071 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001072 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001073 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001074 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001075 req->out.argvar = 1;
1076 req->out.args[0].size = size;
1077 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001078 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001079 req->out.args[0].size = sizeof(outarg);
1080 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001081 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001082 request_send(fc, req);
1083 ret = req->out.h.error;
1084 if (!ret)
1085 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001086 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001087 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001088 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001089 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001090 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001091 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001092 fuse_put_request(fc, req);
1093 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001094}
1095
1096static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1097{
1098 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001099 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001100 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001101 struct fuse_getxattr_in inarg;
1102 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001103 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001104
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001105 if (fc->no_listxattr)
1106 return -EOPNOTSUPP;
1107
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001108 req = fuse_get_request(fc);
1109 if (!req)
1110 return -ERESTARTSYS;
1111
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001112 memset(&inarg, 0, sizeof(inarg));
1113 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001114 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001115 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001116 req->in.numargs = 1;
1117 req->in.args[0].size = sizeof(inarg);
1118 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001119 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001120 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001121 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001122 req->out.argvar = 1;
1123 req->out.args[0].size = size;
1124 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001125 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001126 req->out.args[0].size = sizeof(outarg);
1127 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001128 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001129 request_send(fc, req);
1130 ret = req->out.h.error;
1131 if (!ret)
1132 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001133 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001134 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001135 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001136 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001137 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001138 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001139 fuse_put_request(fc, req);
1140 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001141}
1142
1143static int fuse_removexattr(struct dentry *entry, const char *name)
1144{
1145 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001146 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001147 struct fuse_req *req;
1148 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001149
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001150 if (fc->no_removexattr)
1151 return -EOPNOTSUPP;
1152
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001153 req = fuse_get_request(fc);
1154 if (!req)
1155 return -ERESTARTSYS;
1156
1157 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001158 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001159 req->in.numargs = 1;
1160 req->in.args[0].size = strlen(name) + 1;
1161 req->in.args[0].value = name;
1162 request_send(fc, req);
1163 err = req->out.h.error;
1164 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001165 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001166 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001167 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001168 fuse_put_request(fc, req);
1169 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001170}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001171#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001172
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001173static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001174 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001175 .mkdir = fuse_mkdir,
1176 .symlink = fuse_symlink,
1177 .unlink = fuse_unlink,
1178 .rmdir = fuse_rmdir,
1179 .rename = fuse_rename,
1180 .link = fuse_link,
1181 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001182#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001183 .create = fuse_create,
1184 .mknod = fuse_mknod,
1185 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001186 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001187#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001188 .create = fuse_create_2_4,
1189 .mknod = fuse_mknod_2_4,
1190 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001191 .revalidate = fuse_revalidate,
1192#endif
1193#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001194 .setxattr = fuse_setxattr,
1195 .getxattr = fuse_getxattr,
1196 .listxattr = fuse_listxattr,
1197 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001198#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001199};
1200
1201static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001202 .read = generic_read_dir,
1203 .readdir = fuse_readdir,
1204 .open = fuse_dir_open,
1205 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001206};
1207
1208static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001209 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001210#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001211 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001212 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001213#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001214 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001215 .revalidate = fuse_revalidate,
1216#endif
1217#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001218 .setxattr = fuse_setxattr,
1219 .getxattr = fuse_getxattr,
1220 .listxattr = fuse_listxattr,
1221 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001222#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001223};
1224
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001225static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001226 .setattr = fuse_setattr,
1227 .readlink = fuse_readlink,
1228 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001229#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001230 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001231#else
1232 .revalidate = fuse_revalidate,
1233#endif
1234#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001235 .setxattr = fuse_setxattr,
1236 .getxattr = fuse_getxattr,
1237 .listxattr = fuse_listxattr,
1238 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001239#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001240};
1241
Miklos Szeredi307242f2004-01-26 11:28:44 +00001242static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001243#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001244 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001245#else
1246 .d_revalidate = fuse_dentry_revalidate_2_4,
1247#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001248};