diff options
Diffstat (limited to 'lib/fuse_kern_chan.c')
-rw-r--r-- | lib/fuse_kern_chan.c | 73 |
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); +} |