blob: 90f756e54f2b1df69d499130eb2ba55c7ba016c6 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2007 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU LGPLv2.
6 See the file COPYING.LIB
7*/
8
9#include "fuse_i.h"
10#include "fuse_kernel.h"
11#include "fuse_opt.h"
12#include "fuse_misc.h"
13#include "fuse_common_compat.h"
14#include "fuse_lowlevel_compat.h"
15
16#define linux
17#include <stdio.h>
18#include <stdlib.h>
19#include <stddef.h>
20#include <string.h>
21#include <unistd.h>
22#include <limits.h>
23#include <errno.h>
24
25#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
26#define OFFSET_MAX 0x7fffffffffffffffLL
27
28struct fuse_pollhandle {
29 uint64_t kh;
30 struct fuse_chan *ch;
31 struct fuse_ll *f;
32};
33
34static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
35{
36 attr->ino = stbuf->st_ino;
37 attr->mode = stbuf->st_mode;
38 attr->nlink = stbuf->st_nlink;
39 attr->uid = stbuf->st_uid;
40 attr->gid = stbuf->st_gid;
41 attr->rdev = stbuf->st_rdev;
42 attr->size = stbuf->st_size;
43 attr->blksize = stbuf->st_blksize;
44 attr->blocks = stbuf->st_blocks;
45 attr->atime = stbuf->st_atime;
46 attr->mtime = stbuf->st_mtime;
47 attr->ctime = stbuf->st_ctime;
48 attr->atimensec = ST_ATIM_NSEC(stbuf);
49 attr->mtimensec = ST_MTIM_NSEC(stbuf);
50 attr->ctimensec = ST_CTIM_NSEC(stbuf);
51}
52
53static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
54{
55 stbuf->st_mode = attr->mode;
56 stbuf->st_uid = attr->uid;
57 stbuf->st_gid = attr->gid;
58 stbuf->st_size = attr->size;
59 stbuf->st_atime = attr->atime;
60 stbuf->st_mtime = attr->mtime;
61 ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
62 ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
63}
64
65static size_t iov_length(const struct iovec *iov, size_t count)
66{
67 size_t seg;
68 size_t ret = 0;
69
70 for (seg = 0; seg < count; seg++)
71 ret += iov[seg].iov_len;
72 return ret;
73}
74
75static void list_init_req(struct fuse_req *req)
76{
77 req->next = req;
78 req->prev = req;
79}
80
81static void list_del_req(struct fuse_req *req)
82{
83 struct fuse_req *prev = req->prev;
84 struct fuse_req *next = req->next;
85 prev->next = next;
86 next->prev = prev;
87}
88
89static void list_add_req(struct fuse_req *req, struct fuse_req *next)
90{
91 struct fuse_req *prev = next->prev;
92 req->next = next;
93 req->prev = prev;
94 prev->next = req;
95 next->prev = req;
96}
97
98static void destroy_req(fuse_req_t req)
99{
100 pthread_mutex_destroy(&req->lock);
101 free(req);
102}
103
104void fuse_free_req(fuse_req_t req)
105{
106 int ctr;
107 struct fuse_ll *f = req->f;
108
109 pthread_mutex_lock(&f->lock);
110 req->u.ni.func = NULL;
111 req->u.ni.data = NULL;
112 list_del_req(req);
113 ctr = --req->ctr;
114 pthread_mutex_unlock(&f->lock);
115 if (!ctr)
116 destroy_req(req);
117}
118
119int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
120 int count)
121{
122 struct fuse_out_header out;
123
124 if (error <= -1000 || error > 0) {
125 fprintf(stderr, "fuse: bad error value: %i\n", error);
126 error = -ERANGE;
127 }
128
129 out.unique = req->unique;
130 out.error = error;
131 iov[0].iov_base = &out;
132 iov[0].iov_len = sizeof(struct fuse_out_header);
133 out.len = iov_length(iov, count);
134
135 if (req->f->debug) {
136 if (out.error) {
137 fprintf(stderr,
138 " unique: %llu, error: %i (%s), outsize: %i\n",
139 (unsigned long long) out.unique, out.error,
140 strerror(-out.error), out.len);
141 } else {
142 fprintf(stderr,
143 " unique: %llu, success, outsize: %i\n",
144 (unsigned long long) out.unique, out.len);
145 }
146 }
147
148 return fuse_chan_send(req->ch, iov, count);
149}
150
151static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
152 int count)
153{
154 int res;
155
156 res = fuse_send_reply_iov_nofree(req, error, iov, count);
157 fuse_free_req(req);
158 return res;
159}
160
161static int send_reply(fuse_req_t req, int error, const void *arg,
162 size_t argsize)
163{
164 struct iovec iov[2];
165 int count = 1;
166 if (argsize) {
167 iov[1].iov_base = (void *) arg;
168 iov[1].iov_len = argsize;
169 count++;
170 }
171 return send_reply_iov(req, error, iov, count);
172}
173
174int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
175{
176 int res;
177 struct iovec *padded_iov;
178
179 padded_iov = malloc((count + 1) * sizeof(struct iovec));
180 if (padded_iov == NULL)
181 return fuse_reply_err(req, -ENOMEM);
182
183 memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
184 count++;
185
186 res = send_reply_iov(req, 0, padded_iov, count);
187 free(padded_iov);
188
189 return res;
190}
191
192size_t fuse_dirent_size(size_t namelen)
193{
194 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
195}
196
197char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
198 off64_t off)
199{
200 unsigned namelen = strlen(name);
201 unsigned entlen = FUSE_NAME_OFFSET + namelen;
202 unsigned entsize = fuse_dirent_size(namelen);
203 unsigned padlen = entsize - entlen;
204 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
205
206 dirent->ino = stbuf->st_ino;
207 dirent->off = off;
208 dirent->namelen = namelen;
209 dirent->type = (stbuf->st_mode & 0170000) >> 12;
210 strncpy(dirent->name, name, namelen);
211 if (padlen)
212 memset(buf + entlen, 0, padlen);
213
214 return buf + entsize;
215}
216
217size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
218 const char *name, const struct stat *stbuf, off64_t off)
219{
220 size_t entsize;
221
222 (void) req;
223 entsize = fuse_dirent_size(strlen(name));
224 if (entsize <= bufsize && buf)
225 fuse_add_dirent(buf, name, stbuf, off);
226 return entsize;
227}
228
229static void convert_statfs(const struct statvfs *stbuf,
230 struct fuse_kstatfs *kstatfs)
231{
232 kstatfs->bsize = stbuf->f_bsize;
233 kstatfs->frsize = stbuf->f_frsize;
234 kstatfs->blocks = stbuf->f_blocks;
235 kstatfs->bfree = stbuf->f_bfree;
236 kstatfs->bavail = stbuf->f_bavail;
237 kstatfs->files = stbuf->f_files;
238 kstatfs->ffree = stbuf->f_ffree;
239 kstatfs->namelen = stbuf->f_namemax;
240}
241
242static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
243{
244 return send_reply(req, 0, arg, argsize);
245}
246
247int fuse_reply_err(fuse_req_t req, int err)
248{
249 return send_reply(req, -err, NULL, 0);
250}
251
252void fuse_reply_none(fuse_req_t req)
253{
254 fuse_chan_send(req->ch, NULL, 0);
255 fuse_free_req(req);
256}
257
258static unsigned long calc_timeout_sec(double t)
259{
260 if (t > (double) ULONG_MAX)
261 return ULONG_MAX;
262 else if (t < 0.0)
263 return 0;
264 else
265 return (unsigned long) t;
266}
267
268static unsigned int calc_timeout_nsec(double t)
269{
270 double f = t - (double) calc_timeout_sec(t);
271 if (f < 0.0)
272 return 0;
273 else if (f >= 0.999999999)
274 return 999999999;
275 else
276 return (unsigned int) (f * 1.0e9);
277}
278
279static void fill_entry(struct fuse_entry_out *arg,
280 const struct fuse_entry_param *e)
281{
282 arg->nodeid = e->ino;
283 arg->generation = e->generation;
284 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
285 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
286 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
287 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
288 convert_stat(&e->attr, &arg->attr);
289}
290
291static void fill_open(struct fuse_open_out *arg,
292 const struct fuse_file_info *f)
293{
294 arg->fh = f->fh;
295 if (f->direct_io)
296 arg->open_flags |= FOPEN_DIRECT_IO;
297 if (f->keep_cache)
298 arg->open_flags |= FOPEN_KEEP_CACHE;
299 if (f->nonseekable)
300 arg->open_flags |= FOPEN_NONSEEKABLE;
301}
302
303int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
304{
305 struct fuse_entry_out arg;
306 size_t size = req->f->conn.proto_minor < 9 ?
307 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(arg);
308
309 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
310 negative entry */
311 if (!e->ino && req->f->conn.proto_minor < 4)
312 return fuse_reply_err(req, ENOENT);
313
314 memset(&arg, 0, sizeof(arg));
315 fill_entry(&arg, e);
316 return send_reply_ok(req, &arg, size);
317}
318
319int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
320 const struct fuse_file_info *f)
321{
322 char buf[sizeof(struct fuse_entry_out) + sizeof(struct fuse_open_out)];
323 size_t entrysize = req->f->conn.proto_minor < 9 ?
324 FUSE_COMPAT_ENTRY_OUT_SIZE : sizeof(struct fuse_entry_out);
325 struct fuse_entry_out *earg = (struct fuse_entry_out *) buf;
326 struct fuse_open_out *oarg = (struct fuse_open_out *) (buf + entrysize);
327
328 memset(buf, 0, sizeof(buf));
329 fill_entry(earg, e);
330 fill_open(oarg, f);
331 return send_reply_ok(req, buf,
332 entrysize + sizeof(struct fuse_open_out));
333}
334
335int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
336 double attr_timeout)
337{
338 struct fuse_attr_out arg;
339 size_t size = req->f->conn.proto_minor < 9 ?
340 FUSE_COMPAT_ATTR_OUT_SIZE : sizeof(arg);
341
342 memset(&arg, 0, sizeof(arg));
343 arg.attr_valid = calc_timeout_sec(attr_timeout);
344 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
345 convert_stat(attr, &arg.attr);
346
347 return send_reply_ok(req, &arg, size);
348}
349
350int fuse_reply_readlink(fuse_req_t req, const char *linkname)
351{
352 return send_reply_ok(req, linkname, strlen(linkname));
353}
354
355int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
356{
357 struct fuse_open_out arg;
358
359 memset(&arg, 0, sizeof(arg));
360 fill_open(&arg, f);
361 return send_reply_ok(req, &arg, sizeof(arg));
362}
363
364int fuse_reply_write(fuse_req_t req, size_t count)
365{
366 struct fuse_write_out arg;
367
368 memset(&arg, 0, sizeof(arg));
369 arg.size = count;
370
371 return send_reply_ok(req, &arg, sizeof(arg));
372}
373
374int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
375{
376 return send_reply_ok(req, buf, size);
377}
378
379int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
380{
381 struct fuse_statfs_out arg;
382 size_t size = req->f->conn.proto_minor < 4 ?
383 FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
384
385 memset(&arg, 0, sizeof(arg));
386 convert_statfs(stbuf, &arg.st);
387
388 return send_reply_ok(req, &arg, size);
389}
390
391int fuse_reply_xattr(fuse_req_t req, size_t count)
392{
393 struct fuse_getxattr_out arg;
394
395 memset(&arg, 0, sizeof(arg));
396 arg.size = count;
397
398 return send_reply_ok(req, &arg, sizeof(arg));
399}
400
401int fuse_reply_lock(fuse_req_t req, struct flock *lock)
402{
403 struct fuse_lk_out arg;
404
405 memset(&arg, 0, sizeof(arg));
406 arg.lk.type = lock->l_type;
407 if (lock->l_type != F_UNLCK) {
408 arg.lk.start = lock->l_start;
409 if (lock->l_len == 0)
410 arg.lk.end = OFFSET_MAX;
411 else
412 arg.lk.end = lock->l_start + lock->l_len - 1;
413 }
414 arg.lk.pid = lock->l_pid;
415 return send_reply_ok(req, &arg, sizeof(arg));
416}
417
418int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
419{
420 struct fuse_bmap_out arg;
421
422 memset(&arg, 0, sizeof(arg));
423 arg.block = idx;
424
425 return send_reply_ok(req, &arg, sizeof(arg));
426}
427
428int fuse_reply_ioctl_retry(fuse_req_t req,
429 const struct iovec *in_iov, size_t in_count,
430 const struct iovec *out_iov, size_t out_count)
431{
432 struct fuse_ioctl_out arg;
433 struct iovec iov[4];
434 size_t count = 1;
435
436 memset(&arg, 0, sizeof(arg));
437 arg.flags |= FUSE_IOCTL_RETRY;
438 arg.in_iovs = in_count;
439 arg.out_iovs = out_count;
440 iov[count].iov_base = &arg;
441 iov[count].iov_len = sizeof(arg);
442 count++;
443
444 if (in_count) {
445 iov[count].iov_base = (void *)in_iov;
446 iov[count].iov_len = sizeof(in_iov[0]) * in_count;
447 count++;
448 }
449
450 if (out_count) {
451 iov[count].iov_base = (void *)out_iov;
452 iov[count].iov_len = sizeof(out_iov[0]) * out_count;
453 count++;
454 }
455
456 return send_reply_iov(req, 0, iov, count);
457}
458
459int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
460{
461 struct fuse_ioctl_out arg;
462 struct iovec iov[3];
463 size_t count = 1;
464
465 memset(&arg, 0, sizeof(arg));
466 arg.result = result;
467 iov[count].iov_base = &arg;
468 iov[count].iov_len = sizeof(arg);
469 count++;
470
471 if (size) {
472 iov[count].iov_base = (char *) buf;
473 iov[count].iov_len = size;
474 count++;
475 }
476
477 return send_reply_iov(req, 0, iov, count);
478}
479
480int fuse_reply_ioctl_iov(fuse_req_t req, int result, const struct iovec *iov,
481 int count)
482{
483 struct iovec *padded_iov;
484 struct fuse_ioctl_out arg;
485 int res;
486
487 padded_iov = malloc((count + 2) * sizeof(struct iovec));
488 if (padded_iov == NULL)
489 return fuse_reply_err(req, -ENOMEM);
490
491 memset(&arg, 0, sizeof(arg));
492 arg.result = result;
493 padded_iov[1].iov_base = &arg;
494 padded_iov[1].iov_len = sizeof(arg);
495
496 memcpy(&padded_iov[2], iov, count * sizeof(struct iovec));
497
498 res = send_reply_iov(req, 0, padded_iov, count + 2);
499 free(padded_iov);
500
501 return res;
502}
503
504int fuse_reply_poll(fuse_req_t req, unsigned revents)
505{
506 struct fuse_poll_out arg;
507
508 memset(&arg, 0, sizeof(arg));
509 arg.revents = revents;
510
511 return send_reply_ok(req, &arg, sizeof(arg));
512}
513
514static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
515{
516 char *name = (char *) inarg;
517
518 if (req->f->op.lookup)
519 req->f->op.lookup(req, nodeid, name);
520 else
521 fuse_reply_err(req, ENOSYS);
522}
523
524static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
525{
526 struct fuse_forget_in *arg = (struct fuse_forget_in *) inarg;
527
528 if (req->f->op.forget)
529 req->f->op.forget(req, nodeid, arg->nlookup);
530 else
531 fuse_reply_none(req);
532}
533
534static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
535{
536 struct fuse_file_info *fip = NULL;
537 struct fuse_file_info fi;
538
539 if (req->f->conn.proto_minor >= 9) {
540 struct fuse_getattr_in *arg = (struct fuse_getattr_in *) inarg;
541
542 if (arg->getattr_flags & FUSE_GETATTR_FH) {
543 memset(&fi, 0, sizeof(fi));
544 fi.fh = arg->fh;
545 fi.fh_old = fi.fh;
546 fip = &fi;
547 }
548 }
549
550 if (req->f->op.getattr)
551 req->f->op.getattr(req, nodeid, fip);
552 else
553 fuse_reply_err(req, ENOSYS);
554}
555
556static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
557{
558 struct fuse_setattr_in *arg = (struct fuse_setattr_in *) inarg;
559
560 if (req->f->op.setattr) {
561 struct fuse_file_info *fi = NULL;
562 struct fuse_file_info fi_store;
563 struct stat stbuf;
564 memset(&stbuf, 0, sizeof(stbuf));
565 convert_attr(arg, &stbuf);
566 if (arg->valid & FATTR_FH) {
567 arg->valid &= ~FATTR_FH;
568 memset(&fi_store, 0, sizeof(fi_store));
569 fi = &fi_store;
570 fi->fh = arg->fh;
571 fi->fh_old = fi->fh;
572 }
573 arg->valid &=
574 FUSE_SET_ATTR_MODE |
575 FUSE_SET_ATTR_UID |
576 FUSE_SET_ATTR_GID |
577 FUSE_SET_ATTR_SIZE |
578 FUSE_SET_ATTR_ATIME |
579 FUSE_SET_ATTR_MTIME |
580 FUSE_SET_ATTR_ATIME_NOW |
581 FUSE_SET_ATTR_MTIME_NOW;
582
583 req->f->op.setattr(req, nodeid, &stbuf, arg->valid, fi);
584 } else
585 fuse_reply_err(req, ENOSYS);
586}
587
588static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
589{
590 struct fuse_access_in *arg = (struct fuse_access_in *) inarg;
591
592 if (req->f->op.access)
593 req->f->op.access(req, nodeid, arg->mask);
594 else
595 fuse_reply_err(req, ENOSYS);
596}
597
598static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
599{
600 (void) inarg;
601
602 if (req->f->op.readlink)
603 req->f->op.readlink(req, nodeid);
604 else
605 fuse_reply_err(req, ENOSYS);
606}
607
608static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
609{
610 struct fuse_mknod_in *arg = (struct fuse_mknod_in *) inarg;
611 char *name = PARAM(arg);
612
613 if (req->f->conn.proto_minor >= 12)
614 req->ctx.umask = arg->umask;
615 else
616 name = (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
617
618 if (req->f->op.mknod)
619 req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
620 else
621 fuse_reply_err(req, ENOSYS);
622}
623
624static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
625{
626 struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *) inarg;
627
628 if (req->f->conn.proto_minor >= 12)
629 req->ctx.umask = arg->umask;
630
631 if (req->f->op.mkdir)
632 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
633 else
634 fuse_reply_err(req, ENOSYS);
635}
636
637static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
638{
639 char *name = (char *) inarg;
640
641 if (req->f->op.unlink)
642 req->f->op.unlink(req, nodeid, name);
643 else
644 fuse_reply_err(req, ENOSYS);
645}
646
647static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
648{
649 char *name = (char *) inarg;
650
651 if (req->f->op.rmdir)
652 req->f->op.rmdir(req, nodeid, name);
653 else
654 fuse_reply_err(req, ENOSYS);
655}
656
657static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
658{
659 char *name = (char *) inarg;
660 char *linkname = ((char *) inarg) + strlen((char *) inarg) + 1;
661
662 if (req->f->op.symlink)
663 req->f->op.symlink(req, linkname, nodeid, name);
664 else
665 fuse_reply_err(req, ENOSYS);
666}
667
668static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
669{
670 struct fuse_rename_in *arg = (struct fuse_rename_in *) inarg;
671 char *oldname = PARAM(arg);
672 char *newname = oldname + strlen(oldname) + 1;
673
674 if (req->f->op.rename)
675 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
676 else
677 fuse_reply_err(req, ENOSYS);
678}
679
680static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
681{
682 struct fuse_link_in *arg = (struct fuse_link_in *) inarg;
683
684 if (req->f->op.link)
685 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
686 else
687 fuse_reply_err(req, ENOSYS);
688}
689
690static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
691{
692 struct fuse_create_in *arg = (struct fuse_create_in *) inarg;
693
694 if (req->f->op.create) {
695 struct fuse_file_info fi;
696 char *name = PARAM(arg);
697
698 memset(&fi, 0, sizeof(fi));
699 fi.flags = arg->flags;
700
701 if (req->f->conn.proto_minor >= 12)
702 req->ctx.umask = arg->umask;
703 else
704 name = (char *) inarg + sizeof(struct fuse_open_in);
705
706 req->f->op.create(req, nodeid, name, arg->mode, &fi);
707 } else
708 fuse_reply_err(req, ENOSYS);
709}
710
711static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
712{
713 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
714 struct fuse_file_info fi;
715
716 memset(&fi, 0, sizeof(fi));
717 fi.flags = arg->flags;
718
719 if (req->f->op.open)
720 req->f->op.open(req, nodeid, &fi);
721 else
722 fuse_reply_open(req, &fi);
723}
724
725static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
726{
727 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
728
729 if (req->f->op.read) {
730 struct fuse_file_info fi;
731
732 memset(&fi, 0, sizeof(fi));
733 fi.fh = arg->fh;
734 fi.fh_old = fi.fh;
735 if (req->f->conn.proto_minor >= 9) {
736 fi.lock_owner = arg->lock_owner;
737 fi.flags = arg->flags;
738 }
739 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
740 } else
741 fuse_reply_err(req, ENOSYS);
742}
743
744static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
745{
746 struct fuse_write_in *arg = (struct fuse_write_in *) inarg;
747 struct fuse_file_info fi;
748 char *param;
749
750 memset(&fi, 0, sizeof(fi));
751 fi.fh = arg->fh;
752 fi.fh_old = fi.fh;
753 fi.writepage = arg->write_flags & 1;
754
755 if (req->f->conn.proto_minor < 9) {
756 param = ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE;
757 } else {
758 fi.lock_owner = arg->lock_owner;
759 fi.flags = arg->flags;
760 param = PARAM(arg);
761 }
762
763 if (req->f->op.write)
764 req->f->op.write(req, nodeid, param, arg->size,
765 arg->offset, &fi);
766 else
767 fuse_reply_err(req, ENOSYS);
768}
769
770static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
771{
772 struct fuse_flush_in *arg = (struct fuse_flush_in *) inarg;
773 struct fuse_file_info fi;
774
775 memset(&fi, 0, sizeof(fi));
776 fi.fh = arg->fh;
777 fi.fh_old = fi.fh;
778 fi.flush = 1;
779 if (req->f->conn.proto_minor >= 7)
780 fi.lock_owner = arg->lock_owner;
781
782 if (req->f->op.flush)
783 req->f->op.flush(req, nodeid, &fi);
784 else
785 fuse_reply_err(req, ENOSYS);
786}
787
788static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
789{
790 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
791 struct fuse_file_info fi;
792
793 memset(&fi, 0, sizeof(fi));
794 fi.flags = arg->flags;
795 fi.fh = arg->fh;
796 fi.fh_old = fi.fh;
797 if (req->f->conn.proto_minor >= 8) {
798 fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
799 fi.lock_owner = arg->lock_owner;
800 }
801
802 if (req->f->op.release)
803 req->f->op.release(req, nodeid, &fi);
804 else
805 fuse_reply_err(req, 0);
806}
807
808static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
809{
810 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
811 struct fuse_file_info fi;
812
813 memset(&fi, 0, sizeof(fi));
814 fi.fh = arg->fh;
815 fi.fh_old = fi.fh;
816
817 if (req->f->op.fsync)
818 req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi);
819 else
820 fuse_reply_err(req, ENOSYS);
821}
822
823static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
824{
825 struct fuse_open_in *arg = (struct fuse_open_in *) inarg;
826 struct fuse_file_info fi;
827
828 memset(&fi, 0, sizeof(fi));
829 fi.flags = arg->flags;
830
831 if (req->f->op.opendir)
832 req->f->op.opendir(req, nodeid, &fi);
833 else
834 fuse_reply_open(req, &fi);
835}
836
837static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
838{
839 struct fuse_read_in *arg = (struct fuse_read_in *) inarg;
840 struct fuse_file_info fi;
841
842 memset(&fi, 0, sizeof(fi));
843 fi.fh = arg->fh;
844 fi.fh_old = fi.fh;
845
846 if (req->f->op.readdir)
847 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
848 else
849 fuse_reply_err(req, ENOSYS);
850}
851
852static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
853{
854 struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
855 struct fuse_file_info fi;
856
857 memset(&fi, 0, sizeof(fi));
858 fi.flags = arg->flags;
859 fi.fh = arg->fh;
860 fi.fh_old = fi.fh;
861
862 if (req->f->op.releasedir)
863 req->f->op.releasedir(req, nodeid, &fi);
864 else
865 fuse_reply_err(req, 0);
866}
867
868static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
869{
870 struct fuse_fsync_in *arg = (struct fuse_fsync_in *) inarg;
871 struct fuse_file_info fi;
872
873 memset(&fi, 0, sizeof(fi));
874 fi.fh = arg->fh;
875 fi.fh_old = fi.fh;
876
877 if (req->f->op.fsyncdir)
878 req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi);
879 else
880 fuse_reply_err(req, ENOSYS);
881}
882
883static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
884{
885 (void) nodeid;
886 (void) inarg;
887
888 if (req->f->op.statfs)
889 req->f->op.statfs(req, nodeid);
890 else {
891 struct statvfs buf = {
892 .f_namemax = 255,
893 .f_bsize = 512,
894 };
895 fuse_reply_statfs(req, &buf);
896 }
897}
898
899static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
900{
901 struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *) inarg;
902 char *name = PARAM(arg);
903 char *value = name + strlen(name) + 1;
904
905 if (req->f->op.setxattr)
906 req->f->op.setxattr(req, nodeid, name, value, arg->size,
907 arg->flags);
908 else
909 fuse_reply_err(req, ENOSYS);
910}
911
912static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
913{
914 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
915
916 if (req->f->op.getxattr)
917 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
918 else
919 fuse_reply_err(req, ENOSYS);
920}
921
922static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
923{
924 struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *) inarg;
925
926 if (req->f->op.listxattr)
927 req->f->op.listxattr(req, nodeid, arg->size);
928 else
929 fuse_reply_err(req, ENOSYS);
930}
931
932static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
933{
934 char *name = (char *) inarg;
935
936 if (req->f->op.removexattr)
937 req->f->op.removexattr(req, nodeid, name);
938 else
939 fuse_reply_err(req, ENOSYS);
940}
941
942static void convert_fuse_file_lock(struct fuse_file_lock *fl,
943 struct flock *flock)
944{
945 memset(flock, 0, sizeof(struct flock));
946 flock->l_type = fl->type;
947 flock->l_whence = SEEK_SET;
948 flock->l_start = fl->start;
949 if (fl->end == OFFSET_MAX)
950 flock->l_len = 0;
951 else
952 flock->l_len = fl->end - fl->start + 1;
953 flock->l_pid = fl->pid;
954}
955
956static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
957{
958 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
959 struct fuse_file_info fi;
960 struct flock flock;
961
962 memset(&fi, 0, sizeof(fi));
963 fi.fh = arg->fh;
964 fi.lock_owner = arg->owner;
965
966 convert_fuse_file_lock(&arg->lk, &flock);
967 if (req->f->op.getlk)
968 req->f->op.getlk(req, nodeid, &fi, &flock);
969 else
970 fuse_reply_err(req, ENOSYS);
971}
972
973static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
974 const void *inarg, int sleep)
975{
976 struct fuse_lk_in *arg = (struct fuse_lk_in *) inarg;
977 struct fuse_file_info fi;
978 struct flock flock;
979
980 memset(&fi, 0, sizeof(fi));
981 fi.fh = arg->fh;
982 fi.lock_owner = arg->owner;
983
984 convert_fuse_file_lock(&arg->lk, &flock);
985 if (req->f->op.setlk)
986 req->f->op.setlk(req, nodeid, &fi, &flock, sleep);
987 else
988 fuse_reply_err(req, ENOSYS);
989}
990
991static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
992{
993 do_setlk_common(req, nodeid, inarg, 0);
994}
995
996static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
997{
998 do_setlk_common(req, nodeid, inarg, 1);
999}
1000
1001static int find_interrupted(struct fuse_ll *f, struct fuse_req *req)
1002{
1003 struct fuse_req *curr;
1004
1005 for (curr = f->list.next; curr != &f->list; curr = curr->next) {
1006 if (curr->unique == req->u.i.unique) {
1007 fuse_interrupt_func_t func;
1008 void *data;
1009
1010 curr->ctr++;
1011 pthread_mutex_unlock(&f->lock);
1012
1013 /* Ugh, ugly locking */
1014 pthread_mutex_lock(&curr->lock);
1015 pthread_mutex_lock(&f->lock);
1016 curr->interrupted = 1;
1017 func = curr->u.ni.func;
1018 data = curr->u.ni.data;
1019 pthread_mutex_unlock(&f->lock);
1020 if (func)
1021 func(curr, data);
1022 pthread_mutex_unlock(&curr->lock);
1023
1024 pthread_mutex_lock(&f->lock);
1025 curr->ctr--;
1026 if (!curr->ctr)
1027 destroy_req(curr);
1028
1029 return 1;
1030 }
1031 }
1032 for (curr = f->interrupts.next; curr != &f->interrupts;
1033 curr = curr->next) {
1034 if (curr->u.i.unique == req->u.i.unique)
1035 return 1;
1036 }
1037 return 0;
1038}
1039
1040static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1041{
1042 struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *) inarg;
1043 struct fuse_ll *f = req->f;
1044
1045 (void) nodeid;
1046 if (f->debug)
1047 fprintf(stderr, "INTERRUPT: %llu\n",
1048 (unsigned long long) arg->unique);
1049
1050 req->u.i.unique = arg->unique;
1051
1052 pthread_mutex_lock(&f->lock);
1053 if (find_interrupted(f, req))
1054 destroy_req(req);
1055 else
1056 list_add_req(req, &f->interrupts);
1057 pthread_mutex_unlock(&f->lock);
1058}
1059
1060static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req)
1061{
1062 struct fuse_req *curr;
1063
1064 for (curr = f->interrupts.next; curr != &f->interrupts;
1065 curr = curr->next) {
1066 if (curr->u.i.unique == req->unique) {
1067 req->interrupted = 1;
1068 list_del_req(curr);
1069 free(curr);
1070 return NULL;
1071 }
1072 }
1073 curr = f->interrupts.next;
1074 if (curr != &f->interrupts) {
1075 list_del_req(curr);
1076 list_init_req(curr);
1077 return curr;
1078 } else
1079 return NULL;
1080}
1081
1082static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1083{
1084 struct fuse_bmap_in *arg = (struct fuse_bmap_in *) inarg;
1085
1086 if (req->f->op.bmap)
1087 req->f->op.bmap(req, nodeid, arg->blocksize, arg->block);
1088 else
1089 fuse_reply_err(req, ENOSYS);
1090}
1091
1092static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1093{
1094 struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *) inarg;
1095 unsigned int flags = arg->flags;
1096 void *in_buf = arg->in_size ? PARAM(arg) : NULL;
1097 struct fuse_file_info fi;
1098
1099 memset(&fi, 0, sizeof(fi));
1100 fi.fh = arg->fh;
1101 fi.fh_old = fi.fh;
1102
1103 if (req->f->op.ioctl)
1104 req->f->op.ioctl(req, nodeid, arg->cmd,
1105 (void *)(uintptr_t)arg->arg, &fi, flags,
1106 in_buf, arg->in_size, arg->out_size);
1107 else
1108 fuse_reply_err(req, ENOSYS);
1109}
1110
1111void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
1112{
1113 free(ph);
1114}
1115
1116static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1117{
1118 struct fuse_poll_in *arg = (struct fuse_poll_in *) inarg;
1119 struct fuse_file_info fi;
1120
1121 memset(&fi, 0, sizeof(fi));
1122 fi.fh = arg->fh;
1123 fi.fh_old = fi.fh;
1124
1125 if (req->f->op.poll) {
1126 struct fuse_pollhandle *ph = NULL;
1127
1128 if (arg->flags & FUSE_POLL_SCHEDULE_NOTIFY) {
1129 ph = malloc(sizeof(struct fuse_pollhandle));
1130 if (ph == NULL) {
1131 fuse_reply_err(req, ENOMEM);
1132 return;
1133 }
1134 ph->kh = arg->kh;
1135 ph->ch = req->ch;
1136 ph->f = req->f;
1137 }
1138
1139 req->f->op.poll(req, nodeid, &fi, ph);
1140 } else {
1141 fuse_reply_err(req, ENOSYS);
1142 }
1143}
1144
1145static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1146{
1147 struct fuse_init_in *arg = (struct fuse_init_in *) inarg;
1148 struct fuse_init_out outarg;
1149 struct fuse_ll *f = req->f;
1150 size_t bufsize = fuse_chan_bufsize(req->ch);
1151
1152 (void) nodeid;
1153 if (f->debug) {
1154 fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor);
1155 if (arg->major == 7 && arg->minor >= 6) {
1156 fprintf(stderr, "flags=0x%08x\n", arg->flags);
1157 fprintf(stderr, "max_readahead=0x%08x\n",
1158 arg->max_readahead);
1159 }
1160 }
1161 f->conn.proto_major = arg->major;
1162 f->conn.proto_minor = arg->minor;
1163 f->conn.capable = 0;
1164 f->conn.want = 0;
1165
1166 memset(&outarg, 0, sizeof(outarg));
1167 outarg.major = FUSE_KERNEL_VERSION;
1168 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
1169
1170 if (arg->major < 7) {
1171 fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
1172 arg->major, arg->minor);
1173 fuse_reply_err(req, EPROTO);
1174 return;
1175 }
1176
1177 if (arg->major > 7) {
1178 /* Wait for a second INIT request with a 7.X version */
1179 send_reply_ok(req, &outarg, sizeof(outarg));
1180 return;
1181 }
1182
1183 if (arg->minor >= 6) {
1184 if (f->conn.async_read)
1185 f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
1186 if (arg->max_readahead < f->conn.max_readahead)
1187 f->conn.max_readahead = arg->max_readahead;
1188 if (arg->flags & FUSE_ASYNC_READ)
1189 f->conn.capable |= FUSE_CAP_ASYNC_READ;
1190 if (arg->flags & FUSE_POSIX_LOCKS)
1191 f->conn.capable |= FUSE_CAP_POSIX_LOCKS;
1192 if (arg->flags & FUSE_ATOMIC_O_TRUNC)
1193 f->conn.capable |= FUSE_CAP_ATOMIC_O_TRUNC;
1194 if (arg->flags & FUSE_EXPORT_SUPPORT)
1195 f->conn.capable |= FUSE_CAP_EXPORT_SUPPORT;
1196 if (arg->flags & FUSE_BIG_WRITES)
1197 f->conn.capable |= FUSE_CAP_BIG_WRITES;
1198 if (arg->flags & FUSE_DONT_MASK)
1199 f->conn.capable |= FUSE_CAP_DONT_MASK;
1200 } else {
1201 f->conn.async_read = 0;
1202 f->conn.max_readahead = 0;
1203 }
1204
1205 if (f->atomic_o_trunc)
1206 f->conn.want |= FUSE_CAP_ATOMIC_O_TRUNC;
1207 if (f->op.getlk && f->op.setlk && !f->no_remote_lock)
1208 f->conn.want |= FUSE_CAP_POSIX_LOCKS;
1209 if (f->big_writes)
1210 f->conn.want |= FUSE_CAP_BIG_WRITES;
1211
1212 if (bufsize < FUSE_MIN_READ_BUFFER) {
1213 fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
1214 bufsize);
1215 bufsize = FUSE_MIN_READ_BUFFER;
1216 }
1217
1218 bufsize -= 4096;
1219 if (bufsize < f->conn.max_write)
1220 f->conn.max_write = bufsize;
1221
1222 f->got_init = 1;
1223 if (f->op.init)
1224 f->op.init(f->userdata, &f->conn);
1225
1226 if (f->conn.async_read || (f->conn.want & FUSE_CAP_ASYNC_READ))
1227 outarg.flags |= FUSE_ASYNC_READ;
1228 if (f->conn.want & FUSE_CAP_POSIX_LOCKS)
1229 outarg.flags |= FUSE_POSIX_LOCKS;
1230 if (f->conn.want & FUSE_CAP_ATOMIC_O_TRUNC)
1231 outarg.flags |= FUSE_ATOMIC_O_TRUNC;
1232 if (f->conn.want & FUSE_CAP_EXPORT_SUPPORT)
1233 outarg.flags |= FUSE_EXPORT_SUPPORT;
1234 if (f->conn.want & FUSE_CAP_BIG_WRITES)
1235 outarg.flags |= FUSE_BIG_WRITES;
1236 if (f->conn.want & FUSE_CAP_DONT_MASK)
1237 outarg.flags |= FUSE_DONT_MASK;
1238 outarg.max_readahead = f->conn.max_readahead;
1239 outarg.max_write = f->conn.max_write;
1240
1241 if (f->debug) {
1242 fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor);
1243 fprintf(stderr, " flags=0x%08x\n", outarg.flags);
1244 fprintf(stderr, " max_readahead=0x%08x\n",
1245 outarg.max_readahead);
1246 fprintf(stderr, " max_write=0x%08x\n", outarg.max_write);
1247 }
1248
1249 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
1250}
1251
1252static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1253{
1254 struct fuse_ll *f = req->f;
1255
1256 (void) nodeid;
1257 (void) inarg;
1258
1259 f->got_destroy = 1;
1260 if (f->op.destroy)
1261 f->op.destroy(f->userdata);
1262
1263 send_reply_ok(req, NULL, 0);
1264}
1265
1266static int send_notify_iov(struct fuse_ll *f, struct fuse_chan *ch,
1267 int notify_code, struct iovec *iov, int count)
1268{
1269 struct fuse_out_header out;
1270
1271 out.unique = 0;
1272 out.error = notify_code;
1273 iov[0].iov_base = &out;
1274 iov[0].iov_len = sizeof(struct fuse_out_header);
1275 out.len = iov_length(iov, count);
1276
1277 if (f->debug)
1278 fprintf(stderr, "NOTIFY: code=%d count=%d length=%u\n",
1279 notify_code, count, out.len);
1280
1281 return fuse_chan_send(ch, iov, count);
1282}
1283
1284int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
1285{
1286 if (ph != NULL) {
1287 struct fuse_notify_poll_wakeup_out outarg;
1288 struct iovec iov[2];
1289
1290 outarg.kh = ph->kh;
1291
1292 iov[1].iov_base = &outarg;
1293 iov[1].iov_len = sizeof(outarg);
1294
1295 return send_notify_iov(ph->f, ph->ch, FUSE_NOTIFY_POLL, iov, 2);
1296 } else {
1297 return 0;
1298 }
1299}
1300
1301int fuse_lowlevel_notify_inval_inode(struct fuse_chan *ch, fuse_ino_t ino,
1302 off64_t off, off64_t len)
1303{
1304 struct fuse_notify_inval_inode_out outarg;
1305 struct fuse_ll *f;
1306 struct iovec iov[2];
1307
1308 if (!ch)
1309 return -EINVAL;
1310
1311 f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
1312 if (!f)
1313 return -ENODEV;
1314
1315 outarg.ino = ino;
1316 outarg.off = off;
1317 outarg.len = len;
1318
1319 iov[1].iov_base = &outarg;
1320 iov[1].iov_len = sizeof(outarg);
1321
1322 return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_INODE, iov, 2);
1323}
1324
1325int fuse_lowlevel_notify_inval_entry(struct fuse_chan *ch, fuse_ino_t parent,
1326 const char *name, size_t namelen)
1327{
1328 struct fuse_notify_inval_entry_out outarg;
1329 struct fuse_ll *f;
1330 struct iovec iov[3];
1331
1332 if (!ch)
1333 return -EINVAL;
1334
1335 f = (struct fuse_ll *)fuse_session_data(fuse_chan_session(ch));
1336 if (!f)
1337 return -ENODEV;
1338
1339 outarg.parent = parent;
1340 outarg.namelen = namelen;
1341 outarg.padding = 0;
1342
1343 iov[1].iov_base = &outarg;
1344 iov[1].iov_len = sizeof(outarg);
1345 iov[2].iov_base = (void *)name;
1346 iov[2].iov_len = namelen + 1;
1347
1348 return send_notify_iov(f, ch, FUSE_NOTIFY_INVAL_ENTRY, iov, 3);
1349}
1350
1351void *fuse_req_userdata(fuse_req_t req)
1352{
1353 return req->f->userdata;
1354}
1355
1356const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
1357{
1358 return &req->ctx;
1359}
1360
1361/*
1362 * The size of fuse_ctx got extended, so need to be careful about
1363 * incompatibility (i.e. a new binary cannot work with an old
1364 * library).
1365 */
1366const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req);
1367const struct fuse_ctx *fuse_req_ctx_compat24(fuse_req_t req)
1368{
1369 return fuse_req_ctx(req);
1370}
1371FUSE_SYMVER(".symver fuse_req_ctx_compat24,fuse_req_ctx@FUSE_2.4");
1372
1373
1374void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
1375 void *data)
1376{
1377 pthread_mutex_lock(&req->lock);
1378 pthread_mutex_lock(&req->f->lock);
1379 req->u.ni.func = func;
1380 req->u.ni.data = data;
1381 pthread_mutex_unlock(&req->f->lock);
1382 if (req->interrupted && func)
1383 func(req, data);
1384 pthread_mutex_unlock(&req->lock);
1385}
1386
1387int fuse_req_interrupted(fuse_req_t req)
1388{
1389 int interrupted;
1390
1391 pthread_mutex_lock(&req->f->lock);
1392 interrupted = req->interrupted;
1393 pthread_mutex_unlock(&req->f->lock);
1394
1395 return interrupted;
1396}
1397
1398static struct {
1399 void (*func)(fuse_req_t, fuse_ino_t, const void *);
1400 const char *name;
1401} fuse_ll_ops[] = {
1402 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
1403 [FUSE_FORGET] = { do_forget, "FORGET" },
1404 [FUSE_GETATTR] = { do_getattr, "GETATTR" },
1405 [FUSE_SETATTR] = { do_setattr, "SETATTR" },
1406 [FUSE_READLINK] = { do_readlink, "READLINK" },
1407 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
1408 [FUSE_MKNOD] = { do_mknod, "MKNOD" },
1409 [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
1410 [FUSE_UNLINK] = { do_unlink, "UNLINK" },
1411 [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
1412 [FUSE_RENAME] = { do_rename, "RENAME" },
1413 [FUSE_LINK] = { do_link, "LINK" },
1414 [FUSE_OPEN] = { do_open, "OPEN" },
1415 [FUSE_READ] = { do_read, "READ" },
1416 [FUSE_WRITE] = { do_write, "WRITE" },
1417 [FUSE_STATFS] = { do_statfs, "STATFS" },
1418 [FUSE_RELEASE] = { do_release, "RELEASE" },
1419 [FUSE_FSYNC] = { do_fsync, "FSYNC" },
1420 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
1421 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
1422 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
1423 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
1424 [FUSE_FLUSH] = { do_flush, "FLUSH" },
1425 [FUSE_INIT] = { do_init, "INIT" },
1426 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
1427 [FUSE_READDIR] = { do_readdir, "READDIR" },
1428 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
1429 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
1430 [FUSE_GETLK] = { do_getlk, "GETLK" },
1431 [FUSE_SETLK] = { do_setlk, "SETLK" },
1432 [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
1433 [FUSE_ACCESS] = { do_access, "ACCESS" },
1434 [FUSE_CREATE] = { do_create, "CREATE" },
1435 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
1436 [FUSE_BMAP] = { do_bmap, "BMAP" },
1437 [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
1438 [FUSE_POLL] = { do_poll, "POLL" },
1439 [FUSE_DESTROY] = { do_destroy, "DESTROY" },
1440 [CUSE_INIT] = { cuse_lowlevel_init, "CUSE_INIT" },
1441};
1442
1443#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
1444
1445static const char *opname(enum fuse_opcode opcode)
1446{
1447 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
1448 return "???";
1449 else
1450 return fuse_ll_ops[opcode].name;
1451}
1452
1453static void fuse_ll_process(void *data, const char *buf, size_t len,
1454 struct fuse_chan *ch)
1455{
1456 struct fuse_ll *f = (struct fuse_ll *) data;
1457 struct fuse_in_header *in = (struct fuse_in_header *) buf;
1458 const void *inarg = buf + sizeof(struct fuse_in_header);
1459 struct fuse_req *req;
1460 int err;
1461
1462 if (f->debug)
1463 fprintf(stderr,
1464 "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n",
1465 (unsigned long long) in->unique,
1466 opname((enum fuse_opcode) in->opcode), in->opcode,
1467 (unsigned long) in->nodeid, len);
1468
1469 req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
1470 if (req == NULL) {
1471 fprintf(stderr, "fuse: failed to allocate request\n");
1472 return;
1473 }
1474
1475 req->f = f;
1476 req->unique = in->unique;
1477 req->ctx.uid = in->uid;
1478 req->ctx.gid = in->gid;
1479 req->ctx.pid = in->pid;
1480 req->ch = ch;
1481 req->ctr = 1;
1482 list_init_req(req);
1483 fuse_mutex_init(&req->lock);
1484
1485 err = EIO;
1486 if (!f->got_init) {
1487 enum fuse_opcode expected;
1488
1489 expected = f->cuse_data ? CUSE_INIT : FUSE_INIT;
1490 if (in->opcode != expected)
1491 goto reply_err;
1492 } else if (in->opcode == FUSE_INIT || in->opcode == CUSE_INIT)
1493 goto reply_err;
1494
1495 err = EACCES;
1496 if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
1497 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
1498 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
1499 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
1500 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR)
1501 goto reply_err;
1502
1503 err = ENOSYS;
1504 if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
1505 goto reply_err;
1506 if (in->opcode != FUSE_INTERRUPT) {
1507 struct fuse_req *intr;
1508 pthread_mutex_lock(&f->lock);
1509 intr = check_interrupt(f, req);
1510 list_add_req(req, &f->list);
1511 pthread_mutex_unlock(&f->lock);
1512 if (intr)
1513 fuse_reply_err(intr, EAGAIN);
1514 }
1515 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
1516 return;
1517
1518 reply_err:
1519 fuse_reply_err(req, err);
1520}
1521
1522enum {
1523 KEY_HELP,
1524 KEY_VERSION,
1525};
1526
1527static struct fuse_opt fuse_ll_opts[] = {
1528 { "debug", offsetof(struct fuse_ll, debug), 1 },
1529 { "-d", offsetof(struct fuse_ll, debug), 1 },
1530 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
1531 { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
1532 { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
1533 { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
1534 { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
1535 { "atomic_o_trunc", offsetof(struct fuse_ll, atomic_o_trunc), 1},
1536 { "no_remote_lock", offsetof(struct fuse_ll, no_remote_lock), 1},
1537 { "big_writes", offsetof(struct fuse_ll, big_writes), 1},
1538 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
1539 FUSE_OPT_KEY("-h", KEY_HELP),
1540 FUSE_OPT_KEY("--help", KEY_HELP),
1541 FUSE_OPT_KEY("-V", KEY_VERSION),
1542 FUSE_OPT_KEY("--version", KEY_VERSION),
1543 FUSE_OPT_END
1544};
1545
1546static void fuse_ll_version(void)
1547{
1548 fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
1549 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1550}
1551
1552static void fuse_ll_help(void)
1553{
1554 fprintf(stderr,
1555" -o max_write=N set maximum size of write requests\n"
1556" -o max_readahead=N set maximum readahead\n"
1557" -o async_read perform reads asynchronously (default)\n"
1558" -o sync_read perform reads synchronously\n"
1559" -o atomic_o_trunc enable atomic open+truncate support\n"
1560" -o big_writes enable larger than 4kB writes\n"
1561" -o no_remote_lock disable remote file locking\n");
1562}
1563
1564static int fuse_ll_opt_proc(void *data, const char *arg, int key,
1565 struct fuse_args *outargs)
1566{
1567 (void) data; (void) outargs;
1568
1569 switch (key) {
1570 case KEY_HELP:
1571 fuse_ll_help();
1572 break;
1573
1574 case KEY_VERSION:
1575 fuse_ll_version();
1576 break;
1577
1578 default:
1579 fprintf(stderr, "fuse: unknown option `%s'\n", arg);
1580 }
1581
1582 return -1;
1583}
1584
1585int fuse_lowlevel_is_lib_option(const char *opt)
1586{
1587 return fuse_opt_match(fuse_ll_opts, opt);
1588}
1589
1590static void fuse_ll_destroy(void *data)
1591{
1592 struct fuse_ll *f = (struct fuse_ll *) data;
1593
1594 if (f->got_init && !f->got_destroy) {
1595 if (f->op.destroy)
1596 f->op.destroy(f->userdata);
1597 }
1598
1599 pthread_mutex_destroy(&f->lock);
1600 free(f->cuse_data);
1601 free(f);
1602}
1603
1604/*
1605 * always call fuse_lowlevel_new_common() internally, to work around a
1606 * misfeature in the FreeBSD runtime linker, which links the old
1607 * version of a symbol to internal references.
1608 */
1609struct fuse_session *fuse_lowlevel_new_common(struct fuse_args *args,
1610 const struct fuse_lowlevel_ops *op,
1611 size_t op_size, void *userdata)
1612{
1613 struct fuse_ll *f;
1614 struct fuse_session *se;
1615 struct fuse_session_ops sop = {
1616 .process = fuse_ll_process,
1617 .destroy = fuse_ll_destroy,
1618 };
1619
1620 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
1621 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
1622 op_size = sizeof(struct fuse_lowlevel_ops);
1623 }
1624
1625 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
1626 if (f == NULL) {
1627 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1628 goto out;
1629 }
1630
1631 f->conn.async_read = 1;
1632 f->conn.max_write = UINT_MAX;
1633 f->conn.max_readahead = UINT_MAX;
1634 f->atomic_o_trunc = 0;
1635 list_init_req(&f->list);
1636 list_init_req(&f->interrupts);
1637 fuse_mutex_init(&f->lock);
1638
1639 if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
1640 goto out_free;
1641
1642 if (f->debug)
1643 fprintf(stderr, "FUSE library version: %s\n", PACKAGE_VERSION);
1644
1645 memcpy(&f->op, op, op_size);
1646 f->owner = getuid();
1647 f->userdata = userdata;
1648
1649 se = fuse_session_new(&sop, f);
1650 if (!se)
1651 goto out_free;
1652
1653 return se;
1654
1655out_free:
1656 free(f);
1657out:
1658 return NULL;
1659}
1660
1661
1662struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
1663 const struct fuse_lowlevel_ops *op,
1664 size_t op_size, void *userdata)
1665{
1666 return fuse_lowlevel_new_common(args, op, op_size, userdata);
1667}
1668
1669#ifdef linux
1670int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
1671{
1672 char *buf;
1673 size_t bufsize = 1024;
1674 char path[128];
1675 int ret;
1676 int fd;
1677 unsigned long pid = req->ctx.pid;
1678 char *s;
1679
1680 sprintf(path, "/proc/%lu/task/%lu/status", pid, pid);
1681
1682retry:
1683 buf = malloc(bufsize);
1684 if (buf == NULL)
1685 return -ENOMEM;
1686
1687 ret = -EIO;
1688 fd = open(path, O_RDONLY);
1689 if (fd == -1)
1690 goto out_free;
1691
1692 ret = read(fd, buf, bufsize);
1693 close(fd);
1694 if (ret == -1) {
1695 ret = -EIO;
1696 goto out_free;
1697 }
1698
1699 if (ret == bufsize) {
1700 free(buf);
1701 bufsize *= 4;
1702 goto retry;
1703 }
1704
1705 ret = -EIO;
1706 s = strstr(buf, "\nGroups:");
1707 if (s == NULL)
1708 goto out_free;
1709
1710 s += 8;
1711 ret = 0;
1712 while (1) {
1713 char *end;
1714 unsigned long val = strtoul(s, &end, 0);
1715 if (end == s)
1716 break;
1717
1718 s = end;
1719 if (ret < size)
1720 list[ret] = val;
1721 ret++;
1722 }
1723
1724out_free:
1725 free(buf);
1726 return ret;
1727}
1728#else /* linux */
1729/*
1730 * This is currently not implemented on other than Linux...
1731 */
1732int fuse_req_getgroups(fuse_req_t req, int size, gid_t list[])
1733{
1734 return -ENOSYS;
1735}
1736#endif
1737
1738#ifndef __FreeBSD__
1739
1740static void fill_open_compat(struct fuse_open_out *arg,
1741 const struct fuse_file_info_compat *f)
1742{
1743 arg->fh = f->fh;
1744 if (f->direct_io)
1745 arg->open_flags |= FOPEN_DIRECT_IO;
1746 if (f->keep_cache)
1747 arg->open_flags |= FOPEN_KEEP_CACHE;
1748}
1749
1750static void convert_statfs_compat(const struct statfs *compatbuf,
1751 struct statvfs *buf)
1752{
1753 buf->f_bsize = compatbuf->f_bsize;
1754 buf->f_blocks = compatbuf->f_blocks;
1755 buf->f_bfree = compatbuf->f_bfree;
1756 buf->f_bavail = compatbuf->f_bavail;
1757 buf->f_files = compatbuf->f_files;
1758 buf->f_ffree = compatbuf->f_ffree;
1759 buf->f_namemax = compatbuf->f_namelen;
1760}
1761
1762int fuse_reply_open_compat(fuse_req_t req,
1763 const struct fuse_file_info_compat *f)
1764{
1765 struct fuse_open_out arg;
1766
1767 memset(&arg, 0, sizeof(arg));
1768 fill_open_compat(&arg, f);
1769 return send_reply_ok(req, &arg, sizeof(arg));
1770}
1771
1772int fuse_reply_statfs_compat(fuse_req_t req, const struct statfs *stbuf)
1773{
1774 struct statvfs newbuf;
1775
1776 memset(&newbuf, 0, sizeof(newbuf));
1777 convert_statfs_compat(stbuf, &newbuf);
1778
1779 return fuse_reply_statfs(req, &newbuf);
1780}
1781
1782struct fuse_session *fuse_lowlevel_new_compat(const char *opts,
1783 const struct fuse_lowlevel_ops_compat *op,
1784 size_t op_size, void *userdata)
1785{
1786 struct fuse_session *se;
1787 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
1788
1789 if (opts &&
1790 (fuse_opt_add_arg(&args, "") == -1 ||
1791 fuse_opt_add_arg(&args, "-o") == -1 ||
1792 fuse_opt_add_arg(&args, opts) == -1)) {
1793 fuse_opt_free_args(&args);
1794 return NULL;
1795 }
1796 se = fuse_lowlevel_new(&args, (const struct fuse_lowlevel_ops *) op,
1797 op_size, userdata);
1798 fuse_opt_free_args(&args);
1799
1800 return se;
1801}
1802
1803struct fuse_ll_compat_conf {
1804 unsigned max_read;
1805 int set_max_read;
1806};
1807
1808static const struct fuse_opt fuse_ll_opts_compat[] = {
1809 { "max_read=", offsetof(struct fuse_ll_compat_conf, set_max_read), 1 },
1810 { "max_read=%u", offsetof(struct fuse_ll_compat_conf, max_read), 0 },
1811 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_KEEP),
1812 FUSE_OPT_END
1813};
1814
1815int fuse_sync_compat_args(struct fuse_args *args)
1816{
1817 struct fuse_ll_compat_conf conf;
1818
1819 memset(&conf, 0, sizeof(conf));
1820 if (fuse_opt_parse(args, &conf, fuse_ll_opts_compat, NULL) == -1)
1821 return -1;
1822
1823 if (fuse_opt_insert_arg(args, 1, "-osync_read"))
1824 return -1;
1825
1826 if (conf.set_max_read) {
1827 char tmpbuf[64];
1828
1829 sprintf(tmpbuf, "-omax_readahead=%u", conf.max_read);
1830 if (fuse_opt_insert_arg(args, 1, tmpbuf) == -1)
1831 return -1;
1832 }
1833 return 0;
1834}
1835
1836FUSE_SYMVER(".symver fuse_reply_statfs_compat,fuse_reply_statfs@FUSE_2.4");
1837FUSE_SYMVER(".symver fuse_reply_open_compat,fuse_reply_open@FUSE_2.4");
1838FUSE_SYMVER(".symver fuse_lowlevel_new_compat,fuse_lowlevel_new@FUSE_2.4");
1839
1840#else /* __FreeBSD__ */
1841
1842int fuse_sync_compat_args(struct fuse_args *args)
1843{
1844 (void) args;
1845 return 0;
1846}
1847
1848#endif /* __FreeBSD__ */
1849
1850struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args,
1851 const struct fuse_lowlevel_ops_compat25 *op,
1852 size_t op_size, void *userdata)
1853{
1854 if (fuse_sync_compat_args(args) == -1)
1855 return NULL;
1856
1857 return fuse_lowlevel_new_common(args,
1858 (const struct fuse_lowlevel_ops *) op,
1859 op_size, userdata);
1860}
1861
1862FUSE_SYMVER(".symver fuse_lowlevel_new_compat25,fuse_lowlevel_new@FUSE_2.5");