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