1 /*
2     FUSE: Filesystem in Userspace
3     Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4 
5     This program can be distributed under the terms of the GNU LGPLv2.
6     See the file COPYING.LIB
7 */
8 
9 #include "config.h"
10 #include "fuse_lowlevel.h"
11 #include "fuse_kernel.h"
12 #include "fuse_i.h"
13 
14 #include <stdio.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <assert.h>
18 
fuse_kern_chan_receive(struct fuse_chan ** chp,char * buf,size_t size)19 static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
20                                   size_t size)
21 {
22     struct fuse_chan *ch = *chp;
23     int err;
24     ssize_t res;
25     struct fuse_session *se = fuse_chan_session(ch);
26     assert(se != NULL);
27 
28  restart:
29     res = read(fuse_chan_fd(ch), buf, size);
30     err = errno;
31 
32     if (fuse_session_exited(se))
33         return 0;
34     if (res == -1) {
35         /* ENOENT means the operation was interrupted, it's safe
36            to restart */
37         if (err == ENOENT)
38             goto restart;
39 
40         if (err == ENODEV) {
41             fuse_session_exit(se);
42             return 0;
43         }
44         /* Errors occuring during normal operation: EINTR (read
45            interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
46            umounted) */
47         if (err != EINTR && err != EAGAIN)
48             perror("fuse: reading device");
49         return -err;
50     }
51     if ((size_t) res < sizeof(struct fuse_in_header)) {
52         fprintf(stderr, "short read on fuse device\n");
53         return -EIO;
54     }
55     return res;
56 }
57 
fuse_kern_chan_send(struct fuse_chan * ch,const struct iovec iov[],size_t count)58 static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
59                                size_t count)
60 {
61     if (iov) {
62         ssize_t res = writev(fuse_chan_fd(ch), iov, count);
63         int err = errno;
64 
65         if (res == -1) {
66             struct fuse_session *se = fuse_chan_session(ch);
67 
68             assert(se != NULL);
69 
70             /* ENOENT means the operation was interrupted */
71             if (!fuse_session_exited(se) && err != ENOENT)
72                 perror("fuse: writing device");
73             return -err;
74         }
75     }
76     return 0;
77 }
78 
fuse_kern_chan_destroy(struct fuse_chan * ch)79 static void fuse_kern_chan_destroy(struct fuse_chan *ch)
80 {
81     close(fuse_chan_fd(ch));
82 }
83 
84 #define MIN_BUFSIZE 0x21000
85 
fuse_kern_chan_new(int fd)86 struct fuse_chan *fuse_kern_chan_new(int fd)
87 {
88     struct fuse_chan_ops op = {
89         .receive = fuse_kern_chan_receive,
90         .send = fuse_kern_chan_send,
91         .destroy = fuse_kern_chan_destroy,
92     };
93     size_t bufsize = getpagesize() + 0x1000;
94     bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
95     return fuse_chan_new(&op, fd, bufsize, NULL);
96 }
97