blob: 19aebb19667fca876b0fe87a8117dd632e75cc32 [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 Szeredie815c032004-01-19 18:20:49 +0000201 int err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000202 int version;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000203 struct fuse_entry_out outarg;
Miklos Szeredie815c032004-01-19 18:20:49 +0000204 struct inode *inode = NULL;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000205 struct fuse_conn *fc = get_fuse_conn(dir);
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 Szeredi0fcfa032004-12-13 15:22:28 +0000243void 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 Szeredi0fcfa032004-12-13 15:22:28 +0000248static void fuse_invalidate_entry(struct dentry *entry)
249{
250 d_invalidate(entry);
251 entry->d_time = jiffies - 1;
252}
253
254static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000255 struct inode *dir, struct dentry *entry,
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000256 int mode)
Miklos Szeredi76f65782004-02-19 16:55:40 +0000257{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000258 struct fuse_entry_out outarg;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000259 struct inode *inode;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000260 struct fuse_inode *fi;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000261 int version;
262 int err;
263
264 req->in.h.nodeid = get_node_id(dir);
265 req->out.numargs = 1;
266 req->out.args[0].size = sizeof(outarg);
267 req->out.args[0].value = &outarg;
268 request_send(fc, req);
269 version = req->out.h.unique;
270 err = req->out.h.error;
271 if (err) {
272 fuse_put_request(fc, req);
273 return err;
274 }
275 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
276 &outarg.attr, version);
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000277 if (!inode) {
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000278 fuse_send_forget(fc, req, outarg.nodeid, version);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000279 return -ENOMEM;
Miklos Szeredi2778f6c2004-06-21 09:45:30 +0000280 }
281 fuse_put_request(fc, req);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000282
283 /* Don't allow userspace to do really stupid things... */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000284 if ((inode->i_mode ^ mode) & S_IFMT) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000285 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000286 return -EIO;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000287 }
288
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000289 entry->d_time = time_to_jiffies(outarg.entry_valid,
290 outarg.entry_valid_nsec);
Miklos Szerediad051c32004-07-02 09:22:50 +0000291
Miklos Szeredi039322d2004-12-01 18:39:12 +0000292 fi = get_fuse_inode(inode);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000293 fi->i_time = time_to_jiffies(outarg.attr_valid,
294 outarg.attr_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000295
Miklos Szeredi76f65782004-02-19 16:55:40 +0000296 d_instantiate(entry, inode);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000297 fuse_invalidate_attr(dir);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000298 return 0;
299}
300
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000301static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000302 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000303{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000304 struct fuse_mknod_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000305 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000306 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000307 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000308 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000309
310 memset(&inarg, 0, sizeof(inarg));
311 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000312 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000313 req->in.h.opcode = FUSE_MKNOD;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000314 req->in.numargs = 2;
315 req->in.args[0].size = sizeof(inarg);
316 req->in.args[0].value = &inarg;
317 req->in.args[1].size = entry->d_name.len + 1;
318 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000319 return create_new_entry(fc, req, dir, entry, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000320}
321
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000322static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
323 struct nameidata *nd)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000324{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000325 return fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000326}
327
Miklos Szeredib483c932001-10-29 14:57:57 +0000328static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
329{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000330 struct fuse_mkdir_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000331 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000332 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000333 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000334 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000335
336 memset(&inarg, 0, sizeof(inarg));
337 inarg.mode = mode;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000338 req->in.h.opcode = FUSE_MKDIR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000339 req->in.numargs = 2;
340 req->in.args[0].size = sizeof(inarg);
341 req->in.args[0].value = &inarg;
342 req->in.args[1].size = entry->d_name.len + 1;
343 req->in.args[1].value = entry->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000344 return create_new_entry(fc, req, dir, entry, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000345}
346
347static int fuse_symlink(struct inode *dir, struct dentry *entry,
348 const char *link)
349{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000350 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi83a07442004-11-30 18:25:20 +0000351 unsigned len = strlen(link) + 1;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000352 struct fuse_req *req;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000353
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000354 if (len > FUSE_SYMLINK_MAX)
355 return -ENAMETOOLONG;
Miklos Szeredib483c932001-10-29 14:57:57 +0000356
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000357 req = fuse_get_request(fc);
358 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000359 return -ERESTARTNOINTR;
Miklos Szeredi43696432001-11-18 19:15:05 +0000360
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000361 req->in.h.opcode = FUSE_SYMLINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000362 req->in.numargs = 2;
363 req->in.args[0].size = entry->d_name.len + 1;
364 req->in.args[0].value = entry->d_name.name;
365 req->in.args[1].size = len;
366 req->in.args[1].value = link;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000367 return create_new_entry(fc, req, dir, entry, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000368}
369
Miklos Szeredib5958612004-02-20 14:10:49 +0000370static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000371{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000372 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000373 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000374 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000375 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000376 return -ERESTARTNOINTR;
Miklos Szeredib483c932001-10-29 14:57:57 +0000377
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000378 req->in.h.opcode = FUSE_UNLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000379 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000380 req->in.numargs = 1;
381 req->in.args[0].size = entry->d_name.len + 1;
382 req->in.args[0].value = entry->d_name.name;
383 request_send(fc, req);
384 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000385 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000386 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000387 struct inode *inode = entry->d_inode;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000388
Miklos Szeredib5958612004-02-20 14:10:49 +0000389 /* Set nlink to zero so the inode can be cleared, if
390 the inode does have more links this will be
391 discovered at the next lookup/getattr */
Miklos Szeredi069c9502004-07-16 16:17:02 +0000392 inode->i_nlink = 0;
393 fuse_invalidate_attr(inode);
394 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000395 } else if (err == -EINTR)
396 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000397 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000398}
399
400static int fuse_rmdir(struct inode *dir, struct dentry *entry)
401{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000402 int err;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000403 struct fuse_conn *fc = get_fuse_conn(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000404 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000405 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000406 return -ERESTARTNOINTR;
Miklos Szeredib5958612004-02-20 14:10:49 +0000407
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000408 req->in.h.opcode = FUSE_RMDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000409 req->in.h.nodeid = get_node_id(dir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000410 req->in.numargs = 1;
411 req->in.args[0].size = entry->d_name.len + 1;
412 req->in.args[0].value = entry->d_name.name;
413 request_send(fc, req);
414 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000415 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000416 if (!err) {
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000417 entry->d_inode->i_nlink = 0;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000418 fuse_invalidate_attr(dir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000419 } else if (err == -EINTR)
420 fuse_invalidate_entry(entry);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000421 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000422}
423
424static int fuse_rename(struct inode *olddir, struct dentry *oldent,
425 struct inode *newdir, struct dentry *newent)
426{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000427 int err;
428 struct fuse_rename_in inarg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000429 struct fuse_conn *fc = get_fuse_conn(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000430 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000431 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000432 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000433
Miklos Szeredi43696432001-11-18 19:15:05 +0000434 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000435 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000436 req->in.h.opcode = FUSE_RENAME;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000437 req->in.h.nodeid = get_node_id(olddir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000438 req->in.numargs = 3;
439 req->in.args[0].size = sizeof(inarg);
440 req->in.args[0].value = &inarg;
441 req->in.args[1].size = oldent->d_name.len + 1;
442 req->in.args[1].value = oldent->d_name.name;
443 req->in.args[2].size = newent->d_name.len + 1;
444 req->in.args[2].value = newent->d_name.name;
445 request_send(fc, req);
446 err = req->out.h.error;
447 fuse_put_request(fc, req);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000448 if (!err) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000449 fuse_invalidate_attr(olddir);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000450 if (olddir != newdir)
Miklos Szeredi069c9502004-07-16 16:17:02 +0000451 fuse_invalidate_attr(newdir);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000452 } else if (err == -EINTR) {
453 /* If request was interrupted, DEITY only knows if the
454 rename actually took place. If the invalidation
455 fails (e.g. some process has CWD under the renamed
456 directory), then there can be inconsistency between
457 the dcache and the real filesystem. But not a lot
458 can be done about that */
459 fuse_invalidate_entry(oldent);
460 if (newent->d_inode)
461 fuse_invalidate_entry(newent);
Miklos Szeredi015fe702004-07-12 11:52:24 +0000462 }
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000463
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000464 return err;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000465}
466
467static int fuse_link(struct dentry *entry, struct inode *newdir,
468 struct dentry *newent)
469{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000470 int err;
471 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000472 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000473 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000474 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000475 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000476 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000477
Miklos Szeredi43696432001-11-18 19:15:05 +0000478 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredi039322d2004-12-01 18:39:12 +0000479 inarg.newdir = get_node_id(newdir);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000480 req->in.h.opcode = FUSE_LINK;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000481 req->in.numargs = 2;
482 req->in.args[0].size = sizeof(inarg);
483 req->in.args[0].value = &inarg;
484 req->in.args[1].size = newent->d_name.len + 1;
485 req->in.args[1].value = newent->d_name.name;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000486 err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
487 /* Contrary to "normal" filesystems it can happen that link
488 makes two "logical" inodes point to the same "physical"
489 inode. We invalidate the attributes of the old one, so it
490 will reflect changes in the backing inode (link count,
491 etc.)
492 */
493 if (!err || err == -EINTR)
494 fuse_invalidate_attr(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000495 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000496}
497
Miklos Szeredif85ab242004-01-07 12:16:45 +0000498int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000499{
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000500 int err;
501 struct fuse_attr_out arg;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000502 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000503 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000504 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000505 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000506
507 req->in.h.opcode = FUSE_GETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000508 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000509 req->out.numargs = 1;
510 req->out.args[0].size = sizeof(arg);
511 req->out.args[0].value = &arg;
512 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000513 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000514 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000515 if (!err) {
Miklos Szeredi039322d2004-12-01 18:39:12 +0000516 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000517 change_attributes(inode, &arg.attr);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000518 fi->i_time = time_to_jiffies(arg.attr_valid,
519 arg.attr_valid_nsec);
520 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000521 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000522}
523
Miklos Szeredife25def2001-12-20 15:38:05 +0000524static int fuse_revalidate(struct dentry *entry)
525{
526 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000527 struct fuse_inode *fi = get_fuse_inode(inode);
528 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000529
Miklos Szeredi039322d2004-12-01 18:39:12 +0000530 if (get_node_id(inode) == FUSE_ROOT_ID) {
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000531 if (!(fc->flags & FUSE_ALLOW_OTHER) &&
Miklos Szeredi180ff692004-11-01 16:01:05 +0000532 current->fsuid != fc->uid &&
533 (!(fc->flags & FUSE_ALLOW_ROOT) ||
534 current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000535 return -EACCES;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000536 } else if (!fi->i_time || time_before_eq(jiffies, fi->i_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000537 return 0;
538
Miklos Szeredif85ab242004-01-07 12:16:45 +0000539 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000540}
541
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000542static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
Miklos Szeredife25def2001-12-20 15:38:05 +0000543{
Miklos Szeredi039322d2004-12-01 18:39:12 +0000544 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000545
Miklos Szeredi180ff692004-11-01 16:01:05 +0000546 if (!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid &&
547 (!(fc->flags & FUSE_ALLOW_ROOT) || current->fsuid != 0))
Miklos Szeredife25def2001-12-20 15:38:05 +0000548 return -EACCES;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000549 else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000550#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000551 int err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000552#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000553 int err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000554#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000555
556 /* If permission is denied, try to refresh file
557 attributes. This is also needed, because the root
558 node will at first have no permissions */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000559 if (err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000560 err = fuse_do_getattr(inode);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000561 if (!err)
562#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000563 err = generic_permission(inode, mask, NULL);
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000564#else
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000565 err = vfs_permission(inode, mask);
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000566#endif
Miklos Szeredife25def2001-12-20 15:38:05 +0000567 }
568
569 /* FIXME: Need some mechanism to revoke permissions:
570 currently if the filesystem suddenly changes the
Miklos Szeredi064efb02004-11-09 17:30:29 +0000571 file mode, we will not be informed about it, and
Miklos Szeredife25def2001-12-20 15:38:05 +0000572 continue to allow access to the file/directory.
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000573
Miklos Szeredife25def2001-12-20 15:38:05 +0000574 This is actually not so grave, since the user can
575 simply keep access to the file/directory anyway by
576 keeping it open... */
577
578 return err;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000579 } else {
580 int mode = inode->i_mode;
581 if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
582 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
583 return -EROFS;
584 if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
585 return -EACCES;
Miklos Szeredife25def2001-12-20 15:38:05 +0000586 return 0;
Miklos Szeredi96dfad72004-11-30 00:00:02 +0000587 }
Miklos Szeredife25def2001-12-20 15:38:05 +0000588}
589
Miklos Szeredib483c932001-10-29 14:57:57 +0000590static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
591 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000592{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000593 while (nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000594 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000595 size_t reclen = FUSE_DIRENT_SIZE(dirent);
596 int over;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000597 if (dirent->namelen > NAME_MAX)
598 return -EIO;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000599 if (reclen > nbytes)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000600 break;
601
602 over = filldir(dstbuf, dirent->name, dirent->namelen,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000603 file->f_pos, dirent->ino, dirent->type);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000604 if (over)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000605 break;
606
Miklos Szeredib483c932001-10-29 14:57:57 +0000607 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000608 file->f_pos += reclen;
609 nbytes -= reclen;
610 }
611
Miklos Szeredib483c932001-10-29 14:57:57 +0000612 return 0;
613}
614
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000615static int fuse_checkdir(struct file *cfile, struct file *file)
616{
617 struct inode *inode;
Miklos Szeredie56818b2004-12-12 11:45:24 +0000618 if (!cfile)
619 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000620 inode = cfile->f_dentry->d_inode;
621 if (!S_ISREG(inode->i_mode)) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000622 fput(cfile);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000623 return -EIO;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000624 }
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000625
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000626 file->private_data = cfile;
627 return 0;
628}
629
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000630static int fuse_getdir(struct file *file)
631{
632 struct inode *inode = file->f_dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000633 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000634 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000635 struct fuse_getdir_out_i outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000636 int err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000637
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000638 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000639 return -ERESTARTNOINTR;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000640
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000641 req->in.h.opcode = FUSE_GETDIR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000642 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000643 req->out.numargs = 1;
644 req->out.args[0].size = sizeof(struct fuse_getdir_out);
645 req->out.args[0].value = &outarg;
646 request_send(fc, req);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000647 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000648 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000649 if (!err)
650 err = fuse_checkdir(outarg.file, file);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000651 return err;
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000652}
653
Miklos Szeredib483c932001-10-29 14:57:57 +0000654static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
655{
656 struct file *cfile = file->private_data;
657 char *buf;
658 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000659
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000660 if (!cfile) {
661 ret = fuse_getdir(file);
662 if (ret)
663 return ret;
664
665 cfile = file->private_data;
666 }
Miklos Szeredie815c032004-01-19 18:20:49 +0000667
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000668 buf = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000669 if (!buf)
Miklos Szeredib483c932001-10-29 14:57:57 +0000670 return -ENOMEM;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000671
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000672 ret = kernel_read(cfile, file->f_pos, buf, PAGE_SIZE);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000673 if (ret > 0)
Miklos Szeredib483c932001-10-29 14:57:57 +0000674 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
675
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000676 free_page((unsigned long) buf);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000677 return ret;
678}
679
Miklos Szeredi05033042001-11-13 16:11:35 +0000680static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000681{
682 struct inode *inode = dentry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000683 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000684 struct fuse_req *req = fuse_get_request(fc);
Miklos Szeredi05033042001-11-13 16:11:35 +0000685 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000686
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000687 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000688 return ERR_PTR(-ERESTARTNOINTR);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000689
Miklos Szeredi05033042001-11-13 16:11:35 +0000690 link = (char *) __get_free_page(GFP_KERNEL);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000691 if (!link) {
692 link = ERR_PTR(-ENOMEM);
693 goto out;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000694 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000695 req->in.h.opcode = FUSE_READLINK;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000696 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000697 req->out.argvar = 1;
698 req->out.numargs = 1;
699 req->out.args[0].size = PAGE_SIZE - 1;
700 req->out.args[0].value = link;
701 request_send(fc, req);
702 if (req->out.h.error) {
703 free_page((unsigned long) link);
704 link = ERR_PTR(req->out.h.error);
705 } else
706 link[req->out.args[0].size] = '\0';
707 out:
708 fuse_put_request(fc, req);
Miklos Szeredi05033042001-11-13 16:11:35 +0000709 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000710}
711
712static void free_link(char *link)
713{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000714 if (!IS_ERR(link))
Miklos Szeredi05033042001-11-13 16:11:35 +0000715 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000716}
717
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000718static int fuse_readlink(struct dentry *dentry, char __user *buffer,
719 int buflen)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000720{
721 int ret;
722 char *link;
723
Miklos Szeredi05033042001-11-13 16:11:35 +0000724 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000725 ret = vfs_readlink(dentry, buffer, buflen, link);
726 free_link(link);
727 return ret;
728}
729
730static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
731{
732 int ret;
733 char *link;
734
Miklos Szeredi05033042001-11-13 16:11:35 +0000735 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000736 ret = vfs_follow_link(nd, link);
737 free_link(link);
738 return ret;
739}
740
741static int fuse_dir_open(struct inode *inode, struct file *file)
742{
Miklos Szeredi152f29e2004-06-03 17:52:32 +0000743 file->private_data = NULL;
744 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000745}
746
747static int fuse_dir_release(struct inode *inode, struct file *file)
748{
749 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000750
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000751 if (cfile)
Miklos Szeredia181e612001-11-06 12:03:23 +0000752 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000753
754 return 0;
755}
756
Miklos Szeredi83a07442004-11-30 18:25:20 +0000757static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000758{
Miklos Szeredi83a07442004-11-30 18:25:20 +0000759 unsigned ivalid = iattr->ia_valid;
760 unsigned fvalid = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000761
Miklos Szeredi5e183482001-10-31 14:52:35 +0000762 memset(fattr, 0, sizeof(*fattr));
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000763
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000764 if (ivalid & ATTR_MODE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000765 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000766 if (ivalid & ATTR_UID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000767 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000768 if (ivalid & ATTR_GID)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000769 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000770 if (ivalid & ATTR_SIZE)
Miklos Szeredi5e183482001-10-31 14:52:35 +0000771 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
772 /* You can only _set_ these together (they may change by themselves) */
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000773 if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000774 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000775#ifdef KERNEL_2_6
776 fattr->atime = iattr->ia_atime.tv_sec;
777 fattr->mtime = iattr->ia_mtime.tv_sec;
778#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000779 fattr->atime = iattr->ia_atime;
780 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000781#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000782 }
783
784 return fvalid;
785}
786
787static int fuse_setattr(struct dentry *entry, struct iattr *attr)
788{
789 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000790 struct fuse_conn *fc = get_fuse_conn(inode);
791 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredi58615e02004-07-04 21:21:08 +0000792 struct fuse_req *req;
Miklos Szeredia181e612001-11-06 12:03:23 +0000793 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000794 struct fuse_attr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000795 int err;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000796 int is_truncate = 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000797
Miklos Szeredi94ed76a2004-07-26 19:38:45 +0000798 if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
799 err = inode_change_ok(inode, attr);
800 if (err)
801 return err;
802 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000803
Miklos Szeredi069c9502004-07-16 16:17:02 +0000804 if (attr->ia_valid & ATTR_SIZE) {
805 unsigned long limit;
806 is_truncate = 1;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000807#ifdef KERNEL_2_6_10_PLUS
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000808 limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000809#else
810 limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
Miklos Szeredi08ddb8e2004-11-14 09:19:51 +0000811#endif
812 if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
Miklos Szeredi069c9502004-07-16 16:17:02 +0000813 send_sig(SIGXFSZ, current, 0);
814 return -EFBIG;
815 }
Miklos Szeredi069c9502004-07-16 16:17:02 +0000816 }
Miklos Szeredi58615e02004-07-04 21:21:08 +0000817
818 req = fuse_get_request(fc);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000819 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000820 return -ERESTARTNOINTR;
Miklos Szeredi069c9502004-07-16 16:17:02 +0000821
Miklos Szeredi43696432001-11-18 19:15:05 +0000822 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000823 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000824 req->in.h.opcode = FUSE_SETATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000825 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000826 req->in.numargs = 1;
827 req->in.args[0].size = sizeof(inarg);
828 req->in.args[0].value = &inarg;
829 req->out.numargs = 1;
830 req->out.args[0].size = sizeof(outarg);
831 req->out.args[0].value = &outarg;
832 request_send(fc, req);
833 err = req->out.h.error;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000834 fuse_put_request(fc, req);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000835 if (!err) {
836 if (is_truncate) {
837 loff_t origsize = i_size_read(inode);
838 i_size_write(inode, outarg.attr.size);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000839 if (origsize > outarg.attr.size)
840 vmtruncate(inode, outarg.attr.size);
841 }
842 change_attributes(inode, &outarg.attr);
843 fi->i_time = time_to_jiffies(outarg.attr_valid,
844 outarg.attr_valid_nsec);
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000845 } else if (err == -EINTR)
846 fuse_invalidate_attr(inode);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000847
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000848 return err;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000849}
850
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000851static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000852{
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000853 if (!entry->d_inode)
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000854 return 0;
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000855 else if (entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredie56818b2004-12-12 11:45:24 +0000856 int err;
857 int version;
858 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000859 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000860 struct fuse_inode *fi = get_fuse_inode(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000861 struct fuse_conn *fc = get_fuse_conn(inode);
862 struct fuse_req *req = fuse_get_request_nonint(fc);
863 if (!req)
864 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000865
Miklos Szeredie56818b2004-12-12 11:45:24 +0000866 fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
867 request_send_nonint(fc, req, 0);
868 version = req->out.h.unique;
869 err = req->out.h.error;
870 fuse_put_request(fc, req);
871 if (err)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000872 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000873
Miklos Szeredi039322d2004-12-01 18:39:12 +0000874 if (outarg.nodeid != get_node_id(inode))
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000875 return 0;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000876
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000877 change_attributes(inode, &outarg.attr);
878 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000879 entry->d_time = time_to_jiffies(outarg.entry_valid,
880 outarg.entry_valid_nsec);
Miklos Szeredi069c9502004-07-16 16:17:02 +0000881 fi->i_time = time_to_jiffies(outarg.attr_valid,
882 outarg.attr_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000883 }
884 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000885}
886
Miklos Szeredif85ab242004-01-07 12:16:45 +0000887#ifdef KERNEL_2_6
Miklos Szeredif85ab242004-01-07 12:16:45 +0000888static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
889 struct kstat *stat)
890{
891 struct inode *inode = entry->d_inode;
892 int err = fuse_revalidate(entry);
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000893 if (!err)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000894 generic_fillattr(inode, stat);
Miklos Szerediaa63b6b2004-12-03 13:24:35 +0000895
Miklos Szeredif85ab242004-01-07 12:16:45 +0000896 return err;
897}
898
899static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000900 struct nameidata *nd)
Miklos Szeredif85ab242004-01-07 12:16:45 +0000901{
Miklos Szeredie815c032004-01-19 18:20:49 +0000902 struct inode *inode;
903 int err = fuse_lookup_iget(dir, entry, &inode);
904 if (err)
905 return ERR_PTR(err);
906 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000907}
Miklos Szeredi689f5632004-05-04 08:49:16 +0000908#else /* KERNEL_2_6 */
Miklos Szeredi689f5632004-05-04 08:49:16 +0000909static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
910{
911 struct inode *inode;
912 struct dentry *alias;
913
914 int err = fuse_lookup_iget(dir, entry, &inode);
915 if (err)
916 return ERR_PTR(err);
917
918 if (inode && S_ISDIR(inode->i_mode) &&
919 (alias = d_find_alias(inode)) != NULL) {
920 dput(alias);
921 iput(inode);
Miklos Szeredie56818b2004-12-12 11:45:24 +0000922 return ERR_PTR(-EIO);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000923 }
924
925 d_add(entry, inode);
926 return NULL;
927}
928
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000929static int fuse_mknod_2_4(struct inode *dir, struct dentry *entry, int mode,
Miklos Szeredi83a07442004-11-30 18:25:20 +0000930 int rdev)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000931{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000932 return fuse_mknod(dir, entry, mode, rdev);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000933}
934
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000935static int fuse_dentry_revalidate_2_4(struct dentry *entry, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000936{
Miklos Szeredi13ed4822004-11-20 11:12:21 +0000937 return fuse_dentry_revalidate(entry, NULL);
938}
939
940static int fuse_create_2_4(struct inode *dir, struct dentry *entry, int mode)
941{
942 return fuse_create(dir, entry, mode, NULL);
943}
944
945static int fuse_permission_2_4(struct inode *inode, int mask)
946{
947 return fuse_permission(inode, mask, NULL);
Miklos Szeredi689f5632004-05-04 08:49:16 +0000948}
949#endif /* KERNEL_2_6 */
950
951#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi689f5632004-05-04 08:49:16 +0000952#ifdef KERNEL_2_6
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000953static int fuse_setxattr(struct dentry *entry, const char *name,
954 const void *value, size_t size, int flags)
Miklos Szeredi689f5632004-05-04 08:49:16 +0000955#else
956static int fuse_setxattr(struct dentry *entry, const char *name,
957 void *value, size_t size, int flags)
958#endif
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000959{
960 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000961 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000962 struct fuse_req *req;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000963 struct fuse_setxattr_in inarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000964 int err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000965
Miklos Szeredic26c14d2004-04-09 17:48:32 +0000966 if (size > FUSE_XATTR_SIZE_MAX)
967 return -E2BIG;
968
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000969 if (fc->no_setxattr)
970 return -EOPNOTSUPP;
971
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000972 req = fuse_get_request(fc);
973 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +0000974 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000975
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000976 memset(&inarg, 0, sizeof(inarg));
977 inarg.size = size;
978 inarg.flags = flags;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000979 req->in.h.opcode = FUSE_SETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +0000980 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000981 req->in.numargs = 3;
982 req->in.args[0].size = sizeof(inarg);
983 req->in.args[0].value = &inarg;
984 req->in.args[1].size = strlen(name) + 1;
985 req->in.args[1].value = name;
986 req->in.args[2].size = size;
987 req->in.args[2].value = value;
988 request_send(fc, req);
989 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +0000990 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000991 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000992 fc->no_setxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000993 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +0000994 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +0000995 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +0000996}
997
998static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
999 void *value, size_t size)
1000{
1001 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001002 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001003 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001004 struct fuse_getxattr_in inarg;
1005 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001006 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001007
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001008 if (fc->no_getxattr)
1009 return -EOPNOTSUPP;
1010
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001011 req = fuse_get_request(fc);
1012 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +00001013 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001014
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001015 memset(&inarg, 0, sizeof(inarg));
1016 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001017 req->in.h.opcode = FUSE_GETXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001018 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001019 req->in.numargs = 2;
1020 req->in.args[0].size = sizeof(inarg);
1021 req->in.args[0].value = &inarg;
1022 req->in.args[1].size = strlen(name) + 1;
1023 req->in.args[1].value = name;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001024 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001025 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001026 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001027 req->out.argvar = 1;
1028 req->out.args[0].size = size;
1029 req->out.args[0].value = value;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001030 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001031 req->out.args[0].size = sizeof(outarg);
1032 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001033 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001034 request_send(fc, req);
1035 ret = req->out.h.error;
1036 if (!ret)
1037 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001038 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001039 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001040 fc->no_getxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001041 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001042 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001043 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001044 fuse_put_request(fc, req);
1045 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001046}
1047
1048static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
1049{
1050 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001051 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001052 struct fuse_req *req;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001053 struct fuse_getxattr_in inarg;
1054 struct fuse_getxattr_out outarg;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001055 ssize_t ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001056
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001057 if (fc->no_listxattr)
1058 return -EOPNOTSUPP;
1059
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001060 req = fuse_get_request(fc);
1061 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +00001062 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001063
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001064 memset(&inarg, 0, sizeof(inarg));
1065 inarg.size = size;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001066 req->in.h.opcode = FUSE_LISTXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001067 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001068 req->in.numargs = 1;
1069 req->in.args[0].size = sizeof(inarg);
1070 req->in.args[0].value = &inarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001071 /* This is really two different operations rolled into one */
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001072 req->out.numargs = 1;
Miklos Szeredic26c14d2004-04-09 17:48:32 +00001073 if (size) {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001074 req->out.argvar = 1;
1075 req->out.args[0].size = size;
1076 req->out.args[0].value = list;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001077 } else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001078 req->out.args[0].size = sizeof(outarg);
1079 req->out.args[0].value = &outarg;
Miklos Szeredi03cebae2004-03-31 10:19:18 +00001080 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001081 request_send(fc, req);
1082 ret = req->out.h.error;
1083 if (!ret)
1084 ret = size ? req->out.args[0].size : outarg.size;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001085 else {
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001086 if (ret == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001087 fc->no_listxattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001088 ret = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001089 }
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001090 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001091 fuse_put_request(fc, req);
1092 return ret;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001093}
1094
1095static int fuse_removexattr(struct dentry *entry, const char *name)
1096{
1097 struct inode *inode = entry->d_inode;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001098 struct fuse_conn *fc = get_fuse_conn(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001099 struct fuse_req *req;
1100 int err;
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001101
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001102 if (fc->no_removexattr)
1103 return -EOPNOTSUPP;
1104
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001105 req = fuse_get_request(fc);
1106 if (!req)
Miklos Szeredie56818b2004-12-12 11:45:24 +00001107 return -ERESTARTNOINTR;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001108
1109 req->in.h.opcode = FUSE_REMOVEXATTR;
Miklos Szeredi039322d2004-12-01 18:39:12 +00001110 req->in.h.nodeid = get_node_id(inode);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001111 req->in.numargs = 1;
1112 req->in.args[0].size = strlen(name) + 1;
1113 req->in.args[0].value = name;
1114 request_send(fc, req);
1115 err = req->out.h.error;
Miklos Szeredi0fcfa032004-12-13 15:22:28 +00001116 fuse_put_request(fc, req);
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001117 if (err == -ENOSYS) {
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001118 fc->no_removexattr = 1;
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001119 err = -EOPNOTSUPP;
Miklos Szeredi63b8c1c2004-06-03 14:45:04 +00001120 }
Miklos Szeredi7eafcce2004-06-19 22:42:38 +00001121 return err;
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001122}
Miklos Szeredi689f5632004-05-04 08:49:16 +00001123#endif
Miklos Szeredif85ab242004-01-07 12:16:45 +00001124
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001125static struct inode_operations fuse_dir_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001126 .lookup = fuse_lookup,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001127 .mkdir = fuse_mkdir,
1128 .symlink = fuse_symlink,
1129 .unlink = fuse_unlink,
1130 .rmdir = fuse_rmdir,
1131 .rename = fuse_rename,
1132 .link = fuse_link,
1133 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001134#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001135 .create = fuse_create,
1136 .mknod = fuse_mknod,
1137 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001138 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001139#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001140 .create = fuse_create_2_4,
1141 .mknod = fuse_mknod_2_4,
1142 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001143 .revalidate = fuse_revalidate,
1144#endif
1145#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001146 .setxattr = fuse_setxattr,
1147 .getxattr = fuse_getxattr,
1148 .listxattr = fuse_listxattr,
1149 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001150#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001151};
1152
1153static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001154 .read = generic_read_dir,
1155 .readdir = fuse_readdir,
1156 .open = fuse_dir_open,
1157 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001158};
1159
1160static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001161 .setattr = fuse_setattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001162#ifdef KERNEL_2_6
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001163 .permission = fuse_permission,
Miklos Szeredie8663f32004-01-13 15:33:12 +00001164 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001165#else
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001166 .permission = fuse_permission_2_4,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001167 .revalidate = fuse_revalidate,
1168#endif
1169#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001170 .setxattr = fuse_setxattr,
1171 .getxattr = fuse_getxattr,
1172 .listxattr = fuse_listxattr,
1173 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001174#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001175};
1176
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001177static struct inode_operations fuse_symlink_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +00001178 .setattr = fuse_setattr,
1179 .readlink = fuse_readlink,
1180 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001181#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001182 .getattr = fuse_getattr,
Miklos Szeredi689f5632004-05-04 08:49:16 +00001183#else
1184 .revalidate = fuse_revalidate,
1185#endif
1186#ifdef HAVE_KERNEL_XATTR
Miklos Szeredi3ed84232004-03-30 15:17:26 +00001187 .setxattr = fuse_setxattr,
1188 .getxattr = fuse_getxattr,
1189 .listxattr = fuse_listxattr,
1190 .removexattr = fuse_removexattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +00001191#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +00001192};
1193
Miklos Szeredi307242f2004-01-26 11:28:44 +00001194static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001195#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +00001196 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001197#else
Miklos Szerediaa63b6b2004-12-03 13:24:35 +00001198 .d_revalidate = fuse_dentry_revalidate_2_4,
Miklos Szeredi13ed4822004-11-20 11:12:21 +00001199#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001200};