1 /*
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 "config.h"
10 #include "fuse_lowlevel.h"
11 #include "fuse_kernel.h"
12 #include "fuse_opt.h"
13 #include "fuse_i.h"
14 #include "fuse_misc.h"
15 #include "fuse_lowlevel_compat.h"
16
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 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
27 #endif
28 #ifdef MAJOR_IN_MKDEV
29 #include <sys/mkdev.h>
30 #endif
31 #ifdef MAJOR_IN_SYSMACROS
32 #include <sys/sysmacros.h>
33 #endif
34
35 #define PARAM(inarg) (((const char *)(inarg)) + sizeof(*(inarg)))
36 #define OFFSET_MAX 0x7fffffffffffffffLL
37
38 struct fuse_ll;
39
40 struct fuse_req {
41 struct fuse_ll *f;
42 uint64_t unique;
43 int ctr;
44 pthread_mutex_t lock;
45 struct fuse_ctx ctx;
46 struct fuse_chan *ch;
47 int interrupted;
48 union {
49 struct {
50 uint64_t unique;
51 } i;
52 struct {
53 fuse_interrupt_func_t func;
54 void *data;
55 } ni;
56 } u;
57 struct fuse_req *next;
58 struct fuse_req *prev;
59 };
60
61 struct fuse_ll {
62 int debug;
63 int allow_root;
64 struct fuse_lowlevel_ops op;
65 int got_init;
66 void *userdata;
67 uid_t owner;
68 struct fuse_conn_info conn;
69 struct fuse_req list;
70 struct fuse_req interrupts;
71 pthread_mutex_t lock;
72 int got_destroy;
73 };
74
convert_stat(const struct stat * stbuf,struct fuse_attr * attr)75 static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
76 {
77 attr->ino = stbuf->st_ino;
78 attr->mode = stbuf->st_mode;
79 attr->nlink = stbuf->st_nlink;
80 attr->uid = stbuf->st_uid;
81 attr->gid = stbuf->st_gid;
82 #if defined(__SOLARIS__) && defined(_LP64)
83 /* Must pack the device the old way (attr->rdev limited to 32 bits) */
84 attr->rdev = ((major(stbuf->st_rdev) & 0x3fff) << 18)
85 | (minor(stbuf->st_rdev) & 0x3ffff);
86 #else
87 attr->rdev = stbuf->st_rdev;
88 #endif
89 attr->size = stbuf->st_size;
90 attr->blocks = stbuf->st_blocks;
91 attr->atime = stbuf->st_atime;
92 attr->mtime = stbuf->st_mtime;
93 attr->ctime = stbuf->st_ctime;
94 attr->atimensec = ST_ATIM_NSEC(stbuf);
95 attr->mtimensec = ST_MTIM_NSEC(stbuf);
96 attr->ctimensec = ST_CTIM_NSEC(stbuf);
97 #ifdef POSIXACLS
98 attr->filling = 0; /* JPA trying to be safe */
99 #endif
100 }
101
convert_attr(const struct fuse_setattr_in * attr,struct stat * stbuf)102 static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
103 {
104 stbuf->st_mode = attr->mode;
105 stbuf->st_uid = attr->uid;
106 stbuf->st_gid = attr->gid;
107 stbuf->st_size = attr->size;
108 stbuf->st_atime = attr->atime;
109 stbuf->st_mtime = attr->mtime;
110 ST_ATIM_NSEC_SET(stbuf, attr->atimensec);
111 ST_MTIM_NSEC_SET(stbuf, attr->mtimensec);
112 }
113
iov_length(const struct iovec * iov,size_t count)114 static size_t iov_length(const struct iovec *iov, size_t count)
115 {
116 size_t seg;
117 size_t ret = 0;
118
119 for (seg = 0; seg < count; seg++)
120 ret += iov[seg].iov_len;
121 return ret;
122 }
123
list_init_req(struct fuse_req * req)124 static void list_init_req(struct fuse_req *req)
125 {
126 req->next = req;
127 req->prev = req;
128 }
129
list_del_req(struct fuse_req * req)130 static void list_del_req(struct fuse_req *req)
131 {
132 struct fuse_req *prev = req->prev;
133 struct fuse_req *next = req->next;
134 prev->next = next;
135 next->prev = prev;
136 }
137
list_add_req(struct fuse_req * req,struct fuse_req * next)138 static void list_add_req(struct fuse_req *req, struct fuse_req *next)
139 {
140 struct fuse_req *prev = next->prev;
141 req->next = next;
142 req->prev = prev;
143 prev->next = req;
144 next->prev = req;
145 }
146
destroy_req(fuse_req_t req)147 static void destroy_req(fuse_req_t req)
148 {
149 pthread_mutex_destroy(&req->lock);
150 free(req);
151 }
152
free_req(fuse_req_t req)153 static void free_req(fuse_req_t req)
154 {
155 int ctr;
156 struct fuse_ll *f = req->f;
157
158 pthread_mutex_lock(&req->lock);
159 req->u.ni.func = NULL;
160 req->u.ni.data = NULL;
161 pthread_mutex_unlock(&req->lock);
162
163 pthread_mutex_lock(&f->lock);
164 list_del_req(req);
165 ctr = --req->ctr;
166 pthread_mutex_unlock(&f->lock);
167 if (!ctr)
168 destroy_req(req);
169 }
170
send_reply_iov(fuse_req_t req,int error,struct iovec * iov,int count)171 static int send_reply_iov(fuse_req_t req, int error, struct iovec *iov,
172 int count)
173 {
174 struct fuse_out_header out;
175 int res;
176
177 if (error <= -1000 || error > 0) {
178 fprintf(stderr, "fuse: bad error value: %i\n", error);
179 error = -ERANGE;
180 }
181
182 out.unique = req->unique;
183 out.error = error;
184 iov[0].iov_base = &out;
185 iov[0].iov_len = sizeof(struct fuse_out_header);
186 out.len = iov_length(iov, count);
187
188 if (req->f->debug)
189 fprintf(stderr, " unique: %llu, error: %i (%s), outsize: %i\n",
190 (unsigned long long) out.unique, out.error,
191 strerror(-out.error), out.len);
192 res = fuse_chan_send(req->ch, iov, count);
193 free_req(req);
194
195 return res;
196 }
197
send_reply(fuse_req_t req,int error,const void * arg,size_t argsize)198 static int send_reply(fuse_req_t req, int error, const void *arg,
199 size_t argsize)
200 {
201 struct iovec iov[2];
202 int count = 1;
203 if (argsize) {
204 /* Note : const qualifier dropped */
205 iov[1].iov_base = (void *)(uintptr_t) arg;
206 iov[1].iov_len = argsize;
207 count++;
208 }
209 return send_reply_iov(req, error, iov, count);
210 }
211
212 #if 0 /* not used */
213 int fuse_reply_iov(fuse_req_t req, const struct iovec *iov, int count)
214 {
215 int res;
216 struct iovec *padded_iov;
217
218 padded_iov = malloc((count + 1) * sizeof(struct iovec));
219 if (padded_iov == NULL)
220 return fuse_reply_err(req, -ENOMEM);
221
222 memcpy(padded_iov + 1, iov, count * sizeof(struct iovec));
223 count++;
224
225 res = send_reply_iov(req, 0, padded_iov, count);
226 free(padded_iov);
227
228 return res;
229 }
230 #endif
231
fuse_dirent_size(size_t namelen)232 size_t fuse_dirent_size(size_t namelen)
233 {
234 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
235 }
236
fuse_add_dirent(char * buf,const char * name,const struct stat * stbuf,off_t off)237 char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
238 off_t off)
239 {
240 unsigned namelen = strlen(name);
241 unsigned entlen = FUSE_NAME_OFFSET + namelen;
242 unsigned entsize = fuse_dirent_size(namelen);
243 unsigned padlen = entsize - entlen;
244 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
245
246 dirent->ino = stbuf->st_ino;
247 dirent->off = off;
248 dirent->namelen = namelen;
249 dirent->type = (stbuf->st_mode & 0170000) >> 12;
250 memcpy(dirent->name, name, namelen);
251 if (padlen)
252 memset(buf + entlen, 0, padlen);
253
254 return buf + entsize;
255 }
256
fuse_add_direntry(fuse_req_t req,char * buf,size_t bufsize,const char * name,const struct stat * stbuf,off_t off)257 size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
258 const char *name, const struct stat *stbuf, off_t off)
259 {
260 size_t entsize;
261
262 (void) req;
263 entsize = fuse_dirent_size(strlen(name));
264 if (entsize <= bufsize && buf)
265 fuse_add_dirent(buf, name, stbuf, off);
266 return entsize;
267 }
268
convert_statfs(const struct statvfs * stbuf,struct fuse_kstatfs * kstatfs)269 static void convert_statfs(const struct statvfs *stbuf,
270 struct fuse_kstatfs *kstatfs)
271 {
272 kstatfs->bsize = stbuf->f_bsize;
273 kstatfs->frsize = stbuf->f_frsize;
274 kstatfs->blocks = stbuf->f_blocks;
275 kstatfs->bfree = stbuf->f_bfree;
276 kstatfs->bavail = stbuf->f_bavail;
277 kstatfs->files = stbuf->f_files;
278 kstatfs->ffree = stbuf->f_ffree;
279 kstatfs->namelen = stbuf->f_namemax;
280 }
281
send_reply_ok(fuse_req_t req,const void * arg,size_t argsize)282 static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
283 {
284 return send_reply(req, 0, arg, argsize);
285 }
286
fuse_reply_err(fuse_req_t req,int err)287 int fuse_reply_err(fuse_req_t req, int err)
288 {
289 return send_reply(req, -err, NULL, 0);
290 }
291
fuse_reply_none(fuse_req_t req)292 void fuse_reply_none(fuse_req_t req)
293 {
294 fuse_chan_send(req->ch, NULL, 0);
295 free_req(req);
296 }
297
calc_timeout_sec(double t)298 static unsigned long calc_timeout_sec(double t)
299 {
300 if (t > (double) ULONG_MAX)
301 return ULONG_MAX;
302 else if (t < 0.0)
303 return 0;
304 else
305 return (unsigned long) t;
306 }
307
calc_timeout_nsec(double t)308 static unsigned int calc_timeout_nsec(double t)
309 {
310 unsigned long secs = calc_timeout_sec(t);
311 double f = t - (double)secs;
312 if (f < 0.0)
313 return 0;
314 else if (f >= 0.999999999)
315 return 999999999;
316 else
317 return (unsigned int) (f * 1.0e9);
318 }
319
fill_entry(struct fuse_entry_out * arg,const struct fuse_entry_param * e)320 static void fill_entry(struct fuse_entry_out *arg,
321 const struct fuse_entry_param *e)
322 {
323 arg->nodeid = e->ino;
324 arg->generation = e->generation;
325 arg->entry_valid = calc_timeout_sec(e->entry_timeout);
326 arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
327 arg->attr_valid = calc_timeout_sec(e->attr_timeout);
328 arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
329 convert_stat(&e->attr, &arg->attr);
330 }
331
fill_open(struct fuse_open_out * arg,const struct fuse_file_info * f)332 static void fill_open(struct fuse_open_out *arg,
333 const struct fuse_file_info *f)
334 {
335 arg->fh = f->fh;
336 if (f->direct_io)
337 arg->open_flags |= FOPEN_DIRECT_IO;
338 if (f->keep_cache)
339 arg->open_flags |= FOPEN_KEEP_CACHE;
340 }
341
fuse_reply_entry(fuse_req_t req,const struct fuse_entry_param * e)342 int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
343 {
344 struct fuse_entry_out arg;
345
346 /* before ABI 7.4 e->ino == 0 was invalid, only ENOENT meant
347 negative entry */
348 if (!e->ino && req->f->conn.proto_minor < 4)
349 return fuse_reply_err(req, ENOENT);
350
351 memset(&arg, 0, sizeof(arg));
352 fill_entry(&arg, e);
353 return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
354 ? sizeof(arg) : FUSE_COMPAT_ENTRY_OUT_SIZE));
355 }
356
fuse_reply_create(fuse_req_t req,const struct fuse_entry_param * e,const struct fuse_file_info * f)357 int fuse_reply_create(fuse_req_t req, const struct fuse_entry_param *e,
358 const struct fuse_file_info *f)
359 {
360 struct {
361 struct fuse_entry_out e;
362 struct fuse_open_out o;
363 } arg;
364
365 memset(&arg, 0, sizeof(arg));
366 fill_entry(&arg.e, e);
367 if (req->f->conn.proto_minor < 12) {
368 fill_open((struct fuse_open_out*)
369 ((char*)&arg + FUSE_COMPAT_ENTRY_OUT_SIZE), f);
370 return send_reply_ok(req, &arg,
371 FUSE_COMPAT_ENTRY_OUT_SIZE + sizeof(struct fuse_open_out));
372 } else {
373 fill_open(&arg.o, f);
374 return send_reply_ok(req, &arg, sizeof(arg));
375 }
376 }
377
fuse_reply_attr(fuse_req_t req,const struct stat * attr,double attr_timeout)378 int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
379 double attr_timeout)
380 {
381 struct fuse_attr_out arg;
382
383 memset(&arg, 0, sizeof(arg));
384 arg.attr_valid = calc_timeout_sec(attr_timeout);
385 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
386 convert_stat(attr, &arg.attr);
387
388 return send_reply_ok(req, &arg, (req->f->conn.proto_minor >= 12
389 ? sizeof(arg) : FUSE_COMPAT_FUSE_ATTR_OUT_SIZE));
390 }
391
fuse_reply_readlink(fuse_req_t req,const char * linkname)392 int fuse_reply_readlink(fuse_req_t req, const char *linkname)
393 {
394 return send_reply_ok(req, linkname, strlen(linkname));
395 }
396
fuse_reply_open(fuse_req_t req,const struct fuse_file_info * f)397 int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
398 {
399 struct fuse_open_out arg;
400
401 memset(&arg, 0, sizeof(arg));
402 fill_open(&arg, f);
403 return send_reply_ok(req, &arg, sizeof(arg));
404 }
405
fuse_reply_write(fuse_req_t req,size_t count)406 int fuse_reply_write(fuse_req_t req, size_t count)
407 {
408 struct fuse_write_out arg;
409
410 memset(&arg, 0, sizeof(arg));
411 arg.size = count;
412
413 return send_reply_ok(req, &arg, sizeof(arg));
414 }
415
fuse_reply_buf(fuse_req_t req,const char * buf,size_t size)416 int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
417 {
418 return send_reply_ok(req, buf, size);
419 }
420
fuse_reply_statfs(fuse_req_t req,const struct statvfs * stbuf)421 int fuse_reply_statfs(fuse_req_t req, const struct statvfs *stbuf)
422 {
423 struct fuse_statfs_out arg;
424 size_t size = req->f->conn.proto_minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(arg);
425
426 memset(&arg, 0, sizeof(arg));
427 convert_statfs(stbuf, &arg.st);
428
429 return send_reply_ok(req, &arg, size);
430 }
431
fuse_reply_xattr(fuse_req_t req,size_t count)432 int fuse_reply_xattr(fuse_req_t req, size_t count)
433 {
434 struct fuse_getxattr_out arg;
435
436 memset(&arg, 0, sizeof(arg));
437 arg.size = count;
438
439 return send_reply_ok(req, &arg, sizeof(arg));
440 }
441
fuse_reply_lock(fuse_req_t req,struct flock * lock)442 int fuse_reply_lock(fuse_req_t req, struct flock *lock)
443 {
444 struct fuse_lk_out arg;
445
446 memset(&arg, 0, sizeof(arg));
447 arg.lk.type = lock->l_type;
448 if (lock->l_type != F_UNLCK) {
449 arg.lk.start = lock->l_start;
450 if (lock->l_len == 0)
451 arg.lk.end = OFFSET_MAX;
452 else
453 arg.lk.end = lock->l_start + lock->l_len - 1;
454 }
455 arg.lk.pid = lock->l_pid;
456 return send_reply_ok(req, &arg, sizeof(arg));
457 }
458
fuse_reply_bmap(fuse_req_t req,uint64_t idx)459 int fuse_reply_bmap(fuse_req_t req, uint64_t idx)
460 {
461 struct fuse_bmap_out arg;
462
463 memset(&arg, 0, sizeof(arg));
464 arg.block = idx;
465
466 return send_reply_ok(req, &arg, sizeof(arg));
467 }
468
fuse_reply_ioctl(fuse_req_t req,int result,const void * buf,size_t size)469 int fuse_reply_ioctl(fuse_req_t req, int result, const void *buf, size_t size)
470 {
471 struct fuse_ioctl_out arg;
472 struct iovec iov[3];
473 size_t count = 1;
474
475 memset(&arg, 0, sizeof(arg));
476 arg.result = result;
477 iov[count].iov_base = &arg;
478 iov[count].iov_len = sizeof(arg);
479 count++;
480
481 if (size) {
482 /* Note : const qualifier dropped */
483 iov[count].iov_base = (char *)(uintptr_t) buf;
484 iov[count].iov_len = size;
485 count++;
486 }
487
488 return send_reply_iov(req, 0, iov, count);
489 }
490
do_lookup(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)491 static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
492 {
493 const char *name = (const char *) inarg;
494
495 if (req->f->op.lookup)
496 req->f->op.lookup(req, nodeid, name);
497 else
498 fuse_reply_err(req, ENOSYS);
499 }
500
do_forget(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)501 static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
502 {
503 const struct fuse_forget_in *arg = (const struct fuse_forget_in *) inarg;
504
505 if (req->f->op.forget)
506 req->f->op.forget(req, nodeid, arg->nlookup);
507 else
508 fuse_reply_none(req);
509 }
510
do_getattr(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)511 static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
512 {
513 (void) inarg;
514
515 if (req->f->op.getattr)
516 req->f->op.getattr(req, nodeid, NULL);
517 else
518 fuse_reply_err(req, ENOSYS);
519 }
520
do_setattr(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)521 static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
522 {
523 const struct fuse_setattr_in *arg = (const struct fuse_setattr_in *) inarg;
524
525 if (req->f->op.setattr) {
526 struct fuse_file_info *fi = NULL;
527 struct fuse_file_info fi_store;
528 struct stat stbuf;
529 memset(&stbuf, 0, sizeof(stbuf));
530 convert_attr(arg, &stbuf);
531 if (arg->valid & FATTR_FH) {
532 memset(&fi_store, 0, sizeof(fi_store));
533 fi = &fi_store;
534 fi->fh = arg->fh;
535 fi->fh_old = fi->fh;
536 }
537 req->f->op.setattr(req, nodeid, &stbuf, arg->valid & ~FATTR_FH, fi);
538 } else
539 fuse_reply_err(req, ENOSYS);
540 }
541
do_access(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)542 static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
543 {
544 const struct fuse_access_in *arg = (const struct fuse_access_in *) inarg;
545
546 if (req->f->op.access)
547 req->f->op.access(req, nodeid, arg->mask);
548 else
549 fuse_reply_err(req, ENOSYS);
550 }
551
do_readlink(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)552 static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
553 {
554 (void) inarg;
555
556 if (req->f->op.readlink)
557 req->f->op.readlink(req, nodeid);
558 else
559 fuse_reply_err(req, ENOSYS);
560 }
561
do_mknod(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)562 static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
563 {
564 const struct fuse_mknod_in *arg = (const struct fuse_mknod_in *) inarg;
565 const char *name = PARAM(arg);
566
567 if (req->f->conn.proto_minor >= 12)
568 req->ctx.umask = arg->umask;
569 else
570 name = (const char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE;
571
572 if (req->f->op.mknod) {
573 #if defined(__SOLARIS__) && defined(_LP64)
574 /*
575 * Must unpack the device, as arg->rdev is limited to 32 bits,
576 * and must have the same format in 32-bit and 64-bit builds.
577 */
578 req->f->op.mknod(req, nodeid, name, arg->mode,
579 makedev((arg->rdev >> 18) & 0x3fff,
580 arg->rdev & 0x3ffff));
581 #else
582 req->f->op.mknod(req, nodeid, name, arg->mode, arg->rdev);
583 #endif
584 } else
585 fuse_reply_err(req, ENOSYS);
586 }
587
do_mkdir(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)588 static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
589 {
590 const struct fuse_mkdir_in *arg = (const struct fuse_mkdir_in *) inarg;
591
592 if (req->f->conn.proto_minor >= 12)
593 req->ctx.umask = arg->umask;
594
595 if (req->f->op.mkdir)
596 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
597 else
598 fuse_reply_err(req, ENOSYS);
599 }
600
do_unlink(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)601 static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
602 {
603 const char *name = (const char *) inarg;
604
605 if (req->f->op.unlink)
606 req->f->op.unlink(req, nodeid, name);
607 else
608 fuse_reply_err(req, ENOSYS);
609 }
610
do_rmdir(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)611 static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
612 {
613 const char *name = (const char *) inarg;
614
615 if (req->f->op.rmdir)
616 req->f->op.rmdir(req, nodeid, name);
617 else
618 fuse_reply_err(req, ENOSYS);
619 }
620
do_symlink(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)621 static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
622 {
623 const char *name = (const char *) inarg;
624 const char *linkname = ((const char *) inarg) + strlen((const char *) inarg) + 1;
625
626 if (req->f->op.symlink)
627 req->f->op.symlink(req, linkname, nodeid, name);
628 else
629 fuse_reply_err(req, ENOSYS);
630 }
631
do_rename(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)632 static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
633 {
634 const struct fuse_rename_in *arg = (const struct fuse_rename_in *) inarg;
635 const char *oldname = PARAM(arg);
636 const char *newname = oldname + strlen(oldname) + 1;
637
638 if (req->f->op.rename)
639 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
640 else
641 fuse_reply_err(req, ENOSYS);
642 }
643
do_link(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)644 static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
645 {
646 const struct fuse_link_in *arg = (const struct fuse_link_in *) inarg;
647
648 if (req->f->op.link)
649 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
650 else
651 fuse_reply_err(req, ENOSYS);
652 }
653
do_create(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)654 static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
655 {
656 const struct fuse_create_in *arg = (const struct fuse_create_in *) inarg;
657
658 if (req->f->op.create) {
659 struct fuse_file_info fi;
660 const char *name = PARAM(arg);
661
662 memset(&fi, 0, sizeof(fi));
663 fi.flags = arg->flags;
664
665 if (req->f->conn.proto_minor >= 12)
666 req->ctx.umask = arg->umask;
667 else
668 name = (const char *) inarg + sizeof(struct fuse_open_in);
669
670 req->f->op.create(req, nodeid, name, arg->mode, &fi);
671 } else
672 fuse_reply_err(req, ENOSYS);
673 }
674
do_open(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)675 static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
676 {
677 const struct fuse_open_in *arg = (const struct fuse_open_in *) inarg;
678 struct fuse_file_info fi;
679
680 memset(&fi, 0, sizeof(fi));
681 fi.flags = arg->flags;
682
683 if (req->f->op.open)
684 req->f->op.open(req, nodeid, &fi);
685 else
686 fuse_reply_open(req, &fi);
687 }
688
do_read(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)689 static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
690 {
691 const struct fuse_read_in *arg = (const struct fuse_read_in *) inarg;
692
693 if (req->f->op.read) {
694 struct fuse_file_info fi;
695
696 memset(&fi, 0, sizeof(fi));
697 fi.fh = arg->fh;
698 fi.fh_old = fi.fh;
699 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
700 } else
701 fuse_reply_err(req, ENOSYS);
702 }
703
do_write(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)704 static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
705 {
706 const struct fuse_write_in *arg = (const struct fuse_write_in *) inarg;
707 struct fuse_file_info fi;
708
709 memset(&fi, 0, sizeof(fi));
710 fi.fh = arg->fh;
711 fi.fh_old = fi.fh;
712 fi.writepage = arg->write_flags & 1;
713
714 if (req->f->op.write) {
715 const char *buf;
716
717 if (req->f->conn.proto_minor >= 12)
718 buf = PARAM(arg);
719 else
720 buf = ((const char*)arg) + FUSE_COMPAT_WRITE_IN_SIZE;
721 req->f->op.write(req, nodeid, buf, arg->size, arg->offset, &fi);
722 } else
723 fuse_reply_err(req, ENOSYS);
724 }
725
do_flush(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)726 static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
727 {
728 const struct fuse_flush_in *arg = (const struct fuse_flush_in *) inarg;
729 struct fuse_file_info fi;
730
731 memset(&fi, 0, sizeof(fi));
732 fi.fh = arg->fh;
733 fi.fh_old = fi.fh;
734 fi.flush = 1;
735 if (req->f->conn.proto_minor >= 7)
736 fi.lock_owner = arg->lock_owner;
737
738 if (req->f->op.flush)
739 req->f->op.flush(req, nodeid, &fi);
740 else
741 fuse_reply_err(req, ENOSYS);
742 }
743
do_release(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)744 static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
745 {
746 const struct fuse_release_in *arg = (const struct fuse_release_in *) inarg;
747 struct fuse_file_info fi;
748
749 memset(&fi, 0, sizeof(fi));
750 fi.flags = arg->flags;
751 fi.fh = arg->fh;
752 fi.fh_old = fi.fh;
753 if (req->f->conn.proto_minor >= 8) {
754 fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
755 fi.lock_owner = arg->lock_owner;
756 }
757
758 if (req->f->op.release)
759 req->f->op.release(req, nodeid, &fi);
760 else
761 fuse_reply_err(req, 0);
762 }
763
do_fsync(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)764 static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
765 {
766 const struct fuse_fsync_in *arg = (const struct fuse_fsync_in *) inarg;
767 struct fuse_file_info fi;
768
769 memset(&fi, 0, sizeof(fi));
770 fi.fh = arg->fh;
771 fi.fh_old = fi.fh;
772
773 if (req->f->op.fsync)
774 req->f->op.fsync(req, nodeid, arg->fsync_flags & 1, &fi);
775 else
776 fuse_reply_err(req, ENOSYS);
777 }
778
do_opendir(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)779 static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
780 {
781 const struct fuse_open_in *arg = (const struct fuse_open_in *) inarg;
782 struct fuse_file_info fi;
783
784 memset(&fi, 0, sizeof(fi));
785 fi.flags = arg->flags;
786
787 if (req->f->op.opendir)
788 req->f->op.opendir(req, nodeid, &fi);
789 else
790 fuse_reply_open(req, &fi);
791 }
792
do_readdir(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)793 static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
794 {
795 const struct fuse_read_in *arg = (const struct fuse_read_in *) inarg;
796 struct fuse_file_info fi;
797
798 memset(&fi, 0, sizeof(fi));
799 fi.fh = arg->fh;
800 fi.fh_old = fi.fh;
801
802 if (req->f->op.readdir)
803 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
804 else
805 fuse_reply_err(req, ENOSYS);
806 }
807
do_releasedir(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)808 static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
809 {
810 const struct fuse_release_in *arg = (const struct fuse_release_in *) inarg;
811 struct fuse_file_info fi;
812
813 memset(&fi, 0, sizeof(fi));
814 fi.flags = arg->flags;
815 fi.fh = arg->fh;
816 fi.fh_old = fi.fh;
817
818 if (req->f->op.releasedir)
819 req->f->op.releasedir(req, nodeid, &fi);
820 else
821 fuse_reply_err(req, 0);
822 }
823
do_fsyncdir(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)824 static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
825 {
826 const struct fuse_fsync_in *arg = (const struct fuse_fsync_in *) inarg;
827 struct fuse_file_info fi;
828
829 memset(&fi, 0, sizeof(fi));
830 fi.fh = arg->fh;
831 fi.fh_old = fi.fh;
832
833 if (req->f->op.fsyncdir)
834 req->f->op.fsyncdir(req, nodeid, arg->fsync_flags & 1, &fi);
835 else
836 fuse_reply_err(req, ENOSYS);
837 }
838
do_statfs(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)839 static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
840 {
841 (void) nodeid;
842 (void) inarg;
843
844 if (req->f->op.statfs)
845 req->f->op.statfs(req, nodeid);
846 else {
847 struct statvfs buf = {
848 .f_namemax = 255,
849 .f_bsize = 512,
850 };
851 fuse_reply_statfs(req, &buf);
852 }
853 }
854
do_setxattr(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)855 static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
856 {
857 const struct fuse_setxattr_in *arg = (const struct fuse_setxattr_in *) inarg;
858 const char *name = PARAM(arg);
859 const char *value = name + strlen(name) + 1;
860
861 if (req->f->op.setxattr)
862 req->f->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
863 else
864 fuse_reply_err(req, ENOSYS);
865 }
866
do_getxattr(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)867 static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
868 {
869 const struct fuse_getxattr_in *arg = (const struct fuse_getxattr_in *) inarg;
870
871 if (req->f->op.getxattr)
872 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
873 else
874 fuse_reply_err(req, ENOSYS);
875 }
876
do_listxattr(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)877 static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
878 {
879 const struct fuse_getxattr_in *arg = (const struct fuse_getxattr_in *) inarg;
880
881 if (req->f->op.listxattr)
882 req->f->op.listxattr(req, nodeid, arg->size);
883 else
884 fuse_reply_err(req, ENOSYS);
885 }
886
do_removexattr(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)887 static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
888 {
889 const char *name = (const char *) inarg;
890
891 if (req->f->op.removexattr)
892 req->f->op.removexattr(req, nodeid, name);
893 else
894 fuse_reply_err(req, ENOSYS);
895 }
896
convert_fuse_file_lock(const struct fuse_file_lock * fl,struct flock * flock)897 static void convert_fuse_file_lock(const struct fuse_file_lock *fl,
898 struct flock *flock)
899 {
900 memset(flock, 0, sizeof(struct flock));
901 flock->l_type = fl->type;
902 flock->l_whence = SEEK_SET;
903 flock->l_start = fl->start;
904 if (fl->end == OFFSET_MAX)
905 flock->l_len = 0;
906 else
907 flock->l_len = fl->end - fl->start + 1;
908 flock->l_pid = fl->pid;
909 }
910
do_getlk(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)911 static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
912 {
913 const struct fuse_lk_in *arg = (const struct fuse_lk_in *) inarg;
914 struct fuse_file_info fi;
915 struct flock flock;
916
917 memset(&fi, 0, sizeof(fi));
918 fi.fh = arg->fh;
919 fi.lock_owner = arg->owner;
920
921 convert_fuse_file_lock(&arg->lk, &flock);
922 if (req->f->op.getlk)
923 req->f->op.getlk(req, nodeid, &fi, &flock);
924 else
925 fuse_reply_err(req, ENOSYS);
926 }
927
do_setlk_common(fuse_req_t req,fuse_ino_t nodeid,const void * inarg,int should_sleep)928 static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
929 const void *inarg, int should_sleep)
930 {
931 const struct fuse_lk_in *arg = (const struct fuse_lk_in *) inarg;
932 struct fuse_file_info fi;
933 struct flock flock;
934
935 memset(&fi, 0, sizeof(fi));
936 fi.fh = arg->fh;
937 fi.lock_owner = arg->owner;
938
939 convert_fuse_file_lock(&arg->lk, &flock);
940 if (req->f->op.setlk)
941 req->f->op.setlk(req, nodeid, &fi, &flock, should_sleep);
942 else
943 fuse_reply_err(req, ENOSYS);
944 }
945
do_setlk(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)946 static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
947 {
948 do_setlk_common(req, nodeid, inarg, 0);
949 }
950
do_setlkw(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)951 static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
952 {
953 do_setlk_common(req, nodeid, inarg, 1);
954 }
955
find_interrupted(struct fuse_ll * f,struct fuse_req * req)956 static int find_interrupted(struct fuse_ll *f, struct fuse_req *req)
957 {
958 struct fuse_req *curr;
959
960 for (curr = f->list.next; curr != &f->list; curr = curr->next) {
961 if (curr->unique == req->u.i.unique) {
962 curr->ctr++;
963 pthread_mutex_unlock(&f->lock);
964
965 /* Ugh, ugly locking */
966 pthread_mutex_lock(&curr->lock);
967 pthread_mutex_lock(&f->lock);
968 curr->interrupted = 1;
969 pthread_mutex_unlock(&f->lock);
970 if (curr->u.ni.func)
971 curr->u.ni.func(curr, curr->u.ni.data);
972 pthread_mutex_unlock(&curr->lock);
973
974 pthread_mutex_lock(&f->lock);
975 curr->ctr--;
976 if (!curr->ctr)
977 destroy_req(curr);
978
979 return 1;
980 }
981 }
982 for (curr = f->interrupts.next; curr != &f->interrupts;
983 curr = curr->next) {
984 if (curr->u.i.unique == req->u.i.unique)
985 return 1;
986 }
987 return 0;
988 }
989
do_interrupt(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)990 static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
991 {
992 const struct fuse_interrupt_in *arg = (const struct fuse_interrupt_in *) inarg;
993 struct fuse_ll *f = req->f;
994
995 (void) nodeid;
996 if (f->debug)
997 fprintf(stderr, "INTERRUPT: %llu\n", (unsigned long long) arg->unique);
998
999 req->u.i.unique = arg->unique;
1000
1001 pthread_mutex_lock(&f->lock);
1002 if (find_interrupted(f, req))
1003 destroy_req(req);
1004 else
1005 list_add_req(req, &f->interrupts);
1006 pthread_mutex_unlock(&f->lock);
1007 }
1008
check_interrupt(struct fuse_ll * f,struct fuse_req * req)1009 static struct fuse_req *check_interrupt(struct fuse_ll *f, struct fuse_req *req)
1010 {
1011 struct fuse_req *curr;
1012
1013 for (curr = f->interrupts.next; curr != &f->interrupts; curr = curr->next) {
1014 if (curr->u.i.unique == req->unique) {
1015 req->interrupted = 1;
1016 list_del_req(curr);
1017 free(curr);
1018 return NULL;
1019 }
1020 }
1021 curr = f->interrupts.next;
1022 if (curr != &f->interrupts) {
1023 list_del_req(curr);
1024 list_init_req(curr);
1025 return curr;
1026 } else
1027 return NULL;
1028 }
1029
do_bmap(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)1030 static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1031 {
1032 const struct fuse_bmap_in *arg = (const struct fuse_bmap_in *) inarg;
1033
1034 if (req->f->op.bmap)
1035 req->f->op.bmap(req, nodeid, arg->blocksize, arg->block);
1036 else
1037 fuse_reply_err(req, ENOSYS);
1038 }
1039
do_ioctl(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)1040 static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1041 {
1042 const struct fuse_ioctl_in *arg = (const struct fuse_ioctl_in *) inarg;
1043 unsigned int flags = arg->flags;
1044 const void *in_buf = arg->in_size ? PARAM(arg) : NULL;
1045 struct fuse_file_info fi;
1046
1047 if (flags & FUSE_IOCTL_DIR &&
1048 !(req->f->conn.want & FUSE_CAP_IOCTL_DIR)) {
1049 fuse_reply_err(req, ENOTTY);
1050 return;
1051 }
1052
1053 memset(&fi, 0, sizeof(fi));
1054 fi.fh = arg->fh;
1055
1056 /* TODO JPA (need req->ioctl_64bit in obscure fuse_req_t)
1057 // probably a 64 bit ioctl on a 32-bit cpu
1058 // this is to forward a request from the kernel
1059 if (sizeof(void *) == 4 && req->f->conn.proto_minor >= 16 &&
1060 !(flags & FUSE_IOCTL_32BIT)) {
1061 req->ioctl_64bit = 1;
1062 }
1063 */
1064
1065 if (req->f->op.ioctl)
1066 req->f->op.ioctl(req, nodeid, arg->cmd,
1067 (void *)(uintptr_t)arg->arg, &fi, flags,
1068 in_buf, arg->in_size, arg->out_size);
1069 else
1070 fuse_reply_err(req, ENOSYS);
1071 }
1072
do_init(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)1073 static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1074 {
1075 const struct fuse_init_in *arg = (const struct fuse_init_in *) inarg;
1076 struct fuse_init_out outarg;
1077 struct fuse_ll *f = req->f;
1078 size_t bufsize = fuse_chan_bufsize(req->ch);
1079
1080 (void) nodeid;
1081 if (f->debug) {
1082 fprintf(stderr, "INIT: %u.%u\n", arg->major, arg->minor);
1083 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
1084 fprintf(stderr, "flags=0x%08x\n", arg->flags);
1085 fprintf(stderr, "max_readahead=0x%08x\n", arg->max_readahead);
1086 }
1087 }
1088 f->conn.proto_major = arg->major;
1089 f->conn.proto_minor = arg->minor;
1090
1091 if (arg->major < 7) {
1092 fprintf(stderr, "fuse: unsupported protocol version: %u.%u\n",
1093 arg->major, arg->minor);
1094 fuse_reply_err(req, EPROTO);
1095 return;
1096 }
1097
1098 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 6)) {
1099 if (f->conn.async_read)
1100 f->conn.async_read = arg->flags & FUSE_ASYNC_READ;
1101 if (arg->max_readahead < f->conn.max_readahead)
1102 f->conn.max_readahead = arg->max_readahead;
1103 #ifdef POSIXACLS
1104 if (arg->flags & FUSE_DONT_MASK)
1105 f->conn.capable |= FUSE_CAP_DONT_MASK;
1106 if (arg->flags & FUSE_POSIX_ACL)
1107 f->conn.capable |= FUSE_CAP_POSIX_ACL;
1108 #endif
1109 if (arg->flags & FUSE_BIG_WRITES)
1110 f->conn.capable |= FUSE_CAP_BIG_WRITES;
1111 if (arg->flags & FUSE_HAS_IOCTL_DIR)
1112 f->conn.capable |= FUSE_CAP_IOCTL_DIR;
1113 } else {
1114 f->conn.async_read = 0;
1115 f->conn.max_readahead = 0;
1116 }
1117
1118 if (bufsize < FUSE_MIN_READ_BUFFER) {
1119 fprintf(stderr, "fuse: warning: buffer size too small: %zu\n",
1120 bufsize);
1121 bufsize = FUSE_MIN_READ_BUFFER;
1122 }
1123
1124 bufsize -= 4096;
1125 if (bufsize < f->conn.max_write)
1126 f->conn.max_write = bufsize;
1127
1128 f->got_init = 1;
1129 if (f->op.init)
1130 f->op.init(f->userdata, &f->conn);
1131
1132 memset(&outarg, 0, sizeof(outarg));
1133 outarg.major = FUSE_KERNEL_VERSION;
1134 /*
1135 * Suggest using protocol 7.18 when available, and fallback
1136 * to 7.12 or even earlier when running on an old kernel.
1137 * Protocol 7.12 has the ability to process the umask
1138 * conditionnally (as needed if POSIXACLS is set)
1139 * Protocol 7.18 has the ability to process the ioctls
1140 */
1141 if (arg->major > 7 || (arg->major == 7 && arg->minor >= 18)) {
1142 outarg.minor = FUSE_KERNEL_MINOR_VERSION;
1143 if (f->conn.want & FUSE_CAP_IOCTL_DIR)
1144 outarg.flags |= FUSE_HAS_IOCTL_DIR;
1145 #ifdef POSIXACLS
1146 if (f->conn.want & FUSE_CAP_DONT_MASK)
1147 outarg.flags |= FUSE_DONT_MASK;
1148 if (f->conn.want & FUSE_CAP_POSIX_ACL)
1149 outarg.flags |= FUSE_POSIX_ACL;
1150 #endif
1151 } else {
1152 /* Never use a version more recent than supported by the kernel */
1153 if ((arg->major < FUSE_KERNEL_MAJOR_FALLBACK)
1154 || ((arg->major == FUSE_KERNEL_MAJOR_FALLBACK)
1155 && (arg->minor < FUSE_KERNEL_MINOR_FALLBACK))) {
1156 outarg.major = arg->major;
1157 outarg.minor = arg->minor;
1158 } else {
1159 outarg.major = FUSE_KERNEL_MAJOR_FALLBACK;
1160 outarg.minor = FUSE_KERNEL_MINOR_FALLBACK;
1161 #ifdef POSIXACLS
1162 if (f->conn.want & FUSE_CAP_DONT_MASK)
1163 outarg.flags |= FUSE_DONT_MASK;
1164 if (f->conn.want & FUSE_CAP_POSIX_ACL)
1165 outarg.flags |= FUSE_POSIX_ACL;
1166 #endif
1167 }
1168 }
1169 if (f->conn.async_read)
1170 outarg.flags |= FUSE_ASYNC_READ;
1171 if (f->op.getlk && f->op.setlk)
1172 outarg.flags |= FUSE_POSIX_LOCKS;
1173 if (f->conn.want & FUSE_CAP_BIG_WRITES)
1174 outarg.flags |= FUSE_BIG_WRITES;
1175 outarg.max_readahead = f->conn.max_readahead;
1176 outarg.max_write = f->conn.max_write;
1177
1178 if (f->debug) {
1179 fprintf(stderr, " INIT: %u.%u\n", outarg.major, outarg.minor);
1180 fprintf(stderr, " flags=0x%08x\n", outarg.flags);
1181 fprintf(stderr, " max_readahead=0x%08x\n", outarg.max_readahead);
1182 fprintf(stderr, " max_write=0x%08x\n", outarg.max_write);
1183 }
1184
1185 send_reply_ok(req, &outarg, arg->minor < 5 ? 8 : sizeof(outarg));
1186 }
1187
do_destroy(fuse_req_t req,fuse_ino_t nodeid,const void * inarg)1188 static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1189 {
1190 struct fuse_ll *f = req->f;
1191
1192 (void) nodeid;
1193 (void) inarg;
1194
1195 f->got_destroy = 1;
1196 if (f->op.destroy)
1197 f->op.destroy(f->userdata);
1198
1199 send_reply_ok(req, NULL, 0);
1200 }
1201
fuse_req_userdata(fuse_req_t req)1202 void *fuse_req_userdata(fuse_req_t req)
1203 {
1204 return req->f->userdata;
1205 }
1206
fuse_req_ctx(fuse_req_t req)1207 const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
1208 {
1209 return &req->ctx;
1210 }
1211
fuse_req_interrupt_func(fuse_req_t req,fuse_interrupt_func_t func,void * data)1212 void fuse_req_interrupt_func(fuse_req_t req, fuse_interrupt_func_t func,
1213 void *data)
1214 {
1215 pthread_mutex_lock(&req->lock);
1216 req->u.ni.func = func;
1217 req->u.ni.data = data;
1218 if (req->interrupted && func)
1219 func(req, data);
1220 pthread_mutex_unlock(&req->lock);
1221 }
1222
fuse_req_interrupted(fuse_req_t req)1223 int fuse_req_interrupted(fuse_req_t req)
1224 {
1225 int interrupted;
1226
1227 pthread_mutex_lock(&req->f->lock);
1228 interrupted = req->interrupted;
1229 pthread_mutex_unlock(&req->f->lock);
1230
1231 return interrupted;
1232 }
1233
1234 static struct {
1235 void (*func)(fuse_req_t, fuse_ino_t, const void *);
1236 const char *name;
1237 } fuse_ll_ops[] = {
1238 [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
1239 [FUSE_FORGET] = { do_forget, "FORGET" },
1240 [FUSE_GETATTR] = { do_getattr, "GETATTR" },
1241 [FUSE_SETATTR] = { do_setattr, "SETATTR" },
1242 [FUSE_READLINK] = { do_readlink, "READLINK" },
1243 [FUSE_SYMLINK] = { do_symlink, "SYMLINK" },
1244 [FUSE_MKNOD] = { do_mknod, "MKNOD" },
1245 [FUSE_MKDIR] = { do_mkdir, "MKDIR" },
1246 [FUSE_UNLINK] = { do_unlink, "UNLINK" },
1247 [FUSE_RMDIR] = { do_rmdir, "RMDIR" },
1248 [FUSE_RENAME] = { do_rename, "RENAME" },
1249 [FUSE_LINK] = { do_link, "LINK" },
1250 [FUSE_OPEN] = { do_open, "OPEN" },
1251 [FUSE_READ] = { do_read, "READ" },
1252 [FUSE_WRITE] = { do_write, "WRITE" },
1253 [FUSE_STATFS] = { do_statfs, "STATFS" },
1254 [FUSE_RELEASE] = { do_release, "RELEASE" },
1255 [FUSE_FSYNC] = { do_fsync, "FSYNC" },
1256 [FUSE_SETXATTR] = { do_setxattr, "SETXATTR" },
1257 [FUSE_GETXATTR] = { do_getxattr, "GETXATTR" },
1258 [FUSE_LISTXATTR] = { do_listxattr, "LISTXATTR" },
1259 [FUSE_REMOVEXATTR] = { do_removexattr, "REMOVEXATTR" },
1260 [FUSE_FLUSH] = { do_flush, "FLUSH" },
1261 [FUSE_INIT] = { do_init, "INIT" },
1262 [FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
1263 [FUSE_READDIR] = { do_readdir, "READDIR" },
1264 [FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
1265 [FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
1266 [FUSE_GETLK] = { do_getlk, "GETLK" },
1267 [FUSE_SETLK] = { do_setlk, "SETLK" },
1268 [FUSE_SETLKW] = { do_setlkw, "SETLKW" },
1269 [FUSE_ACCESS] = { do_access, "ACCESS" },
1270 [FUSE_CREATE] = { do_create, "CREATE" },
1271 [FUSE_INTERRUPT] = { do_interrupt, "INTERRUPT" },
1272 [FUSE_BMAP] = { do_bmap, "BMAP" },
1273 [FUSE_IOCTL] = { do_ioctl, "IOCTL" },
1274 [FUSE_DESTROY] = { do_destroy, "DESTROY" },
1275 };
1276
1277 #define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0]))
1278
opname(enum fuse_opcode opcode)1279 static const char *opname(enum fuse_opcode opcode)
1280 {
1281 if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name)
1282 return "???";
1283 else
1284 return fuse_ll_ops[opcode].name;
1285 }
1286
fuse_ll_process(void * data,const char * buf,size_t len,struct fuse_chan * ch)1287 static void fuse_ll_process(void *data, const char *buf, size_t len,
1288 struct fuse_chan *ch)
1289 {
1290 struct fuse_ll *f = (struct fuse_ll *) data;
1291 const struct fuse_in_header *in = (const struct fuse_in_header *) buf;
1292 const void *inarg = buf + sizeof(struct fuse_in_header);
1293 struct fuse_req *req;
1294
1295 if (f->debug)
1296 fprintf(stderr, "unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %zu\n",
1297 (unsigned long long) in->unique,
1298 opname((enum fuse_opcode) in->opcode), in->opcode,
1299 (unsigned long) in->nodeid, len);
1300
1301 req = (struct fuse_req *) calloc(1, sizeof(struct fuse_req));
1302 if (req == NULL) {
1303 fprintf(stderr, "fuse: failed to allocate request\n");
1304 return;
1305 }
1306
1307 req->f = f;
1308 req->unique = in->unique;
1309 req->ctx.uid = in->uid;
1310 req->ctx.gid = in->gid;
1311 req->ctx.pid = in->pid;
1312 req->ch = ch;
1313 req->ctr = 1;
1314 list_init_req(req);
1315 fuse_mutex_init(&req->lock);
1316
1317 if (!f->got_init && in->opcode != FUSE_INIT)
1318 fuse_reply_err(req, EIO);
1319 else if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
1320 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
1321 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
1322 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
1323 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
1324 fuse_reply_err(req, EACCES);
1325 } else if (in->opcode >= FUSE_MAXOP || !fuse_ll_ops[in->opcode].func)
1326 fuse_reply_err(req, ENOSYS);
1327 else {
1328 if (in->opcode != FUSE_INTERRUPT) {
1329 struct fuse_req *intr;
1330 pthread_mutex_lock(&f->lock);
1331 intr = check_interrupt(f, req);
1332 list_add_req(req, &f->list);
1333 pthread_mutex_unlock(&f->lock);
1334 if (intr)
1335 fuse_reply_err(intr, EAGAIN);
1336 }
1337 fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
1338 }
1339 }
1340
1341 enum {
1342 KEY_HELP,
1343 KEY_VERSION,
1344 };
1345
1346 static struct fuse_opt fuse_ll_opts[] = {
1347 { "debug", offsetof(struct fuse_ll, debug), 1 },
1348 { "-d", offsetof(struct fuse_ll, debug), 1 },
1349 { "allow_root", offsetof(struct fuse_ll, allow_root), 1 },
1350 { "max_write=%u", offsetof(struct fuse_ll, conn.max_write), 0 },
1351 { "max_readahead=%u", offsetof(struct fuse_ll, conn.max_readahead), 0 },
1352 { "async_read", offsetof(struct fuse_ll, conn.async_read), 1 },
1353 { "sync_read", offsetof(struct fuse_ll, conn.async_read), 0 },
1354 FUSE_OPT_KEY("max_read=", FUSE_OPT_KEY_DISCARD),
1355 FUSE_OPT_KEY("-h", KEY_HELP),
1356 FUSE_OPT_KEY("--help", KEY_HELP),
1357 FUSE_OPT_KEY("-V", KEY_VERSION),
1358 FUSE_OPT_KEY("--version", KEY_VERSION),
1359 FUSE_OPT_END
1360 };
1361
fuse_ll_version(void)1362 static void fuse_ll_version(void)
1363 {
1364 fprintf(stderr, "using FUSE kernel interface version %i.%i\n",
1365 FUSE_KERNEL_VERSION, FUSE_KERNEL_MINOR_VERSION);
1366 }
1367
fuse_ll_help(void)1368 static void fuse_ll_help(void)
1369 {
1370 fprintf(stderr,
1371 " -o max_write=N set maximum size of write requests\n"
1372 " -o max_readahead=N set maximum readahead\n"
1373 " -o async_read perform reads asynchronously (default)\n"
1374 " -o sync_read perform reads synchronously\n");
1375 }
1376
fuse_ll_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)1377 static int fuse_ll_opt_proc(void *data, const char *arg, int key,
1378 struct fuse_args *outargs)
1379 {
1380 (void) data; (void) outargs;
1381
1382 switch (key) {
1383 case KEY_HELP:
1384 fuse_ll_help();
1385 break;
1386
1387 case KEY_VERSION:
1388 fuse_ll_version();
1389 break;
1390
1391 default:
1392 fprintf(stderr, "fuse: unknown option `%s'\n", arg);
1393 }
1394
1395 return -1;
1396 }
1397
1398 #ifdef __SOLARIS__
1399
fuse_lowlevel_is_lib_option(const char * opt)1400 int fuse_lowlevel_is_lib_option(const char *opt)
1401 {
1402 return fuse_opt_match(fuse_ll_opts, opt);
1403 }
1404
1405 #endif /* __SOLARIS__ */
1406
fuse_ll_destroy(void * data)1407 static void fuse_ll_destroy(void *data)
1408 {
1409 struct fuse_ll *f = (struct fuse_ll *) data;
1410
1411 if (f->got_init && !f->got_destroy) {
1412 if (f->op.destroy)
1413 f->op.destroy(f->userdata);
1414 }
1415
1416 pthread_mutex_destroy(&f->lock);
1417 free(f);
1418 }
1419
fuse_lowlevel_new(struct fuse_args * args,const struct fuse_lowlevel_ops * op,size_t op_size,void * userdata)1420 struct fuse_session *fuse_lowlevel_new(struct fuse_args *args,
1421 const struct fuse_lowlevel_ops *op,
1422 size_t op_size, void *userdata)
1423 {
1424 struct fuse_ll *f;
1425 struct fuse_session *se;
1426 struct fuse_session_ops sop = {
1427 .process = fuse_ll_process,
1428 .destroy = fuse_ll_destroy,
1429 };
1430
1431 if (sizeof(struct fuse_lowlevel_ops) < op_size) {
1432 fprintf(stderr, "fuse: warning: library too old, some operations may not work\n");
1433 op_size = sizeof(struct fuse_lowlevel_ops);
1434 }
1435
1436 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
1437 if (f == NULL) {
1438 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1439 goto out;
1440 }
1441
1442 f->conn.async_read = 1;
1443 f->conn.max_write = UINT_MAX;
1444 f->conn.max_readahead = UINT_MAX;
1445 list_init_req(&f->list);
1446 list_init_req(&f->interrupts);
1447 fuse_mutex_init(&f->lock);
1448
1449 if (fuse_opt_parse(args, f, fuse_ll_opts, fuse_ll_opt_proc) == -1)
1450 goto out_free;
1451
1452 memcpy(&f->op, op, op_size);
1453 f->owner = getuid();
1454 f->userdata = userdata;
1455
1456 se = fuse_session_new(&sop, f);
1457 if (!se)
1458 goto out_free;
1459
1460 return se;
1461
1462 out_free:
1463 free(f);
1464 out:
1465 return NULL;
1466 }
1467