]> git.proxmox.com Git - mirror_qemu.git/blame - tools/virtiofsd/fuse_lowlevel.c
virtiofsd: set maximum RLIMIT_NOFILE limit
[mirror_qemu.git] / tools / virtiofsd / fuse_lowlevel.c
CommitLineData
2de121f0 1/*
7387863d
DDAG
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 */
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;
f779bc52 1145 fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV);
2de121f0 1146
72c42e2d
DDAG
1147 fi.lock_owner = arg->lock_owner;
1148 fi.flags = arg->flags;
2de121f0 1149
7387863d
DDAG
1150 if (req->se->op.write) {
1151 req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi);
1152 } else {
1153 fuse_reply_err(req, ENOSYS);
1154 }
2de121f0
DDAG
1155}
1156
0ba8c3c6
SH
1157static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid,
1158 struct fuse_mbuf_iter *iter, struct fuse_bufvec *ibufv)
7387863d
DDAG
1159{
1160 struct fuse_session *se = req->se;
469f9d2f
DDAG
1161 struct fuse_bufvec *pbufv = ibufv;
1162 struct fuse_bufvec tmpbufv = {
1163 .buf[0] = ibufv->buf[0],
7387863d
DDAG
1164 .count = 1,
1165 };
0ba8c3c6
SH
1166 struct fuse_write_in *arg;
1167 size_t arg_size = sizeof(*arg);
7387863d
DDAG
1168 struct fuse_file_info fi;
1169
1170 memset(&fi, 0, sizeof(fi));
0ba8c3c6
SH
1171
1172 arg = fuse_mbuf_iter_advance(iter, arg_size);
1173 if (!arg) {
1174 fuse_reply_err(req, EINVAL);
1175 return;
1176 }
1177
1178 fi.lock_owner = arg->lock_owner;
1179 fi.flags = arg->flags;
7387863d 1180 fi.fh = arg->fh;
f779bc52
VG
1181 fi.writepage = !!(arg->write_flags & FUSE_WRITE_CACHE);
1182 fi.kill_priv = !!(arg->write_flags & FUSE_WRITE_KILL_PRIV);
7387863d 1183
469f9d2f 1184 if (ibufv->count == 1) {
0ba8c3c6
SH
1185 assert(!(tmpbufv.buf[0].flags & FUSE_BUF_IS_FD));
1186 tmpbufv.buf[0].mem = ((char *)arg) + arg_size;
1187 tmpbufv.buf[0].size -= sizeof(struct fuse_in_header) + arg_size;
469f9d2f
DDAG
1188 pbufv = &tmpbufv;
1189 } else {
1190 /*
1191 * Input bufv contains the headers in the first element
1192 * and the data in the rest, we need to skip that first element
1193 */
1194 ibufv->buf[0].size = 0;
7387863d 1195 }
7387863d 1196
0ba8c3c6
SH
1197 if (fuse_buf_size(pbufv) != arg->size) {
1198 fuse_log(FUSE_LOG_ERR,
1199 "fuse: do_write_buf: buffer size doesn't match arg->size\n");
1200 fuse_reply_err(req, EIO);
1201 return;
1202 }
1203
469f9d2f 1204 se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi);
2de121f0
DDAG
1205}
1206
70995754
SH
1207static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
1208 struct fuse_mbuf_iter *iter)
2de121f0 1209{
70995754 1210 struct fuse_flush_in *arg;
7387863d 1211 struct fuse_file_info fi;
2de121f0 1212
70995754
SH
1213 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1214 if (!arg) {
1215 fuse_reply_err(req, EINVAL);
1216 return;
1217 }
1218
7387863d
DDAG
1219 memset(&fi, 0, sizeof(fi));
1220 fi.fh = arg->fh;
1221 fi.flush = 1;
72c42e2d 1222 fi.lock_owner = arg->lock_owner;
2de121f0 1223
7387863d
DDAG
1224 if (req->se->op.flush) {
1225 req->se->op.flush(req, nodeid, &fi);
1226 } else {
1227 fuse_reply_err(req, ENOSYS);
1228 }
2de121f0
DDAG
1229}
1230
70995754
SH
1231static void do_release(fuse_req_t req, fuse_ino_t nodeid,
1232 struct fuse_mbuf_iter *iter)
2de121f0 1233{
70995754 1234 struct fuse_release_in *arg;
7387863d 1235 struct fuse_file_info fi;
2de121f0 1236
70995754
SH
1237 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1238 if (!arg) {
1239 fuse_reply_err(req, EINVAL);
1240 return;
1241 }
1242
7387863d
DDAG
1243 memset(&fi, 0, sizeof(fi));
1244 fi.flags = arg->flags;
1245 fi.fh = arg->fh;
72c42e2d
DDAG
1246 fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
1247 fi.lock_owner = arg->lock_owner;
70995754 1248
7387863d
DDAG
1249 if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
1250 fi.flock_release = 1;
7387863d 1251 }
2de121f0 1252
7387863d
DDAG
1253 if (req->se->op.release) {
1254 req->se->op.release(req, nodeid, &fi);
1255 } else {
1256 fuse_reply_err(req, 0);
1257 }
2de121f0
DDAG
1258}
1259
70995754
SH
1260static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
1261 struct fuse_mbuf_iter *iter)
2de121f0 1262{
70995754 1263 struct fuse_fsync_in *arg;
7387863d 1264 struct fuse_file_info fi;
70995754
SH
1265 int datasync;
1266
1267 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1268 if (!arg) {
1269 fuse_reply_err(req, EINVAL);
1270 return;
1271 }
1272 datasync = arg->fsync_flags & 1;
2de121f0 1273
7387863d
DDAG
1274 memset(&fi, 0, sizeof(fi));
1275 fi.fh = arg->fh;
2de121f0 1276
7387863d 1277 if (req->se->op.fsync) {
1b209805
VG
1278 if (fi.fh == (uint64_t)-1) {
1279 req->se->op.fsync(req, nodeid, datasync, NULL);
1280 } else {
1281 req->se->op.fsync(req, nodeid, datasync, &fi);
1282 }
7387863d
DDAG
1283 } else {
1284 fuse_reply_err(req, ENOSYS);
1285 }
2de121f0
DDAG
1286}
1287
70995754
SH
1288static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
1289 struct fuse_mbuf_iter *iter)
2de121f0 1290{
70995754 1291 struct fuse_open_in *arg;
7387863d 1292 struct fuse_file_info fi;
2de121f0 1293
70995754
SH
1294 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1295 if (!arg) {
1296 fuse_reply_err(req, EINVAL);
1297 return;
1298 }
1299
7387863d
DDAG
1300 memset(&fi, 0, sizeof(fi));
1301 fi.flags = arg->flags;
2de121f0 1302
7387863d
DDAG
1303 if (req->se->op.opendir) {
1304 req->se->op.opendir(req, nodeid, &fi);
1305 } else {
1306 fuse_reply_open(req, &fi);
1307 }
2de121f0
DDAG
1308}
1309
70995754
SH
1310static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
1311 struct fuse_mbuf_iter *iter)
2de121f0 1312{
70995754 1313 struct fuse_read_in *arg;
7387863d 1314 struct fuse_file_info fi;
2de121f0 1315
70995754
SH
1316 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1317 if (!arg) {
1318 fuse_reply_err(req, EINVAL);
1319 return;
1320 }
1321
7387863d
DDAG
1322 memset(&fi, 0, sizeof(fi));
1323 fi.fh = arg->fh;
2de121f0 1324
7387863d
DDAG
1325 if (req->se->op.readdir) {
1326 req->se->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
1327 } else {
1328 fuse_reply_err(req, ENOSYS);
1329 }
2de121f0
DDAG
1330}
1331
70995754
SH
1332static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid,
1333 struct fuse_mbuf_iter *iter)
2de121f0 1334{
70995754 1335 struct fuse_read_in *arg;
7387863d 1336 struct fuse_file_info fi;
2de121f0 1337
70995754
SH
1338 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1339 if (!arg) {
1340 fuse_reply_err(req, EINVAL);
1341 return;
1342 }
1343
7387863d
DDAG
1344 memset(&fi, 0, sizeof(fi));
1345 fi.fh = arg->fh;
2de121f0 1346
7387863d
DDAG
1347 if (req->se->op.readdirplus) {
1348 req->se->op.readdirplus(req, nodeid, arg->size, arg->offset, &fi);
1349 } else {
1350 fuse_reply_err(req, ENOSYS);
1351 }
2de121f0
DDAG
1352}
1353
70995754
SH
1354static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
1355 struct fuse_mbuf_iter *iter)
2de121f0 1356{
70995754 1357 struct fuse_release_in *arg;
7387863d 1358 struct fuse_file_info fi;
2de121f0 1359
70995754
SH
1360 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1361 if (!arg) {
1362 fuse_reply_err(req, EINVAL);
1363 return;
1364 }
1365
7387863d
DDAG
1366 memset(&fi, 0, sizeof(fi));
1367 fi.flags = arg->flags;
1368 fi.fh = arg->fh;
2de121f0 1369
7387863d
DDAG
1370 if (req->se->op.releasedir) {
1371 req->se->op.releasedir(req, nodeid, &fi);
1372 } else {
1373 fuse_reply_err(req, 0);
1374 }
2de121f0
DDAG
1375}
1376
70995754
SH
1377static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
1378 struct fuse_mbuf_iter *iter)
2de121f0 1379{
70995754 1380 struct fuse_fsync_in *arg;
7387863d 1381 struct fuse_file_info fi;
70995754
SH
1382 int datasync;
1383
1384 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1385 if (!arg) {
1386 fuse_reply_err(req, EINVAL);
1387 return;
1388 }
1389 datasync = arg->fsync_flags & 1;
2de121f0 1390
7387863d
DDAG
1391 memset(&fi, 0, sizeof(fi));
1392 fi.fh = arg->fh;
2de121f0 1393
7387863d
DDAG
1394 if (req->se->op.fsyncdir) {
1395 req->se->op.fsyncdir(req, nodeid, datasync, &fi);
1396 } else {
1397 fuse_reply_err(req, ENOSYS);
1398 }
2de121f0
DDAG
1399}
1400
70995754
SH
1401static void do_statfs(fuse_req_t req, fuse_ino_t nodeid,
1402 struct fuse_mbuf_iter *iter)
2de121f0 1403{
7387863d 1404 (void)nodeid;
70995754 1405 (void)iter;
2de121f0 1406
7387863d
DDAG
1407 if (req->se->op.statfs) {
1408 req->se->op.statfs(req, nodeid);
1409 } else {
1410 struct statvfs buf = {
1411 .f_namemax = 255,
1412 .f_bsize = 512,
1413 };
1414 fuse_reply_statfs(req, &buf);
1415 }
2de121f0
DDAG
1416}
1417
70995754
SH
1418static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
1419 struct fuse_mbuf_iter *iter)
2de121f0 1420{
70995754
SH
1421 struct fuse_setxattr_in *arg;
1422 const char *name;
1423 const char *value;
1424
1425 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1426 name = fuse_mbuf_iter_advance_str(iter);
1427 if (!arg || !name) {
1428 fuse_reply_err(req, EINVAL);
1429 return;
1430 }
1431
1432 value = fuse_mbuf_iter_advance(iter, arg->size);
1433 if (!value) {
1434 fuse_reply_err(req, EINVAL);
1435 return;
1436 }
2de121f0 1437
7387863d
DDAG
1438 if (req->se->op.setxattr) {
1439 req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
1440 } else {
1441 fuse_reply_err(req, ENOSYS);
1442 }
2de121f0
DDAG
1443}
1444
70995754
SH
1445static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
1446 struct fuse_mbuf_iter *iter)
2de121f0 1447{
70995754
SH
1448 struct fuse_getxattr_in *arg;
1449 const char *name;
1450
1451 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1452 name = fuse_mbuf_iter_advance_str(iter);
1453 if (!arg || !name) {
1454 fuse_reply_err(req, EINVAL);
1455 return;
1456 }
2de121f0 1457
7387863d 1458 if (req->se->op.getxattr) {
70995754 1459 req->se->op.getxattr(req, nodeid, name, arg->size);
7387863d
DDAG
1460 } else {
1461 fuse_reply_err(req, ENOSYS);
1462 }
2de121f0
DDAG
1463}
1464
70995754
SH
1465static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
1466 struct fuse_mbuf_iter *iter)
2de121f0 1467{
70995754
SH
1468 struct fuse_getxattr_in *arg;
1469
1470 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1471 if (!arg) {
1472 fuse_reply_err(req, EINVAL);
1473 return;
1474 }
2de121f0 1475
7387863d
DDAG
1476 if (req->se->op.listxattr) {
1477 req->se->op.listxattr(req, nodeid, arg->size);
1478 } else {
1479 fuse_reply_err(req, ENOSYS);
1480 }
2de121f0
DDAG
1481}
1482
70995754
SH
1483static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid,
1484 struct fuse_mbuf_iter *iter)
2de121f0 1485{
70995754
SH
1486 const char *name = fuse_mbuf_iter_advance_str(iter);
1487
1488 if (!name) {
1489 fuse_reply_err(req, EINVAL);
1490 return;
1491 }
2de121f0 1492
7387863d
DDAG
1493 if (req->se->op.removexattr) {
1494 req->se->op.removexattr(req, nodeid, name);
1495 } else {
1496 fuse_reply_err(req, ENOSYS);
1497 }
2de121f0
DDAG
1498}
1499
1500static void convert_fuse_file_lock(struct fuse_file_lock *fl,
7387863d 1501 struct flock *flock)
2de121f0 1502{
7387863d
DDAG
1503 memset(flock, 0, sizeof(struct flock));
1504 flock->l_type = fl->type;
1505 flock->l_whence = SEEK_SET;
1506 flock->l_start = fl->start;
1507 if (fl->end == OFFSET_MAX) {
1508 flock->l_len = 0;
1509 } else {
1510 flock->l_len = fl->end - fl->start + 1;
1511 }
1512 flock->l_pid = fl->pid;
2de121f0
DDAG
1513}
1514
70995754
SH
1515static void do_getlk(fuse_req_t req, fuse_ino_t nodeid,
1516 struct fuse_mbuf_iter *iter)
2de121f0 1517{
70995754 1518 struct fuse_lk_in *arg;
7387863d
DDAG
1519 struct fuse_file_info fi;
1520 struct flock flock;
2de121f0 1521
70995754
SH
1522 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1523 if (!arg) {
1524 fuse_reply_err(req, EINVAL);
1525 return;
1526 }
1527
7387863d
DDAG
1528 memset(&fi, 0, sizeof(fi));
1529 fi.fh = arg->fh;
1530 fi.lock_owner = arg->owner;
2de121f0 1531
7387863d
DDAG
1532 convert_fuse_file_lock(&arg->lk, &flock);
1533 if (req->se->op.getlk) {
1534 req->se->op.getlk(req, nodeid, &fi, &flock);
1535 } else {
1536 fuse_reply_err(req, ENOSYS);
1537 }
2de121f0
DDAG
1538}
1539
1540static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
70995754 1541 struct fuse_mbuf_iter *iter, int sleep)
7387863d 1542{
70995754 1543 struct fuse_lk_in *arg;
7387863d
DDAG
1544 struct fuse_file_info fi;
1545 struct flock flock;
1546
70995754
SH
1547 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1548 if (!arg) {
1549 fuse_reply_err(req, EINVAL);
1550 return;
1551 }
1552
7387863d
DDAG
1553 memset(&fi, 0, sizeof(fi));
1554 fi.fh = arg->fh;
1555 fi.lock_owner = arg->owner;
1556
1557 if (arg->lk_flags & FUSE_LK_FLOCK) {
1558 int op = 0;
1559
1560 switch (arg->lk.type) {
1561 case F_RDLCK:
1562 op = LOCK_SH;
1563 break;
1564 case F_WRLCK:
1565 op = LOCK_EX;
1566 break;
1567 case F_UNLCK:
1568 op = LOCK_UN;
1569 break;
1570 }
1571 if (!sleep) {
1572 op |= LOCK_NB;
1573 }
1574
1575 if (req->se->op.flock) {
1576 req->se->op.flock(req, nodeid, &fi, op);
1577 } else {
1578 fuse_reply_err(req, ENOSYS);
1579 }
1580 } else {
1581 convert_fuse_file_lock(&arg->lk, &flock);
1582 if (req->se->op.setlk) {
1583 req->se->op.setlk(req, nodeid, &fi, &flock, sleep);
1584 } else {
1585 fuse_reply_err(req, ENOSYS);
1586 }
1587 }
2de121f0
DDAG
1588}
1589
70995754
SH
1590static void do_setlk(fuse_req_t req, fuse_ino_t nodeid,
1591 struct fuse_mbuf_iter *iter)
2de121f0 1592{
70995754 1593 do_setlk_common(req, nodeid, iter, 0);
2de121f0
DDAG
1594}
1595
70995754
SH
1596static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid,
1597 struct fuse_mbuf_iter *iter)
2de121f0 1598{
70995754 1599 do_setlk_common(req, nodeid, iter, 1);
2de121f0
DDAG
1600}
1601
1602static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
1603{
7387863d
DDAG
1604 struct fuse_req *curr;
1605
1606 for (curr = se->list.next; curr != &se->list; curr = curr->next) {
1607 if (curr->unique == req->u.i.unique) {
1608 fuse_interrupt_func_t func;
1609 void *data;
1610
1611 curr->ctr++;
1612 pthread_mutex_unlock(&se->lock);
1613
1614 /* Ugh, ugly locking */
1615 pthread_mutex_lock(&curr->lock);
1616 pthread_mutex_lock(&se->lock);
1617 curr->interrupted = 1;
1618 func = curr->u.ni.func;
1619 data = curr->u.ni.data;
1620 pthread_mutex_unlock(&se->lock);
1621 if (func) {
1622 func(curr, data);
1623 }
1624 pthread_mutex_unlock(&curr->lock);
1625
1626 pthread_mutex_lock(&se->lock);
1627 curr->ctr--;
1628 if (!curr->ctr) {
1629 destroy_req(curr);
1630 }
1631
1632 return 1;
1633 }
1634 }
1635 for (curr = se->interrupts.next; curr != &se->interrupts;
1636 curr = curr->next) {
1637 if (curr->u.i.unique == req->u.i.unique) {
1638 return 1;
1639 }
1640 }
1641 return 0;
2de121f0
DDAG
1642}
1643
70995754
SH
1644static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid,
1645 struct fuse_mbuf_iter *iter)
2de121f0 1646{
70995754 1647 struct fuse_interrupt_in *arg;
7387863d 1648 struct fuse_session *se = req->se;
2de121f0 1649
7387863d 1650 (void)nodeid;
70995754
SH
1651
1652 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1653 if (!arg) {
1654 fuse_reply_err(req, EINVAL);
1655 return;
1656 }
1657
7387863d
DDAG
1658 if (se->debug) {
1659 fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
1660 (unsigned long long)arg->unique);
1661 }
2de121f0 1662
7387863d 1663 req->u.i.unique = arg->unique;
2de121f0 1664
7387863d
DDAG
1665 pthread_mutex_lock(&se->lock);
1666 if (find_interrupted(se, req)) {
1667 destroy_req(req);
1668 } else {
1669 list_add_req(req, &se->interrupts);
1670 }
1671 pthread_mutex_unlock(&se->lock);
2de121f0
DDAG
1672}
1673
1674static struct fuse_req *check_interrupt(struct fuse_session *se,
7387863d
DDAG
1675 struct fuse_req *req)
1676{
1677 struct fuse_req *curr;
1678
1679 for (curr = se->interrupts.next; curr != &se->interrupts;
1680 curr = curr->next) {
1681 if (curr->u.i.unique == req->unique) {
1682 req->interrupted = 1;
1683 list_del_req(curr);
1684 free(curr);
1685 return NULL;
1686 }
1687 }
1688 curr = se->interrupts.next;
1689 if (curr != &se->interrupts) {
1690 list_del_req(curr);
1691 list_init_req(curr);
1692 return curr;
1693 } else {
1694 return NULL;
1695 }
2de121f0
DDAG
1696}
1697
70995754
SH
1698static void do_bmap(fuse_req_t req, fuse_ino_t nodeid,
1699 struct fuse_mbuf_iter *iter)
2de121f0 1700{
70995754
SH
1701 struct fuse_bmap_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1702
1703 if (!arg) {
1704 fuse_reply_err(req, EINVAL);
1705 return;
1706 }
2de121f0 1707
7387863d
DDAG
1708 if (req->se->op.bmap) {
1709 req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
1710 } else {
1711 fuse_reply_err(req, ENOSYS);
1712 }
2de121f0
DDAG
1713}
1714
70995754
SH
1715static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid,
1716 struct fuse_mbuf_iter *iter)
2de121f0 1717{
70995754
SH
1718 struct fuse_ioctl_in *arg;
1719 unsigned int flags;
1720 void *in_buf = NULL;
7387863d 1721 struct fuse_file_info fi;
2de121f0 1722
70995754
SH
1723 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1724 if (!arg) {
1725 fuse_reply_err(req, EINVAL);
1726 return;
1727 }
1728
1729 flags = arg->flags;
7387863d
DDAG
1730 if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
1731 fuse_reply_err(req, ENOTTY);
1732 return;
1733 }
2de121f0 1734
70995754
SH
1735 if (arg->in_size) {
1736 in_buf = fuse_mbuf_iter_advance(iter, arg->in_size);
1737 if (!in_buf) {
1738 fuse_reply_err(req, EINVAL);
1739 return;
1740 }
1741 }
1742
7387863d
DDAG
1743 memset(&fi, 0, sizeof(fi));
1744 fi.fh = arg->fh;
2de121f0 1745
72c42e2d 1746 if (sizeof(void *) == 4 && !(flags & FUSE_IOCTL_32BIT)) {
7387863d
DDAG
1747 req->ioctl_64bit = 1;
1748 }
2de121f0 1749
7387863d
DDAG
1750 if (req->se->op.ioctl) {
1751 req->se->op.ioctl(req, nodeid, arg->cmd, (void *)(uintptr_t)arg->arg,
1752 &fi, flags, in_buf, arg->in_size, arg->out_size);
1753 } else {
1754 fuse_reply_err(req, ENOSYS);
1755 }
2de121f0
DDAG
1756}
1757
1758void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
1759{
7387863d 1760 free(ph);
2de121f0
DDAG
1761}
1762
70995754
SH
1763static void do_poll(fuse_req_t req, fuse_ino_t nodeid,
1764 struct fuse_mbuf_iter *iter)
2de121f0 1765{
70995754 1766 struct fuse_poll_in *arg;
7387863d 1767 struct fuse_file_info fi;
2de121f0 1768
70995754
SH
1769 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1770 if (!arg) {
1771 fuse_reply_err(req, EINVAL);
1772 return;
1773 }
1774
7387863d
DDAG
1775 memset(&fi, 0, sizeof(fi));
1776 fi.fh = arg->fh;
1777 fi.poll_events = arg->events;
2de121f0 1778
7387863d
DDAG
1779 if (req->se->op.poll) {
1780 struct fuse_pollhandle *ph = NULL;
2de121f0 1781
7387863d
DDAG
1782 if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
1783 ph = malloc(sizeof(struct fuse_pollhandle));
1784 if (ph == NULL) {
1785 fuse_reply_err(req, ENOMEM);
1786 return;
1787 }
1788 ph->kh = arg->kh;
1789 ph->se = req->se;
1790 }
2de121f0 1791
7387863d
DDAG
1792 req->se->op.poll(req, nodeid, &fi, ph);
1793 } else {
1794 fuse_reply_err(req, ENOSYS);
1795 }
2de121f0
DDAG
1796}
1797
70995754
SH
1798static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid,
1799 struct fuse_mbuf_iter *iter)
2de121f0 1800{
70995754 1801 struct fuse_fallocate_in *arg;
7387863d 1802 struct fuse_file_info fi;
2de121f0 1803
70995754
SH
1804 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1805 if (!arg) {
1806 fuse_reply_err(req, EINVAL);
1807 return;
1808 }
1809
7387863d
DDAG
1810 memset(&fi, 0, sizeof(fi));
1811 fi.fh = arg->fh;
2de121f0 1812
7387863d
DDAG
1813 if (req->se->op.fallocate) {
1814 req->se->op.fallocate(req, nodeid, arg->mode, arg->offset, arg->length,
1815 &fi);
1816 } else {
1817 fuse_reply_err(req, ENOSYS);
1818 }
2de121f0
DDAG
1819}
1820
7387863d 1821static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
70995754 1822 struct fuse_mbuf_iter *iter)
2de121f0 1823{
70995754 1824 struct fuse_copy_file_range_in *arg;
7387863d 1825 struct fuse_file_info fi_in, fi_out;
2de121f0 1826
70995754
SH
1827 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1828 if (!arg) {
1829 fuse_reply_err(req, EINVAL);
1830 return;
1831 }
1832
7387863d
DDAG
1833 memset(&fi_in, 0, sizeof(fi_in));
1834 fi_in.fh = arg->fh_in;
2de121f0 1835
7387863d
DDAG
1836 memset(&fi_out, 0, sizeof(fi_out));
1837 fi_out.fh = arg->fh_out;
2de121f0
DDAG
1838
1839
7387863d
DDAG
1840 if (req->se->op.copy_file_range) {
1841 req->se->op.copy_file_range(req, nodeid_in, arg->off_in, &fi_in,
1842 arg->nodeid_out, arg->off_out, &fi_out,
1843 arg->len, arg->flags);
1844 } else {
1845 fuse_reply_err(req, ENOSYS);
1846 }
2de121f0
DDAG
1847}
1848
70995754
SH
1849static void do_lseek(fuse_req_t req, fuse_ino_t nodeid,
1850 struct fuse_mbuf_iter *iter)
2de121f0 1851{
70995754 1852 struct fuse_lseek_in *arg;
7387863d 1853 struct fuse_file_info fi;
2de121f0 1854
70995754
SH
1855 arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1856 if (!arg) {
1857 fuse_reply_err(req, EINVAL);
1858 return;
1859 }
7387863d
DDAG
1860 memset(&fi, 0, sizeof(fi));
1861 fi.fh = arg->fh;
2de121f0 1862
7387863d
DDAG
1863 if (req->se->op.lseek) {
1864 req->se->op.lseek(req, nodeid, arg->offset, arg->whence, &fi);
1865 } else {
1866 fuse_reply_err(req, ENOSYS);
1867 }
2de121f0
DDAG
1868}
1869
70995754
SH
1870static void do_init(fuse_req_t req, fuse_ino_t nodeid,
1871 struct fuse_mbuf_iter *iter)
2de121f0 1872{
70995754
SH
1873 size_t compat_size = offsetof(struct fuse_init_in, max_readahead);
1874 struct fuse_init_in *arg;
7387863d
DDAG
1875 struct fuse_init_out outarg;
1876 struct fuse_session *se = req->se;
1877 size_t bufsize = se->bufsize;
1878 size_t outargsize = sizeof(outarg);
1879
1880 (void)nodeid;
70995754
SH
1881
1882 /* First consume the old fields... */
1883 arg = fuse_mbuf_iter_advance(iter, compat_size);
1884 if (!arg) {
1885 fuse_reply_err(req, EINVAL);
1886 return;
1887 }
1888
1889 /* ...and now consume the new fields. */
1890 if (arg->major == 7 && arg->minor >= 6) {
1891 if (!fuse_mbuf_iter_advance(iter, sizeof(*arg) - compat_size)) {
1892 fuse_reply_err(req, EINVAL);
1893 return;
1894 }
1895 }
1896
7387863d
DDAG
1897 if (se->debug) {
1898 fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
1899 if (arg->major == 7 && arg->minor >= 6) {
1900 fuse_log(FUSE_LOG_DEBUG, "flags=0x%08x\n", arg->flags);
1901 fuse_log(FUSE_LOG_DEBUG, "max_readahead=0x%08x\n",
1902 arg->max_readahead);
1903 }
1904 }
1905 se->conn.proto_major = arg->major;
1906 se->conn.proto_minor = arg->minor;
1907 se->conn.capable = 0;
1908 se->conn.want = 0;
1909
1910 memset(&outarg, 0, sizeof(outarg));
1911 outarg.major = FUSE_KERNEL_VERSION;
1912 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
1913
72c42e2d 1914 if (arg->major < 7 || (arg->major == 7 && arg->minor < 31)) {
7387863d
DDAG
1915 fuse_log(FUSE_LOG_ERR, "fuse: unsupported protocol version: %u.%u\n",
1916 arg->major, arg->minor);
1917 fuse_reply_err(req, EPROTO);
1918 return;
1919 }
1920
1921 if (arg->major > 7) {
1922 /* Wait for a second INIT request with a 7.X version */
1923 send_reply_ok(req, &outarg, sizeof(outarg));
1924 return;
1925 }
1926
72c42e2d
DDAG
1927 if (arg->max_readahead < se->conn.max_readahead) {
1928 se->conn.max_readahead = arg->max_readahead;
1929 }
1930 if (arg->flags & FUSE_ASYNC_READ) {
1931 se->conn.capable |= FUSE_CAP_ASYNC_READ;
1932 }
1933 if (arg->flags & FUSE_POSIX_LOCKS) {
1934 se->conn.capable |= FUSE_CAP_POSIX_LOCKS;
1935 }
1936 if (arg->flags & FUSE_ATOMIC_O_TRUNC) {
1937 se->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
1938 }
1939 if (arg->flags & FUSE_EXPORT_SUPPORT) {
1940 se->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
1941 }
1942 if (arg->flags & FUSE_DONT_MASK) {
1943 se->conn.capable |= FUSE_CAP_DONT_MASK;
1944 }
1945 if (arg->flags & FUSE_FLOCK_LOCKS) {
1946 se->conn.capable |= FUSE_CAP_FLOCK_LOCKS;
1947 }
1948 if (arg->flags & FUSE_AUTO_INVAL_DATA) {
1949 se->conn.capable |= FUSE_CAP_AUTO_INVAL_DATA;
1950 }
1951 if (arg->flags & FUSE_DO_READDIRPLUS) {
1952 se->conn.capable |= FUSE_CAP_READDIRPLUS;
1953 }
1954 if (arg->flags & FUSE_READDIRPLUS_AUTO) {
1955 se->conn.capable |= FUSE_CAP_READDIRPLUS_AUTO;
1956 }
1957 if (arg->flags & FUSE_ASYNC_DIO) {
1958 se->conn.capable |= FUSE_CAP_ASYNC_DIO;
1959 }
1960 if (arg->flags & FUSE_WRITEBACK_CACHE) {
1961 se->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
1962 }
1963 if (arg->flags & FUSE_NO_OPEN_SUPPORT) {
1964 se->conn.capable |= FUSE_CAP_NO_OPEN_SUPPORT;
1965 }
1966 if (arg->flags & FUSE_PARALLEL_DIROPS) {
1967 se->conn.capable |= FUSE_CAP_PARALLEL_DIROPS;
1968 }
1969 if (arg->flags & FUSE_POSIX_ACL) {
1970 se->conn.capable |= FUSE_CAP_POSIX_ACL;
1971 }
1972 if (arg->flags & FUSE_HANDLE_KILLPRIV) {
1973 se->conn.capable |= FUSE_CAP_HANDLE_KILLPRIV;
1974 }
1975 if (arg->flags & FUSE_NO_OPENDIR_SUPPORT) {
1976 se->conn.capable |= FUSE_CAP_NO_OPENDIR_SUPPORT;
1977 }
1978 if (!(arg->flags & FUSE_MAX_PAGES)) {
1979 size_t max_bufsize = FUSE_DEFAULT_MAX_PAGES_PER_REQ * getpagesize() +
1980 FUSE_BUFFER_HEADER_SIZE;
1981 if (bufsize > max_bufsize) {
1982 bufsize = max_bufsize;
7387863d 1983 }
7387863d 1984 }
2de121f0
DDAG
1985#ifdef HAVE_SPLICE
1986#ifdef HAVE_VMSPLICE
72c42e2d 1987 se->conn.capable |= FUSE_CAP_SPLICE_WRITE | FUSE_CAP_SPLICE_MOVE;
2de121f0 1988#endif
72c42e2d 1989 se->conn.capable |= FUSE_CAP_SPLICE_READ;
2de121f0 1990#endif
72c42e2d 1991 se->conn.capable |= FUSE_CAP_IOCTL_DIR;
7387863d
DDAG
1992
1993 /*
1994 * Default settings for modern filesystems.
1995 *
1996 * Most of these capabilities were disabled by default in
1997 * libfuse2 for backwards compatibility reasons. In libfuse3,
1998 * we can finally enable them by default (as long as they're
1999 * supported by the kernel).
2000 */
2001#define LL_SET_DEFAULT(cond, cap) \
2002 if ((cond) && (se->conn.capable & (cap))) \
2003 se->conn.want |= (cap)
2004 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_READ);
2005 LL_SET_DEFAULT(1, FUSE_CAP_PARALLEL_DIROPS);
2006 LL_SET_DEFAULT(1, FUSE_CAP_AUTO_INVAL_DATA);
2007 LL_SET_DEFAULT(1, FUSE_CAP_HANDLE_KILLPRIV);
2008 LL_SET_DEFAULT(1, FUSE_CAP_ASYNC_DIO);
2009 LL_SET_DEFAULT(1, FUSE_CAP_IOCTL_DIR);
2010 LL_SET_DEFAULT(1, FUSE_CAP_ATOMIC_O_TRUNC);
2011 LL_SET_DEFAULT(se->op.write_buf, FUSE_CAP_SPLICE_READ);
2012 LL_SET_DEFAULT(se->op.getlk && se->op.setlk, FUSE_CAP_POSIX_LOCKS);
2013 LL_SET_DEFAULT(se->op.flock, FUSE_CAP_FLOCK_LOCKS);
2014 LL_SET_DEFAULT(se->op.readdirplus, FUSE_CAP_READDIRPLUS);
2015 LL_SET_DEFAULT(se->op.readdirplus && se->op.readdir,
2016 FUSE_CAP_READDIRPLUS_AUTO);
2017 se->conn.time_gran = 1;
2018
2019 if (bufsize < FUSE_MIN_READ_BUFFER) {
2020 fuse_log(FUSE_LOG_ERR, "fuse: warning: buffer size too small: %zu\n",
2021 bufsize);
2022 bufsize = FUSE_MIN_READ_BUFFER;
2023 }
2024 se->bufsize = bufsize;
2025
2026 if (se->conn.max_write > bufsize - FUSE_BUFFER_HEADER_SIZE) {
2027 se->conn.max_write = bufsize - FUSE_BUFFER_HEADER_SIZE;
2028 }
2029
2030 se->got_init = 1;
2031 if (se->op.init) {
2032 se->op.init(se->userdata, &se->conn);
2033 }
2034
2035 if (se->conn.want & (~se->conn.capable)) {
2036 fuse_log(FUSE_LOG_ERR,
2037 "fuse: error: filesystem requested capabilities "
2038 "0x%x that are not supported by kernel, aborting.\n",
2039 se->conn.want & (~se->conn.capable));
2040 fuse_reply_err(req, EPROTO);
2041 se->error = -EPROTO;
2042 fuse_session_exit(se);
2043 return;
2044 }
2045
2046 if (se->conn.max_write < bufsize - FUSE_BUFFER_HEADER_SIZE) {
2047 se->bufsize = se->conn.max_write + FUSE_BUFFER_HEADER_SIZE;
2048 }
2049 if (arg->flags & FUSE_MAX_PAGES) {
2050 outarg.flags |= FUSE_MAX_PAGES;
2051 outarg.max_pages = (se->conn.max_write - 1) / getpagesize() + 1;
2052 }
2053
2054 /*
2055 * Always enable big writes, this is superseded
2056 * by the max_write option
2057 */
2058 outarg.flags |= FUSE_BIG_WRITES;
2059
2060 if (se->conn.want & FUSE_CAP_ASYNC_READ) {
2061 outarg.flags |= FUSE_ASYNC_READ;
2062 }
2063 if (se->conn.want & FUSE_CAP_POSIX_LOCKS) {
2064 outarg.flags |= FUSE_POSIX_LOCKS;
2065 }
2066 if (se->conn.want & FUSE_CAP_ATOMIC_O_TRUNC) {
2067 outarg.flags |= FUSE_ATOMIC_O_TRUNC;
2068 }
2069 if (se->conn.want & FUSE_CAP_EXPORT_SUPPORT) {
2070 outarg.flags |= FUSE_EXPORT_SUPPORT;
2071 }
2072 if (se->conn.want & FUSE_CAP_DONT_MASK) {
2073 outarg.flags |= FUSE_DONT_MASK;
2074 }
2075 if (se->conn.want & FUSE_CAP_FLOCK_LOCKS) {
2076 outarg.flags |= FUSE_FLOCK_LOCKS;
2077 }
2078 if (se->conn.want & FUSE_CAP_AUTO_INVAL_DATA) {
2079 outarg.flags |= FUSE_AUTO_INVAL_DATA;
2080 }
2081 if (se->conn.want & FUSE_CAP_READDIRPLUS) {
2082 outarg.flags |= FUSE_DO_READDIRPLUS;
2083 }
2084 if (se->conn.want & FUSE_CAP_READDIRPLUS_AUTO) {
2085 outarg.flags |= FUSE_READDIRPLUS_AUTO;
2086 }
2087 if (se->conn.want & FUSE_CAP_ASYNC_DIO) {
2088 outarg.flags |= FUSE_ASYNC_DIO;
2089 }
2090 if (se->conn.want & FUSE_CAP_WRITEBACK_CACHE) {
2091 outarg.flags |= FUSE_WRITEBACK_CACHE;
2092 }
2093 if (se->conn.want & FUSE_CAP_POSIX_ACL) {
2094 outarg.flags |= FUSE_POSIX_ACL;
2095 }
2096 outarg.max_readahead = se->conn.max_readahead;
2097 outarg.max_write = se->conn.max_write;
72c42e2d
DDAG
2098 if (se->conn.max_background >= (1 << 16)) {
2099 se->conn.max_background = (1 << 16) - 1;
2100 }
2101 if (se->conn.congestion_threshold > se->conn.max_background) {
2102 se->conn.congestion_threshold = se->conn.max_background;
7387863d 2103 }
72c42e2d
DDAG
2104 if (!se->conn.congestion_threshold) {
2105 se->conn.congestion_threshold = se->conn.max_background * 3 / 4;
7387863d
DDAG
2106 }
2107
72c42e2d
DDAG
2108 outarg.max_background = se->conn.max_background;
2109 outarg.congestion_threshold = se->conn.congestion_threshold;
2110 outarg.time_gran = se->conn.time_gran;
2111
7387863d
DDAG
2112 if (se->debug) {
2113 fuse_log(FUSE_LOG_DEBUG, " INIT: %u.%u\n", outarg.major,
2114 outarg.minor);
2115 fuse_log(FUSE_LOG_DEBUG, " flags=0x%08x\n", outarg.flags);
2116 fuse_log(FUSE_LOG_DEBUG, " max_readahead=0x%08x\n",
2117 outarg.max_readahead);
2118 fuse_log(FUSE_LOG_DEBUG, " max_write=0x%08x\n", outarg.max_write);
2119 fuse_log(FUSE_LOG_DEBUG, " max_background=%i\n",
2120 outarg.max_background);
2121 fuse_log(FUSE_LOG_DEBUG, " congestion_threshold=%i\n",
2122 outarg.congestion_threshold);
2123 fuse_log(FUSE_LOG_DEBUG, " time_gran=%u\n", outarg.time_gran);
2124 }
7387863d
DDAG
2125
2126 send_reply_ok(req, &outarg, outargsize);
2de121f0
DDAG
2127}
2128
70995754
SH
2129static void do_destroy(fuse_req_t req, fuse_ino_t nodeid,
2130 struct fuse_mbuf_iter *iter)
2de121f0 2131{
7387863d 2132 struct fuse_session *se = req->se;
2de121f0 2133
7387863d 2134 (void)nodeid;
70995754 2135 (void)iter;
2de121f0 2136
7387863d
DDAG
2137 se->got_destroy = 1;
2138 if (se->op.destroy) {
2139 se->op.destroy(se->userdata);
2140 }
2de121f0 2141
7387863d 2142 send_reply_ok(req, NULL, 0);
2de121f0
DDAG
2143}
2144
2de121f0 2145static int send_notify_iov(struct fuse_session *se, int notify_code,
7387863d 2146 struct iovec *iov, int count)
2de121f0 2147{
7387863d 2148 struct fuse_out_header out;
2de121f0 2149
7387863d
DDAG
2150 if (!se->got_init) {
2151 return -ENOTCONN;
2152 }
2de121f0 2153
7387863d
DDAG
2154 out.unique = 0;
2155 out.error = notify_code;
2156 iov[0].iov_base = &out;
2157 iov[0].iov_len = sizeof(struct fuse_out_header);
2de121f0 2158
7387863d 2159 return fuse_send_msg(se, NULL, iov, count);
2de121f0
DDAG
2160}
2161
2162int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
2163{
7387863d
DDAG
2164 if (ph != NULL) {
2165 struct fuse_notify_poll_wakeup_out outarg;
2166 struct iovec iov[2];
2de121f0 2167
7387863d 2168 outarg.kh = ph->kh;
2de121f0 2169
7387863d
DDAG
2170 iov[1].iov_base = &outarg;
2171 iov[1].iov_len = sizeof(outarg);
2de121f0 2172
7387863d
DDAG
2173 return send_notify_iov(ph->se, FUSE_NOTIFY_POLL, iov, 2);
2174 } else {
2175 return 0;
2176 }
2de121f0
DDAG
2177}
2178
2179int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
7387863d 2180 off_t off, off_t len)
2de121f0 2181{
7387863d
DDAG
2182 struct fuse_notify_inval_inode_out outarg;
2183 struct iovec iov[2];
2184
2185 if (!se) {
2186 return -EINVAL;
2187 }
2de121f0 2188
7387863d
DDAG
2189 outarg.ino = ino;
2190 outarg.off = off;
2191 outarg.len = len;
2de121f0 2192
7387863d
DDAG
2193 iov[1].iov_base = &outarg;
2194 iov[1].iov_len = sizeof(outarg);
2de121f0 2195
7387863d 2196 return send_notify_iov(se, FUSE_NOTIFY_INVAL_INODE, iov, 2);
2de121f0
DDAG
2197}
2198
2199int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
7387863d 2200 const char *name, size_t namelen)
2de121f0 2201{
7387863d
DDAG
2202 struct fuse_notify_inval_entry_out outarg;
2203 struct iovec iov[3];
2204
2205 if (!se) {
2206 return -EINVAL;
2207 }
2de121f0 2208
7387863d
DDAG
2209 outarg.parent = parent;
2210 outarg.namelen = namelen;
2211 outarg.padding = 0;
2de121f0 2212
7387863d
DDAG
2213 iov[1].iov_base = &outarg;
2214 iov[1].iov_len = sizeof(outarg);
2215 iov[2].iov_base = (void *)name;
2216 iov[2].iov_len = namelen + 1;
2de121f0 2217
7387863d 2218 return send_notify_iov(se, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
2de121f0
DDAG
2219}
2220
7387863d
DDAG
2221int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
2222 fuse_ino_t child, const char *name,
2223 size_t namelen)
2de121f0 2224{
7387863d
DDAG
2225 struct fuse_notify_delete_out outarg;
2226 struct iovec iov[3];
2de121f0 2227
7387863d
DDAG
2228 if (!se) {
2229 return -EINVAL;
2230 }
2de121f0 2231
7387863d
DDAG
2232 outarg.parent = parent;
2233 outarg.child = child;
2234 outarg.namelen = namelen;
2235 outarg.padding = 0;
2de121f0 2236
7387863d
DDAG
2237 iov[1].iov_base = &outarg;
2238 iov[1].iov_len = sizeof(outarg);
2239 iov[2].iov_base = (void *)name;
2240 iov[2].iov_len = namelen + 1;
2de121f0 2241
7387863d 2242 return send_notify_iov(se, FUSE_NOTIFY_DELETE, iov, 3);
2de121f0
DDAG
2243}
2244
2245int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
8c3fe75e 2246 off_t offset, struct fuse_bufvec *bufv)
2de121f0 2247{
7387863d
DDAG
2248 struct fuse_out_header out;
2249 struct fuse_notify_store_out outarg;
2250 struct iovec iov[3];
2251 size_t size = fuse_buf_size(bufv);
2252 int res;
2de121f0 2253
7387863d
DDAG
2254 if (!se) {
2255 return -EINVAL;
2256 }
2de121f0 2257
7387863d
DDAG
2258 out.unique = 0;
2259 out.error = FUSE_NOTIFY_STORE;
2de121f0 2260
7387863d
DDAG
2261 outarg.nodeid = ino;
2262 outarg.offset = offset;
2263 outarg.size = size;
2264 outarg.padding = 0;
2de121f0 2265
7387863d
DDAG
2266 iov[0].iov_base = &out;
2267 iov[0].iov_len = sizeof(out);
2268 iov[1].iov_base = &outarg;
2269 iov[1].iov_len = sizeof(outarg);
2de121f0 2270
8c3fe75e 2271 res = fuse_send_data_iov(se, NULL, iov, 2, bufv);
7387863d
DDAG
2272 if (res > 0) {
2273 res = -res;
2274 }
2de121f0 2275
7387863d 2276 return res;
2de121f0
DDAG
2277}
2278
2de121f0
DDAG
2279void *fuse_req_userdata(fuse_req_t req)
2280{
7387863d 2281 return req->se->userdata;
2de121f0
DDAG
2282}
2283
2284const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
2285{
7387863d 2286 return &req->ctx;
2de121f0
DDAG
2287}
2288
2289void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
7387863d 2290 void *data)
2de121f0 2291{
7387863d
DDAG
2292 pthread_mutex_lock(&req->lock);
2293 pthread_mutex_lock(&req->se->lock);
2294 req->u.ni.func = func;
2295 req->u.ni.data = data;
2296 pthread_mutex_unlock(&req->se->lock);
2297 if (req->interrupted && func) {
2298 func(req, data);
2299 }
2300 pthread_mutex_unlock(&req->lock);
2de121f0
DDAG
2301}
2302
2303int fuse_req_interrupted(fuse_req_t req)
2304{
7387863d 2305 int interrupted;
2de121f0 2306
7387863d
DDAG
2307 pthread_mutex_lock(&req->se->lock);
2308 interrupted = req->interrupted;
2309 pthread_mutex_unlock(&req->se->lock);
2de121f0 2310
7387863d 2311 return interrupted;
2de121f0
DDAG
2312}
2313
2314static struct {
70995754 2315 void (*func)(fuse_req_t, fuse_ino_t, struct fuse_mbuf_iter *);
7387863d 2316 const char *name;
2de121f0 2317} fuse_ll_ops[] = {
7387863d
DDAG
2318 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
2319 [FUSE_FORGET] = { do_forget, "FORGET" },
2320 [FUSE_GETATTR] = { do_getattr, "GETATTR" },
2321 [FUSE_SETATTR] = { do_setattr, "SETATTR" },
2322 [FUSE_READLINK] = { do_readlink, "READLINK" },
2323 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
2324 [FUSE_MKNOD] = { do_mknod, "MKNOD" },
2325 [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
2326 [FUSE_UNLINK] = { do_unlink, "UNLINK" },
2327 [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
2328 [FUSE_RENAME] = { do_rename, "RENAME" },
2329 [FUSE_LINK] = { do_link, "LINK" },
2330 [FUSE_OPEN] = { do_open, "OPEN" },
2331 [FUSE_READ] = { do_read, "READ" },
2332 [FUSE_WRITE] = { do_write, "WRITE" },
2333 [FUSE_STATFS] = { do_statfs, "STATFS" },
2334 [FUSE_RELEASE] = { do_release, "RELEASE" },
2335 [FUSE_FSYNC] = { do_fsync, "FSYNC" },
2336 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
2337 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
2338 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
2339 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
2340 [FUSE_FLUSH] = { do_flush, "FLUSH" },
2341 [FUSE_INIT] = { do_init, "INIT" },
2342 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
2343 [FUSE_READDIR] = { do_readdir, "READDIR" },
2344 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
2345 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
2346 [FUSE_GETLK] = { do_getlk, "GETLK" },
2347 [FUSE_SETLK] = { do_setlk, "SETLK" },
2348 [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
2349 [FUSE_ACCESS] = { do_access, "ACCESS" },
2350 [FUSE_CREATE] = { do_create, "CREATE" },
2351 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
2352 [FUSE_BMAP] = { do_bmap, "BMAP" },
2353 [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
2354 [FUSE_POLL] = { do_poll, "POLL" },
2355 [FUSE_FALLOCATE] = { do_fallocate, "FALLOCATE" },
2356 [FUSE_DESTROY] = { do_destroy, "DESTROY" },
64c6f408 2357 [FUSE_NOTIFY_REPLY] = { NULL, "NOTIFY_REPLY" },
7387863d
DDAG
2358 [FUSE_BATCH_FORGET] = { do_batch_forget, "BATCH_FORGET" },
2359 [FUSE_READDIRPLUS] = { do_readdirplus, "READDIRPLUS" },
2360 [FUSE_RENAME2] = { do_rename2, "RENAME2" },
2361 [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" },
2362 [FUSE_LSEEK] = { do_lseek, "LSEEK" },
2de121f0
DDAG
2363};
2364
2365#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
2366
2367static const char *opname(enum fuse_opcode opcode)
2368{
7387863d
DDAG
2369 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) {
2370 return "???";
2371 } else {
2372 return fuse_ll_ops[opcode].name;
2373 }
2de121f0
DDAG
2374}
2375
2de121f0 2376void fuse_session_process_buf(struct fuse_session *se,
7387863d 2377 const struct fuse_buf *buf)
2de121f0 2378{
469f9d2f
DDAG
2379 struct fuse_bufvec bufv = { .buf[0] = *buf, .count = 1 };
2380 fuse_session_process_buf_int(se, &bufv, NULL);
2de121f0
DDAG
2381}
2382
469f9d2f
DDAG
2383/*
2384 * Restriction:
2385 * bufv is normally a single entry buffer, except for a write
2386 * where (if it's in memory) then the bufv may be multiple entries,
2387 * where the first entry contains all headers and subsequent entries
2388 * contain data
2389 * bufv shall not use any offsets etc to make the data anything
2390 * other than contiguous starting from 0.
2391 */
2de121f0 2392void fuse_session_process_buf_int(struct fuse_session *se,
469f9d2f 2393 struct fuse_bufvec *bufv,
7387863d
DDAG
2394 struct fuse_chan *ch)
2395{
469f9d2f 2396 const struct fuse_buf *buf = bufv->buf;
0ba8c3c6 2397 struct fuse_mbuf_iter iter = FUSE_MBUF_ITER_INIT(buf);
7387863d 2398 struct fuse_in_header *in;
7387863d
DDAG
2399 struct fuse_req *req;
2400 int err;
2401
0ba8c3c6
SH
2402 /* The first buffer must be a memory buffer */
2403 assert(!(buf->flags & FUSE_BUF_IS_FD));
2404
2405 in = fuse_mbuf_iter_advance(&iter, sizeof(*in));
2406 assert(in); /* caller guarantees the input buffer is large enough */
7387863d
DDAG
2407
2408 if (se->debug) {
2409 fuse_log(FUSE_LOG_DEBUG,
2410 "unique: %llu, opcode: %s (%i), nodeid: %llu, insize: %zu, "
2411 "pid: %u\n",
2412 (unsigned long long)in->unique,
2413 opname((enum fuse_opcode)in->opcode), in->opcode,
2414 (unsigned long long)in->nodeid, buf->size, in->pid);
2415 }
2416
2417 req = fuse_ll_alloc_req(se);
2418 if (req == NULL) {
2419 struct fuse_out_header out = {
2420 .unique = in->unique,
2421 .error = -ENOMEM,
2422 };
2423 struct iovec iov = {
2424 .iov_base = &out,
2425 .iov_len = sizeof(struct fuse_out_header),
2426 };
2427
2428 fuse_send_msg(se, ch, &iov, 1);
2429 return;
2430 }
2431
2432 req->unique = in->unique;
2433 req->ctx.uid = in->uid;
2434 req->ctx.gid = in->gid;
2435 req->ctx.pid = in->pid;
2436 req->ch = ch;
2437
2438 err = EIO;
2439 if (!se->got_init) {
2440 enum fuse_opcode expected;
2441
2442 expected = se->cuse_data ? CUSE_INIT : FUSE_INIT;
2443 if (in->opcode != expected) {
2444 goto reply_err;
2445 }
2446 } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT) {
2447 goto reply_err;
2448 }
2449
2450 err = EACCES;
2451 /* Implement -o allow_root */
2452 if (se->deny_others && in->uid != se->owner && in->uid != 0 &&
2453 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
2454 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
2455 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
2456 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
2457 in->opcode != FUSE_NOTIFY_REPLY && in->opcode != FUSE_READDIRPLUS) {
2458 goto reply_err;
2459 }
2460
2461 err = ENOSYS;
2462 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func) {
2463 goto reply_err;
2464 }
2465 if (in->opcode != FUSE_INTERRUPT) {
2466 struct fuse_req *intr;
2467 pthread_mutex_lock(&se->lock);
2468 intr = check_interrupt(se, req);
2469 list_add_req(req, &se->list);
2470 pthread_mutex_unlock(&se->lock);
2471 if (intr) {
2472 fuse_reply_err(intr, EAGAIN);
2473 }
2474 }
2475
7387863d 2476 if (in->opcode == FUSE_WRITE && se->op.write_buf) {
0ba8c3c6 2477 do_write_buf(req, in->nodeid, &iter, bufv);
7387863d 2478 } else {
70995754 2479 fuse_ll_ops[in->opcode].func(req, in->nodeid, &iter);
7387863d 2480 }
7387863d 2481 return;
2de121f0
DDAG
2482
2483reply_err:
7387863d 2484 fuse_reply_err(req, err);
2de121f0
DDAG
2485}
2486
7387863d
DDAG
2487#define LL_OPTION(n, o, v) \
2488 { \
2489 n, offsetof(struct fuse_session, o), v \
2490 }
2de121f0
DDAG
2491
2492static const struct fuse_opt fuse_ll_opts[] = {
205de006
DDAG
2493 LL_OPTION("debug", debug, 1),
2494 LL_OPTION("-d", debug, 1),
2495 LL_OPTION("--debug", debug, 1),
2496 LL_OPTION("allow_root", deny_others, 1),
2497 LL_OPTION("--socket-path=%s", vu_socket_path, 0),
cee8e35d 2498 LL_OPTION("--fd=%d", vu_listen_fd, 0),
7387863d 2499 FUSE_OPT_END
2de121f0
DDAG
2500};
2501
2502void fuse_lowlevel_version(void)
2503{
7387863d
DDAG
2504 printf("using FUSE kernel interface version %i.%i\n", FUSE_KERNEL_VERSION,
2505 FUSE_KERNEL_MINOR_VERSION);
2de121f0
DDAG
2506}
2507
2508void fuse_lowlevel_help(void)
2509{
7387863d
DDAG
2510 /*
2511 * These are not all options, but the ones that are
2512 * potentially of interest to an end-user
2513 */
205de006
DDAG
2514 printf(
2515 " -o allow_root allow access by root\n"
cee8e35d
SH
2516 " --socket-path=PATH path for the vhost-user socket\n"
2517 " --fd=FDNUM fd number of vhost-user socket\n");
2de121f0
DDAG
2518}
2519
2520void fuse_session_destroy(struct fuse_session *se)
2521{
7387863d
DDAG
2522 if (se->got_init && !se->got_destroy) {
2523 if (se->op.destroy) {
2524 se->op.destroy(se->userdata);
2525 }
2526 }
2527 pthread_mutex_destroy(&se->lock);
2528 free(se->cuse_data);
2529 if (se->fd != -1) {
2530 close(se->fd);
2531 }
2532 free(se);
2de121f0
DDAG
2533}
2534
2535
2de121f0 2536struct fuse_session *fuse_session_new(struct fuse_args *args,
7387863d
DDAG
2537 const struct fuse_lowlevel_ops *op,
2538 size_t op_size, void *userdata)
2539{
2540 struct fuse_session *se;
2541
2542 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
2543 fuse_log(
2544 FUSE_LOG_ERR,
2545 "fuse: warning: library too old, some operations may not work\n");
2546 op_size = sizeof(struct fuse_lowlevel_ops);
2547 }
2548
2549 if (args->argc == 0) {
2550 fuse_log(FUSE_LOG_ERR,
2551 "fuse: empty argv passed to fuse_session_new().\n");
2552 return NULL;
2553 }
2554
2555 se = (struct fuse_session *)calloc(1, sizeof(struct fuse_session));
2556 if (se == NULL) {
2557 fuse_log(FUSE_LOG_ERR, "fuse: failed to allocate fuse object\n");
2558 goto out1;
2559 }
2560 se->fd = -1;
cee8e35d 2561 se->vu_listen_fd = -1;
7387863d
DDAG
2562 se->conn.max_write = UINT_MAX;
2563 se->conn.max_readahead = UINT_MAX;
2564
2565 /* Parse options */
2566 if (fuse_opt_parse(args, se, fuse_ll_opts, NULL) == -1) {
2567 goto out2;
2568 }
2569 if (args->argc == 1 && args->argv[0][0] == '-') {
2570 fuse_log(FUSE_LOG_ERR,
2571 "fuse: warning: argv[0] looks like an option, but "
2572 "will be ignored\n");
2573 } else if (args->argc != 1) {
2574 int i;
2575 fuse_log(FUSE_LOG_ERR, "fuse: unknown option(s): `");
2576 for (i = 1; i < args->argc - 1; i++) {
2577 fuse_log(FUSE_LOG_ERR, "%s ", args->argv[i]);
2578 }
2579 fuse_log(FUSE_LOG_ERR, "%s'\n", args->argv[i]);
2580 goto out4;
2581 }
2582
cee8e35d
SH
2583 if (!se->vu_socket_path && se->vu_listen_fd < 0) {
2584 fuse_log(FUSE_LOG_ERR, "fuse: missing --socket-path or --fd option\n");
2585 goto out4;
2586 }
2587 if (se->vu_socket_path && se->vu_listen_fd >= 0) {
2588 fuse_log(FUSE_LOG_ERR,
2589 "fuse: --socket-path and --fd cannot be given together\n");
d14bf584
DDAG
2590 goto out4;
2591 }
2592
7387863d
DDAG
2593 se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
2594
2595 list_init_req(&se->list);
2596 list_init_req(&se->interrupts);
7387863d
DDAG
2597 fuse_mutex_init(&se->lock);
2598
2599 memcpy(&se->op, op, op_size);
2600 se->owner = getuid();
2601 se->userdata = userdata;
2602
2603 return se;
2de121f0 2604
2de121f0 2605out4:
7387863d 2606 fuse_opt_free_args(args);
2de121f0 2607out2:
7387863d 2608 free(se);
2de121f0 2609out1:
7387863d 2610 return NULL;
2de121f0
DDAG
2611}
2612
67aab022 2613int fuse_session_mount(struct fuse_session *se)
2de121f0 2614{
d14bf584 2615 return virtio_session_mount(se);
2de121f0
DDAG
2616}
2617
2618int fuse_session_fd(struct fuse_session *se)
2619{
7387863d 2620 return se->fd;
2de121f0
DDAG
2621}
2622
2623void fuse_session_unmount(struct fuse_session *se)
2624{
2de121f0
DDAG
2625}
2626
f6f3573c
DDAG
2627int fuse_lowlevel_is_virtio(struct fuse_session *se)
2628{
cee8e35d 2629 return !!se->virtio_dev;
f6f3573c
DDAG
2630}
2631
2de121f0
DDAG
2632#ifdef linux
2633int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
2634{
7387863d
DDAG
2635 char *buf;
2636 size_t bufsize = 1024;
2637 char path[128];
2638 int ret;
2639 int fd;
2640 unsigned long pid = req->ctx.pid;
2641 char *s;
2de121f0 2642
7387863d 2643 sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
2de121f0
DDAG
2644
2645retry:
7387863d
DDAG
2646 buf = malloc(bufsize);
2647 if (buf == NULL) {
2648 return -ENOMEM;
2649 }
2650
2651 ret = -EIO;
2652 fd = open(path, O_RDONLY);
2653 if (fd == -1) {
2654 goto out_free;
2655 }
2656
2657 ret = read(fd, buf, bufsize);
2658 close(fd);
2659 if (ret < 0) {
2660 ret = -EIO;
2661 goto out_free;
2662 }
2663
2664 if ((size_t)ret == bufsize) {
2665 free(buf);
2666 bufsize *= 4;
2667 goto retry;
2668 }
2669
2670 ret = -EIO;
2671 s = strstr(buf, "\nGroups:");
2672 if (s == NULL) {
2673 goto out_free;
2674 }
2675
2676 s += 8;
2677 ret = 0;
2678 while (1) {
2679 char *end;
2680 unsigned long val = strtoul(s, &end, 0);
2681 if (end == s) {
2682 break;
2683 }
2684
2685 s = end;
2686 if (ret < size) {
2687 list[ret] = val;
2688 }
2689 ret++;
2690 }
2de121f0
DDAG
2691
2692out_free:
7387863d
DDAG
2693 free(buf);
2694 return ret;
2de121f0
DDAG
2695}
2696#else /* linux */
2697/*
2698 * This is currently not implemented on other than Linux...
2699 */
2700int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
2701{
7387863d
DDAG
2702 (void)req;
2703 (void)size;
2704 (void)list;
2705 return -ENOSYS;
2de121f0
DDAG
2706}
2707#endif
2708
2709void fuse_session_exit(struct fuse_session *se)
2710{
7387863d 2711 se->exited = 1;
2de121f0
DDAG
2712}
2713
2714void fuse_session_reset(struct fuse_session *se)
2715{
7387863d
DDAG
2716 se->exited = 0;
2717 se->error = 0;
2de121f0
DDAG
2718}
2719
2720int fuse_session_exited(struct fuse_session *se)
2721{
7387863d 2722 return se->exited;
2de121f0 2723}