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