blob: 739b677fa57fe3270bbff9a5bf8bdcd4975b4739 [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 Szeredi307242f2004-01-26 11:28:44 +000021static struct dentry_operations fuse_dentry_operations;
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 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
30
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000031static void change_attributes(struct inode *inode, struct fuse_attr *attr)
32{
Miklos Szeredif85ab242004-01-07 12:16:45 +000033 if(S_ISREG(inode->i_mode) && inode->i_size != attr->size) {
34#ifdef KERNEL_2_6
35 invalidate_inode_pages(inode->i_mapping);
36#else
Miklos Szeredia181e612001-11-06 12:03:23 +000037 invalidate_inode_pages(inode);
Miklos Szeredif85ab242004-01-07 12:16:45 +000038#endif
39 }
Miklos Szeredia181e612001-11-06 12:03:23 +000040
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;
45 inode->i_size = 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;
50 inode->i_atime.tv_nsec = 0;
51 inode->i_mtime.tv_sec = attr->mtime;
52 inode->i_mtime.tv_nsec = 0;
53 inode->i_ctime.tv_sec = attr->ctime;
54 inode->i_ctime.tv_nsec = 0;
55#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;
65 inode->i_size = attr->size;
Miklos Szeredib483c932001-10-29 14:57:57 +000066 if(S_ISREG(inode->i_mode)) {
67 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 }
70 else if(S_ISDIR(inode->i_mode)) {
71 inode->i_op = &fuse_dir_inode_operations;
72 inode->i_fop = &fuse_dir_operations;
73 }
Miklos Szeredi5e183482001-10-31 14:52:35 +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 Szeredi85c74fc2001-10-28 19:44:14 +000077 else {
Miklos Szeredia181e612001-11-06 12:03:23 +000078 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000079 init_special_inode(inode, inode->i_mode,
80 new_decode_dev(attr->rdev));
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000081 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000082 inode->u.generic_ip = inode;
83}
84
85struct inode *fuse_iget(struct super_block *sb, ino_t ino,
Miklos Szeredia181e612001-11-06 12:03:23 +000086 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +000087{
88 struct inode *inode;
89
90 inode = iget(sb, ino);
91 if(inode) {
92 if(!inode->u.generic_ip)
Miklos Szeredia181e612001-11-06 12:03:23 +000093 fuse_init_inode(inode, attr);
Miklos Szeredie815c032004-01-19 18:20:49 +000094
Miklos Szeredi5e183482001-10-31 14:52:35 +000095 change_attributes(inode, attr);
Miklos Szeredia181e612001-11-06 12:03:23 +000096 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +000097 }
98
99 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000100}
101
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000102static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
103 struct fuse_lookup_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000104{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000105 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000106 struct fuse_in in = FUSE_IN_INIT;
107 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000108
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109 in.h.opcode = FUSE_LOOKUP;
110 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000111 in.numargs = 1;
112 in.args[0].size = entry->d_name.len + 1;
113 in.args[0].value = entry->d_name.name;
114 out.numargs = 1;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000115 out.args[0].size = sizeof(struct fuse_lookup_out);
116 out.args[0].value = outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000117 request_send(fc, &in, &out);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000118
119 *version = out.h.unique;
120 return out.h.error;
121}
122
Miklos Szeredie815c032004-01-19 18:20:49 +0000123static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
124 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000125{
Miklos Szeredie815c032004-01-19 18:20:49 +0000126 int err;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000127 struct fuse_lookup_out outarg;
128 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000129 struct inode *inode = NULL;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000130
Miklos Szeredie815c032004-01-19 18:20:49 +0000131 err = fuse_do_lookup(dir, entry, &outarg, &version);
132 if(!err) {
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000133 inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000134 if(!inode)
135 return -ENOMEM;
136 } else if(err != -ENOENT)
137 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000138
Miklos Szeredia181e612001-11-06 12:03:23 +0000139 entry->d_time = jiffies;
Miklos Szeredi307242f2004-01-26 11:28:44 +0000140 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000141 *inodep = inode;
142 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000143}
144
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000145/* create needs to return a positive entry, so this is actually an
146 mknod+lookup */
Miklos Szeredif85ab242004-01-07 12:16:45 +0000147static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
148 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000149{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000150 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000151 struct fuse_in in = FUSE_IN_INIT;
152 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000153 struct fuse_mknod_in inarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000154 struct fuse_mknod_out outarg;
155 struct inode *inode;
Miklos Szeredi43696432001-11-18 19:15:05 +0000156
157 memset(&inarg, 0, sizeof(inarg));
158 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000159 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000160
161 in.h.opcode = FUSE_MKNOD;
162 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000163 in.numargs = 2;
164 in.args[0].size = sizeof(inarg);
165 in.args[0].value = &inarg;
166 in.args[1].size = entry->d_name.len + 1;
167 in.args[1].value = entry->d_name.name;
168 out.numargs = 1;
169 out.args[0].size = sizeof(outarg);
170 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000171 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000172
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000173 if(out.h.error)
174 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000175
Miklos Szeredia181e612001-11-06 12:03:23 +0000176 inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000177 if(!inode)
178 return -ENOMEM;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000179
Miklos Szeredi43696432001-11-18 19:15:05 +0000180 /* Don't allow userspace to do really stupid things... */
181 if((inode->i_mode ^ mode) & S_IFMT) {
182 iput(inode);
183 printk("fuse_mknod: inode has wrong type\n");
184 return -EPROTO;
185 }
186
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000187 d_instantiate(entry, inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000188 return 0;
189}
190
Miklos Szeredif85ab242004-01-07 12:16:45 +0000191static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000192{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000193 return _fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000194}
195
Miklos Szeredie815c032004-01-19 18:20:49 +0000196/* knfsd needs the new entry instantiated in mkdir/symlink/link. this
197 should rather be done like mknod: attributes returned in out arg to
198 save a call to userspace */
199static int lookup_new_entry(struct inode *dir, struct dentry *entry)
200{
201 struct inode *inode;
202 int err = fuse_lookup_iget(dir, entry, &inode);
203 if(err || !inode) {
204 printk("fuse_mkdir: failed to look up new entry\n");
205 return err ? err : -ENOENT;
206 }
207 d_instantiate(entry, inode);
208 return 0;
209}
210
Miklos Szeredib483c932001-10-29 14:57:57 +0000211static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
212{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000213 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000214 struct fuse_in in = FUSE_IN_INIT;
215 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000216 struct fuse_mkdir_in inarg;
217
218 memset(&inarg, 0, sizeof(inarg));
219 inarg.mode = mode;
Miklos Szeredib483c932001-10-29 14:57:57 +0000220
221 in.h.opcode = FUSE_MKDIR;
222 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000223 in.numargs = 2;
224 in.args[0].size = sizeof(inarg);
225 in.args[0].value = &inarg;
226 in.args[1].size = entry->d_name.len + 1;
227 in.args[1].value = entry->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000228 request_send(fc, &in, &out);
Miklos Szeredie815c032004-01-19 18:20:49 +0000229 if(out.h.error)
230 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000231
Miklos Szeredie815c032004-01-19 18:20:49 +0000232 return lookup_new_entry(dir, entry);
Miklos Szeredib483c932001-10-29 14:57:57 +0000233}
234
235static int fuse_symlink(struct inode *dir, struct dentry *entry,
236 const char *link)
237{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000238 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000239 struct fuse_in in = FUSE_IN_INIT;
240 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredib483c932001-10-29 14:57:57 +0000241
242 in.h.opcode = FUSE_SYMLINK;
243 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000244 in.numargs = 2;
245 in.args[0].size = entry->d_name.len + 1;
246 in.args[0].value = entry->d_name.name;
247 in.args[1].size = strlen(link) + 1;
248 in.args[1].value = link;
Miklos Szeredib483c932001-10-29 14:57:57 +0000249 request_send(fc, &in, &out);
Miklos Szeredie815c032004-01-19 18:20:49 +0000250 if(out.h.error)
251 return out.h.error;
Miklos Szeredi43696432001-11-18 19:15:05 +0000252
Miklos Szeredie815c032004-01-19 18:20:49 +0000253 return lookup_new_entry(dir, entry);
Miklos Szeredib483c932001-10-29 14:57:57 +0000254}
255
256static int fuse_remove(struct inode *dir, struct dentry *entry,
257 enum fuse_opcode op)
258{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000259 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000260 struct fuse_in in = FUSE_IN_INIT;
261 struct fuse_out out = FUSE_OUT_INIT;
262
263 in.h.opcode = op;
264 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000265 in.numargs = 1;
266 in.args[0].size = entry->d_name.len + 1;
267 in.args[0].value = entry->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000268 request_send(fc, &in, &out);
Miklos Szeredi43696432001-11-18 19:15:05 +0000269
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000270 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000271}
272
273static int fuse_unlink(struct inode *dir, struct dentry *entry)
274{
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000275 int err = fuse_remove(dir, entry, FUSE_UNLINK);
276 if(!err) {
277 /* FIXME: the new i_nlink could be returned by the
278 unlink operation */
279 err = fuse_do_getattr(entry->d_inode);
280 if(err == -ENOENT)
281 entry->d_inode->i_nlink = 0;
282 return 0;
283 }
284 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000285}
286
287static int fuse_rmdir(struct inode *dir, struct dentry *entry)
288{
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000289 int err = fuse_remove(dir, entry, FUSE_RMDIR);
290 if(!err)
291 entry->d_inode->i_nlink = 0;
292 return err;
Miklos Szeredib483c932001-10-29 14:57:57 +0000293}
294
295static int fuse_rename(struct inode *olddir, struct dentry *oldent,
296 struct inode *newdir, struct dentry *newent)
297{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000298 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000299 struct fuse_in in = FUSE_IN_INIT;
300 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000301 struct fuse_rename_in inarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000302
Miklos Szeredi43696432001-11-18 19:15:05 +0000303 memset(&inarg, 0, sizeof(inarg));
304 inarg.newdir = newdir->i_ino;
Miklos Szeredib483c932001-10-29 14:57:57 +0000305
306 in.h.opcode = FUSE_RENAME;
307 in.h.ino = olddir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000308 in.numargs = 3;
309 in.args[0].size = sizeof(inarg);
310 in.args[0].value = &inarg;
311 in.args[1].size = oldent->d_name.len + 1;
312 in.args[1].value = oldent->d_name.name;
313 in.args[2].size = newent->d_name.len + 1;
314 in.args[2].value = newent->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000315 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000316
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000317 return out.h.error;
318}
319
320static int fuse_link(struct dentry *entry, struct inode *newdir,
321 struct dentry *newent)
322{
323 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000324 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000325 struct fuse_in in = FUSE_IN_INIT;
326 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000327 struct fuse_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000328
Miklos Szeredi43696432001-11-18 19:15:05 +0000329 memset(&inarg, 0, sizeof(inarg));
330 inarg.newdir = newdir->i_ino;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000331
332 in.h.opcode = FUSE_LINK;
333 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000334 in.numargs = 2;
335 in.args[0].size = sizeof(inarg);
336 in.args[0].value = &inarg;
337 in.args[1].size = newent->d_name.len + 1;
338 in.args[1].value = newent->d_name.name;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000339 request_send(fc, &in, &out);
Miklos Szeredie815c032004-01-19 18:20:49 +0000340 if(out.h.error)
341 return out.h.error;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000342
Miklos Szeredie815c032004-01-19 18:20:49 +0000343 /* Invalidate old entry, so attributes are refreshed */
344 d_invalidate(entry);
345 return lookup_new_entry(newdir, newent);
Miklos Szeredib483c932001-10-29 14:57:57 +0000346}
347
Miklos Szeredif85ab242004-01-07 12:16:45 +0000348int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000349{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000350 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000351 struct fuse_in in = FUSE_IN_INIT;
352 struct fuse_out out = FUSE_OUT_INIT;
353 struct fuse_getattr_out arg;
354
355 in.h.opcode = FUSE_GETATTR;
356 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000357 out.numargs = 1;
358 out.args[0].size = sizeof(arg);
359 out.args[0].value = &arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000360 request_send(fc, &in, &out);
361
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000362 if(!out.h.error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000363 change_attributes(inode, &arg.attr);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000364
365 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000366}
367
Miklos Szeredife25def2001-12-20 15:38:05 +0000368static int fuse_revalidate(struct dentry *entry)
369{
370 struct inode *inode = entry->d_inode;
371 struct fuse_conn *fc = INO_FC(inode);
372
373 if(inode->i_ino == FUSE_ROOT_INO) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000374 if(!(fc->flags & FUSE_ALLOW_OTHER) &&
375 current->fsuid != fc->uid)
Miklos Szeredife25def2001-12-20 15:38:05 +0000376 return -EACCES;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000377 } else if(time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
Miklos Szeredife25def2001-12-20 15:38:05 +0000378 return 0;
379
Miklos Szeredif85ab242004-01-07 12:16:45 +0000380 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000381}
382
Miklos Szeredif85ab242004-01-07 12:16:45 +0000383static int _fuse_permission(struct inode *inode, int mask)
Miklos Szeredife25def2001-12-20 15:38:05 +0000384{
385 struct fuse_conn *fc = INO_FC(inode);
386
387 if(!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
388 return -EACCES;
389 else if(fc->flags & FUSE_DEFAULT_PERMISSIONS) {
390 int err = vfs_permission(inode, mask);
391
392 /* If permission is denied, try to refresh file
393 attributes. This is also needed, because the root
394 node will at first have no permissions */
395
396 if(err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000397 err = fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000398 if(!err)
399 err = vfs_permission(inode, mask);
400 }
401
402 /* FIXME: Need some mechanism to revoke permissions:
403 currently if the filesystem suddenly changes the
404 file mode, we will not be informed abot that, and
405 continue to allow access to the file/directory.
406
407 This is actually not so grave, since the user can
408 simply keep access to the file/directory anyway by
409 keeping it open... */
410
411 return err;
412 }
413 else
414 return 0;
415}
416
Miklos Szeredib483c932001-10-29 14:57:57 +0000417static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
418 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000419{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000420 while(nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000421 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000422 size_t reclen = FUSE_DIRENT_SIZE(dirent);
423 int over;
424 if(dirent->namelen > NAME_MAX) {
425 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000426 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000427 }
428 if(reclen > nbytes)
429 break;
430
431 over = filldir(dstbuf, dirent->name, dirent->namelen,
432 file->f_pos, dirent->ino, dirent->type);
433 if(over)
434 break;
435
Miklos Szeredib483c932001-10-29 14:57:57 +0000436 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000437 file->f_pos += reclen;
438 nbytes -= reclen;
439 }
440
Miklos Szeredib483c932001-10-29 14:57:57 +0000441 return 0;
442}
443
444#define DIR_BUFSIZE 2048
445static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
446{
447 struct file *cfile = file->private_data;
448 char *buf;
449 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000450
451 if(!cfile)
452 return -EISDIR;
453
Miklos Szeredib483c932001-10-29 14:57:57 +0000454 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
455 if(!buf)
456 return -ENOMEM;
Miklos Szeredie815c032004-01-19 18:20:49 +0000457
Miklos Szeredib483c932001-10-29 14:57:57 +0000458 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
459 if(ret < 0)
460 printk("fuse_readdir: failed to read container file\n");
461 else
462 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
463
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000464 kfree(buf);
465 return ret;
466}
467
Miklos Szeredi05033042001-11-13 16:11:35 +0000468static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000469{
470 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000471 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000472 struct fuse_in in = FUSE_IN_INIT;
473 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi05033042001-11-13 16:11:35 +0000474 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000475
Miklos Szeredi05033042001-11-13 16:11:35 +0000476 link = (char *) __get_free_page(GFP_KERNEL);
477 if(!link)
478 return ERR_PTR(-ENOMEM);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000479
480 in.h.opcode = FUSE_READLINK;
481 in.h.ino = inode->i_ino;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000482 out.argvar = 1;
Miklos Szeredi43696432001-11-18 19:15:05 +0000483 out.numargs = 1;
484 out.args[0].size = PAGE_SIZE - 1;
485 out.args[0].value = link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000486 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000487 if(out.h.error) {
Miklos Szeredi05033042001-11-13 16:11:35 +0000488 free_page((unsigned long) link);
489 return ERR_PTR(out.h.error);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000490 }
491
Miklos Szeredi43696432001-11-18 19:15:05 +0000492 link[out.args[0].size] = '\0';
Miklos Szeredi05033042001-11-13 16:11:35 +0000493 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000494}
495
496static void free_link(char *link)
497{
Miklos Szeredi05033042001-11-13 16:11:35 +0000498 if(!IS_ERR(link))
499 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000500}
501
502static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
503{
504 int ret;
505 char *link;
506
Miklos Szeredi05033042001-11-13 16:11:35 +0000507 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000508 ret = vfs_readlink(dentry, buffer, buflen, link);
509 free_link(link);
510 return ret;
511}
512
513static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
514{
515 int ret;
516 char *link;
517
Miklos Szeredi05033042001-11-13 16:11:35 +0000518 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000519 ret = vfs_follow_link(nd, link);
520 free_link(link);
521 return ret;
522}
523
524static int fuse_dir_open(struct inode *inode, struct file *file)
525{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000526 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000527 struct fuse_in in = FUSE_IN_INIT;
528 struct fuse_out out = FUSE_OUT_INIT;
529 struct fuse_getdir_out outarg;
530
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000531 in.h.opcode = FUSE_GETDIR;
532 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000533 out.numargs = 1;
534 out.args[0].size = sizeof(outarg);
535 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000536 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000537 if(!out.h.error) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000538 struct file *cfile = outarg.file;
539 struct inode *inode;
540 if(!cfile) {
541 printk("fuse_getdir: invalid file\n");
542 return -EPROTO;
543 }
544 inode = cfile->f_dentry->d_inode;
545 if(!S_ISREG(inode->i_mode)) {
546 printk("fuse_getdir: not a regular file\n");
547 fput(cfile);
548 return -EPROTO;
549 }
550
551 file->private_data = cfile;
552 }
553
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000554 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000555}
556
557static int fuse_dir_release(struct inode *inode, struct file *file)
558{
559 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000560
561 if(cfile)
562 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000563
564 return 0;
565}
566
Miklos Szeredi5e183482001-10-31 14:52:35 +0000567static unsigned int iattr_to_fattr(struct iattr *iattr,
568 struct fuse_attr *fattr)
569{
570 unsigned int ivalid = iattr->ia_valid;
571 unsigned int fvalid = 0;
572
573 memset(fattr, 0, sizeof(*fattr));
574
575 if(ivalid & ATTR_MODE)
576 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
577 if(ivalid & ATTR_UID)
578 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
579 if(ivalid & ATTR_GID)
580 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
581 if(ivalid & ATTR_SIZE)
582 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
583 /* You can only _set_ these together (they may change by themselves) */
584 if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
585 fvalid |= FATTR_UTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000586#ifdef KERNEL_2_6
587 fattr->atime = iattr->ia_atime.tv_sec;
588 fattr->mtime = iattr->ia_mtime.tv_sec;
589#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000590 fattr->atime = iattr->ia_atime;
591 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000592#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000593 }
594
595 return fvalid;
596}
597
598static int fuse_setattr(struct dentry *entry, struct iattr *attr)
599{
600 struct inode *inode = entry->d_inode;
601 struct fuse_conn *fc = INO_FC(inode);
602 struct fuse_in in = FUSE_IN_INIT;
603 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000604 struct fuse_setattr_in inarg;
605 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000606
Miklos Szeredi43696432001-11-18 19:15:05 +0000607 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000608 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000609
610 in.h.opcode = FUSE_SETATTR;
611 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000612 in.numargs = 1;
613 in.args[0].size = sizeof(inarg);
614 in.args[0].value = &inarg;
615 out.numargs = 1;
616 out.args[0].size = sizeof(outarg);
617 out.args[0].value = &outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000618 request_send(fc, &in, &out);
619
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000620 if(!out.h.error) {
621 if(attr->ia_valid & ATTR_SIZE &&
622 outarg.attr.size < inode->i_size)
623 vmtruncate(inode, outarg.attr.size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000624
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000625 change_attributes(inode, &outarg.attr);
626 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000627 return out.h.error;
628}
629
Miklos Szeredif85ab242004-01-07 12:16:45 +0000630static int _fuse_dentry_revalidate(struct dentry *entry)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000631{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000632 if(!entry->d_inode)
633 return 0;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000634 else if(time_after(jiffies, entry->d_time + FUSE_REVALIDATE_TIME)) {
635 struct inode *inode = entry->d_inode;
636 struct fuse_lookup_out outarg;
637 int version;
638 int ret;
639
640 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
641 &version);
642 if(ret)
643 return 0;
644
645 if(outarg.ino != inode->i_ino)
646 return 0;
647
648 change_attributes(inode, &outarg.attr);
649 inode->i_version = version;
650 entry->d_time = jiffies;
651 }
652 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000653}
654
Miklos Szeredif85ab242004-01-07 12:16:45 +0000655#ifdef KERNEL_2_6
656
657#define fuse_mknod _fuse_mknod
658
659static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
660 struct kstat *stat)
661{
662 struct inode *inode = entry->d_inode;
663 int err = fuse_revalidate(entry);
664 if(!err)
665 generic_fillattr(inode, stat);
666
667 return err;
668}
669
670static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
671 struct nameidata *nd)
672{
Miklos Szeredie815c032004-01-19 18:20:49 +0000673 struct inode *inode;
674 int err = fuse_lookup_iget(dir, entry, &inode);
675 if (err)
676 return ERR_PTR(err);
677 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000678}
679
680static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
681 struct nameidata *nd)
682{
683 return _fuse_create(dir, entry, mode);
684}
685
686static int fuse_permission(struct inode *inode, int mask,
687 struct nameidata *nd)
688{
689 return _fuse_permission(inode, mask);
690}
691
692static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
693{
694 return _fuse_dentry_revalidate(entry);
695}
696#else /* KERNEL_2_6 */
697
Miklos Szeredif85ab242004-01-07 12:16:45 +0000698#define fuse_create _fuse_create
699#define fuse_permission _fuse_permission
700
Miklos Szeredie815c032004-01-19 18:20:49 +0000701static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
702{
703 struct inode *inode;
704 struct dentry *alias;
705
706 int err = fuse_lookup_iget(dir, entry, &inode);
707 if(err)
708 return ERR_PTR(err);
709
710 if(inode && S_ISDIR(inode->i_mode) &&
711 (alias = d_find_alias(inode)) != NULL) {
712 dput(alias);
713 iput(inode);
714 printk("fuse: cannot assign an existing directory\n");
Miklos Szeredid23b70a2004-01-26 12:17:53 +0000715 return ERR_PTR(-EPROTO);
Miklos Szeredie815c032004-01-19 18:20:49 +0000716 }
717
718 d_add(entry, inode);
719 return NULL;
720}
721
Miklos Szeredif85ab242004-01-07 12:16:45 +0000722static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
723 int rdev)
724{
725 return fuse_mknod(dir, entry, mode, rdev);
726}
727
728static int fuse_dentry_revalidate(struct dentry *entry, int flags)
729{
730 return _fuse_dentry_revalidate(entry);
731}
732#endif /* KERNEL_2_6 */
733
734
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000735static struct inode_operations fuse_dir_inode_operations =
736{
Miklos Szeredie8663f32004-01-13 15:33:12 +0000737 .lookup = fuse_lookup,
738 .create = fuse_create,
739 .mknod = fuse_mknod,
740 .mkdir = fuse_mkdir,
741 .symlink = fuse_symlink,
742 .unlink = fuse_unlink,
743 .rmdir = fuse_rmdir,
744 .rename = fuse_rename,
745 .link = fuse_link,
746 .setattr = fuse_setattr,
747 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000748#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000749 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000750#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000751 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000752#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000753};
754
755static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000756 .read = generic_read_dir,
757 .readdir = fuse_readdir,
758 .open = fuse_dir_open,
759 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000760};
761
762static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000763 .setattr = fuse_setattr,
764 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000765#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000766 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000767#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000768 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000769#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000770};
771
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000772static struct inode_operations fuse_symlink_inode_operations =
773{
Miklos Szeredie8663f32004-01-13 15:33:12 +0000774 .setattr = fuse_setattr,
775 .readlink = fuse_readlink,
776 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000777#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000778 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000779#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000780 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000781#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000782};
783
Miklos Szeredi307242f2004-01-26 11:28:44 +0000784static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000785 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000786};
787
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000788/*
789 * Local Variables:
790 * indent-tabs-mode: t
791 * c-basic-offset: 8
792 * End:
793 */