aboutsummaryrefslogtreecommitdiffstats
path: root/lib/fuse_kern_chan.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuse_kern_chan.c')
-rw-r--r--lib/fuse_kern_chan.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/lib/fuse_kern_chan.c b/lib/fuse_kern_chan.c
new file mode 100644
index 0000000..577d2e5
--- /dev/null
+++ b/lib/fuse_kern_chan.c
@@ -0,0 +1,73 @@
+/*
+ FUSE: Filesystem in Userspace
+ Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
+
+ This program can be distributed under the terms of the GNU LGPL.
+ See the file COPYING.LIB
+*/
+
+#include "fuse_lowlevel.h"
+#include "fuse_kernel.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+
+static int fuse_kern_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
+{
+ ssize_t res = read(fuse_chan_fd(ch), buf, size);
+ struct fuse_session *se = fuse_chan_session(ch);
+
+ assert(se != NULL);
+ if (fuse_session_exited(se))
+ return 0;
+ if (res == -1) {
+ /* EINTR means, the read() was interrupted, ENOENT means the
+ operation was interrupted */
+ if (errno == EINTR || errno == ENOENT)
+ return 0;
+ /* ENODEV means we got unmounted, so we silenty return failure */
+ if (errno != ENODEV)
+ perror("fuse: reading device");
+ return -1;
+ }
+ if ((size_t) res < sizeof(struct fuse_in_header)) {
+ fprintf(stderr, "short read on fuse device\n");
+ return -1;
+ }
+ return res;
+}
+
+static int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[],
+ size_t count)
+{
+ ssize_t res = writev(fuse_chan_fd(ch), iov, count);
+
+ if (res == -1) {
+ struct fuse_session *se = fuse_chan_session(ch);
+
+ assert(se != NULL);
+
+ /* ENOENT means the operation was interrupted */
+ if (!fuse_session_exited(se) && errno != ENOENT)
+ perror("fuse: writing device");
+ return -errno;
+ }
+ return 0;
+}
+
+static void fuse_kern_chan_destroy(struct fuse_chan *ch)
+{
+ close(fuse_chan_fd(ch));
+}
+
+struct fuse_chan *fuse_kern_chan_new(int fd)
+{
+ struct fuse_chan_ops op = {
+ .receive = fuse_kern_chan_receive,
+ .send = fuse_kern_chan_send,
+ .destroy = fuse_kern_chan_destroy,
+ };
+ return fuse_chan_new(&op, fd, FUSE_MAX_IN, NULL);
+}