1987da915Sopenharmony_ci/* 2987da915Sopenharmony_ci FUSE: Filesystem in Userspace 3987da915Sopenharmony_ci Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu> 4987da915Sopenharmony_ci 5987da915Sopenharmony_ci This program can be distributed under the terms of the GNU LGPLv2. 6987da915Sopenharmony_ci See the file COPYING.LIB 7987da915Sopenharmony_ci*/ 8987da915Sopenharmony_ci 9987da915Sopenharmony_ci#include "config.h" 10987da915Sopenharmony_ci#include "fuse_lowlevel.h" 11987da915Sopenharmony_ci#include "fuse_kernel.h" 12987da915Sopenharmony_ci#include "fuse_i.h" 13987da915Sopenharmony_ci 14987da915Sopenharmony_ci#include <stdio.h> 15987da915Sopenharmony_ci#include <errno.h> 16987da915Sopenharmony_ci#include <unistd.h> 17987da915Sopenharmony_ci#include <assert.h> 18987da915Sopenharmony_ci 19987da915Sopenharmony_cistatic int fuse_kern_chan_receive(struct fuse_chan **chp, char *buf, 20987da915Sopenharmony_ci size_t size) 21987da915Sopenharmony_ci{ 22987da915Sopenharmony_ci struct fuse_chan *ch = *chp; 23987da915Sopenharmony_ci int err; 24987da915Sopenharmony_ci ssize_t res; 25987da915Sopenharmony_ci struct fuse_session *se = fuse_chan_session(ch); 26987da915Sopenharmony_ci assert(se != NULL); 27987da915Sopenharmony_ci 28987da915Sopenharmony_ci restart: 29987da915Sopenharmony_ci res = read(fuse_chan_fd(ch), buf, size); 30987da915Sopenharmony_ci err = errno; 31987da915Sopenharmony_ci 32987da915Sopenharmony_ci if (fuse_session_exited(se)) 33987da915Sopenharmony_ci return 0; 34987da915Sopenharmony_ci if (res == -1) { 35987da915Sopenharmony_ci /* ENOENT means the operation was interrupted, it's safe 36987da915Sopenharmony_ci to restart */ 37987da915Sopenharmony_ci if (err == ENOENT) 38987da915Sopenharmony_ci goto restart; 39987da915Sopenharmony_ci 40987da915Sopenharmony_ci if (err == ENODEV) { 41987da915Sopenharmony_ci fuse_session_exit(se); 42987da915Sopenharmony_ci return 0; 43987da915Sopenharmony_ci } 44987da915Sopenharmony_ci /* Errors occuring during normal operation: EINTR (read 45987da915Sopenharmony_ci interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem 46987da915Sopenharmony_ci umounted) */ 47987da915Sopenharmony_ci if (err != EINTR && err != EAGAIN) 48987da915Sopenharmony_ci perror("fuse: reading device"); 49987da915Sopenharmony_ci return -err; 50987da915Sopenharmony_ci } 51987da915Sopenharmony_ci if ((size_t) res < sizeof(struct fuse_in_header)) { 52987da915Sopenharmony_ci fprintf(stderr, "short read on fuse device\n"); 53987da915Sopenharmony_ci return -EIO; 54987da915Sopenharmony_ci } 55987da915Sopenharmony_ci return res; 56987da915Sopenharmony_ci} 57987da915Sopenharmony_ci 58987da915Sopenharmony_cistatic int fuse_kern_chan_send(struct fuse_chan *ch, const struct iovec iov[], 59987da915Sopenharmony_ci size_t count) 60987da915Sopenharmony_ci{ 61987da915Sopenharmony_ci if (iov) { 62987da915Sopenharmony_ci ssize_t res = writev(fuse_chan_fd(ch), iov, count); 63987da915Sopenharmony_ci int err = errno; 64987da915Sopenharmony_ci 65987da915Sopenharmony_ci if (res == -1) { 66987da915Sopenharmony_ci struct fuse_session *se = fuse_chan_session(ch); 67987da915Sopenharmony_ci 68987da915Sopenharmony_ci assert(se != NULL); 69987da915Sopenharmony_ci 70987da915Sopenharmony_ci /* ENOENT means the operation was interrupted */ 71987da915Sopenharmony_ci if (!fuse_session_exited(se) && err != ENOENT) 72987da915Sopenharmony_ci perror("fuse: writing device"); 73987da915Sopenharmony_ci return -err; 74987da915Sopenharmony_ci } 75987da915Sopenharmony_ci } 76987da915Sopenharmony_ci return 0; 77987da915Sopenharmony_ci} 78987da915Sopenharmony_ci 79987da915Sopenharmony_cistatic void fuse_kern_chan_destroy(struct fuse_chan *ch) 80987da915Sopenharmony_ci{ 81987da915Sopenharmony_ci close(fuse_chan_fd(ch)); 82987da915Sopenharmony_ci} 83987da915Sopenharmony_ci 84987da915Sopenharmony_ci#define MIN_BUFSIZE 0x21000 85987da915Sopenharmony_ci 86987da915Sopenharmony_cistruct fuse_chan *fuse_kern_chan_new(int fd) 87987da915Sopenharmony_ci{ 88987da915Sopenharmony_ci struct fuse_chan_ops op = { 89987da915Sopenharmony_ci .receive = fuse_kern_chan_receive, 90987da915Sopenharmony_ci .send = fuse_kern_chan_send, 91987da915Sopenharmony_ci .destroy = fuse_kern_chan_destroy, 92987da915Sopenharmony_ci }; 93987da915Sopenharmony_ci size_t bufsize = getpagesize() + 0x1000; 94987da915Sopenharmony_ci bufsize = bufsize < MIN_BUFSIZE ? MIN_BUFSIZE : bufsize; 95987da915Sopenharmony_ci return fuse_chan_new(&op, fd, bufsize, NULL); 96987da915Sopenharmony_ci} 97