2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
5 This program can be distributed under the terms of the GNU GPL.
11 #include <linux/pagemap.h>
12 #include <linux/file.h>
13 #include <linux/gfp.h>
14 #include <linux/sched.h>
15 #include <linux/namei.h>
17 static inline unsigned long time_to_jiffies(unsigned long sec
,
20 struct timespec ts
= {sec
, nsec
};
21 return jiffies
+ timespec_to_jiffies(&ts
);
24 static void fuse_lookup_init(struct fuse_req
*req
, struct inode
*dir
,
26 struct fuse_entry_out
*outarg
)
28 req
->in
.h
.opcode
= FUSE_LOOKUP
;
29 req
->in
.h
.nodeid
= get_node_id(dir
);
32 req
->in
.args
[0].size
= entry
->d_name
.len
+ 1;
33 req
->in
.args
[0].value
= entry
->d_name
.name
;
35 req
->out
.args
[0].size
= sizeof(struct fuse_entry_out
);
36 req
->out
.args
[0].value
= outarg
;
39 static int fuse_dentry_revalidate(struct dentry
*entry
, struct nameidata
*nd
)
41 if (!entry
->d_inode
|| is_bad_inode(entry
->d_inode
))
43 else if (time_after(jiffies
, entry
->d_time
)) {
46 struct fuse_entry_out outarg
;
47 struct inode
*inode
= entry
->d_inode
;
48 struct fuse_inode
*fi
= get_fuse_inode(inode
);
49 struct fuse_conn
*fc
= get_fuse_conn(inode
);
50 struct fuse_req
*req
= fuse_get_request_nonint(fc
);
54 fuse_lookup_init(req
, entry
->d_parent
->d_inode
, entry
, &outarg
);
55 request_send_nonint(fc
, req
);
56 version
= req
->out
.h
.unique
;
57 err
= req
->out
.h
.error
;
58 fuse_put_request(fc
, req
);
59 if (err
|| outarg
.nodeid
!= get_node_id(inode
) ||
60 (outarg
.attr
.mode
^ inode
->i_mode
) & S_IFMT
)
63 fuse_change_attributes(inode
, &outarg
.attr
);
64 inode
->i_version
= version
;
65 entry
->d_time
= time_to_jiffies(outarg
.entry_valid
,
66 outarg
.entry_valid_nsec
);
67 fi
->i_time
= time_to_jiffies(outarg
.attr_valid
,
68 outarg
.attr_valid_nsec
);
73 static struct dentry_operations fuse_dentry_operations
= {
74 .d_revalidate
= fuse_dentry_revalidate
,
77 static int fuse_lookup_iget(struct inode
*dir
, struct dentry
*entry
,
78 struct inode
**inodep
)
82 struct fuse_entry_out outarg
;
83 struct inode
*inode
= NULL
;
84 struct fuse_conn
*fc
= get_fuse_conn(dir
);
87 if (entry
->d_name
.len
> FUSE_NAME_MAX
)
90 req
= fuse_get_request(fc
);
92 return -ERESTARTNOINTR
;
94 fuse_lookup_init(req
, dir
, entry
, &outarg
);
95 request_send(fc
, req
);
96 version
= req
->out
.h
.unique
;
97 err
= req
->out
.h
.error
;
99 inode
= fuse_iget(dir
->i_sb
, outarg
.nodeid
, outarg
.generation
,
100 &outarg
.attr
, version
);
102 fuse_send_forget(fc
, req
, outarg
.nodeid
, version
);
106 fuse_put_request(fc
, req
);
107 if (err
&& err
!= -ENOENT
)
111 struct fuse_inode
*fi
= get_fuse_inode(inode
);
112 entry
->d_time
= time_to_jiffies(outarg
.entry_valid
,
113 outarg
.entry_valid_nsec
);
114 fi
->i_time
= time_to_jiffies(outarg
.attr_valid
,
115 outarg
.attr_valid_nsec
);
118 entry
->d_op
= &fuse_dentry_operations
;
123 int fuse_do_getattr(struct inode
*inode
)
126 struct fuse_attr_out arg
;
127 struct fuse_conn
*fc
= get_fuse_conn(inode
);
128 struct fuse_req
*req
= fuse_get_request(fc
);
130 return -ERESTARTNOINTR
;
132 req
->in
.h
.opcode
= FUSE_GETATTR
;
133 req
->in
.h
.nodeid
= get_node_id(inode
);
135 req
->out
.numargs
= 1;
136 req
->out
.args
[0].size
= sizeof(arg
);
137 req
->out
.args
[0].value
= &arg
;
138 request_send(fc
, req
);
139 err
= req
->out
.h
.error
;
140 fuse_put_request(fc
, req
);
142 if ((inode
->i_mode
^ arg
.attr
.mode
) & S_IFMT
) {
143 make_bad_inode(inode
);
146 struct fuse_inode
*fi
= get_fuse_inode(inode
);
147 fuse_change_attributes(inode
, &arg
.attr
);
148 fi
->i_time
= time_to_jiffies(arg
.attr_valid
,
149 arg
.attr_valid_nsec
);
155 static int fuse_revalidate(struct dentry
*entry
)
157 struct inode
*inode
= entry
->d_inode
;
158 struct fuse_inode
*fi
= get_fuse_inode(inode
);
159 struct fuse_conn
*fc
= get_fuse_conn(inode
);
161 if (get_node_id(inode
) == FUSE_ROOT_ID
) {
162 if (current
->fsuid
!= fc
->user_id
)
164 } else if (time_before_eq(jiffies
, fi
->i_time
))
167 return fuse_do_getattr(inode
);
170 static int fuse_permission(struct inode
*inode
, int mask
, struct nameidata
*nd
)
172 struct fuse_conn
*fc
= get_fuse_conn(inode
);
174 if (current
->fsuid
!= fc
->user_id
)
177 int mode
= inode
->i_mode
;
178 if ((mask
& MAY_WRITE
) && IS_RDONLY(inode
) &&
179 (S_ISREG(mode
) || S_ISDIR(mode
) || S_ISLNK(mode
)))
181 if ((mask
& MAY_EXEC
) && !S_ISDIR(mode
) && !(mode
& S_IXUGO
))
187 static int parse_dirfile(char *buf
, size_t nbytes
, struct file
*file
,
188 void *dstbuf
, filldir_t filldir
)
190 while (nbytes
>= FUSE_NAME_OFFSET
) {
191 struct fuse_dirent
*dirent
= (struct fuse_dirent
*) buf
;
192 size_t reclen
= FUSE_DIRENT_SIZE(dirent
);
194 if (!dirent
->namelen
|| dirent
->namelen
> FUSE_NAME_MAX
)
199 over
= filldir(dstbuf
, dirent
->name
, dirent
->namelen
,
200 file
->f_pos
, dirent
->ino
, dirent
->type
);
206 file
->f_pos
= dirent
->off
;
212 static int fuse_checkdir(struct file
*cfile
, struct file
*file
)
217 inode
= cfile
->f_dentry
->d_inode
;
218 if (!S_ISREG(inode
->i_mode
)) {
223 file
->private_data
= cfile
;
227 static int fuse_getdir(struct file
*file
)
229 struct inode
*inode
= file
->f_dentry
->d_inode
;
230 struct fuse_conn
*fc
= get_fuse_conn(inode
);
231 struct fuse_req
*req
= fuse_get_request(fc
);
232 struct fuse_getdir_out_i outarg
;
236 return -ERESTARTNOINTR
;
238 req
->in
.h
.opcode
= FUSE_GETDIR
;
239 req
->in
.h
.nodeid
= get_node_id(inode
);
241 req
->out
.numargs
= 1;
242 req
->out
.args
[0].size
= sizeof(struct fuse_getdir_out
);
243 req
->out
.args
[0].value
= &outarg
;
244 request_send(fc
, req
);
245 err
= req
->out
.h
.error
;
246 fuse_put_request(fc
, req
);
248 err
= fuse_checkdir(outarg
.file
, file
);
252 static int fuse_readdir(struct file
*file
, void *dstbuf
, filldir_t filldir
)
254 struct file
*cfile
= file
->private_data
;
259 ret
= fuse_getdir(file
);
263 cfile
= file
->private_data
;
266 buf
= (char *) __get_free_page(GFP_KERNEL
);
270 ret
= kernel_read(cfile
, file
->f_pos
, buf
, PAGE_SIZE
);
272 ret
= parse_dirfile(buf
, ret
, file
, dstbuf
, filldir
);
274 free_page((unsigned long) buf
);
278 static char *read_link(struct dentry
*dentry
)
280 struct inode
*inode
= dentry
->d_inode
;
281 struct fuse_conn
*fc
= get_fuse_conn(inode
);
282 struct fuse_req
*req
= fuse_get_request(fc
);
286 return ERR_PTR(-ERESTARTNOINTR
);
288 link
= (char *) __get_free_page(GFP_KERNEL
);
290 link
= ERR_PTR(-ENOMEM
);
293 req
->in
.h
.opcode
= FUSE_READLINK
;
294 req
->in
.h
.nodeid
= get_node_id(inode
);
297 req
->out
.numargs
= 1;
298 req
->out
.args
[0].size
= PAGE_SIZE
- 1;
299 req
->out
.args
[0].value
= link
;
300 request_send(fc
, req
);
301 if (req
->out
.h
.error
) {
302 free_page((unsigned long) link
);
303 link
= ERR_PTR(req
->out
.h
.error
);
305 link
[req
->out
.args
[0].size
] = '\0';
307 fuse_put_request(fc
, req
);
311 static void free_link(char *link
)
314 free_page((unsigned long) link
);
317 static void *fuse_follow_link(struct dentry
*dentry
, struct nameidata
*nd
)
319 nd_set_link(nd
, read_link(dentry
));
323 static void fuse_put_link(struct dentry
*dentry
, struct nameidata
*nd
, void *c
)
325 free_link(nd_get_link(nd
));
328 static int fuse_dir_open(struct inode
*inode
, struct file
*file
)
330 file
->private_data
= NULL
;
334 static int fuse_dir_release(struct inode
*inode
, struct file
*file
)
336 struct file
*cfile
= file
->private_data
;
344 static int fuse_getattr(struct vfsmount
*mnt
, struct dentry
*entry
,
347 struct inode
*inode
= entry
->d_inode
;
348 int err
= fuse_revalidate(entry
);
350 generic_fillattr(inode
, stat
);
355 static struct dentry
*fuse_lookup(struct inode
*dir
, struct dentry
*entry
,
356 struct nameidata
*nd
)
359 int err
= fuse_lookup_iget(dir
, entry
, &inode
);
362 if (inode
&& S_ISDIR(inode
->i_mode
)) {
363 /* Don't allow creating an alias to a directory */
364 struct dentry
*alias
= d_find_alias(inode
);
365 if (alias
&& !(alias
->d_flags
& DCACHE_DISCONNECTED
)) {
368 return ERR_PTR(-EIO
);
371 return d_splice_alias(inode
, entry
);
374 static struct inode_operations fuse_dir_inode_operations
= {
375 .lookup
= fuse_lookup
,
376 .permission
= fuse_permission
,
377 .getattr
= fuse_getattr
,
380 static struct file_operations fuse_dir_operations
= {
381 .read
= generic_read_dir
,
382 .readdir
= fuse_readdir
,
383 .open
= fuse_dir_open
,
384 .release
= fuse_dir_release
,
387 static struct inode_operations fuse_common_inode_operations
= {
388 .permission
= fuse_permission
,
389 .getattr
= fuse_getattr
,
392 static struct inode_operations fuse_symlink_inode_operations
= {
393 .follow_link
= fuse_follow_link
,
394 .put_link
= fuse_put_link
,
395 .readlink
= generic_readlink
,
396 .getattr
= fuse_getattr
,
399 void fuse_init_common(struct inode
*inode
)
401 inode
->i_op
= &fuse_common_inode_operations
;
404 void fuse_init_dir(struct inode
*inode
)
406 inode
->i_op
= &fuse_dir_inode_operations
;
407 inode
->i_fop
= &fuse_dir_operations
;
410 void fuse_init_symlink(struct inode
*inode
)
412 inode
->i_op
= &fuse_symlink_inode_operations
;