qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

fuse_lowlevel.c (74564B)


      1 /*
      2  * FUSE: Filesystem in Userspace
      3  * Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
      4  *
      5  * Implementation of (most of) the low-level FUSE API. The session loop
      6  * functions are implemented in separate files.
      7  *
      8  * This program can be distributed under the terms of the GNU LGPLv2.
      9  * See the file COPYING.LIB
     10  */
     11 
     12 #include "qemu/osdep.h"
     13 #include "fuse_i.h"
     14 #include "standard-headers/linux/fuse.h"
     15 #include "fuse_misc.h"
     16 #include "fuse_opt.h"
     17 #include "fuse_virtio.h"
     18 
     19 #include <sys/file.h>
     20 
     21 #define THREAD_POOL_SIZE 0
     22 
     23 #define OFFSET_MAX 0x7fffffffffffffffLL
     24 
     25 struct fuse_pollhandle {
     26     uint64_t kh;
     27     struct fuse_session *se;
     28 };
     29 
     30 static size_t pagesize;
     31 
     32 static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
     33 {
     34     pagesize = getpagesize();
     35 }
     36 
     37 static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
     38 {
     39     *attr = (struct fuse_attr){
     40         .ino = stbuf->st_ino,
     41         .mode = stbuf->st_mode,
     42         .nlink = stbuf->st_nlink,
     43         .uid = stbuf->st_uid,
     44         .gid = stbuf->st_gid,
     45         .rdev = stbuf->st_rdev,
     46         .size = stbuf->st_size,
     47         .blksize = stbuf->st_blksize,
     48         .blocks = stbuf->st_blocks,
     49         .atime = stbuf->st_atime,
     50         .mtime = stbuf->st_mtime,
     51         .ctime = stbuf->st_ctime,
     52         .atimensec = ST_ATIM_NSEC(stbuf),
     53         .mtimensec = ST_MTIM_NSEC(stbuf),
     54         .ctimensec = ST_CTIM_NSEC(stbuf),
     55     };
     56 }
     57 
     58 static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
     59 {
     60     stbuf->st_mode = attr->mode;
     61     stbuf->st_uid = attr->uid;
     62     stbuf->st_gid = attr->gid;
     63     stbuf->st_size = attr->size;
     64     stbuf->st_atime = attr->atime;
     65     stbuf->st_mtime = attr->mtime;
     66     stbuf->st_ctime = attr->ctime;
     67     ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
     68     ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
     69     ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
     70 }
     71 
     72 static size_t iov_length(const struct iovec *iov, size_t count)
     73 {
     74     size_t seg;
     75     size_t ret = 0;
     76 
     77     for (seg = 0; seg < count; seg++) {
     78         ret += iov[seg].iov_len;
     79     }
     80     return ret;
     81 }
     82 
     83 static void list_init_req(struct fuse_req *req)
     84 {
     85     req->next = req;
     86     req->prev = req;
     87 }
     88 
     89 static void list_del_req(struct fuse_req *req)
     90 {
     91     struct fuse_req *prev = req->prev;
     92     struct fuse_req *next = req->next;
     93     prev->next = next;
     94     next->prev = prev;
     95 }
     96 
     97 static void list_add_req(struct fuse_req *req, struct fuse_req *next)
     98 {
     99     struct fuse_req *prev = next->prev;
    100     req->next = next;
    101     req->prev = prev;
    102     prev->next = req;
    103     next->prev = req;
    104 }
    105 
    106 static void destroy_req(fuse_req_t req)
    107 {
    108     pthread_mutex_destroy(&req->lock);
    109     g_free(req);
    110 }
    111 
    112 void fuse_free_req(fuse_req_t req)
    113 {
    114     int ctr;
    115     struct fuse_session *se = req->se;
    116 
    117     pthread_mutex_lock(&se->lock);
    118     req->u.ni.func = NULL;
    119     req->u.ni.data = NULL;
    120     list_del_req(req);
    121     ctr = --req->ctr;
    122     req->ch = NULL;
    123     pthread_mutex_unlock(&se->lock);
    124     if (!ctr) {
    125         destroy_req(req);
    126     }
    127 }
    128 
    129 static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
    130 {
    131     struct fuse_req *req;
    132 
    133     req = g_try_new0(struct fuse_req, 1);
    134     if (req == NULL) {
    135         fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
    136     } else {
    137         req->se = se;
    138         req->ctr = 1;
    139         list_init_req(req);
    140         fuse_mutex_init(&req->lock);
    141     }
    142 
    143     return req;
    144 }
    145 
    146 /* Send data. If *ch* is NULL, send via session master fd */
    147 static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
    148                          struct iovec *iov, int count)
    149 {
    150     struct fuse_out_header *out = iov[0].iov_base;
    151 
    152     out->len = iov_length(iov, count);
    153     if (out->unique == 0) {
    154         fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n", out->error,
    155                  out->len);
    156     } else if (out->error) {
    157         fuse_log(FUSE_LOG_DEBUG,
    158                  "   unique: %llu, error: %i (%s), outsize: %i\n",
    159                  (unsigned long long)out->unique, out->error,
    160                  strerror(-out->error), out->len);
    161     } else {
    162         fuse_log(FUSE_LOG_DEBUG, "   unique: %llu, success, outsize: %i\n",
    163                  (unsigned long long)out->unique, out->len);
    164     }
    165 
    166     if (fuse_lowlevel_is_virtio(se)) {
    167         return virtio_send_msg(se, ch, iov, count);
    168     }
    169 
    170     abort(); /* virtio should have taken it before here */
    171     return 0;
    172 }
    173 
    174 
    175 int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
    176                                int count)
    177 {
    178     struct fuse_out_header out = {
    179         .unique = req->unique,
    180         .error = error,
    181     };
    182 
    183     if (error <= -1000 || error > 0) {
    184         fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
    185         out.error = -ERANGE;
    186     }
    187 
    188     iov[0].iov_base = &out;
    189     iov[0].iov_len = sizeof(struct fuse_out_header);
    190 
    191     return fuse_send_msg(req->se, req->ch, iov, count);
    192 }
    193 
    194 static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
    195                           int count)
    196 {
    197     int res;
    198 
    199     res = fuse_send_reply_iov_nofree(req, error, iov, count);
    200     fuse_free_req(req);
    201     return res;
    202 }
    203 
    204 static int send_reply(fuse_req_t req, int error, const void *arg,
    205                       size_t argsize)
    206 {
    207     struct iovec iov[2];
    208     int count = 1;
    209     if (argsize) {
    210         iov[1].iov_base = (void *)arg;
    211         iov[1].iov_len = argsize;
    212         count++;
    213     }
    214     return send_reply_iov(req, error, iov, count);
    215 }
    216 
    217 int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
    218 {
    219     int res;
    220     g_autofree struct iovec *padded_iov = NULL;
    221 
    222     padded_iov = g_try_new(struct iovec, count + 1);
    223     if (padded_iov == NULL) {
    224         return fuse_reply_err(req, ENOMEM);
    225     }
    226 
    227     memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
    228     count++;
    229 
    230     res = send_reply_iov(req, 0, padded_iov, count);
    231 
    232     return res;
    233 }
    234 
    235 
    236 /*
    237  * 'buf` is allowed to be empty so that the proper size may be
    238  * allocated by the caller
    239  */
    240 size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
    241                          const char *name, const struct stat *stbuf, off_t off)
    242 {
    243     (void)req;
    244     size_t namelen;
    245     size_t entlen;
    246     size_t entlen_padded;
    247     struct fuse_dirent *dirent;
    248 
    249     namelen = strlen(name);
    250     entlen = FUSE_NAME_OFFSET + namelen;
    251     entlen_padded = FUSE_DIRENT_ALIGN(entlen);
    252 
    253     if ((buf == NULL) || (entlen_padded > bufsize)) {
    254         return entlen_padded;
    255     }
    256 
    257     dirent = (struct fuse_dirent *)buf;
    258     dirent->ino = stbuf->st_ino;
    259     dirent->off = off;
    260     dirent->namelen = namelen;
    261     dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
    262     memcpy(dirent->name, name, namelen);
    263     memset(dirent->name + namelen, 0, entlen_padded - entlen);
    264 
    265     return entlen_padded;
    266 }
    267 
    268 static void convert_statfs(const struct statvfs *stbuf,
    269                            struct fuse_kstatfs *kstatfs)
    270 {
    271     *kstatfs = (struct fuse_kstatfs){
    272         .bsize = stbuf->f_bsize,
    273         .frsize = stbuf->f_frsize,
    274         .blocks = stbuf->f_blocks,
    275         .bfree = stbuf->f_bfree,
    276         .bavail = stbuf->f_bavail,
    277         .files = stbuf->f_files,
    278         .ffree = stbuf->f_ffree,
    279         .namelen = stbuf->f_namemax,
    280     };
    281 }
    282 
    283 static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
    284 {
    285     return send_reply(req, 0, arg, argsize);
    286 }
    287 
    288 int fuse_reply_err(fuse_req_t req, int err)
    289 {
    290     return send_reply(req, -err, NULL, 0);
    291 }
    292 
    293 void fuse_reply_none(fuse_req_t req)
    294 {
    295     fuse_free_req(req);
    296 }
    297 
    298 static unsigned long calc_timeout_sec(double t)
    299 {
    300     if (t > (double)ULONG_MAX) {
    301         return ULONG_MAX;
    302     } else if (t < 0.0) {
    303         return 0;
    304     } else {
    305         return (unsigned long)t;
    306     }
    307 }
    308 
    309 static unsigned int calc_timeout_nsec(double t)
    310 {
    311     double f = t - (double)calc_timeout_sec(t);
    312     if (f < 0.0) {
    313         return 0;
    314     } else if (f >= 0.999999999) {
    315         return 999999999;
    316     } else {
    317         return (unsigned int)(f * 1.0e9);
    318     }
    319 }
    320 
    321 static void fill_entry(struct fuse_entry_out *arg,
    322                        const struct fuse_entry_param *e)
    323 {
    324     *arg = (struct fuse_entry_out){
    325         .nodeid = e->ino,
    326         .generation = e->generation,
    327         .entry_valid = calc_timeout_sec(e->entry_timeout),
    328         .entry_valid_nsec = calc_timeout_nsec(e->entry_timeout),
    329         .attr_valid = calc_timeout_sec(e->attr_timeout),
    330         .attr_valid_nsec = calc_timeout_nsec(e->attr_timeout),
    331     };
    332     convert_stat(&e->attr, &arg->attr);
    333 
    334     arg->attr.flags = e->attr_flags;
    335 }
    336 
    337 /*
    338  * `buf` is allowed to be empty so that the proper size may be
    339  * allocated by the caller
    340  */
    341 size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
    342                               const char *name,
    343                               const struct fuse_entry_param *e, off_t off)
    344 {
    345     (void)req;
    346     size_t namelen;
    347     size_t entlen;
    348     size_t entlen_padded;
    349 
    350     namelen = strlen(name);
    351     entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
    352     entlen_padded = FUSE_DIRENT_ALIGN(entlen);
    353     if ((buf == NULL) || (entlen_padded > bufsize)) {
    354         return entlen_padded;
    355     }
    356 
    357     struct fuse_direntplus *dp = (struct fuse_direntplus *)buf;
    358     memset(&dp->entry_out, 0, sizeof(dp->entry_out));
    359     fill_entry(&dp->entry_out, e);
    360 
    361     struct fuse_dirent *dirent = &dp->dirent;
    362     *dirent = (struct fuse_dirent){
    363         .ino = e->attr.st_ino,
    364         .off = off,
    365         .namelen = namelen,
    366         .type = (e->attr.st_mode & S_IFMT) >> 12,
    367     };
    368     memcpy(dirent->name, name, namelen);
    369     memset(dirent->name + namelen, 0, entlen_padded - entlen);
    370 
    371     return entlen_padded;
    372 }
    373 
    374 static void fill_open(struct fuse_open_out *arg, const struct fuse_file_info *f)
    375 {
    376     arg->fh = f->fh;
    377     if (f->direct_io) {
    378         arg->open_flags |= FOPEN_DIRECT_IO;
    379     }
    380     if (f->keep_cache) {
    381         arg->open_flags |= FOPEN_KEEP_CACHE;
    382     }
    383     if (f->cache_readdir) {
    384         arg->open_flags |= FOPEN_CACHE_DIR;
    385     }
    386     if (f->nonseekable) {
    387         arg->open_flags |= FOPEN_NONSEEKABLE;
    388     }
    389 }
    390 
    391 int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
    392 {
    393     struct fuse_entry_out arg;
    394     size_t size = sizeof(arg);
    395 
    396     memset(&arg, 0, sizeof(arg));
    397     fill_entry(&arg, e);
    398     return send_reply_ok(req, &arg, size);
    399 }
    400 
    401 int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
    402                       const struct fuse_file_info *f)
    403 {
    404     char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
    405     size_t entrysize = sizeof(struct fuse_entry_out);
    406     struct fuse_entry_out *earg = (struct fuse_entry_out *)buf;
    407     struct fuse_open_out *oarg = (struct fuse_open_out *)(buf + entrysize);
    408 
    409     memset(buf, 0, sizeof(buf));
    410     fill_entry(earg, e);
    411     fill_open(oarg, f);
    412     return send_reply_ok(req, buf, entrysize + sizeof(struct fuse_open_out));
    413 }
    414 
    415 int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
    416                     double attr_timeout)
    417 {
    418     struct fuse_attr_out arg;
    419     size_t size = sizeof(arg);
    420 
    421     memset(&arg, 0, sizeof(arg));
    422     arg.attr_valid = calc_timeout_sec(attr_timeout);
    423     arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
    424     convert_stat(attr, &arg.attr);
    425 
    426     return send_reply_ok(req, &arg, size);
    427 }
    428 
    429 int fuse_reply_readlink(fuse_req_t req, const char *linkname)
    430 {
    431     return send_reply_ok(req, linkname, strlen(linkname));
    432 }
    433 
    434 int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
    435 {
    436     struct fuse_open_out arg;
    437 
    438     memset(&arg, 0, sizeof(arg));
    439     fill_open(&arg, f);
    440     return send_reply_ok(req, &arg, sizeof(arg));
    441 }
    442 
    443 int fuse_reply_write(fuse_req_t req, size_t count)
    444 {
    445     struct fuse_write_out arg;
    446 
    447     memset(&arg, 0, sizeof(arg));
    448     arg.size = count;
    449 
    450     return send_reply_ok(req, &arg, sizeof(arg));
    451 }
    452 
    453 int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
    454 {
    455     return send_reply_ok(req, buf, size);
    456 }
    457 
    458 static int fuse_send_data_iov_fallback(struct fuse_session *se,
    459                                        struct fuse_chan *ch, struct iovec *iov,
    460                                        int iov_count, struct fuse_bufvec *buf,
    461                                        size_t len)
    462 {
    463     /* Optimize common case */
    464     if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
    465         !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
    466         /*
    467          * FIXME: also avoid memory copy if there are multiple buffers
    468          * but none of them contain an fd
    469          */
    470 
    471         iov[iov_count].iov_base = buf->buf[0].mem;
    472         iov[iov_count].iov_len = len;
    473         iov_count++;
    474         return fuse_send_msg(se, ch, iov, iov_count);
    475     }
    476 
    477     if (fuse_lowlevel_is_virtio(se) && buf->count == 1 &&
    478         buf->buf[0].flags == (FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK)) {
    479         return virtio_send_data_iov(se, ch, iov, iov_count, buf, len);
    480     }
    481 
    482     abort(); /* Will have taken vhost path */
    483     return 0;
    484 }
    485 
    486 static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
    487                               struct iovec *iov, int iov_count,
    488                               struct fuse_bufvec *buf)
    489 {
    490     size_t len = fuse_buf_size(buf);
    491 
    492     return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
    493 }
    494 
    495 int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv)
    496 {
    497     struct iovec iov[2];
    498     struct fuse_out_header out = {
    499         .unique = req->unique,
    500     };
    501     int res;
    502 
    503     iov[0].iov_base = &out;
    504     iov[0].iov_len = sizeof(struct fuse_out_header);
    505 
    506     res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv);
    507     if (res <= 0) {
    508         fuse_free_req(req);
    509         return res;
    510     } else {
    511         return fuse_reply_err(req, res);
    512     }
    513 }
    514 
    515 int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
    516 {
    517     struct fuse_statfs_out arg;
    518     size_t size = sizeof(arg);
    519 
    520     memset(&arg, 0, sizeof(arg));
    521     convert_statfs(stbuf, &arg.st);
    522 
    523     return send_reply_ok(req, &arg, size);
    524 }
    525 
    526 int fuse_reply_xattr(fuse_req_t req, size_t count)
    527 {
    528     struct fuse_getxattr_out arg;
    529 
    530     memset(&arg, 0, sizeof(arg));
    531     arg.size = count;
    532 
    533     return send_reply_ok(req, &arg, sizeof(arg));
    534 }
    535 
    536 int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
    537 {
    538     struct fuse_lk_out arg;
    539 
    540     memset(&arg, 0, sizeof(arg));
    541     arg.lk.type = lock->l_type;
    542     if (lock->l_type != F_UNLCK) {
    543         arg.lk.start = lock->l_start;
    544         if (lock->l_len == 0) {
    545             arg.lk.end = OFFSET_MAX;
    546         } else {
    547             arg.lk.end = lock->l_start + lock->l_len - 1;
    548         }
    549     }
    550     arg.lk.pid = lock->l_pid;
    551     return send_reply_ok(req, &arg, sizeof(arg));
    552 }
    553 
    554 int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
    555 {
    556     struct fuse_bmap_out arg;
    557 
    558     memset(&arg, 0, sizeof(arg));
    559     arg.block = idx;
    560 
    561     return send_reply_ok(req, &arg, sizeof(arg));
    562 }
    563 
    564 static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
    565                                                       size_t count)
    566 {
    567     struct fuse_ioctl_iovec *fiov;
    568     size_t i;
    569 
    570     fiov = g_try_new(struct fuse_ioctl_iovec, count);
    571     if (!fiov) {
    572         return NULL;
    573     }
    574 
    575     for (i = 0; i < count; i++) {
    576         fiov[i].base = (uintptr_t)iov[i].iov_base;
    577         fiov[i].len = iov[i].iov_len;
    578     }
    579 
    580     return fiov;
    581 }
    582 
    583 int fuse_reply_ioctl_retry(fuse_req_t req, const struct iovec *in_iov,
    584                            size_t in_count, const struct iovec *out_iov,
    585                            size_t out_count)
    586 {
    587     struct fuse_ioctl_out arg;
    588     g_autofree struct fuse_ioctl_iovec *in_fiov = NULL;
    589     g_autofree struct fuse_ioctl_iovec *out_fiov = NULL;
    590     struct iovec iov[4];
    591     size_t count = 1;
    592     int res;
    593 
    594     memset(&arg, 0, sizeof(arg));
    595     arg.flags |= FUSE_IOCTL_RETRY;
    596     arg.in_iovs = in_count;
    597     arg.out_iovs = out_count;
    598     iov[count].iov_base = &arg;
    599     iov[count].iov_len = sizeof(arg);
    600     count++;
    601 
    602     /* Can't handle non-compat 64bit ioctls on 32bit */
    603     if (sizeof(void *) == 4 && req->ioctl_64bit) {
    604         res = fuse_reply_err(req, EINVAL);
    605         return res;
    606     }
    607 
    608     if (in_count) {
    609         in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
    610         if (!in_fiov) {
    611             res = fuse_reply_err(req, ENOMEM);
    612             return res;
    613         }
    614 
    615         iov[count].iov_base = (void *)in_fiov;
    616         iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
    617         count++;
    618     }
    619     if (out_count) {
    620         out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
    621         if (!out_fiov) {
    622             res = fuse_reply_err(req, ENOMEM);
    623             return res;
    624         }
    625 
    626         iov[count].iov_base = (void *)out_fiov;
    627         iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
    628         count++;
    629     }
    630 
    631     res = send_reply_iov(req, 0, iov, count);
    632 
    633     return res;
    634 }
    635 
    636 int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
    637 {
    638     struct fuse_ioctl_out arg;
    639     struct iovec iov[3];
    640     size_t count = 1;
    641 
    642     memset(&arg, 0, sizeof(arg));
    643     arg.result = result;
    644     iov[count].iov_base = &arg;
    645     iov[count].iov_len = sizeof(arg);
    646     count++;
    647 
    648     if (size) {
    649         iov[count].iov_base = (char *)buf;
    650         iov[count].iov_len = size;
    651         count++;
    652     }
    653 
    654     return send_reply_iov(req, 0, iov, count);
    655 }
    656 
    657 int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
    658                          int count)
    659 {
    660     g_autofree struct iovec *padded_iov = NULL;
    661     struct fuse_ioctl_out arg;
    662     int res;
    663 
    664     padded_iov = g_try_new(struct iovec, count + 2);
    665     if (padded_iov == NULL) {
    666         return fuse_reply_err(req, ENOMEM);
    667     }
    668 
    669     memset(&arg, 0, sizeof(arg));
    670     arg.result = result;
    671     padded_iov[1].iov_base = &arg;
    672     padded_iov[1].iov_len = sizeof(arg);
    673 
    674     memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
    675 
    676     res = send_reply_iov(req, 0, padded_iov, count + 2);
    677 
    678     return res;
    679 }
    680 
    681 int fuse_reply_poll(fuse_req_t req, unsigned revents)
    682 {
    683     struct fuse_poll_out arg;
    684 
    685     memset(&arg, 0, sizeof(arg));
    686     arg.revents = revents;
    687 
    688     return send_reply_ok(req, &arg, sizeof(arg));
    689 }
    690 
    691 int fuse_reply_lseek(fuse_req_t req, off_t off)
    692 {
    693     struct fuse_lseek_out arg;
    694 
    695     memset(&arg, 0, sizeof(arg));
    696     arg.offset = off;
    697 
    698     return send_reply_ok(req, &arg, sizeof(arg));
    699 }
    700 
    701 static void do_lookup(fuse_req_t req, fuse_ino_t nodeid,
    702                       struct fuse_mbuf_iter *iter)
    703 {
    704     const char *name = fuse_mbuf_iter_advance_str(iter);
    705     if (!name) {
    706         fuse_reply_err(req, EINVAL);
    707         return;
    708     }
    709 
    710     if (req->se->op.lookup) {
    711         req->se->op.lookup(req, nodeid, name);
    712     } else {
    713         fuse_reply_err(req, ENOSYS);
    714     }
    715 }
    716 
    717 static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
    718                       struct fuse_mbuf_iter *iter)
    719 {
    720     struct fuse_forget_in *arg;
    721 
    722     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
    723     if (!arg) {
    724         fuse_reply_err(req, EINVAL);
    725         return;
    726     }
    727 
    728     if (req->se->op.forget) {
    729         req->se->op.forget(req, nodeid, arg->nlookup);
    730     } else {
    731         fuse_reply_none(req);
    732     }
    733 }
    734 
    735 static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
    736                             struct fuse_mbuf_iter *iter)
    737 {
    738     struct fuse_batch_forget_in *arg;
    739     struct fuse_forget_data *forgets;
    740     size_t scount;
    741 
    742     (void)nodeid;
    743 
    744     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
    745     if (!arg) {
    746         fuse_reply_none(req);
    747         return;
    748     }
    749 
    750     /*
    751      * Prevent integer overflow.  The compiler emits the following warning
    752      * unless we use the scount local variable:
    753      *
    754      * error: comparison is always false due to limited range of data type
    755      * [-Werror=type-limits]
    756      *
    757      * This may be true on 64-bit hosts but we need this check for 32-bit
    758      * hosts.
    759      */
    760     scount = arg->count;
    761     if (scount > SIZE_MAX / sizeof(forgets[0])) {
    762         fuse_reply_none(req);
    763         return;
    764     }
    765 
    766     forgets = fuse_mbuf_iter_advance(iter, arg->count * sizeof(forgets[0]));
    767     if (!forgets) {
    768         fuse_reply_none(req);
    769         return;
    770     }
    771 
    772     if (req->se->op.forget_multi) {
    773         req->se->op.forget_multi(req, arg->count, forgets);
    774     } else if (req->se->op.forget) {
    775         unsigned int i;
    776 
    777         for (i = 0; i < arg->count; i++) {
    778             struct fuse_req *dummy_req;
    779 
    780             dummy_req = fuse_ll_alloc_req(req->se);
    781             if (dummy_req == NULL) {
    782                 break;
    783             }
    784 
    785             dummy_req->unique = req->unique;
    786             dummy_req->ctx = req->ctx;
    787             dummy_req->ch = NULL;
    788 
    789             req->se->op.forget(dummy_req, forgets[i].ino, forgets[i].nlookup);
    790         }
    791         fuse_reply_none(req);
    792     } else {
    793         fuse_reply_none(req);
    794     }
    795 }
    796 
    797 static void do_getattr(fuse_req_t req, fuse_ino_t nodeid,
    798                        struct fuse_mbuf_iter *iter)
    799 {
    800     struct fuse_file_info *fip = NULL;
    801     struct fuse_file_info fi;
    802 
    803     struct fuse_getattr_in *arg;
    804 
    805     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
    806     if (!arg) {
    807         fuse_reply_err(req, EINVAL);
    808         return;
    809     }
    810 
    811     if (arg->getattr_flags & FUSE_GETATTR_FH) {
    812         memset(&fi, 0, sizeof(fi));
    813         fi.fh = arg->fh;
    814         fip = &fi;
    815     }
    816 
    817     if (req->se->op.getattr) {
    818         req->se->op.getattr(req, nodeid, fip);
    819     } else {
    820         fuse_reply_err(req, ENOSYS);
    821     }
    822 }
    823 
    824 static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
    825                        struct fuse_mbuf_iter *iter)
    826 {
    827     if (req->se->op.setattr) {
    828         struct fuse_setattr_in *arg;
    829         struct fuse_file_info *fi = NULL;
    830         struct fuse_file_info fi_store;
    831         struct stat stbuf;
    832 
    833         arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
    834         if (!arg) {
    835             fuse_reply_err(req, EINVAL);
    836             return;
    837         }
    838 
    839         memset(&stbuf, 0, sizeof(stbuf));
    840         convert_attr(arg, &stbuf);
    841         if (arg->valid & FATTR_FH) {
    842             arg->valid &= ~FATTR_FH;
    843             memset(&fi_store, 0, sizeof(fi_store));
    844             fi = &fi_store;
    845             fi->fh = arg->fh;
    846         }
    847         arg->valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID |
    848                       FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE |
    849                       FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME |
    850                       FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW |
    851                       FUSE_SET_ATTR_CTIME | FUSE_SET_ATTR_KILL_SUIDGID;
    852 
    853         req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
    854     } else {
    855         fuse_reply_err(req, ENOSYS);
    856     }
    857 }
    858 
    859 static void do_access(fuse_req_t req, fuse_ino_t nodeid,
    860                       struct fuse_mbuf_iter *iter)
    861 {
    862     struct fuse_access_in *arg;
    863 
    864     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
    865     if (!arg) {
    866         fuse_reply_err(req, EINVAL);
    867         return;
    868     }
    869 
    870     if (req->se->op.access) {
    871         req->se->op.access(req, nodeid, arg->mask);
    872     } else {
    873         fuse_reply_err(req, ENOSYS);
    874     }
    875 }
    876 
    877 static void do_readlink(fuse_req_t req, fuse_ino_t nodeid,
    878                         struct fuse_mbuf_iter *iter)
    879 {
    880     (void)iter;
    881 
    882     if (req->se->op.readlink) {
    883         req->se->op.readlink(req, nodeid);
    884     } else {
    885         fuse_reply_err(req, ENOSYS);
    886     }
    887 }
    888 
    889 static int parse_secctx_fill_req(fuse_req_t req, struct fuse_mbuf_iter *iter)
    890 {
    891     struct fuse_secctx_header *fsecctx_header;
    892     struct fuse_secctx *fsecctx;
    893     const void *secctx;
    894     const char *name;
    895 
    896     fsecctx_header = fuse_mbuf_iter_advance(iter, sizeof(*fsecctx_header));
    897     if (!fsecctx_header) {
    898         return -EINVAL;
    899     }
    900 
    901     /*
    902      * As of now maximum of one security context is supported. It can
    903      * change in future though.
    904      */
    905     if (fsecctx_header->nr_secctx > 1) {
    906         return -EINVAL;
    907     }
    908 
    909     /* No security context sent. Maybe no LSM supports it */
    910     if (!fsecctx_header->nr_secctx) {
    911         return 0;
    912     }
    913 
    914     fsecctx = fuse_mbuf_iter_advance(iter, sizeof(*fsecctx));
    915     if (!fsecctx) {
    916         return -EINVAL;
    917     }
    918 
    919     /* struct fsecctx with zero sized context is not expected */
    920     if (!fsecctx->size) {
    921         return -EINVAL;
    922     }
    923     name = fuse_mbuf_iter_advance_str(iter);
    924     if (!name) {
    925         return -EINVAL;
    926     }
    927 
    928     secctx = fuse_mbuf_iter_advance(iter, fsecctx->size);
    929     if (!secctx) {
    930         return -EINVAL;
    931     }
    932 
    933     req->secctx.name = name;
    934     req->secctx.ctx = secctx;
    935     req->secctx.ctxlen = fsecctx->size;
    936     return 0;
    937 }
    938 
    939 static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
    940                      struct fuse_mbuf_iter *iter)
    941 {
    942     struct fuse_mknod_in *arg;
    943     const char *name;
    944     bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX;
    945     int err;
    946 
    947     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
    948     name = fuse_mbuf_iter_advance_str(iter);
    949     if (!arg || !name) {
    950         fuse_reply_err(req, EINVAL);
    951         return;
    952     }
    953 
    954     req->ctx.umask = arg->umask;
    955 
    956     if (secctx_enabled) {
    957         err = parse_secctx_fill_req(req, iter);
    958         if (err) {
    959             fuse_reply_err(req, -err);
    960             return;
    961         }
    962     }
    963 
    964     if (req->se->op.mknod) {
    965         req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
    966     } else {
    967         fuse_reply_err(req, ENOSYS);
    968     }
    969 }
    970 
    971 static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
    972                      struct fuse_mbuf_iter *iter)
    973 {
    974     struct fuse_mkdir_in *arg;
    975     const char *name;
    976     bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX;
    977     int err;
    978 
    979     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
    980     name = fuse_mbuf_iter_advance_str(iter);
    981     if (!arg || !name) {
    982         fuse_reply_err(req, EINVAL);
    983         return;
    984     }
    985 
    986     req->ctx.umask = arg->umask;
    987 
    988     if (secctx_enabled) {
    989         err = parse_secctx_fill_req(req, iter);
    990         if (err) {
    991             fuse_reply_err(req, err);
    992             return;
    993         }
    994     }
    995 
    996     if (req->se->op.mkdir) {
    997         req->se->op.mkdir(req, nodeid, name, arg->mode);
    998     } else {
    999         fuse_reply_err(req, ENOSYS);
   1000     }
   1001 }
   1002 
   1003 static void do_unlink(fuse_req_t req, fuse_ino_t nodeid,
   1004                       struct fuse_mbuf_iter *iter)
   1005 {
   1006     const char *name = fuse_mbuf_iter_advance_str(iter);
   1007 
   1008     if (!name) {
   1009         fuse_reply_err(req, EINVAL);
   1010         return;
   1011     }
   1012 
   1013     if (req->se->op.unlink) {
   1014         req->se->op.unlink(req, nodeid, name);
   1015     } else {
   1016         fuse_reply_err(req, ENOSYS);
   1017     }
   1018 }
   1019 
   1020 static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid,
   1021                      struct fuse_mbuf_iter *iter)
   1022 {
   1023     const char *name = fuse_mbuf_iter_advance_str(iter);
   1024 
   1025     if (!name) {
   1026         fuse_reply_err(req, EINVAL);
   1027         return;
   1028     }
   1029 
   1030     if (req->se->op.rmdir) {
   1031         req->se->op.rmdir(req, nodeid, name);
   1032     } else {
   1033         fuse_reply_err(req, ENOSYS);
   1034     }
   1035 }
   1036 
   1037 static void do_symlink(fuse_req_t req, fuse_ino_t nodeid,
   1038                        struct fuse_mbuf_iter *iter)
   1039 {
   1040     const char *name = fuse_mbuf_iter_advance_str(iter);
   1041     const char *linkname = fuse_mbuf_iter_advance_str(iter);
   1042     bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX;
   1043     int err;
   1044 
   1045     if (!name || !linkname) {
   1046         fuse_reply_err(req, EINVAL);
   1047         return;
   1048     }
   1049 
   1050     if (secctx_enabled) {
   1051         err = parse_secctx_fill_req(req, iter);
   1052         if (err) {
   1053             fuse_reply_err(req, err);
   1054             return;
   1055         }
   1056     }
   1057 
   1058     if (req->se->op.symlink) {
   1059         req->se->op.symlink(req, linkname, nodeid, name);
   1060     } else {
   1061         fuse_reply_err(req, ENOSYS);
   1062     }
   1063 }
   1064 
   1065 static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
   1066                       struct fuse_mbuf_iter *iter)
   1067 {
   1068     struct fuse_rename_in *arg;
   1069     const char *oldname;
   1070     const char *newname;
   1071 
   1072     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1073     oldname = fuse_mbuf_iter_advance_str(iter);
   1074     newname = fuse_mbuf_iter_advance_str(iter);
   1075     if (!arg || !oldname || !newname) {
   1076         fuse_reply_err(req, EINVAL);
   1077         return;
   1078     }
   1079 
   1080     if (req->se->op.rename) {
   1081         req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, 0);
   1082     } else {
   1083         fuse_reply_err(req, ENOSYS);
   1084     }
   1085 }
   1086 
   1087 static void do_rename2(fuse_req_t req, fuse_ino_t nodeid,
   1088                        struct fuse_mbuf_iter *iter)
   1089 {
   1090     struct fuse_rename2_in *arg;
   1091     const char *oldname;
   1092     const char *newname;
   1093 
   1094     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1095     oldname = fuse_mbuf_iter_advance_str(iter);
   1096     newname = fuse_mbuf_iter_advance_str(iter);
   1097     if (!arg || !oldname || !newname) {
   1098         fuse_reply_err(req, EINVAL);
   1099         return;
   1100     }
   1101 
   1102     if (req->se->op.rename) {
   1103         req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
   1104                            arg->flags);
   1105     } else {
   1106         fuse_reply_err(req, ENOSYS);
   1107     }
   1108 }
   1109 
   1110 static void do_link(fuse_req_t req, fuse_ino_t nodeid,
   1111                     struct fuse_mbuf_iter *iter)
   1112 {
   1113     struct fuse_link_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1114     const char *name = fuse_mbuf_iter_advance_str(iter);
   1115 
   1116     if (!arg || !name) {
   1117         fuse_reply_err(req, EINVAL);
   1118         return;
   1119     }
   1120 
   1121     if (req->se->op.link) {
   1122         req->se->op.link(req, arg->oldnodeid, nodeid, name);
   1123     } else {
   1124         fuse_reply_err(req, ENOSYS);
   1125     }
   1126 }
   1127 
   1128 static void do_create(fuse_req_t req, fuse_ino_t nodeid,
   1129                       struct fuse_mbuf_iter *iter)
   1130 {
   1131     bool secctx_enabled = req->se->conn.want & FUSE_CAP_SECURITY_CTX;
   1132 
   1133     if (req->se->op.create) {
   1134         struct fuse_create_in *arg;
   1135         struct fuse_file_info fi;
   1136         const char *name;
   1137 
   1138         arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1139         name = fuse_mbuf_iter_advance_str(iter);
   1140         if (!arg || !name) {
   1141             fuse_reply_err(req, EINVAL);
   1142             return;
   1143         }
   1144 
   1145         if (secctx_enabled) {
   1146             int err;
   1147             err = parse_secctx_fill_req(req, iter);
   1148             if (err) {
   1149                 fuse_reply_err(req, err);
   1150                 return;
   1151             }
   1152         }
   1153 
   1154         memset(&fi, 0, sizeof(fi));
   1155         fi.flags = arg->flags;
   1156         fi.kill_priv = arg->open_flags & FUSE_OPEN_KILL_SUIDGID;
   1157 
   1158         req->ctx.umask = arg->umask;
   1159 
   1160         req->se->op.create(req, nodeid, name, arg->mode, &fi);
   1161     } else {
   1162         fuse_reply_err(req, ENOSYS);
   1163     }
   1164 }
   1165 
   1166 static void do_open(fuse_req_t req, fuse_ino_t nodeid,
   1167                     struct fuse_mbuf_iter *iter)
   1168 {
   1169     struct fuse_open_in *arg;
   1170     struct fuse_file_info fi;
   1171 
   1172     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1173     if (!arg) {
   1174         fuse_reply_err(req, EINVAL);
   1175         return;
   1176     }
   1177 
   1178     /* File creation is handled by do_create() or do_mknod() */
   1179     if (arg->flags & (O_CREAT | O_TMPFILE)) {
   1180         fuse_reply_err(req, EINVAL);
   1181         return;
   1182     }
   1183 
   1184     memset(&fi, 0, sizeof(fi));
   1185     fi.flags = arg->flags;
   1186     fi.kill_priv = arg->open_flags & FUSE_OPEN_KILL_SUIDGID;
   1187 
   1188     if (req->se->op.open) {
   1189         req->se->op.open(req, nodeid, &fi);
   1190     } else {
   1191         fuse_reply_open(req, &fi);
   1192     }
   1193 }
   1194 
   1195 static void do_read(fuse_req_t req, fuse_ino_t nodeid,
   1196                     struct fuse_mbuf_iter *iter)
   1197 {
   1198     if (req->se->op.read) {
   1199         struct fuse_read_in *arg;
   1200         struct fuse_file_info fi;
   1201 
   1202         arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1203         if (!arg) {
   1204             fuse_reply_err(req, EINVAL);
   1205             return;
   1206         }
   1207 
   1208         memset(&fi, 0, sizeof(fi));
   1209         fi.fh = arg->fh;
   1210         fi.lock_owner = arg->lock_owner;
   1211         fi.flags = arg->flags;
   1212         req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
   1213     } else {
   1214         fuse_reply_err(req, ENOSYS);
   1215     }
   1216 }
   1217 
   1218 static void do_write(fuse_req_t req, fuse_ino_t nodeid,
   1219                      struct fuse_mbuf_iter *iter)
   1220 {
   1221     struct fuse_write_in *arg;
   1222     struct fuse_file_info fi;
   1223     const char *param;
   1224 
   1225     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1226     if (!arg) {
   1227         fuse_reply_err(req, EINVAL);
   1228         return;
   1229     }
   1230 
   1231     param = fuse_mbuf_iter_advance(iter, arg->size);
   1232     if (!param) {
   1233         fuse_reply_err(req, EINVAL);
   1234         return;
   1235     }
   1236 
   1237     memset(&fi, 0, sizeof(fi));
   1238     fi.fh = arg->fh;
   1239     fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
   1240     fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV);
   1241 
   1242     fi.lock_owner = arg->lock_owner;
   1243     fi.flags = arg->flags;
   1244 
   1245     if (req->se->op.write) {
   1246         req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi);
   1247     } else {
   1248         fuse_reply_err(req, ENOSYS);
   1249     }
   1250 }
   1251 
   1252 static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid,
   1253                          struct fuse_mbuf_iter *iter, struct fuse_bufvec *ibufv)
   1254 {
   1255     struct fuse_session *se = req->se;
   1256     struct fuse_bufvec *pbufv = ibufv;
   1257     struct fuse_bufvec tmpbufv = {
   1258         .buf[0] = ibufv->buf[0],
   1259         .count = 1,
   1260     };
   1261     struct fuse_write_in *arg;
   1262     size_t arg_size = sizeof(*arg);
   1263     struct fuse_file_info fi;
   1264 
   1265     memset(&fi, 0, sizeof(fi));
   1266 
   1267     arg = fuse_mbuf_iter_advance(iter, arg_size);
   1268     if (!arg) {
   1269         fuse_reply_err(req, EINVAL);
   1270         return;
   1271     }
   1272 
   1273     fi.lock_owner = arg->lock_owner;
   1274     fi.flags = arg->flags;
   1275     fi.fh = arg->fh;
   1276     fi.writepage = !!(arg->write_flags & FUSE_WRITE_CACHE);
   1277     fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV);
   1278 
   1279     if (ibufv->count == 1) {
   1280         assert(!(tmpbufv.buf[0].flags & FUSE_BUF_IS_FD));
   1281         tmpbufv.buf[0].mem = ((char *)arg) + arg_size;
   1282         tmpbufv.buf[0].size -= sizeof(struct fuse_in_header) + arg_size;
   1283         pbufv = &tmpbufv;
   1284     } else {
   1285         /*
   1286          *  Input bufv contains the headers in the first element
   1287          * and the data in the rest, we need to skip that first element
   1288          */
   1289         ibufv->buf[0].size = 0;
   1290     }
   1291 
   1292     if (fuse_buf_size(pbufv) != arg->size) {
   1293         fuse_log(FUSE_LOG_ERR,
   1294                  "fuse: do_write_buf: buffer size doesn't match arg->size\n");
   1295         fuse_reply_err(req, EIO);
   1296         return;
   1297     }
   1298 
   1299     se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi);
   1300 }
   1301 
   1302 static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
   1303                      struct fuse_mbuf_iter *iter)
   1304 {
   1305     struct fuse_flush_in *arg;
   1306     struct fuse_file_info fi;
   1307 
   1308     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1309     if (!arg) {
   1310         fuse_reply_err(req, EINVAL);
   1311         return;
   1312     }
   1313 
   1314     memset(&fi, 0, sizeof(fi));
   1315     fi.fh = arg->fh;
   1316     fi.flush = 1;
   1317     fi.lock_owner = arg->lock_owner;
   1318 
   1319     if (req->se->op.flush) {
   1320         req->se->op.flush(req, nodeid, &fi);
   1321     } else {
   1322         fuse_reply_err(req, ENOSYS);
   1323     }
   1324 }
   1325 
   1326 static void do_release(fuse_req_t req, fuse_ino_t nodeid,
   1327                        struct fuse_mbuf_iter *iter)
   1328 {
   1329     struct fuse_release_in *arg;
   1330     struct fuse_file_info fi;
   1331 
   1332     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1333     if (!arg) {
   1334         fuse_reply_err(req, EINVAL);
   1335         return;
   1336     }
   1337 
   1338     memset(&fi, 0, sizeof(fi));
   1339     fi.flags = arg->flags;
   1340     fi.fh = arg->fh;
   1341     fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
   1342     fi.lock_owner = arg->lock_owner;
   1343 
   1344     if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
   1345         fi.flock_release = 1;
   1346     }
   1347 
   1348     if (req->se->op.release) {
   1349         req->se->op.release(req, nodeid, &fi);
   1350     } else {
   1351         fuse_reply_err(req, 0);
   1352     }
   1353 }
   1354 
   1355 static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
   1356                      struct fuse_mbuf_iter *iter)
   1357 {
   1358     struct fuse_fsync_in *arg;
   1359     struct fuse_file_info fi;
   1360     int datasync;
   1361 
   1362     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1363     if (!arg) {
   1364         fuse_reply_err(req, EINVAL);
   1365         return;
   1366     }
   1367     datasync = arg->fsync_flags & 1;
   1368 
   1369     memset(&fi, 0, sizeof(fi));
   1370     fi.fh = arg->fh;
   1371 
   1372     if (req->se->op.fsync) {
   1373         if (fi.fh == (uint64_t)-1) {
   1374             req->se->op.fsync(req, nodeid, datasync, NULL);
   1375         } else {
   1376             req->se->op.fsync(req, nodeid, datasync, &fi);
   1377         }
   1378     } else {
   1379         fuse_reply_err(req, ENOSYS);
   1380     }
   1381 }
   1382 
   1383 static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
   1384                        struct fuse_mbuf_iter *iter)
   1385 {
   1386     struct fuse_open_in *arg;
   1387     struct fuse_file_info fi;
   1388 
   1389     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1390     if (!arg) {
   1391         fuse_reply_err(req, EINVAL);
   1392         return;
   1393     }
   1394 
   1395     memset(&fi, 0, sizeof(fi));
   1396     fi.flags = arg->flags;
   1397 
   1398     if (req->se->op.opendir) {
   1399         req->se->op.opendir(req, nodeid, &fi);
   1400     } else {
   1401         fuse_reply_open(req, &fi);
   1402     }
   1403 }
   1404 
   1405 static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
   1406                        struct fuse_mbuf_iter *iter)
   1407 {
   1408     struct fuse_read_in *arg;
   1409     struct fuse_file_info fi;
   1410 
   1411     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1412     if (!arg) {
   1413         fuse_reply_err(req, EINVAL);
   1414         return;
   1415     }
   1416 
   1417     memset(&fi, 0, sizeof(fi));
   1418     fi.fh = arg->fh;
   1419 
   1420     if (req->se->op.readdir) {
   1421         req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
   1422     } else {
   1423         fuse_reply_err(req, ENOSYS);
   1424     }
   1425 }
   1426 
   1427 static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid,
   1428                            struct fuse_mbuf_iter *iter)
   1429 {
   1430     struct fuse_read_in *arg;
   1431     struct fuse_file_info fi;
   1432 
   1433     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1434     if (!arg) {
   1435         fuse_reply_err(req, EINVAL);
   1436         return;
   1437     }
   1438 
   1439     memset(&fi, 0, sizeof(fi));
   1440     fi.fh = arg->fh;
   1441 
   1442     if (req->se->op.readdirplus) {
   1443         req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
   1444     } else {
   1445         fuse_reply_err(req, ENOSYS);
   1446     }
   1447 }
   1448 
   1449 static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
   1450                           struct fuse_mbuf_iter *iter)
   1451 {
   1452     struct fuse_release_in *arg;
   1453     struct fuse_file_info fi;
   1454 
   1455     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1456     if (!arg) {
   1457         fuse_reply_err(req, EINVAL);
   1458         return;
   1459     }
   1460 
   1461     memset(&fi, 0, sizeof(fi));
   1462     fi.flags = arg->flags;
   1463     fi.fh = arg->fh;
   1464 
   1465     if (req->se->op.releasedir) {
   1466         req->se->op.releasedir(req, nodeid, &fi);
   1467     } else {
   1468         fuse_reply_err(req, 0);
   1469     }
   1470 }
   1471 
   1472 static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
   1473                         struct fuse_mbuf_iter *iter)
   1474 {
   1475     struct fuse_fsync_in *arg;
   1476     struct fuse_file_info fi;
   1477     int datasync;
   1478 
   1479     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1480     if (!arg) {
   1481         fuse_reply_err(req, EINVAL);
   1482         return;
   1483     }
   1484     datasync = arg->fsync_flags & 1;
   1485 
   1486     memset(&fi, 0, sizeof(fi));
   1487     fi.fh = arg->fh;
   1488 
   1489     if (req->se->op.fsyncdir) {
   1490         req->se->op.fsyncdir(req, nodeid, datasync, &fi);
   1491     } else {
   1492         fuse_reply_err(req, ENOSYS);
   1493     }
   1494 }
   1495 
   1496 static void do_statfs(fuse_req_t req, fuse_ino_t nodeid,
   1497                       struct fuse_mbuf_iter *iter)
   1498 {
   1499     (void)nodeid;
   1500     (void)iter;
   1501 
   1502     if (req->se->op.statfs) {
   1503         req->se->op.statfs(req, nodeid);
   1504     } else {
   1505         struct statvfs buf = {
   1506             .f_namemax = 255,
   1507             .f_bsize = 512,
   1508         };
   1509         fuse_reply_statfs(req, &buf);
   1510     }
   1511 }
   1512 
   1513 static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
   1514                         struct fuse_mbuf_iter *iter)
   1515 {
   1516     struct fuse_setxattr_in *arg;
   1517     const char *name;
   1518     const char *value;
   1519     bool setxattr_ext = req->se->conn.want & FUSE_CAP_SETXATTR_EXT;
   1520 
   1521     if (setxattr_ext) {
   1522         arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1523     } else {
   1524         arg = fuse_mbuf_iter_advance(iter, FUSE_COMPAT_SETXATTR_IN_SIZE);
   1525     }
   1526     name = fuse_mbuf_iter_advance_str(iter);
   1527     if (!arg || !name) {
   1528         fuse_reply_err(req, EINVAL);
   1529         return;
   1530     }
   1531 
   1532     value = fuse_mbuf_iter_advance(iter, arg->size);
   1533     if (!value) {
   1534         fuse_reply_err(req, EINVAL);
   1535         return;
   1536     }
   1537 
   1538     if (req->se->op.setxattr) {
   1539         uint32_t setxattr_flags = setxattr_ext ? arg->setxattr_flags : 0;
   1540         req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags,
   1541                              setxattr_flags);
   1542     } else {
   1543         fuse_reply_err(req, ENOSYS);
   1544     }
   1545 }
   1546 
   1547 static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
   1548                         struct fuse_mbuf_iter *iter)
   1549 {
   1550     struct fuse_getxattr_in *arg;
   1551     const char *name;
   1552 
   1553     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1554     name = fuse_mbuf_iter_advance_str(iter);
   1555     if (!arg || !name) {
   1556         fuse_reply_err(req, EINVAL);
   1557         return;
   1558     }
   1559 
   1560     if (req->se->op.getxattr) {
   1561         req->se->op.getxattr(req, nodeid, name, arg->size);
   1562     } else {
   1563         fuse_reply_err(req, ENOSYS);
   1564     }
   1565 }
   1566 
   1567 static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
   1568                          struct fuse_mbuf_iter *iter)
   1569 {
   1570     struct fuse_getxattr_in *arg;
   1571 
   1572     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1573     if (!arg) {
   1574         fuse_reply_err(req, EINVAL);
   1575         return;
   1576     }
   1577 
   1578     if (req->se->op.listxattr) {
   1579         req->se->op.listxattr(req, nodeid, arg->size);
   1580     } else {
   1581         fuse_reply_err(req, ENOSYS);
   1582     }
   1583 }
   1584 
   1585 static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid,
   1586                            struct fuse_mbuf_iter *iter)
   1587 {
   1588     const char *name = fuse_mbuf_iter_advance_str(iter);
   1589 
   1590     if (!name) {
   1591         fuse_reply_err(req, EINVAL);
   1592         return;
   1593     }
   1594 
   1595     if (req->se->op.removexattr) {
   1596         req->se->op.removexattr(req, nodeid, name);
   1597     } else {
   1598         fuse_reply_err(req, ENOSYS);
   1599     }
   1600 }
   1601 
   1602 static void convert_fuse_file_lock(struct fuse_file_lock *fl,
   1603                                    struct flock *flock)
   1604 {
   1605     memset(flock, 0, sizeof(struct flock));
   1606     flock->l_type = fl->type;
   1607     flock->l_whence = SEEK_SET;
   1608     flock->l_start = fl->start;
   1609     if (fl->end == OFFSET_MAX) {
   1610         flock->l_len = 0;
   1611     } else {
   1612         flock->l_len = fl->end - fl->start + 1;
   1613     }
   1614     flock->l_pid = fl->pid;
   1615 }
   1616 
   1617 static void do_getlk(fuse_req_t req, fuse_ino_t nodeid,
   1618                      struct fuse_mbuf_iter *iter)
   1619 {
   1620     struct fuse_lk_in *arg;
   1621     struct fuse_file_info fi;
   1622     struct flock flock;
   1623 
   1624     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1625     if (!arg) {
   1626         fuse_reply_err(req, EINVAL);
   1627         return;
   1628     }
   1629 
   1630     memset(&fi, 0, sizeof(fi));
   1631     fi.fh = arg->fh;
   1632     fi.lock_owner = arg->owner;
   1633 
   1634     convert_fuse_file_lock(&arg->lk, &flock);
   1635     if (req->se->op.getlk) {
   1636         req->se->op.getlk(req, nodeid, &fi, &flock);
   1637     } else {
   1638         fuse_reply_err(req, ENOSYS);
   1639     }
   1640 }
   1641 
   1642 static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
   1643                             struct fuse_mbuf_iter *iter, int sleep)
   1644 {
   1645     struct fuse_lk_in *arg;
   1646     struct fuse_file_info fi;
   1647     struct flock flock;
   1648 
   1649     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1650     if (!arg) {
   1651         fuse_reply_err(req, EINVAL);
   1652         return;
   1653     }
   1654 
   1655     memset(&fi, 0, sizeof(fi));
   1656     fi.fh = arg->fh;
   1657     fi.lock_owner = arg->owner;
   1658 
   1659     if (arg->lk_flags & FUSE_LK_FLOCK) {
   1660         int op = 0;
   1661 
   1662         switch (arg->lk.type) {
   1663         case F_RDLCK:
   1664             op = LOCK_SH;
   1665             break;
   1666         case F_WRLCK:
   1667             op = LOCK_EX;
   1668             break;
   1669         case F_UNLCK:
   1670             op = LOCK_UN;
   1671             break;
   1672         }
   1673         if (!sleep) {
   1674             op |= LOCK_NB;
   1675         }
   1676 
   1677         if (req->se->op.flock) {
   1678             req->se->op.flock(req, nodeid, &fi, op);
   1679         } else {
   1680             fuse_reply_err(req, ENOSYS);
   1681         }
   1682     } else {
   1683         convert_fuse_file_lock(&arg->lk, &flock);
   1684         if (req->se->op.setlk) {
   1685             req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
   1686         } else {
   1687             fuse_reply_err(req, ENOSYS);
   1688         }
   1689     }
   1690 }
   1691 
   1692 static void do_setlk(fuse_req_t req, fuse_ino_t nodeid,
   1693                      struct fuse_mbuf_iter *iter)
   1694 {
   1695     do_setlk_common(req, nodeid, iter, 0);
   1696 }
   1697 
   1698 static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid,
   1699                       struct fuse_mbuf_iter *iter)
   1700 {
   1701     do_setlk_common(req, nodeid, iter, 1);
   1702 }
   1703 
   1704 static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
   1705 {
   1706     struct fuse_req *curr;
   1707 
   1708     for (curr = se->list.next; curr != &se->list; curr = curr->next) {
   1709         if (curr->unique == req->u.i.unique) {
   1710             fuse_interrupt_func_t func;
   1711             void *data;
   1712 
   1713             curr->ctr++;
   1714             pthread_mutex_unlock(&se->lock);
   1715 
   1716             /* Ugh, ugly locking */
   1717             pthread_mutex_lock(&curr->lock);
   1718             pthread_mutex_lock(&se->lock);
   1719             curr->interrupted = 1;
   1720             func = curr->u.ni.func;
   1721             data = curr->u.ni.data;
   1722             pthread_mutex_unlock(&se->lock);
   1723             if (func) {
   1724                 func(curr, data);
   1725             }
   1726             pthread_mutex_unlock(&curr->lock);
   1727 
   1728             pthread_mutex_lock(&se->lock);
   1729             curr->ctr--;
   1730             if (!curr->ctr) {
   1731                 destroy_req(curr);
   1732             }
   1733 
   1734             return 1;
   1735         }
   1736     }
   1737     for (curr = se->interrupts.next; curr != &se->interrupts;
   1738          curr = curr->next) {
   1739         if (curr->u.i.unique == req->u.i.unique) {
   1740             return 1;
   1741         }
   1742     }
   1743     return 0;
   1744 }
   1745 
   1746 static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid,
   1747                          struct fuse_mbuf_iter *iter)
   1748 {
   1749     struct fuse_interrupt_in *arg;
   1750     struct fuse_session *se = req->se;
   1751 
   1752     (void)nodeid;
   1753 
   1754     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1755     if (!arg) {
   1756         fuse_reply_err(req, EINVAL);
   1757         return;
   1758     }
   1759 
   1760     fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
   1761              (unsigned long long)arg->unique);
   1762 
   1763     req->u.i.unique = arg->unique;
   1764 
   1765     pthread_mutex_lock(&se->lock);
   1766     if (find_interrupted(se, req)) {
   1767         destroy_req(req);
   1768     } else {
   1769         list_add_req(req, &se->interrupts);
   1770     }
   1771     pthread_mutex_unlock(&se->lock);
   1772 }
   1773 
   1774 static struct fuse_req *check_interrupt(struct fuse_session *se,
   1775                                         struct fuse_req *req)
   1776 {
   1777     struct fuse_req *curr;
   1778 
   1779     for (curr = se->interrupts.next; curr != &se->interrupts;
   1780          curr = curr->next) {
   1781         if (curr->u.i.unique == req->unique) {
   1782             req->interrupted = 1;
   1783             list_del_req(curr);
   1784             g_free(curr);
   1785             return NULL;
   1786         }
   1787     }
   1788     curr = se->interrupts.next;
   1789     if (curr != &se->interrupts) {
   1790         list_del_req(curr);
   1791         list_init_req(curr);
   1792         return curr;
   1793     } else {
   1794         return NULL;
   1795     }
   1796 }
   1797 
   1798 static void do_bmap(fuse_req_t req, fuse_ino_t nodeid,
   1799                     struct fuse_mbuf_iter *iter)
   1800 {
   1801     struct fuse_bmap_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1802 
   1803     if (!arg) {
   1804         fuse_reply_err(req, EINVAL);
   1805         return;
   1806     }
   1807 
   1808     if (req->se->op.bmap) {
   1809         req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
   1810     } else {
   1811         fuse_reply_err(req, ENOSYS);
   1812     }
   1813 }
   1814 
   1815 static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid,
   1816                      struct fuse_mbuf_iter *iter)
   1817 {
   1818     struct fuse_ioctl_in *arg;
   1819     unsigned int flags;
   1820     void *in_buf = NULL;
   1821     struct fuse_file_info fi;
   1822 
   1823     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1824     if (!arg) {
   1825         fuse_reply_err(req, EINVAL);
   1826         return;
   1827     }
   1828 
   1829     flags = arg->flags;
   1830     if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
   1831         fuse_reply_err(req, ENOTTY);
   1832         return;
   1833     }
   1834 
   1835     if (arg->in_size) {
   1836         in_buf = fuse_mbuf_iter_advance(iter, arg->in_size);
   1837         if (!in_buf) {
   1838             fuse_reply_err(req, EINVAL);
   1839             return;
   1840         }
   1841     }
   1842 
   1843     memset(&fi, 0, sizeof(fi));
   1844     fi.fh = arg->fh;
   1845 
   1846     if (sizeof(void *) == 4 && !(flags & FUSE_IOCTL_32BIT)) {
   1847         req->ioctl_64bit = 1;
   1848     }
   1849 
   1850     if (req->se->op.ioctl) {
   1851         req->se->op.ioctl(req, nodeid, arg->cmd, (void *)(uintptr_t)arg->arg,
   1852                           &fi, flags, in_buf, arg->in_size, arg->out_size);
   1853     } else {
   1854         fuse_reply_err(req, ENOSYS);
   1855     }
   1856 }
   1857 
   1858 void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
   1859 {
   1860     free(ph);
   1861 }
   1862 
   1863 static void do_poll(fuse_req_t req, fuse_ino_t nodeid,
   1864                     struct fuse_mbuf_iter *iter)
   1865 {
   1866     struct fuse_poll_in *arg;
   1867     struct fuse_file_info fi;
   1868 
   1869     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1870     if (!arg) {
   1871         fuse_reply_err(req, EINVAL);
   1872         return;
   1873     }
   1874 
   1875     memset(&fi, 0, sizeof(fi));
   1876     fi.fh = arg->fh;
   1877     fi.poll_events = arg->events;
   1878 
   1879     if (req->se->op.poll) {
   1880         struct fuse_pollhandle *ph = NULL;
   1881 
   1882         if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
   1883             ph = malloc(sizeof(struct fuse_pollhandle));
   1884             if (ph == NULL) {
   1885                 fuse_reply_err(req, ENOMEM);
   1886                 return;
   1887             }
   1888             ph->kh = arg->kh;
   1889             ph->se = req->se;
   1890         }
   1891 
   1892         req->se->op.poll(req, nodeid, &fi, ph);
   1893     } else {
   1894         fuse_reply_err(req, ENOSYS);
   1895     }
   1896 }
   1897 
   1898 static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid,
   1899                          struct fuse_mbuf_iter *iter)
   1900 {
   1901     struct fuse_fallocate_in *arg;
   1902     struct fuse_file_info fi;
   1903 
   1904     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1905     if (!arg) {
   1906         fuse_reply_err(req, EINVAL);
   1907         return;
   1908     }
   1909 
   1910     memset(&fi, 0, sizeof(fi));
   1911     fi.fh = arg->fh;
   1912 
   1913     if (req->se->op.fallocate) {
   1914         req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length,
   1915                               &fi);
   1916     } else {
   1917         fuse_reply_err(req, ENOSYS);
   1918     }
   1919 }
   1920 
   1921 static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
   1922                                struct fuse_mbuf_iter *iter)
   1923 {
   1924     struct fuse_copy_file_range_in *arg;
   1925     struct fuse_file_info fi_in, fi_out;
   1926 
   1927     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1928     if (!arg) {
   1929         fuse_reply_err(req, EINVAL);
   1930         return;
   1931     }
   1932 
   1933     memset(&fi_in, 0, sizeof(fi_in));
   1934     fi_in.fh = arg->fh_in;
   1935 
   1936     memset(&fi_out, 0, sizeof(fi_out));
   1937     fi_out.fh = arg->fh_out;
   1938 
   1939 
   1940     if (req->se->op.copy_file_range) {
   1941         req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in,
   1942                                     arg->nodeid_out, arg->off_out, &fi_out,
   1943                                     arg->len, arg->flags);
   1944     } else {
   1945         fuse_reply_err(req, ENOSYS);
   1946     }
   1947 }
   1948 
   1949 static void do_lseek(fuse_req_t req, fuse_ino_t nodeid,
   1950                      struct fuse_mbuf_iter *iter)
   1951 {
   1952     struct fuse_lseek_in *arg;
   1953     struct fuse_file_info fi;
   1954 
   1955     arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
   1956     if (!arg) {
   1957         fuse_reply_err(req, EINVAL);
   1958         return;
   1959     }
   1960     memset(&fi, 0, sizeof(fi));
   1961     fi.fh = arg->fh;
   1962 
   1963     if (req->se->op.lseek) {
   1964         req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
   1965     } else {
   1966         fuse_reply_err(req, ENOSYS);
   1967     }
   1968 }
   1969 
   1970 static void do_syncfs(fuse_req_t req, fuse_ino_t nodeid,
   1971                       struct fuse_mbuf_iter *iter)
   1972 {
   1973     if (req->se->op.syncfs) {
   1974         req->se->op.syncfs(req, nodeid);
   1975     } else {
   1976         fuse_reply_err(req, ENOSYS);
   1977     }
   1978 }
   1979 
   1980 static void do_init(fuse_req_t req, fuse_ino_t nodeid,
   1981                     struct fuse_mbuf_iter *iter)
   1982 {
   1983     size_t compat_size = offsetof(struct fuse_init_in, max_readahead);
   1984     size_t compat2_size = offsetof(struct fuse_init_in, flags) +
   1985                               sizeof(uint32_t);
   1986     /* Fuse structure extended with minor version 36 */
   1987     size_t compat3_size = endof(struct fuse_init_in, unused);
   1988     struct fuse_init_in *arg;
   1989     struct fuse_init_out outarg;
   1990     struct fuse_session *se = req->se;
   1991     size_t bufsize = se->bufsize;
   1992     size_t outargsize = sizeof(outarg);
   1993     uint64_t flags = 0;
   1994 
   1995     (void)nodeid;
   1996 
   1997     /* First consume the old fields... */
   1998     arg = fuse_mbuf_iter_advance(iter, compat_size);
   1999     if (!arg) {
   2000         fuse_reply_err(req, EINVAL);
   2001         return;
   2002     }
   2003 
   2004     /* ...and now consume the new fields. */
   2005     if (arg->major == 7 && arg->minor >= 6) {
   2006         if (!fuse_mbuf_iter_advance(iter, compat2_size - compat_size)) {
   2007             fuse_reply_err(req, EINVAL);
   2008             return;
   2009         }
   2010         flags |= arg->flags;
   2011     }
   2012 
   2013     /*
   2014      * fuse_init_in was extended again with minor version 36. Just read
   2015      * current known size of fuse_init so that future extension and
   2016      * header rebase does not cause breakage.
   2017      */
   2018     if (sizeof(*arg) > compat2_size && (arg->flags & FUSE_INIT_EXT)) {
   2019         if (!fuse_mbuf_iter_advance(iter, compat3_size - compat2_size)) {
   2020             fuse_reply_err(req, EINVAL);
   2021             return;
   2022         }
   2023         flags |= (uint64_t) arg->flags2 << 32;
   2024     }
   2025 
   2026     fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
   2027     if (arg->major == 7 && arg->minor >= 6) {
   2028         fuse_log(FUSE_LOG_DEBUG, "flags=0x%016" PRIx64 "\n", flags);
   2029         fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n", arg->max_readahead);
   2030     }
   2031     se->conn.proto_major = arg->major;
   2032     se->conn.proto_minor = arg->minor;
   2033     se->conn.capable = 0;
   2034     se->conn.want = 0;
   2035 
   2036     memset(&outarg, 0, sizeof(outarg));
   2037     outarg.major = FUSE_KERNEL_VERSION;
   2038     outarg.minor = FUSE_KERNEL_MINOR_VERSION;
   2039 
   2040     if (arg->major < 7 || (arg->major == 7 && arg->minor < 31)) {
   2041         fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
   2042                  arg->major, arg->minor);
   2043         fuse_reply_err(req, EPROTO);
   2044         return;
   2045     }
   2046 
   2047     if (arg->major > 7) {
   2048         /* Wait for a second INIT request with a 7.X version */
   2049         send_reply_ok(req, &outarg, sizeof(outarg));
   2050         return;
   2051     }
   2052 
   2053     if (arg->max_readahead < se->conn.max_readahead) {
   2054         se->conn.max_readahead = arg->max_readahead;
   2055     }
   2056     if (flags & FUSE_ASYNC_READ) {
   2057         se->conn.capable |= FUSE_CAP_ASYNC_READ;
   2058     }
   2059     if (flags & FUSE_POSIX_LOCKS) {
   2060         se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
   2061     }
   2062     if (flags & FUSE_ATOMIC_O_TRUNC) {
   2063         se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
   2064     }
   2065     if (flags & FUSE_EXPORT_SUPPORT) {
   2066         se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
   2067     }
   2068     if (flags & FUSE_DONT_MASK) {
   2069         se->conn.capable |= FUSE_CAP_DONT_MASK;
   2070     }
   2071     if (flags & FUSE_FLOCK_LOCKS) {
   2072         se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
   2073     }
   2074     if (flags & FUSE_AUTO_INVAL_DATA) {
   2075         se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
   2076     }
   2077     if (flags & FUSE_DO_READDIRPLUS) {
   2078         se->conn.capable |= FUSE_CAP_READDIRPLUS;
   2079     }
   2080     if (flags & FUSE_READDIRPLUS_AUTO) {
   2081         se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
   2082     }
   2083     if (flags & FUSE_ASYNC_DIO) {
   2084         se->conn.capable |= FUSE_CAP_ASYNC_DIO;
   2085     }
   2086     if (flags & FUSE_WRITEBACK_CACHE) {
   2087         se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
   2088     }
   2089     if (flags & FUSE_NO_OPEN_SUPPORT) {
   2090         se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
   2091     }
   2092     if (flags & FUSE_PARALLEL_DIROPS) {
   2093         se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
   2094     }
   2095     if (flags & FUSE_POSIX_ACL) {
   2096         se->conn.capable |= FUSE_CAP_POSIX_ACL;
   2097     }
   2098     if (flags & FUSE_HANDLE_KILLPRIV) {
   2099         se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
   2100     }
   2101     if (flags & FUSE_NO_OPENDIR_SUPPORT) {
   2102         se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
   2103     }
   2104     if (!(flags & FUSE_MAX_PAGES)) {
   2105         size_t max_bufsize = FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() +
   2106                              FUSE_BUFFER_HEADER_SIZE;
   2107         if (bufsize > max_bufsize) {
   2108             bufsize = max_bufsize;
   2109         }
   2110     }
   2111     if (flags & FUSE_SUBMOUNTS) {
   2112         se->conn.capable |= FUSE_CAP_SUBMOUNTS;
   2113     }
   2114     if (flags & FUSE_HANDLE_KILLPRIV_V2) {
   2115         se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV_V2;
   2116     }
   2117     if (flags & FUSE_SETXATTR_EXT) {
   2118         se->conn.capable |= FUSE_CAP_SETXATTR_EXT;
   2119     }
   2120     if (flags & FUSE_SECURITY_CTX) {
   2121         se->conn.capable |= FUSE_CAP_SECURITY_CTX;
   2122     }
   2123 #ifdef HAVE_SPLICE
   2124 #ifdef HAVE_VMSPLICE
   2125     se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
   2126 #endif
   2127     se->conn.capable |= FUSE_CAP_SPLICE_READ;
   2128 #endif
   2129     se->conn.capable |= FUSE_CAP_IOCTL_DIR;
   2130 
   2131     /*
   2132      * Default settings for modern filesystems.
   2133      *
   2134      * Most of these capabilities were disabled by default in
   2135      * libfuse2 for backwards compatibility reasons. In libfuse3,
   2136      * we can finally enable them by default (as long as they're
   2137      * supported by the kernel).
   2138      */
   2139 #define LL_SET_DEFAULT(cond, cap)             \
   2140     if ((cond) && (se->conn.capable & (cap))) \
   2141         se->conn.want |= (cap)
   2142     LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
   2143     LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
   2144     LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
   2145     LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
   2146     LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
   2147     LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
   2148     LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
   2149     LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
   2150     LL_SET_DEFAULT(se->op.getlk && se->op.setlk, FUSE_CAP_POSIX_LOCKS);
   2151     LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
   2152     LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
   2153     LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
   2154                    FUSE_CAP_READDIRPLUS_AUTO);
   2155     se->conn.time_gran = 1;
   2156 
   2157     if (bufsize < FUSE_MIN_READ_BUFFER) {
   2158         fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
   2159                  bufsize);
   2160         bufsize = FUSE_MIN_READ_BUFFER;
   2161     }
   2162     se->bufsize = bufsize;
   2163 
   2164     if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE) {
   2165         se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
   2166     }
   2167 
   2168     se->got_init = 1;
   2169     se->got_destroy = 0;
   2170     if (se->op.init) {
   2171         se->op.init(se->userdata, &se->conn);
   2172     }
   2173 
   2174     if (se->conn.want & (~se->conn.capable)) {
   2175         fuse_log(FUSE_LOG_ERR,
   2176                  "fuse: error: filesystem requested capabilities "
   2177                  "0x%" PRIx64 " that are not supported by kernel, aborting.\n",
   2178                  se->conn.want & (~se->conn.capable));
   2179         fuse_reply_err(req, EPROTO);
   2180         se->error = -EPROTO;
   2181         fuse_session_exit(se);
   2182         return;
   2183     }
   2184 
   2185     if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
   2186         se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
   2187     }
   2188     if (flags & FUSE_MAX_PAGES) {
   2189         outarg.flags |= FUSE_MAX_PAGES;
   2190         outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
   2191     }
   2192 
   2193     /*
   2194      * Always enable big writes, this is superseded
   2195      * by the max_write option
   2196      */
   2197     outarg.flags |= FUSE_BIG_WRITES;
   2198 
   2199     if (se->conn.want & FUSE_CAP_ASYNC_READ) {
   2200         outarg.flags |= FUSE_ASYNC_READ;
   2201     }
   2202     if (se->conn.want & FUSE_CAP_PARALLEL_DIROPS) {
   2203         outarg.flags |= FUSE_PARALLEL_DIROPS;
   2204     }
   2205     if (se->conn.want & FUSE_CAP_POSIX_LOCKS) {
   2206         outarg.flags |= FUSE_POSIX_LOCKS;
   2207     }
   2208     if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) {
   2209         outarg.flags |= FUSE_ATOMIC_O_TRUNC;
   2210     }
   2211     if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT) {
   2212         outarg.flags |= FUSE_EXPORT_SUPPORT;
   2213     }
   2214     if (se->conn.want & FUSE_CAP_DONT_MASK) {
   2215         outarg.flags |= FUSE_DONT_MASK;
   2216     }
   2217     if (se->conn.want & FUSE_CAP_FLOCK_LOCKS) {
   2218         outarg.flags |= FUSE_FLOCK_LOCKS;
   2219     }
   2220     if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA) {
   2221         outarg.flags |= FUSE_AUTO_INVAL_DATA;
   2222     }
   2223     if (se->conn.want & FUSE_CAP_READDIRPLUS) {
   2224         outarg.flags |= FUSE_DO_READDIRPLUS;
   2225     }
   2226     if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO) {
   2227         outarg.flags |= FUSE_READDIRPLUS_AUTO;
   2228     }
   2229     if (se->conn.want & FUSE_CAP_ASYNC_DIO) {
   2230         outarg.flags |= FUSE_ASYNC_DIO;
   2231     }
   2232     if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE) {
   2233         outarg.flags |= FUSE_WRITEBACK_CACHE;
   2234     }
   2235     if (se->conn.want & FUSE_CAP_POSIX_ACL) {
   2236         outarg.flags |= FUSE_POSIX_ACL;
   2237     }
   2238     outarg.max_readahead = se->conn.max_readahead;
   2239     outarg.max_write = se->conn.max_write;
   2240     if (se->conn.max_background >= (1 << 16)) {
   2241         se->conn.max_background = (1 << 16) - 1;
   2242     }
   2243     if (se->conn.congestion_threshold > se->conn.max_background) {
   2244         se->conn.congestion_threshold = se->conn.max_background;
   2245     }
   2246     if (!se->conn.congestion_threshold) {
   2247         se->conn.congestion_threshold = se->conn.max_background * 3 / 4;
   2248     }
   2249 
   2250     outarg.max_background = se->conn.max_background;
   2251     outarg.congestion_threshold = se->conn.congestion_threshold;
   2252     outarg.time_gran = se->conn.time_gran;
   2253 
   2254     if (se->conn.want & FUSE_CAP_HANDLE_KILLPRIV_V2) {
   2255         outarg.flags |= FUSE_HANDLE_KILLPRIV_V2;
   2256     }
   2257 
   2258     if (se->conn.want & FUSE_CAP_SETXATTR_EXT) {
   2259         outarg.flags |= FUSE_SETXATTR_EXT;
   2260     }
   2261 
   2262     if (se->conn.want & FUSE_CAP_SECURITY_CTX) {
   2263         /* bits 32..63 get shifted down 32 bits into the flags2 field */
   2264         outarg.flags2 |= FUSE_SECURITY_CTX >> 32;
   2265     }
   2266 
   2267     fuse_log(FUSE_LOG_DEBUG, "   INIT: %u.%u\n", outarg.major, outarg.minor);
   2268     fuse_log(FUSE_LOG_DEBUG, "   flags2=0x%08x flags=0x%08x\n", outarg.flags2,
   2269              outarg.flags);
   2270     fuse_log(FUSE_LOG_DEBUG, "   max_readahead=0x%08x\n", outarg.max_readahead);
   2271     fuse_log(FUSE_LOG_DEBUG, "   max_write=0x%08x\n", outarg.max_write);
   2272     fuse_log(FUSE_LOG_DEBUG, "   max_background=%i\n", outarg.max_background);
   2273     fuse_log(FUSE_LOG_DEBUG, "   congestion_threshold=%i\n",
   2274              outarg.congestion_threshold);
   2275     fuse_log(FUSE_LOG_DEBUG, "   time_gran=%u\n", outarg.time_gran);
   2276 
   2277     send_reply_ok(req, &outarg, outargsize);
   2278 }
   2279 
   2280 static void do_destroy(fuse_req_t req, fuse_ino_t nodeid,
   2281                        struct fuse_mbuf_iter *iter)
   2282 {
   2283     struct fuse_session *se = req->se;
   2284 
   2285     (void)nodeid;
   2286     (void)iter;
   2287 
   2288     se->got_destroy = 1;
   2289     se->got_init = 0;
   2290     if (se->op.destroy) {
   2291         se->op.destroy(se->userdata);
   2292     }
   2293 
   2294     send_reply_ok(req, NULL, 0);
   2295 }
   2296 
   2297 int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
   2298                                off_t offset, struct fuse_bufvec *bufv)
   2299 {
   2300     struct fuse_out_header out = {
   2301         .error = FUSE_NOTIFY_STORE,
   2302     };
   2303     struct fuse_notify_store_out outarg = {
   2304         .nodeid = ino,
   2305         .offset = offset,
   2306         .size = fuse_buf_size(bufv),
   2307     };
   2308     struct iovec iov[3];
   2309     int res;
   2310 
   2311     if (!se) {
   2312         return -EINVAL;
   2313     }
   2314 
   2315     iov[0].iov_base = &out;
   2316     iov[0].iov_len = sizeof(out);
   2317     iov[1].iov_base = &outarg;
   2318     iov[1].iov_len = sizeof(outarg);
   2319 
   2320     res = fuse_send_data_iov(se, NULL, iov, 2, bufv);
   2321     if (res > 0) {
   2322         res = -res;
   2323     }
   2324 
   2325     return res;
   2326 }
   2327 
   2328 void *fuse_req_userdata(fuse_req_t req)
   2329 {
   2330     return req->se->userdata;
   2331 }
   2332 
   2333 const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
   2334 {
   2335     return &req->ctx;
   2336 }
   2337 
   2338 void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
   2339                              void *data)
   2340 {
   2341     pthread_mutex_lock(&req->lock);
   2342     pthread_mutex_lock(&req->se->lock);
   2343     req->u.ni.func = func;
   2344     req->u.ni.data = data;
   2345     pthread_mutex_unlock(&req->se->lock);
   2346     if (req->interrupted && func) {
   2347         func(req, data);
   2348     }
   2349     pthread_mutex_unlock(&req->lock);
   2350 }
   2351 
   2352 int fuse_req_interrupted(fuse_req_t req)
   2353 {
   2354     int interrupted;
   2355 
   2356     pthread_mutex_lock(&req->se->lock);
   2357     interrupted = req->interrupted;
   2358     pthread_mutex_unlock(&req->se->lock);
   2359 
   2360     return interrupted;
   2361 }
   2362 
   2363 static struct {
   2364     void (*func)(fuse_req_t, fuse_ino_t, struct fuse_mbuf_iter *);
   2365     const char *name;
   2366 } fuse_ll_ops[] = {
   2367     [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
   2368     [FUSE_FORGET] = { do_forget, "FORGET" },
   2369     [FUSE_GETATTR] = { do_getattr, "GETATTR" },
   2370     [FUSE_SETATTR] = { do_setattr, "SETATTR" },
   2371     [FUSE_READLINK] = { do_readlink, "READLINK" },
   2372     [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
   2373     [FUSE_MKNOD] = { do_mknod, "MKNOD" },
   2374     [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
   2375     [FUSE_UNLINK] = { do_unlink, "UNLINK" },
   2376     [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
   2377     [FUSE_RENAME] = { do_rename, "RENAME" },
   2378     [FUSE_LINK] = { do_link, "LINK" },
   2379     [FUSE_OPEN] = { do_open, "OPEN" },
   2380     [FUSE_READ] = { do_read, "READ" },
   2381     [FUSE_WRITE] = { do_write, "WRITE" },
   2382     [FUSE_STATFS] = { do_statfs, "STATFS" },
   2383     [FUSE_RELEASE] = { do_release, "RELEASE" },
   2384     [FUSE_FSYNC] = { do_fsync, "FSYNC" },
   2385     [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
   2386     [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
   2387     [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
   2388     [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
   2389     [FUSE_FLUSH] = { do_flush, "FLUSH" },
   2390     [FUSE_INIT] = { do_init, "INIT" },
   2391     [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
   2392     [FUSE_READDIR] = { do_readdir, "READDIR" },
   2393     [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
   2394     [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
   2395     [FUSE_GETLK] = { do_getlk, "GETLK" },
   2396     [FUSE_SETLK] = { do_setlk, "SETLK" },
   2397     [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
   2398     [FUSE_ACCESS] = { do_access, "ACCESS" },
   2399     [FUSE_CREATE] = { do_create, "CREATE" },
   2400     [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
   2401     [FUSE_BMAP] = { do_bmap, "BMAP" },
   2402     [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
   2403     [FUSE_POLL] = { do_poll, "POLL" },
   2404     [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
   2405     [FUSE_DESTROY] = { do_destroy, "DESTROY" },
   2406     [FUSE_NOTIFY_REPLY] = { NULL, "NOTIFY_REPLY" },
   2407     [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
   2408     [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS" },
   2409     [FUSE_RENAME2] = { do_rename2, "RENAME2" },
   2410     [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
   2411     [FUSE_LSEEK] = { do_lseek, "LSEEK" },
   2412     [FUSE_SYNCFS] = { do_syncfs, "SYNCFS" },
   2413 };
   2414 
   2415 #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
   2416 
   2417 static const char *opname(enum fuse_opcode opcode)
   2418 {
   2419     if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) {
   2420         return "???";
   2421     } else {
   2422         return fuse_ll_ops[opcode].name;
   2423     }
   2424 }
   2425 
   2426 void fuse_session_process_buf(struct fuse_session *se,
   2427                               const struct fuse_buf *buf)
   2428 {
   2429     struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
   2430     fuse_session_process_buf_int(se, &bufv, NULL);
   2431 }
   2432 
   2433 /*
   2434  * Restriction:
   2435  *   bufv is normally a single entry buffer, except for a write
   2436  *   where (if it's in memory) then the bufv may be multiple entries,
   2437  *   where the first entry contains all headers and subsequent entries
   2438  *   contain data
   2439  *   bufv shall not use any offsets etc to make the data anything
   2440  *   other than contiguous starting from 0.
   2441  */
   2442 void fuse_session_process_buf_int(struct fuse_session *se,
   2443                                   struct fuse_bufvec *bufv,
   2444                                   struct fuse_chan *ch)
   2445 {
   2446     const struct fuse_buf *buf = bufv->buf;
   2447     struct fuse_mbuf_iter iter = FUSE_MBUF_ITER_INIT(buf);
   2448     struct fuse_in_header *in;
   2449     struct fuse_req *req;
   2450     int err;
   2451 
   2452     /* The first buffer must be a memory buffer */
   2453     assert(!(buf->flags & FUSE_BUF_IS_FD));
   2454 
   2455     in = fuse_mbuf_iter_advance(&iter, sizeof(*in));
   2456     assert(in); /* caller guarantees the input buffer is large enough */
   2457 
   2458     fuse_log(
   2459         FUSE_LOG_DEBUG,
   2460         "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
   2461         (unsigned long long)in->unique, opname((enum fuse_opcode)in->opcode),
   2462         in->opcode, (unsigned long long)in->nodeid, buf->size, in->pid);
   2463 
   2464     req = fuse_ll_alloc_req(se);
   2465     if (req == NULL) {
   2466         struct fuse_out_header out = {
   2467             .unique = in->unique,
   2468             .error = -ENOMEM,
   2469         };
   2470         struct iovec iov = {
   2471             .iov_base = &out,
   2472             .iov_len = sizeof(struct fuse_out_header),
   2473         };
   2474 
   2475         fuse_send_msg(se, ch, &iov, 1);
   2476         return;
   2477     }
   2478 
   2479     req->unique = in->unique;
   2480     req->ctx.uid = in->uid;
   2481     req->ctx.gid = in->gid;
   2482     req->ctx.pid = in->pid;
   2483     req->ch = ch;
   2484 
   2485     /*
   2486      * INIT and DESTROY requests are serialized, all other request types
   2487      * run in parallel.  This prevents races between FUSE_INIT and ordinary
   2488      * requests, FUSE_INIT and FUSE_INIT, FUSE_INIT and FUSE_DESTROY, and
   2489      * FUSE_DESTROY and FUSE_DESTROY.
   2490      */
   2491     if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT ||
   2492         in->opcode == FUSE_DESTROY) {
   2493         pthread_rwlock_wrlock(&se->init_rwlock);
   2494     } else {
   2495         pthread_rwlock_rdlock(&se->init_rwlock);
   2496     }
   2497 
   2498     err = EIO;
   2499     if (!se->got_init) {
   2500         enum fuse_opcode expected;
   2501 
   2502         expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
   2503         if (in->opcode != expected) {
   2504             goto reply_err;
   2505         }
   2506     } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) {
   2507         if (fuse_lowlevel_is_virtio(se)) {
   2508             /*
   2509              * TODO: This is after a hard reboot typically, we need to do
   2510              * a destroy, but we can't reply to this request yet so
   2511              * we can't use do_destroy
   2512              */
   2513             fuse_log(FUSE_LOG_DEBUG, "%s: reinit\n", __func__);
   2514             se->got_destroy = 1;
   2515             se->got_init = 0;
   2516             if (se->op.destroy) {
   2517                 se->op.destroy(se->userdata);
   2518             }
   2519         } else {
   2520             goto reply_err;
   2521         }
   2522     }
   2523 
   2524     err = EACCES;
   2525     /* Implement -o allow_root */
   2526     if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
   2527         in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
   2528         in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
   2529         in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
   2530         in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
   2531         in->opcode != FUSE_NOTIFY_REPLY && in->opcode != FUSE_READDIRPLUS) {
   2532         goto reply_err;
   2533     }
   2534 
   2535     err = ENOSYS;
   2536     if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) {
   2537         goto reply_err;
   2538     }
   2539     if (in->opcode != FUSE_INTERRUPT) {
   2540         struct fuse_req *intr;
   2541         pthread_mutex_lock(&se->lock);
   2542         intr = check_interrupt(se, req);
   2543         list_add_req(req, &se->list);
   2544         pthread_mutex_unlock(&se->lock);
   2545         if (intr) {
   2546             fuse_reply_err(intr, EAGAIN);
   2547         }
   2548     }
   2549 
   2550     if (in->opcode == FUSE_WRITE && se->op.write_buf) {
   2551         do_write_buf(req, in->nodeid, &iter, bufv);
   2552     } else {
   2553         fuse_ll_ops[in->opcode].func(req, in->nodeid, &iter);
   2554     }
   2555 
   2556     pthread_rwlock_unlock(&se->init_rwlock);
   2557     return;
   2558 
   2559 reply_err:
   2560     fuse_reply_err(req, err);
   2561     pthread_rwlock_unlock(&se->init_rwlock);
   2562 }
   2563 
   2564 #define LL_OPTION(n, o, v)                     \
   2565     {                                          \
   2566         n, offsetof(struct fuse_session, o), v \
   2567     }
   2568 
   2569 static const struct fuse_opt fuse_ll_opts[] = {
   2570     LL_OPTION("debug", debug, 1),
   2571     LL_OPTION("-d", debug, 1),
   2572     LL_OPTION("--debug", debug, 1),
   2573     LL_OPTION("allow_root", deny_others, 1),
   2574     LL_OPTION("--socket-path=%s", vu_socket_path, 0),
   2575     LL_OPTION("--socket-group=%s", vu_socket_group, 0),
   2576     LL_OPTION("--fd=%d", vu_listen_fd, 0),
   2577     LL_OPTION("--thread-pool-size=%d", thread_pool_size, 0),
   2578     FUSE_OPT_END
   2579 };
   2580 
   2581 void fuse_lowlevel_version(void)
   2582 {
   2583     printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION,
   2584            FUSE_KERNEL_MINOR_VERSION);
   2585 }
   2586 
   2587 void fuse_lowlevel_help(void)
   2588 {
   2589     /*
   2590      * These are not all options, but the ones that are
   2591      * potentially of interest to an end-user
   2592      */
   2593     printf(
   2594         "    -o allow_root              allow access by root\n"
   2595         "    --socket-path=PATH         path for the vhost-user socket\n"
   2596         "    --socket-group=GRNAME      name of group for the vhost-user socket\n"
   2597         "    --fd=FDNUM                 fd number of vhost-user socket\n"
   2598         "    --thread-pool-size=NUM     thread pool size limit (default %d)\n",
   2599         THREAD_POOL_SIZE);
   2600 }
   2601 
   2602 void fuse_session_destroy(struct fuse_session *se)
   2603 {
   2604     if (se->got_init && !se->got_destroy) {
   2605         if (se->op.destroy) {
   2606             se->op.destroy(se->userdata);
   2607         }
   2608     }
   2609     pthread_rwlock_destroy(&se->init_rwlock);
   2610     pthread_mutex_destroy(&se->lock);
   2611     free(se->cuse_data);
   2612     if (se->fd != -1) {
   2613         close(se->fd);
   2614     }
   2615 
   2616     if (fuse_lowlevel_is_virtio(se)) {
   2617         virtio_session_close(se);
   2618     }
   2619 
   2620     free(se->vu_socket_path);
   2621     se->vu_socket_path = NULL;
   2622 
   2623     g_free(se);
   2624 }
   2625 
   2626 
   2627 struct fuse_session *fuse_session_new(struct fuse_args *args,
   2628                                       const struct fuse_lowlevel_ops *op,
   2629                                       size_t op_size, void *userdata)
   2630 {
   2631     struct fuse_session *se;
   2632 
   2633     if (sizeof(struct fuse_lowlevel_ops) < op_size) {
   2634         fuse_log(
   2635             FUSE_LOG_ERR,
   2636             "fuse: warning: library too old, some operations may not work\n");
   2637         op_size = sizeof(struct fuse_lowlevel_ops);
   2638     }
   2639 
   2640     if (args->argc == 0) {
   2641         fuse_log(FUSE_LOG_ERR,
   2642                  "fuse: empty argv passed to fuse_session_new().\n");
   2643         return NULL;
   2644     }
   2645 
   2646     se = g_try_new0(struct fuse_session, 1);
   2647     if (se == NULL) {
   2648         fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
   2649         goto out1;
   2650     }
   2651     se->fd = -1;
   2652     se->vu_listen_fd = -1;
   2653     se->thread_pool_size = THREAD_POOL_SIZE;
   2654     se->conn.max_write = UINT_MAX;
   2655     se->conn.max_readahead = UINT_MAX;
   2656 
   2657     /* Parse options */
   2658     if (fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1) {
   2659         goto out2;
   2660     }
   2661     if (args->argc == 1 && args->argv[0][0] == '-') {
   2662         fuse_log(FUSE_LOG_ERR,
   2663                  "fuse: warning: argv[0] looks like an option, but "
   2664                  "will be ignored\n");
   2665     } else if (args->argc != 1) {
   2666         int i;
   2667         fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
   2668         for (i = 1; i < args->argc - 1; i++) {
   2669             fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
   2670         }
   2671         fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
   2672         goto out4;
   2673     }
   2674 
   2675     if (!se->vu_socket_path && se->vu_listen_fd < 0) {
   2676         fuse_log(FUSE_LOG_ERR, "fuse: missing --socket-path or --fd option\n");
   2677         goto out4;
   2678     }
   2679     if (se->vu_socket_path && se->vu_listen_fd >= 0) {
   2680         fuse_log(FUSE_LOG_ERR,
   2681                  "fuse: --socket-path and --fd cannot be given together\n");
   2682         goto out4;
   2683     }
   2684     if (se->vu_socket_group && !se->vu_socket_path) {
   2685         fuse_log(FUSE_LOG_ERR,
   2686                  "fuse: --socket-group can only be used with --socket-path\n");
   2687         goto out4;
   2688     }
   2689 
   2690     se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
   2691 
   2692     list_init_req(&se->list);
   2693     list_init_req(&se->interrupts);
   2694     fuse_mutex_init(&se->lock);
   2695     pthread_rwlock_init(&se->init_rwlock, NULL);
   2696 
   2697     memcpy(&se->op, op, op_size);
   2698     se->owner = getuid();
   2699     se->userdata = userdata;
   2700 
   2701     return se;
   2702 
   2703 out4:
   2704     fuse_opt_free_args(args);
   2705 out2:
   2706     g_free(se);
   2707 out1:
   2708     return NULL;
   2709 }
   2710 
   2711 int fuse_session_mount(struct fuse_session *se)
   2712 {
   2713     return virtio_session_mount(se);
   2714 }
   2715 
   2716 int fuse_session_fd(struct fuse_session *se)
   2717 {
   2718     return se->fd;
   2719 }
   2720 
   2721 void fuse_session_unmount(struct fuse_session *se)
   2722 {
   2723 }
   2724 
   2725 int fuse_lowlevel_is_virtio(struct fuse_session *se)
   2726 {
   2727     return !!se->virtio_dev;
   2728 }
   2729 
   2730 void fuse_session_exit(struct fuse_session *se)
   2731 {
   2732     se->exited = 1;
   2733 }
   2734 
   2735 void fuse_session_reset(struct fuse_session *se)
   2736 {
   2737     se->exited = 0;
   2738     se->error = 0;
   2739 }
   2740 
   2741 int fuse_session_exited(struct fuse_session *se)
   2742 {
   2743     return se->exited;
   2744 }