blob: f506816132a05c22f73fe5413227485407ea5a63 [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
11#include <linux/module.h>
12#include <linux/kernel.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000013#include <linux/slab.h>
Miklos Szeredi5e183482001-10-31 14:52:35 +000014#include <linux/file.h>
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000015
Miklos Szeredib483c932001-10-29 14:57:57 +000016static struct inode_operations fuse_dir_inode_operations;
17static struct inode_operations fuse_file_inode_operations;
18static struct inode_operations fuse_symlink_inode_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000019
20static struct file_operations fuse_dir_operations;
Miklos Szeredib483c932001-10-29 14:57:57 +000021
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000022static struct dentry_operations fuse_dentry_opertations;
Miklos Szeredib483c932001-10-29 14:57:57 +000023
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000024static void change_attributes(struct inode *inode, struct fuse_attr *attr)
25{
Miklos Szeredia181e612001-11-06 12:03:23 +000026 if(S_ISREG(inode->i_mode) && inode->i_size != attr->size)
27 invalidate_inode_pages(inode);
28
Miklos Szeredi5e183482001-10-31 14:52:35 +000029 inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000030 inode->i_nlink = attr->nlink;
31 inode->i_uid = attr->uid;
32 inode->i_gid = attr->gid;
33 inode->i_size = attr->size;
34 inode->i_blksize = attr->blksize;
35 inode->i_blocks = attr->blocks;
36 inode->i_atime = attr->atime;
37 inode->i_mtime = attr->mtime;
38 inode->i_ctime = attr->ctime;
39}
40
Miklos Szeredia181e612001-11-06 12:03:23 +000041static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000042{
Miklos Szeredia181e612001-11-06 12:03:23 +000043 inode->i_mode = attr->mode & S_IFMT;
44 inode->i_size = attr->size;
Miklos Szeredib483c932001-10-29 14:57:57 +000045 if(S_ISREG(inode->i_mode)) {
46 inode->i_op = &fuse_file_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000047 fuse_init_file_inode(inode);
Miklos Szeredib483c932001-10-29 14:57:57 +000048 }
49 else if(S_ISDIR(inode->i_mode)) {
50 inode->i_op = &fuse_dir_inode_operations;
51 inode->i_fop = &fuse_dir_operations;
52 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000053 else if(S_ISLNK(inode->i_mode)) {
Miklos Szeredib483c932001-10-29 14:57:57 +000054 inode->i_op = &fuse_symlink_inode_operations;
Miklos Szeredi5e183482001-10-31 14:52:35 +000055 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000056 else {
Miklos Szeredia181e612001-11-06 12:03:23 +000057 inode->i_op = &fuse_file_inode_operations;
58 init_special_inode(inode, inode->i_mode, attr->rdev);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000059 }
Miklos Szeredi5e183482001-10-31 14:52:35 +000060 inode->u.generic_ip = inode;
61}
62
63struct inode *fuse_iget(struct super_block *sb, ino_t ino,
Miklos Szeredia181e612001-11-06 12:03:23 +000064 struct fuse_attr *attr, int version)
Miklos Szeredi5e183482001-10-31 14:52:35 +000065{
66 struct inode *inode;
67
68 inode = iget(sb, ino);
69 if(inode) {
70 if(!inode->u.generic_ip)
Miklos Szeredia181e612001-11-06 12:03:23 +000071 fuse_init_inode(inode, attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +000072
73 change_attributes(inode, attr);
Miklos Szeredia181e612001-11-06 12:03:23 +000074 inode->i_version = version;
Miklos Szeredi5e183482001-10-31 14:52:35 +000075 }
76
77 return inode;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000078}
79
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000080static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry)
81{
Miklos Szeredia181e612001-11-06 12:03:23 +000082 int ret;
Miklos Szeredi5e183482001-10-31 14:52:35 +000083 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000084 struct fuse_in in = FUSE_IN_INIT;
85 struct fuse_out out = FUSE_OUT_INIT;
86 struct fuse_lookup_out arg;
87 struct inode *inode;
Miklos Szeredia181e612001-11-06 12:03:23 +000088
Miklos Szeredi85c74fc2001-10-28 19:44:14 +000089 in.h.opcode = FUSE_LOOKUP;
90 in.h.ino = dir->i_ino;
91 in.argsize = entry->d_name.len + 1;
92 in.arg = entry->d_name.name;
93 out.argsize = sizeof(arg);
94 out.arg = &arg;
95 request_send(fc, &in, &out);
96
Miklos Szeredi19dff1b2001-10-30 15:06:52 +000097 inode = NULL;
98 if(!out.h.error) {
Miklos Szeredia181e612001-11-06 12:03:23 +000099 ret = -ENOMEM;
100 inode = fuse_iget(dir->i_sb, arg.ino, &arg.attr, out.h.unique);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000101 if(!inode)
Miklos Szeredia181e612001-11-06 12:03:23 +0000102 goto err;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000103 }
Miklos Szeredia181e612001-11-06 12:03:23 +0000104 else if(out.h.error != -ENOENT) {
105 ret = out.h.error;
106 goto err;
107 }
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000108
Miklos Szeredia181e612001-11-06 12:03:23 +0000109 entry->d_time = jiffies;
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000110 entry->d_op = &fuse_dentry_opertations;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000111 d_add(entry, inode);
Miklos Szeredia181e612001-11-06 12:03:23 +0000112
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000113 return NULL;
Miklos Szeredia181e612001-11-06 12:03:23 +0000114
115 err:
116 return ERR_PTR(ret);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000117}
118
Miklos Szeredib483c932001-10-29 14:57:57 +0000119/* create needs to return a positive entry, so this also does a lookup */
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000120static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
121 int rdev)
122{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000123 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000124 struct fuse_in in = FUSE_IN_INIT;
125 struct fuse_out out = FUSE_OUT_INIT;
126 struct fuse_mknod_in *inarg;
127 unsigned int insize;
128 struct fuse_mknod_out outarg;
129 struct inode *inode;
130
131 insize = offsetof(struct fuse_mknod_in, name) + entry->d_name.len + 1;
132 inarg = kmalloc(insize, GFP_KERNEL);
133 if(!inarg)
134 return -ENOMEM;
135
136 inarg->mode = mode;
137 inarg->rdev = rdev;
138 strcpy(inarg->name, entry->d_name.name);
139
140 in.h.opcode = FUSE_MKNOD;
141 in.h.ino = dir->i_ino;
142 in.argsize = insize;
143 in.arg = inarg;
144 out.argsize = sizeof(outarg);
145 out.arg = &outarg;
146 request_send(fc, &in, &out);
147 kfree(inarg);
Miklos Szeredib483c932001-10-29 14:57:57 +0000148
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000149 if(out.h.error)
150 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000151
Miklos Szeredia181e612001-11-06 12:03:23 +0000152 inode = fuse_iget(dir->i_sb, outarg.ino, &outarg.attr, out.h.unique);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000153 if(!inode)
154 return -ENOMEM;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000155
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000156 d_instantiate(entry, inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000157 return 0;
158}
159
Miklos Szeredib483c932001-10-29 14:57:57 +0000160
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000161static int fuse_create(struct inode *dir, struct dentry *entry, int mode)
162{
163 return fuse_mknod(dir, entry, mode, 0);
164}
165
Miklos Szeredib483c932001-10-29 14:57:57 +0000166static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
167{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000168 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000169 struct fuse_in in = FUSE_IN_INIT;
170 struct fuse_out out = FUSE_OUT_INIT;
171 struct fuse_mkdir_in *inarg;
172 unsigned int insize;
173
174 insize = offsetof(struct fuse_mkdir_in, name) + entry->d_name.len + 1;
175 inarg = kmalloc(insize, GFP_KERNEL);
176 if(!inarg)
177 return -ENOMEM;
178
179 inarg->mode = mode;
180 strcpy(inarg->name, entry->d_name.name);
181
182 in.h.opcode = FUSE_MKDIR;
183 in.h.ino = dir->i_ino;
184 in.argsize = insize;
185 in.arg = inarg;
186 request_send(fc, &in, &out);
187 kfree(inarg);
188
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000189 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000190}
191
192static int fuse_symlink(struct inode *dir, struct dentry *entry,
193 const char *link)
194{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000195 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000196 struct fuse_in in = FUSE_IN_INIT;
197 struct fuse_out out = FUSE_OUT_INIT;
198 char *inarg;
199 unsigned int insize;
200
201 insize = entry->d_name.len + 1 + strlen(link) + 1;
202 inarg = kmalloc(insize, GFP_KERNEL);
203 if(!inarg)
204 return -ENOMEM;
205
206 strcpy(inarg, entry->d_name.name);
207 strcpy(inarg + entry->d_name.len + 1, link);
208
209 in.h.opcode = FUSE_SYMLINK;
210 in.h.ino = dir->i_ino;
211 in.argsize = insize;
212 in.arg = inarg;
213 request_send(fc, &in, &out);
214 kfree(inarg);
215
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000216 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000217}
218
219static int fuse_remove(struct inode *dir, struct dentry *entry,
220 enum fuse_opcode op)
221{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000222 struct fuse_conn *fc = INO_FC(dir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000223 struct fuse_in in = FUSE_IN_INIT;
224 struct fuse_out out = FUSE_OUT_INIT;
225
226 in.h.opcode = op;
227 in.h.ino = dir->i_ino;
228 in.argsize = entry->d_name.len + 1;
229 in.arg = entry->d_name.name;
230 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000231 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000232}
233
234static int fuse_unlink(struct inode *dir, struct dentry *entry)
235{
236 return fuse_remove(dir, entry, FUSE_UNLINK);
237}
238
239static int fuse_rmdir(struct inode *dir, struct dentry *entry)
240{
241 return fuse_remove(dir, entry, FUSE_RMDIR);
242}
243
244static int fuse_rename(struct inode *olddir, struct dentry *oldent,
245 struct inode *newdir, struct dentry *newent)
246{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000247 struct fuse_conn *fc = INO_FC(olddir);
Miklos Szeredib483c932001-10-29 14:57:57 +0000248 struct fuse_in in = FUSE_IN_INIT;
249 struct fuse_out out = FUSE_OUT_INIT;
250 struct fuse_rename_in *inarg;
251 unsigned int oldnamsize = oldent->d_name.len + 1;
252 unsigned int newnamsize = newent->d_name.len + 1;
253 unsigned int insize;
254
255 insize = offsetof(struct fuse_rename_in, names) + oldnamsize +
256 newnamsize;
257 inarg = kmalloc(insize, GFP_KERNEL);
258 if(!inarg)
259 return -ENOMEM;
260
261 inarg->newdir = newdir->i_ino;
262 strcpy(inarg->names, oldent->d_name.name);
263 strcpy(inarg->names + oldnamsize, newent->d_name.name);
264
265 in.h.opcode = FUSE_RENAME;
266 in.h.ino = olddir->i_ino;
267 in.argsize = insize;
268 in.arg = inarg;
269 request_send(fc, &in, &out);
270 kfree(inarg);
271
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000272 return out.h.error;
273}
274
275static int fuse_link(struct dentry *entry, struct inode *newdir,
276 struct dentry *newent)
277{
278 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000279 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000280 struct fuse_in in = FUSE_IN_INIT;
281 struct fuse_out out = FUSE_OUT_INIT;
282 struct fuse_link_in *inarg;
283 unsigned int insize;
284
285 insize = offsetof(struct fuse_link_in, name) + newent->d_name.len + 1;
286 inarg = kmalloc(insize, GFP_KERNEL);
287 if(!inarg)
288 return -ENOMEM;
289
290 inarg->newdir = newdir->i_ino;
291 strcpy(inarg->name, newent->d_name.name);
292
293 in.h.opcode = FUSE_LINK;
294 in.h.ino = inode->i_ino;
295 in.argsize = insize;
296 in.arg = inarg;
297 request_send(fc, &in, &out);
298 kfree(inarg);
299
300 return out.h.error;
Miklos Szeredib483c932001-10-29 14:57:57 +0000301}
302
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000303static int fuse_permission(struct inode *inode, int mask)
304{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000305 return 0;
306}
307
Miklos Szeredia181e612001-11-06 12:03:23 +0000308static int fuse_revalidate(struct dentry *entry)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000309{
Miklos Szeredia181e612001-11-06 12:03:23 +0000310 struct inode *inode = entry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000311 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000312 struct fuse_in in = FUSE_IN_INIT;
313 struct fuse_out out = FUSE_OUT_INIT;
314 struct fuse_getattr_out arg;
315
Miklos Szeredia181e612001-11-06 12:03:23 +0000316 if(inode->i_ino != FUSE_ROOT_INO &&
317 time_before_eq(jiffies, entry->d_time + HZ / 100))
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000318 return 0;
319
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000320 in.h.opcode = FUSE_GETATTR;
321 in.h.ino = inode->i_ino;
322 out.argsize = sizeof(arg);
323 out.arg = &arg;
324 request_send(fc, &in, &out);
325
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000326 if(!out.h.error)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000327 change_attributes(inode, &arg.attr);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000328
329 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000330}
331
Miklos Szeredib483c932001-10-29 14:57:57 +0000332static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
333 void *dstbuf, filldir_t filldir)
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000334{
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000335 while(nbytes >= FUSE_NAME_OFFSET) {
Miklos Szeredib483c932001-10-29 14:57:57 +0000336 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000337 size_t reclen = FUSE_DIRENT_SIZE(dirent);
338 int over;
339 if(dirent->namelen > NAME_MAX) {
340 printk("fuse_readdir: name too long\n");
Miklos Szeredib483c932001-10-29 14:57:57 +0000341 return -EPROTO;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000342 }
343 if(reclen > nbytes)
344 break;
345
346 over = filldir(dstbuf, dirent->name, dirent->namelen,
347 file->f_pos, dirent->ino, dirent->type);
348 if(over)
349 break;
350
Miklos Szeredib483c932001-10-29 14:57:57 +0000351 buf += reclen;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000352 file->f_pos += reclen;
353 nbytes -= reclen;
354 }
355
Miklos Szeredib483c932001-10-29 14:57:57 +0000356 return 0;
357}
358
359#define DIR_BUFSIZE 2048
360static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
361{
362 struct file *cfile = file->private_data;
363 char *buf;
364 int ret;
365
366 buf = kmalloc(DIR_BUFSIZE, GFP_KERNEL);
367 if(!buf)
368 return -ENOMEM;
369
370 ret = kernel_read(cfile, file->f_pos, buf, DIR_BUFSIZE);
371 if(ret < 0)
372 printk("fuse_readdir: failed to read container file\n");
373 else
374 ret = parse_dirfile(buf, ret, file, dstbuf, filldir);
375
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000376 kfree(buf);
377 return ret;
378}
379
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000380static int read_link(struct dentry *dentry, char **bufp)
381{
382 struct inode *inode = dentry->d_inode;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000383 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000384 struct fuse_in in = FUSE_IN_INIT;
385 struct fuse_out out = FUSE_OUT_INIT;
386 unsigned long page;
387
388 page = __get_free_page(GFP_KERNEL);
389 if(!page)
390 return -ENOMEM;
391
392 in.h.opcode = FUSE_READLINK;
393 in.h.ino = inode->i_ino;
394 out.arg = (void *) page;
395 out.argsize = PAGE_SIZE - 1;
396 out.argvar = 1;
397 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000398 if(out.h.error) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000399 free_page(page);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000400 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000401 }
402
403 *bufp = (char *) page;
404 (*bufp)[out.argsize] = '\0';
405 return 0;
406}
407
408static void free_link(char *link)
409{
410 free_page((unsigned long) link);
411}
412
413static int fuse_readlink(struct dentry *dentry, char *buffer, int buflen)
414{
415 int ret;
416 char *link;
417
418 ret = read_link(dentry, &link);
419 if(ret)
420 return ret;
421
422 ret = vfs_readlink(dentry, buffer, buflen, link);
423 free_link(link);
424 return ret;
425}
426
427static int fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
428{
429 int ret;
430 char *link;
431
432 ret = read_link(dentry, &link);
433 if(ret)
434 return ret;
435
436 ret = vfs_follow_link(nd, link);
437 free_link(link);
438 return ret;
439}
440
441static int fuse_dir_open(struct inode *inode, struct file *file)
442{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000443 struct fuse_conn *fc = INO_FC(inode);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000444 struct fuse_in in = FUSE_IN_INIT;
445 struct fuse_out out = FUSE_OUT_INIT;
446 struct fuse_getdir_out outarg;
447
448 if(!(file->f_flags & O_DIRECTORY))
Miklos Szeredia181e612001-11-06 12:03:23 +0000449 return 0;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000450
451 in.h.opcode = FUSE_GETDIR;
452 in.h.ino = inode->i_ino;
453 out.argsize = sizeof(outarg);
454 out.arg = &outarg;
455 request_send(fc, &in, &out);
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000456 if(!out.h.error) {
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000457 struct file *cfile = outarg.file;
458 struct inode *inode;
459 if(!cfile) {
460 printk("fuse_getdir: invalid file\n");
461 return -EPROTO;
462 }
463 inode = cfile->f_dentry->d_inode;
464 if(!S_ISREG(inode->i_mode)) {
465 printk("fuse_getdir: not a regular file\n");
466 fput(cfile);
467 return -EPROTO;
468 }
469
470 file->private_data = cfile;
471 }
472
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000473 return out.h.error;
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000474}
475
476static int fuse_dir_release(struct inode *inode, struct file *file)
477{
478 struct file *cfile = file->private_data;
Miklos Szeredia181e612001-11-06 12:03:23 +0000479
480 if(cfile)
481 fput(cfile);
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000482
483 return 0;
484}
485
Miklos Szeredi5e183482001-10-31 14:52:35 +0000486static unsigned int iattr_to_fattr(struct iattr *iattr,
487 struct fuse_attr *fattr)
488{
489 unsigned int ivalid = iattr->ia_valid;
490 unsigned int fvalid = 0;
491
492 memset(fattr, 0, sizeof(*fattr));
493
494 if(ivalid & ATTR_MODE)
495 fvalid |= FATTR_MODE, fattr->mode = iattr->ia_mode;
496 if(ivalid & ATTR_UID)
497 fvalid |= FATTR_UID, fattr->uid = iattr->ia_uid;
498 if(ivalid & ATTR_GID)
499 fvalid |= FATTR_GID, fattr->gid = iattr->ia_gid;
500 if(ivalid & ATTR_SIZE)
501 fvalid |= FATTR_SIZE, fattr->size = iattr->ia_size;
502 /* You can only _set_ these together (they may change by themselves) */
503 if((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
504 fvalid |= FATTR_UTIME;
505 fattr->atime = iattr->ia_atime;
506 fattr->mtime = iattr->ia_mtime;
507 }
508
509 return fvalid;
510}
511
512static int fuse_setattr(struct dentry *entry, struct iattr *attr)
513{
514 struct inode *inode = entry->d_inode;
515 struct fuse_conn *fc = INO_FC(inode);
516 struct fuse_in in = FUSE_IN_INIT;
517 struct fuse_out out = FUSE_OUT_INIT;
Miklos Szeredia181e612001-11-06 12:03:23 +0000518 struct fuse_setattr_in inarg;
519 struct fuse_setattr_out outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000520
Miklos Szeredia181e612001-11-06 12:03:23 +0000521 inarg.valid = iattr_to_fattr(attr, &inarg.attr);
Miklos Szeredi5e183482001-10-31 14:52:35 +0000522
523 in.h.opcode = FUSE_SETATTR;
524 in.h.ino = inode->i_ino;
Miklos Szeredia181e612001-11-06 12:03:23 +0000525 in.argsize = sizeof(inarg);
526 in.arg = &inarg;
527 out.argsize = sizeof(outarg);
528 out.arg = &outarg;
Miklos Szeredi5e183482001-10-31 14:52:35 +0000529 request_send(fc, &in, &out);
530
Miklos Szeredia181e612001-11-06 12:03:23 +0000531 if(!out.h.error && (attr->ia_valid & ATTR_SIZE)) {
532 if(outarg.newsize > attr->ia_size)
533 outarg.newsize = attr->ia_size;
534
535 vmtruncate(inode, outarg.newsize);
536 }
537
Miklos Szeredi5e183482001-10-31 14:52:35 +0000538 return out.h.error;
539}
540
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000541static int fuse_dentry_revalidate(struct dentry *entry, int flags)
542{
543 if(!entry->d_inode || !(flags & LOOKUP_CONTINUE))
544 return 0;
545 else
546 return 1;
547}
548
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000549static struct inode_operations fuse_dir_inode_operations =
550{
551 lookup: fuse_lookup,
552 create: fuse_create,
553 mknod: fuse_mknod,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000554 mkdir: fuse_mkdir,
Miklos Szeredib483c932001-10-29 14:57:57 +0000555 symlink: fuse_symlink,
556 unlink: fuse_unlink,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000557 rmdir: fuse_rmdir,
558 rename: fuse_rename,
Miklos Szeredib483c932001-10-29 14:57:57 +0000559 link: fuse_link,
560 setattr: fuse_setattr,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000561 permission: fuse_permission,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000562 revalidate: fuse_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000563};
564
565static struct file_operations fuse_dir_operations = {
566 read: generic_read_dir,
567 readdir: fuse_readdir,
568 open: fuse_dir_open,
569 release: fuse_dir_release,
570};
571
572static struct inode_operations fuse_file_inode_operations = {
Miklos Szeredi5e183482001-10-31 14:52:35 +0000573 setattr: fuse_setattr,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000574 permission: fuse_permission,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000575 revalidate: fuse_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000576};
577
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000578static struct inode_operations fuse_symlink_inode_operations =
579{
Miklos Szeredi5e183482001-10-31 14:52:35 +0000580 setattr: fuse_setattr,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000581 readlink: fuse_readlink,
582 follow_link: fuse_follow_link,
Miklos Szeredi19dff1b2001-10-30 15:06:52 +0000583 revalidate: fuse_revalidate,
584};
585
586static struct dentry_operations fuse_dentry_opertations = {
587 d_revalidate: fuse_dentry_revalidate,
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000588};
589
Miklos Szeredi85c74fc2001-10-28 19:44:14 +0000590/*
591 * Local Variables:
592 * indent-tabs-mode: t
593 * c-basic-offset: 8
594 * End:
595 */