blob: 412ffc88ddd91d12c746ace6d536efc38af763a9 [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;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000114 struct fuse_conn *fc = SB_FC(sb);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000115
Miklos Szeredia13d9002004-11-02 17:32:03 +0000116 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
117 if (!inode)
118 return NULL;
Miklos Szeredie815c032004-01-19 18:20:49 +0000119
Miklos Szeredia13d9002004-11-02 17:32:03 +0000120 if ((inode->i_state & I_NEW)) {
121 inode->i_generation = generation;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000122 inode->i_data.backing_dev_info = &fc->bdi;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000123 fuse_init_inode(inode, attr);
124 unlock_new_inode(inode);
125 } else if (inode->i_generation != generation)
126 printk("fuse_iget: bad generation for node %lu\n", nodeid);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000127
Miklos Szeredia13d9002004-11-02 17:32:03 +0000128 change_attributes(inode, attr);
129 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000130 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000131}
132
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000133struct inode *fuse_ilookup(struct super_block *sb, unsigned long nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000134{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000135 return ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000136}
137#else
138static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
139 unsigned long nodeid = *(unsigned long *) _nodeidp;
140 struct fuse_inode *fi = INO_FI(inode);
141 if (inode->u.generic_ip && fi->nodeid == nodeid)
142 return 1;
143 else
144 return 0;
145}
146
147struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
148 int generation, struct fuse_attr *attr, int version)
149{
150 struct inode *inode;
151
152 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
153 if (!inode)
154 return NULL;
155
156 if (!inode->u.generic_ip) {
157 struct fuse_inode *fi = INO_FI(inode);
158 fi->nodeid = nodeid;
159 inode->u.generic_ip = inode;
160 inode->i_generation = generation;
161 fuse_init_inode(inode, attr);
162 } else if (inode->i_generation != generation)
163 printk("fuse_iget: bad generation for node %lu\n", nodeid);
164
165 change_attributes(inode, attr);
166 inode->i_version = version;
167 return inode;
168}
169
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000170struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000171{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000172 struct inode *inode = iget4(sb, ino, fuse_inode_eq, &nodeid);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000173 if (inode && !inode->u.generic_ip) {
174 iput(inode);
175 inode = NULL;
176 }
177 return inode;
178}
Miklos Szeredia13d9002004-11-02 17:32:03 +0000179#endif
180
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000181static int fuse_send_lookup(struct fuse_conn *fc, struct fuse_req *req,
182 struct inode *dir, struct dentry *entry,
183 struct fuse_entry_out *outarg, int *version)
184{
Miklos Szeredia13d9002004-11-02 17:32:03 +0000185 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000186 req->in.h.opcode = FUSE_LOOKUP;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000187 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000188 req->in.numargs = 1;
189 req->in.args[0].size = entry->d_name.len + 1;
190 req->in.args[0].value = entry->d_name.name;
191 req->out.numargs = 1;
192 req->out.args[0].size = sizeof(struct fuse_entry_out);
193 req->out.args[0].value = outarg;
194 request_send(fc, req);
195 *version = req->out.h.unique;
196 return req->out.h.error;
197}
198
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000199static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000200 struct fuse_entry_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000201{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000202 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000203 struct fuse_req *req;
204 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000205
206 if (entry->d_name.len > FUSE_NAME_MAX)
207 return -ENAMETOOLONG;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000208 req = fuse_get_request(fc);
209 if (!req)
210 return -ERESTARTSYS;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000211
212 err = fuse_send_lookup(fc, req, dir, entry, outarg, version);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000213 fuse_put_request(fc, req);
214 return err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000215}
216
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000217static inline unsigned long time_to_jiffies(unsigned long sec,
218 unsigned long nsec)
219{
220 /* prevent wrapping of jiffies */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000221 if (sec + 1 >= LONG_MAX / HZ)
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000222 return 0;
223
224 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
225}
226
Miklos Szeredie815c032004-01-19 18:20:49 +0000227static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
228 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000229{
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000230 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredie815c032004-01-19 18:20:49 +0000231 int err;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000232 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000233 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000234 struct inode *inode = NULL;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000235 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000236
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000237 if (entry->d_name.len > FUSE_NAME_MAX)
238 return -ENAMETOOLONG;
239 req = fuse_get_request(fc);
240 if (!req)
241 return -ERESTARTSYS;
242
243 err = fuse_send_lookup(fc, req, dir, entry, &outarg, &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000244 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000245 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000246 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000247 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000248 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000249 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000250 }
251 }
252 fuse_put_request(fc, req);
253 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000254 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000255
Miklos Szeredi069c9502004-07-16 16:17:02 +0000256 if (inode) {
257 struct fuse_inode *fi = INO_FI(inode);
258 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000259 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000260 fi->i_time = time_to_jiffies(outarg.attr_valid,
261 outarg.attr_valid_nsec);
262 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000263
Miklos Szeredi307242f2004-01-26 11:28:44 +0000264 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000265 *inodep = inode;
266 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000267}
268
Miklos Szeredi069c9502004-07-16 16:17:02 +0000269static void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000270{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000271 struct fuse_inode *fi = INO_FI(inode);
272 fi->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000273}
274
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000275static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
276 struct inode *dir, struct dentry *entry,
277 struct fuse_entry_out *outarg, int version,
278 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000279{
280 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000281 struct fuse_inode *fi;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000282 inode = fuse_iget(dir->i_sb, outarg->nodeid, outarg->generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000283 &outarg->attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000284 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000285 fuse_send_forget(fc, req, outarg->nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000286 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000287 }
288 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000289
290 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000291 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000292 iput(inode);
293 printk("fuse_mknod: inode has wrong type\n");
Miklos Szeredi064efb02004-11-09 17:30:29 +0000294 return -EPROTO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000295 }
296
Miklos Szerediad051c32004-07-02 09:22:50 +0000297 entry->d_time = time_to_jiffies(outarg->entry_valid,
298 outarg->entry_valid_nsec);
299
Miklos Szeredi069c9502004-07-16 16:17:02 +0000300 fi = INO_FI(inode);
301 fi->i_time = time_to_jiffies(outarg->attr_valid,
302 outarg->attr_valid_nsec);
303
Miklos Szeredi76f65782004-02-19 16:55:40 +0000304 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000305 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000306 return 0;
307}
308
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000309static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000310 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000311{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000312 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000313 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000314 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000315 struct fuse_mknod_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000316 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000317 int err;
318
319 if (!req)
320 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000321
322 memset(&inarg, 0, sizeof(inarg));
323 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000324 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000326 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000327 req->in.numargs = 2;
328 req->in.args[0].size = sizeof(inarg);
329 req->in.args[0].value = &inarg;
330 req->in.args[1].size = entry->d_name.len + 1;
331 req->in.args[1].value = entry->d_name.name;
332 req->out.numargs = 1;
333 req->out.args[0].size = sizeof(outarg);
334 req->out.args[0].value = &outarg;
335 request_send(fc, req);
336 err = req->out.h.error;
337 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000338 err = lookup_new_entry(fc, req, dir, entry, &outarg,
339 req->out.h.unique, mode);
340 else
341 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000342 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000343}
344
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000345static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
346 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000347{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000348 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000349}
350
Miklos Szeredib483c932001-10-29 14:57:57 +0000351static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
352{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000353 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000354 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000355 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000356 struct fuse_mkdir_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000357 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000358 int err;
359
360 if (!req)
361 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000362
363 memset(&inarg, 0, sizeof(inarg));
364 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000365 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000366 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000367 req->in.numargs = 2;
368 req->in.args[0].size = sizeof(inarg);
369 req->in.args[0].value = &inarg;
370 req->in.args[1].size = entry->d_name.len + 1;
371 req->in.args[1].value = entry->d_name.name;
372 req->out.numargs = 1;
373 req->out.args[0].size = sizeof(outarg);
374 req->out.args[0].value = &outarg;
375 request_send(fc, req);
376 err = req->out.h.error;
377 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000378 err = lookup_new_entry(fc, req, dir, entry, &outarg,
379 req->out.h.unique, S_IFDIR);
380 else
381 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000382 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000383}
384
385static int fuse_symlink(struct inode *dir, struct dentry *entry,
386 const char *link)
387{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000388 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000389 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000390 struct fuse_req *req;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000391 struct fuse_entry_out outarg;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000392 unsigned len = strlen(link) + 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000393 int err;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000394
395 if (len > FUSE_SYMLINK_MAX)
396 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000397
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000398 req = fuse_get_request(fc);
399 if (!req)
400 return -ERESTARTSYS;
Miklos Szeredi43696432001-11-18 19:15:05 +0000401
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000402 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000403 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000404 req->in.numargs = 2;
405 req->in.args[0].size = entry->d_name.len + 1;
406 req->in.args[0].value = entry->d_name.name;
407 req->in.args[1].size = len;
408 req->in.args[1].value = link;
409 req->out.numargs = 1;
410 req->out.args[0].size = sizeof(outarg);
411 req->out.args[0].value = &outarg;
412 request_send(fc, req);
413 err = req->out.h.error;
414 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000415 err = lookup_new_entry(fc, req, dir, entry, &outarg,
416 req->out.h.unique, S_IFLNK);
417 else
418 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000419 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000420}
421
Miklos Szeredib5958612004-02-20 14:10:49 +0000422static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000423{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000424 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000425 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000426 struct fuse_req *req = fuse_get_request(fc);
427 int err;
428
429 if (!req)
430 return -ERESTARTSYS;
Miklos Szeredib483c932001-10-29 14:57:57 +0000431
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000432 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000433 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000434 req->in.numargs = 1;
435 req->in.args[0].size = entry->d_name.len + 1;
436 req->in.args[0].value = entry->d_name.name;
437 request_send(fc, req);
438 err = req->out.h.error;
439 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000440 struct inode *inode = entry->d_inode;
441
Miklos Szeredib5958612004-02-20 14:10:49 +0000442 /* Set nlink to zero so the inode can be cleared, if
443 the inode does have more links this will be
444 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000445 inode->i_nlink = 0;
446 fuse_invalidate_attr(inode);
447 fuse_invalidate_attr(dir);
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000448 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000449 fuse_put_request(fc, req);
450 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000451}
452
453static int fuse_rmdir(struct inode *dir, struct dentry *entry)
454{
Miklos Szeredib5958612004-02-20 14:10:49 +0000455 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000456 struct fuse_inode *fi = INO_FI(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000457 struct fuse_req *req = fuse_get_request(fc);
458 int err;
459
460 if (!req)
461 return -ERESTARTSYS;
Miklos Szeredib5958612004-02-20 14:10:49 +0000462
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000463 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000464 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000465 req->in.numargs = 1;
466 req->in.args[0].size = entry->d_name.len + 1;
467 req->in.args[0].value = entry->d_name.name;
468 request_send(fc, req);
469 err = req->out.h.error;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000470 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000471 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000472 fuse_invalidate_attr(dir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000473 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000474 fuse_put_request(fc, req);
475 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000476}
477
478static int fuse_rename(struct inode *olddir, struct dentry *oldent,
479 struct inode *newdir, struct dentry *newent)
480{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000481 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000482 struct fuse_inode *oldfi = INO_FI(olddir);
483 struct fuse_inode *newfi = INO_FI(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000484 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000485 struct fuse_rename_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000486 int err;
487
488 if (!req)
489 return -ERESTARTSYS;
490
Miklos Szeredi43696432001-11-18 19:15:05 +0000491 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia13d9002004-11-02 17:32:03 +0000492 inarg.newdir = newfi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000493 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000494 req->in.h.nodeid = oldfi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000495 req->in.numargs = 3;
496 req->in.args[0].size = sizeof(inarg);
497 req->in.args[0].value = &inarg;
498 req->in.args[1].size = oldent->d_name.len + 1;
499 req->in.args[1].value = oldent->d_name.name;
500 req->in.args[2].size = newent->d_name.len + 1;
501 req->in.args[2].value = newent->d_name.name;
502 request_send(fc, req);
503 err = req->out.h.error;
504 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000505 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000506 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000507 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000508 fuse_invalidate_attr(newdir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000509 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000510 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000511}
512
513static int fuse_link(struct dentry *entry, struct inode *newdir,
514 struct dentry *newent)
515{
516 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000517 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000518 struct fuse_inode *fi = INO_FI(inode);
519 struct fuse_inode *newfi = INO_FI(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000520 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000521 struct fuse_link_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000522 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000523 int err;
524
525 if (!req)
526 return -ERESTARTSYS;
527
Miklos Szeredi43696432001-11-18 19:15:05 +0000528 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia13d9002004-11-02 17:32:03 +0000529 inarg.newdir = newfi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000530 req->in.h.opcode = FUSE_LINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000531 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000532 req->in.numargs = 2;
533 req->in.args[0].size = sizeof(inarg);
534 req->in.args[0].value = &inarg;
535 req->in.args[1].size = newent->d_name.len + 1;
536 req->in.args[1].value = newent->d_name.name;
537 req->out.numargs = 1;
538 req->out.args[0].size = sizeof(outarg);
539 req->out.args[0].value = &outarg;
540 request_send(fc, req);
541 err = req->out.h.error;
542 if (!err) {
543 /* Invalidate old entry, so attributes are refreshed */
544 d_invalidate(entry);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000545 err = lookup_new_entry(fc, req, newdir, newent, &outarg,
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000546 req->out.h.unique, inode->i_mode);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000547 } else
548 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000549 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000550}
551
Miklos Szeredif85ab242004-01-07 12:16:45 +0000552int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000553{
Miklos Szeredi069c9502004-07-16 16:17:02 +0000554 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000555 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000556 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000557 struct fuse_attr_out arg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000558 int err;
559
560 if (!req)
561 return -ERESTARTSYS;
562
563 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000564 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000565 req->out.numargs = 1;
566 req->out.args[0].size = sizeof(arg);
567 req->out.args[0].value = &arg;
568 request_send(fc, req);
569 err = req->out.h.error;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000570 if (!err) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000571 change_attributes(inode, &arg.attr);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000572 fi->i_time = time_to_jiffies(arg.attr_valid,
573 arg.attr_valid_nsec);
574 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000575 fuse_put_request(fc, req);
576 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000577}
578
Miklos Szeredife25def2001-12-20 15:38:05 +0000579static int fuse_revalidate(struct dentry *entry)
580{
581 struct inode *inode = entry->d_inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000582 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000583 struct fuse_conn *fc = INO_FC(inode);
584
Miklos Szeredia13d9002004-11-02 17:32:03 +0000585 if (fi->nodeid == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000586 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000587 current->fsuid != fc->uid &&
588 (!(fc->flags & FUSE_ALLOW_ROOT) ||
589 current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000590 return -EACCES;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000591 } else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000592 return 0;
593
Miklos Szeredif85ab242004-01-07 12:16:45 +0000594 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000595}
596
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000597static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000598{
599 struct fuse_conn *fc = INO_FC(inode);
600
Miklos Szeredi180ff692004-11-01 16:01:05 +0000601 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
602 (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000603 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000604 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000605 int err;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000606#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000607 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000608#else
609 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000610#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000611
612 /* If permission is denied, try to refresh file
613 attributes. This is also needed, because the root
614 node will at first have no permissions */
615
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000616 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000617 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000618 if (!err)
619#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000620 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000621#else
Miklos Szeredi83a07442004-11-30 18:25:20 +0000622 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000623#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000624 }
625
626 /* FIXME: Need some mechanism to revoke permissions:
627 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000628 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000629 continue to allow access to the file/directory.
630
631 This is actually not so grave, since the user can
632 simply keep access to the file/directory anyway by
633 keeping it open... */
634
635 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000636 } else {
637 int mode = inode->i_mode;
638 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
639 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
640 return -EROFS;
641 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
642 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000643 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000644 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000645}
646
Miklos Szeredib483c932001-10-29 14:57:57 +0000647static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
648 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000649{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000650 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000651 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000652 size_t reclen = FUSE_DIRENT_SIZE(dirent);
653 int over;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000654 if (dirent->namelen > NAME_MAX) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000655 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000656 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000657 }
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000658 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000659 break;
660
661 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000662 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000663 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000664 break;
665
Miklos Szeredib483c932001-10-29 14:57:57 +0000666 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000667 file->f_pos += reclen;
668 nbytes -= reclen;
669 }
670
Miklos Szeredib483c932001-10-29 14:57:57 +0000671 return 0;
672}
673
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000674static int fuse_checkdir(struct file *cfile, struct file *file)
675{
676 struct inode *inode;
677 if (!cfile) {
678 printk("fuse_getdir: invalid file\n");
679 return -EPROTO;
680 }
681 inode = cfile->f_dentry->d_inode;
682 if (!S_ISREG(inode->i_mode)) {
683 printk("fuse_getdir: not a regular file\n");
684 fput(cfile);
685 return -EPROTO;
686 }
687
688 file->private_data = cfile;
689 return 0;
690}
691
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000692static int fuse_getdir(struct file *file)
693{
694 struct inode *inode = file->f_dentry->d_inode;
695 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000696 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000697 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000698 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000699 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000700
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000701 if (!req)
702 return -ERESTARTSYS;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000703
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000704 req->in.h.opcode = FUSE_GETDIR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000705 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000706 req->out.numargs = 1;
707 req->out.args[0].size = sizeof(struct fuse_getdir_out);
708 req->out.args[0].value = &outarg;
709 request_send(fc, req);
710 err = req->out.h.error;
711 if (!err)
712 err = fuse_checkdir(outarg.file, file);
713 fuse_put_request(fc, req);
714 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000715}
716
Miklos Szeredib483c932001-10-29 14:57:57 +0000717static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
718{
719 struct file *cfile = file->private_data;
720 char *buf;
721 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000722
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000723 if (!cfile) {
724 ret = fuse_getdir(file);
725 if (ret)
726 return ret;
727
728 cfile = file->private_data;
729 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000730
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000731 buf = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000732 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000733 return -ENOMEM;
Miklos Szeredie815c032004-01-19 18:20:49 +0000734
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000735 ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000736 if (ret < 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000737 printk("fuse_readdir: failed to read container file\n");
738 else
739 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
740
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000741 free_page((unsigned long) buf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000742 return ret;
743}
744
Miklos Szeredi05033042001-11-13 16:11:35 +0000745static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000746{
747 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000748 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000749 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000750 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000751 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000752
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000753 if (!req)
754 return ERR_PTR(-ERESTARTSYS);
755
Miklos Szeredi05033042001-11-13 16:11:35 +0000756 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000757 if (!link) {
758 link = ERR_PTR(-ENOMEM);
759 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000760 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000761 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000762 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000763 req->out.argvar = 1;
764 req->out.numargs = 1;
765 req->out.args[0].size = PAGE_SIZE - 1;
766 req->out.args[0].value = link;
767 request_send(fc, req);
768 if (req->out.h.error) {
769 free_page((unsigned long) link);
770 link = ERR_PTR(req->out.h.error);
771 } else
772 link[req->out.args[0].size] = '\0';
773 out:
774 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000775 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000776}
777
778static void free_link(char *link)
779{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000780 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000781 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000782}
783
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000784static int fuse_readlink(struct dentry *dentry, char __user *buffer,
785 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000786{
787 int ret;
788 char *link;
789
Miklos Szeredi05033042001-11-13 16:11:35 +0000790 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000791 ret = vfs_readlink(dentry, buffer, buflen, link);
792 free_link(link);
793 return ret;
794}
795
796static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
797{
798 int ret;
799 char *link;
800
Miklos Szeredi05033042001-11-13 16:11:35 +0000801 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000802 ret = vfs_follow_link(nd, link);
803 free_link(link);
804 return ret;
805}
806
807static int fuse_dir_open(struct inode *inode, struct file *file)
808{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000809 file->private_data = NULL;
810 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000811}
812
813static int fuse_dir_release(struct inode *inode, struct file *file)
814{
815 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000816
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000817 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000818 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000819
820 return 0;
821}
822
Miklos Szeredi83a07442004-11-30 18:25:20 +0000823static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000824{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000825 unsigned ivalid = iattr->ia_valid;
826 unsigned fvalid = 0;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000827
828 memset(fattr, 0, sizeof(*fattr));
829
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000830 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000831 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000832 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000833 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000834 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000835 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000836 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000837 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
838 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000839 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000840 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000841#ifdef KERNEL_2_6
842 fattr->atime = iattr->ia_atime.tv_sec;
843 fattr->mtime = iattr->ia_mtime.tv_sec;
844#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000845 fattr->atime = iattr->ia_atime;
846 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000847#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000848 }
849
850 return fvalid;
851}
852
853static int fuse_setattr(struct dentry *entry, struct iattr *attr)
854{
855 struct inode *inode = entry->d_inode;
856 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000857 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000858 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000859 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000860 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000861 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000862 int is_truncate = 0;
863
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000864 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
865 err = inode_change_ok(inode, attr);
866 if (err)
867 return err;
868 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000869
Miklos Szeredi069c9502004-07-16 16:17:02 +0000870 if (attr->ia_valid & ATTR_SIZE) {
871 unsigned long limit;
872 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000873#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000874 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000875#else
876 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000877#endif
878 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000879 send_sig(SIGXFSZ, current, 0);
880 return -EFBIG;
881 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000882 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000883
884 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000885 if (!req)
886 return -ERESTARTSYS;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000887
Miklos Szeredi069c9502004-07-16 16:17:02 +0000888 if (is_truncate)
889 down_write(&fi->write_sem);
890
Miklos Szeredi43696432001-11-18 19:15:05 +0000891 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000892 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000893 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000894 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000895 req->in.numargs = 1;
896 req->in.args[0].size = sizeof(inarg);
897 req->in.args[0].value = &inarg;
898 req->out.numargs = 1;
899 req->out.args[0].size = sizeof(outarg);
900 req->out.args[0].value = &outarg;
901 request_send(fc, req);
902 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000903 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000904
905 if (!err) {
906 if (is_truncate) {
907 loff_t origsize = i_size_read(inode);
908 i_size_write(inode, outarg.attr.size);
909 up_write(&fi->write_sem);
910 if (origsize > outarg.attr.size)
911 vmtruncate(inode, outarg.attr.size);
912 }
913 change_attributes(inode, &outarg.attr);
914 fi->i_time = time_to_jiffies(outarg.attr_valid,
915 outarg.attr_valid_nsec);
916 } else if (is_truncate)
917 up_write(&fi->write_sem);
918
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000919 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000920}
921
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000922static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000923{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000924 if (!entry->d_inode)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000925 return 0;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000926 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000927 struct inode *inode = entry->d_inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000928 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000929 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000930 int version;
931 int ret;
932
933 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
934 &version);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000935 if (ret)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000936 return 0;
937
Miklos Szeredia13d9002004-11-02 17:32:03 +0000938 if (outarg.nodeid != fi->nodeid)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000939 return 0;
940
941 change_attributes(inode, &outarg.attr);
942 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000943 entry->d_time = time_to_jiffies(outarg.entry_valid,
944 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000945 fi->i_time = time_to_jiffies(outarg.attr_valid,
946 outarg.attr_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000947 }
948 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000949}
950
Miklos Szeredif85ab242004-01-07 12:16:45 +0000951#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000952static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
953 struct kstat *stat)
954{
955 struct inode *inode = entry->d_inode;
956 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000957 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000958 generic_fillattr(inode, stat);
959
960 return err;
961}
962
963static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000964 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000965{
Miklos Szeredie815c032004-01-19 18:20:49 +0000966 struct inode *inode;
967 int err = fuse_lookup_iget(dir, entry, &inode);
968 if (err)
969 return ERR_PTR(err);
970 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000971}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000972#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000973static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
974{
975 struct inode *inode;
976 struct dentry *alias;
977
978 int err = fuse_lookup_iget(dir, entry, &inode);
979 if (err)
980 return ERR_PTR(err);
981
982 if (inode && S_ISDIR(inode->i_mode) &&
983 (alias = d_find_alias(inode)) != NULL) {
984 dput(alias);
985 iput(inode);
986 printk("fuse: cannot assign an existing directory\n");
987 return ERR_PTR(-EPROTO);
988 }
989
990 d_add(entry, inode);
991 return NULL;
992}
993
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000994static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000995 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000996{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000997 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000998}
999
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001000static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001001{
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001002 return fuse_dentry_revalidate(entry, NULL);
1003}
1004
1005static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
1006{
1007 return fuse_create(dir, entry, mode, NULL);
1008}
1009
1010static int fuse_permission_2_4(struct inode *inode, int mask)
1011{
1012 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +00001013}
1014#endif /* KERNEL_2_6 */
1015
1016#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +00001017#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001018static int fuse_setxattr(struct dentry *entry, const char *name,
1019 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +00001020#else
1021static int fuse_setxattr(struct dentry *entry, const char *name,
1022 void *value, size_t size, int flags)
1023#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001024{
1025 struct inode *inode = entry->d_inode;
1026 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001027 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001028 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001029 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001030 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001031
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001032 if (size > FUSE_XATTR_SIZE_MAX)
1033 return -E2BIG;
1034
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001035 if (fc->no_setxattr)
1036 return -EOPNOTSUPP;
1037
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001038 req = fuse_get_request(fc);
1039 if (!req)
1040 return -ERESTARTSYS;
1041
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001042 memset(&inarg, 0, sizeof(inarg));
1043 inarg.size = size;
1044 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001045 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001046 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001047 req->in.numargs = 3;
1048 req->in.args[0].size = sizeof(inarg);
1049 req->in.args[0].value = &inarg;
1050 req->in.args[1].size = strlen(name) + 1;
1051 req->in.args[1].value = name;
1052 req->in.args[2].size = size;
1053 req->in.args[2].value = value;
1054 request_send(fc, req);
1055 err = req->out.h.error;
1056 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001057 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001058 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001059 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 fuse_put_request(fc, req);
1061 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001062}
1063
1064static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1065 void *value, size_t size)
1066{
1067 struct inode *inode = entry->d_inode;
1068 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001069 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001070 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001071 struct fuse_getxattr_in inarg;
1072 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001073 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001074
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001075 if (fc->no_getxattr)
1076 return -EOPNOTSUPP;
1077
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001078 req = fuse_get_request(fc);
1079 if (!req)
1080 return -ERESTARTSYS;
1081
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001082 memset(&inarg, 0, sizeof(inarg));
1083 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001084 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001085 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001086 req->in.numargs = 2;
1087 req->in.args[0].size = sizeof(inarg);
1088 req->in.args[0].value = &inarg;
1089 req->in.args[1].size = strlen(name) + 1;
1090 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001091 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001092 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001093 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001094 req->out.argvar = 1;
1095 req->out.args[0].size = size;
1096 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001097 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001098 req->out.args[0].size = sizeof(outarg);
1099 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001100 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001101 request_send(fc, req);
1102 ret = req->out.h.error;
1103 if (!ret)
1104 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001105 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001106 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001107 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001108 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001109 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001110 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001111 fuse_put_request(fc, req);
1112 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001113}
1114
1115static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1116{
1117 struct inode *inode = entry->d_inode;
1118 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001119 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001120 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001121 struct fuse_getxattr_in inarg;
1122 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001123 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001124
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001125 if (fc->no_listxattr)
1126 return -EOPNOTSUPP;
1127
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001128 req = fuse_get_request(fc);
1129 if (!req)
1130 return -ERESTARTSYS;
1131
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001132 memset(&inarg, 0, sizeof(inarg));
1133 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001134 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001135 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001136 req->in.numargs = 1;
1137 req->in.args[0].size = sizeof(inarg);
1138 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001139 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001140 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001141 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001142 req->out.argvar = 1;
1143 req->out.args[0].size = size;
1144 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001145 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001146 req->out.args[0].size = sizeof(outarg);
1147 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001148 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001149 request_send(fc, req);
1150 ret = req->out.h.error;
1151 if (!ret)
1152 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001153 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001154 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001155 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001156 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001157 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001158 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001159 fuse_put_request(fc, req);
1160 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001161}
1162
1163static int fuse_removexattr(struct dentry *entry, const char *name)
1164{
1165 struct inode *inode = entry->d_inode;
1166 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredia13d9002004-11-02 17:32:03 +00001167 struct fuse_inode *fi = INO_FI(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001168 struct fuse_req *req;
1169 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001170
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001171 if (fc->no_removexattr)
1172 return -EOPNOTSUPP;
1173
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001174 req = fuse_get_request(fc);
1175 if (!req)
1176 return -ERESTARTSYS;
1177
1178 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredia13d9002004-11-02 17:32:03 +00001179 req->in.h.nodeid = fi->nodeid;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001180 req->in.numargs = 1;
1181 req->in.args[0].size = strlen(name) + 1;
1182 req->in.args[0].value = name;
1183 request_send(fc, req);
1184 err = req->out.h.error;
1185 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001186 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001187 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001188 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001189 fuse_put_request(fc, req);
1190 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001191}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001192#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001193
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001194static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001195 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001196 .mkdir = fuse_mkdir,
1197 .symlink = fuse_symlink,
1198 .unlink = fuse_unlink,
1199 .rmdir = fuse_rmdir,
1200 .rename = fuse_rename,
1201 .link = fuse_link,
1202 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001203#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001204 .create = fuse_create,
1205 .mknod = fuse_mknod,
1206 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001207 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001208#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001209 .create = fuse_create_2_4,
1210 .mknod = fuse_mknod_2_4,
1211 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001212 .revalidate = fuse_revalidate,
1213#endif
1214#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001215 .setxattr = fuse_setxattr,
1216 .getxattr = fuse_getxattr,
1217 .listxattr = fuse_listxattr,
1218 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001219#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001220};
1221
1222static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001223 .read = generic_read_dir,
1224 .readdir = fuse_readdir,
1225 .open = fuse_dir_open,
1226 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001227};
1228
1229static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001230 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001231#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001232 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001233 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001234#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001235 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001236 .revalidate = fuse_revalidate,
1237#endif
1238#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001239 .setxattr = fuse_setxattr,
1240 .getxattr = fuse_getxattr,
1241 .listxattr = fuse_listxattr,
1242 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001243#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001244};
1245
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001246static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001247 .setattr = fuse_setattr,
1248 .readlink = fuse_readlink,
1249 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001250#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001251 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001252#else
1253 .revalidate = fuse_revalidate,
1254#endif
1255#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001256 .setxattr = fuse_setxattr,
1257 .getxattr = fuse_getxattr,
1258 .listxattr = fuse_listxattr,
1259 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001260#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001261};
1262
Miklos Szeredi307242f2004-01-26 11:28:44 +00001263static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001264#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001265 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001266#else
1267 .d_revalidate = fuse_dentry_revalidate_2_4,
1268#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001269};