"Fossies" - the Fresh Open Source Software Archive

Member "ntfs-3g_ntfsprogs-2017.3.23/libfuse-lite/fuse_lowlevel.c" (23 Mar 2017, 41311 Bytes) of package /linux/misc/ntfs-3g_ntfsprogs-2017.3.23.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fuse_lowlevel.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3g_ntfsprogs-2016.2.22_vs_3g_ntfsprogs-2017.3.23.

    1 /*
    2     FUSE: Filesystem in Userspace
    3     Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
    4 
    5     This program can be distributed under the terms of the GNU LGPLv2.
    6     See the file COPYING.LIB
    7 */
    8 
    9 #include "config.h"
   10 #include "fuse_lowlevel.h"
   11 #include "fuse_kernel.h"
   12 #include "fuse_opt.h"
   13 #include "fuse_i.h"
   14 #include "fuse_misc.h"
   15 #include "fuse_lowlevel_compat.h"
   16 
   17 #include <stdio.h>
   18 #include <stdlib.h>
   19 #include <stddef.h>
   20 #include <string.h>
   21 #include <unistd.h>
   22 #include <limits.h>
   23 #include <errno.h>
   24 
   25 #ifdef HAVE_SYS_TYPES_H
   26 #include <sys/types.h>
   27 #endif
   28 #ifdef MAJOR_IN_MKDEV
   29 #include <sys/mkdev.h>
   30 #endif
   31 #ifdef MAJOR_IN_SYSMACROS
   32 #include <sys/sysmacros.h>
   33 #endif
   34 
   35 #define PARAM(inarg) (((const char *)(inarg)) + sizeof(*(inarg)))
   36 #define OFFSET_MAX 0x7fffffffffffffffLL
   37 
   38 struct fuse_ll;
   39 
   40 struct fuse_req {
   41     struct fuse_ll *f;
   42     uint64_t unique;
   43     int ctr;
   44     pthread_mutex_t lock;
   45     struct fuse_ctx ctx;
   46     struct fuse_chan *ch;
   47     int interrupted;
   48     union {
   49         struct {
   50             uint64_t unique;
   51         } i;
   52         struct {
   53             fuse_interrupt_func_t func;
   54             void *data;
   55         } ni;
   56     } u;
   57     struct fuse_req *next;
   58     struct fuse_req *prev;
   59 };
   60 
   61 struct fuse_ll {
   62     int debug;
   63     int allow_root;
   64     struct fuse_lowlevel_ops op;
   65     int got_init;
   66     void *userdata;
   67     uid_t owner;
   68     struct fuse_conn_info conn;
   69     struct fuse_req list;
   70     struct fuse_req interrupts;
   71     pthread_mutex_t lock;
   72     int got_destroy;
   73 };
   74 
   75 static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
   76 {
   77     attr->ino       = stbuf->st_ino;
   78     attr->mode      = stbuf->st_mode;
   79     attr->nlink     = stbuf->st_nlink;
   80     attr->uid       = stbuf->st_uid;
   81     attr->gid       = stbuf->st_gid;
   82 #if defined(__SOLARIS__) && defined(_LP64)
   83     /* Must pack the device the old way (attr->rdev limited to 32 bits) */
   84     attr->rdev      = ((major(stbuf->st_rdev) & 0x3fff) << 18)
   85             | (minor(stbuf->st_rdev) & 0x3ffff);
   86 #else
   87     attr->rdev      = stbuf->st_rdev;
   88 #endif
   89     attr->size      = stbuf->st_size;
   90     attr->blocks    = stbuf->st_blocks;
   91     attr->atime     = stbuf->st_atime;
   92     attr->mtime     = stbuf->st_mtime;
   93     attr->ctime     = stbuf->st_ctime;
   94     attr->atimensec = ST_ATIM_NSEC(stbuf);
   95     attr->mtimensec = ST_MTIM_NSEC(stbuf);
   96     attr->ctimensec = ST_CTIM_NSEC(stbuf);
   97 #ifdef POSIXACLS
   98     attr->filling = 0; /* JPA trying to be safe */
   99 #endif
  100 }
  101 
  102 static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
  103 {
  104     stbuf->st_mode         = attr->mode;
  105     stbuf->st_uid          = attr->uid;
  106     stbuf->st_gid          = attr->gid;
  107     stbuf->st_size         = attr->size;
  108     stbuf->st_atime        = attr->atime;
  109     stbuf->st_mtime        = attr->mtime;
  110     ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
  111     ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
  112 }
  113 
  114 static  size_t iov_length(const struct iovec *iov, size_t count)
  115 {
  116     size_t seg;
  117     size_t ret = 0;
  118 
  119     for (seg = 0; seg < count; seg++)
  120         ret += iov[seg].iov_len;
  121     return ret;
  122 }
  123 
  124 static void list_init_req(struct fuse_req *req)
  125 {
  126     req->next = req;
  127     req->prev = req;
  128 }
  129 
  130 static void list_del_req(struct fuse_req *req)
  131 {
  132     struct fuse_req *prev = req->prev;
  133     struct fuse_req *next = req->next;
  134     prev->next = next;
  135     next->prev = prev;
  136 }
  137 
  138 static void list_add_req(struct fuse_req *req, struct fuse_req *next)
  139 {
  140     struct fuse_req *prev = next->prev;
  141     req->next = next;
  142     req->prev = prev;
  143     prev->next = req;
  144     next->prev = req;
  145 }
  146 
  147 static void destroy_req(fuse_req_t req)
  148 {
  149     pthread_mutex_destroy(&req->lock);
  150     free(req);
  151 }
  152 
  153 static void free_req(fuse_req_t req)
  154 {
  155     int ctr;
  156     struct fuse_ll *f = req->f;
  157 
  158     pthread_mutex_lock(&req->lock);
  159     req->u.ni.func = NULL;
  160     req->u.ni.data = NULL;
  161     pthread_mutex_unlock(&req->lock);
  162 
  163     pthread_mutex_lock(&f->lock);
  164     list_del_req(req);
  165     ctr = --req->ctr;
  166     pthread_mutex_unlock(&f->lock);
  167     if (!ctr)
  168         destroy_req(req);
  169 }
  170 
  171 static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
  172                           int count)
  173 {
  174     struct fuse_out_header out;
  175     int res;
  176 
  177     if (error <= -1000 || error > 0) {
  178         fprintf(stderr, "fuse: bad error value: %i\n",  error);
  179         error = -ERANGE;
  180     }
  181 
  182     out.unique = req->unique;
  183     out.error = error;
  184     iov[0].iov_base = &out;
  185     iov[0].iov_len = sizeof(struct fuse_out_header);
  186     out.len = iov_length(iov, count);
  187 
  188     if (req->f->debug)
  189         fprintf(stderr, "   unique: %llu, error: %i (%s), outsize: %i\n",
  190                 (unsigned long long) out.unique, out.error,
  191                 strerror(-out.error), out.len);
  192     res = fuse_chan_send(req->ch, iov, count);
  193     free_req(req);
  194 
  195     return res;
  196 }
  197 
  198 static int send_reply(fuse_req_t req, int error, const void *arg,
  199                       size_t argsize)
  200 {
  201     struct iovec iov[2];
  202     int count = 1;
  203     if (argsize) {
  204         /* Note : const qualifier dropped */
  205         iov[1].iov_base = (void *)(uintptr_t) arg;
  206         iov[1].iov_len = argsize;
  207         count++;
  208     }
  209     return send_reply_iov(req, error, iov, count);
  210 }
  211 
  212 #if 0 /* not used */
  213 int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
  214 {
  215     int res;
  216     struct iovec *padded_iov;
  217 
  218     padded_iov = malloc((count + 1) * sizeof(struct iovec));
  219     if (padded_iov == NULL)
  220         return fuse_reply_err(req, -ENOMEM);
  221 
  222     memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
  223     count++;
  224 
  225     res = send_reply_iov(req, 0, padded_iov, count);
  226     free(padded_iov);
  227 
  228     return res;
  229 }
  230 #endif
  231 
  232 size_t fuse_dirent_size(size_t namelen)
  233 {
  234     return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
  235 }
  236 
  237 char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
  238                       off_t off)
  239 {
  240     unsigned namelen = strlen(name);
  241     unsigned entlen = FUSE_NAME_OFFSET + namelen;
  242     unsigned entsize = fuse_dirent_size(namelen);
  243     unsigned padlen = entsize - entlen;
  244     struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
  245 
  246     dirent->ino = stbuf->st_ino;
  247     dirent->off = off;
  248     dirent->namelen = namelen;
  249     dirent->type = (stbuf->st_mode & 0170000) >> 12;
  250     strncpy(dirent->name, name, namelen);
  251     if (padlen)
  252         memset(buf + entlen, 0, padlen);
  253 
  254     return buf + entsize;
  255 }
  256 
  257 size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
  258                          const char *name, const struct stat *stbuf, off_t off)
  259 {
  260     size_t entsize;
  261 
  262     (void) req;
  263     entsize = fuse_dirent_size(strlen(name));
  264     if (entsize <= bufsize && buf)
  265         fuse_add_dirent(buf, name, stbuf, off);
  266     return entsize;
  267 }
  268 
  269 static void convert_statfs(const struct statvfs *stbuf,
  270                            struct fuse_kstatfs *kstatfs)
  271 {
  272     kstatfs->bsize  = stbuf->f_bsize;
  273     kstatfs->frsize = stbuf->f_frsize;
  274     kstatfs->blocks = stbuf->f_blocks;
  275     kstatfs->bfree  = stbuf->f_bfree;
  276     kstatfs->bavail = stbuf->f_bavail;
  277     kstatfs->files  = stbuf->f_files;
  278     kstatfs->ffree  = stbuf->f_ffree;
  279     kstatfs->namelen    = stbuf->f_namemax;
  280 }
  281 
  282 static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
  283 {
  284     return send_reply(req, 0, arg, argsize);
  285 }
  286 
  287 int fuse_reply_err(fuse_req_t req, int err)
  288 {
  289     return send_reply(req, -err, NULL, 0);
  290 }
  291 
  292 void fuse_reply_none(fuse_req_t req)
  293 {
  294     fuse_chan_send(req->ch, NULL, 0);
  295     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 static unsigned int calc_timeout_nsec(double t)
  309 {
  310     unsigned long secs = calc_timeout_sec(t);
  311     double f = t - (double)secs;
  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 static void fill_entry(struct fuse_entry_out *arg,
  321                        const struct fuse_entry_param *e)
  322 {
  323     arg->nodeid = e->ino;
  324     arg->generation = e->generation;
  325     arg->entry_valid = calc_timeout_sec(e->entry_timeout);
  326     arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
  327     arg->attr_valid = calc_timeout_sec(e->attr_timeout);
  328     arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
  329     convert_stat(&e->attr, &arg->attr);
  330 }
  331 
  332 static void fill_open(struct fuse_open_out *arg,
  333                       const struct fuse_file_info *f)
  334 {
  335     arg->fh = f->fh;
  336     if (f->direct_io)
  337         arg->open_flags |= FOPEN_DIRECT_IO;
  338     if (f->keep_cache)
  339         arg->open_flags |= FOPEN_KEEP_CACHE;
  340 }
  341 
  342 int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
  343 {
  344     struct fuse_entry_out arg;
  345 
  346     /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
  347        negative entry */
  348     if (!e->ino && req->f->conn.proto_minor < 4)
  349         return fuse_reply_err(req, ENOENT);
  350 
  351     memset(&arg, 0, sizeof(arg));
  352     fill_entry(&arg, e);
  353     return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12 
  354             ? sizeof(arg) : FUSE_COMPAT_ENTRY_OUT_SIZE));
  355 }
  356 
  357 int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
  358                       const struct fuse_file_info *f)
  359 {
  360     struct {
  361         struct fuse_entry_out e;
  362         struct fuse_open_out o;
  363     } arg;
  364 
  365     memset(&arg, 0, sizeof(arg));
  366     fill_entry(&arg.e, e);
  367     if (req->f->conn.proto_minor < 12) {
  368     fill_open((struct fuse_open_out*)
  369         ((char*)&arg + FUSE_COMPAT_ENTRY_OUT_SIZE), f);
  370     return send_reply_ok(req, &arg,
  371         FUSE_COMPAT_ENTRY_OUT_SIZE + sizeof(struct fuse_open_out));
  372     } else {
  373         fill_open(&arg.o, f);
  374         return send_reply_ok(req, &arg, sizeof(arg));
  375     }
  376 }
  377 
  378 int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
  379                     double attr_timeout)
  380 {
  381     struct fuse_attr_out arg;
  382 
  383     memset(&arg, 0, sizeof(arg));
  384     arg.attr_valid = calc_timeout_sec(attr_timeout);
  385     arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
  386     convert_stat(attr, &arg.attr);
  387 
  388     return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
  389             ? sizeof(arg) : FUSE_COMPAT_FUSE_ATTR_OUT_SIZE));
  390 }
  391 
  392 int fuse_reply_readlink(fuse_req_t req, const char *linkname)
  393 {
  394     return send_reply_ok(req, linkname, strlen(linkname));
  395 }
  396 
  397 int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
  398 {
  399     struct fuse_open_out arg;
  400 
  401     memset(&arg, 0, sizeof(arg));
  402     fill_open(&arg, f);
  403     return send_reply_ok(req, &arg, sizeof(arg));
  404 }
  405 
  406 int fuse_reply_write(fuse_req_t req, size_t count)
  407 {
  408     struct fuse_write_out arg;
  409 
  410     memset(&arg, 0, sizeof(arg));
  411     arg.size = count;
  412 
  413     return send_reply_ok(req, &arg, sizeof(arg));
  414 }
  415 
  416 int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
  417 {
  418     return send_reply_ok(req, buf, size);
  419 }
  420 
  421 int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
  422 {
  423     struct fuse_statfs_out arg;
  424     size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
  425 
  426     memset(&arg, 0, sizeof(arg));
  427     convert_statfs(stbuf, &arg.st);
  428 
  429     return send_reply_ok(req, &arg, size);
  430 }
  431 
  432 int fuse_reply_xattr(fuse_req_t req, size_t count)
  433 {
  434     struct fuse_getxattr_out arg;
  435 
  436     memset(&arg, 0, sizeof(arg));
  437     arg.size = count;
  438 
  439     return send_reply_ok(req, &arg, sizeof(arg));
  440 }
  441 
  442 int fuse_reply_lock(fuse_req_t req, struct flock *lock)
  443 {
  444     struct fuse_lk_out arg;
  445 
  446     memset(&arg, 0, sizeof(arg));
  447     arg.lk.type = lock->l_type;
  448     if (lock->l_type != F_UNLCK) {
  449         arg.lk.start = lock->l_start;
  450         if (lock->l_len == 0)
  451             arg.lk.end = OFFSET_MAX;
  452         else
  453             arg.lk.end = lock->l_start + lock->l_len - 1;
  454     }
  455     arg.lk.pid = lock->l_pid;
  456     return send_reply_ok(req, &arg, sizeof(arg));
  457 }
  458 
  459 int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
  460 {
  461     struct fuse_bmap_out arg;
  462 
  463     memset(&arg, 0, sizeof(arg));
  464     arg.block = idx;
  465 
  466     return send_reply_ok(req, &arg, sizeof(arg));
  467 }
  468 
  469 int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
  470 {
  471     struct fuse_ioctl_out arg;
  472     struct iovec iov[3];
  473     size_t count = 1;
  474 
  475     memset(&arg, 0, sizeof(arg));
  476     arg.result = result;
  477     iov[count].iov_base = &arg;
  478     iov[count].iov_len = sizeof(arg);
  479     count++;
  480 
  481     if (size) {
  482         /* Note : const qualifier dropped */
  483     iov[count].iov_base = (char *)(uintptr_t) buf;
  484     iov[count].iov_len = size;
  485     count++;
  486     }
  487 
  488     return send_reply_iov(req, 0, iov, count);
  489 }
  490 
  491 static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  492 {
  493     const char *name = (const char *) inarg;
  494 
  495     if (req->f->op.lookup)
  496         req->f->op.lookup(req, nodeid, name);
  497     else
  498         fuse_reply_err(req, ENOSYS);
  499 }
  500 
  501 static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  502 {
  503     const struct fuse_forget_in *arg = (const struct fuse_forget_in *) inarg;
  504 
  505     if (req->f->op.forget)
  506         req->f->op.forget(req, nodeid, arg->nlookup);
  507     else
  508         fuse_reply_none(req);
  509 }
  510 
  511 static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  512 {
  513     (void) inarg;
  514 
  515     if (req->f->op.getattr)
  516         req->f->op.getattr(req, nodeid, NULL);
  517     else
  518         fuse_reply_err(req, ENOSYS);
  519 }
  520 
  521 static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  522 {
  523     const struct fuse_setattr_in *arg = (const struct fuse_setattr_in *) inarg;
  524 
  525     if (req->f->op.setattr) {
  526         struct fuse_file_info *fi = NULL;
  527         struct fuse_file_info fi_store;
  528         struct stat stbuf;
  529         memset(&stbuf, 0, sizeof(stbuf));
  530         convert_attr(arg, &stbuf);
  531         if (arg->valid & FATTR_FH) {
  532             memset(&fi_store, 0, sizeof(fi_store));
  533             fi = &fi_store;
  534             fi->fh = arg->fh;
  535             fi->fh_old = fi->fh;
  536         }
  537         req->f->op.setattr(req, nodeid, &stbuf, arg->valid & ~FATTR_FH, fi);
  538     } else
  539         fuse_reply_err(req, ENOSYS);
  540 }
  541 
  542 static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  543 {
  544     const struct fuse_access_in *arg = (const struct fuse_access_in *) inarg;
  545 
  546     if (req->f->op.access)
  547         req->f->op.access(req, nodeid, arg->mask);
  548     else
  549         fuse_reply_err(req, ENOSYS);
  550 }
  551 
  552 static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  553 {
  554     (void) inarg;
  555 
  556     if (req->f->op.readlink)
  557         req->f->op.readlink(req, nodeid);
  558     else
  559         fuse_reply_err(req, ENOSYS);
  560 }
  561 
  562 static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  563 {
  564     const struct fuse_mknod_in *arg = (const struct fuse_mknod_in *) inarg;
  565     const char *name = PARAM(arg);
  566 
  567     if (req->f->conn.proto_minor >= 12)
  568     req->ctx.umask = arg->umask;
  569     else
  570     name = (const char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
  571 
  572     if (req->f->op.mknod) {
  573 #if defined(__SOLARIS__) && defined(_LP64)
  574     /*
  575      * Must unpack the device, as arg->rdev is limited to 32 bits,
  576      * and must have the same format in 32-bit and 64-bit builds.
  577      */
  578     req->f->op.mknod(req, nodeid, name, arg->mode,
  579         makedev((arg->rdev >> 18) & 0x3fff,
  580             arg->rdev & 0x3ffff));
  581 #else
  582     req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
  583 #endif
  584     } else
  585         fuse_reply_err(req, ENOSYS);
  586 }
  587 
  588 static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  589 {
  590     const struct fuse_mkdir_in *arg = (const struct fuse_mkdir_in *) inarg;
  591 
  592     if (req->f->conn.proto_minor >= 12)
  593     req->ctx.umask = arg->umask;
  594 
  595     if (req->f->op.mkdir)
  596         req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
  597     else
  598         fuse_reply_err(req, ENOSYS);
  599 }
  600 
  601 static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  602 {
  603     const char *name = (const char *) inarg;
  604 
  605     if (req->f->op.unlink)
  606         req->f->op.unlink(req, nodeid, name);
  607     else
  608         fuse_reply_err(req, ENOSYS);
  609 }
  610 
  611 static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  612 {
  613     const char *name = (const char *) inarg;
  614 
  615     if (req->f->op.rmdir)
  616         req->f->op.rmdir(req, nodeid, name);
  617     else
  618         fuse_reply_err(req, ENOSYS);
  619 }
  620 
  621 static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  622 {
  623     const char *name = (const char *) inarg;
  624     const char *linkname = ((const char *) inarg) + strlen((const char *) inarg) + 1;
  625 
  626     if (req->f->op.symlink)
  627         req->f->op.symlink(req, linkname, nodeid, name);
  628     else
  629         fuse_reply_err(req, ENOSYS);
  630 }
  631 
  632 static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  633 {
  634     const struct fuse_rename_in *arg = (const struct fuse_rename_in *) inarg;
  635     const char *oldname = PARAM(arg);
  636     const char *newname = oldname + strlen(oldname) + 1;
  637 
  638     if (req->f->op.rename)
  639         req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
  640     else
  641         fuse_reply_err(req, ENOSYS);
  642 }
  643 
  644 static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  645 {
  646     const struct fuse_link_in *arg = (const struct fuse_link_in *) inarg;
  647 
  648     if (req->f->op.link)
  649         req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
  650     else
  651         fuse_reply_err(req, ENOSYS);
  652 }
  653 
  654 static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  655 {
  656     const struct fuse_create_in *arg = (const struct fuse_create_in *) inarg;
  657 
  658     if (req->f->op.create) {
  659         struct fuse_file_info fi;
  660     const char *name = PARAM(arg);
  661 
  662         memset(&fi, 0, sizeof(fi));
  663         fi.flags = arg->flags;
  664 
  665     if (req->f->conn.proto_minor >= 12)
  666         req->ctx.umask = arg->umask;
  667     else
  668         name = (const char *) inarg + sizeof(struct fuse_open_in);
  669 
  670     req->f->op.create(req, nodeid, name, arg->mode, &fi);
  671     } else
  672         fuse_reply_err(req, ENOSYS);
  673 }
  674 
  675 static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  676 {
  677     const struct fuse_open_in *arg = (const struct fuse_open_in *) inarg;
  678     struct fuse_file_info fi;
  679 
  680     memset(&fi, 0, sizeof(fi));
  681     fi.flags = arg->flags;
  682 
  683     if (req->f->op.open)
  684         req->f->op.open(req, nodeid, &fi);
  685     else
  686         fuse_reply_open(req, &fi);
  687 }
  688 
  689 static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  690 {
  691     const struct fuse_read_in *arg = (const struct fuse_read_in *) inarg;
  692 
  693     if (req->f->op.read) {
  694         struct fuse_file_info fi;
  695 
  696         memset(&fi, 0, sizeof(fi));
  697         fi.fh = arg->fh;
  698         fi.fh_old = fi.fh;
  699         req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
  700     } else
  701         fuse_reply_err(req, ENOSYS);
  702 }
  703 
  704 static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  705 {
  706     const struct fuse_write_in *arg = (const struct fuse_write_in *) inarg;
  707     struct fuse_file_info fi;
  708 
  709     memset(&fi, 0, sizeof(fi));
  710     fi.fh = arg->fh;
  711     fi.fh_old = fi.fh;
  712     fi.writepage = arg->write_flags & 1;
  713 
  714     if (req->f->op.write) {
  715     const char *buf;
  716 
  717     if (req->f->conn.proto_minor >= 12)
  718         buf = PARAM(arg);
  719     else
  720         buf = ((const char*)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
  721         req->f->op.write(req, nodeid, buf, arg->size, arg->offset, &fi);
  722     } else
  723         fuse_reply_err(req, ENOSYS);
  724 }
  725 
  726 static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  727 {
  728     const struct fuse_flush_in *arg = (const struct fuse_flush_in *) inarg;
  729     struct fuse_file_info fi;
  730 
  731     memset(&fi, 0, sizeof(fi));
  732     fi.fh = arg->fh;
  733     fi.fh_old = fi.fh;
  734     fi.flush = 1;
  735     if (req->f->conn.proto_minor >= 7)
  736         fi.lock_owner = arg->lock_owner;
  737 
  738     if (req->f->op.flush)
  739         req->f->op.flush(req, nodeid, &fi);
  740     else
  741         fuse_reply_err(req, ENOSYS);
  742 }
  743 
  744 static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  745 {
  746     const struct fuse_release_in *arg = (const struct fuse_release_in *) inarg;
  747     struct fuse_file_info fi;
  748 
  749     memset(&fi, 0, sizeof(fi));
  750     fi.flags = arg->flags;
  751     fi.fh = arg->fh;
  752     fi.fh_old = fi.fh;
  753     if (req->f->conn.proto_minor >= 8) {
  754         fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
  755         fi.lock_owner = arg->lock_owner;
  756     }
  757 
  758     if (req->f->op.release)
  759         req->f->op.release(req, nodeid, &fi);
  760     else
  761         fuse_reply_err(req, 0);
  762 }
  763 
  764 static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  765 {
  766     const struct fuse_fsync_in *arg = (const struct fuse_fsync_in *) inarg;
  767     struct fuse_file_info fi;
  768 
  769     memset(&fi, 0, sizeof(fi));
  770     fi.fh = arg->fh;
  771     fi.fh_old = fi.fh;
  772 
  773     if (req->f->op.fsync)
  774         req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi);
  775     else
  776         fuse_reply_err(req, ENOSYS);
  777 }
  778 
  779 static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  780 {
  781     const struct fuse_open_in *arg = (const struct fuse_open_in *) inarg;
  782     struct fuse_file_info fi;
  783 
  784     memset(&fi, 0, sizeof(fi));
  785     fi.flags = arg->flags;
  786 
  787     if (req->f->op.opendir)
  788         req->f->op.opendir(req, nodeid, &fi);
  789     else
  790         fuse_reply_open(req, &fi);
  791 }
  792 
  793 static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  794 {
  795     const struct fuse_read_in *arg = (const struct fuse_read_in *) inarg;
  796     struct fuse_file_info fi;
  797 
  798     memset(&fi, 0, sizeof(fi));
  799     fi.fh = arg->fh;
  800     fi.fh_old = fi.fh;
  801 
  802     if (req->f->op.readdir)
  803         req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
  804     else
  805         fuse_reply_err(req, ENOSYS);
  806 }
  807 
  808 static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  809 {
  810     const struct fuse_release_in *arg = (const struct fuse_release_in *) inarg;
  811     struct fuse_file_info fi;
  812 
  813     memset(&fi, 0, sizeof(fi));
  814     fi.flags = arg->flags;
  815     fi.fh = arg->fh;
  816     fi.fh_old = fi.fh;
  817 
  818     if (req->f->op.releasedir)
  819         req->f->op.releasedir(req, nodeid, &fi);
  820     else
  821         fuse_reply_err(req, 0);
  822 }
  823 
  824 static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  825 {
  826     const struct fuse_fsync_in *arg = (const struct fuse_fsync_in *) inarg;
  827     struct fuse_file_info fi;
  828 
  829     memset(&fi, 0, sizeof(fi));
  830     fi.fh = arg->fh;
  831     fi.fh_old = fi.fh;
  832 
  833     if (req->f->op.fsyncdir)
  834         req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi);
  835     else
  836         fuse_reply_err(req, ENOSYS);
  837 }
  838 
  839 static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  840 {
  841     (void) nodeid;
  842     (void) inarg;
  843 
  844     if (req->f->op.statfs)
  845         req->f->op.statfs(req, nodeid);
  846     else {
  847         struct statvfs buf = {
  848             .f_namemax = 255,
  849             .f_bsize = 512,
  850         };
  851         fuse_reply_statfs(req, &buf);
  852     }
  853 }
  854 
  855 static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  856 {
  857     const struct fuse_setxattr_in *arg = (const struct fuse_setxattr_in *) inarg;
  858     const char *name = PARAM(arg);
  859     const char *value = name + strlen(name) + 1;
  860 
  861     if (req->f->op.setxattr)
  862         req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
  863     else
  864         fuse_reply_err(req, ENOSYS);
  865 }
  866 
  867 static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  868 {
  869     const struct fuse_getxattr_in *arg = (const struct fuse_getxattr_in *) inarg;
  870 
  871     if (req->f->op.getxattr)
  872         req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
  873     else
  874         fuse_reply_err(req, ENOSYS);
  875 }
  876 
  877 static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  878 {
  879     const struct fuse_getxattr_in *arg = (const struct fuse_getxattr_in *) inarg;
  880 
  881     if (req->f->op.listxattr)
  882         req->f->op.listxattr(req, nodeid, arg->size);
  883     else
  884         fuse_reply_err(req, ENOSYS);
  885 }
  886 
  887 static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  888 {
  889     const char *name = (const char *) inarg;
  890 
  891     if (req->f->op.removexattr)
  892         req->f->op.removexattr(req, nodeid, name);
  893     else
  894         fuse_reply_err(req, ENOSYS);
  895 }
  896 
  897 static void convert_fuse_file_lock(const struct fuse_file_lock *fl,
  898                                    struct flock *flock)
  899 {
  900     memset(flock, 0, sizeof(struct flock));
  901     flock->l_type = fl->type;
  902     flock->l_whence = SEEK_SET;
  903     flock->l_start = fl->start;
  904     if (fl->end == OFFSET_MAX)
  905         flock->l_len = 0;
  906     else
  907         flock->l_len = fl->end - fl->start + 1;
  908     flock->l_pid = fl->pid;
  909 }
  910 
  911 static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  912 {
  913     const struct fuse_lk_in *arg = (const struct fuse_lk_in *) inarg;
  914     struct fuse_file_info fi;
  915     struct flock flock;
  916 
  917     memset(&fi, 0, sizeof(fi));
  918     fi.fh = arg->fh;
  919     fi.lock_owner = arg->owner;
  920 
  921     convert_fuse_file_lock(&arg->lk, &flock);
  922     if (req->f->op.getlk)
  923         req->f->op.getlk(req, nodeid, &fi, &flock);
  924     else
  925         fuse_reply_err(req, ENOSYS);
  926 }
  927 
  928 static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
  929                             const void *inarg, int should_sleep)
  930 {
  931     const struct fuse_lk_in *arg = (const struct fuse_lk_in *) inarg;
  932     struct fuse_file_info fi;
  933     struct flock flock;
  934 
  935     memset(&fi, 0, sizeof(fi));
  936     fi.fh = arg->fh;
  937     fi.lock_owner = arg->owner;
  938 
  939     convert_fuse_file_lock(&arg->lk, &flock);
  940     if (req->f->op.setlk)
  941         req->f->op.setlk(req, nodeid, &fi, &flock, should_sleep);
  942     else
  943         fuse_reply_err(req, ENOSYS);
  944 }
  945 
  946 static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  947 {
  948     do_setlk_common(req, nodeid, inarg, 0);
  949 }
  950 
  951 static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  952 {
  953     do_setlk_common(req, nodeid, inarg, 1);
  954 }
  955 
  956 static int find_interrupted(struct fuse_ll *f, struct fuse_req *req)
  957 {
  958     struct fuse_req *curr;
  959 
  960     for (curr = f->list.next; curr != &f->list; curr = curr->next) {
  961         if (curr->unique == req->u.i.unique) {
  962             curr->ctr++;
  963             pthread_mutex_unlock(&f->lock);
  964 
  965             /* Ugh, ugly locking */
  966             pthread_mutex_lock(&curr->lock);
  967             pthread_mutex_lock(&f->lock);
  968             curr->interrupted = 1;
  969             pthread_mutex_unlock(&f->lock);
  970             if (curr->u.ni.func)
  971                 curr->u.ni.func(curr, curr->u.ni.data);
  972             pthread_mutex_unlock(&curr->lock);
  973 
  974             pthread_mutex_lock(&f->lock);
  975             curr->ctr--;
  976             if (!curr->ctr)
  977                 destroy_req(curr);
  978 
  979             return 1;
  980         }
  981     }
  982     for (curr = f->interrupts.next; curr != &f->interrupts;
  983          curr = curr->next) {
  984         if (curr->u.i.unique == req->u.i.unique)
  985             return 1;
  986     }
  987     return 0;
  988 }
  989 
  990 static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
  991 {
  992     const struct fuse_interrupt_in *arg = (const struct fuse_interrupt_in *) inarg;
  993     struct fuse_ll *f = req->f;
  994 
  995     (void) nodeid;
  996     if (f->debug)
  997         fprintf(stderr, "INTERRUPT: %llu\n", (unsigned long long) arg->unique);
  998 
  999     req->u.i.unique = arg->unique;
 1000 
 1001     pthread_mutex_lock(&f->lock);
 1002     if (find_interrupted(f, req))
 1003         destroy_req(req);
 1004     else
 1005         list_add_req(req, &f->interrupts);
 1006     pthread_mutex_unlock(&f->lock);
 1007 }
 1008 
 1009 static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req)
 1010 {
 1011     struct fuse_req *curr;
 1012 
 1013     for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) {
 1014         if (curr->u.i.unique == req->unique) {
 1015             req->interrupted = 1;
 1016             list_del_req(curr);
 1017             free(curr);
 1018             return NULL;
 1019         }
 1020     }
 1021     curr = f->interrupts.next;
 1022     if (curr != &f->interrupts) {
 1023         list_del_req(curr);
 1024         list_init_req(curr);
 1025         return curr;
 1026     } else
 1027         return NULL;
 1028 }
 1029 
 1030 static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 1031 {
 1032     const struct fuse_bmap_in *arg = (const struct fuse_bmap_in *) inarg;
 1033 
 1034     if (req->f->op.bmap)
 1035         req->f->op.bmap(req, nodeid, arg->blocksize, arg->block);
 1036     else
 1037         fuse_reply_err(req, ENOSYS);
 1038 }
 1039 
 1040 static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 1041 {
 1042     const struct fuse_ioctl_in *arg = (const struct fuse_ioctl_in *) inarg;
 1043     unsigned int flags = arg->flags;
 1044     const void *in_buf = arg->in_size ? PARAM(arg) : NULL;
 1045     struct fuse_file_info fi;
 1046 
 1047     if (flags & FUSE_IOCTL_DIR &&
 1048         !(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) {
 1049         fuse_reply_err(req, ENOTTY);
 1050         return;
 1051     }
 1052 
 1053     memset(&fi, 0, sizeof(fi));
 1054     fi.fh = arg->fh;
 1055 
 1056 /* TODO JPA (need req->ioctl_64bit in obscure fuse_req_t)
 1057 // probably a 64 bit ioctl on a 32-bit cpu
 1058 // this is to forward a request from the kernel
 1059     if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 &&
 1060         !(flags & FUSE_IOCTL_32BIT)) {
 1061         req->ioctl_64bit = 1;
 1062     }
 1063 */
 1064 
 1065     if (req->f->op.ioctl)
 1066         req->f->op.ioctl(req, nodeid, arg->cmd,
 1067                  (void *)(uintptr_t)arg->arg, &fi, flags,
 1068                  in_buf, arg->in_size, arg->out_size);
 1069     else
 1070         fuse_reply_err(req, ENOSYS);
 1071 }
 1072 
 1073 static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 1074 {
 1075     const struct fuse_init_in *arg = (const struct fuse_init_in *) inarg;
 1076     struct fuse_init_out outarg;
 1077     struct fuse_ll *f = req->f;
 1078     size_t bufsize = fuse_chan_bufsize(req->ch);
 1079 
 1080     (void) nodeid;
 1081     if (f->debug) {
 1082         fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor);
 1083         if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
 1084             fprintf(stderr, "flags=0x%08x\n", arg->flags);
 1085             fprintf(stderr, "max_readahead=0x%08x\n", arg->max_readahead);
 1086         }
 1087     }
 1088     f->conn.proto_major = arg->major;
 1089     f->conn.proto_minor = arg->minor;
 1090 
 1091     if (arg->major < 7) {
 1092         fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
 1093                 arg->major, arg->minor);
 1094         fuse_reply_err(req, EPROTO);
 1095         return;
 1096     }
 1097 
 1098     if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
 1099         if (f->conn.async_read)
 1100             f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
 1101         if (arg->max_readahead < f->conn.max_readahead)
 1102             f->conn.max_readahead = arg->max_readahead;
 1103 #ifdef POSIXACLS
 1104     if (arg->flags & FUSE_DONT_MASK)
 1105         f->conn.capable |= FUSE_CAP_DONT_MASK;
 1106     if (arg->flags & FUSE_POSIX_ACL)
 1107         f->conn.capable |= FUSE_CAP_POSIX_ACL;
 1108 #endif
 1109     if (arg->flags & FUSE_BIG_WRITES)
 1110         f->conn.capable |= FUSE_CAP_BIG_WRITES;
 1111     if (arg->flags & FUSE_HAS_IOCTL_DIR)
 1112         f->conn.capable |= FUSE_CAP_IOCTL_DIR;
 1113     } else {
 1114         f->conn.async_read = 0;
 1115         f->conn.max_readahead = 0;
 1116     }
 1117 
 1118     if (bufsize < FUSE_MIN_READ_BUFFER) {
 1119         fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
 1120                 bufsize);
 1121         bufsize = FUSE_MIN_READ_BUFFER;
 1122     }
 1123 
 1124     bufsize -= 4096;
 1125     if (bufsize < f->conn.max_write)
 1126         f->conn.max_write = bufsize;
 1127 
 1128     f->got_init = 1;
 1129     if (f->op.init)
 1130         f->op.init(f->userdata, &f->conn);
 1131 
 1132     memset(&outarg, 0, sizeof(outarg));
 1133     outarg.major = FUSE_KERNEL_VERSION;
 1134     /*
 1135      * Suggest using protocol 7.18 when available, and fallback
 1136      * to 7.12 or even earlier when running on an old kernel.
 1137      * Protocol 7.12 has the ability to process the umask
 1138      * conditionnally (as needed if POSIXACLS is set)
 1139      * Protocol 7.18 has the ability to process the ioctls
 1140      */
 1141     if (arg->major > 7 || (arg->major == 7 && arg->minor >= 18)) {
 1142         outarg.minor = FUSE_KERNEL_MINOR_VERSION;
 1143         if (f->conn.want & FUSE_CAP_IOCTL_DIR)
 1144         outarg.flags |= FUSE_HAS_IOCTL_DIR;
 1145 #ifdef POSIXACLS
 1146         if (f->conn.want & FUSE_CAP_DONT_MASK)
 1147         outarg.flags |= FUSE_DONT_MASK;
 1148         if (f->conn.want & FUSE_CAP_POSIX_ACL)
 1149         outarg.flags |= FUSE_POSIX_ACL;
 1150 #endif
 1151     } else {
 1152     /* Never use a version more recent than supported by the kernel */
 1153     if ((arg->major < FUSE_KERNEL_MAJOR_FALLBACK)
 1154         || ((arg->major == FUSE_KERNEL_MAJOR_FALLBACK)
 1155         && (arg->minor < FUSE_KERNEL_MINOR_FALLBACK))) {
 1156         outarg.major = arg->major;
 1157         outarg.minor = arg->minor;
 1158     } else {
 1159         outarg.major = FUSE_KERNEL_MAJOR_FALLBACK;
 1160         outarg.minor = FUSE_KERNEL_MINOR_FALLBACK;
 1161 #ifdef POSIXACLS
 1162         if (f->conn.want & FUSE_CAP_DONT_MASK)
 1163         outarg.flags |= FUSE_DONT_MASK;
 1164         if (f->conn.want & FUSE_CAP_POSIX_ACL)
 1165         outarg.flags |= FUSE_POSIX_ACL;
 1166 #endif
 1167         }
 1168     }
 1169     if (f->conn.async_read)
 1170         outarg.flags |= FUSE_ASYNC_READ;
 1171     if (f->op.getlk && f->op.setlk)
 1172         outarg.flags |= FUSE_POSIX_LOCKS;
 1173     if (f->conn.want & FUSE_CAP_BIG_WRITES)
 1174     outarg.flags |= FUSE_BIG_WRITES;
 1175     outarg.max_readahead = f->conn.max_readahead;
 1176     outarg.max_write = f->conn.max_write;
 1177 
 1178     if (f->debug) {
 1179         fprintf(stderr, "   INIT: %u.%u\n", outarg.major, outarg.minor);
 1180         fprintf(stderr, "   flags=0x%08x\n", outarg.flags);
 1181         fprintf(stderr, "   max_readahead=0x%08x\n", outarg.max_readahead);
 1182         fprintf(stderr, "   max_write=0x%08x\n", outarg.max_write);
 1183     }
 1184 
 1185     send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
 1186 }
 1187 
 1188 static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
 1189 {
 1190     struct fuse_ll *f = req->f;
 1191 
 1192     (void) nodeid;
 1193     (void) inarg;
 1194 
 1195     f->got_destroy = 1;
 1196     if (f->op.destroy)
 1197         f->op.destroy(f->userdata);
 1198 
 1199     send_reply_ok(req, NULL, 0);
 1200 }
 1201 
 1202 void *fuse_req_userdata(fuse_req_t req)
 1203 {
 1204     return req->f->userdata;
 1205 }
 1206 
 1207 const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
 1208 {
 1209     return &req->ctx;
 1210 }
 1211 
 1212 void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
 1213                              void *data)
 1214 {
 1215     pthread_mutex_lock(&req->lock);
 1216     req->u.ni.func = func;
 1217     req->u.ni.data = data;
 1218     if (req->interrupted && func)
 1219         func(req, data);
 1220     pthread_mutex_unlock(&req->lock);
 1221 }
 1222 
 1223 int fuse_req_interrupted(fuse_req_t req)
 1224 {
 1225     int interrupted;
 1226 
 1227     pthread_mutex_lock(&req->f->lock);
 1228     interrupted = req->interrupted;
 1229     pthread_mutex_unlock(&req->f->lock);
 1230 
 1231     return interrupted;
 1232 }
 1233 
 1234 static struct {
 1235     void (*func)(fuse_req_t, fuse_ino_t, const void *);
 1236     const char *name;
 1237 } fuse_ll_ops[] = {
 1238     [FUSE_LOOKUP]      = { do_lookup,      "LOOKUP"      },
 1239     [FUSE_FORGET]      = { do_forget,      "FORGET"      },
 1240     [FUSE_GETATTR]     = { do_getattr,     "GETATTR"     },
 1241     [FUSE_SETATTR]     = { do_setattr,     "SETATTR"     },
 1242     [FUSE_READLINK]    = { do_readlink,    "READLINK"    },
 1243     [FUSE_SYMLINK]     = { do_symlink,     "SYMLINK"     },
 1244     [FUSE_MKNOD]       = { do_mknod,       "MKNOD"       },
 1245     [FUSE_MKDIR]       = { do_mkdir,       "MKDIR"       },
 1246     [FUSE_UNLINK]      = { do_unlink,      "UNLINK"      },
 1247     [FUSE_RMDIR]       = { do_rmdir,       "RMDIR"       },
 1248     [FUSE_RENAME]      = { do_rename,      "RENAME"      },
 1249     [FUSE_LINK]        = { do_link,        "LINK"        },
 1250     [FUSE_OPEN]        = { do_open,        "OPEN"        },
 1251     [FUSE_READ]        = { do_read,        "READ"        },
 1252     [FUSE_WRITE]       = { do_write,       "WRITE"       },
 1253     [FUSE_STATFS]      = { do_statfs,      "STATFS"      },
 1254     [FUSE_RELEASE]     = { do_release,     "RELEASE"     },
 1255     [FUSE_FSYNC]       = { do_fsync,       "FSYNC"       },
 1256     [FUSE_SETXATTR]    = { do_setxattr,    "SETXATTR"    },
 1257     [FUSE_GETXATTR]    = { do_getxattr,    "GETXATTR"    },
 1258     [FUSE_LISTXATTR]   = { do_listxattr,   "LISTXATTR"   },
 1259     [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
 1260     [FUSE_FLUSH]       = { do_flush,       "FLUSH"       },
 1261     [FUSE_INIT]        = { do_init,        "INIT"        },
 1262     [FUSE_OPENDIR]     = { do_opendir,     "OPENDIR"     },
 1263     [FUSE_READDIR]     = { do_readdir,     "READDIR"     },
 1264     [FUSE_RELEASEDIR]  = { do_releasedir,  "RELEASEDIR"  },
 1265     [FUSE_FSYNCDIR]    = { do_fsyncdir,    "FSYNCDIR"    },
 1266     [FUSE_GETLK]       = { do_getlk,       "GETLK"       },
 1267     [FUSE_SETLK]       = { do_setlk,       "SETLK"       },
 1268     [FUSE_SETLKW]      = { do_setlkw,      "SETLKW"      },
 1269     [FUSE_ACCESS]      = { do_access,      "ACCESS"      },
 1270     [FUSE_CREATE]      = { do_create,      "CREATE"      },
 1271     [FUSE_INTERRUPT]   = { do_interrupt,   "INTERRUPT"   },
 1272     [FUSE_BMAP]        = { do_bmap,        "BMAP"        },
 1273     [FUSE_IOCTL]       = { do_ioctl,       "IOCTL"       },
 1274     [FUSE_DESTROY]     = { do_destroy,     "DESTROY"     },
 1275 };
 1276 
 1277 #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
 1278 
 1279 static const char *opname(enum fuse_opcode opcode)
 1280 {
 1281     if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
 1282         return "???";
 1283     else
 1284         return fuse_ll_ops[opcode].name;
 1285 }
 1286 
 1287 static void fuse_ll_process(void *data, const char *buf, size_t len,
 1288                      struct fuse_chan *ch)
 1289 {
 1290     struct fuse_ll *f = (struct fuse_ll *) data;
 1291     const struct fuse_in_header *in = (const struct fuse_in_header *) buf;
 1292     const void *inarg = buf + sizeof(struct fuse_in_header);
 1293     struct fuse_req *req;
 1294 
 1295     if (f->debug)
 1296         fprintf(stderr, "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n",
 1297                 (unsigned long long) in->unique,
 1298                 opname((enum fuse_opcode) in->opcode), in->opcode,
 1299                 (unsigned long) in->nodeid, len);
 1300 
 1301     req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
 1302     if (req == NULL) {
 1303         fprintf(stderr, "fuse: failed to allocate request\n");
 1304         return;
 1305     }
 1306 
 1307     req->f = f;
 1308     req->unique = in->unique;
 1309     req->ctx.uid = in->uid;
 1310     req->ctx.gid = in->gid;
 1311     req->ctx.pid = in->pid;
 1312     req->ch = ch;
 1313     req->ctr = 1;
 1314     list_init_req(req);
 1315     fuse_mutex_init(&req->lock);
 1316 
 1317     if (!f->got_init && in->opcode != FUSE_INIT)
 1318         fuse_reply_err(req, EIO);
 1319     else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
 1320              in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
 1321              in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
 1322              in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
 1323              in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
 1324         fuse_reply_err(req, EACCES);
 1325     } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
 1326         fuse_reply_err(req, ENOSYS);
 1327     else {
 1328         if (in->opcode != FUSE_INTERRUPT) {
 1329             struct fuse_req *intr;
 1330             pthread_mutex_lock(&f->lock);
 1331             intr = check_interrupt(f, req);
 1332             list_add_req(req, &f->list);
 1333             pthread_mutex_unlock(&f->lock);
 1334             if (intr)
 1335                 fuse_reply_err(intr, EAGAIN);
 1336         }
 1337         fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
 1338     }
 1339 }
 1340 
 1341 enum {
 1342     KEY_HELP,
 1343     KEY_VERSION,
 1344 };
 1345 
 1346 static struct fuse_opt fuse_ll_opts[] = {
 1347     { "debug", offsetof(struct fuse_ll, debug), 1 },
 1348     { "-d", offsetof(struct fuse_ll, debug), 1 },
 1349     { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
 1350     { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
 1351     { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
 1352     { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
 1353     { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
 1354     FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
 1355     FUSE_OPT_KEY("-h", KEY_HELP),
 1356     FUSE_OPT_KEY("--help", KEY_HELP),
 1357     FUSE_OPT_KEY("-V", KEY_VERSION),
 1358     FUSE_OPT_KEY("--version", KEY_VERSION),
 1359     FUSE_OPT_END
 1360 };
 1361 
 1362 static void fuse_ll_version(void)
 1363 {
 1364     fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
 1365             FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
 1366 }
 1367 
 1368 static void fuse_ll_help(void)
 1369 {
 1370     fprintf(stderr,
 1371 "    -o max_write=N         set maximum size of write requests\n"
 1372 "    -o max_readahead=N     set maximum readahead\n"
 1373 "    -o async_read          perform reads asynchronously (default)\n"
 1374 "    -o sync_read           perform reads synchronously\n");
 1375 }
 1376 
 1377 static int fuse_ll_opt_proc(void *data, const char *arg, int key,
 1378                             struct fuse_args *outargs)
 1379 {
 1380     (void) data; (void) outargs;
 1381 
 1382     switch (key) {
 1383     case KEY_HELP:
 1384         fuse_ll_help();
 1385         break;
 1386 
 1387     case KEY_VERSION:
 1388         fuse_ll_version();
 1389         break;
 1390 
 1391     default:
 1392         fprintf(stderr, "fuse: unknown option `%s'\n", arg);
 1393     }
 1394 
 1395     return -1;
 1396 }
 1397 
 1398 #ifdef __SOLARIS__
 1399 
 1400 int fuse_lowlevel_is_lib_option(const char *opt)
 1401 {
 1402     return fuse_opt_match(fuse_ll_opts, opt);
 1403 }
 1404 
 1405 #endif /* __SOLARIS__ */
 1406 
 1407 static void fuse_ll_destroy(void *data)
 1408 {
 1409     struct fuse_ll *f = (struct fuse_ll *) data;
 1410 
 1411     if (f->got_init && !f->got_destroy) {
 1412         if (f->op.destroy)
 1413             f->op.destroy(f->userdata);
 1414     }
 1415 
 1416     pthread_mutex_destroy(&f->lock);
 1417     free(f);
 1418 }
 1419 
 1420 struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
 1421                        const struct fuse_lowlevel_ops *op,
 1422                                        size_t op_size, void *userdata)
 1423 {
 1424     struct fuse_ll *f;
 1425     struct fuse_session *se;
 1426     struct fuse_session_ops sop = {
 1427         .process = fuse_ll_process,
 1428         .destroy = fuse_ll_destroy,
 1429     };
 1430 
 1431     if (sizeof(struct fuse_lowlevel_ops) < op_size) {
 1432         fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
 1433         op_size = sizeof(struct fuse_lowlevel_ops);
 1434     }
 1435 
 1436     f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
 1437     if (f == NULL) {
 1438         fprintf(stderr, "fuse: failed to allocate fuse object\n");
 1439         goto out;
 1440     }
 1441 
 1442     f->conn.async_read = 1;
 1443     f->conn.max_write = UINT_MAX;
 1444     f->conn.max_readahead = UINT_MAX;
 1445     list_init_req(&f->list);
 1446     list_init_req(&f->interrupts);
 1447     fuse_mutex_init(&f->lock);
 1448 
 1449     if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
 1450         goto out_free;
 1451 
 1452     memcpy(&f->op, op, op_size);
 1453     f->owner = getuid();
 1454     f->userdata = userdata;
 1455 
 1456     se = fuse_session_new(&sop, f);
 1457     if (!se)
 1458         goto out_free;
 1459 
 1460     return se;
 1461 
 1462  out_free:
 1463     free(f);
 1464  out:
 1465     return NULL;
 1466 }