blob: 992c87df01f69d0ea601a237464b2cd5e0df4369 [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
Miklos Szeredie56818b2004-12-12 11:45:24 +00002 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2004 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00004
Miklos Szeredie56818b2004-12-12 11:45:24 +00005 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00007*/
8
9#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000012#include <linux/file.h>
Miklos Szeredi13ed4822004-11-20 11:12:21 +000013#ifdef KERNEL_2_6
14#include <linux/gfp.h>
15#else
16#include <linux/mm.h>
17#endif
18#include <linux/sched.h>
Miklos 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 Szerediaa63b6b2004-12-03 13:24:35 +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 Szeredi064efb02004-11-09 17:30:29 +000084 inode->i_mode = S_IFREG;
85 inode->i_op = &fuse_file_inode_operations;
86 fuse_init_file_inode(inode);
87 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000088}
89
Miklos Szeredia13d9002004-11-02 17:32:03 +000090#ifdef KERNEL_2_6
91static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
92{
93 unsigned long nodeid = *(unsigned long *) _nodeidp;
Miklos Szeredi039322d2004-12-01 18:39:12 +000094 if (get_node_id(inode) == nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +000095 return 1;
96 else
97 return 0;
98}
99
100static int fuse_inode_set(struct inode *inode, void *_nodeidp)
101{
102 unsigned long nodeid = *(unsigned long *) _nodeidp;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000103 get_fuse_inode(inode)->nodeid = nodeid;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000104 return 0;
105}
106
107struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
108 int generation, struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000109{
110 struct inode *inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000111 struct fuse_conn *fc = get_fuse_conn_super(sb);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000112
Miklos Szeredia13d9002004-11-02 17:32:03 +0000113 inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
114 if (!inode)
115 return NULL;
Miklos Szeredie815c032004-01-19 18:20:49 +0000116
Miklos Szeredia13d9002004-11-02 17:32:03 +0000117 if ((inode->i_state & I_NEW)) {
118 inode->i_generation = generation;
Miklos Szeredia25d4c22004-11-23 22:32:16 +0000119 inode->i_data.backing_dev_info = &fc->bdi;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000120 fuse_init_inode(inode, attr);
121 unlock_new_inode(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000122 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000123
Miklos Szeredia13d9002004-11-02 17:32:03 +0000124 change_attributes(inode, attr);
125 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000126 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000127}
128
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000129struct inode *fuse_ilookup(struct super_block *sb, unsigned long nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000130{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000131 return ilookup5(sb, nodeid, fuse_inode_eq, &nodeid);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000132}
133#else
134static int fuse_inode_eq(struct inode *inode, unsigned long ino, void *_nodeidp){
135 unsigned long nodeid = *(unsigned long *) _nodeidp;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000136 if (inode->u.generic_ip && get_node_id(inode) == nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000137 return 1;
138 else
139 return 0;
140}
141
142struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
143 int generation, struct fuse_attr *attr, int version)
144{
145 struct inode *inode;
146
147 inode = iget4(sb, attr->ino, fuse_inode_eq, &nodeid);
148 if (!inode)
149 return NULL;
150
151 if (!inode->u.generic_ip) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000152 get_fuse_inode(inode)->nodeid = nodeid;
Miklos Szeredia13d9002004-11-02 17:32:03 +0000153 inode->u.generic_ip = inode;
154 inode->i_generation = generation;
155 fuse_init_inode(inode, attr);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000156 }
Miklos Szeredia13d9002004-11-02 17:32:03 +0000157
158 change_attributes(inode, attr);
159 inode->i_version = version;
160 return inode;
161}
162
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000163struct inode *fuse_ilookup(struct super_block *sb, ino_t ino, unsigned long nodeid)
Miklos Szeredia13d9002004-11-02 17:32:03 +0000164{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000165 struct inode *inode = iget4(sb, ino, fuse_inode_eq, &nodeid);
Miklos Szeredia13d9002004-11-02 17:32:03 +0000166 if (inode && !inode->u.generic_ip) {
167 iput(inode);
168 inode = NULL;
169 }
170 return inode;
171}
Miklos Szeredia13d9002004-11-02 17:32:03 +0000172#endif
173
Miklos Szeredie56818b2004-12-12 11:45:24 +0000174static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
175 struct dentry *entry,
176 struct fuse_entry_out *outarg)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000177{
178 req->in.h.opcode = FUSE_LOOKUP;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000179 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000180 req->in.numargs = 1;
181 req->in.args[0].size = entry->d_name.len + 1;
182 req->in.args[0].value = entry->d_name.name;
183 req->out.numargs = 1;
184 req->out.args[0].size = sizeof(struct fuse_entry_out);
185 req->out.args[0].value = outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000186}
187
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000188static inline unsigned long time_to_jiffies(unsigned long sec,
189 unsigned long nsec)
190{
191 /* prevent wrapping of jiffies */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000192 if (sec + 1 >= LONG_MAX / HZ)
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000193 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000194
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000195 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
196}
197
Miklos Szeredie815c032004-01-19 18:20:49 +0000198static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
199 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000200{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000201 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredie815c032004-01-19 18:20:49 +0000202 int err;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000203 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000204 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000205 struct inode *inode = NULL;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000206 struct fuse_req *req;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000207
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000208 if (entry->d_name.len > FUSE_NAME_MAX)
209 return -ENAMETOOLONG;
210 req = fuse_get_request(fc);
211 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000212 return -ERESTARTNOINTR;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000213
Miklos Szeredie56818b2004-12-12 11:45:24 +0000214 fuse_lookup_init(req, dir, entry, &outarg);
215 request_send(fc, req);
216 version = req->out.h.unique;
217 err = req->out.h.error;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000218 if (!err) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000219 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000220 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000221 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000222 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000223 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000224 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000225 }
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000226 fuse_put_request(fc, req);
227 if (err && err != -ENOENT)
Miklos Szeredie815c032004-01-19 18:20:49 +0000228 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000229
Miklos Szeredi069c9502004-07-16 16:17:02 +0000230 if (inode) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000231 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000232 entry->d_time = time_to_jiffies(outarg.entry_valid,
Miklos Szerediad051c32004-07-02 09:22:50 +0000233 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000234 fi->i_time = time_to_jiffies(outarg.attr_valid,
235 outarg.attr_valid_nsec);
236 }
Miklos Szerediad051c32004-07-02 09:22:50 +0000237
Miklos Szeredi307242f2004-01-26 11:28:44 +0000238 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000239 *inodep = inode;
240 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000241}
242
Miklos Szeredi069c9502004-07-16 16:17:02 +0000243static void fuse_invalidate_attr(struct inode *inode)
Miklos Szeredi015fe702004-07-12 11:52:24 +0000244{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000245 get_fuse_inode(inode)->i_time = jiffies - 1;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000246}
247
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000248static int lookup_new_entry(struct fuse_conn *fc, struct fuse_req *req,
249 struct inode *dir, struct dentry *entry,
250 struct fuse_entry_out *outarg, int version,
251 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000252{
253 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000254 struct fuse_inode *fi;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000255 inode = fuse_iget(dir->i_sb, outarg->nodeid, outarg->generation,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000256 &outarg->attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000257 if (!inode) {
Miklos Szeredia13d9002004-11-02 17:32:03 +0000258 fuse_send_forget(fc, req, outarg->nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000259 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000260 }
261 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000262
263 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000264 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000265 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000266 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000267 }
268
Miklos Szerediad051c32004-07-02 09:22:50 +0000269 entry->d_time = time_to_jiffies(outarg->entry_valid,
270 outarg->entry_valid_nsec);
271
Miklos Szeredi039322d2004-12-01 18:39:12 +0000272 fi = get_fuse_inode(inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000273 fi->i_time = time_to_jiffies(outarg->attr_valid,
274 outarg->attr_valid_nsec);
275
Miklos Szeredi76f65782004-02-19 16:55:40 +0000276 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000277 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000278 return 0;
279}
280
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000281static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000282 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000283{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000284 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000285 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000286 struct fuse_mknod_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000287 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000288 int err;
289
290 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000291 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000292
293 memset(&inarg, 0, sizeof(inarg));
294 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000295 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000296 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000297 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000298 req->in.numargs = 2;
299 req->in.args[0].size = sizeof(inarg);
300 req->in.args[0].value = &inarg;
301 req->in.args[1].size = entry->d_name.len + 1;
302 req->in.args[1].value = entry->d_name.name;
303 req->out.numargs = 1;
304 req->out.args[0].size = sizeof(outarg);
305 req->out.args[0].value = &outarg;
306 request_send(fc, req);
307 err = req->out.h.error;
308 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000309 err = lookup_new_entry(fc, req, dir, entry, &outarg,
310 req->out.h.unique, mode);
311 else
312 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000314}
315
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000316static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
317 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000318{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000319 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000320}
321
Miklos Szeredib483c932001-10-29 14:57:57 +0000322static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
323{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000324 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000325 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000326 struct fuse_mkdir_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000327 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000328 int err;
329
330 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000331 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000332
333 memset(&inarg, 0, sizeof(inarg));
334 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000335 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000336 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000337 req->in.numargs = 2;
338 req->in.args[0].size = sizeof(inarg);
339 req->in.args[0].value = &inarg;
340 req->in.args[1].size = entry->d_name.len + 1;
341 req->in.args[1].value = entry->d_name.name;
342 req->out.numargs = 1;
343 req->out.args[0].size = sizeof(outarg);
344 req->out.args[0].value = &outarg;
345 request_send(fc, req);
346 err = req->out.h.error;
347 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000348 err = lookup_new_entry(fc, req, dir, entry, &outarg,
349 req->out.h.unique, S_IFDIR);
350 else
351 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000352 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000353}
354
355static int fuse_symlink(struct inode *dir, struct dentry *entry,
356 const char *link)
357{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000358 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000359 struct fuse_req *req;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000360 struct fuse_entry_out outarg;
Miklos Szeredi83a07442004-11-30 18:25:20 +0000361 unsigned len = strlen(link) + 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000362 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000363
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000364 if (len > FUSE_SYMLINK_MAX)
365 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000366
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000367 req = fuse_get_request(fc);
368 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000369 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000370
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000371 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000372 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000373 req->in.numargs = 2;
374 req->in.args[0].size = entry->d_name.len + 1;
375 req->in.args[0].value = entry->d_name.name;
376 req->in.args[1].size = len;
377 req->in.args[1].value = link;
378 req->out.numargs = 1;
379 req->out.args[0].size = sizeof(outarg);
380 req->out.args[0].value = &outarg;
381 request_send(fc, req);
382 err = req->out.h.error;
383 if (!err)
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000384 err = lookup_new_entry(fc, req, dir, entry, &outarg,
385 req->out.h.unique, S_IFLNK);
386 else
387 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000388 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000389}
390
Miklos Szeredib5958612004-02-20 14:10:49 +0000391static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000392{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000393 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000394 struct fuse_req *req = fuse_get_request(fc);
395 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000396
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000397 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000398 return -ERESTARTNOINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000399
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000400 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000401 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000402 req->in.numargs = 1;
403 req->in.args[0].size = entry->d_name.len + 1;
404 req->in.args[0].value = entry->d_name.name;
405 request_send(fc, req);
406 err = req->out.h.error;
407 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000408 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000409
Miklos Szeredib5958612004-02-20 14:10:49 +0000410 /* Set nlink to zero so the inode can be cleared, if
411 the inode does have more links this will be
412 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000413 inode->i_nlink = 0;
414 fuse_invalidate_attr(inode);
415 fuse_invalidate_attr(dir);
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000416 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000417 fuse_put_request(fc, req);
418 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000419}
420
421static int fuse_rmdir(struct inode *dir, struct dentry *entry)
422{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000423 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000424 struct fuse_req *req = fuse_get_request(fc);
425 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000426
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000427 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000428 return -ERESTARTNOINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000429
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000430 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000431 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000432 req->in.numargs = 1;
433 req->in.args[0].size = entry->d_name.len + 1;
434 req->in.args[0].value = entry->d_name.name;
435 request_send(fc, req);
436 err = req->out.h.error;
Miklos Szeredi015fe702004-07-12 11:52:24 +0000437 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000438 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000439 fuse_invalidate_attr(dir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000440 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000441 fuse_put_request(fc, req);
442 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000443}
444
445static int fuse_rename(struct inode *olddir, struct dentry *oldent,
446 struct inode *newdir, struct dentry *newent)
447{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000448 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000449 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000450 struct fuse_rename_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000451 int err;
452
453 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000454 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000455
Miklos Szeredi43696432001-11-18 19:15:05 +0000456 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000457 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000458 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000459 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000460 req->in.numargs = 3;
461 req->in.args[0].size = sizeof(inarg);
462 req->in.args[0].value = &inarg;
463 req->in.args[1].size = oldent->d_name.len + 1;
464 req->in.args[1].value = oldent->d_name.name;
465 req->in.args[2].size = newent->d_name.len + 1;
466 req->in.args[2].value = newent->d_name.name;
467 request_send(fc, req);
468 err = req->out.h.error;
469 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000470 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000471 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000472 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000473 fuse_invalidate_attr(newdir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000474 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000475 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000476}
477
478static int fuse_link(struct dentry *entry, struct inode *newdir,
479 struct dentry *newent)
480{
481 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000482 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000483 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi43696432001-11-18 19:15:05 +0000484 struct fuse_link_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000485 struct fuse_entry_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000486 int err;
487
488 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000489 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000490
Miklos Szeredi43696432001-11-18 19:15:05 +0000491 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000492 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000493 req->in.h.opcode = FUSE_LINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000494 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000495 req->in.numargs = 2;
496 req->in.args[0].size = sizeof(inarg);
497 req->in.args[0].value = &inarg;
498 req->in.args[1].size = newent->d_name.len + 1;
499 req->in.args[1].value = newent->d_name.name;
500 req->out.numargs = 1;
501 req->out.args[0].size = sizeof(outarg);
502 req->out.args[0].value = &outarg;
503 request_send(fc, req);
504 err = req->out.h.error;
505 if (!err) {
506 /* Invalidate old entry, so attributes are refreshed */
507 d_invalidate(entry);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000508 err = lookup_new_entry(fc, req, newdir, newent, &outarg,
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000509 req->out.h.unique, inode->i_mode);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000510 } else
511 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000512 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000513}
514
Miklos Szeredif85ab242004-01-07 12:16:45 +0000515int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000516{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000517 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000518 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000519 struct fuse_attr_out arg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000520 int err;
521
522 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000523 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000524
525 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000526 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000527 req->out.numargs = 1;
528 req->out.args[0].size = sizeof(arg);
529 req->out.args[0].value = &arg;
530 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000531 err = req->out.h.error;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000532 if (!err) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000533 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000534 change_attributes(inode, &arg.attr);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000535 fi->i_time = time_to_jiffies(arg.attr_valid,
536 arg.attr_valid_nsec);
537 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000538 fuse_put_request(fc, req);
539 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000540}
541
Miklos Szeredife25def2001-12-20 15:38:05 +0000542static int fuse_revalidate(struct dentry *entry)
543{
544 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000545 struct fuse_inode *fi = get_fuse_inode(inode);
546 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000547
Miklos Szeredi039322d2004-12-01 18:39:12 +0000548 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000549 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000550 current->fsuid != fc->uid &&
551 (!(fc->flags & FUSE_ALLOW_ROOT) ||
552 current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000553 return -EACCES;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000554 } else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000555 return 0;
556
Miklos Szeredif85ab242004-01-07 12:16:45 +0000557 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000558}
559
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000560static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000561{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000562 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000563
Miklos Szeredi180ff692004-11-01 16:01:05 +0000564 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
565 (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000566 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000567 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000568 int err;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000569#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000570 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000571#else
572 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000573#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000574
575 /* If permission is denied, try to refresh file
576 attributes. This is also needed, because the root
577 node will at first have no permissions */
578
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000579 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000580 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000581 if (!err)
582#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000583 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000584#else
Miklos Szeredie56818b2004-12-12 11:45:24 +0000585 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000586#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000587 }
588
589 /* FIXME: Need some mechanism to revoke permissions:
590 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000591 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000592 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000593
Miklos Szeredife25def2001-12-20 15:38:05 +0000594 This is actually not so grave, since the user can
595 simply keep access to the file/directory anyway by
596 keeping it open... */
597
598 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000599 } else {
600 int mode = inode->i_mode;
601 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
602 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
603 return -EROFS;
604 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
605 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000606 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000607 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000608}
609
Miklos Szeredib483c932001-10-29 14:57:57 +0000610static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
611 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000612{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000613 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000614 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000615 size_t reclen = FUSE_DIRENT_SIZE(dirent);
616 int over;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000617 if (dirent->namelen > NAME_MAX)
618 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000619 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000620 break;
621
622 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000623 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000624 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000625 break;
626
Miklos Szeredib483c932001-10-29 14:57:57 +0000627 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000628 file->f_pos += reclen;
629 nbytes -= reclen;
630 }
631
Miklos Szeredib483c932001-10-29 14:57:57 +0000632 return 0;
633}
634
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000635static int fuse_checkdir(struct file *cfile, struct file *file)
636{
637 struct inode *inode;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000638 if (!cfile)
639 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000640 inode = cfile->f_dentry->d_inode;
641 if (!S_ISREG(inode->i_mode)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000642 fput(cfile);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000643 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000644 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000645
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000646 file->private_data = cfile;
647 return 0;
648}
649
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000650static int fuse_getdir(struct file *file)
651{
652 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000653 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000654 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000655 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000656 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000657
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000658 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000659 return -ERESTARTNOINTR;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000660
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000661 req->in.h.opcode = FUSE_GETDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000662 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000663 req->out.numargs = 1;
664 req->out.args[0].size = sizeof(struct fuse_getdir_out);
665 req->out.args[0].value = &outarg;
666 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000667 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000668 if (!err)
669 err = fuse_checkdir(outarg.file, file);
670 fuse_put_request(fc, req);
671 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000672}
673
Miklos Szeredib483c932001-10-29 14:57:57 +0000674static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
675{
676 struct file *cfile = file->private_data;
677 char *buf;
678 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000679
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000680 if (!cfile) {
681 ret = fuse_getdir(file);
682 if (ret)
683 return ret;
684
685 cfile = file->private_data;
686 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000687
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000688 buf = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000689 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000690 return -ENOMEM;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000691
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000692 ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000693 if (ret > 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000694 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
695
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000696 free_page((unsigned long) buf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000697 return ret;
698}
699
Miklos Szeredi05033042001-11-13 16:11:35 +0000700static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000701{
702 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000703 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000704 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000705 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000706
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000707 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000708 return ERR_PTR(-ERESTARTNOINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000709
Miklos Szeredi05033042001-11-13 16:11:35 +0000710 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000711 if (!link) {
712 link = ERR_PTR(-ENOMEM);
713 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000714 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000715 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000716 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000717 req->out.argvar = 1;
718 req->out.numargs = 1;
719 req->out.args[0].size = PAGE_SIZE - 1;
720 req->out.args[0].value = link;
721 request_send(fc, req);
722 if (req->out.h.error) {
723 free_page((unsigned long) link);
724 link = ERR_PTR(req->out.h.error);
725 } else
726 link[req->out.args[0].size] = '\0';
727 out:
728 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000729 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000730}
731
732static void free_link(char *link)
733{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000734 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000735 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000736}
737
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000738static int fuse_readlink(struct dentry *dentry, char __user *buffer,
739 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000740{
741 int ret;
742 char *link;
743
Miklos Szeredi05033042001-11-13 16:11:35 +0000744 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000745 ret = vfs_readlink(dentry, buffer, buflen, link);
746 free_link(link);
747 return ret;
748}
749
750static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
751{
752 int ret;
753 char *link;
754
Miklos Szeredi05033042001-11-13 16:11:35 +0000755 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000756 ret = vfs_follow_link(nd, link);
757 free_link(link);
758 return ret;
759}
760
761static int fuse_dir_open(struct inode *inode, struct file *file)
762{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000763 file->private_data = NULL;
764 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000765}
766
767static int fuse_dir_release(struct inode *inode, struct file *file)
768{
769 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000770
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000771 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000772 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000773
774 return 0;
775}
776
Miklos Szeredi83a07442004-11-30 18:25:20 +0000777static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000778{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000779 unsigned ivalid = iattr->ia_valid;
780 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000781
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000783
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000784 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000785 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000786 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000787 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000788 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000789 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000790 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000791 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
792 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000793 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000794 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000795#ifdef KERNEL_2_6
796 fattr->atime = iattr->ia_atime.tv_sec;
797 fattr->mtime = iattr->ia_mtime.tv_sec;
798#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000799 fattr->atime = iattr->ia_atime;
800 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000801#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000802 }
803
804 return fvalid;
805}
806
807static int fuse_setattr(struct dentry *entry, struct iattr *attr)
808{
809 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000810 struct fuse_conn *fc = get_fuse_conn(inode);
811 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000812 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000813 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000814 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000815 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000816 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000817
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000818 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
819 err = inode_change_ok(inode, attr);
820 if (err)
821 return err;
822 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000823
Miklos Szeredi069c9502004-07-16 16:17:02 +0000824 if (attr->ia_valid & ATTR_SIZE) {
825 unsigned long limit;
826 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000827#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000828 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000829#else
830 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000831#endif
832 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000833 send_sig(SIGXFSZ, current, 0);
834 return -EFBIG;
835 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000836 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000837
838 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000839 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000840 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000841
Miklos Szeredi43696432001-11-18 19:15:05 +0000842 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000843 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000844 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000845 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000846 req->in.numargs = 1;
847 req->in.args[0].size = sizeof(inarg);
848 req->in.args[0].value = &inarg;
849 req->out.numargs = 1;
850 req->out.args[0].size = sizeof(outarg);
851 req->out.args[0].value = &outarg;
852 request_send(fc, req);
853 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000854 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000855
856 if (!err) {
857 if (is_truncate) {
858 loff_t origsize = i_size_read(inode);
859 i_size_write(inode, outarg.attr.size);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000860 if (origsize > outarg.attr.size)
861 vmtruncate(inode, outarg.attr.size);
862 }
863 change_attributes(inode, &outarg.attr);
864 fi->i_time = time_to_jiffies(outarg.attr_valid,
865 outarg.attr_valid_nsec);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000866 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000867
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000868 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000869}
870
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000871static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000872{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000873 if (!entry->d_inode)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000874 return 0;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000875 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredie56818b2004-12-12 11:45:24 +0000876 int err;
877 int version;
878 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000879 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000880 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000881 struct fuse_conn *fc = get_fuse_conn(inode);
882 struct fuse_req *req = fuse_get_request_nonint(fc);
883 if (!req)
884 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000885
Miklos Szeredie56818b2004-12-12 11:45:24 +0000886 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
887 request_send_nonint(fc, req, 0);
888 version = req->out.h.unique;
889 err = req->out.h.error;
890 fuse_put_request(fc, req);
891 if (err)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000892 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000893
Miklos Szeredi039322d2004-12-01 18:39:12 +0000894 if (outarg.nodeid != get_node_id(inode))
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000895 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000896
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000897 change_attributes(inode, &outarg.attr);
898 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000899 entry->d_time = time_to_jiffies(outarg.entry_valid,
900 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000901 fi->i_time = time_to_jiffies(outarg.attr_valid,
902 outarg.attr_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000903 }
904 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000905}
906
Miklos Szeredif85ab242004-01-07 12:16:45 +0000907#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000908static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
909 struct kstat *stat)
910{
911 struct inode *inode = entry->d_inode;
912 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000913 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000914 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000915
Miklos Szeredif85ab242004-01-07 12:16:45 +0000916 return err;
917}
918
919static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000920 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000921{
Miklos Szeredie815c032004-01-19 18:20:49 +0000922 struct inode *inode;
923 int err = fuse_lookup_iget(dir, entry, &inode);
924 if (err)
925 return ERR_PTR(err);
926 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000927}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000928#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000929static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
930{
931 struct inode *inode;
932 struct dentry *alias;
933
934 int err = fuse_lookup_iget(dir, entry, &inode);
935 if (err)
936 return ERR_PTR(err);
937
938 if (inode && S_ISDIR(inode->i_mode) &&
939 (alias = d_find_alias(inode)) != NULL) {
940 dput(alias);
941 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000942 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000943 }
944
945 d_add(entry, inode);
946 return NULL;
947}
948
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000949static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000950 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000951{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000952 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000953}
954
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000955static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000956{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000957 return fuse_dentry_revalidate(entry, NULL);
958}
959
960static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
961{
962 return fuse_create(dir, entry, mode, NULL);
963}
964
965static int fuse_permission_2_4(struct inode *inode, int mask)
966{
967 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000968}
969#endif /* KERNEL_2_6 */
970
971#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000972#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000973static int fuse_setxattr(struct dentry *entry, const char *name,
974 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000975#else
976static int fuse_setxattr(struct dentry *entry, const char *name,
977 void *value, size_t size, int flags)
978#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000979{
980 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000981 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000982 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000983 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000984 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000985
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000986 if (size > FUSE_XATTR_SIZE_MAX)
987 return -E2BIG;
988
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000989 if (fc->no_setxattr)
990 return -EOPNOTSUPP;
991
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000992 req = fuse_get_request(fc);
993 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000994 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000995
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000996 memset(&inarg, 0, sizeof(inarg));
997 inarg.size = size;
998 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000999 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001000 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001001 req->in.numargs = 3;
1002 req->in.args[0].size = sizeof(inarg);
1003 req->in.args[0].value = &inarg;
1004 req->in.args[1].size = strlen(name) + 1;
1005 req->in.args[1].value = name;
1006 req->in.args[2].size = size;
1007 req->in.args[2].value = value;
1008 request_send(fc, req);
1009 err = req->out.h.error;
1010 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001011 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001012 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001013 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001014 fuse_put_request(fc, req);
1015 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001016}
1017
1018static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
1019 void *value, size_t size)
1020{
1021 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001022 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001023 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001024 struct fuse_getxattr_in inarg;
1025 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001026 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001027
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001028 if (fc->no_getxattr)
1029 return -EOPNOTSUPP;
1030
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001031 req = fuse_get_request(fc);
1032 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +00001033 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001034
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001035 memset(&inarg, 0, sizeof(inarg));
1036 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001037 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001038 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001039 req->in.numargs = 2;
1040 req->in.args[0].size = sizeof(inarg);
1041 req->in.args[0].value = &inarg;
1042 req->in.args[1].size = strlen(name) + 1;
1043 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001044 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001045 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001046 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001047 req->out.argvar = 1;
1048 req->out.args[0].size = size;
1049 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001050 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001051 req->out.args[0].size = sizeof(outarg);
1052 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001053 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001054 request_send(fc, req);
1055 ret = req->out.h.error;
1056 if (!ret)
1057 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001058 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001059 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001060 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001061 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001062 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001063 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001064 fuse_put_request(fc, req);
1065 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001066}
1067
1068static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1069{
1070 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001071 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001072 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001073 struct fuse_getxattr_in inarg;
1074 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001075 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001076
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001077 if (fc->no_listxattr)
1078 return -EOPNOTSUPP;
1079
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001080 req = fuse_get_request(fc);
1081 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +00001082 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001083
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001084 memset(&inarg, 0, sizeof(inarg));
1085 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001086 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001087 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001088 req->in.numargs = 1;
1089 req->in.args[0].size = sizeof(inarg);
1090 req->in.args[0].value = &inarg;
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 = list;
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_listxattr = 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 int fuse_removexattr(struct dentry *entry, const char *name)
1116{
1117 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001118 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001119 struct fuse_req *req;
1120 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001121
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001122 if (fc->no_removexattr)
1123 return -EOPNOTSUPP;
1124
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001125 req = fuse_get_request(fc);
1126 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +00001127 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001128
1129 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001130 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001131 req->in.numargs = 1;
1132 req->in.args[0].size = strlen(name) + 1;
1133 req->in.args[0].value = name;
1134 request_send(fc, req);
1135 err = req->out.h.error;
1136 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001137 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001138 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001139 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001140 fuse_put_request(fc, req);
1141 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001142}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001143#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001144
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001145static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001146 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001147 .mkdir = fuse_mkdir,
1148 .symlink = fuse_symlink,
1149 .unlink = fuse_unlink,
1150 .rmdir = fuse_rmdir,
1151 .rename = fuse_rename,
1152 .link = fuse_link,
1153 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001154#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001155 .create = fuse_create,
1156 .mknod = fuse_mknod,
1157 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001158 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001159#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001160 .create = fuse_create_2_4,
1161 .mknod = fuse_mknod_2_4,
1162 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001163 .revalidate = fuse_revalidate,
1164#endif
1165#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001166 .setxattr = fuse_setxattr,
1167 .getxattr = fuse_getxattr,
1168 .listxattr = fuse_listxattr,
1169 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001170#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001171};
1172
1173static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001174 .read = generic_read_dir,
1175 .readdir = fuse_readdir,
1176 .open = fuse_dir_open,
1177 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001178};
1179
1180static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001181 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001182#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001183 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001184 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001185#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001186 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001187 .revalidate = fuse_revalidate,
1188#endif
1189#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001190 .setxattr = fuse_setxattr,
1191 .getxattr = fuse_getxattr,
1192 .listxattr = fuse_listxattr,
1193 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001194#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001195};
1196
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001197static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001198 .setattr = fuse_setattr,
1199 .readlink = fuse_readlink,
1200 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001201#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001202 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001203#else
1204 .revalidate = fuse_revalidate,
1205#endif
1206#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001207 .setxattr = fuse_setxattr,
1208 .getxattr = fuse_getxattr,
1209 .listxattr = fuse_listxattr,
1210 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001211#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001212};
1213
Miklos Szeredi307242f2004-01-26 11:28:44 +00001214static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001215#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001216 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001217#else
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001218 .d_revalidate = fuse_dentry_revalidate_2_4,
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001219#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001220};