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