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