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