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 COPYING.LIB
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
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <limits.h>
27 #include <errno.h>
28 #include <assert.h>
29 #include <sys/file.h>
30
31 #ifndef F_LINUX_SPECIFIC_BASE
32 #define F_LINUX_SPECIFIC_BASE 1024
33 #endif
34 #ifndef F_SETPIPE_SZ
35 #define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7)
36 #endif
37
38
39 #define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
40 #define OFFSET_MAX 0x7fffffffffffffffLL
41
42 #define container_of(ptr, type, member) ({ \
43 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
44 (type *)( (char *)__mptr - offsetof(type,member) );})
45
46 struct fuse_pollhandle {
47 uint64_t kh;
48 struct fuse_session *se;
49 };
50
51 static size_t pagesize;
52
53 static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
54 {
55 pagesize = getpagesize();
56 }
57
58 static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
59 {
60 attr->ino = stbuf->st_ino;
61 attr->mode = stbuf->st_mode;
62 attr->nlink = stbuf->st_nlink;
63 attr->uid = stbuf->st_uid;
64 attr->gid = stbuf->st_gid;
65 attr->rdev = stbuf->st_rdev;
66 attr->size = stbuf->st_size;
67 attr->blksize = stbuf->st_blksize;
68 attr->blocks = stbuf->st_blocks;
69 attr->atime = stbuf->st_atime;
70 attr->mtime = stbuf->st_mtime;
71 attr->ctime = stbuf->st_ctime;
72 attr->atimensec = ST_ATIM_NSEC(stbuf);
73 attr->mtimensec = ST_MTIM_NSEC(stbuf);
74 attr->ctimensec = ST_CTIM_NSEC(stbuf);
75 }
76
77 static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
78 {
79 stbuf->st_mode = attr->mode;
80 stbuf->st_uid = attr->uid;
81 stbuf->st_gid = attr->gid;
82 stbuf->st_size = attr->size;
83 stbuf->st_atime = attr->atime;
84 stbuf->st_mtime = attr->mtime;
85 stbuf->st_ctime = attr->ctime;
86 ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
87 ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
88 ST_CTIM_NSEC_SET(stbuf, attr->ctimensec);
89 }
90
91 static size_t iov_length(const struct iovec *iov, size_t count)
92 {
93 size_t seg;
94 size_t ret = 0;
95
96 for (seg = 0; seg < count; seg++)
97 ret += iov[seg].iov_len;
98 return ret;
99 }
100
101 static void list_init_req(struct fuse_req *req)
102 {
103 req->next = req;
104 req->prev = req;
105 }
106
107 static void list_del_req(struct fuse_req *req)
108 {
109 struct fuse_req *prev = req->prev;
110 struct fuse_req *next = req->next;
111 prev->next = next;
112 next->prev = prev;
113 }
114
115 static void list_add_req(struct fuse_req *req, struct fuse_req *next)
116 {
117 struct fuse_req *prev = next->prev;
118 req->next = next;
119 req->prev = prev;
120 prev->next = req;
121 next->prev = req;
122 }
123
124 static void destroy_req(fuse_req_t req)
125 {
126 assert(req->ch == NULL);
127 pthread_mutex_destroy(&req->lock);
128 free(req);
129 }
130
131 void fuse_free_req(fuse_req_t req)
132 {
133 int ctr;
134 struct fuse_session *se = req->se;
135
136 pthread_mutex_lock(&se->lock);
137 req->u.ni.func = NULL;
138 req->u.ni.data = NULL;
139 list_del_req(req);
140 ctr = --req->ctr;
141 fuse_chan_put(req->ch);
142 req->ch = NULL;
143 pthread_mutex_unlock(&se->lock);
144 if (!ctr)
145 destroy_req(req);
146 }
147
148 static struct fuse_req *fuse_ll_alloc_req(struct fuse_session *se)
149 {
150 struct fuse_req *req;
151
152 req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
153 if (req == NULL) {
154 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate request\n");
155 } else {
156 req->se = se;
157 req->ctr = 1;
158 list_init_req(req);
159 pthread_mutex_init(&req->lock, NULL);
160 }
161
162 return req;
163 }
164
165 /* Send data. If *ch* is NULL, send via session master fd */
166 static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
167 struct iovec *iov, int count)
168 {
169 struct fuse_out_header *out = iov[0].iov_base;
170
171 assert(se != NULL);
172 out->len = iov_length(iov, count);
173 if (se->debug) {
174 if (out->unique == 0) {
175 fuse_log(FUSE_LOG_DEBUG, "NOTIFY: code=%d length=%u\n",
176 out->error, out->len);
177 } else if (out->error) {
178 fuse_log(FUSE_LOG_DEBUG,
179 " unique: %llu, error: %i (%s), outsize: %i\n",
180 (unsigned long long) out->unique, out->error,
181 strerror(-out->error), out->len);
182 } else {
183 fuse_log(FUSE_LOG_DEBUG,
184 " unique: %llu, success, outsize: %i\n",
185 (unsigned long long) out->unique, out->len);
186 }
187 }
188
189 ssize_t res;
190 if (se->io != NULL)
191 /* se->io->writev is never NULL if se->io is not NULL as
192 specified by fuse_session_custom_io()*/
193 res = se->io->writev(ch ? ch->fd : se->fd, iov, count,
194 se->userdata);
195 else
196 res = writev(ch ? ch->fd : se->fd, iov, count);
197
198 int err = errno;
199
200 if (res == -1) {
201 /* ENOENT means the operation was interrupted */
202 if (!fuse_session_exited(se) && err != ENOENT)
203 perror("fuse: writing device");
204 return -err;
205 }
206
207 return 0;
208 }
209
210
211 int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
212 int count)
213 {
214 struct fuse_out_header out;
215
216 if (error <= -1000 || error > 0) {
217 fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
218 error = -ERANGE;
219 }
220
221 out.unique = req->unique;
222 out.error = error;
223
224 iov[0].iov_base = &out;
225 iov[0].iov_len = sizeof(struct fuse_out_header);
226
227 return fuse_send_msg(req->se, req->ch, iov, count);
228 }
229
230 static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
231 int count)
232 {
233 int res;
234
235 res = fuse_send_reply_iov_nofree(req, error, iov, count);
236 fuse_free_req(req);
237 return res;
238 }
239
240 static int send_reply(fuse_req_t req, int error, const void *arg,
241 size_t argsize)
242 {
243 struct iovec iov[2];
244 int count = 1;
245 if (argsize) {
246 iov[1].iov_base = (void *) arg;
247 iov[1].iov_len = argsize;
248 count++;
249 }
250 return send_reply_iov(req, error, iov, count);
251 }
252
253 int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
254 {
255 int res;
256 struct iovec *padded_iov;
257
258 padded_iov = malloc((count + 1) * sizeof(struct iovec));
259 if (padded_iov == NULL)
260 return fuse_reply_err(req, ENOMEM);
261
262 memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
263 count++;
264
265 res = send_reply_iov(req, 0, padded_iov, count);
266 free(padded_iov);
267
268 return res;
269 }
270
271
272 /* `buf` is allowed to be empty so that the proper size may be
273 allocated by the caller */
274 size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
275 const char *name, const struct stat *stbuf, off_t off)
276 {
277 (void)req;
278 size_t namelen;
279 size_t entlen;
280 size_t entlen_padded;
281 struct fuse_dirent *dirent;
282
283 namelen = strlen(name);
284 entlen = FUSE_NAME_OFFSET + namelen;
285 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
286
287 if ((buf == NULL) || (entlen_padded > bufsize))
288 return entlen_padded;
289
290 dirent = (struct fuse_dirent*) buf;
291 dirent->ino = stbuf->st_ino;
292 dirent->off = off;
293 dirent->namelen = namelen;
294 dirent->type = (stbuf->st_mode & S_IFMT) >> 12;
295 memcpy(dirent->name, name, namelen);
296 memset(dirent->name + namelen, 0, entlen_padded - entlen);
297
298 return entlen_padded;
299 }
300
301 static void convert_statfs(const struct statvfs *stbuf,
302 struct fuse_kstatfs *kstatfs)
303 {
304 kstatfs->bsize = stbuf->f_bsize;
305 kstatfs->frsize = stbuf->f_frsize;
306 kstatfs->blocks = stbuf->f_blocks;
307 kstatfs->bfree = stbuf->f_bfree;
308 kstatfs->bavail = stbuf->f_bavail;
309 kstatfs->files = stbuf->f_files;
310 kstatfs->ffree = stbuf->f_ffree;
311 kstatfs->namelen = stbuf->f_namemax;
312 }
313
314 static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
315 {
316 return send_reply(req, 0, arg, argsize);
317 }
318
319 int fuse_reply_err(fuse_req_t req, int err)
320 {
321 return send_reply(req, -err, NULL, 0);
322 }
323
324 void fuse_reply_none(fuse_req_t req)
325 {
326 fuse_free_req(req);
327 }
328
329 static unsigned long calc_timeout_sec(double t)
330 {
331 if (t > (double) ULONG_MAX)
332 return ULONG_MAX;
333 else if (t < 0.0)
334 return 0;
335 else
336 return (unsigned long) t;
337 }
338
339 static unsigned int calc_timeout_nsec(double t)
340 {
341 double f = t - (double) calc_timeout_sec(t);
342 if (f < 0.0)
343 return 0;
344 else if (f >= 0.999999999)
345 return 999999999;
346 else
347 return (unsigned int) (f * 1.0e9);
348 }
349
350 static void fill_entry(struct fuse_entry_out *arg,
351 const struct fuse_entry_param *e)
352 {
353 arg->nodeid = e->ino;
354 arg->generation = e->generation;
355 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
356 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
357 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
358 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
359 convert_stat(&e->attr, &arg->attr);
360 }
361
362 /* `buf` is allowed to be empty so that the proper size may be
363 allocated by the caller */
364 size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
365 const char *name,
366 const struct fuse_entry_param *e, off_t off)
367 {
368 (void)req;
369 size_t namelen;
370 size_t entlen;
371 size_t entlen_padded;
372
373 namelen = strlen(name);
374 entlen = FUSE_NAME_OFFSET_DIRENTPLUS + namelen;
375 entlen_padded = FUSE_DIRENT_ALIGN(entlen);
376 if ((buf == NULL) || (entlen_padded > bufsize))
377 return entlen_padded;
378
379 struct fuse_direntplus *dp = (struct fuse_direntplus *) buf;
380 memset(&dp->entry_out, 0, sizeof(dp->entry_out));
381 fill_entry(&dp->entry_out, e);
382
383 struct fuse_dirent *dirent = &dp->dirent;
384 dirent->ino = e->attr.st_ino;
385 dirent->off = off;
386 dirent->namelen = namelen;
387 dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
388 memcpy(dirent->name, name, namelen);
389 memset(dirent->name + namelen, 0, entlen_padded - entlen);
390
391 return entlen_padded;
392 }
393
394 static void fill_open(struct fuse_open_out *arg,
395 const struct fuse_file_info *f)
396 {
397 arg->fh = f->fh;
398 if (f->direct_io)
399 arg->open_flags |= FOPEN_DIRECT_IO;
400 if (f->keep_cache)
401 arg->open_flags |= FOPEN_KEEP_CACHE;
402 if (f->cache_readdir)
403 arg->open_flags |= FOPEN_CACHE_DIR;
404 if (f->nonseekable)
405 arg->open_flags |= FOPEN_NONSEEKABLE;
406 if (f->noflush)
407 arg->open_flags |= FOPEN_NOFLUSH;
408 }
409
410 int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
411 {
412 struct fuse_entry_out arg;
413 size_t size = req->se->conn.proto_minor < 9 ?
414 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
415
416 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
417 negative entry */
418 if (!e->ino && req->se->conn.proto_minor < 4)
419 return fuse_reply_err(req, ENOENT);
420
421 memset(&arg, 0, sizeof(arg));
422 fill_entry(&arg, e);
423 return send_reply_ok(req, &arg, size);
424 }
425
426 int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
427 const struct fuse_file_info *f)
428 {
429 char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
430 size_t entrysize = req->se->conn.proto_minor < 9 ?
431 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
432 struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
433 struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
434
435 memset(buf, 0, sizeof(buf));
436 fill_entry(earg, e);
437 fill_open(oarg, f);
438 return send_reply_ok(req, buf,
439 entrysize + sizeof(struct fuse_open_out));
440 }
441
442 int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
443 double attr_timeout)
444 {
445 struct fuse_attr_out arg;
446 size_t size = req->se->conn.proto_minor < 9 ?
447 FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
448
449 memset(&arg, 0, sizeof(arg));
450 arg.attr_valid = calc_timeout_sec(attr_timeout);
451 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
452 convert_stat(attr, &arg.attr);
453
454 return send_reply_ok(req, &arg, size);
455 }
456
457 int fuse_reply_readlink(fuse_req_t req, const char *linkname)
458 {
459 return send_reply_ok(req, linkname, strlen(linkname));
460 }
461
462 int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
463 {
464 struct fuse_open_out arg;
465
466 memset(&arg, 0, sizeof(arg));
467 fill_open(&arg, f);
468 return send_reply_ok(req, &arg, sizeof(arg));
469 }
470
471 int fuse_reply_write(fuse_req_t req, size_t count)
472 {
473 struct fuse_write_out arg;
474
475 memset(&arg, 0, sizeof(arg));
476 arg.size = count;
477
478 return send_reply_ok(req, &arg, sizeof(arg));
479 }
480
481 int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
482 {
483 return send_reply_ok(req, buf, size);
484 }
485
486 static int fuse_send_data_iov_fallback(struct fuse_session *se,
487 struct fuse_chan *ch,
488 struct iovec *iov, int iov_count,
489 struct fuse_bufvec *buf,
490 size_t len)
491 {
492 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
493 void *mbuf;
494 int res;
495
496 /* Optimize common case */
497 if (buf->count == 1 && buf->idx == 0 && buf->off == 0 &&
498 !(buf->buf[0].flags & FUSE_BUF_IS_FD)) {
499 /* FIXME: also avoid memory copy if there are multiple buffers
500 but none of them contain an fd */
501
502 iov[iov_count].iov_base = buf->buf[0].mem;
503 iov[iov_count].iov_len = len;
504 iov_count++;
505 return fuse_send_msg(se, ch, iov, iov_count);
506 }
507
508 res = posix_memalign(&mbuf, pagesize, len);
509 if (res != 0)
510 return res;
511
512 mem_buf.buf[0].mem = mbuf;
513 res = fuse_buf_copy(&mem_buf, buf, 0);
514 if (res < 0) {
515 free(mbuf);
516 return -res;
517 }
518 len = res;
519
520 iov[iov_count].iov_base = mbuf;
521 iov[iov_count].iov_len = len;
522 iov_count++;
523 res = fuse_send_msg(se, ch, iov, iov_count);
524 free(mbuf);
525
526 return res;
527 }
528
529 struct fuse_ll_pipe {
530 size_t size;
531 int can_grow;
532 int pipe[2];
533 };
534
535 static void fuse_ll_pipe_free(struct fuse_ll_pipe *llp)
536 {
537 close(llp->pipe[0]);
538 close(llp->pipe[1]);
539 free(llp);
540 }
541
542 #ifdef HAVE_SPLICE
543 #if !defined(HAVE_PIPE2) || !defined(O_CLOEXEC)
544 static int fuse_pipe(int fds[2])
545 {
546 int rv = pipe(fds);
547
548 if (rv == -1)
549 return rv;
550
551 if (fcntl(fds[0], F_SETFL, O_NONBLOCK) == -1 ||
552 fcntl(fds[1], F_SETFL, O_NONBLOCK) == -1 ||
553 fcntl(fds[0], F_SETFD, FD_CLOEXEC) == -1 ||
554 fcntl(fds[1], F_SETFD, FD_CLOEXEC) == -1) {
555 close(fds[0]);
556 close(fds[1]);
557 rv = -1;
558 }
559 return rv;
560 }
561 #else
562 static int fuse_pipe(int fds[2])
563 {
564 return pipe2(fds, O_CLOEXEC | O_NONBLOCK);
565 }
566 #endif
567
568 static struct fuse_ll_pipe *fuse_ll_get_pipe(struct fuse_session *se)
569 {
570 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
571 if (llp == NULL) {
572 int res;
573
574 llp = malloc(sizeof(struct fuse_ll_pipe));
575 if (llp == NULL)
576 return NULL;
577
578 res = fuse_pipe(llp->pipe);
579 if (res == -1) {
580 free(llp);
581 return NULL;
582 }
583
584 /*
585 *the default size is 16 pages on linux
586 */
587 llp->size = pagesize * 16;
588 llp->can_grow = 1;
589
590 pthread_setspecific(se->pipe_key, llp);
591 }
592
593 return llp;
594 }
595 #endif
596
597 static void fuse_ll_clear_pipe(struct fuse_session *se)
598 {
599 struct fuse_ll_pipe *llp = pthread_getspecific(se->pipe_key);
600 if (llp) {
601 pthread_setspecific(se->pipe_key, NULL);
602 fuse_ll_pipe_free(llp);
603 }
604 }
605
606 #if defined(HAVE_SPLICE) && defined(HAVE_VMSPLICE)
607 static int read_back(int fd, char *buf, size_t len)
608 {
609 int res;
610
611 res = read(fd, buf, len);
612 if (res == -1) {
613 fuse_log(FUSE_LOG_ERR, "fuse: internal error: failed to read back from pipe: %s\n", strerror(errno));
614 return -EIO;
615 }
616 if (res != len) {
617 fuse_log(FUSE_LOG_ERR, "fuse: internal error: short read back from pipe: %i from %zi\n", res, len);
618 return -EIO;
619 }
620 return 0;
621 }
622
623 static int grow_pipe_to_max(int pipefd)
624 {
625 int max;
626 int res;
627 int maxfd;
628 char buf[32];
629
630 maxfd = open("/proc/sys/fs/pipe-max-size", O_RDONLY);
631 if (maxfd < 0)
632 return -errno;
633
634 res = read(maxfd, buf, sizeof(buf) - 1);
635 if (res < 0) {
636 int saved_errno;
637
638 saved_errno = errno;
639 close(maxfd);
640 return -saved_errno;
641 }
642 close(maxfd);
643 buf[res] = '\0';
644
645 max = atoi(buf);
646 res = fcntl(pipefd, F_SETPIPE_SZ, max);
647 if (res < 0)
648 return -errno;
649 return max;
650 }
651
652 static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
653 struct iovec *iov, int iov_count,
654 struct fuse_bufvec *buf, unsigned int flags)
655 {
656 int res;
657 size_t len = fuse_buf_size(buf);
658 struct fuse_out_header *out = iov[0].iov_base;
659 struct fuse_ll_pipe *llp;
660 int splice_flags;
661 size_t pipesize;
662 size_t total_buf_size;
663 size_t idx;
664 size_t headerlen;
665 struct fuse_bufvec pipe_buf = FUSE_BUFVEC_INIT(len);
666
667 if (se->broken_splice_nonblock)
668 goto fallback;
669
670 if (flags & FUSE_BUF_NO_SPLICE)
671 goto fallback;
672
673 total_buf_size = 0;
674 for (idx = buf->idx; idx < buf->count; idx++) {
675 total_buf_size += buf->buf[idx].size;
676 if (idx == buf->idx)
677 total_buf_size -= buf->off;
678 }
679 if (total_buf_size < 2 * pagesize)
680 goto fallback;
681
682 if (se->conn.proto_minor < 14 ||
683 !(se->conn.want & FUSE_CAP_SPLICE_WRITE))
684 goto fallback;
685
686 llp = fuse_ll_get_pipe(se);
687 if (llp == NULL)
688 goto fallback;
689
690
691 headerlen = iov_length(iov, iov_count);
692
693 out->len = headerlen + len;
694
695 /*
696 * Heuristic for the required pipe size, does not work if the
697 * source contains less than page size fragments
698 */
699 pipesize = pagesize * (iov_count + buf->count + 1) + out->len;
700
701 if (llp->size < pipesize) {
702 if (llp->can_grow) {
703 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, pipesize);
704 if (res == -1) {
705 res = grow_pipe_to_max(llp->pipe[0]);
706 if (res > 0)
707 llp->size = res;
708 llp->can_grow = 0;
709 goto fallback;
710 }
711 llp->size = res;
712 }
713 if (llp->size < pipesize)
714 goto fallback;
715 }
716
717
718 res = vmsplice(llp->pipe[1], iov, iov_count, SPLICE_F_NONBLOCK);
719 if (res == -1)
720 goto fallback;
721
722 if (res != headerlen) {
723 res = -EIO;
724 fuse_log(FUSE_LOG_ERR, "fuse: short vmsplice to pipe: %u/%zu\n", res,
725 headerlen);
726 goto clear_pipe;
727 }
728
729 pipe_buf.buf[0].flags = FUSE_BUF_IS_FD;
730 pipe_buf.buf[0].fd = llp->pipe[1];
731
732 res = fuse_buf_copy(&pipe_buf, buf,
733 FUSE_BUF_FORCE_SPLICE | FUSE_BUF_SPLICE_NONBLOCK);
734 if (res < 0) {
735 if (res == -EAGAIN || res == -EINVAL) {
736 /*
737 * Should only get EAGAIN on kernels with
738 * broken SPLICE_F_NONBLOCK support (<=
739 * 2.6.35) where this error or a short read is
740 * returned even if the pipe itself is not
741 * full
742 *
743 * EINVAL might mean that splice can't handle
744 * this combination of input and output.
745 */
746 if (res == -EAGAIN)
747 se->broken_splice_nonblock = 1;
748
749 pthread_setspecific(se->pipe_key, NULL);
750 fuse_ll_pipe_free(llp);
751 goto fallback;
752 }
753 res = -res;
754 goto clear_pipe;
755 }
756
757 if (res != 0 && res < len) {
758 struct fuse_bufvec mem_buf = FUSE_BUFVEC_INIT(len);
759 void *mbuf;
760 size_t now_len = res;
761 /*
762 * For regular files a short count is either
763 * 1) due to EOF, or
764 * 2) because of broken SPLICE_F_NONBLOCK (see above)
765 *
766 * For other inputs it's possible that we overflowed
767 * the pipe because of small buffer fragments.
768 */
769
770 res = posix_memalign(&mbuf, pagesize, len);
771 if (res != 0)
772 goto clear_pipe;
773
774 mem_buf.buf[0].mem = mbuf;
775 mem_buf.off = now_len;
776 res = fuse_buf_copy(&mem_buf, buf, 0);
777 if (res > 0) {
778 char *tmpbuf;
779 size_t extra_len = res;
780 /*
781 * Trickiest case: got more data. Need to get
782 * back the data from the pipe and then fall
783 * back to regular write.
784 */
785 tmpbuf = malloc(headerlen);
786 if (tmpbuf == NULL) {
787 free(mbuf);
788 res = ENOMEM;
789 goto clear_pipe;
790 }
791 res = read_back(llp->pipe[0], tmpbuf, headerlen);
792 free(tmpbuf);
793 if (res != 0) {
794 free(mbuf);
795 goto clear_pipe;
796 }
797 res = read_back(llp->pipe[0], mbuf, now_len);
798 if (res != 0) {
799 free(mbuf);
800 goto clear_pipe;
801 }
802 len = now_len + extra_len;
803 iov[iov_count].iov_base = mbuf;
804 iov[iov_count].iov_len = len;
805 iov_count++;
806 res = fuse_send_msg(se, ch, iov, iov_count);
807 free(mbuf);
808 return res;
809 }
810 free(mbuf);
811 res = now_len;
812 }
813 len = res;
814 out->len = headerlen + len;
815
816 if (se->debug) {
817 fuse_log(FUSE_LOG_DEBUG,
818 " unique: %llu, success, outsize: %i (splice)\n",
819 (unsigned long long) out->unique, out->len);
820 }
821
822 splice_flags = 0;
823 if ((flags & FUSE_BUF_SPLICE_MOVE) &&
824 (se->conn.want & FUSE_CAP_SPLICE_MOVE))
825 splice_flags |= SPLICE_F_MOVE;
826
827 if (se->io != NULL && se->io->splice_send != NULL) {
828 res = se->io->splice_send(llp->pipe[0], NULL,
829 ch ? ch->fd : se->fd, NULL, out->len,
830 splice_flags, se->userdata);
831 } else {
832 res = splice(llp->pipe[0], NULL, ch ? ch->fd : se->fd, NULL,
833 out->len, splice_flags);
834 }
835 if (res == -1) {
836 res = -errno;
837 perror("fuse: splice from pipe");
838 goto clear_pipe;
839 }
840 if (res != out->len) {
841 res = -EIO;
842 fuse_log(FUSE_LOG_ERR, "fuse: short splice from pipe: %u/%u\n",
843 res, out->len);
844 goto clear_pipe;
845 }
846 return 0;
847
848 clear_pipe:
849 fuse_ll_clear_pipe(se);
850 return res;
851
852 fallback:
853 return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
854 }
855 #else
856 static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
857 struct iovec *iov, int iov_count,
858 struct fuse_bufvec *buf, unsigned int flags)
859 {
860 size_t len = fuse_buf_size(buf);
861 (void) flags;
862
863 return fuse_send_data_iov_fallback(se, ch, iov, iov_count, buf, len);
864 }
865 #endif
866
867 int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv,
868 enum fuse_buf_copy_flags flags)
869 {
870 struct iovec iov[2];
871 struct fuse_out_header out;
872 int res;
873
874 iov[0].iov_base = &out;
875 iov[0].iov_len = sizeof(struct fuse_out_header);
876
877 out.unique = req->unique;
878 out.error = 0;
879
880 res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
881 if (res <= 0) {
882 fuse_free_req(req);
883 return res;
884 } else {
885 return fuse_reply_err(req, res);
886 }
887 }
888
889 int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
890 {
891 struct fuse_statfs_out arg;
892 size_t size = req->se->conn.proto_minor < 4 ?
893 FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
894
895 memset(&arg, 0, sizeof(arg));
896 convert_statfs(stbuf, &arg.st);
897
898 return send_reply_ok(req, &arg, size);
899 }
900
901 int fuse_reply_xattr(fuse_req_t req, size_t count)
902 {
903 struct fuse_getxattr_out arg;
904
905 memset(&arg, 0, sizeof(arg));
906 arg.size = count;
907
908 return send_reply_ok(req, &arg, sizeof(arg));
909 }
910
911 int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
912 {
913 struct fuse_lk_out arg;
914
915 memset(&arg, 0, sizeof(arg));
916 arg.lk.type = lock->l_type;
917 if (lock->l_type != F_UNLCK) {
918 arg.lk.start = lock->l_start;
919 if (lock->l_len == 0)
920 arg.lk.end = OFFSET_MAX;
921 else
922 arg.lk.end = lock->l_start + lock->l_len - 1;
923 }
924 arg.lk.pid = lock->l_pid;
925 return send_reply_ok(req, &arg, sizeof(arg));
926 }
927
928 int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
929 {
930 struct fuse_bmap_out arg;
931
932 memset(&arg, 0, sizeof(arg));
933 arg.block = idx;
934
935 return send_reply_ok(req, &arg, sizeof(arg));
936 }
937
938 static struct fuse_ioctl_iovec *fuse_ioctl_iovec_copy(const struct iovec *iov,
939 size_t count)
940 {
941 struct fuse_ioctl_iovec *fiov;
942 size_t i;
943
944 fiov = malloc(sizeof(fiov[0]) * count);
945 if (!fiov)
946 return NULL;
947
948 for (i = 0; i < count; i++) {
949 fiov[i].base = (uintptr_t) iov[i].iov_base;
950 fiov[i].len = iov[i].iov_len;
951 }
952
953 return fiov;
954 }
955
956 int fuse_reply_ioctl_retry(fuse_req_t req,
957 const struct iovec *in_iov, size_t in_count,
958 const struct iovec *out_iov, size_t out_count)
959 {
960 struct fuse_ioctl_out arg;
961 struct fuse_ioctl_iovec *in_fiov = NULL;
962 struct fuse_ioctl_iovec *out_fiov = NULL;
963 struct iovec iov[4];
964 size_t count = 1;
965 int res;
966
967 memset(&arg, 0, sizeof(arg));
968 arg.flags |= FUSE_IOCTL_RETRY;
969 arg.in_iovs = in_count;
970 arg.out_iovs = out_count;
971 iov[count].iov_base = &arg;
972 iov[count].iov_len = sizeof(arg);
973 count++;
974
975 if (req->se->conn.proto_minor < 16) {
976 if (in_count) {
977 iov[count].iov_base = (void *)in_iov;
978 iov[count].iov_len = sizeof(in_iov[0]) * in_count;
979 count++;
980 }
981
982 if (out_count) {
983 iov[count].iov_base = (void *)out_iov;
984 iov[count].iov_len = sizeof(out_iov[0]) * out_count;
985 count++;
986 }
987 } else {
988 /* Can't handle non-compat 64bit ioctls on 32bit */
989 if (sizeof(void *) == 4 && req->ioctl_64bit) {
990 res = fuse_reply_err(req, EINVAL);
991 goto out;
992 }
993
994 if (in_count) {
995 in_fiov = fuse_ioctl_iovec_copy(in_iov, in_count);
996 if (!in_fiov)
997 goto enomem;
998
999 iov[count].iov_base = (void *)in_fiov;
1000 iov[count].iov_len = sizeof(in_fiov[0]) * in_count;
1001 count++;
1002 }
1003 if (out_count) {
1004 out_fiov = fuse_ioctl_iovec_copy(out_iov, out_count);
1005 if (!out_fiov)
1006 goto enomem;
1007
1008 iov[count].iov_base = (void *)out_fiov;
1009 iov[count].iov_len = sizeof(out_fiov[0]) * out_count;
1010 count++;
1011 }
1012 }
1013
1014 res = send_reply_iov(req, 0, iov, count);
1015 out:
1016 free(in_fiov);
1017 free(out_fiov);
1018
1019 return res;
1020
1021 enomem:
1022 res = fuse_reply_err(req, ENOMEM);
1023 goto out;
1024 }
1025
1026 int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
1027 {
1028 struct fuse_ioctl_out arg;
1029 struct iovec iov[3];
1030 size_t count = 1;
1031
1032 memset(&arg, 0, sizeof(arg));
1033 arg.result = result;
1034 iov[count].iov_base = &arg;
1035 iov[count].iov_len = sizeof(arg);
1036 count++;
1037
1038 if (size) {
1039 iov[count].iov_base = (char *) buf;
1040 iov[count].iov_len = size;
1041 count++;
1042 }
1043
1044 return send_reply_iov(req, 0, iov, count);
1045 }
1046
1047 int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
1048 int count)
1049 {
1050 struct iovec *padded_iov;
1051 struct fuse_ioctl_out arg;
1052 int res;
1053
1054 padded_iov = malloc((count + 2) * sizeof(struct iovec));
1055 if (padded_iov == NULL)
1056 return fuse_reply_err(req, ENOMEM);
1057
1058 memset(&arg, 0, sizeof(arg));
1059 arg.result = result;
1060 padded_iov[1].iov_base = &arg;
1061 padded_iov[1].iov_len = sizeof(arg);
1062
1063 memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
1064
1065 res = send_reply_iov(req, 0, padded_iov, count + 2);
1066 free(padded_iov);
1067
1068 return res;
1069 }
1070
1071 int fuse_reply_poll(fuse_req_t req, unsigned revents)
1072 {
1073 struct fuse_poll_out arg;
1074
1075 memset(&arg, 0, sizeof(arg));
1076 arg.revents = revents;
1077
1078 return send_reply_ok(req, &arg, sizeof(arg));
1079 }
1080
1081 int fuse_reply_lseek(fuse_req_t req, off_t off)
1082 {
1083 struct fuse_lseek_out arg;
1084
1085 memset(&arg, 0, sizeof(arg));
1086 arg.offset = off;
1087
1088 return send_reply_ok(req, &arg, sizeof(arg));
1089 }
1090
1091 static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1092 {
1093 char *name = (char *) inarg;
1094
1095 if (req->se->op.lookup)
1096 req->se->op.lookup(req, nodeid, name);
1097 else
1098 fuse_reply_err(req, ENOSYS);
1099 }
1100
1101 static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1102 {
1103 struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
1104
1105 if (req->se->op.forget)
1106 req->se->op.forget(req, nodeid, arg->nlookup);
1107 else
1108 fuse_reply_none(req);
1109 }
1110
1111 static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
1112 const void *inarg)
1113 {
1114 struct fuse_batch_forget_in *arg = (void *) inarg;
1115 struct fuse_forget_one *param = (void *) PARAM(arg);
1116 unsigned int i;
1117
1118 (void) nodeid;
1119
1120 if (req->se->op.forget_multi) {
1121 req->se->op.forget_multi(req, arg->count,
1122 (struct fuse_forget_data *) param);
1123 } else if (req->se->op.forget) {
1124 for (i = 0; i < arg->count; i++) {
1125 struct fuse_forget_one *forget = &param[i];
1126 struct fuse_req *dummy_req;
1127
1128 dummy_req = fuse_ll_alloc_req(req->se);
1129 if (dummy_req == NULL)
1130 break;
1131
1132 dummy_req->unique = req->unique;
1133 dummy_req->ctx = req->ctx;
1134 dummy_req->ch = NULL;
1135
1136 req->se->op.forget(dummy_req, forget->nodeid,
1137 forget->nlookup);
1138 }
1139 fuse_reply_none(req);
1140 } else {
1141 fuse_reply_none(req);
1142 }
1143 }
1144
1145 static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1146 {
1147 struct fuse_file_info *fip = NULL;
1148 struct fuse_file_info fi;
1149
1150 if (req->se->conn.proto_minor >= 9) {
1151 struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
1152
1153 if (arg->getattr_flags & FUSE_GETATTR_FH) {
1154 memset(&fi, 0, sizeof(fi));
1155 fi.fh = arg->fh;
1156 fip = &fi;
1157 }
1158 }
1159
1160 if (req->se->op.getattr)
1161 req->se->op.getattr(req, nodeid, fip);
1162 else
1163 fuse_reply_err(req, ENOSYS);
1164 }
1165
1166 static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1167 {
1168 struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
1169
1170 if (req->se->op.setattr) {
1171 struct fuse_file_info *fi = NULL;
1172 struct fuse_file_info fi_store;
1173 struct stat stbuf;
1174 memset(&stbuf, 0, sizeof(stbuf));
1175 convert_attr(arg, &stbuf);
1176 if (arg->valid & FATTR_FH) {
1177 arg->valid &= ~FATTR_FH;
1178 memset(&fi_store, 0, sizeof(fi_store));
1179 fi = &fi_store;
1180 fi->fh = arg->fh;
1181 }
1182 arg->valid &=
1183 FUSE_SET_ATTR_MODE |
1184 FUSE_SET_ATTR_UID |
1185 FUSE_SET_ATTR_GID |
1186 FUSE_SET_ATTR_SIZE |
1187 FUSE_SET_ATTR_ATIME |
1188 FUSE_SET_ATTR_MTIME |
1189 FUSE_SET_ATTR_ATIME_NOW |
1190 FUSE_SET_ATTR_MTIME_NOW |
1191 FUSE_SET_ATTR_CTIME;
1192
1193 req->se->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
1194 } else
1195 fuse_reply_err(req, ENOSYS);
1196 }
1197
1198 static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1199 {
1200 struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
1201
1202 if (req->se->op.access)
1203 req->se->op.access(req, nodeid, arg->mask);
1204 else
1205 fuse_reply_err(req, ENOSYS);
1206 }
1207
1208 static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1209 {
1210 (void) inarg;
1211
1212 if (req->se->op.readlink)
1213 req->se->op.readlink(req, nodeid);
1214 else
1215 fuse_reply_err(req, ENOSYS);
1216 }
1217
1218 static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1219 {
1220 struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
1221 char *name = PARAM(arg);
1222
1223 if (req->se->conn.proto_minor >= 12)
1224 req->ctx.umask = arg->umask;
1225 else
1226 name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
1227
1228 if (req->se->op.mknod)
1229 req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
1230 else
1231 fuse_reply_err(req, ENOSYS);
1232 }
1233
1234 static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1235 {
1236 struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
1237
1238 if (req->se->conn.proto_minor >= 12)
1239 req->ctx.umask = arg->umask;
1240
1241 if (req->se->op.mkdir)
1242 req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
1243 else
1244 fuse_reply_err(req, ENOSYS);
1245 }
1246
1247 static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1248 {
1249 char *name = (char *) inarg;
1250
1251 if (req->se->op.unlink)
1252 req->se->op.unlink(req, nodeid, name);
1253 else
1254 fuse_reply_err(req, ENOSYS);
1255 }
1256
1257 static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1258 {
1259 char *name = (char *) inarg;
1260
1261 if (req->se->op.rmdir)
1262 req->se->op.rmdir(req, nodeid, name);
1263 else
1264 fuse_reply_err(req, ENOSYS);
1265 }
1266
1267 static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1268 {
1269 char *name = (char *) inarg;
1270 char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
1271
1272 if (req->se->op.symlink)
1273 req->se->op.symlink(req, linkname, nodeid, name);
1274 else
1275 fuse_reply_err(req, ENOSYS);
1276 }
1277
1278 static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1279 {
1280 struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
1281 char *oldname = PARAM(arg);
1282 char *newname = oldname + strlen(oldname) + 1;
1283
1284 if (req->se->op.rename)
1285 req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1286 0);
1287 else
1288 fuse_reply_err(req, ENOSYS);
1289 }
1290
1291 static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1292 {
1293 struct fuse_rename2_in *arg = (struct fuse_rename2_in *) inarg;
1294 char *oldname = PARAM(arg);
1295 char *newname = oldname + strlen(oldname) + 1;
1296
1297 if (req->se->op.rename)
1298 req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1299 arg->flags);
1300 else
1301 fuse_reply_err(req, ENOSYS);
1302 }
1303
1304 static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1305 {
1306 struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
1307
1308 if (req->se->op.link)
1309 req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
1310 else
1311 fuse_reply_err(req, ENOSYS);
1312 }
1313
1314 static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1315 {
1316 struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
1317
1318 if (req->se->op.create) {
1319 struct fuse_file_info fi;
1320 char *name = PARAM(arg);
1321
1322 memset(&fi, 0, sizeof(fi));
1323 fi.flags = arg->flags;
1324
1325 if (req->se->conn.proto_minor >= 12)
1326 req->ctx.umask = arg->umask;
1327 else
1328 name = (char *) inarg + sizeof(struct fuse_open_in);
1329
1330 req->se->op.create(req, nodeid, name, arg->mode, &fi);
1331 } else
1332 fuse_reply_err(req, ENOSYS);
1333 }
1334
1335 static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1336 {
1337 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
1338 struct fuse_file_info fi;
1339
1340 memset(&fi, 0, sizeof(fi));
1341 fi.flags = arg->flags;
1342
1343 if (req->se->op.open)
1344 req->se->op.open(req, nodeid, &fi);
1345 else
1346 fuse_reply_open(req, &fi);
1347 }
1348
1349 static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1350 {
1351 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1352
1353 if (req->se->op.read) {
1354 struct fuse_file_info fi;
1355
1356 memset(&fi, 0, sizeof(fi));
1357 fi.fh = arg->fh;
1358 if (req->se->conn.proto_minor >= 9) {
1359 fi.lock_owner = arg->lock_owner;
1360 fi.flags = arg->flags;
1361 }
1362 req->se->op.read(req, nodeid, arg->size, arg->offset, &fi);
1363 } else
1364 fuse_reply_err(req, ENOSYS);
1365 }
1366
1367 static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1368 {
1369 struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
1370 struct fuse_file_info fi;
1371 char *param;
1372
1373 memset(&fi, 0, sizeof(fi));
1374 fi.fh = arg->fh;
1375 fi.writepage = (arg->write_flags & FUSE_WRITE_CACHE) != 0;
1376
1377 if (req->se->conn.proto_minor < 9) {
1378 param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1379 } else {
1380 fi.lock_owner = arg->lock_owner;
1381 fi.flags = arg->flags;
1382 param = PARAM(arg);
1383 }
1384
1385 if (req->se->op.write)
1386 req->se->op.write(req, nodeid, param, arg->size,
1387 arg->offset, &fi);
1388 else
1389 fuse_reply_err(req, ENOSYS);
1390 }
1391
1392 static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid, const void *inarg,
1393 const struct fuse_buf *ibuf)
1394 {
1395 struct fuse_session *se = req->se;
1396 struct fuse_bufvec bufv = {
1397 .buf[0] = *ibuf,
1398 .count = 1,
1399 };
1400 struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
1401 struct fuse_file_info fi;
1402
1403 memset(&fi, 0, sizeof(fi));
1404 fi.fh = arg->fh;
1405 fi.writepage = arg->write_flags & FUSE_WRITE_CACHE;
1406
1407 if (se->conn.proto_minor < 9) {
1408 bufv.buf[0].mem = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
1409 bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1410 FUSE_COMPAT_WRITE_IN_SIZE;
1411 assert(!(bufv.buf[0].flags & FUSE_BUF_IS_FD));
1412 } else {
1413 fi.lock_owner = arg->lock_owner;
1414 fi.flags = arg->flags;
1415 if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
1416 bufv.buf[0].mem = PARAM(arg);
1417
1418 bufv.buf[0].size -= sizeof(struct fuse_in_header) +
1419 sizeof(struct fuse_write_in);
1420 }
1421 if (bufv.buf[0].size < arg->size) {
1422 fuse_log(FUSE_LOG_ERR, "fuse: do_write_buf: buffer size too small\n");
1423 fuse_reply_err(req, EIO);
1424 goto out;
1425 }
1426 bufv.buf[0].size = arg->size;
1427
1428 se->op.write_buf(req, nodeid, &bufv, arg->offset, &fi);
1429
1430 out:
1431 /* Need to reset the pipe if ->write_buf() didn't consume all data */
1432 if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
1433 fuse_ll_clear_pipe(se);
1434 }
1435
1436 static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1437 {
1438 struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
1439 struct fuse_file_info fi;
1440
1441 memset(&fi, 0, sizeof(fi));
1442 fi.fh = arg->fh;
1443 fi.flush = 1;
1444 if (req->se->conn.proto_minor >= 7)
1445 fi.lock_owner = arg->lock_owner;
1446
1447 if (req->se->op.flush)
1448 req->se->op.flush(req, nodeid, &fi);
1449 else
1450 fuse_reply_err(req, ENOSYS);
1451 }
1452
1453 static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1454 {
1455 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
1456 struct fuse_file_info fi;
1457
1458 memset(&fi, 0, sizeof(fi));
1459 fi.flags = arg->flags;
1460 fi.fh = arg->fh;
1461 if (req->se->conn.proto_minor >= 8) {
1462 fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
1463 fi.lock_owner = arg->lock_owner;
1464 }
1465 if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
1466 fi.flock_release = 1;
1467 fi.lock_owner = arg->lock_owner;
1468 }
1469
1470 if (req->se->op.release)
1471 req->se->op.release(req, nodeid, &fi);
1472 else
1473 fuse_reply_err(req, 0);
1474 }
1475
1476 static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1477 {
1478 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
1479 struct fuse_file_info fi;
1480 int datasync = arg->fsync_flags & 1;
1481
1482 memset(&fi, 0, sizeof(fi));
1483 fi.fh = arg->fh;
1484
1485 if (req->se->op.fsync)
1486 req->se->op.fsync(req, nodeid, datasync, &fi);
1487 else
1488 fuse_reply_err(req, ENOSYS);
1489 }
1490
1491 static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1492 {
1493 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
1494 struct fuse_file_info fi;
1495
1496 memset(&fi, 0, sizeof(fi));
1497 fi.flags = arg->flags;
1498
1499 if (req->se->op.opendir)
1500 req->se->op.opendir(req, nodeid, &fi);
1501 else
1502 fuse_reply_open(req, &fi);
1503 }
1504
1505 static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1506 {
1507 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1508 struct fuse_file_info fi;
1509
1510 memset(&fi, 0, sizeof(fi));
1511 fi.fh = arg->fh;
1512
1513 if (req->se->op.readdir)
1514 req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
1515 else
1516 fuse_reply_err(req, ENOSYS);
1517 }
1518
1519 static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1520 {
1521 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
1522 struct fuse_file_info fi;
1523
1524 memset(&fi, 0, sizeof(fi));
1525 fi.fh = arg->fh;
1526
1527 if (req->se->op.readdirplus)
1528 req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
1529 else
1530 fuse_reply_err(req, ENOSYS);
1531 }
1532
1533 static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1534 {
1535 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
1536 struct fuse_file_info fi;
1537
1538 memset(&fi, 0, sizeof(fi));
1539 fi.flags = arg->flags;
1540 fi.fh = arg->fh;
1541
1542 if (req->se->op.releasedir)
1543 req->se->op.releasedir(req, nodeid, &fi);
1544 else
1545 fuse_reply_err(req, 0);
1546 }
1547
1548 static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1549 {
1550 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
1551 struct fuse_file_info fi;
1552 int datasync = arg->fsync_flags & 1;
1553
1554 memset(&fi, 0, sizeof(fi));
1555 fi.fh = arg->fh;
1556
1557 if (req->se->op.fsyncdir)
1558 req->se->op.fsyncdir(req, nodeid, datasync, &fi);
1559 else
1560 fuse_reply_err(req, ENOSYS);
1561 }
1562
1563 static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1564 {
1565 (void) nodeid;
1566 (void) inarg;
1567
1568 if (req->se->op.statfs)
1569 req->se->op.statfs(req, nodeid);
1570 else {
1571 struct statvfs buf = {
1572 .f_namemax = 255,
1573 .f_bsize = 512,
1574 };
1575 fuse_reply_statfs(req, &buf);
1576 }
1577 }
1578
1579 static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1580 {
1581 struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
1582 char *name = PARAM(arg);
1583 char *value = name + strlen(name) + 1;
1584
1585 if (req->se->op.setxattr)
1586 req->se->op.setxattr(req, nodeid, name, value, arg->size,
1587 arg->flags);
1588 else
1589 fuse_reply_err(req, ENOSYS);
1590 }
1591
1592 static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1593 {
1594 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
1595
1596 if (req->se->op.getxattr)
1597 req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
1598 else
1599 fuse_reply_err(req, ENOSYS);
1600 }
1601
1602 static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1603 {
1604 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
1605
1606 if (req->se->op.listxattr)
1607 req->se->op.listxattr(req, nodeid, arg->size);
1608 else
1609 fuse_reply_err(req, ENOSYS);
1610 }
1611
1612 static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1613 {
1614 char *name = (char *) inarg;
1615
1616 if (req->se->op.removexattr)
1617 req->se->op.removexattr(req, nodeid, name);
1618 else
1619 fuse_reply_err(req, ENOSYS);
1620 }
1621
1622 static void convert_fuse_file_lock(struct fuse_file_lock *fl,
1623 struct flock *flock)
1624 {
1625 memset(flock, 0, sizeof(struct flock));
1626 flock->l_type = fl->type;
1627 flock->l_whence = SEEK_SET;
1628 flock->l_start = fl->start;
1629 if (fl->end == OFFSET_MAX)
1630 flock->l_len = 0;
1631 else
1632 flock->l_len = fl->end - fl->start + 1;
1633 flock->l_pid = fl->pid;
1634 }
1635
1636 static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1637 {
1638 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
1639 struct fuse_file_info fi;
1640 struct flock flock;
1641
1642 memset(&fi, 0, sizeof(fi));
1643 fi.fh = arg->fh;
1644 fi.lock_owner = arg->owner;
1645
1646 convert_fuse_file_lock(&arg->lk, &flock);
1647 if (req->se->op.getlk)
1648 req->se->op.getlk(req, nodeid, &fi, &flock);
1649 else
1650 fuse_reply_err(req, ENOSYS);
1651 }
1652
1653 static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
1654 const void *inarg, int sleep)
1655 {
1656 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
1657 struct fuse_file_info fi;
1658 struct flock flock;
1659
1660 memset(&fi, 0, sizeof(fi));
1661 fi.fh = arg->fh;
1662 fi.lock_owner = arg->owner;
1663
1664 if (arg->lk_flags & FUSE_LK_FLOCK) {
1665 int op = 0;
1666
1667 switch (arg->lk.type) {
1668 case F_RDLCK:
1669 op = LOCK_SH;
1670 break;
1671 case F_WRLCK:
1672 op = LOCK_EX;
1673 break;
1674 case F_UNLCK:
1675 op = LOCK_UN;
1676 break;
1677 }
1678 if (!sleep)
1679 op |= LOCK_NB;
1680
1681 if (req->se->op.flock)
1682 req->se->op.flock(req, nodeid, &fi, op);
1683 else
1684 fuse_reply_err(req, ENOSYS);
1685 } else {
1686 convert_fuse_file_lock(&arg->lk, &flock);
1687 if (req->se->op.setlk)
1688 req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
1689 else
1690 fuse_reply_err(req, ENOSYS);
1691 }
1692 }
1693
1694 static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1695 {
1696 do_setlk_common(req, nodeid, inarg, 0);
1697 }
1698
1699 static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1700 {
1701 do_setlk_common(req, nodeid, inarg, 1);
1702 }
1703
1704 static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
1705 {
1706 struct fuse_req *curr;
1707
1708 for (curr = se->list.next; curr != &se->list; curr = curr->next) {
1709 if (curr->unique == req->u.i.unique) {
1710 fuse_interrupt_func_t func;
1711 void *data;
1712
1713 curr->ctr++;
1714 pthread_mutex_unlock(&se->lock);
1715
1716 /* Ugh, ugly locking */
1717 pthread_mutex_lock(&curr->lock);
1718 pthread_mutex_lock(&se->lock);
1719 curr->interrupted = 1;
1720 func = curr->u.ni.func;
1721 data = curr->u.ni.data;
1722 pthread_mutex_unlock(&se->lock);
1723 if (func)
1724 func(curr, data);
1725 pthread_mutex_unlock(&curr->lock);
1726
1727 pthread_mutex_lock(&se->lock);
1728 curr->ctr--;
1729 if (!curr->ctr) {
1730 fuse_chan_put(req->ch);
1731 req->ch = NULL;
1732 destroy_req(curr);
1733 }
1734
1735 return 1;
1736 }
1737 }
1738 for (curr = se->interrupts.next; curr != &se->interrupts;
1739 curr = curr->next) {
1740 if (curr->u.i.unique == req->u.i.unique)
1741 return 1;
1742 }
1743 return 0;
1744 }
1745
1746 static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1747 {
1748 struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
1749 struct fuse_session *se = req->se;
1750
1751 (void) nodeid;
1752 if (se->debug)
1753 fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
1754 (unsigned long long) arg->unique);
1755
1756 req->u.i.unique = arg->unique;
1757
1758 pthread_mutex_lock(&se->lock);
1759 if (find_interrupted(se, req)) {
1760 fuse_chan_put(req->ch);
1761 req->ch = NULL;
1762 destroy_req(req);
1763 } else
1764 list_add_req(req, &se->interrupts);
1765 pthread_mutex_unlock(&se->lock);
1766 }
1767
1768 static struct fuse_req *check_interrupt(struct fuse_session *se,
1769 struct fuse_req *req)
1770 {
1771 struct fuse_req *curr;
1772
1773 for (curr = se->interrupts.next; curr != &se->interrupts;
1774 curr = curr->next) {
1775 if (curr->u.i.unique == req->unique) {
1776 req->interrupted = 1;
1777 list_del_req(curr);
1778 fuse_chan_put(curr->ch);
1779 curr->ch = NULL;
1780 destroy_req(curr);
1781 return NULL;
1782 }
1783 }
1784 curr = se->interrupts.next;
1785 if (curr != &se->interrupts) {
1786 list_del_req(curr);
1787 list_init_req(curr);
1788 return curr;
1789 } else
1790 return NULL;
1791 }
1792
1793 static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1794 {
1795 struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
1796
1797 if (req->se->op.bmap)
1798 req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
1799 else
1800 fuse_reply_err(req, ENOSYS);
1801 }
1802
1803 static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1804 {
1805 struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
1806 unsigned int flags = arg->flags;
1807 void *in_buf = arg->in_size ? PARAM(arg) : NULL;
1808 struct fuse_file_info fi;
1809
1810 if (flags & FUSE_IOCTL_DIR &&
1811 !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
1812 fuse_reply_err(req, ENOTTY);
1813 return;
1814 }
1815
1816 memset(&fi, 0, sizeof(fi));
1817 fi.fh = arg->fh;
1818
1819 if (sizeof(void *) == 4 && req->se->conn.proto_minor >= 16 &&
1820 !(flags & FUSE_IOCTL_32BIT)) {
1821 req->ioctl_64bit = 1;
1822 }
1823
1824 if (req->se->op.ioctl)
1825 req->se->op.ioctl(req, nodeid, arg->cmd,
1826 (void *)(uintptr_t)arg->arg, &fi, flags,
1827 in_buf, arg->in_size, arg->out_size);
1828 else
1829 fuse_reply_err(req, ENOSYS);
1830 }
1831
1832 void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
1833 {
1834 free(ph);
1835 }
1836
1837 static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1838 {
1839 struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
1840 struct fuse_file_info fi;
1841
1842 memset(&fi, 0, sizeof(fi));
1843 fi.fh = arg->fh;
1844 fi.poll_events = arg->events;
1845
1846 if (req->se->op.poll) {
1847 struct fuse_pollhandle *ph = NULL;
1848
1849 if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
1850 ph = malloc(sizeof(struct fuse_pollhandle));
1851 if (ph == NULL) {
1852 fuse_reply_err(req, ENOMEM);
1853 return;
1854 }
1855 ph->kh = arg->kh;
1856 ph->se = req->se;
1857 }
1858
1859 req->se->op.poll(req, nodeid, &fi, ph);
1860 } else {
1861 fuse_reply_err(req, ENOSYS);
1862 }
1863 }
1864
1865 static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1866 {
1867 struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *) inarg;
1868 struct fuse_file_info fi;
1869
1870 memset(&fi, 0, sizeof(fi));
1871 fi.fh = arg->fh;
1872
1873 if (req->se->op.fallocate)
1874 req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length, &fi);
1875 else
1876 fuse_reply_err(req, ENOSYS);
1877 }
1878
1879 static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const void *inarg)
1880 {
1881 struct fuse_copy_file_range_in *arg = (struct fuse_copy_file_range_in *) inarg;
1882 struct fuse_file_info fi_in, fi_out;
1883
1884 memset(&fi_in, 0, sizeof(fi_in));
1885 fi_in.fh = arg->fh_in;
1886
1887 memset(&fi_out, 0, sizeof(fi_out));
1888 fi_out.fh = arg->fh_out;
1889
1890
1891 if (req->se->op.copy_file_range)
1892 req->se->op.copy_file_range(req, nodeid_in, arg->off_in,
1893 &fi_in, arg->nodeid_out,
1894 arg->off_out, &fi_out, arg->len,
1895 arg->flags);
1896 else
1897 fuse_reply_err(req, ENOSYS);
1898 }
1899
1900 static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1901 {
1902 struct fuse_lseek_in *arg = (struct fuse_lseek_in *) inarg;
1903 struct fuse_file_info fi;
1904
1905 memset(&fi, 0, sizeof(fi));
1906 fi.fh = arg->fh;
1907
1908 if (req->se->op.lseek)
1909 req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
1910 else
1911 fuse_reply_err(req, ENOSYS);
1912 }
1913
1914 /* Prevent bogus data races (bogus since "init" is called before
1915 * multi-threading becomes relevant */
1916 static __attribute__((no_sanitize("thread")))
1917 void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1918 {
1919 struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
1920 struct fuse_init_out outarg;
1921 struct fuse_session *se = req->se;
1922 size_t bufsize = se->bufsize;
1923 size_t outargsize = sizeof(outarg);
1924 uint64_t inargflags = 0;
1925 uint64_t outargflags = 0;
1926 (void) nodeid;
1927 if (se->debug) {
1928 fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
1929 if (arg->major == 7 && arg->minor >= 6) {
1930 fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
1931 fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
1932 arg->max_readahead);
1933 }
1934 }
1935 se->conn.proto_major = arg->major;
1936 se->conn.proto_minor = arg->minor;
1937 se->conn.capable = 0;
1938 se->conn.want = 0;
1939
1940 memset(&outarg, 0, sizeof(outarg));
1941 outarg.major = FUSE_KERNEL_VERSION;
1942 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
1943
1944 if (arg->major < 7) {
1945 fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
1946 arg->major, arg->minor);
1947 fuse_reply_err(req, EPROTO);
1948 return;
1949 }
1950
1951 if (arg->major > 7) {
1952 /* Wait for a second INIT request with a 7.X version */
1953 send_reply_ok(req, &outarg, sizeof(outarg));
1954 return;
1955 }
1956
1957 if (arg->minor >= 6) {
1958 if (arg->max_readahead < se->conn.max_readahead)
1959 se->conn.max_readahead = arg->max_readahead;
1960 inargflags = arg->flags;
1961 if (inargflags & FUSE_INIT_EXT)
1962 inargflags = inargflags | (uint64_t) arg->flags2 << 32;
1963 if (inargflags & FUSE_ASYNC_READ)
1964 se->conn.capable |= FUSE_CAP_ASYNC_READ;
1965 if (inargflags & FUSE_POSIX_LOCKS)
1966 se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
1967 if (inargflags & FUSE_ATOMIC_O_TRUNC)
1968 se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
1969 if (inargflags & FUSE_EXPORT_SUPPORT)
1970 se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
1971 if (inargflags & FUSE_DONT_MASK)
1972 se->conn.capable |= FUSE_CAP_DONT_MASK;
1973 if (inargflags & FUSE_FLOCK_LOCKS)
1974 se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
1975 if (inargflags & FUSE_AUTO_INVAL_DATA)
1976 se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
1977 if (inargflags & FUSE_DO_READDIRPLUS)
1978 se->conn.capable |= FUSE_CAP_READDIRPLUS;
1979 if (inargflags & FUSE_READDIRPLUS_AUTO)
1980 se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
1981 if (inargflags & FUSE_ASYNC_DIO)
1982 se->conn.capable |= FUSE_CAP_ASYNC_DIO;
1983 if (inargflags & FUSE_WRITEBACK_CACHE)
1984 se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
1985 if (inargflags & FUSE_NO_OPEN_SUPPORT)
1986 se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
1987 if (inargflags & FUSE_PARALLEL_DIROPS)
1988 se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
1989 if (inargflags & FUSE_POSIX_ACL)
1990 se->conn.capable |= FUSE_CAP_POSIX_ACL;
1991 if (inargflags & FUSE_HANDLE_KILLPRIV)
1992 se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
1993 if (inargflags & FUSE_CACHE_SYMLINKS)
1994 se->conn.capable |= FUSE_CAP_CACHE_SYMLINKS;
1995 if (inargflags & FUSE_NO_OPENDIR_SUPPORT)
1996 se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
1997 if (inargflags & FUSE_EXPLICIT_INVAL_DATA)
1998 se->conn.capable |= FUSE_CAP_EXPLICIT_INVAL_DATA;
1999 if (!(inargflags & FUSE_MAX_PAGES)) {
2000 size_t max_bufsize =
2001 FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize()
2002 + FUSE_BUFFER_HEADER_SIZE;
2003 if (bufsize > max_bufsize) {
2004 bufsize = max_bufsize;
2005 }
2006 }
2007 if (arg->minor >= 38)
2008 se->conn.capable |= FUSE_CAP_EXPIRE_ONLY;
2009 } else {
2010 se->conn.max_readahead = 0;
2011 }
2012
2013 if (se->conn.proto_minor >= 14) {
2014 #ifdef HAVE_SPLICE
2015 #ifdef HAVE_VMSPLICE
2016 if ((se->io == NULL) || (se->io->splice_send != NULL)) {
2017 se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
2018 }
2019 #endif
2020 if ((se->io == NULL) || (se->io->splice_receive != NULL)) {
2021 se->conn.capable |= FUSE_CAP_SPLICE_READ;
2022 }
2023 #endif
2024 }
2025 if (se->conn.proto_minor >= 18)
2026 se->conn.capable |= FUSE_CAP_IOCTL_DIR;
2027
2028 /* Default settings for modern filesystems.
2029 *
2030 * Most of these capabilities were disabled by default in
2031 * libfuse2 for backwards compatibility reasons. In libfuse3,
2032 * we can finally enable them by default (as long as they're
2033 * supported by the kernel).
2034 */
2035 #define LL_SET_DEFAULT(cond, cap) \
2036 if ((cond) && (se->conn.capable & (cap))) \
2037 se->conn.want |= (cap)
2038 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
2039 LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
2040 LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
2041 LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
2042 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
2043 LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
2044 LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
2045 LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
2046 LL_SET_DEFAULT(se->op.getlk && se->op.setlk,
2047 FUSE_CAP_POSIX_LOCKS);
2048 LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
2049 LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
2050 LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
2051 FUSE_CAP_READDIRPLUS_AUTO);
2052 se->conn.time_gran = 1;
2053
2054 if (bufsize < FUSE_MIN_READ_BUFFER) {
2055 fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
2056 bufsize);
2057 bufsize = FUSE_MIN_READ_BUFFER;
2058 }
2059 se->bufsize = bufsize;
2060
2061 if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE)
2062 se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
2063
2064 se->got_init = 1;
2065 if (se->op.init)
2066 se->op.init(se->userdata, &se->conn);
2067
2068 if (se->conn.want & (~se->conn.capable)) {
2069 fuse_log(FUSE_LOG_ERR, "fuse: error: filesystem requested capabilities "
2070 "0x%x that are not supported by kernel, aborting.\n",
2071 se->conn.want & (~se->conn.capable));
2072 fuse_reply_err(req, EPROTO);
2073 se->error = -EPROTO;
2074 fuse_session_exit(se);
2075 return;
2076 }
2077
2078 unsigned max_read_mo = get_max_read(se->mo);
2079 if (se->conn.max_read != max_read_mo) {
2080 fuse_log(FUSE_LOG_ERR, "fuse: error: init() and fuse_session_new() "
2081 "requested different maximum read size (%u vs %u)\n",
2082 se->conn.max_read, max_read_mo);
2083 fuse_reply_err(req, EPROTO);
2084 se->error = -EPROTO;
2085 fuse_session_exit(se);
2086 return;
2087 }
2088
2089 if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
2090 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
2091 }
2092 if (arg->flags & FUSE_MAX_PAGES) {
2093 outarg.flags |= FUSE_MAX_PAGES;
2094 outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
2095 }
2096 outargflags = outarg.flags;
2097 /* Always enable big writes, this is superseded
2098 by the max_write option */
2099 outargflags |= FUSE_BIG_WRITES;
2100
2101 if (se->conn.want & FUSE_CAP_ASYNC_READ)
2102 outargflags |= FUSE_ASYNC_READ;
2103 if (se->conn.want & FUSE_CAP_POSIX_LOCKS)
2104 outargflags |= FUSE_POSIX_LOCKS;
2105 if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
2106 outargflags |= FUSE_ATOMIC_O_TRUNC;
2107 if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT)
2108 outargflags |= FUSE_EXPORT_SUPPORT;
2109 if (se->conn.want & FUSE_CAP_DONT_MASK)
2110 outargflags |= FUSE_DONT_MASK;
2111 if (se->conn.want & FUSE_CAP_FLOCK_LOCKS)
2112 outargflags |= FUSE_FLOCK_LOCKS;
2113 if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA)
2114 outargflags |= FUSE_AUTO_INVAL_DATA;
2115 if (se->conn.want & FUSE_CAP_READDIRPLUS)
2116 outargflags |= FUSE_DO_READDIRPLUS;
2117 if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO)
2118 outargflags |= FUSE_READDIRPLUS_AUTO;
2119 if (se->conn.want & FUSE_CAP_ASYNC_DIO)
2120 outargflags |= FUSE_ASYNC_DIO;
2121 if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE)
2122 outargflags |= FUSE_WRITEBACK_CACHE;
2123 if (se->conn.want & FUSE_CAP_POSIX_ACL)
2124 outargflags |= FUSE_POSIX_ACL;
2125 if (se->conn.want & FUSE_CAP_CACHE_SYMLINKS)
2126 outargflags |= FUSE_CACHE_SYMLINKS;
2127 if (se->conn.want & FUSE_CAP_EXPLICIT_INVAL_DATA)
2128 outargflags |= FUSE_EXPLICIT_INVAL_DATA;
2129
2130 if (inargflags & FUSE_INIT_EXT) {
2131 outargflags |= FUSE_INIT_EXT;
2132 outarg.flags2 = outargflags >> 32;
2133 }
2134
2135 outarg.flags = outargflags;
2136
2137 outarg.max_readahead = se->conn.max_readahead;
2138 outarg.max_write = se->conn.max_write;
2139 if (se->conn.proto_minor >= 13) {
2140 if (se->conn.max_background >= (1 << 16))
2141 se->conn.max_background = (1 << 16) - 1;
2142 if (se->conn.congestion_threshold > se->conn.max_background)
2143 se->conn.congestion_threshold = se->conn.max_background;
2144 if (!se->conn.congestion_threshold) {
2145 se->conn.congestion_threshold =
2146 se->conn.max_background * 3 / 4;
2147 }
2148
2149 outarg.max_background = se->conn.max_background;
2150 outarg.congestion_threshold = se->conn.congestion_threshold;
2151 }
2152 if (se->conn.proto_minor >= 23)
2153 outarg.time_gran = se->conn.time_gran;
2154
2155 if (se->debug) {
2156 fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major, outarg.minor);
2157 fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
2158 fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n",
2159 outarg.max_readahead);
2160 fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
2161 fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n",
2162 outarg.max_background);
2163 fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n",
2164 outarg.congestion_threshold);
2165 fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n",
2166 outarg.time_gran);
2167 }
2168 if (arg->minor < 5)
2169 outargsize = FUSE_COMPAT_INIT_OUT_SIZE;
2170 else if (arg->minor < 23)
2171 outargsize = FUSE_COMPAT_22_INIT_OUT_SIZE;
2172
2173 send_reply_ok(req, &outarg, outargsize);
2174 }
2175
2176 static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
2177 {
2178 struct fuse_session *se = req->se;
2179
2180 (void) nodeid;
2181 (void) inarg;
2182
2183 se->got_destroy = 1;
2184 if (se->op.destroy)
2185 se->op.destroy(se->userdata);
2186
2187 send_reply_ok(req, NULL, 0);
2188 }
2189
2190 static void list_del_nreq(struct fuse_notify_req *nreq)
2191 {
2192 struct fuse_notify_req *prev = nreq->prev;
2193 struct fuse_notify_req *next = nreq->next;
2194 prev->next = next;
2195 next->prev = prev;
2196 }
2197
2198 static void list_add_nreq(struct fuse_notify_req *nreq,
2199 struct fuse_notify_req *next)
2200 {
2201 struct fuse_notify_req *prev = next->prev;
2202 nreq->next = next;
2203 nreq->prev = prev;
2204 prev->next = nreq;
2205 next->prev = nreq;
2206 }
2207
2208 static void list_init_nreq(struct fuse_notify_req *nreq)
2209 {
2210 nreq->next = nreq;
2211 nreq->prev = nreq;
2212 }
2213
2214 static void do_notify_reply(fuse_req_t req, fuse_ino_t nodeid,
2215 const void *inarg, const struct fuse_buf *buf)
2216 {
2217 struct fuse_session *se = req->se;
2218 struct fuse_notify_req *nreq;
2219 struct fuse_notify_req *head;
2220
2221 pthread_mutex_lock(&se->lock);
2222 head = &se->notify_list;
2223 for (nreq = head->next; nreq != head; nreq = nreq->next) {
2224 if (nreq->unique == req->unique) {
2225 list_del_nreq(nreq);
2226 break;
2227 }
2228 }
2229 pthread_mutex_unlock(&se->lock);
2230
2231 if (nreq != head)
2232 nreq->reply(nreq, req, nodeid, inarg, buf);
2233 }
2234
2235 static int send_notify_iov(struct fuse_session *se, int notify_code,
2236 struct iovec *iov, int count)
2237 {
2238 struct fuse_out_header out;
2239
2240 if (!se->got_init)
2241 return -ENOTCONN;
2242
2243 out.unique = 0;
2244 out.error = notify_code;
2245 iov[0].iov_base = &out;
2246 iov[0].iov_len = sizeof(struct fuse_out_header);
2247
2248 return fuse_send_msg(se, NULL, iov, count);
2249 }
2250
2251 int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
2252 {
2253 if (ph != NULL) {
2254 struct fuse_notify_poll_wakeup_out outarg;
2255 struct iovec iov[2];
2256
2257 outarg.kh = ph->kh;
2258
2259 iov[1].iov_base = &outarg;
2260 iov[1].iov_len = sizeof(outarg);
2261
2262 return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
2263 } else {
2264 return 0;
2265 }
2266 }
2267
2268 int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
2269 off_t off, off_t len)
2270 {
2271 struct fuse_notify_inval_inode_out outarg;
2272 struct iovec iov[2];
2273
2274 if (!se)
2275 return -EINVAL;
2276
2277 if (se->conn.proto_minor < 12)
2278 return -ENOSYS;
2279
2280 outarg.ino = ino;
2281 outarg.off = off;
2282 outarg.len = len;
2283
2284 iov[1].iov_base = &outarg;
2285 iov[1].iov_len = sizeof(outarg);
2286
2287 return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
2288 }
2289
2290 int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent,
2291 const char *name, size_t namelen,
2292 enum fuse_expire_flags flags)
2293 {
2294 struct fuse_notify_inval_entry_out outarg;
2295 struct iovec iov[3];
2296
2297 if (!se)
2298 return -EINVAL;
2299
2300 if (se->conn.proto_minor < 12)
2301 return -ENOSYS;
2302
2303 outarg.parent = parent;
2304 outarg.namelen = namelen;
2305 outarg.flags = 0;
2306 if (flags & FUSE_LL_EXPIRE_ONLY)
2307 outarg.flags |= FUSE_EXPIRE_ONLY;
2308
2309 iov[1].iov_base = &outarg;
2310 iov[1].iov_len = sizeof(outarg);
2311 iov[2].iov_base = (void *)name;
2312 iov[2].iov_len = namelen + 1;
2313
2314 return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
2315 }
2316
2317 int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
2318 const char *name, size_t namelen)
2319 {
2320 return fuse_lowlevel_notify_expire_entry(se, parent, name, namelen, 0);
2321 }
2322
2323
2324 int fuse_lowlevel_notify_delete(struct fuse_session *se,
2325 fuse_ino_t parent, fuse_ino_t child,
2326 const char *name, size_t namelen)
2327 {
2328 struct fuse_notify_delete_out outarg;
2329 struct iovec iov[3];
2330
2331 if (!se)
2332 return -EINVAL;
2333
2334 if (se->conn.proto_minor < 18)
2335 return -ENOSYS;
2336
2337 outarg.parent = parent;
2338 outarg.child = child;
2339 outarg.namelen = namelen;
2340 outarg.padding = 0;
2341
2342 iov[1].iov_base = &outarg;
2343 iov[1].iov_len = sizeof(outarg);
2344 iov[2].iov_base = (void *)name;
2345 iov[2].iov_len = namelen + 1;
2346
2347 return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
2348 }
2349
2350 int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
2351 off_t offset, struct fuse_bufvec *bufv,
2352 enum fuse_buf_copy_flags flags)
2353 {
2354 struct fuse_out_header out;
2355 struct fuse_notify_store_out outarg;
2356 struct iovec iov[3];
2357 size_t size = fuse_buf_size(bufv);
2358 int res;
2359
2360 if (!se)
2361 return -EINVAL;
2362
2363 if (se->conn.proto_minor < 15)
2364 return -ENOSYS;
2365
2366 out.unique = 0;
2367 out.error = FUSE_NOTIFY_STORE;
2368
2369 outarg.nodeid = ino;
2370 outarg.offset = offset;
2371 outarg.size = size;
2372 outarg.padding = 0;
2373
2374 iov[0].iov_base = &out;
2375 iov[0].iov_len = sizeof(out);
2376 iov[1].iov_base = &outarg;
2377 iov[1].iov_len = sizeof(outarg);
2378
2379 res = fuse_send_data_iov(se, NULL, iov, 2, bufv, flags);
2380 if (res > 0)
2381 res = -res;
2382
2383 return res;
2384 }
2385
2386 struct fuse_retrieve_req {
2387 struct fuse_notify_req nreq;
2388 void *cookie;
2389 };
2390
2391 static void fuse_ll_retrieve_reply(struct fuse_notify_req *nreq,
2392 fuse_req_t req, fuse_ino_t ino,
2393 const void *inarg,
2394 const struct fuse_buf *ibuf)
2395 {
2396 struct fuse_session *se = req->se;
2397 struct fuse_retrieve_req *rreq =
2398 container_of(nreq, struct fuse_retrieve_req, nreq);
2399 const struct fuse_notify_retrieve_in *arg = inarg;
2400 struct fuse_bufvec bufv = {
2401 .buf[0] = *ibuf,
2402 .count = 1,
2403 };
2404
2405 if (!(bufv.buf[0].flags & FUSE_BUF_IS_FD))
2406 bufv.buf[0].mem = PARAM(arg);
2407
2408 bufv.buf[0].size -= sizeof(struct fuse_in_header) +
2409 sizeof(struct fuse_notify_retrieve_in);
2410
2411 if (bufv.buf[0].size < arg->size) {
2412 fuse_log(FUSE_LOG_ERR, "fuse: retrieve reply: buffer size too small\n");
2413 fuse_reply_none(req);
2414 goto out;
2415 }
2416 bufv.buf[0].size = arg->size;
2417
2418 if (se->op.retrieve_reply) {
2419 se->op.retrieve_reply(req, rreq->cookie, ino,
2420 arg->offset, &bufv);
2421 } else {
2422 fuse_reply_none(req);
2423 }
2424 out:
2425 free(rreq);
2426 if ((ibuf->flags & FUSE_BUF_IS_FD) && bufv.idx < bufv.count)
2427 fuse_ll_clear_pipe(se);
2428 }
2429
2430 int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino,
2431 size_t size, off_t offset, void *cookie)
2432 {
2433 struct fuse_notify_retrieve_out outarg;
2434 struct iovec iov[2];
2435 struct fuse_retrieve_req *rreq;
2436 int err;
2437
2438 if (!se)
2439 return -EINVAL;
2440
2441 if (se->conn.proto_minor < 15)
2442 return -ENOSYS;
2443
2444 rreq = malloc(sizeof(*rreq));
2445 if (rreq == NULL)
2446 return -ENOMEM;
2447
2448 pthread_mutex_lock(&se->lock);
2449 rreq->cookie = cookie;
2450 rreq->nreq.unique = se->notify_ctr++;
2451 rreq->nreq.reply = fuse_ll_retrieve_reply;
2452 list_add_nreq(&rreq->nreq, &se->notify_list);
2453 pthread_mutex_unlock(&se->lock);
2454
2455 outarg.notify_unique = rreq->nreq.unique;
2456 outarg.nodeid = ino;
2457 outarg.offset = offset;
2458 outarg.size = size;
2459 outarg.padding = 0;
2460
2461 iov[1].iov_base = &outarg;
2462 iov[1].iov_len = sizeof(outarg);
2463
2464 err = send_notify_iov(se, FUSE_NOTIFY_RETRIEVE, iov, 2);
2465 if (err) {
2466 pthread_mutex_lock(&se->lock);
2467 list_del_nreq(&rreq->nreq);
2468 pthread_mutex_unlock(&se->lock);
2469 free(rreq);
2470 }
2471
2472 return err;
2473 }
2474
2475 void *fuse_req_userdata(fuse_req_t req)
2476 {
2477 return req->se->userdata;
2478 }
2479
2480 const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
2481 {
2482 return &req->ctx;
2483 }
2484
2485 void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
2486 void *data)
2487 {
2488 pthread_mutex_lock(&req->lock);
2489 pthread_mutex_lock(&req->se->lock);
2490 req->u.ni.func = func;
2491 req->u.ni.data = data;
2492 pthread_mutex_unlock(&req->se->lock);
2493 if (req->interrupted && func)
2494 func(req, data);
2495 pthread_mutex_unlock(&req->lock);
2496 }
2497
2498 int fuse_req_interrupted(fuse_req_t req)
2499 {
2500 int interrupted;
2501
2502 pthread_mutex_lock(&req->se->lock);
2503 interrupted = req->interrupted;
2504 pthread_mutex_unlock(&req->se->lock);
2505
2506 return interrupted;
2507 }
2508
2509 static struct {
2510 void (*func)(fuse_req_t, fuse_ino_t, const void *);
2511 const char *name;
2512 } fuse_ll_ops[] = {
2513 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
2514 [FUSE_FORGET] = { do_forget, "FORGET" },
2515 [FUSE_GETATTR] = { do_getattr, "GETATTR" },
2516 [FUSE_SETATTR] = { do_setattr, "SETATTR" },
2517 [FUSE_READLINK] = { do_readlink, "READLINK" },
2518 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
2519 [FUSE_MKNOD] = { do_mknod, "MKNOD" },
2520 [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
2521 [FUSE_UNLINK] = { do_unlink, "UNLINK" },
2522 [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
2523 [FUSE_RENAME] = { do_rename, "RENAME" },
2524 [FUSE_LINK] = { do_link, "LINK" },
2525 [FUSE_OPEN] = { do_open, "OPEN" },
2526 [FUSE_READ] = { do_read, "READ" },
2527 [FUSE_WRITE] = { do_write, "WRITE" },
2528 [FUSE_STATFS] = { do_statfs, "STATFS" },
2529 [FUSE_RELEASE] = { do_release, "RELEASE" },
2530 [FUSE_FSYNC] = { do_fsync, "FSYNC" },
2531 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
2532 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
2533 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
2534 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
2535 [FUSE_FLUSH] = { do_flush, "FLUSH" },
2536 [FUSE_INIT] = { do_init, "INIT" },
2537 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
2538 [FUSE_READDIR] = { do_readdir, "READDIR" },
2539 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
2540 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
2541 [FUSE_GETLK] = { do_getlk, "GETLK" },
2542 [FUSE_SETLK] = { do_setlk, "SETLK" },
2543 [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
2544 [FUSE_ACCESS] = { do_access, "ACCESS" },
2545 [FUSE_CREATE] = { do_create, "CREATE" },
2546 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
2547 [FUSE_BMAP] = { do_bmap, "BMAP" },
2548 [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
2549 [FUSE_POLL] = { do_poll, "POLL" },
2550 [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
2551 [FUSE_DESTROY] = { do_destroy, "DESTROY" },
2552 [FUSE_NOTIFY_REPLY] = { (void *) 1, "NOTIFY_REPLY" },
2553 [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
2554 [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS"},
2555 [FUSE_RENAME2] = { do_rename2, "RENAME2" },
2556 [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
2557 [FUSE_LSEEK] = { do_lseek, "LSEEK" },
2558 [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
2559 };
2560
2561 #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
2562
2563 static const char *opname(enum fuse_opcode opcode)
2564 {
2565 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
2566 return "???";
2567 else
2568 return fuse_ll_ops[opcode].name;
2569 }
2570
2571 static int fuse_ll_copy_from_pipe(struct fuse_bufvec *dst,
2572 struct fuse_bufvec *src)
2573 {
2574 ssize_t res = fuse_buf_copy(dst, src, 0);
2575 if (res < 0) {
2576 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n", strerror(-res));
2577 return res;
2578 }
2579 if ((size_t)res < fuse_buf_size(dst)) {
2580 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
2581 return -1;
2582 }
2583 return 0;
2584 }
2585
2586 void fuse_session_process_buf(struct fuse_session *se,
2587 const struct fuse_buf *buf)
2588 {
2589 fuse_session_process_buf_int(se, buf, NULL);
2590 }
2591
2592 void fuse_session_process_buf_int(struct fuse_session *se,
2593 const struct fuse_buf *buf, struct fuse_chan *ch)
2594 {
2595 const size_t write_header_size = sizeof(struct fuse_in_header) +
2596 sizeof(struct fuse_write_in);
2597 struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
2598 struct fuse_bufvec tmpbuf = FUSE_BUFVEC_INIT(write_header_size);
2599 struct fuse_in_header *in;
2600 const void *inarg;
2601 struct fuse_req *req;
2602 void *mbuf = NULL;
2603 int err;
2604 int res;
2605
2606 if (buf->flags & FUSE_BUF_IS_FD) {
2607 if (buf->size < tmpbuf.buf[0].size)
2608 tmpbuf.buf[0].size = buf->size;
2609
2610 mbuf = malloc(tmpbuf.buf[0].size);
2611 if (mbuf == NULL) {
2612 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate header\n");
2613 goto clear_pipe;
2614 }
2615 tmpbuf.buf[0].mem = mbuf;
2616
2617 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
2618 if (res < 0)
2619 goto clear_pipe;
2620
2621 in = mbuf;
2622 } else {
2623 in = buf->mem;
2624 }
2625
2626 if (se->debug) {
2627 fuse_log(FUSE_LOG_DEBUG,
2628 "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, pid: %u\n",
2629 (unsigned long long) in->unique,
2630 opname((enum fuse_opcode) in->opcode), in->opcode,
2631 (unsigned long long) in->nodeid, buf->size, in->pid);
2632 }
2633
2634 req = fuse_ll_alloc_req(se);
2635 if (req == NULL) {
2636 struct fuse_out_header out = {
2637 .unique = in->unique,
2638 .error = -ENOMEM,
2639 };
2640 struct iovec iov = {
2641 .iov_base = &out,
2642 .iov_len = sizeof(struct fuse_out_header),
2643 };
2644
2645 fuse_send_msg(se, ch, &iov, 1);
2646 goto clear_pipe;
2647 }
2648
2649 req->unique = in->unique;
2650 req->ctx.uid = in->uid;
2651 req->ctx.gid = in->gid;
2652 req->ctx.pid = in->pid;
2653 req->ch = ch ? fuse_chan_get(ch) : NULL;
2654
2655 err = EIO;
2656 if (!se->got_init) {
2657 enum fuse_opcode expected;
2658
2659 expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
2660 if (in->opcode != expected)
2661 goto reply_err;
2662 } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
2663 goto reply_err;
2664
2665 err = EACCES;
2666 /* Implement -o allow_root */
2667 if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
2668 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
2669 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
2670 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
2671 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
2672 in->opcode != FUSE_NOTIFY_REPLY &&
2673 in->opcode != FUSE_READDIRPLUS)
2674 goto reply_err;
2675
2676 err = ENOSYS;
2677 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
2678 goto reply_err;
2679 if (in->opcode != FUSE_INTERRUPT) {
2680 struct fuse_req *intr;
2681 pthread_mutex_lock(&se->lock);
2682 intr = check_interrupt(se, req);
2683 list_add_req(req, &se->list);
2684 pthread_mutex_unlock(&se->lock);
2685 if (intr)
2686 fuse_reply_err(intr, EAGAIN);
2687 }
2688
2689 if ((buf->flags & FUSE_BUF_IS_FD) && write_header_size < buf->size &&
2690 (in->opcode != FUSE_WRITE || !se->op.write_buf) &&
2691 in->opcode != FUSE_NOTIFY_REPLY) {
2692 void *newmbuf;
2693
2694 err = ENOMEM;
2695 newmbuf = realloc(mbuf, buf->size);
2696 if (newmbuf == NULL)
2697 goto reply_err;
2698 mbuf = newmbuf;
2699
2700 tmpbuf = FUSE_BUFVEC_INIT(buf->size - write_header_size);
2701 tmpbuf.buf[0].mem = (char *)mbuf + write_header_size;
2702
2703 res = fuse_ll_copy_from_pipe(&tmpbuf, &bufv);
2704 err = -res;
2705 if (res < 0)
2706 goto reply_err;
2707
2708 in = mbuf;
2709 }
2710
2711 inarg = (void *) &in[1];
2712 if (in->opcode == FUSE_WRITE && se->op.write_buf)
2713 do_write_buf(req, in->nodeid, inarg, buf);
2714 else if (in->opcode == FUSE_NOTIFY_REPLY)
2715 do_notify_reply(req, in->nodeid, inarg, buf);
2716 else
2717 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
2718
2719 out_free:
2720 free(mbuf);
2721 return;
2722
2723 reply_err:
2724 fuse_reply_err(req, err);
2725 clear_pipe:
2726 if (buf->flags & FUSE_BUF_IS_FD)
2727 fuse_ll_clear_pipe(se);
2728 goto out_free;
2729 }
2730
2731 #define LL_OPTION(n,o,v) \
2732 { n, offsetof(struct fuse_session, o), v }
2733
2734 static const struct fuse_opt fuse_ll_opts[] = {
2735 LL_OPTION("debug", debug, 1),
2736 LL_OPTION("-d", debug, 1),
2737 LL_OPTION("--debug", debug, 1),
2738 LL_OPTION("allow_root", deny_others, 1),
2739 FUSE_OPT_END
2740 };
2741
2742 void fuse_lowlevel_version(void)
2743 {
2744 printf("using FUSE kernel interface version %i.%i\n",
2745 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
2746 fuse_mount_version();
2747 }
2748
2749 void fuse_lowlevel_help(void)
2750 {
2751 /* These are not all options, but the ones that are
2752 potentially of interest to an end-user */
2753 printf(
2754 " -o allow_other allow access by all users\n"
2755 " -o allow_root allow access by root\n"
2756 " -o auto_unmount auto unmount on process termination\n");
2757 }
2758
2759 void fuse_session_destroy(struct fuse_session *se)
2760 {
2761 struct fuse_ll_pipe *llp;
2762
2763 if (se->got_init && !se->got_destroy) {
2764 if (se->op.destroy)
2765 se->op.destroy(se->userdata);
2766 }
2767 llp = pthread_getspecific(se->pipe_key);
2768 if (llp != NULL)
2769 fuse_ll_pipe_free(llp);
2770 pthread_key_delete(se->pipe_key);
2771 pthread_mutex_destroy(&se->lock);
2772 free(se->cuse_data);
2773 if (se->fd != -1)
2774 close(se->fd);
2775 if (se->io != NULL)
2776 free(se->io);
2777 destroy_mount_opts(se->mo);
2778 free(se);
2779 }
2780
2781
2782 static void fuse_ll_pipe_destructor(void *data)
2783 {
2784 struct fuse_ll_pipe *llp = data;
2785 fuse_ll_pipe_free(llp);
2786 }
2787
2788 int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
2789 {
2790 return fuse_session_receive_buf_int(se, buf, NULL);
2791 }
2792
2793 int fuse_session_receive_buf_int(struct fuse_session *se, struct fuse_buf *buf,
2794 struct fuse_chan *ch)
2795 {
2796 int err;
2797 ssize_t res;
2798 #ifdef HAVE_SPLICE
2799 size_t bufsize = se->bufsize;
2800 struct fuse_ll_pipe *llp;
2801 struct fuse_buf tmpbuf;
2802
2803 if (se->conn.proto_minor < 14 || !(se->conn.want & FUSE_CAP_SPLICE_READ))
2804 goto fallback;
2805
2806 llp = fuse_ll_get_pipe(se);
2807 if (llp == NULL)
2808 goto fallback;
2809
2810 if (llp->size < bufsize) {
2811 if (llp->can_grow) {
2812 res = fcntl(llp->pipe[0], F_SETPIPE_SZ, bufsize);
2813 if (res == -1) {
2814 llp->can_grow = 0;
2815 res = grow_pipe_to_max(llp->pipe[0]);
2816 if (res > 0)
2817 llp->size = res;
2818 goto fallback;
2819 }
2820 llp->size = res;
2821 }
2822 if (llp->size < bufsize)
2823 goto fallback;
2824 }
2825
2826 if (se->io != NULL && se->io->splice_receive != NULL) {
2827 res = se->io->splice_receive(ch ? ch->fd : se->fd, NULL,
2828 llp->pipe[1], NULL, bufsize, 0,
2829 se->userdata);
2830 } else {
2831 res = splice(ch ? ch->fd : se->fd, NULL, llp->pipe[1], NULL,
2832 bufsize, 0);
2833 }
2834 err = errno;
2835
2836 if (fuse_session_exited(se))
2837 return 0;
2838
2839 if (res == -1) {
2840 if (err == ENODEV) {
2841 /* Filesystem was unmounted, or connection was aborted
2842 via /sys/fs/fuse/connections */
2843 fuse_session_exit(se);
2844 return 0;
2845 }
2846 if (err != EINTR && err != EAGAIN)
2847 perror("fuse: splice from device");
2848 return -err;
2849 }
2850
2851 if (res < sizeof(struct fuse_in_header)) {
2852 fuse_log(FUSE_LOG_ERR, "short splice from fuse device\n");
2853 return -EIO;
2854 }
2855
2856 tmpbuf = (struct fuse_buf) {
2857 .size = res,
2858 .flags = FUSE_BUF_IS_FD,
2859 .fd = llp->pipe[0],
2860 };
2861
2862 /*
2863 * Don't bother with zero copy for small requests.
2864 * fuse_loop_mt() needs to check for FORGET so this more than
2865 * just an optimization.
2866 */
2867 if (res < sizeof(struct fuse_in_header) +
2868 sizeof(struct fuse_write_in) + pagesize) {
2869 struct fuse_bufvec src = { .buf[0] = tmpbuf, .count = 1 };
2870 struct fuse_bufvec dst = { .count = 1 };
2871
2872 if (!buf->mem) {
2873 buf->mem = malloc(se->bufsize);
2874 if (!buf->mem) {
2875 fuse_log(FUSE_LOG_ERR,
2876 "fuse: failed to allocate read buffer\n");
2877 return -ENOMEM;
2878 }
2879 }
2880 buf->size = se->bufsize;
2881 buf->flags = 0;
2882 dst.buf[0] = *buf;
2883
2884 res = fuse_buf_copy(&dst, &src, 0);
2885 if (res < 0) {
2886 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: %s\n",
2887 strerror(-res));
2888 fuse_ll_clear_pipe(se);
2889 return res;
2890 }
2891 if (res < tmpbuf.size) {
2892 fuse_log(FUSE_LOG_ERR, "fuse: copy from pipe: short read\n");
2893 fuse_ll_clear_pipe(se);
2894 return -EIO;
2895 }
2896 assert(res == tmpbuf.size);
2897
2898 } else {
2899 /* Don't overwrite buf->mem, as that would cause a leak */
2900 buf->fd = tmpbuf.fd;
2901 buf->flags = tmpbuf.flags;
2902 }
2903 buf->size = tmpbuf.size;
2904
2905 return res;
2906
2907 fallback:
2908 #endif
2909 if (!buf->mem) {
2910 buf->mem = malloc(se->bufsize);
2911 if (!buf->mem) {
2912 fuse_log(FUSE_LOG_ERR,
2913 "fuse: failed to allocate read buffer\n");
2914 return -ENOMEM;
2915 }
2916 }
2917
2918 restart:
2919 if (se->io != NULL) {
2920 /* se->io->read is never NULL if se->io is not NULL as
2921 specified by fuse_session_custom_io()*/
2922 res = se->io->read(ch ? ch->fd : se->fd, buf->mem, se->bufsize,
2923 se->userdata);
2924 } else {
2925 res = read(ch ? ch->fd : se->fd, buf->mem, se->bufsize);
2926 }
2927 err = errno;
2928
2929 if (fuse_session_exited(se))
2930 return 0;
2931 if (res == -1) {
2932 /* ENOENT means the operation was interrupted, it's safe
2933 to restart */
2934 if (err == ENOENT)
2935 goto restart;
2936
2937 if (err == ENODEV) {
2938 /* Filesystem was unmounted, or connection was aborted
2939 via /sys/fs/fuse/connections */
2940 fuse_session_exit(se);
2941 return 0;
2942 }
2943 /* Errors occurring during normal operation: EINTR (read
2944 interrupted), EAGAIN (nonblocking I/O), ENODEV (filesystem
2945 umounted) */
2946 if (err != EINTR && err != EAGAIN)
2947 perror("fuse: reading device");
2948 return -err;
2949 }
2950 if ((size_t) res < sizeof(struct fuse_in_header)) {
2951 fuse_log(FUSE_LOG_ERR, "short read on fuse device\n");
2952 return -EIO;
2953 }
2954
2955 buf->size = res;
2956
2957 return res;
2958 }
2959
2960 struct fuse_session *fuse_session_new(struct fuse_args *args,
2961 const struct fuse_lowlevel_ops *op,
2962 size_t op_size, void *userdata)
2963 {
2964 int err;
2965 struct fuse_session *se;
2966 struct mount_opts *mo;
2967
2968 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
2969 fuse_log(FUSE_LOG_ERR, "fuse: warning: library too old, some operations may not work\n");
2970 op_size = sizeof(struct fuse_lowlevel_ops);
2971 }
2972
2973 if (args->argc == 0) {
2974 fuse_log(FUSE_LOG_ERR, "fuse: empty argv passed to fuse_session_new().\n");
2975 return NULL;
2976 }
2977
2978 se = (struct fuse_session *) calloc(1, sizeof(struct fuse_session));
2979 if (se == NULL) {
2980 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
2981 goto out1;
2982 }
2983 se->fd = -1;
2984 se->conn.max_write = UINT_MAX;
2985 se->conn.max_readahead = UINT_MAX;
2986
2987 /* Parse options */
2988 if(fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1)
2989 goto out2;
2990 if(se->deny_others) {
2991 /* Allowing access only by root is done by instructing
2992 * kernel to allow access by everyone, and then restricting
2993 * access to root and mountpoint owner in libfuse.
2994 */
2995 // We may be adding the option a second time, but
2996 // that doesn't hurt.
2997 if(fuse_opt_add_arg(args, "-oallow_other") == -1)
2998 goto out2;
2999 }
3000 mo = parse_mount_opts(args);
3001 if (mo == NULL)
3002 goto out3;
3003
3004 if(args->argc == 1 &&
3005 args->argv[0][0] == '-') {
3006 fuse_log(FUSE_LOG_ERR, "fuse: warning: argv[0] looks like an option, but "
3007 "will be ignored\n");
3008 } else if (args->argc != 1) {
3009 int i;
3010 fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
3011 for(i = 1; i < args->argc-1; i++)
3012 fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
3013 fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
3014 goto out4;
3015 }
3016
3017 if (se->debug)
3018 fuse_log(FUSE_LOG_DEBUG, "FUSE library version: %s\n", PACKAGE_VERSION);
3019
3020 se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() +
3021 FUSE_BUFFER_HEADER_SIZE;
3022
3023 list_init_req(&se->list);
3024 list_init_req(&se->interrupts);
3025 list_init_nreq(&se->notify_list);
3026 se->notify_ctr = 1;
3027 pthread_mutex_init(&se->lock, NULL);
3028
3029 err = pthread_key_create(&se->pipe_key, fuse_ll_pipe_destructor);
3030 if (err) {
3031 fuse_log(FUSE_LOG_ERR, "fuse: failed to create thread specific key: %s\n",
3032 strerror(err));
3033 goto out5;
3034 }
3035
3036 memcpy(&se->op, op, op_size);
3037 se->owner = getuid();
3038 se->userdata = userdata;
3039
3040 se->mo = mo;
3041 return se;
3042
3043 out5:
3044 pthread_mutex_destroy(&se->lock);
3045 out4:
3046 fuse_opt_free_args(args);
3047 out3:
3048 if (mo != NULL)
3049 destroy_mount_opts(mo);
3050 out2:
3051 free(se);
3052 out1:
3053 return NULL;
3054 }
3055
3056 int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io,
3057 int fd)
3058 {
3059 if (fd < 0) {
3060 fuse_log(FUSE_LOG_ERR, "Invalid file descriptor value %d passed to "
3061 "fuse_session_custom_io()\n", fd);
3062 return -EBADF;
3063 }
3064 if (io == NULL) {
3065 fuse_log(FUSE_LOG_ERR, "No custom IO passed to "
3066 "fuse_session_custom_io()\n");
3067 return -EINVAL;
3068 } else if (io->read == NULL || io->writev == NULL) {
3069 /* If the user provides their own file descriptor, we can't
3070 guarantee that the default behavior of the io operations made
3071 in libfuse will function properly. Therefore, we enforce the
3072 user to implement these io operations when using custom io. */
3073 fuse_log(FUSE_LOG_ERR, "io passed to fuse_session_custom_io() must "
3074 "implement both io->read() and io->writev\n");
3075 return -EINVAL;
3076 }
3077
3078 se->io = malloc(sizeof(struct fuse_custom_io));
3079 if (se->io == NULL) {
3080 fuse_log(FUSE_LOG_ERR, "Failed to allocate memory for custom io. "
3081 "Error: %s\n", strerror(errno));
3082 return -errno;
3083 }
3084
3085 se->fd = fd;
3086 *se->io = *io;
3087 return 0;
3088 }
3089
3090 int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
3091 {
3092 int fd;
3093
3094 /*
3095 * Make sure file descriptors 0, 1 and 2 are open, otherwise chaos
3096 * would ensue.
3097 */
3098 do {
3099 fd = open("/dev/null", O_RDWR);
3100 if (fd > 2)
3101 close(fd);
3102 } while (fd >= 0 && fd <= 2);
3103
3104 /*
3105 * To allow FUSE daemons to run without privileges, the caller may open
3106 * /dev/fuse before launching the file system and pass on the file
3107 * descriptor by specifying /dev/fd/N as the mount point. Note that the
3108 * parent process takes care of performing the mount in this case.
3109 */
3110 fd = fuse_mnt_parse_fuse_fd(mountpoint);
3111 if (fd != -1) {
3112 if (fcntl(fd, F_GETFD) == -1) {
3113 fuse_log(FUSE_LOG_ERR,
3114 "fuse: Invalid file descriptor /dev/fd/%u\n",
3115 fd);
3116 return -1;
3117 }
3118 se->fd = fd;
3119 return 0;
3120 }
3121
3122 /* Open channel */
3123 fd = fuse_kern_mount(mountpoint, se->mo);
3124 if (fd == -1)
3125 return -1;
3126 se->fd = fd;
3127
3128 /* Save mountpoint */
3129 se->mountpoint = strdup(mountpoint);
3130 if (se->mountpoint == NULL)
3131 goto error_out;
3132
3133 return 0;
3134
3135 error_out:
3136 fuse_kern_unmount(mountpoint, fd);
3137 return -1;
3138 }
3139
3140 int fuse_session_fd(struct fuse_session *se)
3141 {
3142 return se->fd;
3143 }
3144
3145 void fuse_session_unmount(struct fuse_session *se)
3146 {
3147 if (se->mountpoint != NULL) {
3148 fuse_kern_unmount(se->mountpoint, se->fd);
3149 se->fd = -1;
3150 free(se->mountpoint);
3151 se->mountpoint = NULL;
3152 }
3153 }
3154
3155 #ifdef linux
3156 int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
3157 {
3158 char *buf;
3159 size_t bufsize = 1024;
3160 char path[128];
3161 int ret;
3162 int fd;
3163 unsigned long pid = req->ctx.pid;
3164 char *s;
3165
3166 sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
3167
3168 retry:
3169 buf = malloc(bufsize);
3170 if (buf == NULL)
3171 return -ENOMEM;
3172
3173 ret = -EIO;
3174 fd = open(path, O_RDONLY);
3175 if (fd == -1)
3176 goto out_free;
3177
3178 ret = read(fd, buf, bufsize);
3179 close(fd);
3180 if (ret < 0) {
3181 ret = -EIO;
3182 goto out_free;
3183 }
3184
3185 if ((size_t)ret == bufsize) {
3186 free(buf);
3187 bufsize *= 4;
3188 goto retry;
3189 }
3190
3191 ret = -EIO;
3192 s = strstr(buf, "\nGroups:");
3193 if (s == NULL)
3194 goto out_free;
3195
3196 s += 8;
3197 ret = 0;
3198 while (1) {
3199 char *end;
3200 unsigned long val = strtoul(s, &end, 0);
3201 if (end == s)
3202 break;
3203
3204 s = end;
3205 if (ret < size)
3206 list[ret] = val;
3207 ret++;
3208 }
3209
3210 out_free:
3211 free(buf);
3212 return ret;
3213 }
3214 #else /* linux */
3215 /*
3216 * This is currently not implemented on other than Linux...
3217 */
3218 int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
3219 {
3220 (void) req; (void) size; (void) list;
3221 return -ENOSYS;
3222 }
3223 #endif
3224
3225 /* Prevent spurious data race warning - we don't care
3226 * about races for this flag */
3227 __attribute__((no_sanitize_thread))
3228 void fuse_session_exit(struct fuse_session *se)
3229 {
3230 se->exited = 1;
3231 }
3232
3233 __attribute__((no_sanitize_thread))
3234 void fuse_session_reset(struct fuse_session *se)
3235 {
3236 se->exited = 0;
3237 se->error = 0;
3238 }
3239
3240 __attribute__((no_sanitize_thread))
3241 int fuse_session_exited(struct fuse_session *se)
3242 {
3243 return se->exited;
3244 }
FUSE_CAP_IOCTL_DIR
#define FUSE_CAP_IOCTL_DIR
Definition: fuse_common.h:232
FUSE_CAP_DONT_MASK
#define FUSE_CAP_DONT_MASK
Definition: fuse_common.h:187
FUSE_CAP_HANDLE_KILLPRIV
#define FUSE_CAP_HANDLE_KILLPRIV
Definition: fuse_common.h:361
FUSE_CAP_AUTO_INVAL_DATA
#define FUSE_CAP_AUTO_INVAL_DATA
Definition: fuse_common.h:254
FUSE_CAP_SPLICE_READ
#define FUSE_CAP_SPLICE_READ
Definition: fuse_common.h:212
FUSE_CAP_PARALLEL_DIROPS
#define FUSE_CAP_PARALLEL_DIROPS
Definition: fuse_common.h:333
fuse_buf_size
size_t fuse_buf_size(const struct fuse_bufvec *bufv)
Definition: buffer.c:22
FUSE_CAP_WRITEBACK_CACHE
#define FUSE_CAP_WRITEBACK_CACHE
Definition: fuse_common.h:310
FUSE_CAP_EXPIRE_ONLY
#define FUSE_CAP_EXPIRE_ONLY
Definition: fuse_common.h:425
FUSE_CAP_ATOMIC_O_TRUNC
#define FUSE_CAP_ATOMIC_O_TRUNC
Definition: fuse_common.h:172
FUSE_CAP_ASYNC_READ
#define FUSE_CAP_ASYNC_READ
Definition: fuse_common.h:155
FUSE_CAP_SPLICE_WRITE
#define FUSE_CAP_SPLICE_WRITE
Definition: fuse_common.h:195
FUSE_CAP_CACHE_SYMLINKS
#define FUSE_CAP_CACHE_SYMLINKS
Definition: fuse_common.h:374
FUSE_CAP_POSIX_ACL
#define FUSE_CAP_POSIX_ACL
Definition: fuse_common.h:352
FUSE_BUF_IS_FD
@ FUSE_BUF_IS_FD
Definition: fuse_common.h:663
FUSE_CAP_EXPORT_SUPPORT
#define FUSE_CAP_EXPORT_SUPPORT
Definition: fuse_common.h:179
FUSE_CAP_POSIX_LOCKS
#define FUSE_CAP_POSIX_LOCKS
Definition: fuse_common.h:163
FUSE_CAP_EXPLICIT_INVAL_DATA
#define FUSE_CAP_EXPLICIT_INVAL_DATA
Definition: fuse_common.h:409
FUSE_CAP_READDIRPLUS_AUTO
#define FUSE_CAP_READDIRPLUS_AUTO
Definition: fuse_common.h:290
fuse_buf_copy
ssize_t fuse_buf_copy(struct fuse_bufvec *dst, struct fuse_bufvec *src, enum fuse_buf_copy_flags flags)
Definition: buffer.c:284
FUSE_CAP_NO_OPENDIR_SUPPORT
#define FUSE_CAP_NO_OPENDIR_SUPPORT
Definition: fuse_common.h:386
FUSE_CAP_ASYNC_DIO
#define FUSE_CAP_ASYNC_DIO
Definition: fuse_common.h:301
FUSE_CAP_NO_OPEN_SUPPORT
#define FUSE_CAP_NO_OPEN_SUPPORT
Definition: fuse_common.h:323
FUSE_CAP_READDIRPLUS
#define FUSE_CAP_READDIRPLUS
Definition: fuse_common.h:262
fuse_pollhandle_destroy
void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
Definition: fuse_lowlevel.c:1832
fuse_buf_copy_flags
fuse_buf_copy_flags
Definition: fuse_common.h:687
FUSE_BUF_SPLICE_NONBLOCK
@ FUSE_BUF_SPLICE_NONBLOCK
Definition: fuse_common.h:723
FUSE_BUF_FORCE_SPLICE
@ FUSE_BUF_FORCE_SPLICE
Definition: fuse_common.h:705
FUSE_BUF_NO_SPLICE
@ FUSE_BUF_NO_SPLICE
Definition: fuse_common.h:697
FUSE_BUF_SPLICE_MOVE
@ FUSE_BUF_SPLICE_MOVE
Definition: fuse_common.h:714
FUSE_CAP_SPLICE_MOVE
#define FUSE_CAP_SPLICE_MOVE
Definition: fuse_common.h:203
FUSE_CAP_FLOCK_LOCKS
#define FUSE_CAP_FLOCK_LOCKS
Definition: fuse_common.h:225
fuse_log
void fuse_log(enum fuse_log_level level, const char *fmt,...)
Definition: fuse_log.c:33
fuse_session_destroy
void fuse_session_destroy(struct fuse_session *se)
Definition: fuse_lowlevel.c:2759
fuse_expire_flags
fuse_expire_flags
Definition: fuse_lowlevel.h:146
fuse_reply_data
int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv, enum fuse_buf_copy_flags flags)
Definition: fuse_lowlevel.c:867
fuse_reply_lock
int fuse_reply_lock(fuse_req_t req, const struct flock *lock)
Definition: fuse_lowlevel.c:911
fuse_reply_open
int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *fi)
Definition: fuse_lowlevel.c:462
fuse_session_exit
void fuse_session_exit(struct fuse_session *se)
fuse_interrupt_func_t
void(* fuse_interrupt_func_t)(fuse_req_t req, void *data)
Definition: fuse_lowlevel.h:1872
fuse_reply_poll
int fuse_reply_poll(fuse_req_t req, unsigned revents)
Definition: fuse_lowlevel.c:1071
fuse_reply_err
int fuse_reply_err(fuse_req_t req, int err)
Definition: fuse_lowlevel.c:319
fuse_reply_buf
int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
Definition: fuse_lowlevel.c:481
fuse_req_t
struct fuse_req * fuse_req_t
Definition: fuse_lowlevel.h:49
fuse_add_direntry_plus
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)
Definition: fuse_lowlevel.c:364
fuse_reply_ioctl_iov
int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov, int count)
Definition: fuse_lowlevel.c:1047
fuse_lowlevel_notify_delete
int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent, fuse_ino_t child, const char *name, size_t namelen)
Definition: fuse_lowlevel.c:2324
fuse_session_process_buf
void fuse_session_process_buf(struct fuse_session *se, const struct fuse_buf *buf)
Definition: fuse_lowlevel.c:2586
fuse_session_exited
int fuse_session_exited(struct fuse_session *se)
fuse_session_fd
int fuse_session_fd(struct fuse_session *se)
Definition: fuse_lowlevel.c:3140
fuse_req_interrupted
int fuse_req_interrupted(fuse_req_t req)
Definition: fuse_lowlevel.c:2498
fuse_req_getgroups
int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
Definition: fuse_lowlevel.c:3218
fuse_lowlevel_notify_retrieve
int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie)
Definition: fuse_lowlevel.c:2430
fuse_reply_readlink
int fuse_reply_readlink(fuse_req_t req, const char *link)
Definition: fuse_lowlevel.c:457
fuse_reply_iov
int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
Definition: fuse_lowlevel.c:253
fuse_reply_bmap
int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
Definition: fuse_lowlevel.c:928
fuse_reply_entry
int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
Definition: fuse_lowlevel.c:410
fuse_session_unmount
void fuse_session_unmount(struct fuse_session *se)
Definition: fuse_lowlevel.c:3145
fuse_reply_none
void fuse_reply_none(fuse_req_t req)
Definition: fuse_lowlevel.c:324
fuse_reply_ioctl_retry
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)
Definition: fuse_lowlevel.c:956
fuse_lowlevel_help
void fuse_lowlevel_help(void)
Definition: fuse_lowlevel.c:2749
fuse_lowlevel_notify_inval_inode
int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino, off_t off, off_t len)
Definition: fuse_lowlevel.c:2268
fuse_session_new
struct fuse_session * fuse_session_new(struct fuse_args *args, const struct fuse_lowlevel_ops *op, size_t op_size, void *userdata)
Definition: fuse_lowlevel.c:2960
fuse_reply_statfs
int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
Definition: fuse_lowlevel.c:889
fuse_reply_write
int fuse_reply_write(fuse_req_t req, size_t count)
Definition: fuse_lowlevel.c:471
fuse_session_receive_buf
int fuse_session_receive_buf(struct fuse_session *se, struct fuse_buf *buf)
Definition: fuse_lowlevel.c:2788
fuse_session_mount
int fuse_session_mount(struct fuse_session *se, const char *mountpoint)
Definition: fuse_lowlevel.c:3090
fuse_req_userdata
void * fuse_req_userdata(fuse_req_t req)
Definition: fuse_lowlevel.c:2475
fuse_lowlevel_notify_expire_entry
int fuse_lowlevel_notify_expire_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen, enum fuse_expire_flags flags)
Definition: fuse_lowlevel.c:2290
fuse_lowlevel_notify_poll
int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
Definition: fuse_lowlevel.c:2251
fuse_lowlevel_notify_inval_entry
int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent, const char *name, size_t namelen)
Definition: fuse_lowlevel.c:2317
fuse_req_interrupt_func
void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func, void *data)
Definition: fuse_lowlevel.c:2485
fuse_session_reset
void fuse_session_reset(struct fuse_session *se)
fuse_session_custom_io
int fuse_session_custom_io(struct fuse_session *se, const struct fuse_custom_io *io, int fd)
Definition: fuse_lowlevel.c:3056
fuse_reply_create
int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e, const struct fuse_file_info *fi)
Definition: fuse_lowlevel.c:426
fuse_reply_lseek
int fuse_reply_lseek(fuse_req_t req, off_t off)
Definition: fuse_lowlevel.c:1081
fuse_lowlevel_version
void fuse_lowlevel_version(void)
Definition: fuse_lowlevel.c:2742
fuse_ino_t
uint64_t fuse_ino_t
Definition: fuse_lowlevel.h:46
fuse_add_direntry
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize, const char *name, const struct stat *stbuf, off_t off)
Definition: fuse_lowlevel.c:274
fuse_req_ctx
const struct fuse_ctx * fuse_req_ctx(fuse_req_t req)
Definition: fuse_lowlevel.c:2480
fuse_reply_attr
int fuse_reply_attr(fuse_req_t req, const struct stat *attr, double attr_timeout)
Definition: fuse_lowlevel.c:442
fuse_reply_ioctl
int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
Definition: fuse_lowlevel.c:1026
fuse_lowlevel_notify_store
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)
Definition: fuse_lowlevel.c:2350
fuse_reply_xattr
int fuse_reply_xattr(fuse_req_t req, size_t count)
Definition: fuse_lowlevel.c:901
fuse_opt_add_arg
int fuse_opt_add_arg(struct fuse_args *args, const char *arg)
Definition: fuse_opt.c:55
fuse_opt_free_args
void fuse_opt_free_args(struct fuse_args *args)
Definition: fuse_opt.c:34
fuse_opt_parse
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
FUSE_OPT_END
#define FUSE_OPT_END
Definition: fuse_opt.h:104
fuse_args
Definition: fuse_opt.h:109
fuse_args::argc
int argc
Definition: fuse_opt.h:111
fuse_args::argv
char ** argv
Definition: fuse_opt.h:114
fuse_buf
Definition: fuse_common.h:732
fuse_buf::flags
enum fuse_buf_flags flags
Definition: fuse_common.h:741
fuse_buf::fd
int fd
Definition: fuse_common.h:755
fuse_buf::mem
void * mem
Definition: fuse_common.h:748
fuse_buf::size
size_t size
Definition: fuse_common.h:736
fuse_bufvec
Definition: fuse_common.h:773
fuse_bufvec::off
size_t off
Definition: fuse_common.h:787
fuse_bufvec::buf
struct fuse_buf buf[1]
Definition: fuse_common.h:792
fuse_bufvec::idx
size_t idx
Definition: fuse_common.h:782
fuse_bufvec::count
size_t count
Definition: fuse_common.h:777
fuse_ctx
Definition: fuse_lowlevel.h:111
fuse_entry_param
Definition: fuse_lowlevel.h:59
fuse_entry_param::entry_timeout
double entry_timeout
Definition: fuse_lowlevel.h:100
fuse_entry_param::ino
fuse_ino_t ino
Definition: fuse_lowlevel.h:67
fuse_entry_param::generation
uint64_t generation
Definition: fuse_lowlevel.h:79
fuse_entry_param::attr_timeout
double attr_timeout
Definition: fuse_lowlevel.h:94
fuse_entry_param::attr
struct stat attr
Definition: fuse_lowlevel.h:88
fuse_file_info
Definition: fuse_common.h:44
fuse_file_info::direct_io
unsigned int direct_io
Definition: fuse_common.h:57
fuse_file_info::keep_cache
unsigned int keep_cache
Definition: fuse_common.h:64
fuse_file_info::nonseekable
unsigned int nonseekable
Definition: fuse_common.h:73
fuse_file_info::lock_owner
uint64_t lock_owner
Definition: fuse_common.h:100
fuse_file_info::fh
uint64_t fh
Definition: fuse_common.h:97
fuse_file_info::poll_events
uint32_t poll_events
Definition: fuse_common.h:104
fuse_file_info::noflush
unsigned int noflush
Definition: fuse_common.h:88
fuse_file_info::writepage
unsigned int writepage
Definition: fuse_common.h:54
fuse_file_info::flush
unsigned int flush
Definition: fuse_common.h:69
fuse_file_info::flags
int flags
Definition: fuse_common.h:46
fuse_file_info::cache_readdir
unsigned int cache_readdir
Definition: fuse_common.h:84
fuse_lowlevel_ops
Definition: fuse_lowlevel.h:192
fuse_opt
Definition: fuse_opt.h:77