blob: a3f148512a742935e15494aeb40b448ed86c0d4f [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 Szeredia181e612001-11-06 12:03:23 +000028 if(S_ISREG(inode->i_mode) && inode->i_size != attr->size)
29 invalidate_inode_pages(inode);
30
Miklos Szeredi5e183482001-10-31 14:52:35 +000031 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000032 inode->i_nlink = attr->nlink;
33 inode->i_uid = attr->uid;
34 inode->i_gid = attr->gid;
35 inode->i_size = attr->size;
Miklos Szeredi05033042001-11-13 16:11:35 +000036 inode->i_blksize = PAGE_CACHE_SIZE;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000037 inode->i_blocks = attr->blocks;
38 inode->i_atime = attr->atime;
39 inode->i_mtime = attr->mtime;
40 inode->i_ctime = attr->ctime;
41}
42
Miklos Szeredia181e612001-11-06 12:03:23 +000043static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000044{
Miklos Szeredia181e612001-11-06 12:03:23 +000045 inode->i_mode = attr->mode & S_IFMT;
46 inode->i_size = attr->size;
Miklos Szeredib483c932001-10-29 14:57:57 +000047 if(S_ISREG(inode->i_mode)) {
48 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000049 fuse_init_file_inode(inode);
Miklos Szeredib483c932001-10-29 14:57:57 +000050 }
51 else if(S_ISDIR(inode->i_mode)) {
52 inode->i_op = &fuse_dir_inode_operations;
53 inode->i_fop = &fuse_dir_operations;
54 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000055 else if(S_ISLNK(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000056 inode->i_op = &fuse_symlink_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000057 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000058 else {
Miklos Szeredia181e612001-11-06 12:03:23 +000059 inode->i_op = &fuse_file_inode_operations;
60 init_special_inode(inode, inode->i_mode, attr->rdev);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000061 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000062 inode->u.generic_ip = inode;
63}
64
65struct inode *fuse_iget(struct super_block *sb, ino_t ino,
Miklos Szeredia181e612001-11-06 12:03:23 +000066 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +000067{
68 struct inode *inode;
69
70 inode = iget(sb, ino);
71 if(inode) {
72 if(!inode->u.generic_ip)
Miklos Szeredia181e612001-11-06 12:03:23 +000073 fuse_init_inode(inode, attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +000074
75 change_attributes(inode, attr);
Miklos Szeredia181e612001-11-06 12:03:23 +000076 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +000077 }
78
79 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000080}
81
Miklos Szeredi43696432001-11-18 19:15:05 +000082/* If the inode belongs to an existing directory, then it cannot be
83 assigned to new dentry */
84static int inode_ok(struct inode *inode)
85{
86 struct dentry *alias;
87 if(S_ISDIR(inode->i_mode) && (alias = d_find_alias(inode)) != NULL) {
88 dput(alias);
89 printk("fuse: cannot assign an existing directory\n");
90 return 0;
91
92 }
93 return 1;
94}
95
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000096static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
97{
Miklos Szeredia181e612001-11-06 12:03:23 +000098 int ret;
Miklos Szeredi5e183482001-10-31 14:52:35 +000099 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000100 struct fuse_in in = FUSE_IN_INIT;
101 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000102 struct fuse_lookup_out outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000103 struct inode *inode;
Miklos Szeredia181e612001-11-06 12:03:23 +0000104
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000105 in.h.opcode = FUSE_LOOKUP;
106 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000107 in.numargs = 1;
108 in.args[0].size = entry->d_name.len + 1;
109 in.args[0].value = entry->d_name.name;
110 out.numargs = 1;
111 out.args[0].size = sizeof(outarg);
112 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000113 request_send(fc, &in, &out);
114
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000115 inode = NULL;
116 if(!out.h.error) {
Miklos Szeredia181e612001-11-06 12:03:23 +0000117 ret = -ENOMEM;
Miklos Szeredi43696432001-11-18 19:15:05 +0000118 inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr,
119 out.h.unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000120 if(!inode)
Miklos Szeredia181e612001-11-06 12:03:23 +0000121 goto err;
Miklos Szeredi43696432001-11-18 19:15:05 +0000122
123 ret = -EPROTO;
124 if(!inode_ok(inode)) {
125 iput(inode);
126 goto err;
127 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000128 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000129 else if(out.h.error != -ENOENT) {
130 ret = out.h.error;
131 goto err;
132 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000133
Miklos Szeredia181e612001-11-06 12:03:23 +0000134 entry->d_time = jiffies;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000135 entry->d_op = &fuse_dentry_opertations;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000136 d_add(entry, inode);
Miklos Szeredia181e612001-11-06 12:03:23 +0000137
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000138 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000139
140 err:
141 return ERR_PTR(ret);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000142}
143
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000144/* create needs to return a positive entry, so this is actually an
145 mknod+lookup */
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000146static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
147 int rdev)
148{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000149 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000150 struct fuse_in in = FUSE_IN_INIT;
151 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000152 struct fuse_mknod_in inarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000153 struct fuse_mknod_out outarg;
154 struct inode *inode;
Miklos Szeredi43696432001-11-18 19:15:05 +0000155
156 memset(&inarg, 0, sizeof(inarg));
157 inarg.mode = mode;
158 inarg.rdev = rdev;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000159
160 in.h.opcode = FUSE_MKNOD;
161 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000162 in.numargs = 2;
163 in.args[0].size = sizeof(inarg);
164 in.args[0].value = &inarg;
165 in.args[1].size = entry->d_name.len + 1;
166 in.args[1].value = entry->d_name.name;
167 out.numargs = 1;
168 out.args[0].size = sizeof(outarg);
169 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000170 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000171
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000172 if(out.h.error)
173 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000174
Miklos Szeredia181e612001-11-06 12:03:23 +0000175 inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000176 if(!inode)
177 return -ENOMEM;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000178
Miklos Szeredi43696432001-11-18 19:15:05 +0000179 /* Don't allow userspace to do really stupid things... */
180 if((inode->i_mode ^ mode) & S_IFMT) {
181 iput(inode);
182 printk("fuse_mknod: inode has wrong type\n");
183 return -EPROTO;
184 }
185
186 if(!inode_ok(inode)) {
187 iput(inode);
188 return -EPROTO;
189 }
190
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000191 d_instantiate(entry, inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000192 return 0;
193}
194
Miklos Szeredib483c932001-10-29 14:57:57 +0000195
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000196static int fuse_create(struct inode *dir, struct dentry *entry, int mode)
197{
198 return fuse_mknod(dir, entry, mode, 0);
199}
200
Miklos Szeredib483c932001-10-29 14:57:57 +0000201static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
202{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000203 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000204 struct fuse_in in = FUSE_IN_INIT;
205 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000206 struct fuse_mkdir_in inarg;
207
208 memset(&inarg, 0, sizeof(inarg));
209 inarg.mode = mode;
Miklos Szeredib483c932001-10-29 14:57:57 +0000210
211 in.h.opcode = FUSE_MKDIR;
212 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000213 in.numargs = 2;
214 in.args[0].size = sizeof(inarg);
215 in.args[0].value = &inarg;
216 in.args[1].size = entry->d_name.len + 1;
217 in.args[1].value = entry->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000218 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000219
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000220 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000221}
222
223static int fuse_symlink(struct inode *dir, struct dentry *entry,
224 const char *link)
225{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000226 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000227 struct fuse_in in = FUSE_IN_INIT;
228 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredib483c932001-10-29 14:57:57 +0000229
230 in.h.opcode = FUSE_SYMLINK;
231 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000232 in.numargs = 2;
233 in.args[0].size = entry->d_name.len + 1;
234 in.args[0].value = entry->d_name.name;
235 in.args[1].size = strlen(link) + 1;
236 in.args[1].value = link;
Miklos Szeredib483c932001-10-29 14:57:57 +0000237 request_send(fc, &in, &out);
Miklos Szeredi43696432001-11-18 19:15:05 +0000238
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000239 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000240}
241
242static int fuse_remove(struct inode *dir, struct dentry *entry,
243 enum fuse_opcode op)
244{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000245 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000246 struct fuse_in in = FUSE_IN_INIT;
247 struct fuse_out out = FUSE_OUT_INIT;
248
249 in.h.opcode = op;
250 in.h.ino = dir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000251 in.numargs = 1;
252 in.args[0].size = entry->d_name.len + 1;
253 in.args[0].value = entry->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000254 request_send(fc, &in, &out);
Miklos Szeredi43696432001-11-18 19:15:05 +0000255
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000256 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000257}
258
259static int fuse_unlink(struct inode *dir, struct dentry *entry)
260{
261 return fuse_remove(dir, entry, FUSE_UNLINK);
262}
263
264static int fuse_rmdir(struct inode *dir, struct dentry *entry)
265{
266 return fuse_remove(dir, entry, FUSE_RMDIR);
267}
268
269static int fuse_rename(struct inode *olddir, struct dentry *oldent,
270 struct inode *newdir, struct dentry *newent)
271{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000272 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000273 struct fuse_in in = FUSE_IN_INIT;
274 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi43696432001-11-18 19:15:05 +0000275 struct fuse_rename_in inarg;
Miklos Szeredib483c932001-10-29 14:57:57 +0000276
Miklos Szeredi43696432001-11-18 19:15:05 +0000277 memset(&inarg, 0, sizeof(inarg));
278 inarg.newdir = newdir->i_ino;
Miklos Szeredib483c932001-10-29 14:57:57 +0000279
280 in.h.opcode = FUSE_RENAME;
281 in.h.ino = olddir->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000282 in.numargs = 3;
283 in.args[0].size = sizeof(inarg);
284 in.args[0].value = &inarg;
285 in.args[1].size = oldent->d_name.len + 1;
286 in.args[1].value = oldent->d_name.name;
287 in.args[2].size = newent->d_name.len + 1;
288 in.args[2].value = newent->d_name.name;
Miklos Szeredib483c932001-10-29 14:57:57 +0000289 request_send(fc, &in, &out);
Miklos Szeredib483c932001-10-29 14:57:57 +0000290
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000291 return out.h.error;
292}
293
294static int fuse_link(struct dentry *entry, struct inode *newdir,
295 struct dentry *newent)
296{
297 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000298 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +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_link_in inarg;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000302
Miklos Szeredi43696432001-11-18 19:15:05 +0000303 memset(&inarg, 0, sizeof(inarg));
304 inarg.newdir = newdir->i_ino;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000305
306 in.h.opcode = FUSE_LINK;
307 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000308 in.numargs = 2;
309 in.args[0].size = sizeof(inarg);
310 in.args[0].value = &inarg;
311 in.args[1].size = newent->d_name.len + 1;
312 in.args[1].value = newent->d_name.name;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000313 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000314
315 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000316}
317
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000318static int fuse_permission(struct inode *inode, int mask)
319{
Miklos Szeredi8cffdb92001-11-09 14:49:18 +0000320 struct fuse_conn *fc = INO_FC(inode);
321
Miklos Szeredi0a7077f2001-11-11 18:20:17 +0000322 /* (too) simple protection */
323 if(current->fsuid == fc->uid)
324 return 0;
325 else
326 return -EACCES;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000327}
328
Miklos Szeredia181e612001-11-06 12:03:23 +0000329static int fuse_revalidate(struct dentry *entry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000330{
Miklos Szeredia181e612001-11-06 12:03:23 +0000331 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000332 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000333 struct fuse_in in = FUSE_IN_INIT;
334 struct fuse_out out = FUSE_OUT_INIT;
335 struct fuse_getattr_out arg;
336
Miklos Szeredia181e612001-11-06 12:03:23 +0000337 if(inode->i_ino != FUSE_ROOT_INO &&
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000338 time_before_eq(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000339 return 0;
340
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000341 in.h.opcode = FUSE_GETATTR;
342 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000343 out.numargs = 1;
344 out.args[0].size = sizeof(arg);
345 out.args[0].value = &arg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000346 request_send(fc, &in, &out);
347
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000348 if(!out.h.error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000349 change_attributes(inode, &arg.attr);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000350
351 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000352}
353
Miklos Szeredib483c932001-10-29 14:57:57 +0000354static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
355 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000356{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000357 while(nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000358 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000359 size_t reclen = FUSE_DIRENT_SIZE(dirent);
360 int over;
361 if(dirent->namelen > NAME_MAX) {
362 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000363 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000364 }
365 if(reclen > nbytes)
366 break;
367
368 over = filldir(dstbuf, dirent->name, dirent->namelen,
369 file->f_pos, dirent->ino, dirent->type);
370 if(over)
371 break;
372
Miklos Szeredib483c932001-10-29 14:57:57 +0000373 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000374 file->f_pos += reclen;
375 nbytes -= reclen;
376 }
377
Miklos Szeredib483c932001-10-29 14:57:57 +0000378 return 0;
379}
380
381#define DIR_BUFSIZE 2048
382static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
383{
384 struct file *cfile = file->private_data;
385 char *buf;
386 int ret;
387
388 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
389 if(!buf)
390 return -ENOMEM;
391
392 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
393 if(ret < 0)
394 printk("fuse_readdir: failed to read container file\n");
395 else
396 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
397
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000398 kfree(buf);
399 return ret;
400}
401
Miklos Szeredi05033042001-11-13 16:11:35 +0000402static char *read_link(struct dentry *dentry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000403{
404 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000405 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000406 struct fuse_in in = FUSE_IN_INIT;
407 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredi05033042001-11-13 16:11:35 +0000408 char *link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000409
Miklos Szeredi05033042001-11-13 16:11:35 +0000410 link = (char *) __get_free_page(GFP_KERNEL);
411 if(!link)
412 return ERR_PTR(-ENOMEM);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000413
414 in.h.opcode = FUSE_READLINK;
415 in.h.ino = inode->i_ino;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000416 out.argvar = 1;
Miklos Szeredi43696432001-11-18 19:15:05 +0000417 out.numargs = 1;
418 out.args[0].size = PAGE_SIZE - 1;
419 out.args[0].value = link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000420 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000421 if(out.h.error) {
Miklos Szeredi05033042001-11-13 16:11:35 +0000422 free_page((unsigned long) link);
423 return ERR_PTR(out.h.error);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000424 }
425
Miklos Szeredi43696432001-11-18 19:15:05 +0000426 link[out.args[0].size] = '\0';
Miklos Szeredi05033042001-11-13 16:11:35 +0000427 return link;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000428}
429
430static void free_link(char *link)
431{
Miklos Szeredi05033042001-11-13 16:11:35 +0000432 if(!IS_ERR(link))
433 free_page((unsigned long) link);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000434}
435
436static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
437{
438 int ret;
439 char *link;
440
Miklos Szeredi05033042001-11-13 16:11:35 +0000441 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000442 ret = vfs_readlink(dentry, buffer, buflen, link);
443 free_link(link);
444 return ret;
445}
446
447static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
448{
449 int ret;
450 char *link;
451
Miklos Szeredi05033042001-11-13 16:11:35 +0000452 link = read_link(dentry);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000453 ret = vfs_follow_link(nd, link);
454 free_link(link);
455 return ret;
456}
457
458static int fuse_dir_open(struct inode *inode, struct file *file)
459{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000460 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000461 struct fuse_in in = FUSE_IN_INIT;
462 struct fuse_out out = FUSE_OUT_INIT;
463 struct fuse_getdir_out outarg;
464
465 if(!(file->f_flags & O_DIRECTORY))
Miklos Szeredia181e612001-11-06 12:03:23 +0000466 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000467
468 in.h.opcode = FUSE_GETDIR;
469 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000470 out.numargs = 1;
471 out.args[0].size = sizeof(outarg);
472 out.args[0].value = &outarg;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000473 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000474 if(!out.h.error) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000475 struct file *cfile = outarg.file;
476 struct inode *inode;
477 if(!cfile) {
478 printk("fuse_getdir: invalid file\n");
479 return -EPROTO;
480 }
481 inode = cfile->f_dentry->d_inode;
482 if(!S_ISREG(inode->i_mode)) {
483 printk("fuse_getdir: not a regular file\n");
484 fput(cfile);
485 return -EPROTO;
486 }
487
488 file->private_data = cfile;
489 }
490
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000491 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000492}
493
494static int fuse_dir_release(struct inode *inode, struct file *file)
495{
496 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000497
498 if(cfile)
499 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000500
501 return 0;
502}
503
Miklos Szeredi5e183482001-10-31 14:52:35 +0000504static unsigned int iattr_to_fattr(struct iattr *iattr,
505 struct fuse_attr *fattr)
506{
507 unsigned int ivalid = iattr->ia_valid;
508 unsigned int fvalid = 0;
509
510 memset(fattr, 0, sizeof(*fattr));
511
512 if(ivalid & ATTR_MODE)
513 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
514 if(ivalid & ATTR_UID)
515 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
516 if(ivalid & ATTR_GID)
517 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
518 if(ivalid & ATTR_SIZE)
519 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
520 /* You can only _set_ these together (they may change by themselves) */
521 if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
522 fvalid |= FATTR_UTIME;
523 fattr->atime = iattr->ia_atime;
524 fattr->mtime = iattr->ia_mtime;
525 }
526
527 return fvalid;
528}
529
530static int fuse_setattr(struct dentry *entry, struct iattr *attr)
531{
532 struct inode *inode = entry->d_inode;
533 struct fuse_conn *fc = INO_FC(inode);
534 struct fuse_in in = FUSE_IN_INIT;
535 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000536 struct fuse_setattr_in inarg;
537 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000538
Miklos Szeredi43696432001-11-18 19:15:05 +0000539 memset(&inarg, 0, sizeof(inarg));
Miklos Szeredia181e612001-11-06 12:03:23 +0000540 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000541
542 in.h.opcode = FUSE_SETATTR;
543 in.h.ino = inode->i_ino;
Miklos Szeredi43696432001-11-18 19:15:05 +0000544 in.numargs = 1;
545 in.args[0].size = sizeof(inarg);
546 in.args[0].value = &inarg;
547 out.numargs = 1;
548 out.args[0].size = sizeof(outarg);
549 out.args[0].value = &outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000550 request_send(fc, &in, &out);
551
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000552 if(!out.h.error) {
553 if(attr->ia_valid & ATTR_SIZE &&
554 outarg.attr.size < inode->i_size)
555 vmtruncate(inode, outarg.attr.size);
Miklos Szeredia181e612001-11-06 12:03:23 +0000556
Miklos Szeredif3ea83b2001-11-07 14:55:16 +0000557 change_attributes(inode, &outarg.attr);
558 }
Miklos Szeredi5e183482001-10-31 14:52:35 +0000559 return out.h.error;
560}
561
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000562static int fuse_dentry_revalidate(struct dentry *entry, int flags)
563{
Miklos Szeredi97c61e92001-11-07 12:09:43 +0000564 if(!entry->d_inode)
565 return 0;
Miklos Szeredi4c749292001-11-16 21:40:00 +0000566 /* Must not revaidate too soon, since kernel revalidate logic is
567 broken, and could return ENOENT */
568 else if(!(flags & LOOKUP_CONTINUE) &&
569 time_after(jiffies, entry->d_time + FUSE_REVALIDATE_TIME))
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000570 return 0;
571 else
572 return 1;
573}
574
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000575static struct inode_operations fuse_dir_inode_operations =
576{
577 lookup: fuse_lookup,
578 create: fuse_create,
579 mknod: fuse_mknod,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000580 mkdir: fuse_mkdir,
Miklos Szeredib483c932001-10-29 14:57:57 +0000581 symlink: fuse_symlink,
582 unlink: fuse_unlink,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000583 rmdir: fuse_rmdir,
584 rename: fuse_rename,
Miklos Szeredib483c932001-10-29 14:57:57 +0000585 link: fuse_link,
586 setattr: fuse_setattr,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000587 permission: fuse_permission,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000588 revalidate: fuse_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000589};
590
591static struct file_operations fuse_dir_operations = {
592 read: generic_read_dir,
593 readdir: fuse_readdir,
594 open: fuse_dir_open,
595 release: fuse_dir_release,
596};
597
598static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000599 setattr: fuse_setattr,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000600 permission: fuse_permission,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000601 revalidate: fuse_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000602};
603
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000604static struct inode_operations fuse_symlink_inode_operations =
605{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000606 setattr: fuse_setattr,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000607 readlink: fuse_readlink,
608 follow_link: fuse_follow_link,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000609 revalidate: fuse_revalidate,
610};
611
612static struct dentry_operations fuse_dentry_opertations = {
613 d_revalidate: fuse_dentry_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000614};
615
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000616/*
617 * Local Variables:
618 * indent-tabs-mode: t
619 * c-basic-offset: 8
620 * End:
621 */