diff options
Diffstat (limited to 'lib/fuse_lowlevel.c')
-rw-r--r-- | lib/fuse_lowlevel.c | 84 |
1 files changed, 75 insertions, 9 deletions
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 7d76309..8fe47db 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -186,8 +186,15 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch, } } - ssize_t res = writev(ch ? ch->fd : se->fd, - iov, count); + ssize_t res; + if (se->io != NULL) + /* se->io->writev is never NULL if se->io is not NULL as + specified by fuse_session_custom_io()*/ + res = se->io->writev(ch ? ch->fd : se->fd, iov, count, + se->userdata); + else + res = writev(ch ? ch->fd : se->fd, iov, count); + int err = errno; if (res == -1) { @@ -817,8 +824,14 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, (se->conn.want & FUSE_CAP_SPLICE_MOVE)) splice_flags |= SPLICE_F_MOVE; - res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, - NULL, out->len, splice_flags); + if (se->io != NULL && se->io->splice_send != NULL) { + res = se->io->splice_send(llp->pipe[0], NULL, + ch ? ch->fd : se->fd, NULL, out->len, + splice_flags, se->userdata); + } else { + res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL, + out->len, splice_flags); + } if (res == -1) { res = -errno; perror("fuse: splice from pipe"); @@ -2000,9 +2013,13 @@ void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) if (se->conn.proto_minor >= 14) { #ifdef HAVE_SPLICE #ifdef HAVE_VMSPLICE - se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; + if ((se->io == NULL) || (se->io->splice_send != NULL)) { + se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE; + } #endif - se->conn.capable |= FUSE_CAP_SPLICE_READ; + if ((se->io == NULL) || (se->io->splice_receive != NULL)) { + se->conn.capable |= FUSE_CAP_SPLICE_READ; + } #endif } if (se->conn.proto_minor >= 18) @@ -2755,6 +2772,8 @@ void fuse_session_destroy(struct fuse_session *se) free(se->cuse_data); if (se->fd != -1) close(se->fd); + if (se->io != NULL) + free(se->io); destroy_mount_opts(se->mo); free(se); } @@ -2804,8 +2823,14 @@ int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf, goto fallback; } - res = splice(ch ? ch->fd : se->fd, - NULL, llp->pipe[1], NULL, bufsize, 0); + if (se->io != NULL && se->io->splice_receive != NULL) { + res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL, + llp->pipe[1], NULL, bufsize, 0, + se->userdata); + } else { + res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL, + bufsize, 0); + } err = errno; if (fuse_session_exited(se)) @@ -2891,7 +2916,14 @@ fallback: } restart: - res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize); + if (se->io != NULL) { + /* se->io->read is never NULL if se->io is not NULL as + specified by fuse_session_custom_io()*/ + res = se->io->read(ch ? ch->fd : se->fd, buf->mem, se->bufsize, + se->userdata); + } else { + res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize); + } err = errno; if (fuse_session_exited(se)) @@ -3021,6 +3053,40 @@ out1: return NULL; } +int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io, + int fd) +{ + if (fd < 0) { + fuse_log(FUSE_LOG_ERR, "Invalid file descriptor value %d passed to " + "fuse_session_custom_io()\n", fd); + return -EBADF; + } + if (io == NULL) { + fuse_log(FUSE_LOG_ERR, "No custom IO passed to " + "fuse_session_custom_io()\n"); + return -EINVAL; + } else if (io->read == NULL || io->writev == NULL) { + /* If the user provides their own file descriptor, we can't + guarantee that the default behavior of the io operations made + in libfuse will function properly. Therefore, we enforce the + user to implement these io operations when using custom io. */ + fuse_log(FUSE_LOG_ERR, "io passed to fuse_session_custom_io() must " + "implement both io->read() and io->writev\n"); + return -EINVAL; + } + + se->io = malloc(sizeof(struct fuse_custom_io)); + if (se->io == NULL) { + fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for custom io. " + "Error: %s\n", strerror(errno)); + return -errno; + } + + se->fd = fd; + *se->io = *io; + return 0; +} + int fuse_session_mount(struct fuse_session *se, const char *mountpoint) { int fd; |