• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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