blob: 7da5bc235bda05c52daadad367fbe8de687a029f [file] [log] [blame]
Miklos Szeredi85c74fc2001-10-28 19:44:14 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001 Miklos Szeredi (mszeredi@inf.bme.hu)
4
5 This program can be distributed under the terms of the GNU GPL.
6 See the file COPYING.
7*/
8
9#include "fuse_i.h"
10
Miklos Szeredi05033042001-11-13 16:11:35 +000011#include <linux/pagemap.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000012#include <linux/slab.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000013#include <linux/file.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000014
Miklos Szeredib483c932001-10-29 14:57:57 +000015static struct inode_operations fuse_dir_inode_operations;
16static struct inode_operations fuse_file_inode_operations;
17static struct inode_operations fuse_symlink_inode_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000018
19static struct file_operations fuse_dir_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000020
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000021static struct dentry_operations fuse_dentry_opertations;
Miklos Szeredib483c932001-10-29 14:57:57 +000022
Miklos Szeredif3ea83b2001-11-07 14:55:16 +000023/* FIXME: This should be user configurable */
24#define FUSE_REVALIDATE_TIME (1 * HZ)
Miklos Szeredi97c61e92001-11-07 12:09:43 +000025
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000026static void change_attributes(struct inode *inode, struct fuse_attr *attr)
27{
Miklos Szeredif85ab242004-01-07 12:16:45 +000028 if(S_ISREG(inode->i_mode) && inode->i_size != attr->size) {
29#ifdef KERNEL_2_6
30 invalidate_inode_pages(inode->i_mapping);
31#else
Miklos Szeredia181e612001-11-06 12:03:23 +000032 invalidate_inode_pages(inode);
Miklos Szeredif85ab242004-01-07 12:16:45 +000033#endif
34 }
Miklos Szeredia181e612001-11-06 12:03:23 +000035
Miklos Szeredi5e183482001-10-31 14:52:35 +000036 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000037 inode->i_nlink = attr->nlink;
38 inode->i_uid = attr->uid;
39 inode->i_gid = attr->gid;
40 inode->i_size = attr->size;
Miklos Szeredi05033042001-11-13 16:11:35 +000041 inode->i_blksize = PAGE_CACHE_SIZE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000042 inode->i_blocks = attr->blocks;
Miklos Szeredif85ab242004-01-07 12:16:45 +000043#ifdef KERNEL_2_6
44 inode->i_atime.tv_sec = attr->atime;
45 inode->i_atime.tv_nsec = 0;
46 inode->i_mtime.tv_sec = attr->mtime;
47 inode->i_mtime.tv_nsec = 0;
48 inode->i_ctime.tv_sec = attr->ctime;
49 inode->i_ctime.tv_nsec = 0;
50#else
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000051 inode->i_atime = attr->atime;
52 inode->i_mtime = attr->mtime;
53 inode->i_ctime = attr->ctime;
Miklos Szeredif85ab242004-01-07 12:16:45 +000054#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000055}
56
Miklos Szeredia181e612001-11-06 12:03:23 +000057static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000058{
Miklos Szeredia181e612001-11-06 12:03:23 +000059 inode->i_mode = attr->mode & S_IFMT;
60 inode->i_size = attr->size;
Miklos Szeredib483c932001-10-29 14:57:57 +000061 if(S_ISREG(inode->i_mode)) {
62 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000063 fuse_init_file_inode(inode);
Miklos Szeredib483c932001-10-29 14:57:57 +000064 }
65 else if(S_ISDIR(inode->i_mode)) {
66 inode->i_op = &fuse_dir_inode_operations;
67 inode->i_fop = &fuse_dir_operations;
68 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000069 else if(S_ISLNK(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000070 inode->i_op = &fuse_symlink_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000071 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000072 else {
Miklos Szeredia181e612001-11-06 12:03:23 +000073 inode->i_op = &fuse_file_inode_operations;
74 init_special_inode(inode, inode->i_mode, attr->rdev);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000075 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000076 inode->u.generic_ip = inode;
77}
78
79struct inode *fuse_iget(struct super_block *sb, ino_t ino,
Miklos Szeredia181e612001-11-06 12:03:23 +000080 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +000081{
82 struct inode *inode;
83
84 inode = iget(sb, ino);
85 if(inode) {
86 if(!inode->u.generic_ip)
Miklos Szeredia181e612001-11-06 12:03:23 +000087 fuse_init_inode(inode, attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +000088
89 change_attributes(inode, attr);
Miklos Szeredia181e612001-11-06 12:03:23 +000090 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +000091 }
92
93 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000094}
95
Miklos Szeredi43696432001-11-18 19:15:05 +000096/* If the inode belongs to an existing directory, then it cannot be
97 assigned to new dentry */
98static int inode_ok(struct inode *inode)
99{
100 struct dentry *alias;
101 if(S_ISDIR(inode->i_mode) && (alias = d_find_alias(inode)) != NULL) {
102 dput(alias);
103 printk("fuse: cannot assign an existing directory\n");
104 return 0;
105
106 }
107 return 1;
108}
109
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000110static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
111 struct fuse_lookup_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000112{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000113 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000114 struct fuse_in in = FUSE_IN_INIT;
115 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000116
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000117 in.h.opcode = FUSE_LOOKUP;
118 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000119 in.numargs = 1;
120 in.args[0].size = entry->d_name.len + 1;
121 in.args[0].value = entry->d_name.name;
122 out.numargs = 1;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000123 out.args[0].size = sizeof(struct fuse_lookup_out);
124 out.args[0].value = outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000125 request_send(fc, &in, &out);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000126
127 *version = out.h.unique;
128 return out.h.error;
129}
130
Miklos Szeredif85ab242004-01-07 12:16:45 +0000131static struct dentry *_fuse_lookup(struct inode *dir, struct dentry *entry)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000132{
133 int ret;
134 struct fuse_lookup_out outarg;
135 int version;
136 struct inode *inode;
137
138 ret = fuse_do_lookup(dir, entry, &outarg, &version);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000139 inode = NULL;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000140 if(!ret) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000141 ret = -ENOMEM;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000142 inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, version);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000143 if(!inode)
Miklos Szeredia181e612001-11-06 12:03:23 +0000144 goto err;
Miklos Szeredi43696432001-11-18 19:15:05 +0000145
146 ret = -EPROTO;
147 if(!inode_ok(inode)) {
148 iput(inode);
149 goto err;
150 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000151 }
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000152 else if(ret != -ENOENT)
Miklos Szeredia181e612001-11-06 12:03:23 +0000153 goto err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000154
Miklos Szeredia181e612001-11-06 12:03:23 +0000155 entry->d_time = jiffies;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000156 entry->d_op = &fuse_dentry_opertations;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000157 d_add(entry, inode);
Miklos Szeredia181e612001-11-06 12:03:23 +0000158
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000159 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000160
161 err:
162 return ERR_PTR(ret);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000163}
164
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000165/* create needs to return a positive entry, so this is actually an
166 mknod+lookup */
Miklos Szeredif85ab242004-01-07 12:16:45 +0000167static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
168 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000169{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000170 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000171 struct fuse_in in = FUSE_IN_INIT;
172 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000173 struct fuse_mknod_in inarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000174 struct fuse_mknod_out outarg;
175 struct inode *inode;
Miklos Szeredi43696432001-11-18 19:15:05 +0000176
177 memset(&inarg, 0, sizeof(inarg));
178 inarg.mode = mode;
179 inarg.rdev = rdev;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000180
181 in.h.opcode = FUSE_MKNOD;
182 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000183 in.numargs = 2;
184 in.args[0].size = sizeof(inarg);
185 in.args[0].value = &inarg;
186 in.args[1].size = entry->d_name.len + 1;
187 in.args[1].value = entry->d_name.name;
188 out.numargs = 1;
189 out.args[0].size = sizeof(outarg);
190 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000191 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000192
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000193 if(out.h.error)
194 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000195
Miklos Szeredia181e612001-11-06 12:03:23 +0000196 inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000197 if(!inode)
198 return -ENOMEM;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000199
Miklos Szeredi43696432001-11-18 19:15:05 +0000200 /* Don't allow userspace to do really stupid things... */
201 if((inode->i_mode ^ mode) & S_IFMT) {
202 iput(inode);
203 printk("fuse_mknod: inode has wrong type\n");
204 return -EPROTO;
205 }
206
207 if(!inode_ok(inode)) {
208 iput(inode);
209 return -EPROTO;
210 }
211
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000212 d_instantiate(entry, inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000213 return 0;
214}
215
Miklos Szeredif85ab242004-01-07 12:16:45 +0000216static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000217{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000218 return _fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000219}
220
Miklos Szeredib483c932001-10-29 14:57:57 +0000221static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
222{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000223 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000224 struct fuse_in in = FUSE_IN_INIT;
225 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000226 struct fuse_mkdir_in inarg;
227
228 memset(&inarg, 0, sizeof(inarg));
229 inarg.mode = mode;
Miklos Szeredib483c932001-10-29 14:57:57 +0000230
231 in.h.opcode = FUSE_MKDIR;
232 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000233 in.numargs = 2;
234 in.args[0].size = sizeof(inarg);
235 in.args[0].value = &inarg;
236 in.args[1].size = entry->d_name.len + 1;
237 in.args[1].value = entry->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000238 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000239
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000240 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000241}
242
243static int fuse_symlink(struct inode *dir, struct dentry *entry,
244 const char *link)
245{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000246 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000247 struct fuse_in in = FUSE_IN_INIT;
248 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredib483c932001-10-29 14:57:57 +0000249
250 in.h.opcode = FUSE_SYMLINK;
251 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000252 in.numargs = 2;
253 in.args[0].size = entry->d_name.len + 1;
254 in.args[0].value = entry->d_name.name;
255 in.args[1].size = strlen(link) + 1;
256 in.args[1].value = link;
Miklos Szeredib483c932001-10-29 14:57:57 +0000257 request_send(fc, &in, &out);
Miklos Szeredi43696432001-11-18 19:15:05 +0000258
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000259 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000260}
261
262static int fuse_remove(struct inode *dir, struct dentry *entry,
263 enum fuse_opcode op)
264{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000265 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000266 struct fuse_in in = FUSE_IN_INIT;
267 struct fuse_out out = FUSE_OUT_INIT;
268
269 in.h.opcode = op;
270 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000271 in.numargs = 1;
272 in.args[0].size = entry->d_name.len + 1;
273 in.args[0].value = entry->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000274 request_send(fc, &in, &out);
Miklos Szeredi43696432001-11-18 19:15:05 +0000275
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000276 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000277}
278
279static int fuse_unlink(struct inode *dir, struct dentry *entry)
280{
281 return fuse_remove(dir, entry, FUSE_UNLINK);
282}
283
284static int fuse_rmdir(struct inode *dir, struct dentry *entry)
285{
286 return fuse_remove(dir, entry, FUSE_RMDIR);
287}
288
289static int fuse_rename(struct inode *olddir, struct dentry *oldent,
290 struct inode *newdir, struct dentry *newent)
291{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000292 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000293 struct fuse_in in = FUSE_IN_INIT;
294 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000295 struct fuse_rename_in inarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000296
Miklos Szeredi43696432001-11-18 19:15:05 +0000297 memset(&inarg, 0, sizeof(inarg));
298 inarg.newdir = newdir->i_ino;
Miklos Szeredib483c932001-10-29 14:57:57 +0000299
300 in.h.opcode = FUSE_RENAME;
301 in.h.ino = olddir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000302 in.numargs = 3;
303 in.args[0].size = sizeof(inarg);
304 in.args[0].value = &inarg;
305 in.args[1].size = oldent->d_name.len + 1;
306 in.args[1].value = oldent->d_name.name;
307 in.args[2].size = newent->d_name.len + 1;
308 in.args[2].value = newent->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000309 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000310
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000311 return out.h.error;
312}
313
314static int fuse_link(struct dentry *entry, struct inode *newdir,
315 struct dentry *newent)
316{
317 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000318 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000319 struct fuse_in in = FUSE_IN_INIT;
320 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000321 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000322
Miklos Szeredi43696432001-11-18 19:15:05 +0000323 memset(&inarg, 0, sizeof(inarg));
324 inarg.newdir = newdir->i_ino;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000325
326 in.h.opcode = FUSE_LINK;
327 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000328 in.numargs = 2;
329 in.args[0].size = sizeof(inarg);
330 in.args[0].value = &inarg;
331 in.args[1].size = newent->d_name.len + 1;
332 in.args[1].value = newent->d_name.name;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000333 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000334
335 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000336}
337
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000338
Miklos Szeredif85ab242004-01-07 12:16:45 +0000339int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000340{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000341 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342 struct fuse_in in = FUSE_IN_INIT;
343 struct fuse_out out = FUSE_OUT_INIT;
344 struct fuse_getattr_out arg;
345
346 in.h.opcode = FUSE_GETATTR;
347 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000348 out.numargs = 1;
349 out.args[0].size = sizeof(arg);
350 out.args[0].value = &arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000351 request_send(fc, &in, &out);
352
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000353 if(!out.h.error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000354 change_attributes(inode, &arg.attr);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000355
356 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000357}
358
Miklos Szeredife25def2001-12-20 15:38:05 +0000359static int fuse_revalidate(struct dentry *entry)
360{
361 struct inode *inode = entry->d_inode;
362 struct fuse_conn *fc = INO_FC(inode);
363
364 if(inode->i_ino == FUSE_ROOT_INO) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000365 if(!(fc->flags & FUSE_ALLOW_OTHER) &&
366 current->fsuid != fc->uid)
Miklos Szeredife25def2001-12-20 15:38:05 +0000367 return -EACCES;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000368 } else if(time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
Miklos Szeredife25def2001-12-20 15:38:05 +0000369 return 0;
370
Miklos Szeredif85ab242004-01-07 12:16:45 +0000371 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000372}
373
Miklos Szeredif85ab242004-01-07 12:16:45 +0000374static int _fuse_permission(struct inode *inode, int mask)
Miklos Szeredife25def2001-12-20 15:38:05 +0000375{
376 struct fuse_conn *fc = INO_FC(inode);
377
378 if(!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
379 return -EACCES;
380 else if(fc->flags & FUSE_DEFAULT_PERMISSIONS) {
381 int err = vfs_permission(inode, mask);
382
383 /* If permission is denied, try to refresh file
384 attributes. This is also needed, because the root
385 node will at first have no permissions */
386
387 if(err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000388 err = fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000389 if(!err)
390 err = vfs_permission(inode, mask);
391 }
392
393 /* FIXME: Need some mechanism to revoke permissions:
394 currently if the filesystem suddenly changes the
395 file mode, we will not be informed abot that, and
396 continue to allow access to the file/directory.
397
398 This is actually not so grave, since the user can
399 simply keep access to the file/directory anyway by
400 keeping it open... */
401
402 return err;
403 }
404 else
405 return 0;
406}
407
Miklos Szeredib483c932001-10-29 14:57:57 +0000408static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
409 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000410{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000411 while(nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000412 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000413 size_t reclen = FUSE_DIRENT_SIZE(dirent);
414 int over;
415 if(dirent->namelen > NAME_MAX) {
416 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000417 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000418 }
419 if(reclen > nbytes)
420 break;
421
422 over = filldir(dstbuf, dirent->name, dirent->namelen,
423 file->f_pos, dirent->ino, dirent->type);
424 if(over)
425 break;
426
Miklos Szeredib483c932001-10-29 14:57:57 +0000427 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000428 file->f_pos += reclen;
429 nbytes -= reclen;
430 }
431
Miklos Szeredib483c932001-10-29 14:57:57 +0000432 return 0;
433}
434
435#define DIR_BUFSIZE 2048
436static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
437{
438 struct file *cfile = file->private_data;
439 char *buf;
440 int ret;
441
442 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
443 if(!buf)
444 return -ENOMEM;
445
446 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
447 if(ret < 0)
448 printk("fuse_readdir: failed to read container file\n");
449 else
450 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
451
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000452 kfree(buf);
453 return ret;
454}
455
Miklos Szeredi05033042001-11-13 16:11:35 +0000456static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000457{
458 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000459 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000460 struct fuse_in in = FUSE_IN_INIT;
461 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi05033042001-11-13 16:11:35 +0000462 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000463
Miklos Szeredi05033042001-11-13 16:11:35 +0000464 link = (char *) __get_free_page(GFP_KERNEL);
465 if(!link)
466 return ERR_PTR(-ENOMEM);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000467
468 in.h.opcode = FUSE_READLINK;
469 in.h.ino = inode->i_ino;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000470 out.argvar = 1;
Miklos Szeredi43696432001-11-18 19:15:05 +0000471 out.numargs = 1;
472 out.args[0].size = PAGE_SIZE - 1;
473 out.args[0].value = link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000474 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000475 if(out.h.error) {
Miklos Szeredi05033042001-11-13 16:11:35 +0000476 free_page((unsigned long) link);
477 return ERR_PTR(out.h.error);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000478 }
479
Miklos Szeredi43696432001-11-18 19:15:05 +0000480 link[out.args[0].size] = '\0';
Miklos Szeredi05033042001-11-13 16:11:35 +0000481 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000482}
483
484static void free_link(char *link)
485{
Miklos Szeredi05033042001-11-13 16:11:35 +0000486 if(!IS_ERR(link))
487 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000488}
489
490static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
491{
492 int ret;
493 char *link;
494
Miklos Szeredi05033042001-11-13 16:11:35 +0000495 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000496 ret = vfs_readlink(dentry, buffer, buflen, link);
497 free_link(link);
498 return ret;
499}
500
501static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
502{
503 int ret;
504 char *link;
505
Miklos Szeredi05033042001-11-13 16:11:35 +0000506 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000507 ret = vfs_follow_link(nd, link);
508 free_link(link);
509 return ret;
510}
511
512static int fuse_dir_open(struct inode *inode, struct file *file)
513{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000514 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000515 struct fuse_in in = FUSE_IN_INIT;
516 struct fuse_out out = FUSE_OUT_INIT;
517 struct fuse_getdir_out outarg;
518
519 if(!(file->f_flags & O_DIRECTORY))
Miklos Szeredia181e612001-11-06 12:03:23 +0000520 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000521
522 in.h.opcode = FUSE_GETDIR;
523 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000524 out.numargs = 1;
525 out.args[0].size = sizeof(outarg);
526 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000527 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000528 if(!out.h.error) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000529 struct file *cfile = outarg.file;
530 struct inode *inode;
531 if(!cfile) {
532 printk("fuse_getdir: invalid file\n");
533 return -EPROTO;
534 }
535 inode = cfile->f_dentry->d_inode;
536 if(!S_ISREG(inode->i_mode)) {
537 printk("fuse_getdir: not a regular file\n");
538 fput(cfile);
539 return -EPROTO;
540 }
541
542 file->private_data = cfile;
543 }
544
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000545 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000546}
547
548static int fuse_dir_release(struct inode *inode, struct file *file)
549{
550 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000551
552 if(cfile)
553 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000554
555 return 0;
556}
557
Miklos Szeredi5e183482001-10-31 14:52:35 +0000558static unsigned int iattr_to_fattr(struct iattr *iattr,
559 struct fuse_attr *fattr)
560{
561 unsigned int ivalid = iattr->ia_valid;
562 unsigned int fvalid = 0;
563
564 memset(fattr, 0, sizeof(*fattr));
565
566 if(ivalid & ATTR_MODE)
567 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
568 if(ivalid & ATTR_UID)
569 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
570 if(ivalid & ATTR_GID)
571 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
572 if(ivalid & ATTR_SIZE)
573 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
574 /* You can only _set_ these together (they may change by themselves) */
575 if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
576 fvalid |= FATTR_UTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000577#ifdef KERNEL_2_6
578 fattr->atime = iattr->ia_atime.tv_sec;
579 fattr->mtime = iattr->ia_mtime.tv_sec;
580#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000581 fattr->atime = iattr->ia_atime;
582 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000583#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000584 }
585
586 return fvalid;
587}
588
589static int fuse_setattr(struct dentry *entry, struct iattr *attr)
590{
591 struct inode *inode = entry->d_inode;
592 struct fuse_conn *fc = INO_FC(inode);
593 struct fuse_in in = FUSE_IN_INIT;
594 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000595 struct fuse_setattr_in inarg;
596 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000597
Miklos Szeredi43696432001-11-18 19:15:05 +0000598 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000599 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000600
601 in.h.opcode = FUSE_SETATTR;
602 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000603 in.numargs = 1;
604 in.args[0].size = sizeof(inarg);
605 in.args[0].value = &inarg;
606 out.numargs = 1;
607 out.args[0].size = sizeof(outarg);
608 out.args[0].value = &outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000609 request_send(fc, &in, &out);
610
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000611 if(!out.h.error) {
612 if(attr->ia_valid & ATTR_SIZE &&
613 outarg.attr.size < inode->i_size)
614 vmtruncate(inode, outarg.attr.size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000615
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000616 change_attributes(inode, &outarg.attr);
617 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000618 return out.h.error;
619}
620
Miklos Szeredif85ab242004-01-07 12:16:45 +0000621static int _fuse_dentry_revalidate(struct dentry *entry)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000622{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000623 if(!entry->d_inode)
624 return 0;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000625 else if(time_after(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) {
626 struct inode *inode = entry->d_inode;
627 struct fuse_lookup_out outarg;
628 int version;
629 int ret;
630
631 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
632 &version);
633 if(ret)
634 return 0;
635
636 if(outarg.ino != inode->i_ino)
637 return 0;
638
639 change_attributes(inode, &outarg.attr);
640 inode->i_version = version;
641 entry->d_time = jiffies;
642 }
643 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000644}
645
Miklos Szeredif85ab242004-01-07 12:16:45 +0000646#ifdef KERNEL_2_6
647
648#define fuse_mknod _fuse_mknod
649
650static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
651 struct kstat *stat)
652{
653 struct inode *inode = entry->d_inode;
654 int err = fuse_revalidate(entry);
655 if(!err)
656 generic_fillattr(inode, stat);
657
658 return err;
659}
660
661static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
662 struct nameidata *nd)
663{
664 return _fuse_lookup(dir, entry);
665}
666
667static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
668 struct nameidata *nd)
669{
670 return _fuse_create(dir, entry, mode);
671}
672
673static int fuse_permission(struct inode *inode, int mask,
674 struct nameidata *nd)
675{
676 return _fuse_permission(inode, mask);
677}
678
679static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
680{
681 return _fuse_dentry_revalidate(entry);
682}
683#else /* KERNEL_2_6 */
684
685#define fuse_lookup _fuse_lookup
686#define fuse_create _fuse_create
687#define fuse_permission _fuse_permission
688
689static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
690 int rdev)
691{
692 return fuse_mknod(dir, entry, mode, rdev);
693}
694
695static int fuse_dentry_revalidate(struct dentry *entry, int flags)
696{
697 return _fuse_dentry_revalidate(entry);
698}
699#endif /* KERNEL_2_6 */
700
701
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000702static struct inode_operations fuse_dir_inode_operations =
703{
Miklos Szeredie8663f32004-01-13 15:33:12 +0000704 .lookup = fuse_lookup,
705 .create = fuse_create,
706 .mknod = fuse_mknod,
707 .mkdir = fuse_mkdir,
708 .symlink = fuse_symlink,
709 .unlink = fuse_unlink,
710 .rmdir = fuse_rmdir,
711 .rename = fuse_rename,
712 .link = fuse_link,
713 .setattr = fuse_setattr,
714 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000715#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000716 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000717#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000718 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000719#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000720};
721
722static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000723 .read = generic_read_dir,
724 .readdir = fuse_readdir,
725 .open = fuse_dir_open,
726 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000727};
728
729static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000730 .setattr = fuse_setattr,
731 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000732#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000733 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000734#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000735 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000736#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000737};
738
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000739static struct inode_operations fuse_symlink_inode_operations =
740{
Miklos Szeredie8663f32004-01-13 15:33:12 +0000741 .setattr = fuse_setattr,
742 .readlink = fuse_readlink,
743 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000744#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000745 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000746#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000747 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000748#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000749};
750
751static struct dentry_operations fuse_dentry_opertations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000752 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000753};
754
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000755/*
756 * Local Variables:
757 * indent-tabs-mode: t
758 * c-basic-offset: 8
759 * End:
760 */