blob: 4a9beb8f8dfe5b94d6cdb1c8d7db8509d2ddc090 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
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 "fuse_lowlevel.h"
10#include "fuse_kernel.h"
11#include "fuse_i.h"
12
13#include <stdio.h>
14#include <errno.h>
15#include <unistd.h>
16#include <assert.h>
17
18static int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf,
19 size_t size)
20{
21 struct fuse_chan *ch = *chp;
22 int err;
23 ssize_t res;
24 struct fuse_session *se = fuse_chan_session(ch);
25 assert(se != NULL);
26
27restart:
28 res = read(fuse_chan_fd(ch), buf, size);
29 err = errno;
30
31 if (fuse_session_exited(se))
32 return 0;
33 if (res == -1) {
34 /* ENOENT means the operation was interrupted, it's safe
35 to restart */
36 if (err == ENOENT)
37 goto restart;
38
39 if (err == ENODEV) {
40 fuse_session_exit(se);
41 return 0;
42 }
Dees_Troye34c1332013-02-06 19:13:00 +000043 /* Errors occurring during normal operation: EINTR (read
bigbiff bigbiff9c754052013-01-09 09:09:08 -050044 interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
45 umounted) */
46 if (err != EINTR && err != EAGAIN)
47 perror("fuse: reading device");
48 return -err;
49 }
50 if ((size_t) res < sizeof(struct fuse_in_header)) {
51 fprintf(stderr, "short read on fuse device\n");
52 return -EIO;
53 }
54 return res;
55}
56
57static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
58 size_t count)
59{
60 if (iov) {
61 ssize_t res = writev(fuse_chan_fd(ch), iov, count);
62 int err = errno;
63
64 if (res == -1) {
65 struct fuse_session *se = fuse_chan_session(ch);
66
67 assert(se != NULL);
68
69 /* ENOENT means the operation was interrupted */
70 if (!fuse_session_exited(se) && err != ENOENT)
71 perror("fuse: writing device");
72 return -err;
73 }
74 }
75 return 0;
76}
77
78static void fuse_kern_chan_destroy(struct fuse_chan *ch)
79{
Matt Mower523a0592015-12-13 11:31:00 -060080 int fd = fuse_chan_fd(ch);
81
82 if (fd != -1)
83 close(fd);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050084}
85
86#define MIN_BUFSIZE 0x21000
87
88struct fuse_chan *fuse_kern_chan_new(int fd)
89{
90 struct fuse_chan_ops op = {
91 .receive = fuse_kern_chan_receive,
92 .send = fuse_kern_chan_send,
93 .destroy = fuse_kern_chan_destroy,
94 };
95 size_t bufsize = getpagesize() + 0x1000;
96 bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize;
97 return fuse_chan_new(&op, fd, bufsize, NULL);
98}