blob: 4051d07389cd7d3913d874c1d21103fe0970a64c [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 Szeredi7c35cf92004-01-14 16:56:49 +000023#ifndef KERNEL_2_6
24#define new_decode_dev(x) (x)
25#define new_encode_dev(x) (x)
26#endif
27
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000028static void change_attributes(struct inode *inode, struct fuse_attr *attr)
29{
Miklos Szeredid1199f82004-02-06 15:29:22 +000030 if(S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) {
Miklos Szeredif85ab242004-01-07 12:16:45 +000031#ifdef KERNEL_2_6
32 invalidate_inode_pages(inode->i_mapping);
33#else
Miklos Szeredia181e612001-11-06 12:03:23 +000034 invalidate_inode_pages(inode);
Miklos Szeredif85ab242004-01-07 12:16:45 +000035#endif
36 }
Miklos Szeredia181e612001-11-06 12:03:23 +000037
Miklos Szeredi5e183482001-10-31 14:52:35 +000038 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000039 inode->i_nlink = attr->nlink;
40 inode->i_uid = attr->uid;
41 inode->i_gid = attr->gid;
Miklos Szeredid1199f82004-02-06 15:29:22 +000042 i_size_write(inode, attr->size);
Miklos Szeredi05033042001-11-13 16:11:35 +000043 inode->i_blksize = PAGE_CACHE_SIZE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000044 inode->i_blocks = attr->blocks;
Miklos Szeredif85ab242004-01-07 12:16:45 +000045#ifdef KERNEL_2_6
46 inode->i_atime.tv_sec = attr->atime;
Miklos Szeredib5958612004-02-20 14:10:49 +000047 inode->i_atime.tv_nsec = attr->atimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000048 inode->i_mtime.tv_sec = attr->mtime;
Miklos Szeredib5958612004-02-20 14:10:49 +000049 inode->i_mtime.tv_nsec = attr->mtimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000050 inode->i_ctime.tv_sec = attr->ctime;
Miklos Szeredib5958612004-02-20 14:10:49 +000051 inode->i_ctime.tv_nsec = attr->ctimensec;
Miklos Szeredif85ab242004-01-07 12:16:45 +000052#else
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000053 inode->i_atime = attr->atime;
54 inode->i_mtime = attr->mtime;
55 inode->i_ctime = attr->ctime;
Miklos Szeredif85ab242004-01-07 12:16:45 +000056#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000057}
58
Miklos Szeredia181e612001-11-06 12:03:23 +000059static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000060{
Miklos Szeredia181e612001-11-06 12:03:23 +000061 inode->i_mode = attr->mode & S_IFMT;
Miklos Szeredid1199f82004-02-06 15:29:22 +000062 i_size_write(inode, attr->size);
Miklos Szeredib483c932001-10-29 14:57:57 +000063 if(S_ISREG(inode->i_mode)) {
64 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000065 fuse_init_file_inode(inode);
Miklos Szeredib483c932001-10-29 14:57:57 +000066 }
67 else if(S_ISDIR(inode->i_mode)) {
68 inode->i_op = &fuse_dir_inode_operations;
69 inode->i_fop = &fuse_dir_operations;
70 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000071 else if(S_ISLNK(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000072 inode->i_op = &fuse_symlink_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000073 }
Miklos Szeredi76f65782004-02-19 16:55:40 +000074 else if(S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
75 S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)){
Miklos Szeredia181e612001-11-06 12:03:23 +000076 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +000077 init_special_inode(inode, inode->i_mode,
78 new_decode_dev(attr->rdev));
Miklos Szeredi76f65782004-02-19 16:55:40 +000079 } else
80 printk("fuse_init_inode: bad file type: %o\n", inode->i_mode);
81
Miklos Szeredi5e183482001-10-31 14:52:35 +000082 inode->u.generic_ip = inode;
83}
84
Miklos Szeredi76f65782004-02-19 16:55:40 +000085struct inode *fuse_iget(struct super_block *sb, ino_t ino, int generation,
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) {
Miklos Szeredi76f65782004-02-19 16:55:40 +000092 if(!inode->u.generic_ip) {
93 inode->i_generation = generation;
Miklos Szeredia181e612001-11-06 12:03:23 +000094 fuse_init_inode(inode, attr);
Miklos Szeredi76f65782004-02-19 16:55:40 +000095 } else if(inode->i_generation != generation)
96 printk("fuse_iget: bad generation for ino %lu\n", ino);
Miklos Szeredie815c032004-01-19 18:20:49 +000097
Miklos Szeredi5e183482001-10-31 14:52:35 +000098 change_attributes(inode, attr);
Miklos Szeredia181e612001-11-06 12:03:23 +000099 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000100 }
101
102 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000103}
104
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000105static int fuse_do_lookup(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000106 struct fuse_entry_out *outarg, int *version)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000107{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000108 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000109 struct fuse_in in = FUSE_IN_INIT;
110 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000111
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000112 in.h.opcode = FUSE_LOOKUP;
113 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000114 in.numargs = 1;
115 in.args[0].size = entry->d_name.len + 1;
116 in.args[0].value = entry->d_name.name;
117 out.numargs = 1;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000118 out.args[0].size = sizeof(struct fuse_entry_out);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000119 out.args[0].value = outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000120 request_send(fc, &in, &out);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000121
122 *version = out.h.unique;
123 return out.h.error;
124}
125
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000126static inline unsigned long time_to_jiffies(unsigned long sec,
127 unsigned long nsec)
128{
129 /* prevent wrapping of jiffies */
130 if(sec + 1 >= LONG_MAX / HZ)
131 return 0;
132
133 return jiffies + sec * HZ + nsec / (1000000000 / HZ);
134}
135
Miklos Szeredie815c032004-01-19 18:20:49 +0000136static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
137 struct inode **inodep)
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000138{
Miklos Szeredie815c032004-01-19 18:20:49 +0000139 int err;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000140 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000141 int version;
Miklos Szeredie815c032004-01-19 18:20:49 +0000142 struct inode *inode = NULL;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000143
Miklos Szeredie815c032004-01-19 18:20:49 +0000144 err = fuse_do_lookup(dir, entry, &outarg, &version);
145 if(!err) {
Miklos Szeredi76f65782004-02-19 16:55:40 +0000146 inode = fuse_iget(dir->i_sb, outarg.ino, outarg.generation,
147 &outarg.attr, version);
Miklos Szeredie815c032004-01-19 18:20:49 +0000148 if(!inode)
149 return -ENOMEM;
150 } else if(err != -ENOENT)
151 return err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000152
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000153 entry->d_time = time_to_jiffies(outarg.entry_valid,
154 outarg.entry_valid_nsec);
Miklos Szeredi307242f2004-01-26 11:28:44 +0000155 entry->d_op = &fuse_dentry_operations;
Miklos Szeredie815c032004-01-19 18:20:49 +0000156 *inodep = inode;
157 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000158}
159
Miklos Szeredi76f65782004-02-19 16:55:40 +0000160static int lookup_new_entry(struct inode *dir, struct dentry *entry,
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000161 struct fuse_entry_out *outarg, int version,
Miklos Szeredi76f65782004-02-19 16:55:40 +0000162 int mode)
163{
164 struct inode *inode;
165 inode = fuse_iget(dir->i_sb, outarg->ino, outarg->generation,
166 &outarg->attr, version);
167 if(!inode)
168 return -ENOMEM;
169
170 /* Don't allow userspace to do really stupid things... */
171 if((inode->i_mode ^ mode) & S_IFMT) {
172 iput(inode);
173 printk("fuse_mknod: inode has wrong type\n");
174 return -EINVAL;
175 }
176
177 d_instantiate(entry, inode);
178 return 0;
179}
180
181
Miklos Szeredif85ab242004-01-07 12:16:45 +0000182static int _fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
183 dev_t rdev)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000184{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000185 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000186 struct fuse_in in = FUSE_IN_INIT;
187 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000188 struct fuse_mknod_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000189 struct fuse_entry_out outarg;
Miklos Szeredi43696432001-11-18 19:15:05 +0000190
191 memset(&inarg, 0, sizeof(inarg));
192 inarg.mode = mode;
Miklos Szeredi7c35cf92004-01-14 16:56:49 +0000193 inarg.rdev = new_encode_dev(rdev);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000194
195 in.h.opcode = FUSE_MKNOD;
196 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000197 in.numargs = 2;
198 in.args[0].size = sizeof(inarg);
199 in.args[0].value = &inarg;
200 in.args[1].size = entry->d_name.len + 1;
201 in.args[1].value = entry->d_name.name;
202 out.numargs = 1;
203 out.args[0].size = sizeof(outarg);
204 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000205 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000206
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000207 if(out.h.error)
208 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000209
Miklos Szeredi76f65782004-02-19 16:55:40 +0000210 return lookup_new_entry(dir, entry, &outarg, out.h.unique, mode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000211}
212
Miklos Szeredif85ab242004-01-07 12:16:45 +0000213static int _fuse_create(struct inode *dir, struct dentry *entry, int mode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000214{
Miklos Szeredif85ab242004-01-07 12:16:45 +0000215 return _fuse_mknod(dir, entry, mode, 0);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000216}
217
Miklos Szeredie815c032004-01-19 18:20:49 +0000218
Miklos Szeredib483c932001-10-29 14:57:57 +0000219static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
220{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000221 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000222 struct fuse_in in = FUSE_IN_INIT;
223 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000224 struct fuse_mkdir_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000225 struct fuse_entry_out outarg;
Miklos Szeredi43696432001-11-18 19:15:05 +0000226
227 memset(&inarg, 0, sizeof(inarg));
228 inarg.mode = mode;
Miklos Szeredib483c932001-10-29 14:57:57 +0000229
230 in.h.opcode = FUSE_MKDIR;
231 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000232 in.numargs = 2;
233 in.args[0].size = sizeof(inarg);
234 in.args[0].value = &inarg;
235 in.args[1].size = entry->d_name.len + 1;
236 in.args[1].value = entry->d_name.name;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000237 out.numargs = 1;
238 out.args[0].size = sizeof(outarg);
239 out.args[0].value = &outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000240 request_send(fc, &in, &out);
Miklos Szeredie815c032004-01-19 18:20:49 +0000241 if(out.h.error)
242 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000243
Miklos Szeredi76f65782004-02-19 16:55:40 +0000244 return lookup_new_entry(dir, entry, &outarg, out.h.unique, S_IFDIR);
Miklos Szeredib483c932001-10-29 14:57:57 +0000245}
246
247static int fuse_symlink(struct inode *dir, struct dentry *entry,
248 const char *link)
249{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000250 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000251 struct fuse_in in = FUSE_IN_INIT;
252 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000253 struct fuse_entry_out outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000254
255 in.h.opcode = FUSE_SYMLINK;
256 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000257 in.numargs = 2;
258 in.args[0].size = entry->d_name.len + 1;
259 in.args[0].value = entry->d_name.name;
260 in.args[1].size = strlen(link) + 1;
261 in.args[1].value = link;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000262 out.numargs = 1;
263 out.args[0].size = sizeof(outarg);
264 out.args[0].value = &outarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000265 request_send(fc, &in, &out);
Miklos Szeredie815c032004-01-19 18:20:49 +0000266 if(out.h.error)
267 return out.h.error;
Miklos Szeredi43696432001-11-18 19:15:05 +0000268
Miklos Szeredi76f65782004-02-19 16:55:40 +0000269 return lookup_new_entry(dir, entry, &outarg, out.h.unique, S_IFLNK);
Miklos Szeredib483c932001-10-29 14:57:57 +0000270}
271
Miklos Szeredib5958612004-02-20 14:10:49 +0000272static int fuse_unlink(struct inode *dir, struct dentry *entry)
Miklos Szeredib483c932001-10-29 14:57:57 +0000273{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000274 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000275 struct fuse_in in = FUSE_IN_INIT;
276 struct fuse_out out = FUSE_OUT_INIT;
277
Miklos Szeredib5958612004-02-20 14:10:49 +0000278 in.h.opcode = FUSE_UNLINK;
Miklos Szeredib483c932001-10-29 14:57:57 +0000279 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000280 in.numargs = 1;
281 in.args[0].size = entry->d_name.len + 1;
282 in.args[0].value = entry->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000283 request_send(fc, &in, &out);
Miklos Szeredi43696432001-11-18 19:15:05 +0000284
Miklos Szeredib5958612004-02-20 14:10:49 +0000285 if(!out.h.error) {
286 /* Set nlink to zero so the inode can be cleared, if
287 the inode does have more links this will be
288 discovered at the next lookup/getattr */
289 /* FIXME: mark inode "not uptodate" */
290 entry->d_inode->i_nlink = 0;
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000291 }
Miklos Szeredib5958612004-02-20 14:10:49 +0000292
293 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000294}
295
296static int fuse_rmdir(struct inode *dir, struct dentry *entry)
297{
Miklos Szeredib5958612004-02-20 14:10:49 +0000298 struct fuse_conn *fc = INO_FC(dir);
299 struct fuse_in in = FUSE_IN_INIT;
300 struct fuse_out out = FUSE_OUT_INIT;
301
302 in.h.opcode = FUSE_RMDIR;
303 in.h.ino = dir->i_ino;
304 in.numargs = 1;
305 in.args[0].size = entry->d_name.len + 1;
306 in.args[0].value = entry->d_name.name;
307 request_send(fc, &in, &out);
308 if(!out.h.error)
Miklos Szeredif4f8b892004-01-27 17:04:59 +0000309 entry->d_inode->i_nlink = 0;
Miklos Szeredib5958612004-02-20 14:10:49 +0000310
311 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000312}
313
314static int fuse_rename(struct inode *olddir, struct dentry *oldent,
315 struct inode *newdir, struct dentry *newent)
316{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000317 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000318 struct fuse_in in = FUSE_IN_INIT;
319 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000320 struct fuse_rename_in inarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000321
Miklos Szeredi43696432001-11-18 19:15:05 +0000322 memset(&inarg, 0, sizeof(inarg));
323 inarg.newdir = newdir->i_ino;
Miklos Szeredib483c932001-10-29 14:57:57 +0000324
325 in.h.opcode = FUSE_RENAME;
326 in.h.ino = olddir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000327 in.numargs = 3;
328 in.args[0].size = sizeof(inarg);
329 in.args[0].value = &inarg;
330 in.args[1].size = oldent->d_name.len + 1;
331 in.args[1].value = oldent->d_name.name;
332 in.args[2].size = newent->d_name.len + 1;
333 in.args[2].value = newent->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000334 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000335
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000336 return out.h.error;
337}
338
339static int fuse_link(struct dentry *entry, struct inode *newdir,
340 struct dentry *newent)
341{
342 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000343 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000344 struct fuse_in in = FUSE_IN_INIT;
345 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000346 struct fuse_link_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000347 struct fuse_entry_out outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000348
Miklos Szeredi43696432001-11-18 19:15:05 +0000349 memset(&inarg, 0, sizeof(inarg));
350 inarg.newdir = newdir->i_ino;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000351
352 in.h.opcode = FUSE_LINK;
353 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000354 in.numargs = 2;
355 in.args[0].size = sizeof(inarg);
356 in.args[0].value = &inarg;
357 in.args[1].size = newent->d_name.len + 1;
358 in.args[1].value = newent->d_name.name;
Miklos Szeredi76f65782004-02-19 16:55:40 +0000359 out.numargs = 1;
360 out.args[0].size = sizeof(outarg);
361 out.args[0].value = &outarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000362 request_send(fc, &in, &out);
Miklos Szeredie815c032004-01-19 18:20:49 +0000363 if(out.h.error)
364 return out.h.error;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000365
Miklos Szeredie815c032004-01-19 18:20:49 +0000366 /* Invalidate old entry, so attributes are refreshed */
367 d_invalidate(entry);
Miklos Szeredi76f65782004-02-19 16:55:40 +0000368 return lookup_new_entry(newdir, newent, &outarg, out.h.unique,
369 inode->i_mode);
Miklos Szeredib483c932001-10-29 14:57:57 +0000370}
371
Miklos Szeredif85ab242004-01-07 12:16:45 +0000372int fuse_do_getattr(struct inode *inode)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000373{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000374 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000375 struct fuse_in in = FUSE_IN_INIT;
376 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000377 struct fuse_attr_out arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000378
379 in.h.opcode = FUSE_GETATTR;
380 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000381 out.numargs = 1;
382 out.args[0].size = sizeof(arg);
383 out.args[0].value = &arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000384 request_send(fc, &in, &out);
385
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000386 if(!out.h.error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000387 change_attributes(inode, &arg.attr);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000388
389 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000390}
391
Miklos Szeredife25def2001-12-20 15:38:05 +0000392static int fuse_revalidate(struct dentry *entry)
393{
394 struct inode *inode = entry->d_inode;
395 struct fuse_conn *fc = INO_FC(inode);
396
397 if(inode->i_ino == FUSE_ROOT_INO) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000398 if(!(fc->flags & FUSE_ALLOW_OTHER) &&
399 current->fsuid != fc->uid)
Miklos Szeredife25def2001-12-20 15:38:05 +0000400 return -EACCES;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000401 } else if(!entry->d_time || time_before_eq(jiffies, entry->d_time))
Miklos Szeredife25def2001-12-20 15:38:05 +0000402 return 0;
403
Miklos Szeredif85ab242004-01-07 12:16:45 +0000404 return fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000405}
406
Miklos Szeredif85ab242004-01-07 12:16:45 +0000407static int _fuse_permission(struct inode *inode, int mask)
Miklos Szeredife25def2001-12-20 15:38:05 +0000408{
409 struct fuse_conn *fc = INO_FC(inode);
410
411 if(!(fc->flags & FUSE_ALLOW_OTHER) && current->fsuid != fc->uid)
412 return -EACCES;
413 else if(fc->flags & FUSE_DEFAULT_PERMISSIONS) {
414 int err = vfs_permission(inode, mask);
415
416 /* If permission is denied, try to refresh file
417 attributes. This is also needed, because the root
418 node will at first have no permissions */
419
420 if(err == -EACCES) {
Miklos Szeredif85ab242004-01-07 12:16:45 +0000421 err = fuse_do_getattr(inode);
Miklos Szeredife25def2001-12-20 15:38:05 +0000422 if(!err)
423 err = vfs_permission(inode, mask);
424 }
425
426 /* FIXME: Need some mechanism to revoke permissions:
427 currently if the filesystem suddenly changes the
428 file mode, we will not be informed abot that, and
429 continue to allow access to the file/directory.
430
431 This is actually not so grave, since the user can
432 simply keep access to the file/directory anyway by
433 keeping it open... */
434
435 return err;
Miklos Szeredi69cc79a2004-02-17 08:57:29 +0000436 } else
Miklos Szeredife25def2001-12-20 15:38:05 +0000437 return 0;
438}
439
Miklos Szeredib483c932001-10-29 14:57:57 +0000440static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
441 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000442{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000443 while(nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000444 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000445 size_t reclen = FUSE_DIRENT_SIZE(dirent);
446 int over;
447 if(dirent->namelen > NAME_MAX) {
448 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000449 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000450 }
451 if(reclen > nbytes)
452 break;
453
454 over = filldir(dstbuf, dirent->name, dirent->namelen,
455 file->f_pos, dirent->ino, dirent->type);
456 if(over)
457 break;
458
Miklos Szeredib483c932001-10-29 14:57:57 +0000459 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000460 file->f_pos += reclen;
461 nbytes -= reclen;
462 }
463
Miklos Szeredib483c932001-10-29 14:57:57 +0000464 return 0;
465}
466
467#define DIR_BUFSIZE 2048
468static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
469{
470 struct file *cfile = file->private_data;
471 char *buf;
472 int ret;
Miklos Szeredie815c032004-01-19 18:20:49 +0000473
474 if(!cfile)
475 return -EISDIR;
476
Miklos Szeredib483c932001-10-29 14:57:57 +0000477 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
478 if(!buf)
479 return -ENOMEM;
Miklos Szeredie815c032004-01-19 18:20:49 +0000480
Miklos Szeredib483c932001-10-29 14:57:57 +0000481 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
482 if(ret < 0)
483 printk("fuse_readdir: failed to read container file\n");
484 else
485 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
486
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000487 kfree(buf);
488 return ret;
489}
490
Miklos Szeredi05033042001-11-13 16:11:35 +0000491static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000492{
493 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000494 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000495 struct fuse_in in = FUSE_IN_INIT;
496 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi05033042001-11-13 16:11:35 +0000497 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000498
Miklos Szeredi05033042001-11-13 16:11:35 +0000499 link = (char *) __get_free_page(GFP_KERNEL);
500 if(!link)
501 return ERR_PTR(-ENOMEM);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000502
503 in.h.opcode = FUSE_READLINK;
504 in.h.ino = inode->i_ino;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000505 out.argvar = 1;
Miklos Szeredi43696432001-11-18 19:15:05 +0000506 out.numargs = 1;
507 out.args[0].size = PAGE_SIZE - 1;
508 out.args[0].value = link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000509 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000510 if(out.h.error) {
Miklos Szeredi05033042001-11-13 16:11:35 +0000511 free_page((unsigned long) link);
512 return ERR_PTR(out.h.error);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000513 }
514
Miklos Szeredi43696432001-11-18 19:15:05 +0000515 link[out.args[0].size] = '\0';
Miklos Szeredi05033042001-11-13 16:11:35 +0000516 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000517}
518
519static void free_link(char *link)
520{
Miklos Szeredi05033042001-11-13 16:11:35 +0000521 if(!IS_ERR(link))
522 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000523}
524
525static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
526{
527 int ret;
528 char *link;
529
Miklos Szeredi05033042001-11-13 16:11:35 +0000530 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000531 ret = vfs_readlink(dentry, buffer, buflen, link);
532 free_link(link);
533 return ret;
534}
535
536static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
537{
538 int ret;
539 char *link;
540
Miklos Szeredi05033042001-11-13 16:11:35 +0000541 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000542 ret = vfs_follow_link(nd, link);
543 free_link(link);
544 return ret;
545}
546
547static int fuse_dir_open(struct inode *inode, struct file *file)
548{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000549 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000550 struct fuse_in in = FUSE_IN_INIT;
551 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000552 struct fuse_getdir_out_i outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000553
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000554 in.h.opcode = FUSE_GETDIR;
555 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000556 out.numargs = 1;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000557 out.args[0].size = sizeof(struct fuse_getdir_out);
Miklos Szeredi43696432001-11-18 19:15:05 +0000558 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000559 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000560 if(!out.h.error) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000561 struct file *cfile = outarg.file;
562 struct inode *inode;
563 if(!cfile) {
564 printk("fuse_getdir: invalid file\n");
565 return -EPROTO;
566 }
567 inode = cfile->f_dentry->d_inode;
568 if(!S_ISREG(inode->i_mode)) {
569 printk("fuse_getdir: not a regular file\n");
570 fput(cfile);
571 return -EPROTO;
572 }
573
574 file->private_data = cfile;
575 }
576
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000577 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000578}
579
580static int fuse_dir_release(struct inode *inode, struct file *file)
581{
582 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000583
584 if(cfile)
585 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000586
587 return 0;
588}
589
Miklos Szeredi5e183482001-10-31 14:52:35 +0000590static unsigned int iattr_to_fattr(struct iattr *iattr,
591 struct fuse_attr *fattr)
592{
593 unsigned int ivalid = iattr->ia_valid;
594 unsigned int fvalid = 0;
595
596 memset(fattr, 0, sizeof(*fattr));
597
598 if(ivalid & ATTR_MODE)
599 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
600 if(ivalid & ATTR_UID)
601 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
602 if(ivalid & ATTR_GID)
603 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
604 if(ivalid & ATTR_SIZE)
605 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
606 /* You can only _set_ these together (they may change by themselves) */
607 if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
Miklos Szeredib5958612004-02-20 14:10:49 +0000608 fvalid |= FATTR_ATIME | FATTR_MTIME;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000609#ifdef KERNEL_2_6
610 fattr->atime = iattr->ia_atime.tv_sec;
611 fattr->mtime = iattr->ia_mtime.tv_sec;
612#else
Miklos Szeredi5e183482001-10-31 14:52:35 +0000613 fattr->atime = iattr->ia_atime;
614 fattr->mtime = iattr->ia_mtime;
Miklos Szeredif85ab242004-01-07 12:16:45 +0000615#endif
Miklos Szeredi5e183482001-10-31 14:52:35 +0000616 }
617
618 return fvalid;
619}
620
621static int fuse_setattr(struct dentry *entry, struct iattr *attr)
622{
623 struct inode *inode = entry->d_inode;
624 struct fuse_conn *fc = INO_FC(inode);
625 struct fuse_in in = FUSE_IN_INIT;
626 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000627 struct fuse_setattr_in inarg;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000628 struct fuse_attr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000629
Miklos Szeredi43696432001-11-18 19:15:05 +0000630 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000631 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000632
633 in.h.opcode = FUSE_SETATTR;
634 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000635 in.numargs = 1;
636 in.args[0].size = sizeof(inarg);
637 in.args[0].value = &inarg;
638 out.numargs = 1;
639 out.args[0].size = sizeof(outarg);
640 out.args[0].value = &outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000641 request_send(fc, &in, &out);
642
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000643 if(!out.h.error) {
644 if(attr->ia_valid & ATTR_SIZE &&
Miklos Szeredid1199f82004-02-06 15:29:22 +0000645 outarg.attr.size < i_size_read(inode))
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000646 vmtruncate(inode, outarg.attr.size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000647
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000648 change_attributes(inode, &outarg.attr);
649 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000650 return out.h.error;
651}
652
Miklos Szeredif85ab242004-01-07 12:16:45 +0000653static int _fuse_dentry_revalidate(struct dentry *entry)
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000654{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000655 if(!entry->d_inode)
656 return 0;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000657 else if(entry->d_time && time_after(jiffies, entry->d_time)) {
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000658 struct inode *inode = entry->d_inode;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000659 struct fuse_entry_out outarg;
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000660 int version;
661 int ret;
662
663 ret = fuse_do_lookup(entry->d_parent->d_inode, entry, &outarg,
664 &version);
665 if(ret)
666 return 0;
667
668 if(outarg.ino != inode->i_ino)
669 return 0;
670
671 change_attributes(inode, &outarg.attr);
672 inode->i_version = version;
Miklos Szeredi254d5ed2004-03-02 11:11:24 +0000673 entry->d_time = time_to_jiffies(outarg.entry_valid,
674 outarg.entry_valid_nsec);
Miklos Szeredi5e5d61f2002-10-24 11:50:33 +0000675 }
676 return 1;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000677}
678
Miklos Szeredif85ab242004-01-07 12:16:45 +0000679#ifdef KERNEL_2_6
680
681#define fuse_mknod _fuse_mknod
682
683static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
684 struct kstat *stat)
685{
686 struct inode *inode = entry->d_inode;
687 int err = fuse_revalidate(entry);
688 if(!err)
689 generic_fillattr(inode, stat);
690
691 return err;
692}
693
694static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
695 struct nameidata *nd)
696{
Miklos Szeredie815c032004-01-19 18:20:49 +0000697 struct inode *inode;
698 int err = fuse_lookup_iget(dir, entry, &inode);
699 if (err)
700 return ERR_PTR(err);
701 return d_splice_alias(inode, entry);
Miklos Szeredif85ab242004-01-07 12:16:45 +0000702}
703
704static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
705 struct nameidata *nd)
706{
707 return _fuse_create(dir, entry, mode);
708}
709
710static int fuse_permission(struct inode *inode, int mask,
711 struct nameidata *nd)
712{
713 return _fuse_permission(inode, mask);
714}
715
716static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
717{
718 return _fuse_dentry_revalidate(entry);
719}
720#else /* KERNEL_2_6 */
721
Miklos Szeredif85ab242004-01-07 12:16:45 +0000722#define fuse_create _fuse_create
723#define fuse_permission _fuse_permission
724
Miklos Szeredie815c032004-01-19 18:20:49 +0000725static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
726{
727 struct inode *inode;
728 struct dentry *alias;
729
730 int err = fuse_lookup_iget(dir, entry, &inode);
731 if(err)
732 return ERR_PTR(err);
733
734 if(inode && S_ISDIR(inode->i_mode) &&
735 (alias = d_find_alias(inode)) != NULL) {
736 dput(alias);
737 iput(inode);
738 printk("fuse: cannot assign an existing directory\n");
Miklos Szeredid23b70a2004-01-26 12:17:53 +0000739 return ERR_PTR(-EPROTO);
Miklos Szeredie815c032004-01-19 18:20:49 +0000740 }
741
742 d_add(entry, inode);
743 return NULL;
744}
745
Miklos Szeredif85ab242004-01-07 12:16:45 +0000746static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
747 int rdev)
748{
749 return fuse_mknod(dir, entry, mode, rdev);
750}
751
752static int fuse_dentry_revalidate(struct dentry *entry, int flags)
753{
754 return _fuse_dentry_revalidate(entry);
755}
756#endif /* KERNEL_2_6 */
757
758
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000759static struct inode_operations fuse_dir_inode_operations =
760{
Miklos Szeredie8663f32004-01-13 15:33:12 +0000761 .lookup = fuse_lookup,
762 .create = fuse_create,
763 .mknod = fuse_mknod,
764 .mkdir = fuse_mkdir,
765 .symlink = fuse_symlink,
766 .unlink = fuse_unlink,
767 .rmdir = fuse_rmdir,
768 .rename = fuse_rename,
769 .link = fuse_link,
770 .setattr = fuse_setattr,
771 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000772#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000773 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000774#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000775 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000776#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000777};
778
779static struct file_operations fuse_dir_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000780 .read = generic_read_dir,
781 .readdir = fuse_readdir,
782 .open = fuse_dir_open,
783 .release = fuse_dir_release,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000784};
785
786static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000787 .setattr = fuse_setattr,
788 .permission = fuse_permission,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000789#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000790 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000791#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000792 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000793#endif
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000794};
795
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000796static struct inode_operations fuse_symlink_inode_operations =
797{
Miklos Szeredie8663f32004-01-13 15:33:12 +0000798 .setattr = fuse_setattr,
799 .readlink = fuse_readlink,
800 .follow_link = fuse_follow_link,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000801#ifdef KERNEL_2_6
Miklos Szeredie8663f32004-01-13 15:33:12 +0000802 .getattr = fuse_getattr,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000803#else
Miklos Szeredie8663f32004-01-13 15:33:12 +0000804 .revalidate = fuse_revalidate,
Miklos Szeredif85ab242004-01-07 12:16:45 +0000805#endif
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000806};
807
Miklos Szeredi307242f2004-01-26 11:28:44 +0000808static struct dentry_operations fuse_dentry_operations = {
Miklos Szeredie8663f32004-01-13 15:33:12 +0000809 .d_revalidate = fuse_dentry_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000810};
811
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000812/*
813 * Local Variables:
814 * indent-tabs-mode: t
815 * c-basic-offset: 8
816 * End:
817 */