libfuse
fuse_lowlevel.c
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 LGPL2.txt
10*/
11
12#define _GNU_SOURCE
13
14#include "fuse_config.h"
15#include "fuse_i.h"
16#include "fuse_kernel.h"
17#include "fuse_opt.h"
18#include "fuse_misc.h"
19#include "mount_util.h"
20#include "util.h"
21#include "fuse_uring_i.h"
22
23#include <pthread.h>
24#include <stdatomic.h>
25#include <stdint.h>
26#include <inttypes.h>
27#include <stdbool.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <stddef.h>
31#include <stdalign.h>
32#include <string.h>
33#include <unistd.h>
34#include <limits.h>
35#include <errno.h>
36#include <assert.h>
37#include <sys/file.h>
38#include <sys/ioctl.h>
39#include <stdalign.h>
40
41#ifdef USDT_ENABLED
42#include "usdt.h"
43#endif
44
45#ifndef F_LINUX_SPECIFIC_BASE
46#define F_LINUX_SPECIFIC_BASE 1024
47#endif
48#ifndef F_SETPIPE_SZ
49#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
50#endif
51
52#ifndef O_CLOEXEC
53#define O_CLOEXEC 0
54#endif
55
56#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
57#define OFFSET_MAX 0x7fffffffffffffffLL
58
59struct fuse_pollhandle {
60 uint64_t kh;
61 struct fuse_session *se;
62};
63
64static size_t pagesize;
65
66static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
67{
68 pagesize = getpagesize();
69}
70
71#ifdef USDT_ENABLED
72/* tracepoints */
73static void trace_request_receive(int err)
74{
75 USDT(libfuse, request_receive, err);
76}
77
78static void trace_request_process(unsigned int opcode, unsigned int unique)
79{
80 USDT(libfuse, request_process, opcode, unique);
81}
82
83static void trace_request_reply(uint64_t unique, unsigned int len,
84 int error, int reply_err)
85{
86 USDT(libfuse, request_reply, unique, len, error, reply_err);
87}
88#else
89static void trace_request_receive(int err)
90{
91 (void)err;
92}
93
94static void trace_request_process(unsigned int opcode, unsigned int unique)
95{
96 (void)opcode;
97 (void)unique;
98}
99
100static void trace_request_reply(uint64_t unique, unsigned int len,
101 int error, int reply_err)
102{
103 (void)unique;
104 (void)len;
105 (void)error;
106 (void)reply_err;
107}
108#endif
109
110static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
111{
112 attr->ino = stbuf->st_ino;
113 attr->mode = stbuf->st_mode;
114 attr->nlink = stbuf->st_nlink;
115 attr->uid = stbuf->st_uid;
116 attr->gid = stbuf->st_gid;
117 attr->rdev = stbuf->st_rdev;
118 attr->size = stbuf->st_size;
119 attr->blksize = stbuf->st_blksize;
120 attr->blocks = stbuf->st_blocks;
121 attr->atime = stbuf->st_atime;
122 attr->mtime = stbuf->st_mtime;
123 attr->ctime = stbuf->st_ctime;
124 attr->atimensec = ST_ATIM_NSEC(stbuf);
125 attr->mtimensec = ST_MTIM_NSEC(stbuf);
126 attr->ctimensec = ST_CTIM_NSEC(stbuf);
127}
128
129static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
130{
131 stbuf->st_mode = attr->mode;
132 stbuf->st_uid = attr->uid;
133 stbuf->st_gid = attr->gid;
134 stbuf->st_size = attr->size;
135 stbuf->st_atime = attr->atime;
136 stbuf->st_mtime = attr->mtime;
137 stbuf->st_ctime = attr->ctime;
138 ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
139 ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
140 ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
141}
142
143static size_t iov_length(const struct iovec *iov, size_t count)
144{
145 size_t seg;
146 size_t ret = 0;
147
148 for (seg = 0; seg < count; seg++)
149 ret += iov[seg].iov_len;
150 return ret;
151}
152
153void list_init_req(struct fuse_req *req)
154{
155 req->next = req;
156 req->prev = req;
157}
158
159static void list_del_req(struct fuse_req *req)
160{
161 struct fuse_req *prev = req->prev;
162 struct fuse_req *next = req->next;
163 prev->next = next;
164 next->prev = prev;
165}
166
167static void list_add_req(struct fuse_req *req, struct fuse_req *next)
168{
169 struct fuse_req *prev = next->prev;
170 req->next = next;
171 req->prev = prev;
172 prev->next = req;
173 next->prev = req;
174}
175
176static void destroy_req(fuse_req_t req)
177{
178 if (req->flags.is_uring) {
179 fuse_log(FUSE_LOG_ERR, "Refusing to destruct uring req\n");
180 return;
181 }
182 assert(req->ch == NULL);
183 pthread_mutex_destroy(&req->lock);
184 free(req);
185}
186
187void fuse_free_req(fuse_req_t req)
188{
189 int ctr;
190 struct fuse_session *se = req->se;
191
192 /* XXX: for now no support for interrupts with io-uring
193 * It actually might work already, though. But then would add
194 * a lock across ring queues.
195 */
196 if (se->conn.no_interrupt || req->flags.is_uring) {
197 ctr = --req->ref_cnt;
198 fuse_chan_put(req->ch);
199 req->ch = NULL;
200 } else {
201 pthread_mutex_lock(&se->lock);
202 req->u.ni.func = NULL;
203 req->u.ni.data = NULL;
204 list_del_req(req);
205 ctr = --req->ref_cnt;
206 fuse_chan_put(req->ch);
207 req->ch = NULL;
208 pthread_mutex_unlock(&se->lock);
209 }
210 if (!ctr)
211 destroy_req(req);
212}
213
214static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
215{
216 struct fuse_req *req;
217
218 req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
219 if (req == NULL) {
220 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
221 } else {
222 req->se = se;
223 req->ref_cnt = 1;
224 list_init_req(req);
225 pthread_mutex_init(&req->lock, NULL);
226 }
227
228 return req;
229}
230
231/*
232 * Send data to fuse-kernel using an fd of the fuse device.
233 */
234static int fuse_write_msg_dev(struct fuse_session *se, struct fuse_chan *ch,
235 struct iovec *iov, int count)
236{
237 ssize_t res;
238 int err;
239
240 if (se->io != NULL)
241
242 /* se->io->writev is never NULL if se->io is not NULL as
243 * specified by fuse_session_custom_io()
244 */
245 res = se->io->writev(ch ? ch->fd : se->fd, iov, count,
246 se->userdata);
247 else
248 res = writev(ch ? ch->fd : se->fd, iov, count);
249
250 if (res == -1) {
251 /* ENOENT means the operation was interrupted */
252 err = errno;
253 if (!fuse_session_exited(se) && err != ENOENT)
254 perror("fuse: writing device");
255 return -err;
256 }
257
258 return 0;
259}
260
261static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
262 struct iovec *iov, int count, fuse_req_t req)
263{
264 struct fuse_out_header *out = iov[0].iov_base;
265 int err;
266 bool is_uring = req && req->flags.is_uring ? true : false;
267
268 if (!is_uring)
269 assert(se != NULL);
270 out->len = iov_length(iov, count);
271
272 if (se->debug) {
273 if (out->unique == 0) {
274 fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
275 out->error, out->len);
276 } else if (out->error) {
277 fuse_log(FUSE_LOG_DEBUG,
278 " unique: %llu, error: %i (%s), outsize: %i\n",
279 (unsigned long long) out->unique, out->error,
280 strerror(-out->error), out->len);
281 } else {
282 fuse_log(FUSE_LOG_DEBUG,
283 " unique: %llu, success, outsize: %i\n",
284 (unsigned long long) out->unique, out->len);
285 }
286 }
287
288 if (is_uring)
289 err = fuse_send_msg_uring(req, iov, count);
290 else
291 err = fuse_write_msg_dev(se, ch, iov, count);
292
293 trace_request_reply(out->unique, out->len, out->error, err);
294 return err;
295}
296
297int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
298 int count)
299{
300 struct fuse_out_header out;
301
302#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 32
303 const char *str = strerrordesc_np(error * -1);
304 if ((str == NULL && error != 0) || error > 0) {
305#else
306 if (error <= -1000 || error > 0) {
307#endif
308 fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
309 error = -ERANGE;
310 }
311
312 out.unique = req->unique;
313 out.error = error;
314
315 iov[0].iov_base = &out;
316 iov[0].iov_len = sizeof(struct fuse_out_header);
317
318 return fuse_send_msg(req->se, req->ch, iov, count, req);
319}
320
321static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
322 int count)
323{
324 int res;
325
326 res = fuse_send_reply_iov_nofree(req, error, iov, count);
327 fuse_free_req(req);
328 return res;
329}
330
331static int send_reply(fuse_req_t req, int error, const void *arg,
332 size_t argsize)
333{
334 if (req->flags.is_uring)
335 return send_reply_uring(req, error, arg, argsize);
336
337 struct iovec iov[2];
338 int count = 1;
339 if (argsize) {
340 iov[1].iov_base = (void *) arg;
341 iov[1].iov_len = argsize;
342 count++;
343 }
344 return send_reply_iov(req, error, iov, count);
345}
346
347int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
348{
349 int res;
350 struct iovec *padded_iov;
351
352 padded_iov = malloc((count + 1) * sizeof(struct iovec));
353 if (padded_iov == NULL)
354 return fuse_reply_err(req, ENOMEM);
355
356 memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
357 count++;
358
359 res = send_reply_iov(req, 0, padded_iov, count);
360 free(padded_iov);
361
362 return res;
363}
364
365
366/* `buf` is allowed to be empty so that the proper size may be
367 allocated by the caller */
368size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
369 const char *name, const struct stat *stbuf, off_t off)
370{
371 (void)req;
372 size_t namelen;
373 size_t entlen;
374 size_t entlen_padded;
375 struct fuse_dirent *dirent;
376
377 namelen = strlen(name);
378 entlen = FUSE_NAME_OFFSET + namelen;
379 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
380
381 if ((buf == NULL) || (entlen_padded > bufsize))
382 return entlen_padded;
383
384 dirent = (struct fuse_dirent*) buf;
385 dirent->ino = stbuf->st_ino;
386 dirent->off = off;
387 dirent->namelen = namelen;
388 dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
389 memcpy(dirent->name, name, namelen);
390 memset(dirent->name + namelen, 0, entlen_padded - entlen);
391
392 return entlen_padded;
393}
394
395static void convert_statfs(const struct statvfs *stbuf,
396 struct fuse_kstatfs *kstatfs)
397{
398 kstatfs->bsize = stbuf->f_bsize;
399 kstatfs->frsize = stbuf->f_frsize;
400 kstatfs->blocks = stbuf->f_blocks;
401 kstatfs->bfree = stbuf->f_bfree;
402 kstatfs->bavail = stbuf->f_bavail;
403 kstatfs->files = stbuf->f_files;
404 kstatfs->ffree = stbuf->f_ffree;
405 kstatfs->namelen = stbuf->f_namemax;
406}
407
408static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
409{
410 return send_reply(req, 0, arg, argsize);
411}
412
413int fuse_reply_err(fuse_req_t req, int err)
414{
415 return send_reply(req, -err, NULL, 0);
416}
417
419{
420 if (req->flags.is_uring) {
421 send_reply_uring(req, 0, NULL, 0);
422 return;
423 }
424 fuse_free_req(req);
425}
426
427static unsigned long calc_timeout_sec(double t)
428{
429 if (t > (double) ULONG_MAX)
430 return ULONG_MAX;
431 else if (t < 0.0)
432 return 0;
433 else
434 return (unsigned long) t;
435}
436
437static unsigned int calc_timeout_nsec(double t)
438{
439 double f = t - (double) calc_timeout_sec(t);
440 if (f < 0.0)
441 return 0;
442 else if (f >= 0.999999999)
443 return 999999999;
444 else
445 return (unsigned int) (f * 1.0e9);
446}
447
448static void fill_entry(struct fuse_entry_out *arg,
449 const struct fuse_entry_param *e)
450{
451 arg->nodeid = e->ino;
452 arg->generation = e->generation;
453 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
454 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
455 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
456 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
457 convert_stat(&e->attr, &arg->attr);
458}
459
460/* `buf` is allowed to be empty so that the proper size may be
461 allocated by the caller */
462size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
463 const char *name,
464 const struct fuse_entry_param *e, off_t off)
465{
466 (void)req;
467 size_t namelen;
468 size_t entlen;
469 size_t entlen_padded;
470
471 namelen = strlen(name);
472 entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
473 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
474 if ((buf == NULL) || (entlen_padded > bufsize))
475 return entlen_padded;
476
477 struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
478 memset(&dp->entry_out, 0, sizeof(dp->entry_out));
479 fill_entry(&dp->entry_out, e);
480
481 struct fuse_dirent *dirent = &dp->dirent;
482 dirent->ino = e->attr.st_ino;
483 dirent->off = off;
484 dirent->namelen = namelen;
485 dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
486 memcpy(dirent->name, name, namelen);
487 memset(dirent->name + namelen, 0, entlen_padded - entlen);
488
489 return entlen_padded;
490}
491
492static void fill_open(struct fuse_open_out *arg,
493 const struct fuse_file_info *f)
494{
495 arg->fh = f->fh;
496 if (f->backing_id > 0) {
497 arg->backing_id = f->backing_id;
498 arg->open_flags |= FOPEN_PASSTHROUGH;
499 }
500 if (f->direct_io)
501 arg->open_flags |= FOPEN_DIRECT_IO;
502 if (f->keep_cache)
503 arg->open_flags |= FOPEN_KEEP_CACHE;
504 if (f->cache_readdir)
505 arg->open_flags |= FOPEN_CACHE_DIR;
506 if (f->nonseekable)
507 arg->open_flags |= FOPEN_NONSEEKABLE;
508 if (f->noflush)
509 arg->open_flags |= FOPEN_NOFLUSH;
511 arg->open_flags |= FOPEN_PARALLEL_DIRECT_WRITES;
512}
513
515{
516 struct fuse_entry_out arg;
517 size_t size = req->se->conn.proto_minor < 9 ?
518 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
519
520 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
521 negative entry */
522 if (!e->ino && req->se->conn.proto_minor < 4)
523 return fuse_reply_err(req, ENOENT);
524
525 memset(&arg, 0, sizeof(arg));
526 fill_entry(&arg, e);
527 return send_reply_ok(req, &arg, size);
528}
529
531 const struct fuse_file_info *f)
532{
533 alignas(uint64_t) char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
534 size_t entrysize = req->se->conn.proto_minor < 9 ?
535 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
536 struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
537 struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
538
539 memset(buf, 0, sizeof(buf));
540 fill_entry(earg, e);
541 fill_open(oarg, f);
542 return send_reply_ok(req, buf,
543 entrysize + sizeof(struct fuse_open_out));
544}
545
546int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
547 double attr_timeout)
548{
549 struct fuse_attr_out arg;
550 size_t size = req->se->conn.proto_minor < 9 ?
551 FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
552
553 memset(&arg, 0, sizeof(arg));
554 arg.attr_valid = calc_timeout_sec(attr_timeout);
555 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
556 convert_stat(attr, &arg.attr);
557
558 return send_reply_ok(req, &arg, size);
559}
560
561int fuse_reply_readlink(fuse_req_t req, const char *linkname)
562{
563 return send_reply_ok(req, linkname, strlen(linkname));
564}
565
567{
568 struct fuse_backing_map map = { .fd = fd };
569 int ret;
570
571 ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_OPEN, &map);
572 if (ret <= 0) {
573 fuse_log(FUSE_LOG_ERR, "fuse: passthrough_open: %s\n", strerror(errno));
574 return 0;
575 }
576
577 return ret;
578}
579
580int fuse_passthrough_close(fuse_req_t req, int backing_id)
581{
582 int ret;
583
584 ret = ioctl(req->se->fd, FUSE_DEV_IOC_BACKING_CLOSE, &backing_id);
585 if (ret < 0)
586 fuse_log(FUSE_LOG_ERR, "fuse: passthrough_close: %s\n", strerror(errno));
587
588 return ret;
589}
590
592{
593 struct fuse_open_out arg;
594
595 memset(&arg, 0, sizeof(arg));
596 fill_open(&arg, f);
597 return send_reply_ok(req, &arg, sizeof(arg));
598}
599
600static int do_fuse_reply_write(fuse_req_t req, size_t count)
601{
602 struct fuse_write_out arg;
603
604 memset(&arg, 0, sizeof(arg));
605 arg.size = count;
606
607 return send_reply_ok(req, &arg, sizeof(arg));
608}
609
610static int do_fuse_reply_copy(fuse_req_t req, size_t count)
611{
612 struct fuse_copy_file_range_out arg;
613
614 memset(&arg, 0, sizeof(arg));
615 arg.bytes_copied = count;
616
617 return send_reply_ok(req, &arg, sizeof(arg));
618}
619
620int fuse_reply_write(fuse_req_t req, size_t count)
621{
622 /*
623 * This function is also used by FUSE_COPY_FILE_RANGE and its 64-bit
624 * variant.
625 */
626 if (req->flags.is_copy_file_range_64)
627 return do_fuse_reply_copy(req, count);
628 else
629 return do_fuse_reply_write(req, count);
630}
631
632int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
633{
634 return send_reply_ok(req, buf, size);
635}
636
637static int fuse_send_data_iov_fallback(struct fuse_session *se,
638 struct fuse_chan *ch,
639 struct iovec *iov, int iov_count,
640 struct fuse_bufvec *buf,
641 size_t len, fuse_req_t req)
642{
643 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
644 void *mbuf;
645 int res;
646
647 /* Optimize common case */
648 if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
649 !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
650 /* FIXME: also avoid memory copy if there are multiple buffers
651 but none of them contain an fd */
652
653 iov[iov_count].iov_base = buf->buf[0].mem;
654 iov[iov_count].iov_len = len;
655 iov_count++;
656 return fuse_send_msg(se, ch, iov, iov_count, req);
657 }
658
659 res = posix_memalign(&mbuf, pagesize, len);
660 if (res != 0)
661 return res;
662
663 mem_buf.buf[0].mem = mbuf;
664 res = fuse_buf_copy(&mem_buf, buf, 0);
665 if (res < 0) {
666 free(mbuf);
667 return -res;
668 }
669 len = res;
670
671 iov[iov_count].iov_base = mbuf;
672 iov[iov_count].iov_len = len;
673 iov_count++;
674 res = fuse_send_msg(se, ch, iov, iov_count, req);
675 free(mbuf);
676
677 return res;
678}
679
680struct fuse_ll_pipe {
681 size_t size;
682 int can_grow;
683 int pipe[2];
684};
685
686static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
687{
688 close(llp->pipe[0]);
689 close(llp->pipe[1]);
690 free(llp);
691}
692
693#ifdef HAVE_SPLICE
694#if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
695static int fuse_pipe(int fds[2])
696{
697 int rv = pipe(fds);
698
699 if (rv == -1)
700 return rv;
701
702 if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
703 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
704 fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
705 fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
706 close(fds[0]);
707 close(fds[1]);
708 rv = -1;
709 }
710 return rv;
711}
712#else
713static int fuse_pipe(int fds[2])
714{
715 return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
716}
717#endif
718
719static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
720{
721 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
722 if (llp == NULL) {
723 int res;
724
725 llp = malloc(sizeof(struct fuse_ll_pipe));
726 if (llp == NULL)
727 return NULL;
728
729 res = fuse_pipe(llp->pipe);
730 if (res == -1) {
731 free(llp);
732 return NULL;
733 }
734
735 /*
736 *the default size is 16 pages on linux
737 */
738 llp->size = pagesize * 16;
739 llp->can_grow = 1;
740
741 pthread_setspecific(se->pipe_key, llp);
742 }
743
744 return llp;
745}
746#endif
747
748static void fuse_ll_clear_pipe(struct fuse_session *se)
749{
750 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
751 if (llp) {
752 pthread_setspecific(se->pipe_key, NULL);
753 fuse_ll_pipe_free(llp);
754 }
755}
756
757#if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
758static int read_back(int fd, char *buf, size_t len)
759{
760 int res;
761
762 res = read(fd, buf, len);
763 if (res == -1) {
764 fuse_log(FUSE_LOG_ERR,
765 "fuse: internal error: failed to read back from pipe: %s\n",
766 strerror(errno));
767 return -EIO;
768 }
769 if (res != len) {
770 fuse_log(FUSE_LOG_ERR,
771 "fuse: internal error: short read back from pipe: %i from %zd\n",
772 res, len);
773 return -EIO;
774 }
775 return 0;
776}
777
778static int grow_pipe_to_max(int pipefd)
779{
780 int res;
781 long max;
782 long maxfd;
783 char buf[32];
784
785 maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY | O_CLOEXEC);
786 if (maxfd < 0)
787 return -errno;
788
789 res = read(maxfd, buf, sizeof(buf) - 1);
790 if (res < 0) {
791 int saved_errno;
792
793 saved_errno = errno;
794 close(maxfd);
795 return -saved_errno;
796 }
797 close(maxfd);
798 buf[res] = '\0';
799
800 res = libfuse_strtol(buf, &max);
801 if (res)
802 return res;
803 res = fcntl(pipefd, F_SETPIPE_SZ, max);
804 if (res < 0)
805 return -errno;
806 return max;
807}
808
809static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
810 struct iovec *iov, int iov_count,
811 struct fuse_bufvec *buf, unsigned int flags,
812 fuse_req_t req)
813{
814 int res;
815 size_t len = fuse_buf_size(buf);
816 struct fuse_out_header *out = iov[0].iov_base;
817 struct fuse_ll_pipe *llp;
818 int splice_flags;
819 size_t pipesize;
820 size_t total_buf_size;
821 size_t idx;
822 size_t headerlen;
823 struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
824
825 if (se->broken_splice_nonblock)
826 goto fallback;
827
828 if (flags & FUSE_BUF_NO_SPLICE)
829 goto fallback;
830
831 total_buf_size = 0;
832 for (idx = buf->idx; idx < buf->count; idx++) {
833 total_buf_size += buf->buf[idx].size;
834 if (idx == buf->idx)
835 total_buf_size -= buf->off;
836 }
837 if (total_buf_size < 2 * pagesize)
838 goto fallback;
839
840 if (se->conn.proto_minor < 14 ||
841 !(se->conn.want_ext & FUSE_CAP_SPLICE_WRITE))
842 goto fallback;
843
844 llp = fuse_ll_get_pipe(se);
845 if (llp == NULL)
846 goto fallback;
847
848
849 headerlen = iov_length(iov, iov_count);
850
851 out->len = headerlen + len;
852
853 /*
854 * Heuristic for the required pipe size, does not work if the
855 * source contains less than page size fragments
856 */
857 pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
858
859 if (llp->size < pipesize) {
860 if (llp->can_grow) {
861 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
862 if (res == -1) {
863 res = grow_pipe_to_max(llp->pipe[0]);
864 if (res > 0)
865 llp->size = res;
866 llp->can_grow = 0;
867 goto fallback;
868 }
869 llp->size = res;
870 }
871 if (llp->size < pipesize)
872 goto fallback;
873 }
874
875
876 res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
877 if (res == -1)
878 goto fallback;
879
880 if (res != headerlen) {
881 res = -EIO;
882 fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res,
883 headerlen);
884 goto clear_pipe;
885 }
886
887 pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
888 pipe_buf.buf[0].fd = llp->pipe[1];
889
890 res = fuse_buf_copy(&pipe_buf, buf,
892 if (res < 0) {
893 if (res == -EAGAIN || res == -EINVAL) {
894 /*
895 * Should only get EAGAIN on kernels with
896 * broken SPLICE_F_NONBLOCK support (<=
897 * 2.6.35) where this error or a short read is
898 * returned even if the pipe itself is not
899 * full
900 *
901 * EINVAL might mean that splice can't handle
902 * this combination of input and output.
903 */
904 if (res == -EAGAIN)
905 se->broken_splice_nonblock = 1;
906
907 pthread_setspecific(se->pipe_key, NULL);
908 fuse_ll_pipe_free(llp);
909 goto fallback;
910 }
911 res = -res;
912 goto clear_pipe;
913 }
914
915 if (res != 0 && res < len) {
916 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
917 void *mbuf;
918 size_t now_len = res;
919 /*
920 * For regular files a short count is either
921 * 1) due to EOF, or
922 * 2) because of broken SPLICE_F_NONBLOCK (see above)
923 *
924 * For other inputs it's possible that we overflowed
925 * the pipe because of small buffer fragments.
926 */
927
928 res = posix_memalign(&mbuf, pagesize, len);
929 if (res != 0)
930 goto clear_pipe;
931
932 mem_buf.buf[0].mem = mbuf;
933 mem_buf.off = now_len;
934 res = fuse_buf_copy(&mem_buf, buf, 0);
935 if (res > 0) {
936 char *tmpbuf;
937 size_t extra_len = res;
938 /*
939 * Trickiest case: got more data. Need to get
940 * back the data from the pipe and then fall
941 * back to regular write.
942 */
943 tmpbuf = malloc(headerlen);
944 if (tmpbuf == NULL) {
945 free(mbuf);
946 res = ENOMEM;
947 goto clear_pipe;
948 }
949 res = read_back(llp->pipe[0], tmpbuf, headerlen);
950 free(tmpbuf);
951 if (res != 0) {
952 free(mbuf);
953 goto clear_pipe;
954 }
955 res = read_back(llp->pipe[0], mbuf, now_len);
956 if (res != 0) {
957 free(mbuf);
958 goto clear_pipe;
959 }
960 len = now_len + extra_len;
961 iov[iov_count].iov_base = mbuf;
962 iov[iov_count].iov_len = len;
963 iov_count++;
964 res = fuse_send_msg(se, ch, iov, iov_count, req);
965 free(mbuf);
966 return res;
967 }
968 free(mbuf);
969 res = now_len;
970 }
971 len = res;
972 out->len = headerlen + len;
973
974 if (se->debug) {
975 fuse_log(FUSE_LOG_DEBUG,
976 " unique: %llu, success, outsize: %i (splice)\n",
977 (unsigned long long) out->unique, out->len);
978 }
979
980 splice_flags = 0;
981 if ((flags & FUSE_BUF_SPLICE_MOVE) &&
982 (se->conn.want_ext & FUSE_CAP_SPLICE_MOVE))
983 splice_flags |= SPLICE_F_MOVE;
984
985 if (se->io != NULL && se->io->splice_send != NULL) {
986 res = se->io->splice_send(llp->pipe[0], NULL,
987 ch ? ch->fd : se->fd, NULL, out->len,
988 splice_flags, se->userdata);
989 } else {
990 res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL,
991 out->len, splice_flags);
992 }
993 if (res == -1) {
994 res = -errno;
995 perror("fuse: splice from pipe");
996 goto clear_pipe;
997 }
998 if (res != out->len) {
999 res = -EIO;
1000 fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n",
1001 res, out->len);
1002 goto clear_pipe;
1003 }
1004 return 0;
1005
1006clear_pipe:
1007 fuse_ll_clear_pipe(se);
1008 return res;
1009
1010fallback:
1011 return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len, req);
1012}
1013#else
1014static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
1015 struct iovec *iov, int iov_count,
1016 struct fuse_bufvec *req_data, unsigned int flags,
1017 fuse_req_t req)
1018{
1019 size_t len = fuse_buf_size(req_data);
1020 (void) flags;
1021
1022 return fuse_send_data_iov_fallback(se, ch, iov, iov_count, req_data, len, req);
1023}
1024#endif
1025
1027 enum fuse_buf_copy_flags flags)
1028{
1029 struct iovec iov[2];
1030 struct fuse_out_header out;
1031 int res;
1032
1033 if (req->flags.is_uring)
1034 return fuse_reply_data_uring(req, bufv, flags);
1035
1036 iov[0].iov_base = &out;
1037 iov[0].iov_len = sizeof(struct fuse_out_header);
1038
1039 out.unique = req->unique;
1040 out.error = 0;
1041
1042 res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags, req);
1043 if (res <= 0) {
1044 fuse_free_req(req);
1045 return res;
1046 } else {
1047 return fuse_reply_err(req, res);
1048 }
1049}
1050
1051int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
1052{
1053 struct fuse_statfs_out arg;
1054 size_t size = req->se->conn.proto_minor < 4 ?
1055 FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
1056
1057 memset(&arg, 0, sizeof(arg));
1058 convert_statfs(stbuf, &arg.st);
1059
1060 return send_reply_ok(req, &arg, size);
1061}
1062
1063int fuse_reply_xattr(fuse_req_t req, size_t count)
1064{
1065 struct fuse_getxattr_out arg;
1066
1067 memset(&arg, 0, sizeof(arg));
1068 arg.size = count;
1069
1070 return send_reply_ok(req, &arg, sizeof(arg));
1071}
1072
1073int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
1074{
1075 struct fuse_lk_out arg;
1076
1077 memset(&arg, 0, sizeof(arg));
1078 arg.lk.type = lock->l_type;
1079 if (lock->l_type != F_UNLCK) {
1080 arg.lk.start = lock->l_start;
1081 if (lock->l_len == 0)
1082 arg.lk.end = OFFSET_MAX;
1083 else
1084 arg.lk.end = lock->l_start + lock->l_len - 1;
1085 }
1086 arg.lk.pid = lock->l_pid;
1087 return send_reply_ok(req, &arg, sizeof(arg));
1088}
1089
1090int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
1091{
1092 struct fuse_bmap_out arg;
1093
1094 memset(&arg, 0, sizeof(arg));
1095 arg.block = idx;
1096
1097 return send_reply_ok(req, &arg, sizeof(arg));
1098}
1099
1100static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
1101 size_t count)
1102{
1103 struct fuse_ioctl_iovec *fiov;
1104 size_t i;
1105
1106 fiov = malloc(sizeof(fiov[0]) * count);
1107 if (!fiov)
1108 return NULL;
1109
1110 for (i = 0; i < count; i++) {
1111 fiov[i].base = (uintptr_t) iov[i].iov_base;
1112 fiov[i].len = iov[i].iov_len;
1113 }
1114
1115 return fiov;
1116}
1117
1119 const struct iovec *in_iov, size_t in_count,
1120 const struct iovec *out_iov, size_t out_count)
1121{
1122 struct fuse_ioctl_out arg;
1123 struct fuse_ioctl_iovec *in_fiov = NULL;
1124 struct fuse_ioctl_iovec *out_fiov = NULL;
1125 struct iovec iov[4];
1126 size_t count = 1;
1127 int res;
1128
1129 memset(&arg, 0, sizeof(arg));
1130 arg.flags |= FUSE_IOCTL_RETRY;
1131 arg.in_iovs = in_count;
1132 arg.out_iovs = out_count;
1133 iov[count].iov_base = &arg;
1134 iov[count].iov_len = sizeof(arg);
1135 count++;
1136
1137 if (req->se->conn.proto_minor < 16) {
1138 if (in_count) {
1139 iov[count].iov_base = (void *)in_iov;
1140 iov[count].iov_len = sizeof(in_iov[0]) * in_count;
1141 count++;
1142 }
1143
1144 if (out_count) {
1145 iov[count].iov_base = (void *)out_iov;
1146 iov[count].iov_len = sizeof(out_iov[0]) * out_count;
1147 count++;
1148 }
1149 } else {
1150 /* Can't handle non-compat 64bit ioctls on 32bit */
1151 if (sizeof(void *) == 4 && req->flags.ioctl_64bit) {
1152 res = fuse_reply_err(req, EINVAL);
1153 goto out;
1154 }
1155
1156 if (in_count) {
1157 in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
1158 if (!in_fiov)
1159 goto enomem;
1160
1161 iov[count].iov_base = (void *)in_fiov;
1162 iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
1163 count++;
1164 }
1165 if (out_count) {
1166 out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
1167 if (!out_fiov)
1168 goto enomem;
1169
1170 iov[count].iov_base = (void *)out_fiov;
1171 iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
1172 count++;
1173 }
1174 }
1175
1176 res = send_reply_iov(req, 0, iov, count);
1177out:
1178 free(in_fiov);
1179 free(out_fiov);
1180
1181 return res;
1182
1183enomem:
1184 res = fuse_reply_err(req, ENOMEM);
1185 goto out;
1186}
1187
1188int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
1189{
1190 struct fuse_ioctl_out arg;
1191 struct iovec iov[3];
1192 size_t count = 1;
1193
1194 memset(&arg, 0, sizeof(arg));
1195 arg.result = result;
1196 iov[count].iov_base = &arg;
1197 iov[count].iov_len = sizeof(arg);
1198 count++;
1199
1200 if (size) {
1201 iov[count].iov_base = (char *) buf;
1202 iov[count].iov_len = size;
1203 count++;
1204 }
1205
1206 return send_reply_iov(req, 0, iov, count);
1207}
1208
1209int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
1210 int count)
1211{
1212 struct iovec *padded_iov;
1213 struct fuse_ioctl_out arg;
1214 int res;
1215
1216 padded_iov = malloc((count + 2) * sizeof(struct iovec));
1217 if (padded_iov == NULL)
1218 return fuse_reply_err(req, ENOMEM);
1219
1220 memset(&arg, 0, sizeof(arg));
1221 arg.result = result;
1222 padded_iov[1].iov_base = &arg;
1223 padded_iov[1].iov_len = sizeof(arg);
1224
1225 memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
1226
1227 res = send_reply_iov(req, 0, padded_iov, count + 2);
1228 free(padded_iov);
1229
1230 return res;
1231}
1232
1233int fuse_reply_poll(fuse_req_t req, unsigned revents)
1234{
1235 struct fuse_poll_out arg;
1236
1237 memset(&arg, 0, sizeof(arg));
1238 arg.revents = revents;
1239
1240 return send_reply_ok(req, &arg, sizeof(arg));
1241}
1242
1243int fuse_reply_lseek(fuse_req_t req, off_t off)
1244{
1245 struct fuse_lseek_out arg;
1246
1247 memset(&arg, 0, sizeof(arg));
1248 arg.offset = off;
1249
1250 return send_reply_ok(req, &arg, sizeof(arg));
1251}
1252
1253#ifdef HAVE_STATX
1254int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx,
1255 double attr_timeout)
1256{
1257 struct fuse_statx_out arg;
1258
1259 memset(&arg, 0, sizeof(arg));
1260 arg.flags = flags;
1261 arg.attr_valid = calc_timeout_sec(attr_timeout);
1262 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
1263 memcpy(&arg.stat, statx, sizeof(arg.stat));
1264
1265 return send_reply_ok(req, &arg, sizeof(arg));
1266}
1267#else
1268int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx,
1269 double attr_timeout)
1270{
1271 (void)req;
1272 (void)flags;
1273 (void)statx;
1274 (void)attr_timeout;
1275
1276 return -ENOSYS;
1277}
1278#endif
1279
1280static void _do_lookup(fuse_req_t req, const fuse_ino_t nodeid,
1281 const void *op_in, const void *in_payload)
1282{
1283 (void)op_in;
1284
1285 char *name = (char *)in_payload;
1286
1287 if (req->se->op.lookup)
1288 req->se->op.lookup(req, nodeid, name);
1289 else
1290 fuse_reply_err(req, ENOSYS);
1291}
1292
1293static void do_lookup(fuse_req_t req, const fuse_ino_t nodeid,
1294 const void *inarg)
1295{
1296 _do_lookup(req, nodeid, NULL, inarg);
1297}
1298
1299static void _do_forget(fuse_req_t req, const fuse_ino_t nodeid,
1300 const void *op_in, const void *in_payload)
1301{
1302 (void)in_payload;
1303
1304 struct fuse_forget_in *arg = (struct fuse_forget_in *)op_in;
1305
1306 if (req->se->op.forget)
1307 req->se->op.forget(req, nodeid, arg->nlookup);
1308 else
1309 fuse_reply_none(req);
1310}
1311
1312static void do_forget(fuse_req_t req, const fuse_ino_t nodeid,
1313 const void *inarg)
1314{
1315 _do_forget(req, nodeid, inarg, NULL);
1316}
1317
1318static void _do_batch_forget(fuse_req_t req, const fuse_ino_t nodeid,
1319 const void *op_in, const void *in_payload)
1320{
1321 (void)nodeid;
1322 unsigned int i;
1323
1324 const struct fuse_batch_forget_in *arg = op_in;
1325 const struct fuse_forget_one *forgets = in_payload;
1326
1327 if (req->se->op.forget_multi) {
1328 req->se->op.forget_multi(req, arg->count,
1329 (struct fuse_forget_data *)in_payload);
1330 } else if (req->se->op.forget) {
1331 for (i = 0; i < arg->count; i++) {
1332 const struct fuse_forget_one *forget = &forgets[i];
1333 struct fuse_req *dummy_req;
1334
1335 dummy_req = fuse_ll_alloc_req(req->se);
1336 if (dummy_req == NULL)
1337 break;
1338
1339 dummy_req->unique = req->unique;
1340 dummy_req->ctx = req->ctx;
1341 dummy_req->ch = NULL;
1342
1343 req->se->op.forget(dummy_req, forget->nodeid,
1344 forget->nlookup);
1345 }
1346 fuse_reply_none(req);
1347 } else {
1348 fuse_reply_none(req);
1349 }
1350}
1351
1352static void do_batch_forget(fuse_req_t req, const fuse_ino_t nodeid,
1353 const void *inarg)
1354{
1355 struct fuse_batch_forget_in *arg = (void *)inarg;
1356 struct fuse_forget_one *param = (void *)PARAM(arg);
1357
1358 _do_batch_forget(req, nodeid, inarg, param);
1359}
1360
1361static void _do_getattr(fuse_req_t req, const fuse_ino_t nodeid,
1362 const void *op_in, const void *in_payload)
1363{
1364 struct fuse_getattr_in *arg = (struct fuse_getattr_in *)op_in;
1365 (void)in_payload;
1366
1367 struct fuse_file_info *fip = NULL;
1368 struct fuse_file_info fi;
1369
1370 if (req->se->conn.proto_minor >= 9) {
1371 if (arg->getattr_flags & FUSE_GETATTR_FH) {
1372 memset(&fi, 0, sizeof(fi));
1373 fi.fh = arg->fh;
1374 fip = &fi;
1375 }
1376 }
1377
1378 if (req->se->op.getattr)
1379 req->se->op.getattr(req, nodeid, fip);
1380 else
1381 fuse_reply_err(req, ENOSYS);
1382}
1383
1384static void do_getattr(fuse_req_t req, const fuse_ino_t nodeid,
1385 const void *inarg)
1386{
1387 _do_getattr(req, nodeid, inarg, NULL);
1388}
1389
1390static void _do_setattr(fuse_req_t req, const fuse_ino_t nodeid,
1391 const void *op_in, const void *in_payload)
1392{
1393 (void)in_payload;
1394 const struct fuse_setattr_in *arg = op_in;
1395 uint32_t valid = arg->valid;
1396
1397 if (req->se->op.setattr) {
1398 struct fuse_file_info *fi = NULL;
1399 struct fuse_file_info fi_store;
1400 struct stat stbuf;
1401 memset(&stbuf, 0, sizeof(stbuf));
1402 convert_attr(arg, &stbuf);
1403 if (arg->valid & FATTR_FH) {
1404 valid &= ~FATTR_FH;
1405 memset(&fi_store, 0, sizeof(fi_store));
1406 fi = &fi_store;
1407 fi->fh = arg->fh;
1408 }
1409 valid &= FUSE_SET_ATTR_MODE | FUSE_SET_ATTR_UID |
1410 FUSE_SET_ATTR_GID | FUSE_SET_ATTR_SIZE |
1411 FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME |
1412 FUSE_SET_ATTR_KILL_SUID | FUSE_SET_ATTR_KILL_SGID |
1413 FUSE_SET_ATTR_ATIME_NOW | FUSE_SET_ATTR_MTIME_NOW |
1414 FUSE_SET_ATTR_CTIME;
1415
1416 req->se->op.setattr(req, nodeid, &stbuf, valid, fi);
1417 } else
1418 fuse_reply_err(req, ENOSYS);
1419}
1420
1421static void do_setattr(fuse_req_t req, const fuse_ino_t nodeid,
1422 const void *inarg)
1423{
1424 _do_setattr(req, nodeid, inarg, NULL);
1425}
1426
1427static void _do_access(fuse_req_t req, const fuse_ino_t nodeid,
1428 const void *op_in, const void *in_payload)
1429{
1430 (void)in_payload;
1431 const struct fuse_access_in *arg = op_in;
1432
1433 if (req->se->op.access)
1434 req->se->op.access(req, nodeid, arg->mask);
1435 else
1436 fuse_reply_err(req, ENOSYS);
1437}
1438
1439static void do_access(fuse_req_t req, const fuse_ino_t nodeid,
1440 const void *inarg)
1441{
1442 _do_access(req, nodeid, inarg, NULL);
1443}
1444
1445static void _do_readlink(fuse_req_t req, const fuse_ino_t nodeid,
1446 const void *op_in, const void *in_payload)
1447{
1448 (void)op_in;
1449 (void)in_payload;
1450
1451 if (req->se->op.readlink)
1452 req->se->op.readlink(req, nodeid);
1453 else
1454 fuse_reply_err(req, ENOSYS);
1455}
1456
1457static void do_readlink(fuse_req_t req, const fuse_ino_t nodeid,
1458 const void *inarg)
1459{
1460 _do_readlink(req, nodeid, inarg, NULL);
1461}
1462
1463static void _do_mknod(fuse_req_t req, const fuse_ino_t nodeid,
1464 const void *op_in, const void *in_payload)
1465{
1466 const struct fuse_mknod_in *arg = (struct fuse_mknod_in *)op_in;
1467 const char *name = in_payload;
1468
1469 if (req->se->conn.proto_minor >= 12)
1470 req->ctx.umask = arg->umask;
1471
1472 if (req->se->op.mknod)
1473 req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
1474 else
1475 fuse_reply_err(req, ENOSYS);
1476}
1477
1478static void do_mknod(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1479{
1480 struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg;
1481 char *name = PARAM(arg);
1482
1483 if (req->se->conn.proto_minor < 12)
1484 name = (char *)inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
1485
1486 _do_mknod(req, nodeid, inarg, name);
1487}
1488
1489static void _do_mkdir(fuse_req_t req, const fuse_ino_t nodeid,
1490 const void *op_in, const void *in_payload)
1491{
1492 const char *name = in_payload;
1493 const struct fuse_mkdir_in *arg = op_in;
1494
1495 if (req->se->conn.proto_minor >= 12)
1496 req->ctx.umask = arg->umask;
1497
1498 if (req->se->op.mkdir)
1499 req->se->op.mkdir(req, nodeid, name, arg->mode);
1500 else
1501 fuse_reply_err(req, ENOSYS);
1502}
1503
1504static void do_mkdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1505{
1506 const struct fuse_mkdir_in *arg = inarg;
1507 const char *name = PARAM(arg);
1508
1509 _do_mkdir(req, nodeid, inarg, name);
1510}
1511
1512static void _do_unlink(fuse_req_t req, const fuse_ino_t nodeid,
1513 const void *op_in, const void *in_payload)
1514{
1515 (void)op_in;
1516 const char *name = in_payload;
1517
1518 if (req->se->op.unlink)
1519 req->se->op.unlink(req, nodeid, name);
1520 else
1521 fuse_reply_err(req, ENOSYS);
1522}
1523
1524static void do_unlink(fuse_req_t req, const fuse_ino_t nodeid,
1525 const void *inarg)
1526{
1527 _do_unlink(req, nodeid, NULL, inarg);
1528}
1529
1530static void _do_rmdir(fuse_req_t req, const fuse_ino_t nodeid,
1531 const void *op_in, const void *in_payload)
1532{
1533 (void)op_in;
1534 const char *name = in_payload;
1535
1536 if (req->se->op.rmdir)
1537 req->se->op.rmdir(req, nodeid, name);
1538 else
1539 fuse_reply_err(req, ENOSYS);
1540}
1541
1542static void do_rmdir(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1543{
1544 _do_rmdir(req, nodeid, NULL, inarg);
1545}
1546
1547static void _do_symlink(fuse_req_t req, const fuse_ino_t nodeid,
1548 const void *op_in, const void *in_payload)
1549{
1550 (void)op_in;
1551 const char *name = (char *)in_payload;
1552 const char *linkname = name + strlen(name) + 1;
1553
1554 if (req->se->op.symlink)
1555 req->se->op.symlink(req, linkname, nodeid, name);
1556 else
1557 fuse_reply_err(req, ENOSYS);
1558}
1559
1560static void do_symlink(fuse_req_t req, const fuse_ino_t nodeid,
1561 const void *inarg)
1562{
1563 _do_symlink(req, nodeid, NULL, inarg);
1564}
1565
1566static void _do_rename(fuse_req_t req, const fuse_ino_t nodeid,
1567 const void *op_in, const void *in_payload)
1568{
1569 const struct fuse_rename_in *arg = (struct fuse_rename_in *)op_in;
1570 const char *oldname = in_payload;
1571 const char *newname = oldname + strlen(oldname) + 1;
1572
1573 if (req->se->op.rename)
1574 req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1575 0);
1576 else
1577 fuse_reply_err(req, ENOSYS);
1578}
1579
1580static void do_rename(fuse_req_t req, const fuse_ino_t nodeid,
1581 const void *inarg)
1582{
1583 const struct fuse_rename_in *arg = inarg;
1584 const void *payload = PARAM(arg);
1585
1586 _do_rename(req, nodeid, arg, payload);
1587}
1588
1589static void _do_rename2(fuse_req_t req, const fuse_ino_t nodeid,
1590 const void *op_in, const void *in_payload)
1591{
1592 const struct fuse_rename2_in *arg = op_in;
1593 const char *oldname = in_payload;
1594 const char *newname = oldname + strlen(oldname) + 1;
1595
1596 if (req->se->op.rename)
1597 req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1598 arg->flags);
1599 else
1600 fuse_reply_err(req, ENOSYS);
1601}
1602
1603static void do_rename2(fuse_req_t req, const fuse_ino_t nodeid,
1604 const void *inarg)
1605{
1606 const struct fuse_rename2_in *arg = inarg;
1607 const void *payload = PARAM(arg);
1608
1609 _do_rename2(req, nodeid, arg, payload);
1610}
1611
1612static void _do_tmpfile(fuse_req_t req, fuse_ino_t nodeid, const void *op_in,
1613 const void *in_payload)
1614{
1615 (void)in_payload;
1616 const struct fuse_create_in *arg = op_in;
1617
1618 if (req->se->op.tmpfile) {
1619 struct fuse_file_info fi;
1620
1621 memset(&fi, 0, sizeof(fi));
1622 fi.flags = arg->flags;
1623
1624 if (req->se->conn.proto_minor >= 12)
1625 req->ctx.umask = arg->umask;
1626
1627 req->se->op.tmpfile(req, nodeid, arg->mode, &fi);
1628 } else
1629 fuse_reply_err(req, ENOSYS);
1630}
1631
1632static void do_tmpfile(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1633{
1634 struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
1635
1636 _do_tmpfile(req, nodeid, arg, NULL);
1637}
1638
1639static void _do_link(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
1640 const void *in_payload)
1641{
1642 struct fuse_link_in *arg = (struct fuse_link_in *)op_in;
1643
1644 if (req->se->op.link)
1645 req->se->op.link(req, arg->oldnodeid, nodeid, in_payload);
1646 else
1647 fuse_reply_err(req, ENOSYS);
1648}
1649
1650static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1651{
1652 const struct fuse_link_in *arg = inarg;
1653 const void *name = PARAM(arg);
1654
1655 _do_link(req, nodeid, inarg, name);
1656}
1657
1658static void _do_create(fuse_req_t req, const fuse_ino_t nodeid,
1659 const void *op_in, const void *in_payload)
1660{
1661 const struct fuse_create_in *arg = op_in;
1662 const char *name = in_payload;
1663
1664 if (req->se->op.create) {
1665 struct fuse_file_info fi;
1666
1667 memset(&fi, 0, sizeof(fi));
1668 fi.flags = arg->flags;
1669
1670 if (req->se->conn.proto_minor >= 12)
1671 req->ctx.umask = arg->umask;
1672
1673 if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
1674 fi.kill_suidgid =
1675 (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0;
1676
1677 req->se->op.create(req, nodeid, name, arg->mode, &fi);
1678 } else {
1679 fuse_reply_err(req, ENOSYS);
1680 }
1681}
1682
1683static void do_create(fuse_req_t req, const fuse_ino_t nodeid,
1684 const void *inarg)
1685{
1686 const struct fuse_create_in *arg = (struct fuse_create_in *)inarg;
1687 void *payload = PARAM(arg);
1688
1689 if (req->se->conn.proto_minor < 12)
1690 payload = (char *)inarg + sizeof(struct fuse_open_in);
1691
1692 _do_create(req, nodeid, arg, payload);
1693}
1694
1695static void _do_open(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
1696 const void *in_payload)
1697{
1698 (void)in_payload;
1699 struct fuse_open_in *arg = (struct fuse_open_in *)op_in;
1700 struct fuse_file_info fi;
1701
1702 memset(&fi, 0, sizeof(fi));
1703 fi.flags = arg->flags;
1704
1705 if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
1706 fi.kill_suidgid =
1707 (arg->open_flags & FUSE_OPEN_KILL_SUIDGID) != 0;
1708
1709 if (req->se->op.open)
1710 req->se->op.open(req, nodeid, &fi);
1711 else if (req->se->conn.want_ext & FUSE_CAP_NO_OPEN_SUPPORT)
1712 fuse_reply_err(req, ENOSYS);
1713 else
1714 fuse_reply_open(req, &fi);
1715}
1716
1717static void do_open(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1718{
1719 _do_open(req, nodeid, inarg, NULL);
1720}
1721
1722static void _do_read(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
1723 const void *in_payload)
1724{
1725 (void)in_payload;
1726 struct fuse_read_in *arg = (struct fuse_read_in *)op_in;
1727
1728 if (req->se->op.read) {
1729 struct fuse_file_info fi;
1730
1731 memset(&fi, 0, sizeof(fi));
1732 fi.fh = arg->fh;
1733 if (req->se->conn.proto_minor >= 9) {
1734 fi.lock_owner = arg->lock_owner;
1735 fi.flags = arg->flags;
1736 }
1737 req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
1738 } else
1739 fuse_reply_err(req, ENOSYS);
1740}
1741
1742static void do_read(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1743{
1744 _do_read(req, nodeid, inarg, NULL);
1745}
1746
1747static void _do_write(fuse_req_t req, const fuse_ino_t nodeid,
1748 const void *op_in, const void *in_payload)
1749{
1750 struct fuse_write_in *arg = (struct fuse_write_in *)op_in;
1751 const char *buf = in_payload;
1752 struct fuse_file_info fi;
1753
1754 memset(&fi, 0, sizeof(fi));
1755 fi.fh = arg->fh;
1756 fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
1757
1758 if (req->se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
1759 fi.kill_suidgid =
1760 (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0;
1761
1762 if (req->se->conn.proto_minor >= 9) {
1763 fi.lock_owner = arg->lock_owner;
1764 fi.flags = arg->flags;
1765 }
1766
1767 if (req->se->op.write)
1768 req->se->op.write(req, nodeid, buf, arg->size, arg->offset,
1769 &fi);
1770 else
1771 fuse_reply_err(req, ENOSYS);
1772}
1773
1774static void do_write(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1775{
1776 struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
1777 const void *payload;
1778
1779 if (req->se->conn.proto_minor < 9)
1780 payload = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1781 else
1782 payload = PARAM(arg);
1783
1784 _do_write(req, nodeid, arg, payload);
1785}
1786
1787static void _do_write_buf(fuse_req_t req, const fuse_ino_t nodeid,
1788 const void *op_in, struct fuse_bufvec *bufv)
1789{
1790 struct fuse_session *se = req->se;
1791 struct fuse_write_in *arg = (struct fuse_write_in *)op_in;
1792 struct fuse_file_info fi;
1793
1794 memset(&fi, 0, sizeof(fi));
1795 fi.fh = arg->fh;
1796 fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
1797
1798 if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
1799 fi.kill_suidgid =
1800 (arg->write_flags & FUSE_WRITE_KILL_SUIDGID) != 0;
1801
1802 if (se->conn.proto_minor >= 9) {
1803 fi.lock_owner = arg->lock_owner;
1804 fi.flags = arg->flags;
1805 }
1806
1807 se->op.write_buf(req, nodeid, bufv, arg->offset, &fi);
1808}
1809
1810static void do_write_buf(fuse_req_t req, const fuse_ino_t nodeid,
1811 const void *inarg, const struct fuse_buf *ibuf)
1812{
1813 struct fuse_session *se = req->se;
1814 struct fuse_bufvec bufv = {
1815 .buf[0] = *ibuf,
1816 .count = 1,
1817 };
1818 struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
1819
1820 if (se->conn.proto_minor < 9) {
1821 bufv.buf[0].mem = ((char *)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1822 bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1823 FUSE_COMPAT_WRITE_IN_SIZE;
1824 assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
1825 } else {
1826 if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
1827 bufv.buf[0].mem = PARAM(arg);
1828
1829 bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1830 sizeof(struct fuse_write_in);
1831 }
1832 if (bufv.buf[0].size < arg->size) {
1833 fuse_log(FUSE_LOG_ERR,
1834 "fuse: %s: buffer size too small\n", __func__);
1835 fuse_reply_err(req, EIO);
1836 goto out;
1837 }
1838 bufv.buf[0].size = arg->size;
1839
1840 _do_write_buf(req, nodeid, inarg, &bufv);
1841
1842out:
1843 /* Need to reset the pipe if ->write_buf() didn't consume all data */
1844 if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
1845 fuse_ll_clear_pipe(se);
1846}
1847
1848static void _do_flush(fuse_req_t req, const fuse_ino_t nodeid,
1849 const void *op_in, const void *in_payload)
1850{
1851 (void)in_payload;
1852 struct fuse_flush_in *arg = (struct fuse_flush_in *)op_in;
1853 struct fuse_file_info fi;
1854
1855 memset(&fi, 0, sizeof(fi));
1856 fi.fh = arg->fh;
1857 fi.flush = 1;
1858 if (req->se->conn.proto_minor >= 7)
1859 fi.lock_owner = arg->lock_owner;
1860
1861 if (req->se->op.flush)
1862 req->se->op.flush(req, nodeid, &fi);
1863 else
1864 fuse_reply_err(req, ENOSYS);
1865}
1866
1867static void do_flush(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1868{
1869 _do_flush(req, nodeid, inarg, NULL);
1870}
1871
1872static void _do_release(fuse_req_t req, const fuse_ino_t nodeid,
1873 const void *op_in, const void *in_payload)
1874{
1875 (void)in_payload;
1876 const struct fuse_release_in *arg = op_in;
1877 struct fuse_file_info fi;
1878
1879 memset(&fi, 0, sizeof(fi));
1880 fi.flags = arg->flags;
1881 fi.fh = arg->fh;
1882 if (req->se->conn.proto_minor >= 8) {
1883 fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
1884 fi.lock_owner = arg->lock_owner;
1885 }
1886 if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
1887 fi.flock_release = 1;
1888 fi.lock_owner = arg->lock_owner;
1889 }
1890
1891 if (req->se->op.release)
1892 req->se->op.release(req, nodeid, &fi);
1893 else
1894 fuse_reply_err(req, 0);
1895}
1896
1897static void do_release(fuse_req_t req, const fuse_ino_t nodeid,
1898 const void *inarg)
1899{
1900 _do_release(req, nodeid, inarg, NULL);
1901}
1902
1903static void _do_fsync(fuse_req_t req, const fuse_ino_t nodeid,
1904 const void *op_in, const void *in_payload)
1905{
1906 (void)in_payload;
1907 const struct fuse_fsync_in *arg = op_in;
1908 struct fuse_file_info fi;
1909 int datasync = arg->fsync_flags & 1;
1910
1911 memset(&fi, 0, sizeof(fi));
1912 fi.fh = arg->fh;
1913
1914 if (req->se->op.fsync)
1915 req->se->op.fsync(req, nodeid, datasync, &fi);
1916 else
1917 fuse_reply_err(req, ENOSYS);
1918}
1919
1920static void do_fsync(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
1921{
1922 _do_fsync(req, nodeid, inarg, NULL);
1923}
1924
1925static void _do_opendir(fuse_req_t req, const fuse_ino_t nodeid,
1926 const void *op_in, const void *in_payload)
1927{
1928 (void)in_payload;
1929 const struct fuse_open_in *arg = op_in;
1930 struct fuse_file_info fi;
1931
1932 memset(&fi, 0, sizeof(fi));
1933 fi.flags = arg->flags;
1934 /* XXX: fuse_open_in::open_flags */
1935
1936 if (req->se->op.opendir)
1937 req->se->op.opendir(req, nodeid, &fi);
1938 else if (req->se->conn.want_ext & FUSE_CAP_NO_OPENDIR_SUPPORT)
1939 fuse_reply_err(req, ENOSYS);
1940 else
1941 fuse_reply_open(req, &fi);
1942}
1943
1944static void do_opendir(fuse_req_t req, const fuse_ino_t nodeid,
1945 const void *inarg)
1946{
1947 _do_opendir(req, nodeid, inarg, NULL);
1948}
1949
1950static void _do_readdir(fuse_req_t req, const fuse_ino_t nodeid,
1951 const void *op_in, const void *in_payload)
1952{
1953 (void)in_payload;
1954 struct fuse_read_in *arg = (struct fuse_read_in *)op_in;
1955 struct fuse_file_info fi;
1956
1957 memset(&fi, 0, sizeof(fi));
1958 fi.fh = arg->fh;
1959
1960 if (req->se->op.readdir)
1961 req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
1962 else
1963 fuse_reply_err(req, ENOSYS);
1964}
1965
1966static void do_readdir(fuse_req_t req, const fuse_ino_t nodeid,
1967 const void *inarg)
1968{
1969 _do_readdir(req, nodeid, inarg, NULL);
1970}
1971
1972static void _do_readdirplus(fuse_req_t req, const fuse_ino_t nodeid,
1973 const void *op_in, const void *in_payload)
1974{
1975 (void)in_payload;
1976 struct fuse_read_in *arg = (struct fuse_read_in *)op_in;
1977 struct fuse_file_info fi;
1978
1979 memset(&fi, 0, sizeof(fi));
1980 fi.fh = arg->fh;
1981
1982 if (req->se->op.readdirplus)
1983 req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
1984 else
1985 fuse_reply_err(req, ENOSYS);
1986}
1987
1988static void do_readdirplus(fuse_req_t req, const fuse_ino_t nodeid,
1989 const void *inarg)
1990{
1991 _do_readdirplus(req, nodeid, inarg, NULL);
1992}
1993
1994static void _do_releasedir(fuse_req_t req, const fuse_ino_t nodeid,
1995 const void *op_in, const void *in_payload)
1996{
1997 (void)in_payload;
1998 struct fuse_release_in *arg = (struct fuse_release_in *)op_in;
1999 struct fuse_file_info fi;
2000
2001 memset(&fi, 0, sizeof(fi));
2002 fi.flags = arg->flags;
2003 fi.fh = arg->fh;
2004
2005 if (req->se->op.releasedir)
2006 req->se->op.releasedir(req, nodeid, &fi);
2007 else
2008 fuse_reply_err(req, 0);
2009}
2010
2011static void do_releasedir(fuse_req_t req, const fuse_ino_t nodeid,
2012 const void *inarg)
2013{
2014 _do_releasedir(req, nodeid, inarg, NULL);
2015}
2016
2017static void _do_fsyncdir(fuse_req_t req, const fuse_ino_t nodeid,
2018 const void *op_in, const void *in_payload)
2019{
2020 (void)in_payload;
2021 struct fuse_fsync_in *arg = (struct fuse_fsync_in *)op_in;
2022 struct fuse_file_info fi;
2023 int datasync = arg->fsync_flags & 1;
2024
2025 memset(&fi, 0, sizeof(fi));
2026 fi.fh = arg->fh;
2027
2028 if (req->se->op.fsyncdir)
2029 req->se->op.fsyncdir(req, nodeid, datasync, &fi);
2030 else
2031 fuse_reply_err(req, ENOSYS);
2032}
2033static void do_fsyncdir(fuse_req_t req, const fuse_ino_t nodeid,
2034 const void *inarg)
2035{
2036 _do_fsyncdir(req, nodeid, inarg, NULL);
2037}
2038
2039static void _do_statfs(fuse_req_t req, const fuse_ino_t nodeid,
2040 const void *op_in, const void *in_payload)
2041{
2042 (void) nodeid;
2043 (void)op_in;
2044 (void)in_payload;
2045
2046 if (req->se->op.statfs)
2047 req->se->op.statfs(req, nodeid);
2048 else {
2049 struct statvfs buf = {
2050 .f_namemax = 255,
2051 .f_bsize = 512,
2052 };
2053 fuse_reply_statfs(req, &buf);
2054 }
2055}
2056static void do_statfs(fuse_req_t req, const fuse_ino_t nodeid,
2057 const void *inarg)
2058{
2059 _do_statfs(req, nodeid, inarg, NULL);
2060}
2061
2062static void _do_setxattr(fuse_req_t req, const fuse_ino_t nodeid,
2063 const void *op_in, const void *in_payload)
2064{
2065 struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *)op_in;
2066 const char *name = in_payload;
2067 const char *value = name + strlen(name) + 1;
2068
2069 /* XXX:The API should be extended to support extra_flags/setxattr_flags */
2070
2071 if (req->se->op.setxattr)
2072 req->se->op.setxattr(req, nodeid, name, value, arg->size,
2073 arg->flags);
2074 else
2075 fuse_reply_err(req, ENOSYS);
2076}
2077static void do_setxattr(fuse_req_t req, const fuse_ino_t nodeid,
2078 const void *inarg)
2079{
2080 struct fuse_session *se = req->se;
2081 unsigned int xattr_ext = !!(se->conn.want & FUSE_CAP_SETXATTR_EXT);
2082 const struct fuse_setxattr_in *arg = inarg;
2083 char *payload = xattr_ext ? PARAM(arg) :
2084 (char *)arg + FUSE_COMPAT_SETXATTR_IN_SIZE;
2085
2086 _do_setxattr(req, nodeid, arg, payload);
2087}
2088
2089static void _do_getxattr(fuse_req_t req, const fuse_ino_t nodeid,
2090 const void *op_in, const void *in_payload)
2091{
2092 const struct fuse_getxattr_in *arg = op_in;
2093
2094 if (req->se->op.getxattr)
2095 req->se->op.getxattr(req, nodeid, in_payload, arg->size);
2096 else
2097 fuse_reply_err(req, ENOSYS);
2098}
2099
2100static void do_getxattr(fuse_req_t req, const fuse_ino_t nodeid,
2101 const void *inarg)
2102{
2103 const struct fuse_getxattr_in *arg = inarg;
2104 const void *payload = PARAM(arg);
2105
2106 _do_getxattr(req, nodeid, arg, payload);
2107}
2108
2109static void _do_listxattr(fuse_req_t req, const fuse_ino_t nodeid,
2110 const void *inarg, const void *in_payload)
2111{
2112 (void)in_payload;
2113 const struct fuse_getxattr_in *arg = inarg;
2114
2115 if (req->se->op.listxattr)
2116 req->se->op.listxattr(req, nodeid, arg->size);
2117 else
2118 fuse_reply_err(req, ENOSYS);
2119}
2120static void do_listxattr(fuse_req_t req, const fuse_ino_t nodeid,
2121 const void *inarg)
2122{
2123 _do_listxattr(req, nodeid, inarg, NULL);
2124}
2125
2126static void _do_removexattr(fuse_req_t req, const fuse_ino_t nodeid,
2127 const void *inarg, const void *in_payload)
2128{
2129 (void)inarg;
2130 const char *name = in_payload;
2131
2132 if (req->se->op.removexattr)
2133 req->se->op.removexattr(req, nodeid, name);
2134 else
2135 fuse_reply_err(req, ENOSYS);
2136}
2137static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2138{
2139 _do_removexattr(req, nodeid, NULL, inarg);
2140}
2141
2142static void convert_fuse_file_lock(const struct fuse_file_lock *fl,
2143 struct flock *flock)
2144{
2145 memset(flock, 0, sizeof(struct flock));
2146 flock->l_type = fl->type;
2147 flock->l_whence = SEEK_SET;
2148 flock->l_start = fl->start;
2149 if (fl->end == OFFSET_MAX)
2150 flock->l_len = 0;
2151 else
2152 flock->l_len = fl->end - fl->start + 1;
2153 flock->l_pid = fl->pid;
2154}
2155
2156static void _do_getlk(fuse_req_t req, const fuse_ino_t nodeid,
2157 const void *op_in, const void *in_payload)
2158{
2159 (void)in_payload;
2160 const struct fuse_lk_in *arg = op_in;
2161 struct fuse_file_info fi;
2162 struct flock flock;
2163
2164 memset(&fi, 0, sizeof(fi));
2165 fi.fh = arg->fh;
2166 fi.lock_owner = arg->owner;
2167
2168 convert_fuse_file_lock(&arg->lk, &flock);
2169 if (req->se->op.getlk)
2170 req->se->op.getlk(req, nodeid, &fi, &flock);
2171 else
2172 fuse_reply_err(req, ENOSYS);
2173}
2174static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2175{
2176 _do_getlk(req, nodeid, inarg, NULL);
2177}
2178
2179static void do_setlk_common(fuse_req_t req, const fuse_ino_t nodeid,
2180 const void *op_in, int sleep)
2181{
2182 const struct fuse_lk_in *arg = op_in;
2183 struct fuse_file_info fi;
2184 struct flock flock;
2185
2186 memset(&fi, 0, sizeof(fi));
2187 fi.fh = arg->fh;
2188 fi.lock_owner = arg->owner;
2189
2190 if (arg->lk_flags & FUSE_LK_FLOCK) {
2191 int op = 0;
2192
2193 switch (arg->lk.type) {
2194 case F_RDLCK:
2195 op = LOCK_SH;
2196 break;
2197 case F_WRLCK:
2198 op = LOCK_EX;
2199 break;
2200 case F_UNLCK:
2201 op = LOCK_UN;
2202 break;
2203 }
2204 if (!sleep)
2205 op |= LOCK_NB;
2206
2207 if (req->se->op.flock)
2208 req->se->op.flock(req, nodeid, &fi, op);
2209 else
2210 fuse_reply_err(req, ENOSYS);
2211 } else {
2212 convert_fuse_file_lock(&arg->lk, &flock);
2213 if (req->se->op.setlk)
2214 req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
2215 else
2216 fuse_reply_err(req, ENOSYS);
2217 }
2218}
2219
2220static void _do_setlk(fuse_req_t req, const fuse_ino_t nodeid,
2221 const void *op_in, const void *in_payload)
2222{
2223 (void)in_payload;
2224 do_setlk_common(req, nodeid, op_in, 0);
2225}
2226
2227static void do_setlk(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
2228{
2229 _do_setlk(req, nodeid, inarg, NULL);
2230}
2231
2232static void _do_setlkw(fuse_req_t req, const fuse_ino_t nodeid,
2233 const void *op_in, const void *in_payload)
2234{
2235 (void)in_payload;
2236 do_setlk_common(req, nodeid, op_in, 1);
2237}
2238static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2239{
2240 _do_setlkw(req, nodeid, inarg, NULL);
2241}
2242
2243static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
2244{
2245 struct fuse_req *curr;
2246
2247 for (curr = se->list.next; curr != &se->list; curr = curr->next) {
2248 if (curr->unique == req->u.i.unique) {
2250 void *data;
2251
2252 curr->ref_cnt++;
2253 pthread_mutex_unlock(&se->lock);
2254
2255 /* Ugh, ugly locking */
2256 pthread_mutex_lock(&curr->lock);
2257 pthread_mutex_lock(&se->lock);
2258 curr->interrupted = 1;
2259 func = curr->u.ni.func;
2260 data = curr->u.ni.data;
2261 pthread_mutex_unlock(&se->lock);
2262 if (func)
2263 func(curr, data);
2264 pthread_mutex_unlock(&curr->lock);
2265
2266 pthread_mutex_lock(&se->lock);
2267 curr->ref_cnt--;
2268 if (!curr->ref_cnt) {
2269 destroy_req(curr);
2270 }
2271
2272 return 1;
2273 }
2274 }
2275 for (curr = se->interrupts.next; curr != &se->interrupts;
2276 curr = curr->next) {
2277 if (curr->u.i.unique == req->u.i.unique)
2278 return 1;
2279 }
2280 return 0;
2281}
2282
2283static void _do_interrupt(fuse_req_t req, const fuse_ino_t nodeid,
2284 const void *op_in, const void *in_payload)
2285{
2286 (void)in_payload;
2287 const struct fuse_interrupt_in *arg = op_in;
2288 struct fuse_session *se = req->se;
2289
2290 (void) nodeid;
2291 if (se->debug)
2292 fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
2293 (unsigned long long) arg->unique);
2294
2295 req->u.i.unique = arg->unique;
2296
2297 pthread_mutex_lock(&se->lock);
2298 if (find_interrupted(se, req)) {
2299 fuse_chan_put(req->ch);
2300 req->ch = NULL;
2301 destroy_req(req);
2302 } else
2303 list_add_req(req, &se->interrupts);
2304 pthread_mutex_unlock(&se->lock);
2305}
2306static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2307{
2308 _do_interrupt(req, nodeid, inarg, NULL);
2309}
2310
2311static struct fuse_req *check_interrupt(struct fuse_session *se,
2312 struct fuse_req *req)
2313{
2314 struct fuse_req *curr;
2315
2316 for (curr = se->interrupts.next; curr != &se->interrupts;
2317 curr = curr->next) {
2318 if (curr->u.i.unique == req->unique) {
2319 req->interrupted = 1;
2320 list_del_req(curr);
2321 fuse_chan_put(curr->ch);
2322 curr->ch = NULL;
2323 destroy_req(curr);
2324 return NULL;
2325 }
2326 }
2327 curr = se->interrupts.next;
2328 if (curr != &se->interrupts) {
2329 list_del_req(curr);
2330 list_init_req(curr);
2331 return curr;
2332 } else
2333 return NULL;
2334}
2335
2336static void _do_bmap(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
2337 const void *in_payload)
2338{
2339 (void)in_payload;
2340 const struct fuse_bmap_in *arg = op_in;
2341
2342 if (req->se->op.bmap)
2343 req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
2344 else
2345 fuse_reply_err(req, ENOSYS);
2346}
2347static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2348{
2349 _do_bmap(req, nodeid, inarg, NULL);
2350}
2351
2352static void _do_ioctl(fuse_req_t req, const fuse_ino_t nodeid,
2353 const void *op_in, const void *in_payload)
2354{
2355 struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *)op_in;
2356 unsigned int flags = arg->flags;
2357 const void *in_buf = in_payload;
2358 struct fuse_file_info fi;
2359
2360 if (flags & FUSE_IOCTL_DIR &&
2361 !(req->se->conn.want_ext & FUSE_CAP_IOCTL_DIR)) {
2362 fuse_reply_err(req, ENOTTY);
2363 return;
2364 }
2365
2366 memset(&fi, 0, sizeof(fi));
2367 fi.fh = arg->fh;
2368
2369 if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
2370 !(flags & FUSE_IOCTL_32BIT)) {
2371 req->flags.ioctl_64bit = 1;
2372 }
2373
2374 if (req->se->op.ioctl)
2375 req->se->op.ioctl(req, nodeid, arg->cmd,
2376 (void *)(uintptr_t)arg->arg, &fi, flags,
2377 in_buf, arg->in_size, arg->out_size);
2378 else
2379 fuse_reply_err(req, ENOSYS);
2380}
2381static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2382{
2383 const struct fuse_ioctl_in *arg = inarg;
2384 void *in_buf = arg->in_size ? PARAM(arg) : NULL;
2385
2386 _do_ioctl(req, nodeid, arg, in_buf);
2387}
2388
2389void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
2390{
2391 free(ph);
2392}
2393
2394static void _do_poll(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
2395 const void *in_payload)
2396{
2397 (void)in_payload;
2398 struct fuse_poll_in *arg = (struct fuse_poll_in *)op_in;
2399 struct fuse_file_info fi;
2400
2401 memset(&fi, 0, sizeof(fi));
2402 fi.fh = arg->fh;
2403 fi.poll_events = arg->events;
2404
2405 if (req->se->op.poll) {
2406 struct fuse_pollhandle *ph = NULL;
2407
2408 if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
2409 ph = malloc(sizeof(struct fuse_pollhandle));
2410 if (ph == NULL) {
2411 fuse_reply_err(req, ENOMEM);
2412 return;
2413 }
2414 ph->kh = arg->kh;
2415 ph->se = req->se;
2416 }
2417
2418 req->se->op.poll(req, nodeid, &fi, ph);
2419 } else {
2420 fuse_reply_err(req, ENOSYS);
2421 }
2422}
2423
2424static void do_poll(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
2425{
2426 _do_poll(req, nodeid, inarg, NULL);
2427}
2428
2429static void _do_fallocate(fuse_req_t req, const fuse_ino_t nodeid,
2430 const void *op_in, const void *in_payload)
2431{
2432 (void)in_payload;
2433 const struct fuse_fallocate_in *arg = op_in;
2434 struct fuse_file_info fi;
2435
2436 memset(&fi, 0, sizeof(fi));
2437 fi.fh = arg->fh;
2438
2439 if (req->se->op.fallocate)
2440 req->se->op.fallocate(req, nodeid, arg->mode, arg->offset,
2441 arg->length, &fi);
2442 else
2443 fuse_reply_err(req, ENOSYS);
2444}
2445
2446static void do_fallocate(fuse_req_t req, const fuse_ino_t nodeid,
2447 const void *inarg)
2448{
2449 _do_fallocate(req, nodeid, inarg, NULL);
2450}
2451
2452static void copy_file_range_common(fuse_req_t req, const fuse_ino_t nodeid_in,
2453 const struct fuse_copy_file_range_in *arg)
2454{
2455 struct fuse_file_info fi_in, fi_out;
2456
2457 memset(&fi_in, 0, sizeof(fi_in));
2458 fi_in.fh = arg->fh_in;
2459
2460 memset(&fi_out, 0, sizeof(fi_out));
2461 fi_out.fh = arg->fh_out;
2462
2463 if (req->se->op.copy_file_range)
2464 req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in,
2465 arg->nodeid_out, arg->off_out,
2466 &fi_out, arg->len, arg->flags);
2467 else
2468 fuse_reply_err(req, ENOSYS);
2469}
2470
2471static void _do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
2472 const void *op_in, const void *in_payload)
2473{
2474 const struct fuse_copy_file_range_in *arg = op_in;
2475 struct fuse_copy_file_range_in arg_tmp;
2476
2477 (void) in_payload;
2478 /* fuse_write_out can only handle 32bit copy size */
2479 if (arg->len > 0xfffff000) {
2480 arg_tmp = *arg;
2481 arg_tmp.len = 0xfffff000;
2482 arg = &arg_tmp;
2483 }
2484 copy_file_range_common(req, nodeid_in, arg);
2485}
2486
2487static void do_copy_file_range(fuse_req_t req, const fuse_ino_t nodeid_in,
2488 const void *inarg)
2489{
2490 _do_copy_file_range(req, nodeid_in, inarg, NULL);
2491}
2492
2493static void _do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in,
2494 const void *op_in, const void *in_payload)
2495{
2496 (void) in_payload;
2497 req->flags.is_copy_file_range_64 = 1;
2498 /* Limit size on 32bit userspace to avoid conversion overflow */
2499 if (sizeof(size_t) == 4)
2500 _do_copy_file_range(req, nodeid_in, op_in, NULL);
2501 else
2502 copy_file_range_common(req, nodeid_in, op_in);
2503}
2504
2505static void do_copy_file_range_64(fuse_req_t req, const fuse_ino_t nodeid_in,
2506 const void *inarg)
2507{
2508 _do_copy_file_range_64(req, nodeid_in, inarg, NULL);
2509}
2510
2511/*
2512 * Note that the uint64_t offset in struct fuse_lseek_in is derived from
2513 * linux kernel loff_t and is therefore signed.
2514 */
2515static void _do_lseek(fuse_req_t req, const fuse_ino_t nodeid,
2516 const void *op_in, const void *in_payload)
2517{
2518 (void)in_payload;
2519 const struct fuse_lseek_in *arg = op_in;
2520 struct fuse_file_info fi;
2521
2522 memset(&fi, 0, sizeof(fi));
2523 fi.fh = arg->fh;
2524
2525 if (req->se->op.lseek)
2526 req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
2527 else
2528 fuse_reply_err(req, ENOSYS);
2529}
2530
2531static void do_lseek(fuse_req_t req, const fuse_ino_t nodeid, const void *inarg)
2532{
2533 _do_lseek(req, nodeid, inarg, NULL);
2534}
2535
2536#ifdef HAVE_STATX
2537static void _do_statx(fuse_req_t req, const fuse_ino_t nodeid,
2538 const void *op_in, const void *in_payload)
2539{
2540 (void)in_payload;
2541 const struct fuse_statx_in *arg = op_in;
2542 struct fuse_file_info *fip = NULL;
2543 struct fuse_file_info fi;
2544
2545 if (arg->getattr_flags & FUSE_GETATTR_FH) {
2546 memset(&fi, 0, sizeof(fi));
2547 fi.fh = arg->fh;
2548 fip = &fi;
2549 }
2550
2551 if (req->se->op.statx)
2552 req->se->op.statx(req, nodeid, arg->sx_flags, arg->sx_mask, fip);
2553 else
2554 fuse_reply_err(req, ENOSYS);
2555}
2556#else
2557static void _do_statx(fuse_req_t req, const fuse_ino_t nodeid,
2558 const void *op_in, const void *in_payload)
2559{
2560 (void)in_payload;
2561 (void)nodeid;
2562 (void)op_in;
2563 fuse_reply_err(req, ENOSYS);
2564}
2565#endif
2566
2567static void do_statx(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2568{
2569 _do_statx(req, nodeid, inarg, NULL);
2570}
2571
2572static bool want_flags_valid(uint64_t capable, uint64_t want)
2573{
2574 uint64_t unknown_flags = want & (~capable);
2575 if (unknown_flags != 0) {
2576 fuse_log(FUSE_LOG_ERR,
2577 "fuse: unknown connection 'want' flags: 0x%08llx\n",
2578 (unsigned long long)unknown_flags);
2579 return false;
2580 }
2581 return true;
2582}
2583
2588{
2589 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
2590
2591 /*
2592 * Convert want to want_ext if necessary.
2593 * For the high level interface this function might be called
2594 * twice, once from the high level interface and once from the
2595 * low level interface. Both, with different want_ext_default and
2596 * want_default values. In order to suppress a failure for the
2597 * second call, we check if the lower 32 bits of want_ext are
2598 * already set to the value of want.
2599 */
2600 if (conn->want != se->conn_want &&
2601 fuse_lower_32_bits(conn->want_ext) != conn->want) {
2602 if (conn->want_ext != se->conn_want_ext) {
2603 fuse_log(FUSE_LOG_ERR,
2604 "%s: Both conn->want_ext and conn->want are set.\n"
2605 "want=%x want_ext=%llx, se->want=%x se->want_ext=%llx\n",
2606 __func__, conn->want,
2607 (unsigned long long)conn->want_ext,
2608 se->conn_want,
2609 (unsigned long long)se->conn_want_ext);
2610 return -EINVAL;
2611 }
2612
2613 /* high bits from want_ext, low bits from want */
2614 conn->want_ext = fuse_higher_32_bits(conn->want_ext) |
2615 conn->want;
2616 }
2617
2618 /* ensure there won't be a second conversion */
2619 conn->want = fuse_lower_32_bits(conn->want_ext);
2620
2621 return 0;
2622}
2623
2625 uint64_t flag)
2626{
2627 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
2628
2629 if (conn->capable_ext & flag) {
2630 conn->want_ext |= flag;
2631 se->conn_want_ext |= flag;
2632 conn->want |= flag;
2633 se->conn_want |= flag;
2634 return true;
2635 }
2636 return false;
2637}
2638
2640 uint64_t flag)
2641{
2642 struct fuse_session *se = container_of(conn, struct fuse_session, conn);
2643
2644 conn->want_ext &= ~flag;
2645 se->conn_want_ext &= ~flag;
2646 conn->want &= ~flag;
2647 se->conn_want &= ~flag;
2648}
2649
2651 uint64_t flag)
2652{
2653 return conn->capable_ext & flag ? true : false;
2654}
2655
2656/* Prevent bogus data races (bogus since "init" is called before
2657 * multi-threading becomes relevant */
2658static __attribute__((no_sanitize("thread"))) void
2659_do_init(fuse_req_t req, const fuse_ino_t nodeid, const void *op_in,
2660 const void *in_payload)
2661{
2662 (void)in_payload;
2663 const struct fuse_init_in *arg = op_in;
2664 struct fuse_init_out outarg;
2665 struct fuse_session *se = req->se;
2666 size_t bufsize = se->bufsize;
2667 size_t outargsize = sizeof(outarg);
2668 uint64_t inargflags = 0;
2669 uint64_t outargflags = 0;
2670 bool buf_reallocable = se->buf_reallocable;
2671 (void) nodeid;
2672 bool enable_io_uring = false;
2673
2674 if (se->debug) {
2675 fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
2676 if (arg->major == 7 && arg->minor >= 6) {
2677 fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
2678 fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
2679 arg->max_readahead);
2680 }
2681 }
2682 se->conn.proto_major = arg->major;
2683 se->conn.proto_minor = arg->minor;
2684 se->conn.capable_ext = 0;
2685 se->conn.want_ext = 0;
2686
2687 memset(&outarg, 0, sizeof(outarg));
2688 outarg.major = FUSE_KERNEL_VERSION;
2689 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
2690
2691 if (arg->major < 7) {
2692 fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
2693 arg->major, arg->minor);
2694 fuse_reply_err(req, EPROTO);
2695 return;
2696 }
2697
2698 if (arg->major > 7) {
2699 /* Wait for a second INIT request with a 7.X version */
2700 send_reply_ok(req, &outarg, sizeof(outarg));
2701 return;
2702 }
2703
2704 if (arg->minor >= 6) {
2705 if (arg->max_readahead < se->conn.max_readahead)
2706 se->conn.max_readahead = arg->max_readahead;
2707 inargflags = arg->flags;
2708 if (inargflags & FUSE_INIT_EXT)
2709 inargflags = inargflags | (uint64_t) arg->flags2 << 32;
2710 if (inargflags & FUSE_ASYNC_READ)
2711 se->conn.capable_ext |= FUSE_CAP_ASYNC_READ;
2712 if (inargflags & FUSE_POSIX_LOCKS)
2713 se->conn.capable_ext |= FUSE_CAP_POSIX_LOCKS;
2714 if (inargflags & FUSE_ATOMIC_O_TRUNC)
2715 se->conn.capable_ext |= FUSE_CAP_ATOMIC_O_TRUNC;
2716 if (inargflags & FUSE_EXPORT_SUPPORT)
2717 se->conn.capable_ext |= FUSE_CAP_EXPORT_SUPPORT;
2718 if (inargflags & FUSE_DONT_MASK)
2719 se->conn.capable_ext |= FUSE_CAP_DONT_MASK;
2720 if (inargflags & FUSE_FLOCK_LOCKS)
2721 se->conn.capable_ext |= FUSE_CAP_FLOCK_LOCKS;
2722 if (inargflags & FUSE_AUTO_INVAL_DATA)
2723 se->conn.capable_ext |= FUSE_CAP_AUTO_INVAL_DATA;
2724 if (inargflags & FUSE_DO_READDIRPLUS)
2725 se->conn.capable_ext |= FUSE_CAP_READDIRPLUS;
2726 if (inargflags & FUSE_READDIRPLUS_AUTO)
2727 se->conn.capable_ext |= FUSE_CAP_READDIRPLUS_AUTO;
2728 if (inargflags & FUSE_ASYNC_DIO)
2729 se->conn.capable_ext |= FUSE_CAP_ASYNC_DIO;
2730 if (inargflags & FUSE_WRITEBACK_CACHE)
2731 se->conn.capable_ext |= FUSE_CAP_WRITEBACK_CACHE;
2732 if (inargflags & FUSE_NO_OPEN_SUPPORT)
2733 se->conn.capable_ext |= FUSE_CAP_NO_OPEN_SUPPORT;
2734 if (inargflags & FUSE_PARALLEL_DIROPS)
2735 se->conn.capable_ext |= FUSE_CAP_PARALLEL_DIROPS;
2736 if (inargflags & FUSE_POSIX_ACL)
2737 se->conn.capable_ext |= FUSE_CAP_POSIX_ACL;
2738 if (inargflags & FUSE_HANDLE_KILLPRIV)
2739 se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV;
2740 if (inargflags & FUSE_HANDLE_KILLPRIV_V2)
2741 se->conn.capable_ext |= FUSE_CAP_HANDLE_KILLPRIV_V2;
2742 if (inargflags & FUSE_CACHE_SYMLINKS)
2743 se->conn.capable_ext |= FUSE_CAP_CACHE_SYMLINKS;
2744 if (inargflags & FUSE_NO_OPENDIR_SUPPORT)
2745 se->conn.capable_ext |= FUSE_CAP_NO_OPENDIR_SUPPORT;
2746 if (inargflags & FUSE_EXPLICIT_INVAL_DATA)
2747 se->conn.capable_ext |= FUSE_CAP_EXPLICIT_INVAL_DATA;
2748 if (inargflags & FUSE_SETXATTR_EXT)
2749 se->conn.capable_ext |= FUSE_CAP_SETXATTR_EXT;
2750 if (!(inargflags & FUSE_MAX_PAGES)) {
2751 size_t max_bufsize =
2752 FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
2753 + FUSE_BUFFER_HEADER_SIZE;
2754 if (bufsize > max_bufsize) {
2755 bufsize = max_bufsize;
2756 }
2757 buf_reallocable = false;
2758 }
2759 if (inargflags & FUSE_DIRECT_IO_ALLOW_MMAP)
2760 se->conn.capable_ext |= FUSE_CAP_DIRECT_IO_ALLOW_MMAP;
2761 if (arg->minor >= 38 || (inargflags & FUSE_HAS_EXPIRE_ONLY))
2762 se->conn.capable_ext |= FUSE_CAP_EXPIRE_ONLY;
2763 if (inargflags & FUSE_PASSTHROUGH)
2764 se->conn.capable_ext |= FUSE_CAP_PASSTHROUGH;
2765 if (inargflags & FUSE_NO_EXPORT_SUPPORT)
2766 se->conn.capable_ext |= FUSE_CAP_NO_EXPORT_SUPPORT;
2767 if (inargflags & FUSE_OVER_IO_URING)
2768 se->conn.capable_ext |= FUSE_CAP_OVER_IO_URING;
2769
2770 } else {
2771 se->conn.max_readahead = 0;
2772 }
2773
2774 if (se->conn.proto_minor >= 14) {
2775#ifdef HAVE_SPLICE
2776#ifdef HAVE_VMSPLICE
2777 if ((se->io == NULL) || (se->io->splice_send != NULL)) {
2778 se->conn.capable_ext |= FUSE_CAP_SPLICE_WRITE |
2780 }
2781#endif
2782 if ((se->io == NULL) || (se->io->splice_receive != NULL)) {
2783 se->conn.capable_ext |= FUSE_CAP_SPLICE_READ;
2784 }
2785#endif
2786 }
2787 if (se->conn.proto_minor >= 18)
2788 se->conn.capable_ext |= FUSE_CAP_IOCTL_DIR;
2789
2790 /* Default settings for modern filesystems.
2791 *
2792 * Most of these capabilities were disabled by default in
2793 * libfuse2 for backwards compatibility reasons. In libfuse3,
2794 * we can finally enable them by default (as long as they're
2795 * supported by the kernel).
2796 */
2797#define LL_SET_DEFAULT(cond, cap) \
2798 if ((cond)) \
2799 fuse_set_feature_flag(&se->conn, cap)
2800
2801 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
2802 LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
2803 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
2804 LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
2805 LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
2806 LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
2807 LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
2809 LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
2810 LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
2811 LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
2813 LL_SET_DEFAULT(1, FUSE_CAP_OVER_IO_URING);
2814
2815 /* This could safely become default, but libfuse needs an API extension
2816 * to support it
2817 * LL_SET_DEFAULT(1, FUSE_CAP_SETXATTR_EXT);
2818 */
2819
2820 se->conn.time_gran = 1;
2821
2822 if (se->op.init) {
2823 // Apply the first 32 bits of capable_ext to capable
2824 se->conn.capable = fuse_lower_32_bits(se->conn.capable_ext);
2825
2826 se->op.init(se->userdata, &se->conn);
2827
2828 /*
2829 * se->conn.want is 32-bit value and deprecated in favour of
2830 * se->conn.want_ext
2831 * Userspace might still use conn.want - we need to convert it
2832 */
2834 }
2835
2836 if (!want_flags_valid(se->conn.capable_ext, se->conn.want_ext)) {
2837 fuse_reply_err(req, EPROTO);
2838 se->error = -EPROTO;
2840 return;
2841 }
2842
2843 unsigned max_read_mo = get_max_read(se->mo);
2844 if (se->conn.max_read != max_read_mo) {
2845 fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() "
2846 "requested different maximum read size (%u vs %u)\n",
2847 se->conn.max_read, max_read_mo);
2848 fuse_reply_err(req, EPROTO);
2849 se->error = -EPROTO;
2851 return;
2852 }
2853
2854 if (bufsize < FUSE_MIN_READ_BUFFER) {
2855 fuse_log(FUSE_LOG_ERR,
2856 "fuse: warning: buffer size too small: %zu\n",
2857 bufsize);
2858 bufsize = FUSE_MIN_READ_BUFFER;
2859 }
2860
2861 if (buf_reallocable)
2862 bufsize = UINT_MAX;
2863 se->conn.max_write = MIN(se->conn.max_write, bufsize - FUSE_BUFFER_HEADER_SIZE);
2864 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
2865
2866 if (arg->flags & FUSE_MAX_PAGES) {
2867 outarg.flags |= FUSE_MAX_PAGES;
2868 outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
2869 }
2870 outargflags = outarg.flags;
2871 /* Always enable big writes, this is superseded
2872 by the max_write option */
2873 outargflags |= FUSE_BIG_WRITES;
2874
2875 if (se->conn.want_ext & FUSE_CAP_ASYNC_READ)
2876 outargflags |= FUSE_ASYNC_READ;
2877 if (se->conn.want_ext & FUSE_CAP_POSIX_LOCKS)
2878 outargflags |= FUSE_POSIX_LOCKS;
2879 if (se->conn.want_ext & FUSE_CAP_ATOMIC_O_TRUNC)
2880 outargflags |= FUSE_ATOMIC_O_TRUNC;
2881 if (se->conn.want_ext & FUSE_CAP_EXPORT_SUPPORT)
2882 outargflags |= FUSE_EXPORT_SUPPORT;
2883 if (se->conn.want_ext & FUSE_CAP_DONT_MASK)
2884 outargflags |= FUSE_DONT_MASK;
2885 if (se->conn.want_ext & FUSE_CAP_FLOCK_LOCKS)
2886 outargflags |= FUSE_FLOCK_LOCKS;
2887 if (se->conn.want_ext & FUSE_CAP_AUTO_INVAL_DATA)
2888 outargflags |= FUSE_AUTO_INVAL_DATA;
2889 if (se->conn.want_ext & FUSE_CAP_READDIRPLUS)
2890 outargflags |= FUSE_DO_READDIRPLUS;
2891 if (se->conn.want_ext & FUSE_CAP_READDIRPLUS_AUTO)
2892 outargflags |= FUSE_READDIRPLUS_AUTO;
2893 if (se->conn.want_ext & FUSE_CAP_ASYNC_DIO)
2894 outargflags |= FUSE_ASYNC_DIO;
2895 if (se->conn.want_ext & FUSE_CAP_WRITEBACK_CACHE)
2896 outargflags |= FUSE_WRITEBACK_CACHE;
2897 if (se->conn.want_ext & FUSE_CAP_PARALLEL_DIROPS)
2898 outargflags |= FUSE_PARALLEL_DIROPS;
2899 if (se->conn.want_ext & FUSE_CAP_POSIX_ACL)
2900 outargflags |= FUSE_POSIX_ACL;
2901 if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV)
2902 outargflags |= FUSE_HANDLE_KILLPRIV;
2903 if (se->conn.want_ext & FUSE_CAP_HANDLE_KILLPRIV_V2)
2904 outargflags |= FUSE_HANDLE_KILLPRIV_V2;
2905 if (se->conn.want_ext & FUSE_CAP_CACHE_SYMLINKS)
2906 outargflags |= FUSE_CACHE_SYMLINKS;
2907 if (se->conn.want_ext & FUSE_CAP_EXPLICIT_INVAL_DATA)
2908 outargflags |= FUSE_EXPLICIT_INVAL_DATA;
2909 if (se->conn.want_ext & FUSE_CAP_SETXATTR_EXT)
2910 outargflags |= FUSE_SETXATTR_EXT;
2911 if (se->conn.want_ext & FUSE_CAP_DIRECT_IO_ALLOW_MMAP)
2912 outargflags |= FUSE_DIRECT_IO_ALLOW_MMAP;
2913 if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH) {
2914 outargflags |= FUSE_PASSTHROUGH;
2915 /*
2916 * outarg.max_stack_depth includes the fuse stack layer,
2917 * so it is one more than max_backing_stack_depth.
2918 */
2919 outarg.max_stack_depth = se->conn.max_backing_stack_depth + 1;
2920 }
2921 if (se->conn.want_ext & FUSE_CAP_NO_EXPORT_SUPPORT)
2922 outargflags |= FUSE_NO_EXPORT_SUPPORT;
2923 if (se->uring.enable && se->conn.want_ext & FUSE_CAP_OVER_IO_URING) {
2924 outargflags |= FUSE_OVER_IO_URING;
2925 enable_io_uring = true;
2926 }
2927
2928 if ((inargflags & FUSE_REQUEST_TIMEOUT) && se->conn.request_timeout) {
2929 outargflags |= FUSE_REQUEST_TIMEOUT;
2930 outarg.request_timeout = se->conn.request_timeout;
2931 }
2932
2933 outarg.max_readahead = se->conn.max_readahead;
2934 outarg.max_write = se->conn.max_write;
2935 if (se->conn.proto_minor >= 13) {
2936 if (se->conn.max_background >= (1 << 16))
2937 se->conn.max_background = (1 << 16) - 1;
2938 if (se->conn.congestion_threshold > se->conn.max_background)
2939 se->conn.congestion_threshold = se->conn.max_background;
2940 if (!se->conn.congestion_threshold) {
2941 se->conn.congestion_threshold =
2942 se->conn.max_background * 3 / 4;
2943 }
2944
2945 outarg.max_background = se->conn.max_background;
2946 outarg.congestion_threshold = se->conn.congestion_threshold;
2947 }
2948 if (se->conn.proto_minor >= 23)
2949 outarg.time_gran = se->conn.time_gran;
2950
2951 if (se->debug) {
2952 fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor);
2953 fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
2954 fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n",
2955 outarg.max_readahead);
2956 fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
2957 fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n",
2958 outarg.max_background);
2959 fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n",
2960 outarg.congestion_threshold);
2961 fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n",
2962 outarg.time_gran);
2963 if (se->conn.want_ext & FUSE_CAP_PASSTHROUGH)
2964 fuse_log(FUSE_LOG_DEBUG, " max_stack_depth=%u\n",
2965 outarg.max_stack_depth);
2966 }
2967 if (arg->minor < 5)
2968 outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
2969 else if (arg->minor < 23)
2970 outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
2971
2972 /* XXX: Add an option to make non-available io-uring fatal */
2973 if (enable_io_uring) {
2974 int ring_rc = fuse_uring_start(se);
2975
2976 if (ring_rc != 0) {
2977 fuse_log(FUSE_LOG_INFO,
2978 "fuse: failed to start io-uring: %s\n",
2979 strerror(ring_rc));
2980 outargflags &= ~FUSE_OVER_IO_URING;
2981 enable_io_uring = false;
2982 }
2983 }
2984
2985 if (inargflags & FUSE_INIT_EXT) {
2986 outargflags |= FUSE_INIT_EXT;
2987 outarg.flags2 = outargflags >> 32;
2988 }
2989 outarg.flags = outargflags;
2990
2991 /*
2992 * Has to be set before replying, as new kernel requests might
2993 * immediately arrive and got_init is used for op-code sanity.
2994 * Especially with external handlers, where we have no control
2995 * over the thread scheduling.
2996 */
2997 se->got_init = 1;
2998 send_reply_ok(req, &outarg, outargsize);
2999 if (enable_io_uring)
3000 fuse_uring_wake_ring_threads(se);
3001}
3002
3003static __attribute__((no_sanitize("thread"))) void
3004do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
3005{
3006 _do_init(req, nodeid, inarg, NULL);
3007}
3008
3009static void _do_destroy(fuse_req_t req, const fuse_ino_t nodeid,
3010 const void *op_in, const void *in_payload)
3011{
3012 struct fuse_session *se = req->se;
3013 char *mountpoint;
3014
3015 (void) nodeid;
3016 (void)op_in;
3017 (void)in_payload;
3018
3019 mountpoint = atomic_exchange(&se->mountpoint, NULL);
3020 free(mountpoint);
3021
3022 se->got_destroy = 1;
3023 se->got_init = 0;
3024 if (se->op.destroy)
3025 se->op.destroy(se->userdata);
3026
3027 send_reply_ok(req, NULL, 0);
3028}
3029
3030static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
3031{
3032 _do_destroy(req, nodeid, inarg, NULL);
3033}
3034
3035static void list_del_nreq(struct fuse_notify_req *nreq)
3036{
3037 struct fuse_notify_req *prev = nreq->prev;
3038 struct fuse_notify_req *next = nreq->next;
3039 prev->next = next;
3040 next->prev = prev;
3041}
3042
3043static void list_add_nreq(struct fuse_notify_req *nreq,
3044 struct fuse_notify_req *next)
3045{
3046 struct fuse_notify_req *prev = next->prev;
3047 nreq->next = next;
3048 nreq->prev = prev;
3049 prev->next = nreq;
3050 next->prev = nreq;
3051}
3052
3053static void list_init_nreq(struct fuse_notify_req *nreq)
3054{
3055 nreq->next = nreq;
3056 nreq->prev = nreq;
3057}
3058
3059static void _do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
3060 const void *inarg, const struct fuse_buf *buf)
3061{
3062 struct fuse_session *se = req->se;
3063 struct fuse_notify_req *nreq;
3064 struct fuse_notify_req *head;
3065
3066 pthread_mutex_lock(&se->lock);
3067 head = &se->notify_list;
3068 for (nreq = head->next; nreq != head; nreq = nreq->next) {
3069 if (nreq->unique == req->unique) {
3070 list_del_nreq(nreq);
3071 break;
3072 }
3073 }
3074 pthread_mutex_unlock(&se->lock);
3075
3076 if (nreq != head)
3077 nreq->reply(nreq, req, nodeid, inarg, buf);
3078}
3079
3080static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
3081 const void *inarg, const struct fuse_buf *ibuf)
3082{
3083 struct fuse_buf buf = *ibuf;
3084
3085 buf.size -= sizeof(struct fuse_in_header);
3086 _do_notify_reply(req, nodeid, inarg, &buf);
3087}
3088
3089static int send_notify_iov(struct fuse_session *se, int notify_code,
3090 struct iovec *iov, int count)
3091{
3092 struct fuse_out_header out;
3093 struct fuse_req *req = NULL;
3094
3095 if (!se->got_init)
3096 return -ENOTCONN;
3097
3098 out.unique = 0;
3099 out.error = notify_code;
3100 iov[0].iov_base = &out;
3101 iov[0].iov_len = sizeof(struct fuse_out_header);
3102
3103 return fuse_send_msg(se, NULL, iov, count, req);
3104}
3105
3106int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
3107{
3108 if (ph != NULL) {
3109 struct fuse_notify_poll_wakeup_out outarg;
3110 struct iovec iov[2];
3111
3112 outarg.kh = ph->kh;
3113
3114 iov[1].iov_base = &outarg;
3115 iov[1].iov_len = sizeof(outarg);
3116
3117 return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
3118 } else {
3119 return 0;
3120 }
3121}
3122
3123int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
3124 off_t off, off_t len)
3125{
3126 struct fuse_notify_inval_inode_out outarg;
3127 struct iovec iov[2];
3128
3129 if (!se)
3130 return -EINVAL;
3131
3132 if (se->conn.proto_minor < 12)
3133 return -ENOSYS;
3134
3135 outarg.ino = ino;
3136 outarg.off = off;
3137 outarg.len = len;
3138
3139 iov[1].iov_base = &outarg;
3140 iov[1].iov_len = sizeof(outarg);
3141
3142 return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
3143}
3144
3145int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
3146{
3147 struct iovec iov[1];
3148
3149 if (!se)
3150 return -EINVAL;
3151
3152 if (se->conn.proto_minor < 44)
3153 return -ENOSYS;
3154
3155 return send_notify_iov(se, FUSE_NOTIFY_INC_EPOCH, iov, 1);
3156}
3157
3177static int fuse_lowlevel_notify_entry(struct fuse_session *se, fuse_ino_t parent,
3178 const char *name, size_t namelen,
3179 enum fuse_notify_entry_flags flags)
3180{
3181 struct fuse_notify_inval_entry_out outarg;
3182 struct iovec iov[3];
3183
3184 if (!se)
3185 return -EINVAL;
3186
3187 if (se->conn.proto_minor < 12)
3188 return -ENOSYS;
3189
3190 outarg.parent = parent;
3191 outarg.namelen = namelen;
3192 outarg.flags = 0;
3193 if (flags & FUSE_LL_EXPIRE_ONLY)
3194 outarg.flags |= FUSE_EXPIRE_ONLY;
3195
3196 iov[1].iov_base = &outarg;
3197 iov[1].iov_len = sizeof(outarg);
3198 iov[2].iov_base = (void *)name;
3199 iov[2].iov_len = namelen + 1;
3200
3201 return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
3202}
3203
3204int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
3205 const char *name, size_t namelen)
3206{
3207 return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_INVALIDATE);
3208}
3209
3210int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent,
3211 const char *name, size_t namelen)
3212{
3213 if (!se)
3214 return -EINVAL;
3215
3216 if (!(se->conn.capable_ext & FUSE_CAP_EXPIRE_ONLY))
3217 return -ENOSYS;
3218
3219 return fuse_lowlevel_notify_entry(se, parent, name, namelen, FUSE_LL_EXPIRE_ONLY);
3220}
3221
3222
3223int fuse_lowlevel_notify_delete(struct fuse_session *se,
3224 fuse_ino_t parent, fuse_ino_t child,
3225 const char *name, size_t namelen)
3226{
3227 struct fuse_notify_delete_out outarg;
3228 struct iovec iov[3];
3229
3230 if (!se)
3231 return -EINVAL;
3232
3233 if (se->conn.proto_minor < 18)
3234 return -ENOSYS;
3235
3236 outarg.parent = parent;
3237 outarg.child = child;
3238 outarg.namelen = namelen;
3239 outarg.padding = 0;
3240
3241 iov[1].iov_base = &outarg;
3242 iov[1].iov_len = sizeof(outarg);
3243 iov[2].iov_base = (void *)name;
3244 iov[2].iov_len = namelen + 1;
3245
3246 return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
3247}
3248
3249int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
3250 off_t offset, struct fuse_bufvec *bufv,
3251 enum fuse_buf_copy_flags flags)
3252{
3253 struct fuse_out_header out;
3254 struct fuse_notify_store_out outarg;
3255 struct iovec iov[3];
3256 size_t size = fuse_buf_size(bufv);
3257 int res;
3258 struct fuse_req *req = NULL;
3259
3260 if (!se)
3261 return -EINVAL;
3262
3263 if (se->conn.proto_minor < 15)
3264 return -ENOSYS;
3265
3266 out.unique = 0;
3267 out.error = FUSE_NOTIFY_STORE;
3268
3269 outarg.nodeid = ino;
3270 outarg.offset = offset;
3271 outarg.size = size;
3272 outarg.padding = 0;
3273
3274 iov[0].iov_base = &out;
3275 iov[0].iov_len = sizeof(out);
3276 iov[1].iov_base = &outarg;
3277 iov[1].iov_len = sizeof(outarg);
3278
3279 res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags, req);
3280 if (res > 0)
3281 res = -res;
3282
3283 return res;
3284}
3285
3286struct fuse_retrieve_req {
3287 struct fuse_notify_req nreq;
3288 void *cookie;
3289};
3290
3291static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
3292 fuse_req_t req, fuse_ino_t ino,
3293 const void *inarg,
3294 const struct fuse_buf *ibuf)
3295{
3296 struct fuse_session *se = req->se;
3297 struct fuse_retrieve_req *rreq =
3298 container_of(nreq, struct fuse_retrieve_req, nreq);
3299 const struct fuse_notify_retrieve_in *arg = inarg;
3300 struct fuse_bufvec bufv = {
3301 .buf[0] = *ibuf,
3302 .count = 1,
3303 };
3304
3305 if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
3306 bufv.buf[0].mem = PARAM(arg);
3307
3308 bufv.buf[0].size -= sizeof(struct fuse_notify_retrieve_in);
3309
3310 if (bufv.buf[0].size < arg->size) {
3311 fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
3312 fuse_reply_none(req);
3313 goto out;
3314 }
3315 bufv.buf[0].size = arg->size;
3316
3317 if (se->op.retrieve_reply) {
3318 se->op.retrieve_reply(req, rreq->cookie, ino,
3319 arg->offset, &bufv);
3320 } else {
3321 fuse_reply_none(req);
3322 }
3323out:
3324 free(rreq);
3325 if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
3326 fuse_ll_clear_pipe(se);
3327}
3328
3329int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
3330 size_t size, off_t offset, void *cookie)
3331{
3332 struct fuse_notify_retrieve_out outarg;
3333 struct iovec iov[2];
3334 struct fuse_retrieve_req *rreq;
3335 int err;
3336
3337 if (!se)
3338 return -EINVAL;
3339
3340 if (se->conn.proto_minor < 15)
3341 return -ENOSYS;
3342
3343 rreq = malloc(sizeof(*rreq));
3344 if (rreq == NULL)
3345 return -ENOMEM;
3346
3347 pthread_mutex_lock(&se->lock);
3348 rreq->cookie = cookie;
3349 rreq->nreq.unique = se->notify_ctr++;
3350 rreq->nreq.reply = fuse_ll_retrieve_reply;
3351 list_add_nreq(&rreq->nreq, &se->notify_list);
3352 pthread_mutex_unlock(&se->lock);
3353
3354 outarg.notify_unique = rreq->nreq.unique;
3355 outarg.nodeid = ino;
3356 outarg.offset = offset;
3357 outarg.size = size;
3358 outarg.padding = 0;
3359
3360 iov[1].iov_base = &outarg;
3361 iov[1].iov_len = sizeof(outarg);
3362
3363 err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
3364 if (err) {
3365 pthread_mutex_lock(&se->lock);
3366 list_del_nreq(&rreq->nreq);
3367 pthread_mutex_unlock(&se->lock);
3368 free(rreq);
3369 }
3370
3371 return err;
3372}
3373
3375{
3376 return req->se->userdata;
3377}
3378
3380{
3381 return &req->ctx;
3382}
3383
3385 void *data)
3386{
3387 pthread_mutex_lock(&req->lock);
3388 pthread_mutex_lock(&req->se->lock);
3389 req->u.ni.func = func;
3390 req->u.ni.data = data;
3391 pthread_mutex_unlock(&req->se->lock);
3392 if (req->interrupted && func)
3393 func(req, data);
3394 pthread_mutex_unlock(&req->lock);
3395}
3396
3398{
3399 int interrupted;
3400
3401 pthread_mutex_lock(&req->se->lock);
3402 interrupted = req->interrupted;
3403 pthread_mutex_unlock(&req->se->lock);
3404
3405 return interrupted;
3406}
3407
3409{
3410 return req->flags.is_uring;
3411}
3412
3413#ifndef HAVE_URING
3414int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz,
3415 void **mr)
3416{
3417 (void)req;
3418 (void)payload;
3419 (void)payload_sz;
3420 (void)mr;
3421 return -ENOTSUP;
3422}
3423#endif
3424
3425static struct {
3426 void (*func)(fuse_req_t req, const fuse_ino_t node, const void *arg);
3427 const char *name;
3428} fuse_ll_ops[] = {
3429 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
3430 [FUSE_FORGET] = { do_forget, "FORGET" },
3431 [FUSE_GETATTR] = { do_getattr, "GETATTR" },
3432 [FUSE_SETATTR] = { do_setattr, "SETATTR" },
3433 [FUSE_READLINK] = { do_readlink, "READLINK" },
3434 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
3435 [FUSE_MKNOD] = { do_mknod, "MKNOD" },
3436 [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
3437 [FUSE_UNLINK] = { do_unlink, "UNLINK" },
3438 [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
3439 [FUSE_RENAME] = { do_rename, "RENAME" },
3440 [FUSE_LINK] = { do_link, "LINK" },
3441 [FUSE_OPEN] = { do_open, "OPEN" },
3442 [FUSE_READ] = { do_read, "READ" },
3443 [FUSE_WRITE] = { do_write, "WRITE" },
3444 [FUSE_STATFS] = { do_statfs, "STATFS" },
3445 [FUSE_RELEASE] = { do_release, "RELEASE" },
3446 [FUSE_FSYNC] = { do_fsync, "FSYNC" },
3447 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
3448 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
3449 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
3450 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
3451 [FUSE_FLUSH] = { do_flush, "FLUSH" },
3452 [FUSE_INIT] = { do_init, "INIT" },
3453 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
3454 [FUSE_READDIR] = { do_readdir, "READDIR" },
3455 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
3456 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
3457 [FUSE_GETLK] = { do_getlk, "GETLK" },
3458 [FUSE_SETLK] = { do_setlk, "SETLK" },
3459 [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
3460 [FUSE_ACCESS] = { do_access, "ACCESS" },
3461 [FUSE_CREATE] = { do_create, "CREATE" },
3462 [FUSE_TMPFILE] = { do_tmpfile, "TMPFILE" },
3463 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
3464 [FUSE_BMAP] = { do_bmap, "BMAP" },
3465 [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
3466 [FUSE_POLL] = { do_poll, "POLL" },
3467 [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
3468 [FUSE_DESTROY] = { do_destroy, "DESTROY" },
3469 [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
3470 [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
3471 [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
3472 [FUSE_RENAME2] = { do_rename2, "RENAME2" },
3473 [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
3474 [FUSE_COPY_FILE_RANGE_64] = { do_copy_file_range_64, "COPY_FILE_RANGE_64" },
3475 [FUSE_LSEEK] = { do_lseek, "LSEEK" },
3476 [FUSE_STATX] = { do_statx, "STATX" },
3477 [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
3478};
3479
3480static struct {
3481 void (*func)(fuse_req_t req, const fuse_ino_t ino, const void *op_in,
3482 const void *op_payload);
3483 const char *name;
3484} fuse_ll_ops2[] __attribute__((unused)) = {
3485 [FUSE_LOOKUP] = { _do_lookup, "LOOKUP" },
3486 [FUSE_FORGET] = { _do_forget, "FORGET" },
3487 [FUSE_GETATTR] = { _do_getattr, "GETATTR" },
3488 [FUSE_SETATTR] = { _do_setattr, "SETATTR" },
3489 [FUSE_READLINK] = { _do_readlink, "READLINK" },
3490 [FUSE_SYMLINK] = { _do_symlink, "SYMLINK" },
3491 [FUSE_MKNOD] = { _do_mknod, "MKNOD" },
3492 [FUSE_MKDIR] = { _do_mkdir, "MKDIR" },
3493 [FUSE_UNLINK] = { _do_unlink, "UNLINK" },
3494 [FUSE_RMDIR] = { _do_rmdir, "RMDIR" },
3495 [FUSE_RENAME] = { _do_rename, "RENAME" },
3496 [FUSE_LINK] = { _do_link, "LINK" },
3497 [FUSE_OPEN] = { _do_open, "OPEN" },
3498 [FUSE_READ] = { _do_read, "READ" },
3499 [FUSE_WRITE] = { _do_write, "WRITE" },
3500 [FUSE_STATFS] = { _do_statfs, "STATFS" },
3501 [FUSE_RELEASE] = { _do_release, "RELEASE" },
3502 [FUSE_FSYNC] = { _do_fsync, "FSYNC" },
3503 [FUSE_SETXATTR] = { _do_setxattr, "SETXATTR" },
3504 [FUSE_GETXATTR] = { _do_getxattr, "GETXATTR" },
3505 [FUSE_LISTXATTR] = { _do_listxattr, "LISTXATTR" },
3506 [FUSE_REMOVEXATTR] = { _do_removexattr, "REMOVEXATTR" },
3507 [FUSE_FLUSH] = { _do_flush, "FLUSH" },
3508 [FUSE_INIT] = { _do_init, "INIT" },
3509 [FUSE_OPENDIR] = { _do_opendir, "OPENDIR" },
3510 [FUSE_READDIR] = { _do_readdir, "READDIR" },
3511 [FUSE_RELEASEDIR] = { _do_releasedir, "RELEASEDIR" },
3512 [FUSE_FSYNCDIR] = { _do_fsyncdir, "FSYNCDIR" },
3513 [FUSE_GETLK] = { _do_getlk, "GETLK" },
3514 [FUSE_SETLK] = { _do_setlk, "SETLK" },
3515 [FUSE_SETLKW] = { _do_setlkw, "SETLKW" },
3516 [FUSE_ACCESS] = { _do_access, "ACCESS" },
3517 [FUSE_CREATE] = { _do_create, "CREATE" },
3518 [FUSE_TMPFILE] = { _do_tmpfile, "TMPFILE" },
3519 [FUSE_INTERRUPT] = { _do_interrupt, "INTERRUPT" },
3520 [FUSE_BMAP] = { _do_bmap, "BMAP" },
3521 [FUSE_IOCTL] = { _do_ioctl, "IOCTL" },
3522 [FUSE_POLL] = { _do_poll, "POLL" },
3523 [FUSE_FALLOCATE] = { _do_fallocate, "FALLOCATE" },
3524 [FUSE_DESTROY] = { _do_destroy, "DESTROY" },
3525 [FUSE_NOTIFY_REPLY] = { (void *)1, "NOTIFY_REPLY" },
3526 [FUSE_BATCH_FORGET] = { _do_batch_forget, "BATCH_FORGET" },
3527 [FUSE_READDIRPLUS] = { _do_readdirplus, "READDIRPLUS" },
3528 [FUSE_RENAME2] = { _do_rename2, "RENAME2" },
3529 [FUSE_COPY_FILE_RANGE] = { _do_copy_file_range, "COPY_FILE_RANGE" },
3530 [FUSE_COPY_FILE_RANGE_64] = { _do_copy_file_range_64, "COPY_FILE_RANGE_64" },
3531 [FUSE_LSEEK] = { _do_lseek, "LSEEK" },
3532 [FUSE_STATX] = { _do_statx, "STATX" },
3533 [CUSE_INIT] = { _cuse_lowlevel_init, "CUSE_INIT" },
3534};
3535
3536/*
3537 * For ABI compatibility we cannot allow higher values than CUSE_INIT.
3538 * Without ABI compatibility we could use the size of the array.
3539 * #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
3540 */
3541#define FUSE_MAXOP (CUSE_INIT + 1)
3542
3543
3548static inline int
3549fuse_req_opcode_sanity_ok(struct fuse_session *se, enum fuse_opcode in_op)
3550{
3551 int err = EIO;
3552
3553 if (!se->got_init) {
3554 enum fuse_opcode expected;
3555
3556 expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
3557 if (in_op != expected)
3558 return err;
3559 } else if (in_op == FUSE_INIT || in_op == CUSE_INIT)
3560 return err;
3561
3562 return 0;
3563}
3564
3565static inline void
3566fuse_session_in2req(struct fuse_req *req, struct fuse_in_header *in)
3567{
3568 req->unique = in->unique;
3569 req->ctx.uid = in->uid;
3570 req->ctx.gid = in->gid;
3571 req->ctx.pid = in->pid;
3572}
3573
3577static inline int
3578fuse_req_check_allow_root(struct fuse_session *se, enum fuse_opcode in_op,
3579 uid_t in_uid)
3580{
3581 int err = EACCES;
3582
3583 if (se->deny_others && in_uid != se->owner && in_uid != 0 &&
3584 in_op != FUSE_INIT && in_op != FUSE_READ &&
3585 in_op != FUSE_WRITE && in_op != FUSE_FSYNC &&
3586 in_op != FUSE_RELEASE && in_op != FUSE_READDIR &&
3587 in_op != FUSE_FSYNCDIR && in_op != FUSE_RELEASEDIR &&
3588 in_op != FUSE_NOTIFY_REPLY &&
3589 in_op != FUSE_READDIRPLUS)
3590 return err;
3591
3592 return 0;
3593}
3594
3595static const char *opname(enum fuse_opcode opcode)
3596{
3597 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
3598 return "???";
3599 else
3600 return fuse_ll_ops[opcode].name;
3601}
3602
3603static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
3604 struct fuse_bufvec *src)
3605{
3606 ssize_t res = fuse_buf_copy(dst, src, 0);
3607 if (res < 0) {
3608 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res));
3609 return res;
3610 }
3611 if ((size_t)res < fuse_buf_size(dst)) {
3612 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
3613 return -1;
3614 }
3615 return 0;
3616}
3617
3618void fuse_session_process_buf(struct fuse_session *se,
3619 const struct fuse_buf *buf)
3620{
3621 fuse_session_process_buf_internal(se, buf, NULL);
3622}
3623
3624/* libfuse internal handler */
3625void fuse_session_process_buf_internal(struct fuse_session *se,
3626 const struct fuse_buf *buf, struct fuse_chan *ch)
3627{
3628 const size_t write_header_size = sizeof(struct fuse_in_header) +
3629 sizeof(struct fuse_write_in);
3630 struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
3631 struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
3632 struct fuse_in_header *in;
3633 const void *inarg;
3634 struct fuse_req *req;
3635 void *mbuf = NULL;
3636 int err;
3637 int res;
3638
3639 if (buf->flags & FUSE_BUF_IS_FD) {
3640 if (buf->size < tmpbuf.buf[0].size)
3641 tmpbuf.buf[0].size = buf->size;
3642
3643 mbuf = malloc(tmpbuf.buf[0].size);
3644 if (mbuf == NULL) {
3645 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n");
3646 goto clear_pipe;
3647 }
3648 tmpbuf.buf[0].mem = mbuf;
3649
3650 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
3651 if (res < 0)
3652 goto clear_pipe;
3653
3654 in = mbuf;
3655 } else {
3656 in = buf->mem;
3657 }
3658
3659 trace_request_process(in->opcode, in->unique);
3660
3661 if (se->debug) {
3662 fuse_log(FUSE_LOG_DEBUG,
3663 "dev unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
3664 (unsigned long long) in->unique,
3665 opname((enum fuse_opcode) in->opcode), in->opcode,
3666 (unsigned long long) in->nodeid, buf->size, in->pid);
3667 }
3668
3669 req = fuse_ll_alloc_req(se);
3670 if (req == NULL) {
3671 struct fuse_out_header out = {
3672 .unique = in->unique,
3673 .error = -ENOMEM,
3674 };
3675 struct iovec iov = {
3676 .iov_base = &out,
3677 .iov_len = sizeof(struct fuse_out_header),
3678 };
3679
3680 fuse_send_msg(se, ch, &iov, 1, NULL);
3681 goto clear_pipe;
3682 }
3683
3684 fuse_session_in2req(req, in);
3685 req->ch = ch ? fuse_chan_get(ch) : NULL;
3686
3687 err = fuse_req_opcode_sanity_ok(se, in->opcode);
3688 if (err)
3689 goto reply_err;
3690
3691 err = fuse_req_check_allow_root(se, in->opcode, in->uid);
3692 if (err)
3693 goto reply_err;
3694
3695 err = ENOSYS;
3696 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
3697 goto reply_err;
3698 /* Do not process interrupt request */
3699 if (se->conn.no_interrupt && in->opcode == FUSE_INTERRUPT) {
3700 if (se->debug)
3701 fuse_log(FUSE_LOG_DEBUG, "FUSE_INTERRUPT: reply to kernel to disable interrupt\n");
3702 goto reply_err;
3703 }
3704 if (!se->conn.no_interrupt && in->opcode != FUSE_INTERRUPT) {
3705 struct fuse_req *intr;
3706 pthread_mutex_lock(&se->lock);
3707 intr = check_interrupt(se, req);
3708 list_add_req(req, &se->list);
3709 pthread_mutex_unlock(&se->lock);
3710 if (intr)
3711 fuse_reply_err(intr, EAGAIN);
3712 }
3713
3714 if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
3715 (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
3716 in->opcode != FUSE_NOTIFY_REPLY) {
3717 void *newmbuf;
3718
3719 err = ENOMEM;
3720 newmbuf = realloc(mbuf, buf->size);
3721 if (newmbuf == NULL)
3722 goto reply_err;
3723 mbuf = newmbuf;
3724
3725 tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
3726 tmpbuf.buf[0].mem = (char *)mbuf + write_header_size;
3727
3728 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
3729 err = -res;
3730 if (res < 0)
3731 goto reply_err;
3732
3733 in = mbuf;
3734 }
3735
3736 inarg = (void *) &in[1];
3737 if (in->opcode == FUSE_WRITE && se->op.write_buf)
3738 do_write_buf(req, in->nodeid, inarg, buf);
3739 else if (in->opcode == FUSE_NOTIFY_REPLY)
3740 do_notify_reply(req, in->nodeid, inarg, buf);
3741 else
3742 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
3743
3744out_free:
3745 free(mbuf);
3746 return;
3747
3748reply_err:
3749 fuse_reply_err(req, err);
3750clear_pipe:
3751 if (buf->flags & FUSE_BUF_IS_FD)
3752 fuse_ll_clear_pipe(se);
3753 goto out_free;
3754}
3755
3756void fuse_session_process_uring_cqe(struct fuse_session *se,
3757 struct fuse_req *req,
3758 struct fuse_in_header *in, void *op_in,
3759 void *op_payload, size_t payload_len)
3760{
3761 int err;
3762
3763 fuse_session_in2req(req, in);
3764
3765 err = fuse_req_opcode_sanity_ok(se, in->opcode);
3766 if (err)
3767 goto reply_err;
3768
3769 err = fuse_req_check_allow_root(se, in->opcode, in->uid);
3770 if (err)
3771 goto reply_err;
3772
3773 err = ENOSYS;
3774 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops2[in->opcode].func)
3775 goto reply_err;
3776
3777 if (se->debug) {
3778 fuse_log(
3779 FUSE_LOG_DEBUG,
3780 "cqe unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
3781 (unsigned long long)in->unique,
3782 opname((enum fuse_opcode)in->opcode), in->opcode,
3783 (unsigned long long)in->nodeid, payload_len, in->pid);
3784 }
3785
3786 if (in->opcode == FUSE_WRITE && se->op.write_buf) {
3787 struct fuse_bufvec bufv = {
3788 .buf[0] = { .size = payload_len,
3789 .flags = 0,
3790 .mem = op_payload },
3791 .count = 1,
3792 };
3793 _do_write_buf(req, in->nodeid, op_in, &bufv);
3794 } else if (in->opcode == FUSE_NOTIFY_REPLY) {
3795 struct fuse_buf buf = { .size = payload_len,
3796 .mem = op_payload };
3797 _do_notify_reply(req, in->nodeid, op_payload, &buf);
3798 } else {
3799 fuse_ll_ops2[in->opcode].func(req, in->nodeid, op_in,
3800 op_payload);
3801 }
3802
3803 return;
3804
3805reply_err:
3806 fuse_reply_err(req, err);
3807}
3808
3809#define LL_OPTION(n,o,v) \
3810 { n, offsetof(struct fuse_session, o), v }
3811
3812static const struct fuse_opt fuse_ll_opts[] = {
3813 LL_OPTION("debug", debug, 1),
3814 LL_OPTION("-d", debug, 1),
3815 LL_OPTION("--debug", debug, 1),
3816 LL_OPTION("allow_root", deny_others, 1),
3817 LL_OPTION("io_uring", uring.enable, 1),
3818 LL_OPTION("io_uring_q_depth=%u", uring.q_depth, -1),
3820};
3821
3823{
3824 printf("using FUSE kernel interface version %i.%i\n",
3825 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
3826 fuse_mount_version();
3827}
3828
3830{
3831 /* These are not all options, but the ones that are
3832 potentially of interest to an end-user */
3833 printf(
3834" -o allow_other allow access by all users\n"
3835" -o allow_root allow access by root\n"
3836" -o auto_unmount auto unmount on process termination\n"
3837" -o io_uring enable io-uring\n"
3838" -o io_uring_q_depth=<n> io-uring queue depth\n"
3839);
3840}
3841
3842void fuse_session_destroy(struct fuse_session *se)
3843{
3844 struct fuse_ll_pipe *llp;
3845
3846 if (se->got_init && !se->got_destroy) {
3847 if (se->op.destroy)
3848 se->op.destroy(se->userdata);
3849 }
3850 llp = pthread_getspecific(se->pipe_key);
3851 if (llp != NULL)
3852 fuse_ll_pipe_free(llp);
3853 pthread_key_delete(se->pipe_key);
3854 sem_destroy(&se->mt_finish);
3855 pthread_mutex_destroy(&se->mt_lock);
3856 pthread_mutex_destroy(&se->lock);
3857 free(se->cuse_data);
3858 if (se->fd != -1)
3859 close(se->fd);
3860 if (se->io != NULL)
3861 free(se->io);
3862 destroy_mount_opts(se->mo);
3863 free(atomic_exchange(&se->mountpoint, NULL));
3864 free(se);
3865}
3866
3867
3868static void fuse_ll_pipe_destructor(void *data)
3869{
3870 struct fuse_ll_pipe *llp = data;
3871 fuse_ll_pipe_free(llp);
3872}
3873
3874void fuse_buf_free(struct fuse_buf *buf)
3875{
3876 if (buf->mem == NULL)
3877 return;
3878
3879 size_t write_header_sz =
3880 sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in);
3881
3882 char *ptr = (char *)buf->mem - pagesize + write_header_sz;
3883 free(ptr);
3884 buf->mem = NULL;
3885}
3886
3887/*
3888 * This is used to allocate buffers that hold fuse requests
3889 */
3890static void *buf_alloc(size_t size, bool internal)
3891{
3892 /*
3893 * For libfuse internal caller add in alignment. That cannot be done
3894 * for an external caller, as it is not guaranteed that the external
3895 * caller frees the raw pointer.
3896 */
3897 if (internal) {
3898 size_t write_header_sz = sizeof(struct fuse_in_header) +
3899 sizeof(struct fuse_write_in);
3900 size_t new_size = ROUND_UP(size + write_header_sz, pagesize);
3901
3902 char *buf = aligned_alloc(pagesize, new_size);
3903 if (buf == NULL)
3904 return NULL;
3905
3906 buf += pagesize - write_header_sz;
3907
3908 return buf;
3909 } else {
3910 return malloc(size);
3911 }
3912}
3913
3914/*
3915 *@param internal true if called from libfuse internal code
3916 */
3917static int _fuse_session_receive_buf(struct fuse_session *se,
3918 struct fuse_buf *buf, struct fuse_chan *ch,
3919 bool internal)
3920{
3921 int err;
3922 ssize_t res;
3923 size_t bufsize;
3924#ifdef HAVE_SPLICE
3925 struct fuse_ll_pipe *llp;
3926 struct fuse_buf tmpbuf;
3927
3928pipe_retry:
3929 bufsize = se->bufsize;
3930
3931 if (se->conn.proto_minor < 14 ||
3932 !(se->conn.want_ext & FUSE_CAP_SPLICE_READ))
3933 goto fallback;
3934
3935 llp = fuse_ll_get_pipe(se);
3936 if (llp == NULL)
3937 goto fallback;
3938
3939 if (llp->size < bufsize) {
3940 if (llp->can_grow) {
3941 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
3942 if (res == -1) {
3943 llp->can_grow = 0;
3944 res = grow_pipe_to_max(llp->pipe[0]);
3945 if (res > 0)
3946 llp->size = res;
3947 fuse_ll_clear_pipe(se);
3948 goto fallback;
3949 }
3950 llp->size = res;
3951 }
3952 if (llp->size < bufsize) {
3953 fuse_ll_clear_pipe(se);
3954 goto fallback;
3955 }
3956 }
3957
3958 if (se->io != NULL && se->io->splice_receive != NULL) {
3959 res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL,
3960 llp->pipe[1], NULL, bufsize, 0,
3961 se->userdata);
3962 } else {
3963 res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL,
3964 bufsize, 0);
3965 }
3966 err = errno;
3967 trace_request_receive(err);
3968
3969 if (fuse_session_exited(se))
3970 return 0;
3971
3972 if (res == -1) {
3973 if (err == ENODEV) {
3974 /* Filesystem was unmounted, or connection was aborted
3975 via /sys/fs/fuse/connections */
3977 return 0;
3978 }
3979
3980 /* FUSE_INIT might have increased the required bufsize */
3981 if (err == EINVAL && bufsize < se->bufsize) {
3982 fuse_ll_clear_pipe(se);
3983 goto pipe_retry;
3984 }
3985
3986 if (err != EINTR && err != EAGAIN)
3987 perror("fuse: splice from device");
3988 return -err;
3989 }
3990
3991 if (res < sizeof(struct fuse_in_header)) {
3992 fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n");
3993 return -EIO;
3994 }
3995
3996 tmpbuf = (struct fuse_buf){
3997 .size = res,
3998 .flags = FUSE_BUF_IS_FD,
3999 .fd = llp->pipe[0],
4000 };
4001
4002 /*
4003 * Don't bother with zero copy for small requests.
4004 * fuse_loop_mt() needs to check for FORGET so this more than
4005 * just an optimization.
4006 */
4007 if (res < sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) +
4008 pagesize) {
4009 struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
4010 struct fuse_bufvec dst = { .count = 1 };
4011
4012 if (!buf->mem) {
4013 buf->mem = buf_alloc(bufsize, internal);
4014 if (!buf->mem) {
4015 fuse_log(
4016 FUSE_LOG_ERR,
4017 "fuse: failed to allocate read buffer\n");
4018 return -ENOMEM;
4019 }
4020 buf->mem_size = bufsize;
4021 }
4022 buf->size = bufsize;
4023 buf->flags = 0;
4024 dst.buf[0] = *buf;
4025
4026 res = fuse_buf_copy(&dst, &src, 0);
4027 if (res < 0) {
4028 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
4029 strerror(-res));
4030 fuse_ll_clear_pipe(se);
4031 return res;
4032 }
4033 if (res < tmpbuf.size) {
4034 fuse_log(FUSE_LOG_ERR,
4035 "fuse: copy from pipe: short read\n");
4036 fuse_ll_clear_pipe(se);
4037 return -EIO;
4038 }
4039 assert(res == tmpbuf.size);
4040
4041 } else {
4042 /* Don't overwrite buf->mem, as that would cause a leak */
4043 buf->fd = tmpbuf.fd;
4044 buf->flags = tmpbuf.flags;
4045 }
4046 buf->size = tmpbuf.size;
4047
4048 return res;
4049
4050fallback:
4051#endif
4052 bufsize = internal ? buf->mem_size : se->bufsize;
4053 if (!buf->mem) {
4054 bufsize = se->bufsize; /* might have changed */
4055 buf->mem = buf_alloc(bufsize, internal);
4056 if (!buf->mem) {
4057 fuse_log(FUSE_LOG_ERR,
4058 "fuse: failed to allocate read buffer\n");
4059 return -ENOMEM;
4060 }
4061
4062 if (internal)
4063 buf->mem_size = bufsize;
4064 }
4065
4066restart:
4067 if (se->io != NULL) {
4068 /* se->io->read is never NULL if se->io is not NULL as
4069 specified by fuse_session_custom_io()*/
4070 res = se->io->read(ch ? ch->fd : se->fd, buf->mem, bufsize,
4071 se->userdata);
4072 } else {
4073 res = read(ch ? ch->fd : se->fd, buf->mem, bufsize);
4074 }
4075 err = errno;
4076 trace_request_receive(err);
4077
4078 if (fuse_session_exited(se))
4079 return 0;
4080 if (res == -1) {
4081 if (err == EINVAL && internal && se->bufsize > bufsize) {
4082 /* FUSE_INIT might have increased the required bufsize */
4083 bufsize = se->bufsize;
4084 void *newbuf = buf_alloc(bufsize, internal);
4085 if (!newbuf) {
4086 fuse_log(
4087 FUSE_LOG_ERR,
4088 "fuse: failed to (re)allocate read buffer\n");
4089 return -ENOMEM;
4090 }
4091 fuse_buf_free(buf);
4092 buf->mem = newbuf;
4093 buf->mem_size = bufsize;
4094 goto restart;
4095 }
4096
4097 /* ENOENT means the operation was interrupted, it's safe
4098 to restart */
4099 if (err == ENOENT)
4100 goto restart;
4101
4102 if (err == ENODEV) {
4103 /* Filesystem was unmounted, or connection was aborted
4104 via /sys/fs/fuse/connections */
4106 return 0;
4107 }
4108 /* Errors occurring during normal operation: EINTR (read
4109 interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
4110 umounted) */
4111 if (err != EINTR && err != EAGAIN)
4112 perror("fuse: reading device");
4113 return -err;
4114 }
4115 if ((size_t)res < sizeof(struct fuse_in_header)) {
4116 fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
4117 return -EIO;
4118 }
4119
4120 buf->size = res;
4121
4122 return res;
4123}
4124
4125int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
4126{
4127 return _fuse_session_receive_buf(se, buf, NULL, false);
4128}
4129
4130/* libfuse internal handler */
4131int fuse_session_receive_buf_internal(struct fuse_session *se,
4132 struct fuse_buf *buf,
4133 struct fuse_chan *ch)
4134{
4135 /*
4136 * if run internally thread buffers are from libfuse - we can
4137 * reallocate them
4138 */
4139 if (unlikely(!se->got_init) && !se->buf_reallocable)
4140 se->buf_reallocable = true;
4141
4142 return _fuse_session_receive_buf(se, buf, ch, true);
4143}
4144
4145struct fuse_session *
4146fuse_session_new_versioned(struct fuse_args *args,
4147 const struct fuse_lowlevel_ops *op, size_t op_size,
4148 struct libfuse_version *version, void *userdata)
4149{
4150 int err;
4151 struct fuse_session *se;
4152 struct mount_opts *mo;
4153
4154 if (op == NULL || op_size == 0) {
4155 fuse_log(FUSE_LOG_ERR,
4156 "fuse: warning: empty op list passed to fuse_session_new()\n");
4157 return NULL;
4158 }
4159
4160 if (version == NULL) {
4161 fuse_log(FUSE_LOG_ERR, "fuse: warning: version not passed to fuse_session_new()\n");
4162 return NULL;
4163 }
4164
4165 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
4166 fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
4167 op_size = sizeof(struct fuse_lowlevel_ops);
4168 }
4169
4170 if (args == NULL || args->argc == 0) {
4171 fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
4172 return NULL;
4173 }
4174
4175 se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
4176 if (se == NULL) {
4177 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
4178 goto out1;
4179 }
4180 se->fd = -1;
4181 se->conn.max_write = FUSE_DEFAULT_MAX_PAGES_LIMIT * getpagesize();
4182 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
4183 se->conn.max_readahead = UINT_MAX;
4184
4185 /*
4186 * Allow overriding with env, mostly to avoid the need to modify
4187 * all tests. I.e. to test with and without io-uring being enabled.
4188 */
4189 se->uring.enable = getenv("FUSE_URING_ENABLE") ?
4190 atoi(getenv("FUSE_URING_ENABLE")) :
4191 SESSION_DEF_URING_ENABLE;
4192 se->uring.q_depth = getenv("FUSE_URING_QUEUE_DEPTH") ?
4193 atoi(getenv("FUSE_URING_QUEUE_DEPTH")) :
4194 SESSION_DEF_URING_Q_DEPTH;
4195
4196 /* Parse options */
4197 if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
4198 goto out2;
4199 if(se->deny_others) {
4200 /* Allowing access only by root is done by instructing
4201 * kernel to allow access by everyone, and then restricting
4202 * access to root and mountpoint owner in libfuse.
4203 */
4204 // We may be adding the option a second time, but
4205 // that doesn't hurt.
4206 if(fuse_opt_add_arg(args, "-oallow_other") == -1)
4207 goto out2;
4208 }
4209 mo = parse_mount_opts(args);
4210 if (mo == NULL)
4211 goto out3;
4212
4213 if(args->argc == 1 &&
4214 args->argv[0][0] == '-') {
4215 fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
4216 "will be ignored\n");
4217 } else if (args->argc != 1) {
4218 int i;
4219 fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
4220 for(i = 1; i < args->argc-1; i++)
4221 fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
4222 fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
4223 goto out4;
4224 }
4225
4226 if (se->debug)
4227 fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
4228
4229 list_init_req(&se->list);
4230 list_init_req(&se->interrupts);
4231 list_init_nreq(&se->notify_list);
4232 se->notify_ctr = 1;
4233 pthread_mutex_init(&se->lock, NULL);
4234 sem_init(&se->mt_finish, 0, 0);
4235 pthread_mutex_init(&se->mt_lock, NULL);
4236
4237 err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
4238 if (err) {
4239 fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
4240 strerror(err));
4241 goto out5;
4242 }
4243
4244 memcpy(&se->op, op, op_size);
4245 se->owner = getuid();
4246 se->userdata = userdata;
4247
4248 se->mo = mo;
4249
4250 /* Fuse server application should pass the version it was compiled
4251 * against and pass it. If a libfuse version accidentally introduces an
4252 * ABI incompatibility, it might be possible to 'fix' that at run time,
4253 * by checking the version numbers.
4254 */
4255 se->version = *version;
4256
4257 return se;
4258
4259out5:
4260 sem_destroy(&se->mt_finish);
4261 pthread_mutex_destroy(&se->mt_lock);
4262 pthread_mutex_destroy(&se->lock);
4263out4:
4264 fuse_opt_free_args(args);
4265out3:
4266 if (mo != NULL)
4267 destroy_mount_opts(mo);
4268out2:
4269 free(se);
4270out1:
4271 return NULL;
4272}
4273
4274struct fuse_session *fuse_session_new_30(struct fuse_args *args,
4275 const struct fuse_lowlevel_ops *op,
4276 size_t op_size, void *userdata);
4277struct fuse_session *fuse_session_new_30(struct fuse_args *args,
4278 const struct fuse_lowlevel_ops *op,
4279 size_t op_size,
4280 void *userdata)
4281{
4282 struct fuse_lowlevel_ops null_ops = { 0 };
4283
4284 /* unknown version */
4285 struct libfuse_version version = { 0 };
4286
4287 /*
4288 * This function is the ABI interface function from fuse_session_new in
4289 * compat.c. External libraries like "fuser" might call fuse_session_new()
4290 * with NULL ops and then pass that session to fuse_session_mount().
4291 * The actual FUSE operations are handled in their own library.
4292 */
4293 if (op == NULL) {
4294 op = &null_ops;
4295 op_size = sizeof(null_ops);
4296 }
4297
4298 return fuse_session_new_versioned(args, op, op_size, &version,
4299 userdata);
4300}
4301
4302FUSE_SYMVER("fuse_session_custom_io_317", "fuse_session_custom_io@@FUSE_3.17")
4303int fuse_session_custom_io_317(struct fuse_session *se,
4304 const struct fuse_custom_io *io, size_t op_size, int fd)
4305{
4306#ifndef HAVE_CUSTOM_IO
4307 (void)se;
4308 (void)io;
4309 (void)op_size;
4310 (void)fd;
4311 fuse_log(FUSE_LOG_ERR, "fuse: custom io is not enabled in this build\n");
4312 return -ENOTSUP;
4313#else
4314 if (sizeof(struct fuse_custom_io) < op_size) {
4315 fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
4316 op_size = sizeof(struct fuse_custom_io);
4317 }
4318
4319 if (fd < 0) {
4320 fuse_log(FUSE_LOG_ERR, "Invalid file descriptor value %d passed to "
4321 "fuse_session_custom_io()\n", fd);
4322 return -EBADF;
4323 }
4324 if (io == NULL) {
4325 fuse_log(FUSE_LOG_ERR, "No custom IO passed to "
4326 "fuse_session_custom_io()\n");
4327 return -EINVAL;
4328 } else if (io->read == NULL || io->writev == NULL) {
4329 /* If the user provides their own file descriptor, we can't
4330 guarantee that the default behavior of the io operations made
4331 in libfuse will function properly. Therefore, we enforce the
4332 user to implement these io operations when using custom io. */
4333 fuse_log(FUSE_LOG_ERR, "io passed to fuse_session_custom_io() must "
4334 "implement both io->read() and io->writev\n");
4335 return -EINVAL;
4336 }
4337
4338 se->io = calloc(1, sizeof(struct fuse_custom_io));
4339 if (se->io == NULL) {
4340 fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for custom io. "
4341 "Error: %s\n", strerror(errno));
4342 return -errno;
4343 }
4344
4345 se->fd = fd;
4346 memcpy(se->io, io, op_size);
4347 return 0;
4348#endif
4349}
4350
4351int fuse_session_custom_io_30(struct fuse_session *se,
4352 const struct fuse_custom_io *io, int fd);
4353FUSE_SYMVER("fuse_session_custom_io_30", "fuse_session_custom_io@FUSE_3.0")
4354int fuse_session_custom_io_30(struct fuse_session *se,
4355 const struct fuse_custom_io *io, int fd)
4356{
4357 return fuse_session_custom_io_317(se, io,
4358 offsetof(struct fuse_custom_io, clone_fd), fd);
4359}
4360
4361int fuse_session_mount(struct fuse_session *se, const char *_mountpoint)
4362{
4363 int fd;
4364 char *mountpoint;
4365
4366 if (_mountpoint == NULL) {
4367 fuse_log(FUSE_LOG_ERR, "Invalid null-ptr mountpoint!\n");
4368 return -1;
4369 }
4370
4371 mountpoint = strdup(_mountpoint);
4372 if (mountpoint == NULL) {
4373 fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for mountpoint. Error: %s\n",
4374 strerror(errno));
4375 return -1;
4376 }
4377
4378 /*
4379 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
4380 * would ensue.
4381 */
4382 do {
4383 fd = open("/dev/null", O_RDWR);
4384 if (fd > 2)
4385 close(fd);
4386 } while (fd >= 0 && fd <= 2);
4387
4388 /*
4389 * To allow FUSE daemons to run without privileges, the caller may open
4390 * /dev/fuse before launching the file system and pass on the file
4391 * descriptor by specifying /dev/fd/N as the mount point. Note that the
4392 * parent process takes care of performing the mount in this case.
4393 */
4394 fd = fuse_mnt_parse_fuse_fd(mountpoint);
4395 if (fd != -1) {
4396 if (fcntl(fd, F_GETFD) == -1) {
4397 fuse_log(FUSE_LOG_ERR,
4398 "fuse: Invalid file descriptor /dev/fd/%u\n",
4399 fd);
4400 goto error_out;
4401 }
4402 goto out;
4403 }
4404
4405 /* Open channel */
4406 fd = fuse_kern_mount(mountpoint, se->mo);
4407 if (fd == -1)
4408 goto error_out;
4409
4410out:
4411 se->fd = fd;
4412 se->mountpoint = mountpoint;
4413
4414 return 0;
4415
4416error_out:
4417 free(mountpoint);
4418 return -1;
4419}
4420
4421int fuse_session_fd(struct fuse_session *se)
4422{
4423 return se->fd;
4424}
4425
4426void fuse_session_unmount(struct fuse_session *se)
4427{
4428 if (se->mountpoint != NULL) {
4429 char *mountpoint = atomic_exchange(&se->mountpoint, NULL);
4430
4431 fuse_kern_unmount(mountpoint, se->fd);
4432 se->fd = -1;
4433 free(mountpoint);
4434 }
4435}
4436
4437#ifdef linux
4438int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
4439{
4440 char *buf;
4441 size_t bufsize = 1024;
4442 char path[128];
4443 int ret;
4444 int fd;
4445 unsigned long pid = req->ctx.pid;
4446 char *s;
4447
4448 sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
4449
4450retry:
4451 buf = malloc(bufsize);
4452 if (buf == NULL)
4453 return -ENOMEM;
4454
4455 ret = -EIO;
4456 fd = open(path, O_RDONLY);
4457 if (fd == -1)
4458 goto out_free;
4459
4460 ret = read(fd, buf, bufsize);
4461 close(fd);
4462 if (ret < 0) {
4463 ret = -EIO;
4464 goto out_free;
4465 }
4466
4467 if ((size_t)ret == bufsize) {
4468 free(buf);
4469 bufsize *= 4;
4470 goto retry;
4471 }
4472
4473 buf[ret] = '\0';
4474 ret = -EIO;
4475 s = strstr(buf, "\nGroups:");
4476 if (s == NULL)
4477 goto out_free;
4478
4479 s += 8;
4480 ret = 0;
4481 while (1) {
4482 char *end;
4483 unsigned long val = strtoul(s, &end, 0);
4484 if (end == s)
4485 break;
4486
4487 s = end;
4488 if (ret < size)
4489 list[ret] = val;
4490 ret++;
4491 }
4492
4493out_free:
4494 free(buf);
4495 return ret;
4496}
4497#else /* linux */
4498/*
4499 * This is currently not implemented on other than Linux...
4500 */
4501int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
4502{
4503 (void) req; (void) size; (void) list;
4504 return -ENOSYS;
4505}
4506#endif
4507
4508/* Prevent spurious data race warning - we don't care
4509 * about races for this flag */
4510__attribute__((no_sanitize_thread))
4511void fuse_session_exit(struct fuse_session *se)
4512{
4513 atomic_store_explicit(&se->mt_exited, 1, memory_order_relaxed);
4514 sem_post(&se->mt_finish);
4515}
4516
4517__attribute__((no_sanitize_thread))
4518void fuse_session_reset(struct fuse_session *se)
4519{
4520 se->mt_exited = false;
4521 se->error = 0;
4522}
4523
4524__attribute__((no_sanitize_thread))
4525int fuse_session_exited(struct fuse_session *se)
4526{
4527 bool exited =
4528 atomic_load_explicit(&se->mt_exited, memory_order_relaxed);
4529
4530 return exited ? 1 : 0;
4531}
#define FUSE_CAP_IOCTL_DIR
#define FUSE_CAP_DONT_MASK
void fuse_unset_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
int fuse_convert_to_conn_want_ext(struct fuse_conn_info *conn)
bool fuse_set_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
#define FUSE_CAP_HANDLE_KILLPRIV
#define FUSE_CAP_AUTO_INVAL_DATA
#define FUSE_CAP_HANDLE_KILLPRIV_V2
#define FUSE_CAP_SPLICE_READ
#define FUSE_CAP_PARALLEL_DIROPS
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition buffer.c:22
#define FUSE_CAP_WRITEBACK_CACHE
#define FUSE_CAP_EXPIRE_ONLY
#define FUSE_CAP_ATOMIC_O_TRUNC
#define FUSE_CAP_ASYNC_READ
#define FUSE_CAP_SPLICE_WRITE
#define FUSE_CAP_CACHE_SYMLINKS
#define FUSE_CAP_POSIX_ACL
@ FUSE_BUF_IS_FD
#define FUSE_CAP_EXPORT_SUPPORT
#define FUSE_CAP_POSIX_LOCKS
#define FUSE_CAP_EXPLICIT_INVAL_DATA
#define FUSE_CAP_READDIRPLUS_AUTO
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition buffer.c:284
#define FUSE_CAP_NO_OPENDIR_SUPPORT
#define FUSE_CAP_ASYNC_DIO
#define FUSE_CAP_OVER_IO_URING
bool fuse_get_feature_flag(struct fuse_conn_info *conn, uint64_t flag)
#define FUSE_CAP_PASSTHROUGH
#define FUSE_CAP_DIRECT_IO_ALLOW_MMAP
#define FUSE_CAP_NO_OPEN_SUPPORT
#define FUSE_CAP_READDIRPLUS
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
fuse_buf_copy_flags
@ FUSE_BUF_SPLICE_NONBLOCK
@ FUSE_BUF_FORCE_SPLICE
@ FUSE_BUF_NO_SPLICE
@ FUSE_BUF_SPLICE_MOVE
#define FUSE_CAP_SETXATTR_EXT
#define FUSE_CAP_SPLICE_MOVE
#define FUSE_CAP_NO_EXPORT_SUPPORT
#define FUSE_CAP_FLOCK_LOCKS
void fuse_log(enum fuse_log_level level, const char *fmt,...) __attribute__((format(printf
void fuse_session_destroy(struct fuse_session *se)
fuse_notify_entry_flags
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
void fuse_session_exit(struct fuse_session *se)
void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
int fuse_reply_poll(fuse_req_t req, unsigned revents)
int fuse_reply_err(fuse_req_t req, int err)
bool fuse_req_is_uring(fuse_req_t req)
const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
void * fuse_req_userdata(fuse_req_t req)
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
struct fuse_req * fuse_req_t
size_t 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)
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
int fuse_session_exited(struct fuse_session *se)
int fuse_session_fd(struct fuse_session *se)
int fuse_req_interrupted(fuse_req_t req)
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
int fuse_reply_readlink(fuse_req_t req, const char *link)
int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
void fuse_session_unmount(struct fuse_session *se)
void fuse_reply_none(fuse_req_t req)
int fuse_req_get_payload(fuse_req_t req, char **payload, size_t *payload_sz, void **mr)
int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
int 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)
void fuse_lowlevel_help(void)
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
int fuse_reply_write(fuse_req_t req, size_t count)
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
int fuse_lowlevel_notify_increment_epoch(struct fuse_session *se)
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
void fuse_session_reset(struct fuse_session *se)
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
int fuse_reply_lseek(fuse_req_t req, off_t off)
void fuse_lowlevel_version(void)
int fuse_reply_statx(fuse_req_t req, int flags, struct statx *statx, double attr_timeout)
uint64_t fuse_ino_t
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
int fuse_passthrough_open(fuse_req_t req, int fd)
int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, off_t offset, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
int fuse_reply_xattr(fuse_req_t req, size_t count)
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition fuse_opt.c:55
void fuse_opt_free_args(struct fuse_args *args)
Definition fuse_opt.c:34
int fuse_opt_parse(struct fuse_args *args, void *data, const struct fuse_opt opts[], fuse_opt_proc_t proc)
Definition fuse_opt.c:398
#define FUSE_OPT_END
Definition fuse_opt.h:104
char ** argv
Definition fuse_opt.h:114
enum fuse_buf_flags flags
size_t mem_size
void * mem
size_t size
struct fuse_buf buf[1]
uint32_t proto_minor
uint64_t capable_ext
uint64_t want_ext
mode_t umask
double entry_timeout
fuse_ino_t ino
uint64_t generation
double attr_timeout
struct stat attr
uint64_t lock_owner
uint32_t kill_suidgid
uint32_t writepage
Definition fuse_common.h:60
uint32_t poll_events
uint32_t cache_readdir
Definition fuse_common.h:89
uint32_t nonseekable
Definition fuse_common.h:78
int32_t backing_id
uint32_t parallel_direct_writes
Definition fuse_common.h:97
uint32_t noflush
Definition fuse_common.h:93
uint32_t flush
Definition fuse_common.h:74
uint32_t direct_io
Definition fuse_common.h:63
uint32_t keep_cache
Definition fuse_common.h:69
void(* fsync)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(* bmap)(fuse_req_t req, fuse_ino_t ino, size_t blocksize, uint64_t idx)
void(* unlink)(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* getxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, size_t size)
void(* rename)(fuse_req_t req, fuse_ino_t parent, const char *name, fuse_ino_t newparent, const char *newname, unsigned int flags)
void(* releasedir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* setxattr)(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value, size_t size, int flags)
void(* symlink)(fuse_req_t req, const char *link, fuse_ino_t parent, const char *name)
void(* statfs)(fuse_req_t req, fuse_ino_t ino)
void(* tmpfile)(fuse_req_t req, fuse_ino_t parent, mode_t mode, struct fuse_file_info *fi)
void(* release)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* readdir)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* fallocate)(fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t length, struct fuse_file_info *fi)
void(* create)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, struct fuse_file_info *fi)
void(* link)(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent, const char *newname)
void(* write)(fuse_req_t req, fuse_ino_t ino, const char *buf, size_t size, off_t off, struct fuse_file_info *fi)
void(* lookup)(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* readdirplus)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* flock)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, int op)
void(* getattr)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* copy_file_range)(fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fuse_file_info *fi_in, fuse_ino_t ino_out, off_t off_out, struct fuse_file_info *fi_out, size_t len, int flags)
void(* setattr)(fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, struct fuse_file_info *fi)
void(* open)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* removexattr)(fuse_req_t req, fuse_ino_t ino, const char *name)
void(* forget)(fuse_req_t req, fuse_ino_t ino, uint64_t nlookup)
void(* poll)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct fuse_pollhandle *ph)
void(* ioctl)(fuse_req_t req, fuse_ino_t ino, unsigned int cmd, void *arg, struct fuse_file_info *fi, unsigned flags, const void *in_buf, size_t in_bufsz, size_t out_bufsz)
void(* rmdir)(fuse_req_t req, fuse_ino_t parent, const char *name)
void(* setlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock, int sleep)
void(* fsyncdir)(fuse_req_t req, fuse_ino_t ino, int datasync, struct fuse_file_info *fi)
void(* mkdir)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
void(* statx)(fuse_req_t req, fuse_ino_t ino, int flags, int mask, struct fuse_file_info *fi)
void(* access)(fuse_req_t req, fuse_ino_t ino, int mask)
void(* mknod)(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode, dev_t rdev)
void(* lseek)(fuse_req_t req, fuse_ino_t ino, off_t off, int whence, struct fuse_file_info *fi)
void(* getlk)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, struct flock *lock)
void(* readlink)(fuse_req_t req, fuse_ino_t ino)
void(* read)(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi)
void(* flush)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* listxattr)(fuse_req_t req, fuse_ino_t ino, size_t size)
void(* opendir)(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
void(* forget_multi)(fuse_req_t req, size_t count, struct fuse_forget_data *forgets)