1987da915Sopenharmony_ci/*
2987da915Sopenharmony_ci    FUSE: Filesystem in Userspace
3987da915Sopenharmony_ci    Copyright (C) 2001-2007  Miklos Szeredi <miklos@szeredi.hu>
4987da915Sopenharmony_ci
5987da915Sopenharmony_ci    This program can be distributed under the terms of the GNU LGPLv2.
6987da915Sopenharmony_ci    See the file COPYING.LIB
7987da915Sopenharmony_ci*/
8987da915Sopenharmony_ci
9987da915Sopenharmony_ci#ifdef __SOLARIS__
10987da915Sopenharmony_ci/* For pthread_rwlock_t */
11987da915Sopenharmony_ci#define _GNU_SOURCE
12987da915Sopenharmony_ci#endif /* __SOLARIS__ */
13987da915Sopenharmony_ci
14987da915Sopenharmony_ci#include "config.h"
15987da915Sopenharmony_ci#include "fuse_i.h"
16987da915Sopenharmony_ci#include "fuse_lowlevel.h"
17987da915Sopenharmony_ci#include "fuse_opt.h"
18987da915Sopenharmony_ci#include "fuse_misc.h"
19987da915Sopenharmony_ci
20987da915Sopenharmony_ci#include <stdio.h>
21987da915Sopenharmony_ci#include <string.h>
22987da915Sopenharmony_ci#include <stdlib.h>
23987da915Sopenharmony_ci#include <stddef.h>
24987da915Sopenharmony_ci#include <unistd.h>
25987da915Sopenharmony_ci#include <time.h>
26987da915Sopenharmony_ci#include <fcntl.h>
27987da915Sopenharmony_ci#include <limits.h>
28987da915Sopenharmony_ci#include <errno.h>
29987da915Sopenharmony_ci#include <signal.h>
30987da915Sopenharmony_ci#include <dlfcn.h>
31987da915Sopenharmony_ci#include <assert.h>
32987da915Sopenharmony_ci#include <sys/param.h>
33987da915Sopenharmony_ci#include <sys/uio.h>
34987da915Sopenharmony_ci#include <sys/time.h>
35987da915Sopenharmony_ci
36987da915Sopenharmony_ci#ifdef __SOLARIS__
37987da915Sopenharmony_ci#define FUSE_MAX_PATH 4096
38987da915Sopenharmony_ci#endif /* __SOLARIS__ */
39987da915Sopenharmony_ci
40987da915Sopenharmony_ci#define FUSE_DEFAULT_INTR_SIGNAL SIGUSR1
41987da915Sopenharmony_ci
42987da915Sopenharmony_ci#define FUSE_UNKNOWN_INO 0xffffffff
43987da915Sopenharmony_ci#define OFFSET_MAX 0x7fffffffffffffffLL
44987da915Sopenharmony_ci
45987da915Sopenharmony_cistruct fuse_config {
46987da915Sopenharmony_ci    unsigned int uid;
47987da915Sopenharmony_ci    unsigned int gid;
48987da915Sopenharmony_ci    unsigned int  umask;
49987da915Sopenharmony_ci    double entry_timeout;
50987da915Sopenharmony_ci    double negative_timeout;
51987da915Sopenharmony_ci    double attr_timeout;
52987da915Sopenharmony_ci    double ac_attr_timeout;
53987da915Sopenharmony_ci    int ac_attr_timeout_set;
54987da915Sopenharmony_ci    int debug;
55987da915Sopenharmony_ci    int hard_remove;
56987da915Sopenharmony_ci    int use_ino;
57987da915Sopenharmony_ci    int readdir_ino;
58987da915Sopenharmony_ci    int set_mode;
59987da915Sopenharmony_ci    int set_uid;
60987da915Sopenharmony_ci    int set_gid;
61987da915Sopenharmony_ci    int direct_io;
62987da915Sopenharmony_ci    int kernel_cache;
63987da915Sopenharmony_ci    int intr;
64987da915Sopenharmony_ci    int intr_signal;
65987da915Sopenharmony_ci    int help;
66987da915Sopenharmony_ci#ifdef __SOLARIS__
67987da915Sopenharmony_ci    int auto_cache;
68987da915Sopenharmony_ci    char *modules;
69987da915Sopenharmony_ci#endif /* __SOLARIS__ */
70987da915Sopenharmony_ci};
71987da915Sopenharmony_ci
72987da915Sopenharmony_cistruct fuse_fs {
73987da915Sopenharmony_ci    struct fuse_operations op;
74987da915Sopenharmony_ci    void *user_data;
75987da915Sopenharmony_ci#ifdef __SOLARIS__
76987da915Sopenharmony_ci    struct fuse_module *m;
77987da915Sopenharmony_ci#endif /* __SOLARIS__ */
78987da915Sopenharmony_ci};
79987da915Sopenharmony_ci
80987da915Sopenharmony_ci#ifdef __SOLARIS__
81987da915Sopenharmony_cistruct fusemod_so {
82987da915Sopenharmony_ci    void *handle;
83987da915Sopenharmony_ci    int ctr;
84987da915Sopenharmony_ci};
85987da915Sopenharmony_ci#endif /* __SOLARIS__ */
86987da915Sopenharmony_ci
87987da915Sopenharmony_cistruct fuse {
88987da915Sopenharmony_ci    struct fuse_session *se;
89987da915Sopenharmony_ci    struct node **name_table;
90987da915Sopenharmony_ci    size_t name_table_size;
91987da915Sopenharmony_ci    struct node **id_table;
92987da915Sopenharmony_ci    size_t id_table_size;
93987da915Sopenharmony_ci    fuse_ino_t ctr;
94987da915Sopenharmony_ci    unsigned int generation;
95987da915Sopenharmony_ci    unsigned int hidectr;
96987da915Sopenharmony_ci    pthread_mutex_t lock;
97987da915Sopenharmony_ci    pthread_rwlock_t tree_lock;
98987da915Sopenharmony_ci    struct fuse_config conf;
99987da915Sopenharmony_ci    int intr_installed;
100987da915Sopenharmony_ci    struct fuse_fs *fs;
101987da915Sopenharmony_ci};
102987da915Sopenharmony_ci
103987da915Sopenharmony_cistruct lock {
104987da915Sopenharmony_ci    int type;
105987da915Sopenharmony_ci    off_t start;
106987da915Sopenharmony_ci    off_t end;
107987da915Sopenharmony_ci    pid_t pid;
108987da915Sopenharmony_ci    uint64_t owner;
109987da915Sopenharmony_ci    struct lock *next;
110987da915Sopenharmony_ci};
111987da915Sopenharmony_ci
112987da915Sopenharmony_cistruct node {
113987da915Sopenharmony_ci    struct node *name_next;
114987da915Sopenharmony_ci    struct node *id_next;
115987da915Sopenharmony_ci    fuse_ino_t nodeid;
116987da915Sopenharmony_ci    unsigned int generation;
117987da915Sopenharmony_ci    int refctr;
118987da915Sopenharmony_ci    struct node *parent;
119987da915Sopenharmony_ci    char *name;
120987da915Sopenharmony_ci    uint64_t nlookup;
121987da915Sopenharmony_ci    int open_count;
122987da915Sopenharmony_ci    int is_hidden;
123987da915Sopenharmony_ci#ifdef __SOLARIS__
124987da915Sopenharmony_ci    struct timespec stat_updated;
125987da915Sopenharmony_ci    struct timespec mtime;
126987da915Sopenharmony_ci    off_t size;
127987da915Sopenharmony_ci    int cache_valid;
128987da915Sopenharmony_ci#endif /* __SOLARIS__ */
129987da915Sopenharmony_ci    struct lock *locks;
130987da915Sopenharmony_ci};
131987da915Sopenharmony_ci
132987da915Sopenharmony_cistruct fuse_dh {
133987da915Sopenharmony_ci    pthread_mutex_t lock;
134987da915Sopenharmony_ci    struct fuse *fuse;
135987da915Sopenharmony_ci    fuse_req_t req;
136987da915Sopenharmony_ci    char *contents;
137987da915Sopenharmony_ci    unsigned len;
138987da915Sopenharmony_ci    unsigned size;
139987da915Sopenharmony_ci    unsigned needlen;
140987da915Sopenharmony_ci    int filled;
141987da915Sopenharmony_ci    uint64_t fh;
142987da915Sopenharmony_ci    int error;
143987da915Sopenharmony_ci    fuse_ino_t nodeid;
144987da915Sopenharmony_ci};
145987da915Sopenharmony_ci
146987da915Sopenharmony_cistruct fuse_context_i {
147987da915Sopenharmony_ci    struct fuse_context ctx;
148987da915Sopenharmony_ci    fuse_req_t req;
149987da915Sopenharmony_ci};
150987da915Sopenharmony_ci
151987da915Sopenharmony_cistatic pthread_key_t fuse_context_key;
152987da915Sopenharmony_cistatic pthread_mutex_t fuse_context_lock = PTHREAD_MUTEX_INITIALIZER;
153987da915Sopenharmony_cistatic int fuse_context_ref;
154987da915Sopenharmony_ci
155987da915Sopenharmony_ci#ifdef __SOLARIS__
156987da915Sopenharmony_ci
157987da915Sopenharmony_cistatic struct fusemod_so *fuse_current_so;
158987da915Sopenharmony_cistatic struct fuse_module *fuse_modules;
159987da915Sopenharmony_ci
160987da915Sopenharmony_cistatic int fuse_load_so_name(const char *soname)
161987da915Sopenharmony_ci{
162987da915Sopenharmony_ci    struct fusemod_so *so;
163987da915Sopenharmony_ci
164987da915Sopenharmony_ci    so = calloc(1, sizeof(struct fusemod_so));
165987da915Sopenharmony_ci    if (!so) {
166987da915Sopenharmony_ci        fprintf(stderr, "fuse: memory allocation failed\n");
167987da915Sopenharmony_ci        return -1;
168987da915Sopenharmony_ci    }
169987da915Sopenharmony_ci
170987da915Sopenharmony_ci    fuse_current_so = so;
171987da915Sopenharmony_ci    so->handle = dlopen(soname, RTLD_NOW);
172987da915Sopenharmony_ci    fuse_current_so = NULL;
173987da915Sopenharmony_ci    if (!so->handle) {
174987da915Sopenharmony_ci        fprintf(stderr, "fuse: %s\n", dlerror());
175987da915Sopenharmony_ci        goto err;
176987da915Sopenharmony_ci    }
177987da915Sopenharmony_ci    if (!so->ctr) {
178987da915Sopenharmony_ci        fprintf(stderr, "fuse: %s did not register any modules", soname);
179987da915Sopenharmony_ci        goto err;
180987da915Sopenharmony_ci    }
181987da915Sopenharmony_ci    return 0;
182987da915Sopenharmony_ci
183987da915Sopenharmony_ci err:
184987da915Sopenharmony_ci    if (so->handle)
185987da915Sopenharmony_ci        dlclose(so->handle);
186987da915Sopenharmony_ci    free(so);
187987da915Sopenharmony_ci    return -1;
188987da915Sopenharmony_ci}
189987da915Sopenharmony_ci
190987da915Sopenharmony_cistatic int fuse_load_so_module(const char *module)
191987da915Sopenharmony_ci{
192987da915Sopenharmony_ci    int res;
193987da915Sopenharmony_ci    char *soname = malloc(strlen(module) + 64);
194987da915Sopenharmony_ci    if (!soname) {
195987da915Sopenharmony_ci        fprintf(stderr, "fuse: memory allocation failed\n");
196987da915Sopenharmony_ci        return -1;
197987da915Sopenharmony_ci    }
198987da915Sopenharmony_ci    sprintf(soname, "libfusemod_%s.so", module);
199987da915Sopenharmony_ci    res = fuse_load_so_name(soname);
200987da915Sopenharmony_ci    free(soname);
201987da915Sopenharmony_ci    return res;
202987da915Sopenharmony_ci}
203987da915Sopenharmony_ci
204987da915Sopenharmony_cistatic struct fuse_module *fuse_find_module(const char *module)
205987da915Sopenharmony_ci{
206987da915Sopenharmony_ci    struct fuse_module *m;
207987da915Sopenharmony_ci    for (m = fuse_modules; m; m = m->next) {
208987da915Sopenharmony_ci        if (strcmp(module, m->name) == 0) {
209987da915Sopenharmony_ci            m->ctr++;
210987da915Sopenharmony_ci            break;
211987da915Sopenharmony_ci        }
212987da915Sopenharmony_ci    }
213987da915Sopenharmony_ci    return m;
214987da915Sopenharmony_ci}
215987da915Sopenharmony_ci
216987da915Sopenharmony_cistatic struct fuse_module *fuse_get_module(const char *module)
217987da915Sopenharmony_ci{
218987da915Sopenharmony_ci    struct fuse_module *m;
219987da915Sopenharmony_ci
220987da915Sopenharmony_ci    pthread_mutex_lock(&fuse_context_lock);
221987da915Sopenharmony_ci    m = fuse_find_module(module);
222987da915Sopenharmony_ci    if (!m) {
223987da915Sopenharmony_ci        int err = fuse_load_so_module(module);
224987da915Sopenharmony_ci        if (!err)
225987da915Sopenharmony_ci            m = fuse_find_module(module);
226987da915Sopenharmony_ci    }
227987da915Sopenharmony_ci    pthread_mutex_unlock(&fuse_context_lock);
228987da915Sopenharmony_ci    return m;
229987da915Sopenharmony_ci}
230987da915Sopenharmony_ci
231987da915Sopenharmony_cistatic void fuse_put_module(struct fuse_module *m)
232987da915Sopenharmony_ci{
233987da915Sopenharmony_ci    pthread_mutex_lock(&fuse_context_lock);
234987da915Sopenharmony_ci    assert(m->ctr > 0);
235987da915Sopenharmony_ci    m->ctr--;
236987da915Sopenharmony_ci    if (!m->ctr && m->so) {
237987da915Sopenharmony_ci        struct fusemod_so *so = m->so;
238987da915Sopenharmony_ci        assert(so->ctr > 0);
239987da915Sopenharmony_ci        so->ctr--;
240987da915Sopenharmony_ci        if (!so->ctr) {
241987da915Sopenharmony_ci            struct fuse_module **mp;
242987da915Sopenharmony_ci            for (mp = &fuse_modules; *mp;) {
243987da915Sopenharmony_ci                if ((*mp)->so == so)
244987da915Sopenharmony_ci                    *mp = (*mp)->next;
245987da915Sopenharmony_ci                else
246987da915Sopenharmony_ci                    mp = &(*mp)->next;
247987da915Sopenharmony_ci            }
248987da915Sopenharmony_ci            dlclose(so->handle);
249987da915Sopenharmony_ci            free(so);
250987da915Sopenharmony_ci        }
251987da915Sopenharmony_ci    }
252987da915Sopenharmony_ci    pthread_mutex_unlock(&fuse_context_lock);
253987da915Sopenharmony_ci}
254987da915Sopenharmony_ci#endif /* __SOLARIS__ */
255987da915Sopenharmony_ci
256987da915Sopenharmony_cistatic struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
257987da915Sopenharmony_ci{
258987da915Sopenharmony_ci    size_t hash = nodeid % f->id_table_size;
259987da915Sopenharmony_ci    struct node *node;
260987da915Sopenharmony_ci
261987da915Sopenharmony_ci    for (node = f->id_table[hash]; node != NULL; node = node->id_next)
262987da915Sopenharmony_ci        if (node->nodeid == nodeid)
263987da915Sopenharmony_ci            return node;
264987da915Sopenharmony_ci
265987da915Sopenharmony_ci    return NULL;
266987da915Sopenharmony_ci}
267987da915Sopenharmony_ci
268987da915Sopenharmony_cistatic struct node *get_node(struct fuse *f, fuse_ino_t nodeid)
269987da915Sopenharmony_ci{
270987da915Sopenharmony_ci    struct node *node = get_node_nocheck(f, nodeid);
271987da915Sopenharmony_ci    if (!node) {
272987da915Sopenharmony_ci        fprintf(stderr, "fuse internal error: node %llu not found\n",
273987da915Sopenharmony_ci                (unsigned long long) nodeid);
274987da915Sopenharmony_ci        abort();
275987da915Sopenharmony_ci    }
276987da915Sopenharmony_ci    return node;
277987da915Sopenharmony_ci}
278987da915Sopenharmony_ci
279987da915Sopenharmony_cistatic void free_node(struct node *node)
280987da915Sopenharmony_ci{
281987da915Sopenharmony_ci    free(node->name);
282987da915Sopenharmony_ci    free(node);
283987da915Sopenharmony_ci}
284987da915Sopenharmony_ci
285987da915Sopenharmony_cistatic void unhash_id(struct fuse *f, struct node *node)
286987da915Sopenharmony_ci{
287987da915Sopenharmony_ci    size_t hash = node->nodeid % f->id_table_size;
288987da915Sopenharmony_ci    struct node **nodep = &f->id_table[hash];
289987da915Sopenharmony_ci
290987da915Sopenharmony_ci    for (; *nodep != NULL; nodep = &(*nodep)->id_next)
291987da915Sopenharmony_ci        if (*nodep == node) {
292987da915Sopenharmony_ci            *nodep = node->id_next;
293987da915Sopenharmony_ci            return;
294987da915Sopenharmony_ci        }
295987da915Sopenharmony_ci}
296987da915Sopenharmony_ci
297987da915Sopenharmony_cistatic void hash_id(struct fuse *f, struct node *node)
298987da915Sopenharmony_ci{
299987da915Sopenharmony_ci    size_t hash = node->nodeid % f->id_table_size;
300987da915Sopenharmony_ci    node->id_next = f->id_table[hash];
301987da915Sopenharmony_ci    f->id_table[hash] = node;
302987da915Sopenharmony_ci}
303987da915Sopenharmony_ci
304987da915Sopenharmony_cistatic unsigned int name_hash(struct fuse *f, fuse_ino_t parent,
305987da915Sopenharmony_ci                              const char *name)
306987da915Sopenharmony_ci{
307987da915Sopenharmony_ci    unsigned int hash = *name;
308987da915Sopenharmony_ci
309987da915Sopenharmony_ci    if (hash)
310987da915Sopenharmony_ci        for (name += 1; *name != '\0'; name++)
311987da915Sopenharmony_ci            hash = (hash << 5) - hash + *name;
312987da915Sopenharmony_ci
313987da915Sopenharmony_ci    return (hash + parent) % f->name_table_size;
314987da915Sopenharmony_ci}
315987da915Sopenharmony_ci
316987da915Sopenharmony_cistatic void unref_node(struct fuse *f, struct node *node);
317987da915Sopenharmony_ci
318987da915Sopenharmony_cistatic void unhash_name(struct fuse *f, struct node *node)
319987da915Sopenharmony_ci{
320987da915Sopenharmony_ci    if (node->name) {
321987da915Sopenharmony_ci        size_t hash = name_hash(f, node->parent->nodeid, node->name);
322987da915Sopenharmony_ci        struct node **nodep = &f->name_table[hash];
323987da915Sopenharmony_ci
324987da915Sopenharmony_ci        for (; *nodep != NULL; nodep = &(*nodep)->name_next)
325987da915Sopenharmony_ci            if (*nodep == node) {
326987da915Sopenharmony_ci                *nodep = node->name_next;
327987da915Sopenharmony_ci                node->name_next = NULL;
328987da915Sopenharmony_ci                unref_node(f, node->parent);
329987da915Sopenharmony_ci                free(node->name);
330987da915Sopenharmony_ci                node->name = NULL;
331987da915Sopenharmony_ci                node->parent = NULL;
332987da915Sopenharmony_ci                return;
333987da915Sopenharmony_ci            }
334987da915Sopenharmony_ci        fprintf(stderr, "fuse internal error: unable to unhash node: %llu\n",
335987da915Sopenharmony_ci                (unsigned long long) node->nodeid);
336987da915Sopenharmony_ci        abort();
337987da915Sopenharmony_ci    }
338987da915Sopenharmony_ci}
339987da915Sopenharmony_ci
340987da915Sopenharmony_cistatic int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
341987da915Sopenharmony_ci                     const char *name)
342987da915Sopenharmony_ci{
343987da915Sopenharmony_ci    size_t hash = name_hash(f, parentid, name);
344987da915Sopenharmony_ci    struct node *parent = get_node(f, parentid);
345987da915Sopenharmony_ci    node->name = strdup(name);
346987da915Sopenharmony_ci    if (node->name == NULL)
347987da915Sopenharmony_ci        return -1;
348987da915Sopenharmony_ci
349987da915Sopenharmony_ci    parent->refctr ++;
350987da915Sopenharmony_ci    node->parent = parent;
351987da915Sopenharmony_ci    node->name_next = f->name_table[hash];
352987da915Sopenharmony_ci    f->name_table[hash] = node;
353987da915Sopenharmony_ci    return 0;
354987da915Sopenharmony_ci}
355987da915Sopenharmony_ci
356987da915Sopenharmony_cistatic void delete_node(struct fuse *f, struct node *node)
357987da915Sopenharmony_ci{
358987da915Sopenharmony_ci    if (f->conf.debug)
359987da915Sopenharmony_ci        fprintf(stderr, "delete: %llu\n", (unsigned long long) node->nodeid);
360987da915Sopenharmony_ci
361987da915Sopenharmony_ci    assert(!node->name);
362987da915Sopenharmony_ci    unhash_id(f, node);
363987da915Sopenharmony_ci    free_node(node);
364987da915Sopenharmony_ci}
365987da915Sopenharmony_ci
366987da915Sopenharmony_cistatic void unref_node(struct fuse *f, struct node *node)
367987da915Sopenharmony_ci{
368987da915Sopenharmony_ci    assert(node->refctr > 0);
369987da915Sopenharmony_ci    node->refctr --;
370987da915Sopenharmony_ci    if (!node->refctr)
371987da915Sopenharmony_ci        delete_node(f, node);
372987da915Sopenharmony_ci}
373987da915Sopenharmony_ci
374987da915Sopenharmony_cistatic fuse_ino_t next_id(struct fuse *f)
375987da915Sopenharmony_ci{
376987da915Sopenharmony_ci    do {
377987da915Sopenharmony_ci        f->ctr = (f->ctr + 1) & 0xffffffff;
378987da915Sopenharmony_ci        if (!f->ctr)
379987da915Sopenharmony_ci            f->generation ++;
380987da915Sopenharmony_ci    } while (f->ctr == 0 || f->ctr == FUSE_UNKNOWN_INO ||
381987da915Sopenharmony_ci             get_node_nocheck(f, f->ctr) != NULL);
382987da915Sopenharmony_ci    return f->ctr;
383987da915Sopenharmony_ci}
384987da915Sopenharmony_ci
385987da915Sopenharmony_cistatic struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
386987da915Sopenharmony_ci                                const char *name)
387987da915Sopenharmony_ci{
388987da915Sopenharmony_ci    size_t hash = name_hash(f, parent, name);
389987da915Sopenharmony_ci    struct node *node;
390987da915Sopenharmony_ci
391987da915Sopenharmony_ci    for (node = f->name_table[hash]; node != NULL; node = node->name_next)
392987da915Sopenharmony_ci        if (node->parent->nodeid == parent && strcmp(node->name, name) == 0)
393987da915Sopenharmony_ci            return node;
394987da915Sopenharmony_ci
395987da915Sopenharmony_ci    return NULL;
396987da915Sopenharmony_ci}
397987da915Sopenharmony_ci
398987da915Sopenharmony_cistatic struct node *find_node(struct fuse *f, fuse_ino_t parent,
399987da915Sopenharmony_ci                              const char *name)
400987da915Sopenharmony_ci{
401987da915Sopenharmony_ci    struct node *node;
402987da915Sopenharmony_ci
403987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
404987da915Sopenharmony_ci    node = lookup_node(f, parent, name);
405987da915Sopenharmony_ci    if (node == NULL) {
406987da915Sopenharmony_ci        node = (struct node *) calloc(1, sizeof(struct node));
407987da915Sopenharmony_ci        if (node == NULL)
408987da915Sopenharmony_ci            goto out_err;
409987da915Sopenharmony_ci
410987da915Sopenharmony_ci        node->refctr = 1;
411987da915Sopenharmony_ci        node->nodeid = next_id(f);
412987da915Sopenharmony_ci        node->open_count = 0;
413987da915Sopenharmony_ci        node->is_hidden = 0;
414987da915Sopenharmony_ci        node->generation = f->generation;
415987da915Sopenharmony_ci        if (hash_name(f, node, parent, name) == -1) {
416987da915Sopenharmony_ci            free(node);
417987da915Sopenharmony_ci            node = NULL;
418987da915Sopenharmony_ci            goto out_err;
419987da915Sopenharmony_ci        }
420987da915Sopenharmony_ci        hash_id(f, node);
421987da915Sopenharmony_ci    }
422987da915Sopenharmony_ci    node->nlookup ++;
423987da915Sopenharmony_ci out_err:
424987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
425987da915Sopenharmony_ci    return node;
426987da915Sopenharmony_ci}
427987da915Sopenharmony_ci
428987da915Sopenharmony_ci#ifndef __SOLARIS__
429987da915Sopenharmony_cistatic char *add_name(char **buf, unsigned *bufsize, char *s, const char *name)
430987da915Sopenharmony_ci#else /* __SOLARIS__ */
431987da915Sopenharmony_cistatic char *add_name(char *buf, char *s, const char *name)
432987da915Sopenharmony_ci#endif /* __SOLARIS__ */
433987da915Sopenharmony_ci{
434987da915Sopenharmony_ci    size_t len = strlen(name);
435987da915Sopenharmony_ci
436987da915Sopenharmony_ci#ifndef __SOLARIS__
437987da915Sopenharmony_ci    if (s - len <= *buf) {
438987da915Sopenharmony_ci	unsigned pathlen = *bufsize - (s - *buf);
439987da915Sopenharmony_ci	unsigned newbufsize = *bufsize;
440987da915Sopenharmony_ci	char *newbuf;
441987da915Sopenharmony_ci
442987da915Sopenharmony_ci	while (newbufsize < pathlen + len + 1) {
443987da915Sopenharmony_ci	    if (newbufsize >= 0x80000000)
444987da915Sopenharmony_ci	    	newbufsize = 0xffffffff;
445987da915Sopenharmony_ci	    else
446987da915Sopenharmony_ci	    	newbufsize *= 2;
447987da915Sopenharmony_ci	}
448987da915Sopenharmony_ci
449987da915Sopenharmony_ci	newbuf = realloc(*buf, newbufsize);
450987da915Sopenharmony_ci	if (newbuf == NULL)
451987da915Sopenharmony_ci		return NULL;
452987da915Sopenharmony_ci
453987da915Sopenharmony_ci	*buf = newbuf;
454987da915Sopenharmony_ci	s = newbuf + newbufsize - pathlen;
455987da915Sopenharmony_ci	memmove(s, newbuf + *bufsize - pathlen, pathlen);
456987da915Sopenharmony_ci	*bufsize = newbufsize;
457987da915Sopenharmony_ci    }
458987da915Sopenharmony_ci    s -= len;
459987da915Sopenharmony_ci#else /* ! __SOLARIS__ */
460987da915Sopenharmony_ci    s -= len;
461987da915Sopenharmony_ci    if (s <= buf) {
462987da915Sopenharmony_ci        fprintf(stderr, "fuse: path too long: ...%s\n", s + len);
463987da915Sopenharmony_ci        return NULL;
464987da915Sopenharmony_ci    }
465987da915Sopenharmony_ci#endif /* __SOLARIS__ */
466987da915Sopenharmony_ci    memcpy(s, name, len);
467987da915Sopenharmony_ci    s--;
468987da915Sopenharmony_ci    *s = '/';
469987da915Sopenharmony_ci
470987da915Sopenharmony_ci    return s;
471987da915Sopenharmony_ci}
472987da915Sopenharmony_ci
473987da915Sopenharmony_cistatic char *get_path_name(struct fuse *f, fuse_ino_t nodeid, const char *name)
474987da915Sopenharmony_ci{
475987da915Sopenharmony_ci#ifdef __SOLARIS__
476987da915Sopenharmony_ci    char buf[FUSE_MAX_PATH];
477987da915Sopenharmony_ci    char *s = buf + FUSE_MAX_PATH - 1;
478987da915Sopenharmony_ci    struct node *node;
479987da915Sopenharmony_ci
480987da915Sopenharmony_ci    *s = '\0';
481987da915Sopenharmony_ci
482987da915Sopenharmony_ci    if (name != NULL) {
483987da915Sopenharmony_ci        s = add_name(buf, s, name);
484987da915Sopenharmony_ci        if (s == NULL)
485987da915Sopenharmony_ci            return NULL;
486987da915Sopenharmony_ci    }
487987da915Sopenharmony_ci
488987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
489987da915Sopenharmony_ci    for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
490987da915Sopenharmony_ci         node = node->parent) {
491987da915Sopenharmony_ci        if (node->name == NULL) {
492987da915Sopenharmony_ci            s = NULL;
493987da915Sopenharmony_ci            break;
494987da915Sopenharmony_ci        }
495987da915Sopenharmony_ci
496987da915Sopenharmony_ci        s = add_name(buf, s, node->name);
497987da915Sopenharmony_ci        if (s == NULL)
498987da915Sopenharmony_ci            break;
499987da915Sopenharmony_ci    }
500987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
501987da915Sopenharmony_ci
502987da915Sopenharmony_ci    if (node == NULL || s == NULL)
503987da915Sopenharmony_ci        return NULL;
504987da915Sopenharmony_ci    else if (*s == '\0')
505987da915Sopenharmony_ci        return strdup("/");
506987da915Sopenharmony_ci    else
507987da915Sopenharmony_ci        return strdup(s);
508987da915Sopenharmony_ci
509987da915Sopenharmony_ci#else /* __SOLARIS__ */
510987da915Sopenharmony_ci
511987da915Sopenharmony_ci    unsigned bufsize = 256;
512987da915Sopenharmony_ci    char *buf;
513987da915Sopenharmony_ci    char *s;
514987da915Sopenharmony_ci    struct node *node;
515987da915Sopenharmony_ci
516987da915Sopenharmony_ci    buf = malloc(bufsize);
517987da915Sopenharmony_ci    if (buf == NULL)
518987da915Sopenharmony_ci            return NULL;
519987da915Sopenharmony_ci
520987da915Sopenharmony_ci    s = buf + bufsize - 1;
521987da915Sopenharmony_ci    *s = '\0';
522987da915Sopenharmony_ci
523987da915Sopenharmony_ci    if (name != NULL) {
524987da915Sopenharmony_ci        s = add_name(&buf, &bufsize, s, name);
525987da915Sopenharmony_ci        if (s == NULL)
526987da915Sopenharmony_ci            goto out_free;
527987da915Sopenharmony_ci    }
528987da915Sopenharmony_ci
529987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
530987da915Sopenharmony_ci    for (node = get_node(f, nodeid); node && node->nodeid != FUSE_ROOT_ID;
531987da915Sopenharmony_ci         node = node->parent) {
532987da915Sopenharmony_ci        if (node->name == NULL) {
533987da915Sopenharmony_ci            s = NULL;
534987da915Sopenharmony_ci            break;
535987da915Sopenharmony_ci        }
536987da915Sopenharmony_ci
537987da915Sopenharmony_ci        s = add_name(&buf, &bufsize, s, node->name);
538987da915Sopenharmony_ci        if (s == NULL)
539987da915Sopenharmony_ci            break;
540987da915Sopenharmony_ci    }
541987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
542987da915Sopenharmony_ci
543987da915Sopenharmony_ci    if (node == NULL || s == NULL)
544987da915Sopenharmony_ci        goto out_free;
545987da915Sopenharmony_ci
546987da915Sopenharmony_ci    if (s[0])
547987da915Sopenharmony_ci            memmove(buf, s, bufsize - (s - buf));
548987da915Sopenharmony_ci    else
549987da915Sopenharmony_ci            strcpy(buf, "/");
550987da915Sopenharmony_ci    return buf;
551987da915Sopenharmony_ci
552987da915Sopenharmony_ciout_free:
553987da915Sopenharmony_ci    free(buf);
554987da915Sopenharmony_ci    return NULL;
555987da915Sopenharmony_ci#endif /* __SOLARIS__ */
556987da915Sopenharmony_ci}
557987da915Sopenharmony_ci
558987da915Sopenharmony_cistatic char *get_path(struct fuse *f, fuse_ino_t nodeid)
559987da915Sopenharmony_ci{
560987da915Sopenharmony_ci    return get_path_name(f, nodeid, NULL);
561987da915Sopenharmony_ci}
562987da915Sopenharmony_ci
563987da915Sopenharmony_cistatic void forget_node(struct fuse *f, fuse_ino_t nodeid, uint64_t nlookup)
564987da915Sopenharmony_ci{
565987da915Sopenharmony_ci    struct node *node;
566987da915Sopenharmony_ci    if (nodeid == FUSE_ROOT_ID)
567987da915Sopenharmony_ci        return;
568987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
569987da915Sopenharmony_ci    node = get_node(f, nodeid);
570987da915Sopenharmony_ci    assert(node->nlookup >= nlookup);
571987da915Sopenharmony_ci    node->nlookup -= nlookup;
572987da915Sopenharmony_ci    if (!node->nlookup) {
573987da915Sopenharmony_ci        unhash_name(f, node);
574987da915Sopenharmony_ci        unref_node(f, node);
575987da915Sopenharmony_ci    }
576987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
577987da915Sopenharmony_ci}
578987da915Sopenharmony_ci
579987da915Sopenharmony_cistatic void remove_node(struct fuse *f, fuse_ino_t dir, const char *name)
580987da915Sopenharmony_ci{
581987da915Sopenharmony_ci    struct node *node;
582987da915Sopenharmony_ci
583987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
584987da915Sopenharmony_ci    node = lookup_node(f, dir, name);
585987da915Sopenharmony_ci    if (node != NULL)
586987da915Sopenharmony_ci        unhash_name(f, node);
587987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
588987da915Sopenharmony_ci}
589987da915Sopenharmony_ci
590987da915Sopenharmony_cistatic int rename_node(struct fuse *f, fuse_ino_t olddir, const char *oldname,
591987da915Sopenharmony_ci                        fuse_ino_t newdir, const char *newname, int hide)
592987da915Sopenharmony_ci{
593987da915Sopenharmony_ci    struct node *node;
594987da915Sopenharmony_ci    struct node *newnode;
595987da915Sopenharmony_ci    int err = 0;
596987da915Sopenharmony_ci
597987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
598987da915Sopenharmony_ci    node  = lookup_node(f, olddir, oldname);
599987da915Sopenharmony_ci    newnode  = lookup_node(f, newdir, newname);
600987da915Sopenharmony_ci    if (node == NULL)
601987da915Sopenharmony_ci        goto out;
602987da915Sopenharmony_ci
603987da915Sopenharmony_ci    if (newnode != NULL) {
604987da915Sopenharmony_ci        if (hide) {
605987da915Sopenharmony_ci            fprintf(stderr, "fuse: hidden file got created during hiding\n");
606987da915Sopenharmony_ci            err = -EBUSY;
607987da915Sopenharmony_ci            goto out;
608987da915Sopenharmony_ci        }
609987da915Sopenharmony_ci        unhash_name(f, newnode);
610987da915Sopenharmony_ci    }
611987da915Sopenharmony_ci
612987da915Sopenharmony_ci    unhash_name(f, node);
613987da915Sopenharmony_ci    if (hash_name(f, node, newdir, newname) == -1) {
614987da915Sopenharmony_ci        err = -ENOMEM;
615987da915Sopenharmony_ci        goto out;
616987da915Sopenharmony_ci    }
617987da915Sopenharmony_ci
618987da915Sopenharmony_ci    if (hide)
619987da915Sopenharmony_ci        node->is_hidden = 1;
620987da915Sopenharmony_ci
621987da915Sopenharmony_ci out:
622987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
623987da915Sopenharmony_ci    return err;
624987da915Sopenharmony_ci}
625987da915Sopenharmony_ci
626987da915Sopenharmony_cistatic void set_stat(struct fuse *f, fuse_ino_t nodeid, struct stat *stbuf)
627987da915Sopenharmony_ci{
628987da915Sopenharmony_ci    if (!f->conf.use_ino)
629987da915Sopenharmony_ci        stbuf->st_ino = nodeid;
630987da915Sopenharmony_ci    if (f->conf.set_mode)
631987da915Sopenharmony_ci        stbuf->st_mode = (stbuf->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
632987da915Sopenharmony_ci    if (f->conf.set_uid)
633987da915Sopenharmony_ci        stbuf->st_uid = f->conf.uid;
634987da915Sopenharmony_ci    if (f->conf.set_gid)
635987da915Sopenharmony_ci        stbuf->st_gid = f->conf.gid;
636987da915Sopenharmony_ci}
637987da915Sopenharmony_ci
638987da915Sopenharmony_cistatic struct fuse *req_fuse(fuse_req_t req)
639987da915Sopenharmony_ci{
640987da915Sopenharmony_ci    return (struct fuse *) fuse_req_userdata(req);
641987da915Sopenharmony_ci}
642987da915Sopenharmony_ci
643987da915Sopenharmony_cistatic void fuse_intr_sighandler(int sig)
644987da915Sopenharmony_ci{
645987da915Sopenharmony_ci    (void) sig;
646987da915Sopenharmony_ci    /* Nothing to do */
647987da915Sopenharmony_ci}
648987da915Sopenharmony_ci
649987da915Sopenharmony_cistruct fuse_intr_data {
650987da915Sopenharmony_ci    pthread_t id;
651987da915Sopenharmony_ci    pthread_cond_t cond;
652987da915Sopenharmony_ci    int finished;
653987da915Sopenharmony_ci};
654987da915Sopenharmony_ci
655987da915Sopenharmony_cistatic void fuse_interrupt(fuse_req_t req, void *d_)
656987da915Sopenharmony_ci{
657987da915Sopenharmony_ci    struct fuse_intr_data *d = d_;
658987da915Sopenharmony_ci    struct fuse *f = req_fuse(req);
659987da915Sopenharmony_ci
660987da915Sopenharmony_ci    if (d->id == pthread_self())
661987da915Sopenharmony_ci        return;
662987da915Sopenharmony_ci
663987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
664987da915Sopenharmony_ci    while (!d->finished) {
665987da915Sopenharmony_ci        struct timeval now;
666987da915Sopenharmony_ci        struct timespec timeout;
667987da915Sopenharmony_ci
668987da915Sopenharmony_ci        pthread_kill(d->id, f->conf.intr_signal);
669987da915Sopenharmony_ci        gettimeofday(&now, NULL);
670987da915Sopenharmony_ci        timeout.tv_sec = now.tv_sec + 1;
671987da915Sopenharmony_ci        timeout.tv_nsec = now.tv_usec * 1000;
672987da915Sopenharmony_ci        pthread_cond_timedwait(&d->cond, &f->lock, &timeout);
673987da915Sopenharmony_ci    }
674987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
675987da915Sopenharmony_ci}
676987da915Sopenharmony_ci
677987da915Sopenharmony_cistatic void fuse_do_finish_interrupt(struct fuse *f, fuse_req_t req,
678987da915Sopenharmony_ci                                     struct fuse_intr_data *d)
679987da915Sopenharmony_ci{
680987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
681987da915Sopenharmony_ci    d->finished = 1;
682987da915Sopenharmony_ci    pthread_cond_broadcast(&d->cond);
683987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
684987da915Sopenharmony_ci    fuse_req_interrupt_func(req, NULL, NULL);
685987da915Sopenharmony_ci    pthread_cond_destroy(&d->cond);
686987da915Sopenharmony_ci}
687987da915Sopenharmony_ci
688987da915Sopenharmony_cistatic void fuse_do_prepare_interrupt(fuse_req_t req, struct fuse_intr_data *d)
689987da915Sopenharmony_ci{
690987da915Sopenharmony_ci    d->id = pthread_self();
691987da915Sopenharmony_ci    pthread_cond_init(&d->cond, NULL);
692987da915Sopenharmony_ci    d->finished = 0;
693987da915Sopenharmony_ci    fuse_req_interrupt_func(req, fuse_interrupt, d);
694987da915Sopenharmony_ci}
695987da915Sopenharmony_ci
696987da915Sopenharmony_cistatic void fuse_finish_interrupt(struct fuse *f, fuse_req_t req,
697987da915Sopenharmony_ci                                         struct fuse_intr_data *d)
698987da915Sopenharmony_ci{
699987da915Sopenharmony_ci    if (f->conf.intr)
700987da915Sopenharmony_ci        fuse_do_finish_interrupt(f, req, d);
701987da915Sopenharmony_ci}
702987da915Sopenharmony_ci
703987da915Sopenharmony_cistatic void fuse_prepare_interrupt(struct fuse *f, fuse_req_t req,
704987da915Sopenharmony_ci                                          struct fuse_intr_data *d)
705987da915Sopenharmony_ci{
706987da915Sopenharmony_ci    if (f->conf.intr)
707987da915Sopenharmony_ci        fuse_do_prepare_interrupt(req, d);
708987da915Sopenharmony_ci}
709987da915Sopenharmony_ci
710987da915Sopenharmony_ciint fuse_fs_getattr(struct fuse_fs *fs, const char *path, struct stat *buf)
711987da915Sopenharmony_ci{
712987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
713987da915Sopenharmony_ci    if (fs->op.getattr)
714987da915Sopenharmony_ci        return fs->op.getattr(path, buf);
715987da915Sopenharmony_ci    else
716987da915Sopenharmony_ci        return -ENOSYS;
717987da915Sopenharmony_ci}
718987da915Sopenharmony_ci
719987da915Sopenharmony_ciint fuse_fs_fgetattr(struct fuse_fs *fs, const char *path, struct stat *buf,
720987da915Sopenharmony_ci                     struct fuse_file_info *fi)
721987da915Sopenharmony_ci{
722987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
723987da915Sopenharmony_ci    if (fs->op.fgetattr)
724987da915Sopenharmony_ci        return fs->op.fgetattr(path, buf, fi);
725987da915Sopenharmony_ci    else if (fs->op.getattr)
726987da915Sopenharmony_ci        return fs->op.getattr(path, buf);
727987da915Sopenharmony_ci    else
728987da915Sopenharmony_ci        return -ENOSYS;
729987da915Sopenharmony_ci}
730987da915Sopenharmony_ci
731987da915Sopenharmony_ciint fuse_fs_rename(struct fuse_fs *fs, const char *oldpath,
732987da915Sopenharmony_ci                   const char *newpath)
733987da915Sopenharmony_ci{
734987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
735987da915Sopenharmony_ci    if (fs->op.rename)
736987da915Sopenharmony_ci        return fs->op.rename(oldpath, newpath);
737987da915Sopenharmony_ci    else
738987da915Sopenharmony_ci        return -ENOSYS;
739987da915Sopenharmony_ci}
740987da915Sopenharmony_ci
741987da915Sopenharmony_ciint fuse_fs_unlink(struct fuse_fs *fs, const char *path)
742987da915Sopenharmony_ci{
743987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
744987da915Sopenharmony_ci    if (fs->op.unlink)
745987da915Sopenharmony_ci        return fs->op.unlink(path);
746987da915Sopenharmony_ci    else
747987da915Sopenharmony_ci        return -ENOSYS;
748987da915Sopenharmony_ci}
749987da915Sopenharmony_ci
750987da915Sopenharmony_ciint fuse_fs_rmdir(struct fuse_fs *fs, const char *path)
751987da915Sopenharmony_ci{
752987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
753987da915Sopenharmony_ci    if (fs->op.rmdir)
754987da915Sopenharmony_ci        return fs->op.rmdir(path);
755987da915Sopenharmony_ci    else
756987da915Sopenharmony_ci        return -ENOSYS;
757987da915Sopenharmony_ci}
758987da915Sopenharmony_ci
759987da915Sopenharmony_ciint fuse_fs_symlink(struct fuse_fs *fs, const char *linkname, const char *path)
760987da915Sopenharmony_ci{
761987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
762987da915Sopenharmony_ci    if (fs->op.symlink)
763987da915Sopenharmony_ci        return fs->op.symlink(linkname, path);
764987da915Sopenharmony_ci    else
765987da915Sopenharmony_ci        return -ENOSYS;
766987da915Sopenharmony_ci}
767987da915Sopenharmony_ci
768987da915Sopenharmony_ciint fuse_fs_link(struct fuse_fs *fs, const char *oldpath, const char *newpath)
769987da915Sopenharmony_ci{
770987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
771987da915Sopenharmony_ci    if (fs->op.link)
772987da915Sopenharmony_ci        return fs->op.link(oldpath, newpath);
773987da915Sopenharmony_ci    else
774987da915Sopenharmony_ci        return -ENOSYS;
775987da915Sopenharmony_ci}
776987da915Sopenharmony_ci
777987da915Sopenharmony_ciint fuse_fs_release(struct fuse_fs *fs,  const char *path,
778987da915Sopenharmony_ci                    struct fuse_file_info *fi)
779987da915Sopenharmony_ci{
780987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
781987da915Sopenharmony_ci    if (fs->op.release)
782987da915Sopenharmony_ci        return fs->op.release(path, fi);
783987da915Sopenharmony_ci    else
784987da915Sopenharmony_ci        return 0;
785987da915Sopenharmony_ci}
786987da915Sopenharmony_ci
787987da915Sopenharmony_ciint fuse_fs_opendir(struct fuse_fs *fs, const char *path,
788987da915Sopenharmony_ci                    struct fuse_file_info *fi)
789987da915Sopenharmony_ci{
790987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
791987da915Sopenharmony_ci    if (fs->op.opendir)
792987da915Sopenharmony_ci        return fs->op.opendir(path, fi);
793987da915Sopenharmony_ci    else
794987da915Sopenharmony_ci        return 0;
795987da915Sopenharmony_ci}
796987da915Sopenharmony_ci
797987da915Sopenharmony_ciint fuse_fs_open(struct fuse_fs *fs, const char *path,
798987da915Sopenharmony_ci                 struct fuse_file_info *fi)
799987da915Sopenharmony_ci{
800987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
801987da915Sopenharmony_ci    if (fs->op.open)
802987da915Sopenharmony_ci        return fs->op.open(path, fi);
803987da915Sopenharmony_ci    else
804987da915Sopenharmony_ci        return 0;
805987da915Sopenharmony_ci}
806987da915Sopenharmony_ci
807987da915Sopenharmony_ciint fuse_fs_read(struct fuse_fs *fs, const char *path, char *buf, size_t size,
808987da915Sopenharmony_ci                 off_t off, struct fuse_file_info *fi)
809987da915Sopenharmony_ci{
810987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
811987da915Sopenharmony_ci    if (fs->op.read)
812987da915Sopenharmony_ci        return fs->op.read(path, buf, size, off, fi);
813987da915Sopenharmony_ci    else
814987da915Sopenharmony_ci        return -ENOSYS;
815987da915Sopenharmony_ci}
816987da915Sopenharmony_ci
817987da915Sopenharmony_ciint fuse_fs_write(struct fuse_fs *fs, const char *path, const char *buf,
818987da915Sopenharmony_ci                  size_t size, off_t off, struct fuse_file_info *fi)
819987da915Sopenharmony_ci{
820987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
821987da915Sopenharmony_ci    if (fs->op.write)
822987da915Sopenharmony_ci        return fs->op.write(path, buf, size, off, fi);
823987da915Sopenharmony_ci    else
824987da915Sopenharmony_ci        return -ENOSYS;
825987da915Sopenharmony_ci}
826987da915Sopenharmony_ci
827987da915Sopenharmony_ciint fuse_fs_fsync(struct fuse_fs *fs, const char *path, int datasync,
828987da915Sopenharmony_ci                  struct fuse_file_info *fi)
829987da915Sopenharmony_ci{
830987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
831987da915Sopenharmony_ci    if (fs->op.fsync)
832987da915Sopenharmony_ci        return fs->op.fsync(path, datasync, fi);
833987da915Sopenharmony_ci    else
834987da915Sopenharmony_ci        return -ENOSYS;
835987da915Sopenharmony_ci}
836987da915Sopenharmony_ci
837987da915Sopenharmony_ciint fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
838987da915Sopenharmony_ci                     struct fuse_file_info *fi)
839987da915Sopenharmony_ci{
840987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
841987da915Sopenharmony_ci    if (fs->op.fsyncdir)
842987da915Sopenharmony_ci        return fs->op.fsyncdir(path, datasync, fi);
843987da915Sopenharmony_ci    else
844987da915Sopenharmony_ci        return -ENOSYS;
845987da915Sopenharmony_ci}
846987da915Sopenharmony_ci
847987da915Sopenharmony_ciint fuse_fs_flush(struct fuse_fs *fs, const char *path,
848987da915Sopenharmony_ci                  struct fuse_file_info *fi)
849987da915Sopenharmony_ci{
850987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
851987da915Sopenharmony_ci    if (fs->op.flush)
852987da915Sopenharmony_ci        return fs->op.flush(path, fi);
853987da915Sopenharmony_ci    else
854987da915Sopenharmony_ci        return -ENOSYS;
855987da915Sopenharmony_ci}
856987da915Sopenharmony_ci
857987da915Sopenharmony_ciint fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf)
858987da915Sopenharmony_ci{
859987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
860987da915Sopenharmony_ci    if (fs->op.statfs)
861987da915Sopenharmony_ci        return fs->op.statfs(path, buf);
862987da915Sopenharmony_ci    else {
863987da915Sopenharmony_ci        buf->f_namemax = 255;
864987da915Sopenharmony_ci        buf->f_bsize = 512;
865987da915Sopenharmony_ci        return 0;
866987da915Sopenharmony_ci    }
867987da915Sopenharmony_ci}
868987da915Sopenharmony_ci
869987da915Sopenharmony_ciint fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
870987da915Sopenharmony_ci                       struct fuse_file_info *fi)
871987da915Sopenharmony_ci{
872987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
873987da915Sopenharmony_ci    if (fs->op.releasedir)
874987da915Sopenharmony_ci        return fs->op.releasedir(path, fi);
875987da915Sopenharmony_ci    else
876987da915Sopenharmony_ci        return 0;
877987da915Sopenharmony_ci}
878987da915Sopenharmony_ci
879987da915Sopenharmony_ciint fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
880987da915Sopenharmony_ci                    fuse_fill_dir_t filler, off_t off,
881987da915Sopenharmony_ci                    struct fuse_file_info *fi)
882987da915Sopenharmony_ci{
883987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
884987da915Sopenharmony_ci    if (fs->op.readdir)
885987da915Sopenharmony_ci        return fs->op.readdir(path, buf, filler, off, fi);
886987da915Sopenharmony_ci    else
887987da915Sopenharmony_ci        return -ENOSYS;
888987da915Sopenharmony_ci}
889987da915Sopenharmony_ci
890987da915Sopenharmony_ciint fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
891987da915Sopenharmony_ci                   struct fuse_file_info *fi)
892987da915Sopenharmony_ci{
893987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
894987da915Sopenharmony_ci    if (fs->op.create)
895987da915Sopenharmony_ci        return fs->op.create(path, mode, fi);
896987da915Sopenharmony_ci    else
897987da915Sopenharmony_ci        return -ENOSYS;
898987da915Sopenharmony_ci}
899987da915Sopenharmony_ci
900987da915Sopenharmony_ciint fuse_fs_lock(struct fuse_fs *fs, const char *path,
901987da915Sopenharmony_ci                 struct fuse_file_info *fi, int cmd, struct flock *lock)
902987da915Sopenharmony_ci{
903987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
904987da915Sopenharmony_ci    if (fs->op.lock)
905987da915Sopenharmony_ci        return fs->op.lock(path, fi, cmd, lock);
906987da915Sopenharmony_ci    else
907987da915Sopenharmony_ci        return -ENOSYS;
908987da915Sopenharmony_ci}
909987da915Sopenharmony_ci
910987da915Sopenharmony_ciint fuse_fs_chown(struct fuse_fs *fs, const char *path, uid_t uid, gid_t gid)
911987da915Sopenharmony_ci{
912987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
913987da915Sopenharmony_ci    if (fs->op.chown)
914987da915Sopenharmony_ci        return fs->op.chown(path, uid, gid);
915987da915Sopenharmony_ci    else
916987da915Sopenharmony_ci        return -ENOSYS;
917987da915Sopenharmony_ci}
918987da915Sopenharmony_ci
919987da915Sopenharmony_ciint fuse_fs_truncate(struct fuse_fs *fs, const char *path, off_t size)
920987da915Sopenharmony_ci{
921987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
922987da915Sopenharmony_ci    if (fs->op.truncate)
923987da915Sopenharmony_ci        return fs->op.truncate(path, size);
924987da915Sopenharmony_ci    else
925987da915Sopenharmony_ci        return -ENOSYS;
926987da915Sopenharmony_ci}
927987da915Sopenharmony_ci
928987da915Sopenharmony_ciint fuse_fs_ftruncate(struct fuse_fs *fs, const char *path, off_t size,
929987da915Sopenharmony_ci                      struct fuse_file_info *fi)
930987da915Sopenharmony_ci{
931987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
932987da915Sopenharmony_ci    if (fs->op.ftruncate)
933987da915Sopenharmony_ci        return fs->op.ftruncate(path, size, fi);
934987da915Sopenharmony_ci    else if (fs->op.truncate)
935987da915Sopenharmony_ci        return fs->op.truncate(path, size);
936987da915Sopenharmony_ci    else
937987da915Sopenharmony_ci        return -ENOSYS;
938987da915Sopenharmony_ci}
939987da915Sopenharmony_ci
940987da915Sopenharmony_ciint fuse_fs_utimens(struct fuse_fs *fs, const char *path,
941987da915Sopenharmony_ci                    const struct timespec tv[2])
942987da915Sopenharmony_ci{
943987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
944987da915Sopenharmony_ci    if (fs->op.utimens)
945987da915Sopenharmony_ci        return fs->op.utimens(path, tv);
946987da915Sopenharmony_ci    else if(fs->op.utime) {
947987da915Sopenharmony_ci        struct utimbuf buf;
948987da915Sopenharmony_ci        buf.actime = tv[0].tv_sec;
949987da915Sopenharmony_ci        buf.modtime = tv[1].tv_sec;
950987da915Sopenharmony_ci        return fs->op.utime(path, &buf);
951987da915Sopenharmony_ci    } else
952987da915Sopenharmony_ci        return -ENOSYS;
953987da915Sopenharmony_ci}
954987da915Sopenharmony_ci
955987da915Sopenharmony_ciint fuse_fs_access(struct fuse_fs *fs, const char *path, int mask)
956987da915Sopenharmony_ci{
957987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
958987da915Sopenharmony_ci    if (fs->op.access)
959987da915Sopenharmony_ci        return fs->op.access(path, mask);
960987da915Sopenharmony_ci    else
961987da915Sopenharmony_ci        return -ENOSYS;
962987da915Sopenharmony_ci}
963987da915Sopenharmony_ci
964987da915Sopenharmony_ciint fuse_fs_readlink(struct fuse_fs *fs, const char *path, char *buf,
965987da915Sopenharmony_ci                     size_t len)
966987da915Sopenharmony_ci{
967987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
968987da915Sopenharmony_ci    if (fs->op.readlink)
969987da915Sopenharmony_ci        return fs->op.readlink(path, buf, len);
970987da915Sopenharmony_ci    else
971987da915Sopenharmony_ci        return -ENOSYS;
972987da915Sopenharmony_ci}
973987da915Sopenharmony_ci
974987da915Sopenharmony_ciint fuse_fs_mknod(struct fuse_fs *fs, const char *path, mode_t mode,
975987da915Sopenharmony_ci                  dev_t rdev)
976987da915Sopenharmony_ci{
977987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
978987da915Sopenharmony_ci    if (fs->op.mknod)
979987da915Sopenharmony_ci        return fs->op.mknod(path, mode, rdev);
980987da915Sopenharmony_ci    else
981987da915Sopenharmony_ci        return -ENOSYS;
982987da915Sopenharmony_ci}
983987da915Sopenharmony_ci
984987da915Sopenharmony_ciint fuse_fs_mkdir(struct fuse_fs *fs, const char *path, mode_t mode)
985987da915Sopenharmony_ci{
986987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
987987da915Sopenharmony_ci    if (fs->op.mkdir)
988987da915Sopenharmony_ci        return fs->op.mkdir(path, mode);
989987da915Sopenharmony_ci    else
990987da915Sopenharmony_ci        return -ENOSYS;
991987da915Sopenharmony_ci}
992987da915Sopenharmony_ci
993987da915Sopenharmony_ciint fuse_fs_setxattr(struct fuse_fs *fs, const char *path, const char *name,
994987da915Sopenharmony_ci                     const char *value, size_t size, int flags)
995987da915Sopenharmony_ci{
996987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
997987da915Sopenharmony_ci    if (fs->op.setxattr)
998987da915Sopenharmony_ci        return fs->op.setxattr(path, name, value, size, flags);
999987da915Sopenharmony_ci    else
1000987da915Sopenharmony_ci        return -ENOSYS;
1001987da915Sopenharmony_ci}
1002987da915Sopenharmony_ci
1003987da915Sopenharmony_ciint fuse_fs_getxattr(struct fuse_fs *fs, const char *path, const char *name,
1004987da915Sopenharmony_ci                     char *value, size_t size)
1005987da915Sopenharmony_ci{
1006987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1007987da915Sopenharmony_ci    if (fs->op.getxattr)
1008987da915Sopenharmony_ci        return fs->op.getxattr(path, name, value, size);
1009987da915Sopenharmony_ci    else
1010987da915Sopenharmony_ci        return -ENOSYS;
1011987da915Sopenharmony_ci}
1012987da915Sopenharmony_ci
1013987da915Sopenharmony_ciint fuse_fs_listxattr(struct fuse_fs *fs, const char *path, char *list,
1014987da915Sopenharmony_ci                      size_t size)
1015987da915Sopenharmony_ci{
1016987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1017987da915Sopenharmony_ci    if (fs->op.listxattr)
1018987da915Sopenharmony_ci        return fs->op.listxattr(path, list, size);
1019987da915Sopenharmony_ci    else
1020987da915Sopenharmony_ci        return -ENOSYS;
1021987da915Sopenharmony_ci}
1022987da915Sopenharmony_ci
1023987da915Sopenharmony_ciint fuse_fs_bmap(struct fuse_fs *fs, const char *path, size_t blocksize,
1024987da915Sopenharmony_ci                 uint64_t *idx)
1025987da915Sopenharmony_ci{
1026987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1027987da915Sopenharmony_ci    if (fs->op.bmap)
1028987da915Sopenharmony_ci        return fs->op.bmap(path, blocksize, idx);
1029987da915Sopenharmony_ci    else
1030987da915Sopenharmony_ci        return -ENOSYS;
1031987da915Sopenharmony_ci}
1032987da915Sopenharmony_ci
1033987da915Sopenharmony_ciint fuse_fs_removexattr(struct fuse_fs *fs, const char *path, const char *name)
1034987da915Sopenharmony_ci{
1035987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1036987da915Sopenharmony_ci    if (fs->op.removexattr)
1037987da915Sopenharmony_ci        return fs->op.removexattr(path, name);
1038987da915Sopenharmony_ci    else
1039987da915Sopenharmony_ci        return -ENOSYS;
1040987da915Sopenharmony_ci}
1041987da915Sopenharmony_ci
1042987da915Sopenharmony_ciint fuse_fs_ioctl(struct fuse_fs *fs, const char *path, int cmd, void *arg,
1043987da915Sopenharmony_ci		  struct fuse_file_info *fi, unsigned int flags, void *data)
1044987da915Sopenharmony_ci{
1045987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1046987da915Sopenharmony_ci    if (fs->op.ioctl) {
1047987da915Sopenharmony_ci/*
1048987da915Sopenharmony_ci	if (fs->debug)
1049987da915Sopenharmony_ci	    fprintf(stderr, "ioctl[%llu] 0x%x flags: 0x%x\n",
1050987da915Sopenharmony_ci		    (unsigned long long) fi->fh, cmd, flags);
1051987da915Sopenharmony_ci*/
1052987da915Sopenharmony_ci	return fs->op.ioctl(path, cmd, arg, fi, flags, data);
1053987da915Sopenharmony_ci    } else
1054987da915Sopenharmony_ci	return -ENOSYS;
1055987da915Sopenharmony_ci}
1056987da915Sopenharmony_ci
1057987da915Sopenharmony_cistatic int is_open(struct fuse *f, fuse_ino_t dir, const char *name)
1058987da915Sopenharmony_ci{
1059987da915Sopenharmony_ci    struct node *node;
1060987da915Sopenharmony_ci    int isopen = 0;
1061987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
1062987da915Sopenharmony_ci    node = lookup_node(f, dir, name);
1063987da915Sopenharmony_ci    if (node && node->open_count > 0)
1064987da915Sopenharmony_ci        isopen = 1;
1065987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
1066987da915Sopenharmony_ci    return isopen;
1067987da915Sopenharmony_ci}
1068987da915Sopenharmony_ci
1069987da915Sopenharmony_cistatic char *hidden_name(struct fuse *f, fuse_ino_t dir, const char *oldname,
1070987da915Sopenharmony_ci                         char *newname, size_t bufsize)
1071987da915Sopenharmony_ci{
1072987da915Sopenharmony_ci    struct stat buf;
1073987da915Sopenharmony_ci    struct node *node;
1074987da915Sopenharmony_ci    struct node *newnode;
1075987da915Sopenharmony_ci    char *newpath;
1076987da915Sopenharmony_ci    int res;
1077987da915Sopenharmony_ci    int failctr = 10;
1078987da915Sopenharmony_ci
1079987da915Sopenharmony_ci    do {
1080987da915Sopenharmony_ci        pthread_mutex_lock(&f->lock);
1081987da915Sopenharmony_ci        node = lookup_node(f, dir, oldname);
1082987da915Sopenharmony_ci        if (node == NULL) {
1083987da915Sopenharmony_ci            pthread_mutex_unlock(&f->lock);
1084987da915Sopenharmony_ci            return NULL;
1085987da915Sopenharmony_ci        }
1086987da915Sopenharmony_ci        do {
1087987da915Sopenharmony_ci            f->hidectr ++;
1088987da915Sopenharmony_ci            snprintf(newname, bufsize, ".fuse_hidden%08x%08x",
1089987da915Sopenharmony_ci                     (unsigned int) node->nodeid, f->hidectr);
1090987da915Sopenharmony_ci            newnode = lookup_node(f, dir, newname);
1091987da915Sopenharmony_ci        } while(newnode);
1092987da915Sopenharmony_ci        pthread_mutex_unlock(&f->lock);
1093987da915Sopenharmony_ci
1094987da915Sopenharmony_ci        newpath = get_path_name(f, dir, newname);
1095987da915Sopenharmony_ci        if (!newpath)
1096987da915Sopenharmony_ci            break;
1097987da915Sopenharmony_ci
1098987da915Sopenharmony_ci        res = fuse_fs_getattr(f->fs, newpath, &buf);
1099987da915Sopenharmony_ci        if (res == -ENOENT)
1100987da915Sopenharmony_ci            break;
1101987da915Sopenharmony_ci        free(newpath);
1102987da915Sopenharmony_ci        newpath = NULL;
1103987da915Sopenharmony_ci    } while(res == 0 && --failctr);
1104987da915Sopenharmony_ci
1105987da915Sopenharmony_ci    return newpath;
1106987da915Sopenharmony_ci}
1107987da915Sopenharmony_ci
1108987da915Sopenharmony_cistatic int hide_node(struct fuse *f, const char *oldpath,
1109987da915Sopenharmony_ci                     fuse_ino_t dir, const char *oldname)
1110987da915Sopenharmony_ci{
1111987da915Sopenharmony_ci    char newname[64];
1112987da915Sopenharmony_ci    char *newpath;
1113987da915Sopenharmony_ci    int err = -EBUSY;
1114987da915Sopenharmony_ci
1115987da915Sopenharmony_ci    newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
1116987da915Sopenharmony_ci    if (newpath) {
1117987da915Sopenharmony_ci        err = fuse_fs_rename(f->fs, oldpath, newpath);
1118987da915Sopenharmony_ci        if (!err)
1119987da915Sopenharmony_ci            err = rename_node(f, dir, oldname, dir, newname, 1);
1120987da915Sopenharmony_ci        free(newpath);
1121987da915Sopenharmony_ci    }
1122987da915Sopenharmony_ci    return err;
1123987da915Sopenharmony_ci}
1124987da915Sopenharmony_ci
1125987da915Sopenharmony_ci#ifdef __SOLARIS__
1126987da915Sopenharmony_ci
1127987da915Sopenharmony_cistatic int mtime_eq(const struct stat *stbuf, const struct timespec *ts)
1128987da915Sopenharmony_ci{
1129987da915Sopenharmony_ci    return stbuf->st_mtime == ts->tv_sec && ST_MTIM_NSEC(stbuf) == ts->tv_nsec;
1130987da915Sopenharmony_ci}
1131987da915Sopenharmony_ci
1132987da915Sopenharmony_ci#ifndef CLOCK_MONOTONIC
1133987da915Sopenharmony_ci#define CLOCK_MONOTONIC CLOCK_REALTIME
1134987da915Sopenharmony_ci#endif
1135987da915Sopenharmony_ci
1136987da915Sopenharmony_cistatic void curr_time(struct timespec *now)
1137987da915Sopenharmony_ci{
1138987da915Sopenharmony_ci    static clockid_t clockid = CLOCK_MONOTONIC;
1139987da915Sopenharmony_ci    int res = clock_gettime(clockid, now);
1140987da915Sopenharmony_ci    if (res == -1 && errno == EINVAL) {
1141987da915Sopenharmony_ci        clockid = CLOCK_REALTIME;
1142987da915Sopenharmony_ci        res = clock_gettime(clockid, now);
1143987da915Sopenharmony_ci    }
1144987da915Sopenharmony_ci    if (res == -1) {
1145987da915Sopenharmony_ci        perror("fuse: clock_gettime");
1146987da915Sopenharmony_ci        abort();
1147987da915Sopenharmony_ci    }
1148987da915Sopenharmony_ci}
1149987da915Sopenharmony_ci
1150987da915Sopenharmony_cistatic void update_stat(struct node *node, const struct stat *stbuf)
1151987da915Sopenharmony_ci{
1152987da915Sopenharmony_ci    if (node->cache_valid && (!mtime_eq(stbuf, &node->mtime) ||
1153987da915Sopenharmony_ci                              stbuf->st_size != node->size))
1154987da915Sopenharmony_ci        node->cache_valid = 0;
1155987da915Sopenharmony_ci    node->mtime.tv_sec = stbuf->st_mtime;
1156987da915Sopenharmony_ci    node->mtime.tv_nsec = ST_MTIM_NSEC(stbuf);
1157987da915Sopenharmony_ci    node->size = stbuf->st_size;
1158987da915Sopenharmony_ci    curr_time(&node->stat_updated);
1159987da915Sopenharmony_ci}
1160987da915Sopenharmony_ci
1161987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1162987da915Sopenharmony_ci
1163987da915Sopenharmony_cistatic int lookup_path(struct fuse *f, fuse_ino_t nodeid,
1164987da915Sopenharmony_ci                       const char *name, const char *path,
1165987da915Sopenharmony_ci                       struct fuse_entry_param *e, struct fuse_file_info *fi)
1166987da915Sopenharmony_ci{
1167987da915Sopenharmony_ci    int res;
1168987da915Sopenharmony_ci
1169987da915Sopenharmony_ci    memset(e, 0, sizeof(struct fuse_entry_param));
1170987da915Sopenharmony_ci    if (fi)
1171987da915Sopenharmony_ci        res = fuse_fs_fgetattr(f->fs, path, &e->attr, fi);
1172987da915Sopenharmony_ci    else
1173987da915Sopenharmony_ci        res = fuse_fs_getattr(f->fs, path, &e->attr);
1174987da915Sopenharmony_ci    if (res == 0) {
1175987da915Sopenharmony_ci        struct node *node;
1176987da915Sopenharmony_ci
1177987da915Sopenharmony_ci        node = find_node(f, nodeid, name);
1178987da915Sopenharmony_ci        if (node == NULL)
1179987da915Sopenharmony_ci            res = -ENOMEM;
1180987da915Sopenharmony_ci        else {
1181987da915Sopenharmony_ci            e->ino = node->nodeid;
1182987da915Sopenharmony_ci            e->generation = node->generation;
1183987da915Sopenharmony_ci            e->entry_timeout = f->conf.entry_timeout;
1184987da915Sopenharmony_ci            e->attr_timeout = f->conf.attr_timeout;
1185987da915Sopenharmony_ci#ifdef __SOLARIS__
1186987da915Sopenharmony_ci            if (f->conf.auto_cache) {
1187987da915Sopenharmony_ci                pthread_mutex_lock(&f->lock);
1188987da915Sopenharmony_ci                update_stat(node, &e->attr);
1189987da915Sopenharmony_ci                pthread_mutex_unlock(&f->lock);
1190987da915Sopenharmony_ci            }
1191987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1192987da915Sopenharmony_ci            set_stat(f, e->ino, &e->attr);
1193987da915Sopenharmony_ci            if (f->conf.debug)
1194987da915Sopenharmony_ci                fprintf(stderr, "   NODEID: %lu\n", (unsigned long) e->ino);
1195987da915Sopenharmony_ci        }
1196987da915Sopenharmony_ci    }
1197987da915Sopenharmony_ci    return res;
1198987da915Sopenharmony_ci}
1199987da915Sopenharmony_ci
1200987da915Sopenharmony_cistatic struct fuse_context_i *fuse_get_context_internal(void)
1201987da915Sopenharmony_ci{
1202987da915Sopenharmony_ci    struct fuse_context_i *c;
1203987da915Sopenharmony_ci
1204987da915Sopenharmony_ci    c = (struct fuse_context_i *) pthread_getspecific(fuse_context_key);
1205987da915Sopenharmony_ci    if (c == NULL) {
1206987da915Sopenharmony_ci        c = (struct fuse_context_i *) malloc(sizeof(struct fuse_context_i));
1207987da915Sopenharmony_ci        if (c == NULL) {
1208987da915Sopenharmony_ci            /* This is hard to deal with properly, so just abort.  If
1209987da915Sopenharmony_ci               memory is so low that the context cannot be allocated,
1210987da915Sopenharmony_ci               there's not much hope for the filesystem anyway */
1211987da915Sopenharmony_ci            fprintf(stderr, "fuse: failed to allocate thread specific data\n");
1212987da915Sopenharmony_ci            abort();
1213987da915Sopenharmony_ci        }
1214987da915Sopenharmony_ci        pthread_setspecific(fuse_context_key, c);
1215987da915Sopenharmony_ci    }
1216987da915Sopenharmony_ci    return c;
1217987da915Sopenharmony_ci}
1218987da915Sopenharmony_ci
1219987da915Sopenharmony_cistatic void fuse_freecontext(void *data)
1220987da915Sopenharmony_ci{
1221987da915Sopenharmony_ci    free(data);
1222987da915Sopenharmony_ci}
1223987da915Sopenharmony_ci
1224987da915Sopenharmony_cistatic int fuse_create_context_key(void)
1225987da915Sopenharmony_ci{
1226987da915Sopenharmony_ci    int err = 0;
1227987da915Sopenharmony_ci    pthread_mutex_lock(&fuse_context_lock);
1228987da915Sopenharmony_ci    if (!fuse_context_ref) {
1229987da915Sopenharmony_ci        err = pthread_key_create(&fuse_context_key, fuse_freecontext);
1230987da915Sopenharmony_ci        if (err) {
1231987da915Sopenharmony_ci            fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
1232987da915Sopenharmony_ci                    strerror(err));
1233987da915Sopenharmony_ci            pthread_mutex_unlock(&fuse_context_lock);
1234987da915Sopenharmony_ci            return -1;
1235987da915Sopenharmony_ci        }
1236987da915Sopenharmony_ci    }
1237987da915Sopenharmony_ci    fuse_context_ref++;
1238987da915Sopenharmony_ci    pthread_mutex_unlock(&fuse_context_lock);
1239987da915Sopenharmony_ci    return 0;
1240987da915Sopenharmony_ci}
1241987da915Sopenharmony_ci
1242987da915Sopenharmony_cistatic void fuse_delete_context_key(void)
1243987da915Sopenharmony_ci{
1244987da915Sopenharmony_ci    pthread_mutex_lock(&fuse_context_lock);
1245987da915Sopenharmony_ci    fuse_context_ref--;
1246987da915Sopenharmony_ci    if (!fuse_context_ref) {
1247987da915Sopenharmony_ci        free(pthread_getspecific(fuse_context_key));
1248987da915Sopenharmony_ci        pthread_key_delete(fuse_context_key);
1249987da915Sopenharmony_ci    }
1250987da915Sopenharmony_ci    pthread_mutex_unlock(&fuse_context_lock);
1251987da915Sopenharmony_ci}
1252987da915Sopenharmony_ci
1253987da915Sopenharmony_cistatic struct fuse *req_fuse_prepare(fuse_req_t req)
1254987da915Sopenharmony_ci{
1255987da915Sopenharmony_ci    struct fuse_context_i *c = fuse_get_context_internal();
1256987da915Sopenharmony_ci    const struct fuse_ctx *ctx = fuse_req_ctx(req);
1257987da915Sopenharmony_ci    c->req = req;
1258987da915Sopenharmony_ci    c->ctx.fuse = req_fuse(req);
1259987da915Sopenharmony_ci    c->ctx.uid = ctx->uid;
1260987da915Sopenharmony_ci    c->ctx.gid = ctx->gid;
1261987da915Sopenharmony_ci    c->ctx.pid = ctx->pid;
1262987da915Sopenharmony_ci#ifdef POSIXACLS
1263987da915Sopenharmony_ci    c->ctx.umask = ctx->umask;
1264987da915Sopenharmony_ci#endif
1265987da915Sopenharmony_ci    return c->ctx.fuse;
1266987da915Sopenharmony_ci}
1267987da915Sopenharmony_ci
1268987da915Sopenharmony_ci#ifndef __SOLARIS__
1269987da915Sopenharmony_cistatic void reply_err(fuse_req_t req, int err)
1270987da915Sopenharmony_ci#else /* __SOLARIS__ */
1271987da915Sopenharmony_cistatic inline void reply_err(fuse_req_t req, int err)
1272987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1273987da915Sopenharmony_ci{
1274987da915Sopenharmony_ci    /* fuse_reply_err() uses non-negated errno values */
1275987da915Sopenharmony_ci    fuse_reply_err(req, -err);
1276987da915Sopenharmony_ci}
1277987da915Sopenharmony_ci
1278987da915Sopenharmony_cistatic void reply_entry(fuse_req_t req, const struct fuse_entry_param *e,
1279987da915Sopenharmony_ci                        int err)
1280987da915Sopenharmony_ci{
1281987da915Sopenharmony_ci    if (!err) {
1282987da915Sopenharmony_ci        struct fuse *f = req_fuse(req);
1283987da915Sopenharmony_ci#ifdef __SOLARIS__
1284987da915Sopenharmony_ci                     /* Skip forget for negative result */
1285987da915Sopenharmony_ci        if ((fuse_reply_entry(req, e) == -ENOENT)
1286987da915Sopenharmony_ci          && (e->ino != 0))
1287987da915Sopenharmony_ci            forget_node(f, e->ino, 1);
1288987da915Sopenharmony_ci#else /* __SOLARIS__ */
1289987da915Sopenharmony_ci        if (fuse_reply_entry(req, e) == -ENOENT)
1290987da915Sopenharmony_ci            forget_node(f, e->ino, 1);
1291987da915Sopenharmony_ci#endif
1292987da915Sopenharmony_ci    } else
1293987da915Sopenharmony_ci        reply_err(req, err);
1294987da915Sopenharmony_ci}
1295987da915Sopenharmony_ci
1296987da915Sopenharmony_civoid fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn)
1297987da915Sopenharmony_ci{
1298987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1299987da915Sopenharmony_ci    if (fs->op.init)
1300987da915Sopenharmony_ci        fs->user_data = fs->op.init(conn);
1301987da915Sopenharmony_ci}
1302987da915Sopenharmony_ci
1303987da915Sopenharmony_cistatic void fuse_lib_init(void *data, struct fuse_conn_info *conn)
1304987da915Sopenharmony_ci{
1305987da915Sopenharmony_ci    struct fuse *f = (struct fuse *) data;
1306987da915Sopenharmony_ci    struct fuse_context_i *c = fuse_get_context_internal();
1307987da915Sopenharmony_ci
1308987da915Sopenharmony_ci    memset(c, 0, sizeof(*c));
1309987da915Sopenharmony_ci    c->ctx.fuse = f;
1310987da915Sopenharmony_ci    fuse_fs_init(f->fs, conn);
1311987da915Sopenharmony_ci}
1312987da915Sopenharmony_ci
1313987da915Sopenharmony_civoid fuse_fs_destroy(struct fuse_fs *fs)
1314987da915Sopenharmony_ci{
1315987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1316987da915Sopenharmony_ci    if (fs->op.destroy)
1317987da915Sopenharmony_ci        fs->op.destroy(fs->user_data);
1318987da915Sopenharmony_ci#ifdef __SOLARIS__
1319987da915Sopenharmony_ci    if (fs->m)
1320987da915Sopenharmony_ci        fuse_put_module(fs->m);
1321987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1322987da915Sopenharmony_ci    free(fs);
1323987da915Sopenharmony_ci}
1324987da915Sopenharmony_ci
1325987da915Sopenharmony_cistatic void fuse_lib_destroy(void *data)
1326987da915Sopenharmony_ci{
1327987da915Sopenharmony_ci    struct fuse *f = (struct fuse *) data;
1328987da915Sopenharmony_ci    struct fuse_context_i *c = fuse_get_context_internal();
1329987da915Sopenharmony_ci
1330987da915Sopenharmony_ci    memset(c, 0, sizeof(*c));
1331987da915Sopenharmony_ci    c->ctx.fuse = f;
1332987da915Sopenharmony_ci    fuse_fs_destroy(f->fs);
1333987da915Sopenharmony_ci    f->fs = NULL;
1334987da915Sopenharmony_ci}
1335987da915Sopenharmony_ci
1336987da915Sopenharmony_cistatic void fuse_lib_lookup(fuse_req_t req, fuse_ino_t parent,
1337987da915Sopenharmony_ci                            const char *name)
1338987da915Sopenharmony_ci{
1339987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1340987da915Sopenharmony_ci    struct fuse_entry_param e;
1341987da915Sopenharmony_ci    char *path;
1342987da915Sopenharmony_ci    int err;
1343987da915Sopenharmony_ci
1344987da915Sopenharmony_ci    err = -ENOENT;
1345987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1346987da915Sopenharmony_ci    path = get_path_name(f, parent, name);
1347987da915Sopenharmony_ci    if (path != NULL) {
1348987da915Sopenharmony_ci        struct fuse_intr_data d;
1349987da915Sopenharmony_ci        if (f->conf.debug)
1350987da915Sopenharmony_ci            fprintf(stderr, "LOOKUP %s\n", path);
1351987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1352987da915Sopenharmony_ci        err = lookup_path(f, parent, name, path, &e, NULL);
1353987da915Sopenharmony_ci        if (err == -ENOENT && f->conf.negative_timeout != 0.0) {
1354987da915Sopenharmony_ci            e.ino = 0;
1355987da915Sopenharmony_ci            e.entry_timeout = f->conf.negative_timeout;
1356987da915Sopenharmony_ci            err = 0;
1357987da915Sopenharmony_ci        }
1358987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1359987da915Sopenharmony_ci        free(path);
1360987da915Sopenharmony_ci    }
1361987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1362987da915Sopenharmony_ci    reply_entry(req, &e, err);
1363987da915Sopenharmony_ci}
1364987da915Sopenharmony_ci
1365987da915Sopenharmony_cistatic void fuse_lib_forget(fuse_req_t req, fuse_ino_t ino,
1366987da915Sopenharmony_ci                            unsigned long nlookup)
1367987da915Sopenharmony_ci{
1368987da915Sopenharmony_ci    struct fuse *f = req_fuse(req);
1369987da915Sopenharmony_ci    if (f->conf.debug)
1370987da915Sopenharmony_ci        fprintf(stderr, "FORGET %llu/%lu\n", (unsigned long long)ino, nlookup);
1371987da915Sopenharmony_ci    forget_node(f, ino, nlookup);
1372987da915Sopenharmony_ci    fuse_reply_none(req);
1373987da915Sopenharmony_ci}
1374987da915Sopenharmony_ci
1375987da915Sopenharmony_cistatic void fuse_lib_getattr(fuse_req_t req, fuse_ino_t ino,
1376987da915Sopenharmony_ci                             struct fuse_file_info *fi)
1377987da915Sopenharmony_ci{
1378987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1379987da915Sopenharmony_ci    struct stat buf;
1380987da915Sopenharmony_ci    char *path;
1381987da915Sopenharmony_ci    int err;
1382987da915Sopenharmony_ci
1383987da915Sopenharmony_ci    (void) fi;
1384987da915Sopenharmony_ci    memset(&buf, 0, sizeof(buf));
1385987da915Sopenharmony_ci
1386987da915Sopenharmony_ci    err = -ENOENT;
1387987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1388987da915Sopenharmony_ci    path = get_path(f, ino);
1389987da915Sopenharmony_ci    if (path != NULL) {
1390987da915Sopenharmony_ci        struct fuse_intr_data d;
1391987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1392987da915Sopenharmony_ci        err = fuse_fs_getattr(f->fs, path, &buf);
1393987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1394987da915Sopenharmony_ci        free(path);
1395987da915Sopenharmony_ci    }
1396987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1397987da915Sopenharmony_ci    if (!err) {
1398987da915Sopenharmony_ci#ifdef __SOLARIS__
1399987da915Sopenharmony_ci        if (f->conf.auto_cache) {
1400987da915Sopenharmony_ci            pthread_mutex_lock(&f->lock);
1401987da915Sopenharmony_ci            update_stat(get_node(f, ino), &buf);
1402987da915Sopenharmony_ci            pthread_mutex_unlock(&f->lock);
1403987da915Sopenharmony_ci        }
1404987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1405987da915Sopenharmony_ci        set_stat(f, ino, &buf);
1406987da915Sopenharmony_ci        fuse_reply_attr(req, &buf, f->conf.attr_timeout);
1407987da915Sopenharmony_ci    } else
1408987da915Sopenharmony_ci        reply_err(req, err);
1409987da915Sopenharmony_ci}
1410987da915Sopenharmony_ci
1411987da915Sopenharmony_ciint fuse_fs_chmod(struct fuse_fs *fs, const char *path, mode_t mode)
1412987da915Sopenharmony_ci{
1413987da915Sopenharmony_ci    fuse_get_context()->private_data = fs->user_data;
1414987da915Sopenharmony_ci    if (fs->op.chmod)
1415987da915Sopenharmony_ci        return fs->op.chmod(path, mode);
1416987da915Sopenharmony_ci    else
1417987da915Sopenharmony_ci        return -ENOSYS;
1418987da915Sopenharmony_ci}
1419987da915Sopenharmony_ci
1420987da915Sopenharmony_cistatic void fuse_lib_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1421987da915Sopenharmony_ci                             int valid, struct fuse_file_info *fi)
1422987da915Sopenharmony_ci{
1423987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1424987da915Sopenharmony_ci    struct stat buf;
1425987da915Sopenharmony_ci    char *path;
1426987da915Sopenharmony_ci    int err;
1427987da915Sopenharmony_ci
1428987da915Sopenharmony_ci    err = -ENOENT;
1429987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1430987da915Sopenharmony_ci    path = get_path(f, ino);
1431987da915Sopenharmony_ci    if (path != NULL) {
1432987da915Sopenharmony_ci        struct fuse_intr_data d;
1433987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1434987da915Sopenharmony_ci        err = 0;
1435987da915Sopenharmony_ci        if (!err && (valid & FUSE_SET_ATTR_MODE))
1436987da915Sopenharmony_ci            err = fuse_fs_chmod(f->fs, path, attr->st_mode);
1437987da915Sopenharmony_ci        if (!err && (valid & (FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID))) {
1438987da915Sopenharmony_ci            uid_t uid =
1439987da915Sopenharmony_ci                (valid & FUSE_SET_ATTR_UID) ? attr->st_uid : (uid_t) -1;
1440987da915Sopenharmony_ci            gid_t gid =
1441987da915Sopenharmony_ci                (valid & FUSE_SET_ATTR_GID) ? attr->st_gid : (gid_t) -1;
1442987da915Sopenharmony_ci            err = fuse_fs_chown(f->fs, path, uid, gid);
1443987da915Sopenharmony_ci        }
1444987da915Sopenharmony_ci        if (!err && (valid & FUSE_SET_ATTR_SIZE)) {
1445987da915Sopenharmony_ci            if (fi)
1446987da915Sopenharmony_ci                err = fuse_fs_ftruncate(f->fs, path, attr->st_size, fi);
1447987da915Sopenharmony_ci            else
1448987da915Sopenharmony_ci                err = fuse_fs_truncate(f->fs, path, attr->st_size);
1449987da915Sopenharmony_ci        }
1450987da915Sopenharmony_ci#ifdef HAVE_UTIMENSAT
1451987da915Sopenharmony_ci        if (!err &&
1452987da915Sopenharmony_ci            (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) {
1453987da915Sopenharmony_ci            struct timespec tv[2];
1454987da915Sopenharmony_ci
1455987da915Sopenharmony_ci            tv[0].tv_sec = 0;
1456987da915Sopenharmony_ci            tv[1].tv_sec = 0;
1457987da915Sopenharmony_ci            tv[0].tv_nsec = UTIME_OMIT;
1458987da915Sopenharmony_ci            tv[1].tv_nsec = UTIME_OMIT;
1459987da915Sopenharmony_ci
1460987da915Sopenharmony_ci            if (valid & FUSE_SET_ATTR_ATIME_NOW)
1461987da915Sopenharmony_ci                tv[0].tv_nsec = UTIME_NOW;
1462987da915Sopenharmony_ci            else if (valid & FUSE_SET_ATTR_ATIME)
1463987da915Sopenharmony_ci                tv[0] = attr->st_atim;
1464987da915Sopenharmony_ci
1465987da915Sopenharmony_ci            if (valid & FUSE_SET_ATTR_MTIME_NOW)
1466987da915Sopenharmony_ci                tv[1].tv_nsec = UTIME_NOW;
1467987da915Sopenharmony_ci            else if (valid & FUSE_SET_ATTR_MTIME)
1468987da915Sopenharmony_ci                tv[1] = attr->st_mtim;
1469987da915Sopenharmony_ci
1470987da915Sopenharmony_ci            err = fuse_fs_utimens(f->fs, path, tv);
1471987da915Sopenharmony_ci        } else
1472987da915Sopenharmony_ci#endif
1473987da915Sopenharmony_ci        if (!err && (valid & (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) ==
1474987da915Sopenharmony_ci            (FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME)) {
1475987da915Sopenharmony_ci            struct timespec tv[2];
1476987da915Sopenharmony_ci            tv[0].tv_sec = attr->st_atime;
1477987da915Sopenharmony_ci            tv[0].tv_nsec = ST_ATIM_NSEC(attr);
1478987da915Sopenharmony_ci            tv[1].tv_sec = attr->st_mtime;
1479987da915Sopenharmony_ci            tv[1].tv_nsec = ST_MTIM_NSEC(attr);
1480987da915Sopenharmony_ci            err = fuse_fs_utimens(f->fs, path, tv);
1481987da915Sopenharmony_ci        }
1482987da915Sopenharmony_ci        if (!err)
1483987da915Sopenharmony_ci            err = fuse_fs_getattr(f->fs,  path, &buf);
1484987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1485987da915Sopenharmony_ci        free(path);
1486987da915Sopenharmony_ci    }
1487987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1488987da915Sopenharmony_ci    if (!err) {
1489987da915Sopenharmony_ci#ifdef __SOLARIS__
1490987da915Sopenharmony_ci        if (f->conf.auto_cache) {
1491987da915Sopenharmony_ci            pthread_mutex_lock(&f->lock);
1492987da915Sopenharmony_ci            update_stat(get_node(f, ino), &buf);
1493987da915Sopenharmony_ci            pthread_mutex_unlock(&f->lock);
1494987da915Sopenharmony_ci        }
1495987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1496987da915Sopenharmony_ci        set_stat(f, ino, &buf);
1497987da915Sopenharmony_ci        fuse_reply_attr(req, &buf, f->conf.attr_timeout);
1498987da915Sopenharmony_ci    } else
1499987da915Sopenharmony_ci        reply_err(req, err);
1500987da915Sopenharmony_ci}
1501987da915Sopenharmony_ci
1502987da915Sopenharmony_cistatic void fuse_lib_access(fuse_req_t req, fuse_ino_t ino, int mask)
1503987da915Sopenharmony_ci{
1504987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1505987da915Sopenharmony_ci    char *path;
1506987da915Sopenharmony_ci    int err;
1507987da915Sopenharmony_ci
1508987da915Sopenharmony_ci    err = -ENOENT;
1509987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1510987da915Sopenharmony_ci    path = get_path(f, ino);
1511987da915Sopenharmony_ci    if (path != NULL) {
1512987da915Sopenharmony_ci        struct fuse_intr_data d;
1513987da915Sopenharmony_ci        if (f->conf.debug)
1514987da915Sopenharmony_ci            fprintf(stderr, "ACCESS %s 0%o\n", path, mask);
1515987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1516987da915Sopenharmony_ci        err = fuse_fs_access(f->fs, path, mask);
1517987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1518987da915Sopenharmony_ci        free(path);
1519987da915Sopenharmony_ci    }
1520987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1521987da915Sopenharmony_ci    reply_err(req, err);
1522987da915Sopenharmony_ci}
1523987da915Sopenharmony_ci
1524987da915Sopenharmony_cistatic void fuse_lib_readlink(fuse_req_t req, fuse_ino_t ino)
1525987da915Sopenharmony_ci{
1526987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1527987da915Sopenharmony_ci    char linkname[PATH_MAX + 1];
1528987da915Sopenharmony_ci    char *path;
1529987da915Sopenharmony_ci    int err;
1530987da915Sopenharmony_ci
1531987da915Sopenharmony_ci    err = -ENOENT;
1532987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1533987da915Sopenharmony_ci    path = get_path(f, ino);
1534987da915Sopenharmony_ci    if (path != NULL) {
1535987da915Sopenharmony_ci        struct fuse_intr_data d;
1536987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1537987da915Sopenharmony_ci        err = fuse_fs_readlink(f->fs, path, linkname, sizeof(linkname));
1538987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1539987da915Sopenharmony_ci        free(path);
1540987da915Sopenharmony_ci    }
1541987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1542987da915Sopenharmony_ci    if (!err) {
1543987da915Sopenharmony_ci        linkname[PATH_MAX] = '\0';
1544987da915Sopenharmony_ci        fuse_reply_readlink(req, linkname);
1545987da915Sopenharmony_ci    } else
1546987da915Sopenharmony_ci        reply_err(req, err);
1547987da915Sopenharmony_ci}
1548987da915Sopenharmony_ci
1549987da915Sopenharmony_cistatic void fuse_lib_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1550987da915Sopenharmony_ci                           mode_t mode, dev_t rdev)
1551987da915Sopenharmony_ci{
1552987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1553987da915Sopenharmony_ci    struct fuse_entry_param e;
1554987da915Sopenharmony_ci    char *path;
1555987da915Sopenharmony_ci    int err;
1556987da915Sopenharmony_ci
1557987da915Sopenharmony_ci    err = -ENOENT;
1558987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1559987da915Sopenharmony_ci    path = get_path_name(f, parent, name);
1560987da915Sopenharmony_ci    if (path) {
1561987da915Sopenharmony_ci        struct fuse_intr_data d;
1562987da915Sopenharmony_ci        if (f->conf.debug)
1563987da915Sopenharmony_ci            fprintf(stderr, "MKNOD %s\n", path);
1564987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1565987da915Sopenharmony_ci        err = -ENOSYS;
1566987da915Sopenharmony_ci        if (S_ISREG(mode)) {
1567987da915Sopenharmony_ci            struct fuse_file_info fi;
1568987da915Sopenharmony_ci
1569987da915Sopenharmony_ci            memset(&fi, 0, sizeof(fi));
1570987da915Sopenharmony_ci            fi.flags = O_CREAT | O_EXCL | O_WRONLY;
1571987da915Sopenharmony_ci            err = fuse_fs_create(f->fs, path, mode, &fi);
1572987da915Sopenharmony_ci            if (!err) {
1573987da915Sopenharmony_ci                err = lookup_path(f, parent, name, path, &e, &fi);
1574987da915Sopenharmony_ci                fuse_fs_release(f->fs, path, &fi);
1575987da915Sopenharmony_ci            }
1576987da915Sopenharmony_ci        }
1577987da915Sopenharmony_ci        if (err == -ENOSYS) {
1578987da915Sopenharmony_ci            err = fuse_fs_mknod(f->fs, path, mode, rdev);
1579987da915Sopenharmony_ci            if (!err)
1580987da915Sopenharmony_ci                err = lookup_path(f, parent, name, path, &e, NULL);
1581987da915Sopenharmony_ci        }
1582987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1583987da915Sopenharmony_ci        free(path);
1584987da915Sopenharmony_ci    }
1585987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1586987da915Sopenharmony_ci    reply_entry(req, &e, err);
1587987da915Sopenharmony_ci}
1588987da915Sopenharmony_ci
1589987da915Sopenharmony_cistatic void fuse_lib_mkdir(fuse_req_t req, fuse_ino_t parent, const char *name,
1590987da915Sopenharmony_ci                           mode_t mode)
1591987da915Sopenharmony_ci{
1592987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1593987da915Sopenharmony_ci    struct fuse_entry_param e;
1594987da915Sopenharmony_ci    char *path;
1595987da915Sopenharmony_ci    int err;
1596987da915Sopenharmony_ci
1597987da915Sopenharmony_ci    err = -ENOENT;
1598987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1599987da915Sopenharmony_ci    path = get_path_name(f, parent, name);
1600987da915Sopenharmony_ci    if (path != NULL) {
1601987da915Sopenharmony_ci        struct fuse_intr_data d;
1602987da915Sopenharmony_ci        if (f->conf.debug)
1603987da915Sopenharmony_ci            fprintf(stderr, "MKDIR %s\n", path);
1604987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1605987da915Sopenharmony_ci        err = fuse_fs_mkdir(f->fs, path, mode);
1606987da915Sopenharmony_ci        if (!err)
1607987da915Sopenharmony_ci            err = lookup_path(f, parent, name, path, &e, NULL);
1608987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1609987da915Sopenharmony_ci        free(path);
1610987da915Sopenharmony_ci    }
1611987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1612987da915Sopenharmony_ci    reply_entry(req, &e, err);
1613987da915Sopenharmony_ci}
1614987da915Sopenharmony_ci
1615987da915Sopenharmony_cistatic void fuse_lib_unlink(fuse_req_t req, fuse_ino_t parent,
1616987da915Sopenharmony_ci                            const char *name)
1617987da915Sopenharmony_ci{
1618987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1619987da915Sopenharmony_ci    char *path;
1620987da915Sopenharmony_ci    int err;
1621987da915Sopenharmony_ci
1622987da915Sopenharmony_ci    err = -ENOENT;
1623987da915Sopenharmony_ci    pthread_rwlock_wrlock(&f->tree_lock);
1624987da915Sopenharmony_ci    path = get_path_name(f, parent, name);
1625987da915Sopenharmony_ci    if (path != NULL) {
1626987da915Sopenharmony_ci        struct fuse_intr_data d;
1627987da915Sopenharmony_ci        if (f->conf.debug)
1628987da915Sopenharmony_ci            fprintf(stderr, "UNLINK %s\n", path);
1629987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1630987da915Sopenharmony_ci        if (!f->conf.hard_remove && is_open(f, parent, name))
1631987da915Sopenharmony_ci            err = hide_node(f, path, parent, name);
1632987da915Sopenharmony_ci        else {
1633987da915Sopenharmony_ci            err = fuse_fs_unlink(f->fs, path);
1634987da915Sopenharmony_ci            if (!err)
1635987da915Sopenharmony_ci                remove_node(f, parent, name);
1636987da915Sopenharmony_ci        }
1637987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1638987da915Sopenharmony_ci        free(path);
1639987da915Sopenharmony_ci    }
1640987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1641987da915Sopenharmony_ci    reply_err(req, err);
1642987da915Sopenharmony_ci}
1643987da915Sopenharmony_ci
1644987da915Sopenharmony_cistatic void fuse_lib_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
1645987da915Sopenharmony_ci{
1646987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1647987da915Sopenharmony_ci    char *path;
1648987da915Sopenharmony_ci    int err;
1649987da915Sopenharmony_ci
1650987da915Sopenharmony_ci    err = -ENOENT;
1651987da915Sopenharmony_ci    pthread_rwlock_wrlock(&f->tree_lock);
1652987da915Sopenharmony_ci    path = get_path_name(f, parent, name);
1653987da915Sopenharmony_ci    if (path != NULL) {
1654987da915Sopenharmony_ci        struct fuse_intr_data d;
1655987da915Sopenharmony_ci        if (f->conf.debug)
1656987da915Sopenharmony_ci            fprintf(stderr, "RMDIR %s\n", path);
1657987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1658987da915Sopenharmony_ci        err = fuse_fs_rmdir(f->fs, path);
1659987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1660987da915Sopenharmony_ci        if (!err)
1661987da915Sopenharmony_ci            remove_node(f, parent, name);
1662987da915Sopenharmony_ci        free(path);
1663987da915Sopenharmony_ci    }
1664987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1665987da915Sopenharmony_ci    reply_err(req, err);
1666987da915Sopenharmony_ci}
1667987da915Sopenharmony_ci
1668987da915Sopenharmony_cistatic void fuse_lib_symlink(fuse_req_t req, const char *linkname,
1669987da915Sopenharmony_ci                             fuse_ino_t parent, const char *name)
1670987da915Sopenharmony_ci{
1671987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1672987da915Sopenharmony_ci    struct fuse_entry_param e;
1673987da915Sopenharmony_ci    char *path;
1674987da915Sopenharmony_ci    int err;
1675987da915Sopenharmony_ci
1676987da915Sopenharmony_ci    err = -ENOENT;
1677987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1678987da915Sopenharmony_ci    path = get_path_name(f, parent, name);
1679987da915Sopenharmony_ci    if (path != NULL) {
1680987da915Sopenharmony_ci        struct fuse_intr_data d;
1681987da915Sopenharmony_ci        if (f->conf.debug)
1682987da915Sopenharmony_ci            fprintf(stderr, "SYMLINK %s\n", path);
1683987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1684987da915Sopenharmony_ci        err = fuse_fs_symlink(f->fs, linkname, path);
1685987da915Sopenharmony_ci        if (!err)
1686987da915Sopenharmony_ci            err = lookup_path(f, parent, name, path, &e, NULL);
1687987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1688987da915Sopenharmony_ci        free(path);
1689987da915Sopenharmony_ci    }
1690987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1691987da915Sopenharmony_ci    reply_entry(req, &e, err);
1692987da915Sopenharmony_ci}
1693987da915Sopenharmony_ci
1694987da915Sopenharmony_cistatic void fuse_lib_rename(fuse_req_t req, fuse_ino_t olddir,
1695987da915Sopenharmony_ci                            const char *oldname, fuse_ino_t newdir,
1696987da915Sopenharmony_ci                            const char *newname)
1697987da915Sopenharmony_ci{
1698987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1699987da915Sopenharmony_ci    char *oldpath;
1700987da915Sopenharmony_ci    char *newpath;
1701987da915Sopenharmony_ci    int err;
1702987da915Sopenharmony_ci
1703987da915Sopenharmony_ci    err = -ENOENT;
1704987da915Sopenharmony_ci    pthread_rwlock_wrlock(&f->tree_lock);
1705987da915Sopenharmony_ci    oldpath = get_path_name(f, olddir, oldname);
1706987da915Sopenharmony_ci    if (oldpath != NULL) {
1707987da915Sopenharmony_ci        newpath = get_path_name(f, newdir, newname);
1708987da915Sopenharmony_ci        if (newpath != NULL) {
1709987da915Sopenharmony_ci            struct fuse_intr_data d;
1710987da915Sopenharmony_ci            if (f->conf.debug)
1711987da915Sopenharmony_ci                fprintf(stderr, "RENAME %s -> %s\n", oldpath, newpath);
1712987da915Sopenharmony_ci            err = 0;
1713987da915Sopenharmony_ci            fuse_prepare_interrupt(f, req, &d);
1714987da915Sopenharmony_ci            if (!f->conf.hard_remove && is_open(f, newdir, newname))
1715987da915Sopenharmony_ci                err = hide_node(f, newpath, newdir, newname);
1716987da915Sopenharmony_ci            if (!err) {
1717987da915Sopenharmony_ci                err = fuse_fs_rename(f->fs, oldpath, newpath);
1718987da915Sopenharmony_ci                if (!err)
1719987da915Sopenharmony_ci                    err = rename_node(f, olddir, oldname, newdir, newname, 0);
1720987da915Sopenharmony_ci            }
1721987da915Sopenharmony_ci            fuse_finish_interrupt(f, req, &d);
1722987da915Sopenharmony_ci            free(newpath);
1723987da915Sopenharmony_ci        }
1724987da915Sopenharmony_ci        free(oldpath);
1725987da915Sopenharmony_ci    }
1726987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1727987da915Sopenharmony_ci    reply_err(req, err);
1728987da915Sopenharmony_ci}
1729987da915Sopenharmony_ci
1730987da915Sopenharmony_cistatic void fuse_lib_link(fuse_req_t req, fuse_ino_t ino, fuse_ino_t newparent,
1731987da915Sopenharmony_ci                          const char *newname)
1732987da915Sopenharmony_ci{
1733987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1734987da915Sopenharmony_ci    struct fuse_entry_param e;
1735987da915Sopenharmony_ci    char *oldpath;
1736987da915Sopenharmony_ci    char *newpath;
1737987da915Sopenharmony_ci    int err;
1738987da915Sopenharmony_ci
1739987da915Sopenharmony_ci    err = -ENOENT;
1740987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1741987da915Sopenharmony_ci    oldpath = get_path(f, ino);
1742987da915Sopenharmony_ci    if (oldpath != NULL) {
1743987da915Sopenharmony_ci        newpath =  get_path_name(f, newparent, newname);
1744987da915Sopenharmony_ci        if (newpath != NULL) {
1745987da915Sopenharmony_ci            struct fuse_intr_data d;
1746987da915Sopenharmony_ci            if (f->conf.debug)
1747987da915Sopenharmony_ci                fprintf(stderr, "LINK %s\n", newpath);
1748987da915Sopenharmony_ci            fuse_prepare_interrupt(f, req, &d);
1749987da915Sopenharmony_ci            err = fuse_fs_link(f->fs, oldpath, newpath);
1750987da915Sopenharmony_ci            if (!err)
1751987da915Sopenharmony_ci                err = lookup_path(f, newparent, newname, newpath, &e, NULL);
1752987da915Sopenharmony_ci            fuse_finish_interrupt(f, req, &d);
1753987da915Sopenharmony_ci            free(newpath);
1754987da915Sopenharmony_ci        }
1755987da915Sopenharmony_ci        free(oldpath);
1756987da915Sopenharmony_ci    }
1757987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1758987da915Sopenharmony_ci    reply_entry(req, &e, err);
1759987da915Sopenharmony_ci}
1760987da915Sopenharmony_ci
1761987da915Sopenharmony_cistatic void fuse_do_release(struct fuse *f, fuse_ino_t ino, const char *path,
1762987da915Sopenharmony_ci                            struct fuse_file_info *fi)
1763987da915Sopenharmony_ci{
1764987da915Sopenharmony_ci    struct node *node;
1765987da915Sopenharmony_ci    int unlink_hidden = 0;
1766987da915Sopenharmony_ci
1767987da915Sopenharmony_ci    fuse_fs_release(f->fs, path ? path : "-", fi);
1768987da915Sopenharmony_ci
1769987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
1770987da915Sopenharmony_ci    node = get_node(f, ino);
1771987da915Sopenharmony_ci    assert(node->open_count > 0);
1772987da915Sopenharmony_ci    --node->open_count;
1773987da915Sopenharmony_ci    if (node->is_hidden && !node->open_count) {
1774987da915Sopenharmony_ci        unlink_hidden = 1;
1775987da915Sopenharmony_ci        node->is_hidden = 0;
1776987da915Sopenharmony_ci    }
1777987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
1778987da915Sopenharmony_ci
1779987da915Sopenharmony_ci    if(unlink_hidden && path)
1780987da915Sopenharmony_ci        fuse_fs_unlink(f->fs, path);
1781987da915Sopenharmony_ci}
1782987da915Sopenharmony_ci
1783987da915Sopenharmony_cistatic void fuse_lib_create(fuse_req_t req, fuse_ino_t parent,
1784987da915Sopenharmony_ci                            const char *name, mode_t mode,
1785987da915Sopenharmony_ci                            struct fuse_file_info *fi)
1786987da915Sopenharmony_ci{
1787987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1788987da915Sopenharmony_ci    struct fuse_intr_data d;
1789987da915Sopenharmony_ci    struct fuse_entry_param e;
1790987da915Sopenharmony_ci    char *path;
1791987da915Sopenharmony_ci    int err;
1792987da915Sopenharmony_ci
1793987da915Sopenharmony_ci    err = -ENOENT;
1794987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1795987da915Sopenharmony_ci    path = get_path_name(f, parent, name);
1796987da915Sopenharmony_ci    if (path) {
1797987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1798987da915Sopenharmony_ci        err = fuse_fs_create(f->fs, path, mode, fi);
1799987da915Sopenharmony_ci        if (!err) {
1800987da915Sopenharmony_ci            err = lookup_path(f, parent, name, path, &e, fi);
1801987da915Sopenharmony_ci            if (err)
1802987da915Sopenharmony_ci                fuse_fs_release(f->fs, path, fi);
1803987da915Sopenharmony_ci            else if (!S_ISREG(e.attr.st_mode)) {
1804987da915Sopenharmony_ci                err = -EIO;
1805987da915Sopenharmony_ci                fuse_fs_release(f->fs, path, fi);
1806987da915Sopenharmony_ci                forget_node(f, e.ino, 1);
1807987da915Sopenharmony_ci            } else {
1808987da915Sopenharmony_ci                if (f->conf.direct_io)
1809987da915Sopenharmony_ci                    fi->direct_io = 1;
1810987da915Sopenharmony_ci                if (f->conf.kernel_cache)
1811987da915Sopenharmony_ci                    fi->keep_cache = 1;
1812987da915Sopenharmony_ci
1813987da915Sopenharmony_ci            }
1814987da915Sopenharmony_ci        }
1815987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1816987da915Sopenharmony_ci    }
1817987da915Sopenharmony_ci    if (!err) {
1818987da915Sopenharmony_ci        pthread_mutex_lock(&f->lock);
1819987da915Sopenharmony_ci        get_node(f, e.ino)->open_count++;
1820987da915Sopenharmony_ci        pthread_mutex_unlock(&f->lock);
1821987da915Sopenharmony_ci        if (fuse_reply_create(req, &e, fi) == -ENOENT) {
1822987da915Sopenharmony_ci            /* The open syscall was interrupted, so it must be cancelled */
1823987da915Sopenharmony_ci            fuse_prepare_interrupt(f, req, &d);
1824987da915Sopenharmony_ci            fuse_do_release(f, e.ino, path, fi);
1825987da915Sopenharmony_ci            fuse_finish_interrupt(f, req, &d);
1826987da915Sopenharmony_ci            forget_node(f, e.ino, 1);
1827987da915Sopenharmony_ci        } else if (f->conf.debug) {
1828987da915Sopenharmony_ci            fprintf(stderr, "  CREATE[%llu] flags: 0x%x %s\n",
1829987da915Sopenharmony_ci                    (unsigned long long) fi->fh, fi->flags, path);
1830987da915Sopenharmony_ci        }
1831987da915Sopenharmony_ci    } else
1832987da915Sopenharmony_ci        reply_err(req, err);
1833987da915Sopenharmony_ci
1834987da915Sopenharmony_ci    if (path)
1835987da915Sopenharmony_ci        free(path);
1836987da915Sopenharmony_ci
1837987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1838987da915Sopenharmony_ci}
1839987da915Sopenharmony_ci
1840987da915Sopenharmony_ci#ifdef __SOLARIS__
1841987da915Sopenharmony_ci
1842987da915Sopenharmony_cistatic double diff_timespec(const struct timespec *t1,
1843987da915Sopenharmony_ci                            const struct timespec *t2)
1844987da915Sopenharmony_ci{
1845987da915Sopenharmony_ci    return (t1->tv_sec - t2->tv_sec) +
1846987da915Sopenharmony_ci        ((double) t1->tv_nsec - (double) t2->tv_nsec) / 1000000000.0;
1847987da915Sopenharmony_ci}
1848987da915Sopenharmony_ci
1849987da915Sopenharmony_cistatic void open_auto_cache(struct fuse *f, fuse_ino_t ino, const char *path,
1850987da915Sopenharmony_ci                            struct fuse_file_info *fi)
1851987da915Sopenharmony_ci{
1852987da915Sopenharmony_ci    struct node *node;
1853987da915Sopenharmony_ci
1854987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
1855987da915Sopenharmony_ci    node = get_node(f, ino);
1856987da915Sopenharmony_ci    if (node->cache_valid) {
1857987da915Sopenharmony_ci        struct timespec now;
1858987da915Sopenharmony_ci
1859987da915Sopenharmony_ci        curr_time(&now);
1860987da915Sopenharmony_ci        if (diff_timespec(&now, &node->stat_updated) > f->conf.ac_attr_timeout) {
1861987da915Sopenharmony_ci            struct stat stbuf;
1862987da915Sopenharmony_ci            int err;
1863987da915Sopenharmony_ci            pthread_mutex_unlock(&f->lock);
1864987da915Sopenharmony_ci            err = fuse_fs_fgetattr(f->fs, path, &stbuf, fi);
1865987da915Sopenharmony_ci            pthread_mutex_lock(&f->lock);
1866987da915Sopenharmony_ci            if (!err)
1867987da915Sopenharmony_ci                update_stat(node, &stbuf);
1868987da915Sopenharmony_ci            else
1869987da915Sopenharmony_ci                node->cache_valid = 0;
1870987da915Sopenharmony_ci        }
1871987da915Sopenharmony_ci    }
1872987da915Sopenharmony_ci    if (node->cache_valid)
1873987da915Sopenharmony_ci        fi->keep_cache = 1;
1874987da915Sopenharmony_ci
1875987da915Sopenharmony_ci    node->cache_valid = 1;
1876987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
1877987da915Sopenharmony_ci}
1878987da915Sopenharmony_ci
1879987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1880987da915Sopenharmony_ci
1881987da915Sopenharmony_cistatic void fuse_lib_open(fuse_req_t req, fuse_ino_t ino,
1882987da915Sopenharmony_ci                          struct fuse_file_info *fi)
1883987da915Sopenharmony_ci{
1884987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1885987da915Sopenharmony_ci    struct fuse_intr_data d;
1886987da915Sopenharmony_ci    char *path = NULL;
1887987da915Sopenharmony_ci    int err = 0;
1888987da915Sopenharmony_ci
1889987da915Sopenharmony_ci    err = -ENOENT;
1890987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1891987da915Sopenharmony_ci    path = get_path(f, ino);
1892987da915Sopenharmony_ci    if (path) {
1893987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1894987da915Sopenharmony_ci        err = fuse_fs_open(f->fs, path, fi);
1895987da915Sopenharmony_ci        if (!err) {
1896987da915Sopenharmony_ci            if (f->conf.direct_io)
1897987da915Sopenharmony_ci                fi->direct_io = 1;
1898987da915Sopenharmony_ci            if (f->conf.kernel_cache)
1899987da915Sopenharmony_ci                fi->keep_cache = 1;
1900987da915Sopenharmony_ci#ifdef __SOLARIS__
1901987da915Sopenharmony_ci
1902987da915Sopenharmony_ci            if (f->conf.auto_cache)
1903987da915Sopenharmony_ci                open_auto_cache(f, ino, path, fi);
1904987da915Sopenharmony_ci#endif /* __SOLARIS__ */
1905987da915Sopenharmony_ci        }
1906987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1907987da915Sopenharmony_ci    }
1908987da915Sopenharmony_ci    if (!err) {
1909987da915Sopenharmony_ci        pthread_mutex_lock(&f->lock);
1910987da915Sopenharmony_ci        get_node(f, ino)->open_count++;
1911987da915Sopenharmony_ci        pthread_mutex_unlock(&f->lock);
1912987da915Sopenharmony_ci        if (fuse_reply_open(req, fi) == -ENOENT) {
1913987da915Sopenharmony_ci            /* The open syscall was interrupted, so it must be cancelled */
1914987da915Sopenharmony_ci            fuse_prepare_interrupt(f, req, &d);
1915987da915Sopenharmony_ci            fuse_do_release(f, ino, path, fi);
1916987da915Sopenharmony_ci            fuse_finish_interrupt(f, req, &d);
1917987da915Sopenharmony_ci        } else if (f->conf.debug) {
1918987da915Sopenharmony_ci            fprintf(stderr, "OPEN[%llu] flags: 0x%x %s\n",
1919987da915Sopenharmony_ci                    (unsigned long long) fi->fh, fi->flags, path);
1920987da915Sopenharmony_ci        }
1921987da915Sopenharmony_ci    } else
1922987da915Sopenharmony_ci        reply_err(req, err);
1923987da915Sopenharmony_ci
1924987da915Sopenharmony_ci    if (path)
1925987da915Sopenharmony_ci        free(path);
1926987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1927987da915Sopenharmony_ci}
1928987da915Sopenharmony_ci
1929987da915Sopenharmony_cistatic void fuse_lib_read(fuse_req_t req, fuse_ino_t ino, size_t size,
1930987da915Sopenharmony_ci                          off_t off, struct fuse_file_info *fi)
1931987da915Sopenharmony_ci{
1932987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1933987da915Sopenharmony_ci    char *path;
1934987da915Sopenharmony_ci    char *buf;
1935987da915Sopenharmony_ci    int res;
1936987da915Sopenharmony_ci
1937987da915Sopenharmony_ci    buf = (char *) malloc(size);
1938987da915Sopenharmony_ci    if (buf == NULL) {
1939987da915Sopenharmony_ci        reply_err(req, -ENOMEM);
1940987da915Sopenharmony_ci        return;
1941987da915Sopenharmony_ci    }
1942987da915Sopenharmony_ci
1943987da915Sopenharmony_ci    res = -ENOENT;
1944987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1945987da915Sopenharmony_ci    path = get_path(f, ino);
1946987da915Sopenharmony_ci    if (path != NULL) {
1947987da915Sopenharmony_ci        struct fuse_intr_data d;
1948987da915Sopenharmony_ci        if (f->conf.debug)
1949987da915Sopenharmony_ci            fprintf(stderr, "READ[%llu] %lu bytes from %llu\n",
1950987da915Sopenharmony_ci                    (unsigned long long) fi->fh, (unsigned long) size,
1951987da915Sopenharmony_ci                    (unsigned long long) off);
1952987da915Sopenharmony_ci
1953987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1954987da915Sopenharmony_ci        res = fuse_fs_read(f->fs, path, buf, size, off, fi);
1955987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1956987da915Sopenharmony_ci        free(path);
1957987da915Sopenharmony_ci    }
1958987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1959987da915Sopenharmony_ci
1960987da915Sopenharmony_ci    if (res >= 0) {
1961987da915Sopenharmony_ci        if (f->conf.debug)
1962987da915Sopenharmony_ci            fprintf(stderr, "   READ[%llu] %u bytes\n",
1963987da915Sopenharmony_ci                    (unsigned long long)fi->fh, res);
1964987da915Sopenharmony_ci        if ((size_t) res > size)
1965987da915Sopenharmony_ci            fprintf(stderr, "fuse: read too many bytes");
1966987da915Sopenharmony_ci        fuse_reply_buf(req, buf, res);
1967987da915Sopenharmony_ci    } else
1968987da915Sopenharmony_ci        reply_err(req, res);
1969987da915Sopenharmony_ci
1970987da915Sopenharmony_ci    free(buf);
1971987da915Sopenharmony_ci}
1972987da915Sopenharmony_ci
1973987da915Sopenharmony_cistatic void fuse_lib_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1974987da915Sopenharmony_ci                       size_t size, off_t off, struct fuse_file_info *fi)
1975987da915Sopenharmony_ci{
1976987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
1977987da915Sopenharmony_ci    char *path;
1978987da915Sopenharmony_ci    int res;
1979987da915Sopenharmony_ci
1980987da915Sopenharmony_ci    res = -ENOENT;
1981987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
1982987da915Sopenharmony_ci    path = get_path(f, ino);
1983987da915Sopenharmony_ci    if (path != NULL) {
1984987da915Sopenharmony_ci        struct fuse_intr_data d;
1985987da915Sopenharmony_ci        if (f->conf.debug)
1986987da915Sopenharmony_ci            fprintf(stderr, "WRITE%s[%llu] %lu bytes to %llu\n",
1987987da915Sopenharmony_ci                    fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
1988987da915Sopenharmony_ci                    (unsigned long) size, (unsigned long long) off);
1989987da915Sopenharmony_ci
1990987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
1991987da915Sopenharmony_ci        res = fuse_fs_write(f->fs, path, buf, size, off, fi);
1992987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
1993987da915Sopenharmony_ci        free(path);
1994987da915Sopenharmony_ci    }
1995987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
1996987da915Sopenharmony_ci
1997987da915Sopenharmony_ci    if (res >= 0) {
1998987da915Sopenharmony_ci        if (f->conf.debug)
1999987da915Sopenharmony_ci            fprintf(stderr, "   WRITE%s[%llu] %u bytes\n",
2000987da915Sopenharmony_ci                    fi->writepage ? "PAGE" : "", (unsigned long long) fi->fh,
2001987da915Sopenharmony_ci                    res);
2002987da915Sopenharmony_ci        if ((size_t) res > size)
2003987da915Sopenharmony_ci            fprintf(stderr, "fuse: wrote too many bytes");
2004987da915Sopenharmony_ci        fuse_reply_write(req, res);
2005987da915Sopenharmony_ci    } else
2006987da915Sopenharmony_ci        reply_err(req, res);
2007987da915Sopenharmony_ci}
2008987da915Sopenharmony_ci
2009987da915Sopenharmony_cistatic void fuse_lib_fsync(fuse_req_t req, fuse_ino_t ino, int datasync,
2010987da915Sopenharmony_ci                       struct fuse_file_info *fi)
2011987da915Sopenharmony_ci{
2012987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2013987da915Sopenharmony_ci    char *path;
2014987da915Sopenharmony_ci    int err;
2015987da915Sopenharmony_ci
2016987da915Sopenharmony_ci    err = -ENOENT;
2017987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2018987da915Sopenharmony_ci    path = get_path(f, ino);
2019987da915Sopenharmony_ci    if (path != NULL) {
2020987da915Sopenharmony_ci        struct fuse_intr_data d;
2021987da915Sopenharmony_ci        if (f->conf.debug)
2022987da915Sopenharmony_ci            fprintf(stderr, "FSYNC[%llu]\n", (unsigned long long) fi->fh);
2023987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2024987da915Sopenharmony_ci        err = fuse_fs_fsync(f->fs, path, datasync, fi);
2025987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2026987da915Sopenharmony_ci        free(path);
2027987da915Sopenharmony_ci    }
2028987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2029987da915Sopenharmony_ci    reply_err(req, err);
2030987da915Sopenharmony_ci}
2031987da915Sopenharmony_ci
2032987da915Sopenharmony_cistatic struct fuse_dh *get_dirhandle(const struct fuse_file_info *llfi,
2033987da915Sopenharmony_ci                                     struct fuse_file_info *fi)
2034987da915Sopenharmony_ci{
2035987da915Sopenharmony_ci    struct fuse_dh *dh = (struct fuse_dh *) (uintptr_t) llfi->fh;
2036987da915Sopenharmony_ci    memset(fi, 0, sizeof(struct fuse_file_info));
2037987da915Sopenharmony_ci    fi->fh = dh->fh;
2038987da915Sopenharmony_ci    fi->fh_old = dh->fh;
2039987da915Sopenharmony_ci    return dh;
2040987da915Sopenharmony_ci}
2041987da915Sopenharmony_ci
2042987da915Sopenharmony_cistatic void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
2043987da915Sopenharmony_ci                       struct fuse_file_info *llfi)
2044987da915Sopenharmony_ci{
2045987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2046987da915Sopenharmony_ci    struct fuse_intr_data d;
2047987da915Sopenharmony_ci    struct fuse_dh *dh;
2048987da915Sopenharmony_ci    struct fuse_file_info fi;
2049987da915Sopenharmony_ci    char *path;
2050987da915Sopenharmony_ci    int err;
2051987da915Sopenharmony_ci
2052987da915Sopenharmony_ci    dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
2053987da915Sopenharmony_ci    if (dh == NULL) {
2054987da915Sopenharmony_ci        reply_err(req, -ENOMEM);
2055987da915Sopenharmony_ci        return;
2056987da915Sopenharmony_ci    }
2057987da915Sopenharmony_ci    memset(dh, 0, sizeof(struct fuse_dh));
2058987da915Sopenharmony_ci    dh->fuse = f;
2059987da915Sopenharmony_ci    dh->contents = NULL;
2060987da915Sopenharmony_ci    dh->len = 0;
2061987da915Sopenharmony_ci    dh->filled = 0;
2062987da915Sopenharmony_ci    dh->nodeid = ino;
2063987da915Sopenharmony_ci    fuse_mutex_init(&dh->lock);
2064987da915Sopenharmony_ci
2065987da915Sopenharmony_ci    llfi->fh = (uintptr_t) dh;
2066987da915Sopenharmony_ci
2067987da915Sopenharmony_ci    memset(&fi, 0, sizeof(fi));
2068987da915Sopenharmony_ci    fi.flags = llfi->flags;
2069987da915Sopenharmony_ci
2070987da915Sopenharmony_ci    err = -ENOENT;
2071987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2072987da915Sopenharmony_ci    path = get_path(f, ino);
2073987da915Sopenharmony_ci    if (path != NULL) {
2074987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2075987da915Sopenharmony_ci        err = fuse_fs_opendir(f->fs, path, &fi);
2076987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2077987da915Sopenharmony_ci        dh->fh = fi.fh;
2078987da915Sopenharmony_ci    }
2079987da915Sopenharmony_ci    if (!err) {
2080987da915Sopenharmony_ci        if (fuse_reply_open(req, llfi) == -ENOENT) {
2081987da915Sopenharmony_ci            /* The opendir syscall was interrupted, so it must be cancelled */
2082987da915Sopenharmony_ci            fuse_prepare_interrupt(f, req, &d);
2083987da915Sopenharmony_ci            fuse_fs_releasedir(f->fs, path, &fi);
2084987da915Sopenharmony_ci            fuse_finish_interrupt(f, req, &d);
2085987da915Sopenharmony_ci            pthread_mutex_destroy(&dh->lock);
2086987da915Sopenharmony_ci            free(dh);
2087987da915Sopenharmony_ci        }
2088987da915Sopenharmony_ci    } else {
2089987da915Sopenharmony_ci        reply_err(req, err);
2090987da915Sopenharmony_ci        pthread_mutex_destroy(&dh->lock);
2091987da915Sopenharmony_ci        free(dh);
2092987da915Sopenharmony_ci    }
2093987da915Sopenharmony_ci    free(path);
2094987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2095987da915Sopenharmony_ci}
2096987da915Sopenharmony_ci
2097987da915Sopenharmony_cistatic int extend_contents(struct fuse_dh *dh, unsigned minsize)
2098987da915Sopenharmony_ci{
2099987da915Sopenharmony_ci    if (minsize > dh->size) {
2100987da915Sopenharmony_ci        char *newptr;
2101987da915Sopenharmony_ci        unsigned newsize = dh->size;
2102987da915Sopenharmony_ci        if (!newsize)
2103987da915Sopenharmony_ci            newsize = 1024;
2104987da915Sopenharmony_ci#ifndef __SOLARIS__
2105987da915Sopenharmony_ci        while (newsize < minsize) {
2106987da915Sopenharmony_ci	    if (newsize >= 0x80000000)
2107987da915Sopenharmony_ci	       	newsize = 0xffffffff;
2108987da915Sopenharmony_ci	    else
2109987da915Sopenharmony_ci	       	newsize *= 2;
2110987da915Sopenharmony_ci        }
2111987da915Sopenharmony_ci#else /* __SOLARIS__ */
2112987da915Sopenharmony_ci        while (newsize < minsize)
2113987da915Sopenharmony_ci            newsize *= 2;
2114987da915Sopenharmony_ci#endif /* __SOLARIS__ */
2115987da915Sopenharmony_ci
2116987da915Sopenharmony_ci        newptr = (char *) realloc(dh->contents, newsize);
2117987da915Sopenharmony_ci        if (!newptr) {
2118987da915Sopenharmony_ci            dh->error = -ENOMEM;
2119987da915Sopenharmony_ci            return -1;
2120987da915Sopenharmony_ci        }
2121987da915Sopenharmony_ci        dh->contents = newptr;
2122987da915Sopenharmony_ci        dh->size = newsize;
2123987da915Sopenharmony_ci    }
2124987da915Sopenharmony_ci    return 0;
2125987da915Sopenharmony_ci}
2126987da915Sopenharmony_ci
2127987da915Sopenharmony_cistatic int fill_dir(void *dh_, const char *name, const struct stat *statp,
2128987da915Sopenharmony_ci                    off_t off)
2129987da915Sopenharmony_ci{
2130987da915Sopenharmony_ci    struct fuse_dh *dh = (struct fuse_dh *) dh_;
2131987da915Sopenharmony_ci    struct stat stbuf;
2132987da915Sopenharmony_ci    size_t newlen;
2133987da915Sopenharmony_ci
2134987da915Sopenharmony_ci    if (statp)
2135987da915Sopenharmony_ci        stbuf = *statp;
2136987da915Sopenharmony_ci    else {
2137987da915Sopenharmony_ci        memset(&stbuf, 0, sizeof(stbuf));
2138987da915Sopenharmony_ci        stbuf.st_ino = FUSE_UNKNOWN_INO;
2139987da915Sopenharmony_ci    }
2140987da915Sopenharmony_ci
2141987da915Sopenharmony_ci    if (!dh->fuse->conf.use_ino) {
2142987da915Sopenharmony_ci        stbuf.st_ino = FUSE_UNKNOWN_INO;
2143987da915Sopenharmony_ci        if (dh->fuse->conf.readdir_ino) {
2144987da915Sopenharmony_ci            struct node *node;
2145987da915Sopenharmony_ci            pthread_mutex_lock(&dh->fuse->lock);
2146987da915Sopenharmony_ci            node = lookup_node(dh->fuse, dh->nodeid, name);
2147987da915Sopenharmony_ci            if (node)
2148987da915Sopenharmony_ci                stbuf.st_ino  = (ino_t) node->nodeid;
2149987da915Sopenharmony_ci            pthread_mutex_unlock(&dh->fuse->lock);
2150987da915Sopenharmony_ci        }
2151987da915Sopenharmony_ci    }
2152987da915Sopenharmony_ci
2153987da915Sopenharmony_ci    if (off) {
2154987da915Sopenharmony_ci        if (extend_contents(dh, dh->needlen) == -1)
2155987da915Sopenharmony_ci            return 1;
2156987da915Sopenharmony_ci
2157987da915Sopenharmony_ci        dh->filled = 0;
2158987da915Sopenharmony_ci        newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
2159987da915Sopenharmony_ci                                             dh->needlen - dh->len, name,
2160987da915Sopenharmony_ci                                             &stbuf, off);
2161987da915Sopenharmony_ci        if (newlen > dh->needlen)
2162987da915Sopenharmony_ci            return 1;
2163987da915Sopenharmony_ci    } else {
2164987da915Sopenharmony_ci        newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
2165987da915Sopenharmony_ci        if (extend_contents(dh, newlen) == -1)
2166987da915Sopenharmony_ci            return 1;
2167987da915Sopenharmony_ci
2168987da915Sopenharmony_ci        fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
2169987da915Sopenharmony_ci                          name, &stbuf, newlen);
2170987da915Sopenharmony_ci    }
2171987da915Sopenharmony_ci    dh->len = newlen;
2172987da915Sopenharmony_ci    return 0;
2173987da915Sopenharmony_ci}
2174987da915Sopenharmony_ci
2175987da915Sopenharmony_cistatic int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2176987da915Sopenharmony_ci                        size_t size, off_t off, struct fuse_dh *dh,
2177987da915Sopenharmony_ci                        struct fuse_file_info *fi)
2178987da915Sopenharmony_ci{
2179987da915Sopenharmony_ci    int err = -ENOENT;
2180987da915Sopenharmony_ci    char *path;
2181987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2182987da915Sopenharmony_ci    path = get_path(f, ino);
2183987da915Sopenharmony_ci    if (path != NULL) {
2184987da915Sopenharmony_ci        struct fuse_intr_data d;
2185987da915Sopenharmony_ci
2186987da915Sopenharmony_ci        dh->len = 0;
2187987da915Sopenharmony_ci        dh->error = 0;
2188987da915Sopenharmony_ci        dh->needlen = size;
2189987da915Sopenharmony_ci        dh->filled = 1;
2190987da915Sopenharmony_ci        dh->req = req;
2191987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2192987da915Sopenharmony_ci        err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
2193987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2194987da915Sopenharmony_ci        dh->req = NULL;
2195987da915Sopenharmony_ci        if (!err)
2196987da915Sopenharmony_ci            err = dh->error;
2197987da915Sopenharmony_ci        if (err)
2198987da915Sopenharmony_ci            dh->filled = 0;
2199987da915Sopenharmony_ci        free(path);
2200987da915Sopenharmony_ci    }
2201987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2202987da915Sopenharmony_ci    return err;
2203987da915Sopenharmony_ci}
2204987da915Sopenharmony_ci
2205987da915Sopenharmony_cistatic void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
2206987da915Sopenharmony_ci                             off_t off, struct fuse_file_info *llfi)
2207987da915Sopenharmony_ci{
2208987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2209987da915Sopenharmony_ci    struct fuse_file_info fi;
2210987da915Sopenharmony_ci    struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2211987da915Sopenharmony_ci
2212987da915Sopenharmony_ci    pthread_mutex_lock(&dh->lock);
2213987da915Sopenharmony_ci    /* According to SUS, directory contents need to be refreshed on
2214987da915Sopenharmony_ci       rewinddir() */
2215987da915Sopenharmony_ci    if (!off)
2216987da915Sopenharmony_ci        dh->filled = 0;
2217987da915Sopenharmony_ci
2218987da915Sopenharmony_ci    if (!dh->filled) {
2219987da915Sopenharmony_ci        int err = readdir_fill(f, req, ino, size, off, dh, &fi);
2220987da915Sopenharmony_ci        if (err) {
2221987da915Sopenharmony_ci            reply_err(req, err);
2222987da915Sopenharmony_ci            goto out;
2223987da915Sopenharmony_ci        }
2224987da915Sopenharmony_ci    }
2225987da915Sopenharmony_ci    if (dh->filled) {
2226987da915Sopenharmony_ci        if ((off >= 0) && (off < dh->len)) {
2227987da915Sopenharmony_ci            if (off + size > dh->len)
2228987da915Sopenharmony_ci                size = dh->len - off;
2229987da915Sopenharmony_ci        } else
2230987da915Sopenharmony_ci            size = 0;
2231987da915Sopenharmony_ci    } else {
2232987da915Sopenharmony_ci        size = dh->len;
2233987da915Sopenharmony_ci        off = 0;
2234987da915Sopenharmony_ci    }
2235987da915Sopenharmony_ci    fuse_reply_buf(req, dh->contents + off, size);
2236987da915Sopenharmony_ci out:
2237987da915Sopenharmony_ci    pthread_mutex_unlock(&dh->lock);
2238987da915Sopenharmony_ci}
2239987da915Sopenharmony_ci
2240987da915Sopenharmony_cistatic void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
2241987da915Sopenharmony_ci                            struct fuse_file_info *llfi)
2242987da915Sopenharmony_ci{
2243987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2244987da915Sopenharmony_ci    struct fuse_intr_data d;
2245987da915Sopenharmony_ci    struct fuse_file_info fi;
2246987da915Sopenharmony_ci    struct fuse_dh *dh = get_dirhandle(llfi, &fi);
2247987da915Sopenharmony_ci    char *path;
2248987da915Sopenharmony_ci
2249987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2250987da915Sopenharmony_ci    path = get_path(f, ino);
2251987da915Sopenharmony_ci    fuse_prepare_interrupt(f, req, &d);
2252987da915Sopenharmony_ci    fuse_fs_releasedir(f->fs, path ? path : "-", &fi);
2253987da915Sopenharmony_ci    fuse_finish_interrupt(f, req, &d);
2254987da915Sopenharmony_ci    if (path)
2255987da915Sopenharmony_ci        free(path);
2256987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2257987da915Sopenharmony_ci    pthread_mutex_lock(&dh->lock);
2258987da915Sopenharmony_ci    pthread_mutex_unlock(&dh->lock);
2259987da915Sopenharmony_ci    pthread_mutex_destroy(&dh->lock);
2260987da915Sopenharmony_ci    free(dh->contents);
2261987da915Sopenharmony_ci    free(dh);
2262987da915Sopenharmony_ci    reply_err(req, 0);
2263987da915Sopenharmony_ci}
2264987da915Sopenharmony_ci
2265987da915Sopenharmony_cistatic void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
2266987da915Sopenharmony_ci                          struct fuse_file_info *llfi)
2267987da915Sopenharmony_ci{
2268987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2269987da915Sopenharmony_ci    struct fuse_file_info fi;
2270987da915Sopenharmony_ci    char *path;
2271987da915Sopenharmony_ci    int err;
2272987da915Sopenharmony_ci
2273987da915Sopenharmony_ci    get_dirhandle(llfi, &fi);
2274987da915Sopenharmony_ci
2275987da915Sopenharmony_ci    err = -ENOENT;
2276987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2277987da915Sopenharmony_ci    path = get_path(f, ino);
2278987da915Sopenharmony_ci    if (path != NULL) {
2279987da915Sopenharmony_ci        struct fuse_intr_data d;
2280987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2281987da915Sopenharmony_ci        err = fuse_fs_fsyncdir(f->fs, path, datasync, &fi);
2282987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2283987da915Sopenharmony_ci        free(path);
2284987da915Sopenharmony_ci    }
2285987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2286987da915Sopenharmony_ci    reply_err(req, err);
2287987da915Sopenharmony_ci}
2288987da915Sopenharmony_ci
2289987da915Sopenharmony_cistatic void fuse_lib_statfs(fuse_req_t req, fuse_ino_t ino)
2290987da915Sopenharmony_ci{
2291987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2292987da915Sopenharmony_ci    struct statvfs buf;
2293987da915Sopenharmony_ci    char *path;
2294987da915Sopenharmony_ci    int err;
2295987da915Sopenharmony_ci
2296987da915Sopenharmony_ci    memset(&buf, 0, sizeof(buf));
2297987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2298987da915Sopenharmony_ci    if (!ino) {
2299987da915Sopenharmony_ci        err = -ENOMEM;
2300987da915Sopenharmony_ci        path = strdup("/");
2301987da915Sopenharmony_ci    } else {
2302987da915Sopenharmony_ci        err = -ENOENT;
2303987da915Sopenharmony_ci        path = get_path(f, ino);
2304987da915Sopenharmony_ci    }
2305987da915Sopenharmony_ci    if (path) {
2306987da915Sopenharmony_ci        struct fuse_intr_data d;
2307987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2308987da915Sopenharmony_ci        err = fuse_fs_statfs(f->fs, path, &buf);
2309987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2310987da915Sopenharmony_ci        free(path);
2311987da915Sopenharmony_ci    }
2312987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2313987da915Sopenharmony_ci
2314987da915Sopenharmony_ci    if (!err)
2315987da915Sopenharmony_ci        fuse_reply_statfs(req, &buf);
2316987da915Sopenharmony_ci    else
2317987da915Sopenharmony_ci        reply_err(req, err);
2318987da915Sopenharmony_ci}
2319987da915Sopenharmony_ci
2320987da915Sopenharmony_cistatic void fuse_lib_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2321987da915Sopenharmony_ci                              const char *value, size_t size, int flags)
2322987da915Sopenharmony_ci{
2323987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2324987da915Sopenharmony_ci    char *path;
2325987da915Sopenharmony_ci    int err;
2326987da915Sopenharmony_ci
2327987da915Sopenharmony_ci    err = -ENOENT;
2328987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2329987da915Sopenharmony_ci    path = get_path(f, ino);
2330987da915Sopenharmony_ci    if (path != NULL) {
2331987da915Sopenharmony_ci        struct fuse_intr_data d;
2332987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2333987da915Sopenharmony_ci        err = fuse_fs_setxattr(f->fs, path, name, value, size, flags);
2334987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2335987da915Sopenharmony_ci        free(path);
2336987da915Sopenharmony_ci    }
2337987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2338987da915Sopenharmony_ci    reply_err(req, err);
2339987da915Sopenharmony_ci}
2340987da915Sopenharmony_ci
2341987da915Sopenharmony_cistatic int common_getxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2342987da915Sopenharmony_ci                           const char *name, char *value, size_t size)
2343987da915Sopenharmony_ci{
2344987da915Sopenharmony_ci    int err;
2345987da915Sopenharmony_ci    char *path;
2346987da915Sopenharmony_ci
2347987da915Sopenharmony_ci    err = -ENOENT;
2348987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2349987da915Sopenharmony_ci    path = get_path(f, ino);
2350987da915Sopenharmony_ci    if (path != NULL) {
2351987da915Sopenharmony_ci        struct fuse_intr_data d;
2352987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2353987da915Sopenharmony_ci        err = fuse_fs_getxattr(f->fs, path, name, value, size);
2354987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2355987da915Sopenharmony_ci        free(path);
2356987da915Sopenharmony_ci    }
2357987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2358987da915Sopenharmony_ci    return err;
2359987da915Sopenharmony_ci}
2360987da915Sopenharmony_ci
2361987da915Sopenharmony_cistatic void fuse_lib_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2362987da915Sopenharmony_ci                              size_t size)
2363987da915Sopenharmony_ci{
2364987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2365987da915Sopenharmony_ci    int res;
2366987da915Sopenharmony_ci
2367987da915Sopenharmony_ci    if (size) {
2368987da915Sopenharmony_ci        char *value = (char *) malloc(size);
2369987da915Sopenharmony_ci        if (value == NULL) {
2370987da915Sopenharmony_ci            reply_err(req, -ENOMEM);
2371987da915Sopenharmony_ci            return;
2372987da915Sopenharmony_ci        }
2373987da915Sopenharmony_ci        res = common_getxattr(f, req, ino, name, value, size);
2374987da915Sopenharmony_ci        if (res > 0)
2375987da915Sopenharmony_ci            fuse_reply_buf(req, value, res);
2376987da915Sopenharmony_ci        else
2377987da915Sopenharmony_ci            reply_err(req, res);
2378987da915Sopenharmony_ci        free(value);
2379987da915Sopenharmony_ci    } else {
2380987da915Sopenharmony_ci        res = common_getxattr(f, req, ino, name, NULL, 0);
2381987da915Sopenharmony_ci        if (res >= 0)
2382987da915Sopenharmony_ci            fuse_reply_xattr(req, res);
2383987da915Sopenharmony_ci        else
2384987da915Sopenharmony_ci            reply_err(req, res);
2385987da915Sopenharmony_ci    }
2386987da915Sopenharmony_ci}
2387987da915Sopenharmony_ci
2388987da915Sopenharmony_cistatic int common_listxattr(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2389987da915Sopenharmony_ci                            char *list, size_t size)
2390987da915Sopenharmony_ci{
2391987da915Sopenharmony_ci    char *path;
2392987da915Sopenharmony_ci    int err;
2393987da915Sopenharmony_ci
2394987da915Sopenharmony_ci    err = -ENOENT;
2395987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2396987da915Sopenharmony_ci    path = get_path(f, ino);
2397987da915Sopenharmony_ci    if (path != NULL) {
2398987da915Sopenharmony_ci        struct fuse_intr_data d;
2399987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2400987da915Sopenharmony_ci        err = fuse_fs_listxattr(f->fs, path, list, size);
2401987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2402987da915Sopenharmony_ci        free(path);
2403987da915Sopenharmony_ci    }
2404987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2405987da915Sopenharmony_ci    return err;
2406987da915Sopenharmony_ci}
2407987da915Sopenharmony_ci
2408987da915Sopenharmony_cistatic void fuse_lib_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
2409987da915Sopenharmony_ci{
2410987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2411987da915Sopenharmony_ci    int res;
2412987da915Sopenharmony_ci
2413987da915Sopenharmony_ci    if (size) {
2414987da915Sopenharmony_ci        char *list = (char *) malloc(size);
2415987da915Sopenharmony_ci        if (list == NULL) {
2416987da915Sopenharmony_ci            reply_err(req, -ENOMEM);
2417987da915Sopenharmony_ci            return;
2418987da915Sopenharmony_ci        }
2419987da915Sopenharmony_ci        res = common_listxattr(f, req, ino, list, size);
2420987da915Sopenharmony_ci        if (res > 0)
2421987da915Sopenharmony_ci            fuse_reply_buf(req, list, res);
2422987da915Sopenharmony_ci        else
2423987da915Sopenharmony_ci            reply_err(req, res);
2424987da915Sopenharmony_ci        free(list);
2425987da915Sopenharmony_ci    } else {
2426987da915Sopenharmony_ci        res = common_listxattr(f, req, ino, NULL, 0);
2427987da915Sopenharmony_ci        if (res >= 0)
2428987da915Sopenharmony_ci            fuse_reply_xattr(req, res);
2429987da915Sopenharmony_ci        else
2430987da915Sopenharmony_ci            reply_err(req, res);
2431987da915Sopenharmony_ci    }
2432987da915Sopenharmony_ci}
2433987da915Sopenharmony_ci
2434987da915Sopenharmony_cistatic void fuse_lib_removexattr(fuse_req_t req, fuse_ino_t ino,
2435987da915Sopenharmony_ci                                 const char *name)
2436987da915Sopenharmony_ci{
2437987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2438987da915Sopenharmony_ci    char *path;
2439987da915Sopenharmony_ci    int err;
2440987da915Sopenharmony_ci
2441987da915Sopenharmony_ci    err = -ENOENT;
2442987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2443987da915Sopenharmony_ci    path = get_path(f, ino);
2444987da915Sopenharmony_ci    if (path != NULL) {
2445987da915Sopenharmony_ci        struct fuse_intr_data d;
2446987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2447987da915Sopenharmony_ci        err = fuse_fs_removexattr(f->fs, path, name);
2448987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2449987da915Sopenharmony_ci        free(path);
2450987da915Sopenharmony_ci    }
2451987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2452987da915Sopenharmony_ci    reply_err(req, err);
2453987da915Sopenharmony_ci}
2454987da915Sopenharmony_ci
2455987da915Sopenharmony_cistatic struct lock *locks_conflict(struct node *node, const struct lock *lock)
2456987da915Sopenharmony_ci{
2457987da915Sopenharmony_ci    struct lock *l;
2458987da915Sopenharmony_ci
2459987da915Sopenharmony_ci    for (l = node->locks; l; l = l->next)
2460987da915Sopenharmony_ci        if (l->owner != lock->owner &&
2461987da915Sopenharmony_ci            lock->start <= l->end && l->start <= lock->end &&
2462987da915Sopenharmony_ci            (l->type == F_WRLCK || lock->type == F_WRLCK))
2463987da915Sopenharmony_ci            break;
2464987da915Sopenharmony_ci
2465987da915Sopenharmony_ci    return l;
2466987da915Sopenharmony_ci}
2467987da915Sopenharmony_ci
2468987da915Sopenharmony_cistatic void delete_lock(struct lock **lockp)
2469987da915Sopenharmony_ci{
2470987da915Sopenharmony_ci    struct lock *l = *lockp;
2471987da915Sopenharmony_ci    *lockp = l->next;
2472987da915Sopenharmony_ci    free(l);
2473987da915Sopenharmony_ci}
2474987da915Sopenharmony_ci
2475987da915Sopenharmony_cistatic void insert_lock(struct lock **pos, struct lock *lock)
2476987da915Sopenharmony_ci{
2477987da915Sopenharmony_ci    lock->next = *pos;
2478987da915Sopenharmony_ci    *pos = lock;
2479987da915Sopenharmony_ci}
2480987da915Sopenharmony_ci
2481987da915Sopenharmony_cistatic int locks_insert(struct node *node, struct lock *lock)
2482987da915Sopenharmony_ci{
2483987da915Sopenharmony_ci    struct lock **lp;
2484987da915Sopenharmony_ci    struct lock *newl1 = NULL;
2485987da915Sopenharmony_ci    struct lock *newl2 = NULL;
2486987da915Sopenharmony_ci
2487987da915Sopenharmony_ci    if (lock->type != F_UNLCK || lock->start != 0 || lock->end != OFFSET_MAX) {
2488987da915Sopenharmony_ci        newl1 = malloc(sizeof(struct lock));
2489987da915Sopenharmony_ci        newl2 = malloc(sizeof(struct lock));
2490987da915Sopenharmony_ci
2491987da915Sopenharmony_ci        if (!newl1 || !newl2) {
2492987da915Sopenharmony_ci            free(newl1);
2493987da915Sopenharmony_ci            free(newl2);
2494987da915Sopenharmony_ci            return -ENOLCK;
2495987da915Sopenharmony_ci        }
2496987da915Sopenharmony_ci    }
2497987da915Sopenharmony_ci
2498987da915Sopenharmony_ci    for (lp = &node->locks; *lp;) {
2499987da915Sopenharmony_ci        struct lock *l = *lp;
2500987da915Sopenharmony_ci        if (l->owner != lock->owner)
2501987da915Sopenharmony_ci            goto skip;
2502987da915Sopenharmony_ci
2503987da915Sopenharmony_ci        if (lock->type == l->type) {
2504987da915Sopenharmony_ci            if (l->end < lock->start - 1)
2505987da915Sopenharmony_ci                goto skip;
2506987da915Sopenharmony_ci            if (lock->end < l->start - 1)
2507987da915Sopenharmony_ci                break;
2508987da915Sopenharmony_ci            if (l->start <= lock->start && lock->end <= l->end)
2509987da915Sopenharmony_ci                goto out;
2510987da915Sopenharmony_ci            if (l->start < lock->start)
2511987da915Sopenharmony_ci                lock->start = l->start;
2512987da915Sopenharmony_ci            if (lock->end < l->end)
2513987da915Sopenharmony_ci                lock->end = l->end;
2514987da915Sopenharmony_ci            goto delete;
2515987da915Sopenharmony_ci        } else {
2516987da915Sopenharmony_ci            if (l->end < lock->start)
2517987da915Sopenharmony_ci                goto skip;
2518987da915Sopenharmony_ci            if (lock->end < l->start)
2519987da915Sopenharmony_ci                break;
2520987da915Sopenharmony_ci            if (lock->start <= l->start && l->end <= lock->end)
2521987da915Sopenharmony_ci                goto delete;
2522987da915Sopenharmony_ci            if (l->end <= lock->end) {
2523987da915Sopenharmony_ci                l->end = lock->start - 1;
2524987da915Sopenharmony_ci                goto skip;
2525987da915Sopenharmony_ci            }
2526987da915Sopenharmony_ci            if (lock->start <= l->start) {
2527987da915Sopenharmony_ci                l->start = lock->end + 1;
2528987da915Sopenharmony_ci                break;
2529987da915Sopenharmony_ci            }
2530987da915Sopenharmony_ci            *newl2 = *l;
2531987da915Sopenharmony_ci            newl2->start = lock->end + 1;
2532987da915Sopenharmony_ci            l->end = lock->start - 1;
2533987da915Sopenharmony_ci            insert_lock(&l->next, newl2);
2534987da915Sopenharmony_ci            newl2 = NULL;
2535987da915Sopenharmony_ci        }
2536987da915Sopenharmony_ci    skip:
2537987da915Sopenharmony_ci        lp = &l->next;
2538987da915Sopenharmony_ci        continue;
2539987da915Sopenharmony_ci
2540987da915Sopenharmony_ci    delete:
2541987da915Sopenharmony_ci        delete_lock(lp);
2542987da915Sopenharmony_ci    }
2543987da915Sopenharmony_ci    if (lock->type != F_UNLCK) {
2544987da915Sopenharmony_ci        *newl1 = *lock;
2545987da915Sopenharmony_ci        insert_lock(lp, newl1);
2546987da915Sopenharmony_ci        newl1 = NULL;
2547987da915Sopenharmony_ci    }
2548987da915Sopenharmony_ciout:
2549987da915Sopenharmony_ci    free(newl1);
2550987da915Sopenharmony_ci    free(newl2);
2551987da915Sopenharmony_ci    return 0;
2552987da915Sopenharmony_ci}
2553987da915Sopenharmony_ci
2554987da915Sopenharmony_cistatic void flock_to_lock(struct flock *flock, struct lock *lock)
2555987da915Sopenharmony_ci{
2556987da915Sopenharmony_ci    memset(lock, 0, sizeof(struct lock));
2557987da915Sopenharmony_ci    lock->type = flock->l_type;
2558987da915Sopenharmony_ci    lock->start = flock->l_start;
2559987da915Sopenharmony_ci    lock->end = flock->l_len ? flock->l_start + flock->l_len - 1 : OFFSET_MAX;
2560987da915Sopenharmony_ci    lock->pid = flock->l_pid;
2561987da915Sopenharmony_ci}
2562987da915Sopenharmony_ci
2563987da915Sopenharmony_cistatic void lock_to_flock(struct lock *lock, struct flock *flock)
2564987da915Sopenharmony_ci{
2565987da915Sopenharmony_ci    flock->l_type = lock->type;
2566987da915Sopenharmony_ci    flock->l_start = lock->start;
2567987da915Sopenharmony_ci    flock->l_len = (lock->end == OFFSET_MAX) ? 0 : lock->end - lock->start + 1;
2568987da915Sopenharmony_ci    flock->l_pid = lock->pid;
2569987da915Sopenharmony_ci}
2570987da915Sopenharmony_ci
2571987da915Sopenharmony_cistatic int fuse_flush_common(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
2572987da915Sopenharmony_ci                             const char *path, struct fuse_file_info *fi)
2573987da915Sopenharmony_ci{
2574987da915Sopenharmony_ci    struct fuse_intr_data d;
2575987da915Sopenharmony_ci    struct flock lock;
2576987da915Sopenharmony_ci    struct lock l;
2577987da915Sopenharmony_ci    int err;
2578987da915Sopenharmony_ci    int errlock;
2579987da915Sopenharmony_ci
2580987da915Sopenharmony_ci    fuse_prepare_interrupt(f, req, &d);
2581987da915Sopenharmony_ci    memset(&lock, 0, sizeof(lock));
2582987da915Sopenharmony_ci    lock.l_type = F_UNLCK;
2583987da915Sopenharmony_ci    lock.l_whence = SEEK_SET;
2584987da915Sopenharmony_ci    err = fuse_fs_flush(f->fs, path, fi);
2585987da915Sopenharmony_ci    errlock = fuse_fs_lock(f->fs, path, fi, F_SETLK, &lock);
2586987da915Sopenharmony_ci    fuse_finish_interrupt(f, req, &d);
2587987da915Sopenharmony_ci
2588987da915Sopenharmony_ci    if (errlock != -ENOSYS) {
2589987da915Sopenharmony_ci        flock_to_lock(&lock, &l);
2590987da915Sopenharmony_ci        l.owner = fi->lock_owner;
2591987da915Sopenharmony_ci        pthread_mutex_lock(&f->lock);
2592987da915Sopenharmony_ci        locks_insert(get_node(f, ino), &l);
2593987da915Sopenharmony_ci        pthread_mutex_unlock(&f->lock);
2594987da915Sopenharmony_ci
2595987da915Sopenharmony_ci        /* if op.lock() is defined FLUSH is needed regardless of op.flush() */
2596987da915Sopenharmony_ci        if (err == -ENOSYS)
2597987da915Sopenharmony_ci            err = 0;
2598987da915Sopenharmony_ci    }
2599987da915Sopenharmony_ci    return err;
2600987da915Sopenharmony_ci}
2601987da915Sopenharmony_ci
2602987da915Sopenharmony_cistatic void fuse_lib_release(fuse_req_t req, fuse_ino_t ino,
2603987da915Sopenharmony_ci                             struct fuse_file_info *fi)
2604987da915Sopenharmony_ci{
2605987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2606987da915Sopenharmony_ci    struct fuse_intr_data d;
2607987da915Sopenharmony_ci    char *path;
2608987da915Sopenharmony_ci    int err = 0;
2609987da915Sopenharmony_ci
2610987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2611987da915Sopenharmony_ci    path = get_path(f, ino);
2612987da915Sopenharmony_ci    if (f->conf.debug)
2613987da915Sopenharmony_ci        fprintf(stderr, "RELEASE%s[%llu] flags: 0x%x\n",
2614987da915Sopenharmony_ci                fi->flush ? "+FLUSH" : "",
2615987da915Sopenharmony_ci                (unsigned long long) fi->fh, fi->flags);
2616987da915Sopenharmony_ci
2617987da915Sopenharmony_ci    if (fi->flush) {
2618987da915Sopenharmony_ci        err = fuse_flush_common(f, req, ino, path, fi);
2619987da915Sopenharmony_ci        if (err == -ENOSYS)
2620987da915Sopenharmony_ci            err = 0;
2621987da915Sopenharmony_ci    }
2622987da915Sopenharmony_ci
2623987da915Sopenharmony_ci    fuse_prepare_interrupt(f, req, &d);
2624987da915Sopenharmony_ci    fuse_do_release(f, ino, path, fi);
2625987da915Sopenharmony_ci    fuse_finish_interrupt(f, req, &d);
2626987da915Sopenharmony_ci    free(path);
2627987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2628987da915Sopenharmony_ci
2629987da915Sopenharmony_ci    reply_err(req, err);
2630987da915Sopenharmony_ci}
2631987da915Sopenharmony_ci
2632987da915Sopenharmony_cistatic void fuse_lib_flush(fuse_req_t req, fuse_ino_t ino,
2633987da915Sopenharmony_ci                       struct fuse_file_info *fi)
2634987da915Sopenharmony_ci{
2635987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2636987da915Sopenharmony_ci    char *path;
2637987da915Sopenharmony_ci    int err;
2638987da915Sopenharmony_ci
2639987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2640987da915Sopenharmony_ci    path = get_path(f, ino);
2641987da915Sopenharmony_ci    if (path && f->conf.debug)
2642987da915Sopenharmony_ci        fprintf(stderr, "FLUSH[%llu]\n", (unsigned long long) fi->fh);
2643987da915Sopenharmony_ci    err = fuse_flush_common(f, req, ino, path, fi);
2644987da915Sopenharmony_ci    free(path);
2645987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2646987da915Sopenharmony_ci    reply_err(req, err);
2647987da915Sopenharmony_ci}
2648987da915Sopenharmony_ci
2649987da915Sopenharmony_cistatic int fuse_lock_common(fuse_req_t req, fuse_ino_t ino,
2650987da915Sopenharmony_ci                            struct fuse_file_info *fi, struct flock *lock,
2651987da915Sopenharmony_ci                            int cmd)
2652987da915Sopenharmony_ci{
2653987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2654987da915Sopenharmony_ci    char *path;
2655987da915Sopenharmony_ci    int err;
2656987da915Sopenharmony_ci
2657987da915Sopenharmony_ci    err = -ENOENT;
2658987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2659987da915Sopenharmony_ci    path = get_path(f, ino);
2660987da915Sopenharmony_ci    if (path != NULL) {
2661987da915Sopenharmony_ci        struct fuse_intr_data d;
2662987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2663987da915Sopenharmony_ci        err = fuse_fs_lock(f->fs, path, fi, cmd, lock);
2664987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2665987da915Sopenharmony_ci        free(path);
2666987da915Sopenharmony_ci    }
2667987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2668987da915Sopenharmony_ci    return err;
2669987da915Sopenharmony_ci}
2670987da915Sopenharmony_ci
2671987da915Sopenharmony_cistatic void fuse_lib_getlk(fuse_req_t req, fuse_ino_t ino,
2672987da915Sopenharmony_ci                           struct fuse_file_info *fi, struct flock *lock)
2673987da915Sopenharmony_ci{
2674987da915Sopenharmony_ci    int err;
2675987da915Sopenharmony_ci    struct lock l;
2676987da915Sopenharmony_ci    struct lock *conflict;
2677987da915Sopenharmony_ci    struct fuse *f = req_fuse(req);
2678987da915Sopenharmony_ci
2679987da915Sopenharmony_ci    flock_to_lock(lock, &l);
2680987da915Sopenharmony_ci    l.owner = fi->lock_owner;
2681987da915Sopenharmony_ci    pthread_mutex_lock(&f->lock);
2682987da915Sopenharmony_ci    conflict = locks_conflict(get_node(f, ino), &l);
2683987da915Sopenharmony_ci    if (conflict)
2684987da915Sopenharmony_ci        lock_to_flock(conflict, lock);
2685987da915Sopenharmony_ci    pthread_mutex_unlock(&f->lock);
2686987da915Sopenharmony_ci    if (!conflict)
2687987da915Sopenharmony_ci        err = fuse_lock_common(req, ino, fi, lock, F_GETLK);
2688987da915Sopenharmony_ci    else
2689987da915Sopenharmony_ci        err = 0;
2690987da915Sopenharmony_ci
2691987da915Sopenharmony_ci    if (!err)
2692987da915Sopenharmony_ci        fuse_reply_lock(req, lock);
2693987da915Sopenharmony_ci    else
2694987da915Sopenharmony_ci        reply_err(req, err);
2695987da915Sopenharmony_ci}
2696987da915Sopenharmony_ci
2697987da915Sopenharmony_cistatic void fuse_lib_setlk(fuse_req_t req, fuse_ino_t ino,
2698987da915Sopenharmony_ci                           struct fuse_file_info *fi, struct flock *lock,
2699987da915Sopenharmony_ci                           int should_sleep)
2700987da915Sopenharmony_ci{
2701987da915Sopenharmony_ci    int err = fuse_lock_common(req, ino, fi, lock, should_sleep ? F_SETLKW : F_SETLK);
2702987da915Sopenharmony_ci    if (!err) {
2703987da915Sopenharmony_ci        struct fuse *f = req_fuse(req);
2704987da915Sopenharmony_ci        struct lock l;
2705987da915Sopenharmony_ci        flock_to_lock(lock, &l);
2706987da915Sopenharmony_ci        l.owner = fi->lock_owner;
2707987da915Sopenharmony_ci        pthread_mutex_lock(&f->lock);
2708987da915Sopenharmony_ci        locks_insert(get_node(f, ino), &l);
2709987da915Sopenharmony_ci        pthread_mutex_unlock(&f->lock);
2710987da915Sopenharmony_ci    }
2711987da915Sopenharmony_ci    reply_err(req, err);
2712987da915Sopenharmony_ci}
2713987da915Sopenharmony_ci
2714987da915Sopenharmony_cistatic void fuse_lib_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2715987da915Sopenharmony_ci                          uint64_t idx)
2716987da915Sopenharmony_ci{
2717987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2718987da915Sopenharmony_ci    struct fuse_intr_data d;
2719987da915Sopenharmony_ci    char *path;
2720987da915Sopenharmony_ci    int err;
2721987da915Sopenharmony_ci
2722987da915Sopenharmony_ci    err = -ENOENT;
2723987da915Sopenharmony_ci    pthread_rwlock_rdlock(&f->tree_lock);
2724987da915Sopenharmony_ci    path = get_path(f, ino);
2725987da915Sopenharmony_ci    if (path != NULL) {
2726987da915Sopenharmony_ci        fuse_prepare_interrupt(f, req, &d);
2727987da915Sopenharmony_ci        err = fuse_fs_bmap(f->fs, path, blocksize, &idx);
2728987da915Sopenharmony_ci        fuse_finish_interrupt(f, req, &d);
2729987da915Sopenharmony_ci        free(path);
2730987da915Sopenharmony_ci    }
2731987da915Sopenharmony_ci    pthread_rwlock_unlock(&f->tree_lock);
2732987da915Sopenharmony_ci    if (!err)
2733987da915Sopenharmony_ci        fuse_reply_bmap(req, idx);
2734987da915Sopenharmony_ci    else
2735987da915Sopenharmony_ci        reply_err(req, err);
2736987da915Sopenharmony_ci}
2737987da915Sopenharmony_ci
2738987da915Sopenharmony_cistatic void fuse_lib_ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg,
2739987da915Sopenharmony_ci			   struct fuse_file_info *llfi, unsigned int flags,
2740987da915Sopenharmony_ci			   const void *in_buf, size_t in_bufsz,
2741987da915Sopenharmony_ci			   size_t out_bufsz)
2742987da915Sopenharmony_ci{
2743987da915Sopenharmony_ci    struct fuse *f = req_fuse_prepare(req);
2744987da915Sopenharmony_ci    struct fuse_intr_data d;
2745987da915Sopenharmony_ci    struct fuse_file_info fi;
2746987da915Sopenharmony_ci    char *path, *out_buf = NULL;
2747987da915Sopenharmony_ci    int err;
2748987da915Sopenharmony_ci
2749987da915Sopenharmony_ci    err = -EPERM;
2750987da915Sopenharmony_ci    if (flags & FUSE_IOCTL_UNRESTRICTED)
2751987da915Sopenharmony_ci	goto err;
2752987da915Sopenharmony_ci
2753987da915Sopenharmony_ci    if (flags & FUSE_IOCTL_DIR)
2754987da915Sopenharmony_ci	get_dirhandle(llfi, &fi);
2755987da915Sopenharmony_ci    else
2756987da915Sopenharmony_ci	fi = *llfi;
2757987da915Sopenharmony_ci
2758987da915Sopenharmony_ci    if (out_bufsz) {
2759987da915Sopenharmony_ci	err = -ENOMEM;
2760987da915Sopenharmony_ci	out_buf = malloc(out_bufsz);
2761987da915Sopenharmony_ci	if (!out_buf)
2762987da915Sopenharmony_ci	    goto err;
2763987da915Sopenharmony_ci    }
2764987da915Sopenharmony_ci
2765987da915Sopenharmony_ci    assert(!in_bufsz || !out_bufsz || in_bufsz == out_bufsz);
2766987da915Sopenharmony_ci    if (out_buf)
2767987da915Sopenharmony_ci	memcpy(out_buf, in_buf, in_bufsz);
2768987da915Sopenharmony_ci
2769987da915Sopenharmony_ci    path = get_path(f, ino); /* Should be get_path_nullok() */
2770987da915Sopenharmony_ci    if (!path) {
2771987da915Sopenharmony_ci	err = ENOENT;
2772987da915Sopenharmony_ci	goto err;
2773987da915Sopenharmony_ci    }
2774987da915Sopenharmony_ci
2775987da915Sopenharmony_ci    fuse_prepare_interrupt(f, req, &d);
2776987da915Sopenharmony_ci
2777987da915Sopenharmony_ci	/* Note : const qualifier dropped */
2778987da915Sopenharmony_ci    err = fuse_fs_ioctl(f->fs, path, cmd, arg, &fi, flags,
2779987da915Sopenharmony_ci			out_buf ? (void*)out_buf : (void*)(uintptr_t)in_buf);
2780987da915Sopenharmony_ci
2781987da915Sopenharmony_ci    fuse_finish_interrupt(f, req, &d);
2782987da915Sopenharmony_ci    free(path);
2783987da915Sopenharmony_ci
2784987da915Sopenharmony_ci    if (err >= 0) { /* not an error */
2785987da915Sopenharmony_ci        fuse_reply_ioctl(req, err, out_buf, out_bufsz);
2786987da915Sopenharmony_ci	goto out;
2787987da915Sopenharmony_ci    }
2788987da915Sopenharmony_cierr:
2789987da915Sopenharmony_ci    reply_err(req, err);
2790987da915Sopenharmony_ciout:
2791987da915Sopenharmony_ci    free(out_buf);
2792987da915Sopenharmony_ci}
2793987da915Sopenharmony_ci
2794987da915Sopenharmony_cistatic struct fuse_lowlevel_ops fuse_path_ops = {
2795987da915Sopenharmony_ci    .init = fuse_lib_init,
2796987da915Sopenharmony_ci    .destroy = fuse_lib_destroy,
2797987da915Sopenharmony_ci    .lookup = fuse_lib_lookup,
2798987da915Sopenharmony_ci    .forget = fuse_lib_forget,
2799987da915Sopenharmony_ci    .getattr = fuse_lib_getattr,
2800987da915Sopenharmony_ci    .setattr = fuse_lib_setattr,
2801987da915Sopenharmony_ci    .access = fuse_lib_access,
2802987da915Sopenharmony_ci    .readlink = fuse_lib_readlink,
2803987da915Sopenharmony_ci    .mknod = fuse_lib_mknod,
2804987da915Sopenharmony_ci    .mkdir = fuse_lib_mkdir,
2805987da915Sopenharmony_ci    .unlink = fuse_lib_unlink,
2806987da915Sopenharmony_ci    .rmdir = fuse_lib_rmdir,
2807987da915Sopenharmony_ci    .symlink = fuse_lib_symlink,
2808987da915Sopenharmony_ci    .rename = fuse_lib_rename,
2809987da915Sopenharmony_ci    .link = fuse_lib_link,
2810987da915Sopenharmony_ci    .create = fuse_lib_create,
2811987da915Sopenharmony_ci    .open = fuse_lib_open,
2812987da915Sopenharmony_ci    .read = fuse_lib_read,
2813987da915Sopenharmony_ci    .write = fuse_lib_write,
2814987da915Sopenharmony_ci    .flush = fuse_lib_flush,
2815987da915Sopenharmony_ci    .release = fuse_lib_release,
2816987da915Sopenharmony_ci    .fsync = fuse_lib_fsync,
2817987da915Sopenharmony_ci    .opendir = fuse_lib_opendir,
2818987da915Sopenharmony_ci    .readdir = fuse_lib_readdir,
2819987da915Sopenharmony_ci    .releasedir = fuse_lib_releasedir,
2820987da915Sopenharmony_ci    .fsyncdir = fuse_lib_fsyncdir,
2821987da915Sopenharmony_ci    .statfs = fuse_lib_statfs,
2822987da915Sopenharmony_ci    .setxattr = fuse_lib_setxattr,
2823987da915Sopenharmony_ci    .getxattr = fuse_lib_getxattr,
2824987da915Sopenharmony_ci    .listxattr = fuse_lib_listxattr,
2825987da915Sopenharmony_ci    .removexattr = fuse_lib_removexattr,
2826987da915Sopenharmony_ci    .getlk = fuse_lib_getlk,
2827987da915Sopenharmony_ci    .setlk = fuse_lib_setlk,
2828987da915Sopenharmony_ci    .bmap = fuse_lib_bmap,
2829987da915Sopenharmony_ci    .ioctl = fuse_lib_ioctl,
2830987da915Sopenharmony_ci};
2831987da915Sopenharmony_ci
2832987da915Sopenharmony_cistruct fuse_session *fuse_get_session(struct fuse *f)
2833987da915Sopenharmony_ci{
2834987da915Sopenharmony_ci    return f->se;
2835987da915Sopenharmony_ci}
2836987da915Sopenharmony_ci
2837987da915Sopenharmony_ciint fuse_loop(struct fuse *f)
2838987da915Sopenharmony_ci{
2839987da915Sopenharmony_ci    if (f)
2840987da915Sopenharmony_ci        return fuse_session_loop(f->se);
2841987da915Sopenharmony_ci    else
2842987da915Sopenharmony_ci        return -1;
2843987da915Sopenharmony_ci}
2844987da915Sopenharmony_ci
2845987da915Sopenharmony_civoid fuse_exit(struct fuse *f)
2846987da915Sopenharmony_ci{
2847987da915Sopenharmony_ci    fuse_session_exit(f->se);
2848987da915Sopenharmony_ci}
2849987da915Sopenharmony_ci
2850987da915Sopenharmony_cistruct fuse_context *fuse_get_context(void)
2851987da915Sopenharmony_ci{
2852987da915Sopenharmony_ci    return &fuse_get_context_internal()->ctx;
2853987da915Sopenharmony_ci}
2854987da915Sopenharmony_ci
2855987da915Sopenharmony_ciint fuse_interrupted(void)
2856987da915Sopenharmony_ci{
2857987da915Sopenharmony_ci    return fuse_req_interrupted(fuse_get_context_internal()->req);
2858987da915Sopenharmony_ci}
2859987da915Sopenharmony_ci
2860987da915Sopenharmony_cienum {
2861987da915Sopenharmony_ci    KEY_HELP,
2862987da915Sopenharmony_ci};
2863987da915Sopenharmony_ci
2864987da915Sopenharmony_ci#define FUSE_LIB_OPT(t, p, v) { t, offsetof(struct fuse_config, p), v }
2865987da915Sopenharmony_ci
2866987da915Sopenharmony_cistatic const struct fuse_opt fuse_lib_opts[] = {
2867987da915Sopenharmony_ci    FUSE_OPT_KEY("-h",                    KEY_HELP),
2868987da915Sopenharmony_ci    FUSE_OPT_KEY("--help",                KEY_HELP),
2869987da915Sopenharmony_ci    FUSE_OPT_KEY("debug",                 FUSE_OPT_KEY_KEEP),
2870987da915Sopenharmony_ci    FUSE_OPT_KEY("-d",                    FUSE_OPT_KEY_KEEP),
2871987da915Sopenharmony_ci    FUSE_LIB_OPT("debug",                 debug, 1),
2872987da915Sopenharmony_ci    FUSE_LIB_OPT("-d",                    debug, 1),
2873987da915Sopenharmony_ci    FUSE_LIB_OPT("hard_remove",           hard_remove, 1),
2874987da915Sopenharmony_ci    FUSE_LIB_OPT("use_ino",               use_ino, 1),
2875987da915Sopenharmony_ci    FUSE_LIB_OPT("readdir_ino",           readdir_ino, 1),
2876987da915Sopenharmony_ci    FUSE_LIB_OPT("direct_io",             direct_io, 1),
2877987da915Sopenharmony_ci    FUSE_LIB_OPT("kernel_cache",          kernel_cache, 1),
2878987da915Sopenharmony_ci#ifdef __SOLARIS__
2879987da915Sopenharmony_ci    FUSE_LIB_OPT("auto_cache",            auto_cache, 1),
2880987da915Sopenharmony_ci    FUSE_LIB_OPT("noauto_cache",          auto_cache, 0),
2881987da915Sopenharmony_ci#endif /* __SOLARIS__ */
2882987da915Sopenharmony_ci    FUSE_LIB_OPT("umask=",                set_mode, 1),
2883987da915Sopenharmony_ci    FUSE_LIB_OPT("umask=%o",              umask, 0),
2884987da915Sopenharmony_ci    FUSE_LIB_OPT("uid=",                  set_uid, 1),
2885987da915Sopenharmony_ci    FUSE_LIB_OPT("uid=%d",                uid, 0),
2886987da915Sopenharmony_ci    FUSE_LIB_OPT("gid=",                  set_gid, 1),
2887987da915Sopenharmony_ci    FUSE_LIB_OPT("gid=%d",                gid, 0),
2888987da915Sopenharmony_ci    FUSE_LIB_OPT("entry_timeout=%lf",     entry_timeout, 0),
2889987da915Sopenharmony_ci    FUSE_LIB_OPT("attr_timeout=%lf",      attr_timeout, 0),
2890987da915Sopenharmony_ci    FUSE_LIB_OPT("ac_attr_timeout=%lf",   ac_attr_timeout, 0),
2891987da915Sopenharmony_ci    FUSE_LIB_OPT("ac_attr_timeout=",      ac_attr_timeout_set, 1),
2892987da915Sopenharmony_ci    FUSE_LIB_OPT("negative_timeout=%lf",  negative_timeout, 0),
2893987da915Sopenharmony_ci    FUSE_LIB_OPT("intr",                  intr, 1),
2894987da915Sopenharmony_ci    FUSE_LIB_OPT("intr_signal=%d",        intr_signal, 0),
2895987da915Sopenharmony_ci#ifdef __SOLARIS__
2896987da915Sopenharmony_ci    FUSE_LIB_OPT("modules=%s",            modules, 0),
2897987da915Sopenharmony_ci#endif /* __SOLARIS__ */
2898987da915Sopenharmony_ci    FUSE_OPT_END
2899987da915Sopenharmony_ci};
2900987da915Sopenharmony_ci
2901987da915Sopenharmony_cistatic void fuse_lib_help(void)
2902987da915Sopenharmony_ci{
2903987da915Sopenharmony_ci    fprintf(stderr,
2904987da915Sopenharmony_ci"    -o hard_remove         immediate removal (don't hide files)\n"
2905987da915Sopenharmony_ci"    -o use_ino             let filesystem set inode numbers\n"
2906987da915Sopenharmony_ci"    -o readdir_ino         try to fill in d_ino in readdir\n"
2907987da915Sopenharmony_ci"    -o direct_io           use direct I/O\n"
2908987da915Sopenharmony_ci"    -o kernel_cache        cache files in kernel\n"
2909987da915Sopenharmony_ci#ifdef __SOLARIS__
2910987da915Sopenharmony_ci"    -o [no]auto_cache      enable caching based on modification times (off)\n"
2911987da915Sopenharmony_ci#endif /* __SOLARIS__ */
2912987da915Sopenharmony_ci"    -o umask=M             set file permissions (octal)\n"
2913987da915Sopenharmony_ci"    -o uid=N               set file owner\n"
2914987da915Sopenharmony_ci"    -o gid=N               set file group\n"
2915987da915Sopenharmony_ci"    -o entry_timeout=T     cache timeout for names (1.0s)\n"
2916987da915Sopenharmony_ci"    -o negative_timeout=T  cache timeout for deleted names (0.0s)\n"
2917987da915Sopenharmony_ci"    -o attr_timeout=T      cache timeout for attributes (1.0s)\n"
2918987da915Sopenharmony_ci"    -o ac_attr_timeout=T   auto cache timeout for attributes (attr_timeout)\n"
2919987da915Sopenharmony_ci"    -o intr                allow requests to be interrupted\n"
2920987da915Sopenharmony_ci"    -o intr_signal=NUM     signal to send on interrupt (%i)\n"
2921987da915Sopenharmony_ci#ifdef __SOLARIS__
2922987da915Sopenharmony_ci"    -o modules=M1[:M2...]  names of modules to push onto filesystem stack\n"
2923987da915Sopenharmony_ci#endif /* __SOLARIS__ */
2924987da915Sopenharmony_ci"\n", FUSE_DEFAULT_INTR_SIGNAL);
2925987da915Sopenharmony_ci}
2926987da915Sopenharmony_ci
2927987da915Sopenharmony_ci#ifdef __SOLARIS__
2928987da915Sopenharmony_ci
2929987da915Sopenharmony_cistatic void fuse_lib_help_modules(void)
2930987da915Sopenharmony_ci{
2931987da915Sopenharmony_ci    struct fuse_module *m;
2932987da915Sopenharmony_ci    fprintf(stderr, "\nModule options:\n");
2933987da915Sopenharmony_ci    pthread_mutex_lock(&fuse_context_lock);
2934987da915Sopenharmony_ci    for (m = fuse_modules; m; m = m->next) {
2935987da915Sopenharmony_ci        struct fuse_fs *fs = NULL;
2936987da915Sopenharmony_ci        struct fuse_fs *newfs;
2937987da915Sopenharmony_ci        struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
2938987da915Sopenharmony_ci        if (fuse_opt_add_arg(&args, "") != -1 &&
2939987da915Sopenharmony_ci            fuse_opt_add_arg(&args, "-h") != -1) {
2940987da915Sopenharmony_ci            fprintf(stderr, "\n[%s]\n", m->name);
2941987da915Sopenharmony_ci            newfs = m->factory(&args, &fs);
2942987da915Sopenharmony_ci            assert(newfs == NULL);
2943987da915Sopenharmony_ci        }
2944987da915Sopenharmony_ci        fuse_opt_free_args(&args);
2945987da915Sopenharmony_ci    }
2946987da915Sopenharmony_ci    pthread_mutex_unlock(&fuse_context_lock);
2947987da915Sopenharmony_ci}
2948987da915Sopenharmony_ci
2949987da915Sopenharmony_ciint fuse_is_lib_option(const char *opt)
2950987da915Sopenharmony_ci{
2951987da915Sopenharmony_ci    return fuse_lowlevel_is_lib_option(opt) ||
2952987da915Sopenharmony_ci        fuse_opt_match(fuse_lib_opts, opt);
2953987da915Sopenharmony_ci}
2954987da915Sopenharmony_ci
2955987da915Sopenharmony_ci#endif /* __SOLARIS__ */
2956987da915Sopenharmony_ci
2957987da915Sopenharmony_cistatic int fuse_lib_opt_proc(void *data, const char *arg, int key,
2958987da915Sopenharmony_ci                             struct fuse_args *outargs)
2959987da915Sopenharmony_ci{
2960987da915Sopenharmony_ci    (void) arg; (void) outargs;
2961987da915Sopenharmony_ci
2962987da915Sopenharmony_ci    if (key == KEY_HELP) {
2963987da915Sopenharmony_ci        struct fuse_config *conf = (struct fuse_config *) data;
2964987da915Sopenharmony_ci        fuse_lib_help();
2965987da915Sopenharmony_ci        conf->help = 1;
2966987da915Sopenharmony_ci    }
2967987da915Sopenharmony_ci
2968987da915Sopenharmony_ci    return 1;
2969987da915Sopenharmony_ci}
2970987da915Sopenharmony_ci
2971987da915Sopenharmony_cistatic int fuse_init_intr_signal(int signum, int *installed)
2972987da915Sopenharmony_ci{
2973987da915Sopenharmony_ci    struct sigaction old_sa;
2974987da915Sopenharmony_ci
2975987da915Sopenharmony_ci    if (sigaction(signum, NULL, &old_sa) == -1) {
2976987da915Sopenharmony_ci        perror("fuse: cannot get old signal handler");
2977987da915Sopenharmony_ci        return -1;
2978987da915Sopenharmony_ci    }
2979987da915Sopenharmony_ci
2980987da915Sopenharmony_ci    if (old_sa.sa_handler == SIG_DFL) {
2981987da915Sopenharmony_ci        struct sigaction sa;
2982987da915Sopenharmony_ci
2983987da915Sopenharmony_ci        memset(&sa, 0, sizeof(struct sigaction));
2984987da915Sopenharmony_ci        sa.sa_handler = fuse_intr_sighandler;
2985987da915Sopenharmony_ci        sigemptyset(&sa.sa_mask);
2986987da915Sopenharmony_ci
2987987da915Sopenharmony_ci        if (sigaction(signum, &sa, NULL) == -1) {
2988987da915Sopenharmony_ci            perror("fuse: cannot set interrupt signal handler");
2989987da915Sopenharmony_ci            return -1;
2990987da915Sopenharmony_ci        }
2991987da915Sopenharmony_ci        *installed = 1;
2992987da915Sopenharmony_ci    }
2993987da915Sopenharmony_ci    return 0;
2994987da915Sopenharmony_ci}
2995987da915Sopenharmony_ci
2996987da915Sopenharmony_cistatic void fuse_restore_intr_signal(int signum)
2997987da915Sopenharmony_ci{
2998987da915Sopenharmony_ci    struct sigaction sa;
2999987da915Sopenharmony_ci
3000987da915Sopenharmony_ci    memset(&sa, 0, sizeof(struct sigaction));
3001987da915Sopenharmony_ci    sa.sa_handler = SIG_DFL;
3002987da915Sopenharmony_ci    sigaction(signum, &sa, NULL);
3003987da915Sopenharmony_ci}
3004987da915Sopenharmony_ci
3005987da915Sopenharmony_ci#ifdef __SOLARIS__
3006987da915Sopenharmony_ci
3007987da915Sopenharmony_cistatic int fuse_push_module(struct fuse *f, const char *module,
3008987da915Sopenharmony_ci                            struct fuse_args *args)
3009987da915Sopenharmony_ci{
3010987da915Sopenharmony_ci    struct fuse_fs *newfs;
3011987da915Sopenharmony_ci    struct fuse_module *m = fuse_get_module(module);
3012987da915Sopenharmony_ci    struct fuse_fs *fs[2];
3013987da915Sopenharmony_ci
3014987da915Sopenharmony_ci    fs[0] = f->fs;
3015987da915Sopenharmony_ci    fs[1] = NULL;
3016987da915Sopenharmony_ci    if (!m)
3017987da915Sopenharmony_ci        return -1;
3018987da915Sopenharmony_ci
3019987da915Sopenharmony_ci    newfs = m->factory(args, fs);
3020987da915Sopenharmony_ci    if (!newfs) {
3021987da915Sopenharmony_ci        fuse_put_module(m);
3022987da915Sopenharmony_ci        return -1;
3023987da915Sopenharmony_ci    }
3024987da915Sopenharmony_ci    newfs->m = m;
3025987da915Sopenharmony_ci    f->fs = newfs;
3026987da915Sopenharmony_ci    return 0;
3027987da915Sopenharmony_ci}
3028987da915Sopenharmony_ci
3029987da915Sopenharmony_ci#endif /* __SOLARIS__ */
3030987da915Sopenharmony_ci
3031987da915Sopenharmony_cistruct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
3032987da915Sopenharmony_ci                            void *user_data)
3033987da915Sopenharmony_ci{
3034987da915Sopenharmony_ci    struct fuse_fs *fs;
3035987da915Sopenharmony_ci
3036987da915Sopenharmony_ci    if (sizeof(struct fuse_operations) < op_size) {
3037987da915Sopenharmony_ci        fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
3038987da915Sopenharmony_ci        op_size = sizeof(struct fuse_operations);
3039987da915Sopenharmony_ci    }
3040987da915Sopenharmony_ci
3041987da915Sopenharmony_ci    fs = (struct fuse_fs *) calloc(1, sizeof(struct fuse_fs));
3042987da915Sopenharmony_ci    if (!fs) {
3043987da915Sopenharmony_ci        fprintf(stderr, "fuse: failed to allocate fuse_fs object\n");
3044987da915Sopenharmony_ci        return NULL;
3045987da915Sopenharmony_ci    }
3046987da915Sopenharmony_ci
3047987da915Sopenharmony_ci    fs->user_data = user_data;
3048987da915Sopenharmony_ci    if (op)
3049987da915Sopenharmony_ci        memcpy(&fs->op, op, op_size);
3050987da915Sopenharmony_ci    return fs;
3051987da915Sopenharmony_ci}
3052987da915Sopenharmony_ci
3053987da915Sopenharmony_cistruct fuse *fuse_new(struct fuse_chan *ch, struct fuse_args *args,
3054987da915Sopenharmony_ci		      const struct fuse_operations *op, size_t op_size,
3055987da915Sopenharmony_ci		      void *user_data)
3056987da915Sopenharmony_ci{
3057987da915Sopenharmony_ci    struct fuse *f;
3058987da915Sopenharmony_ci    struct node *root;
3059987da915Sopenharmony_ci    struct fuse_fs *fs;
3060987da915Sopenharmony_ci    struct fuse_lowlevel_ops llop = fuse_path_ops;
3061987da915Sopenharmony_ci
3062987da915Sopenharmony_ci    if (fuse_create_context_key() == -1)
3063987da915Sopenharmony_ci        goto out;
3064987da915Sopenharmony_ci
3065987da915Sopenharmony_ci    f = (struct fuse *) calloc(1, sizeof(struct fuse));
3066987da915Sopenharmony_ci    if (f == NULL) {
3067987da915Sopenharmony_ci        fprintf(stderr, "fuse: failed to allocate fuse object\n");
3068987da915Sopenharmony_ci        goto out_delete_context_key;
3069987da915Sopenharmony_ci    }
3070987da915Sopenharmony_ci
3071987da915Sopenharmony_ci    fs = fuse_fs_new(op, op_size, user_data);
3072987da915Sopenharmony_ci    if (!fs)
3073987da915Sopenharmony_ci        goto out_free;
3074987da915Sopenharmony_ci
3075987da915Sopenharmony_ci    f->fs = fs;
3076987da915Sopenharmony_ci
3077987da915Sopenharmony_ci    /* Oh f**k, this is ugly! */
3078987da915Sopenharmony_ci    if (!fs->op.lock) {
3079987da915Sopenharmony_ci        llop.getlk = NULL;
3080987da915Sopenharmony_ci        llop.setlk = NULL;
3081987da915Sopenharmony_ci    }
3082987da915Sopenharmony_ci
3083987da915Sopenharmony_ci    f->conf.entry_timeout = 1.0;
3084987da915Sopenharmony_ci    f->conf.attr_timeout = 1.0;
3085987da915Sopenharmony_ci    f->conf.negative_timeout = 0.0;
3086987da915Sopenharmony_ci    f->conf.hard_remove = 1;
3087987da915Sopenharmony_ci    f->conf.intr_signal = FUSE_DEFAULT_INTR_SIGNAL;
3088987da915Sopenharmony_ci
3089987da915Sopenharmony_ci    if (fuse_opt_parse(args, &f->conf, fuse_lib_opts, fuse_lib_opt_proc) == -1)
3090987da915Sopenharmony_ci        goto out_free_fs;
3091987da915Sopenharmony_ci
3092987da915Sopenharmony_ci#ifdef __SOLARIS__
3093987da915Sopenharmony_ci    if (f->conf.modules) {
3094987da915Sopenharmony_ci        char *module;
3095987da915Sopenharmony_ci        char *next;
3096987da915Sopenharmony_ci
3097987da915Sopenharmony_ci        for (module = f->conf.modules; module; module = next) {
3098987da915Sopenharmony_ci            char *p;
3099987da915Sopenharmony_ci            for (p = module; *p && *p != ':'; p++);
3100987da915Sopenharmony_ci            next = *p ? p + 1 : NULL;
3101987da915Sopenharmony_ci            *p = '\0';
3102987da915Sopenharmony_ci            if (module[0] && fuse_push_module(f, module, args) == -1)
3103987da915Sopenharmony_ci                goto out_free_fs;
3104987da915Sopenharmony_ci        }
3105987da915Sopenharmony_ci    }
3106987da915Sopenharmony_ci#endif /* __SOLARIS__ */
3107987da915Sopenharmony_ci
3108987da915Sopenharmony_ci    if (!f->conf.ac_attr_timeout_set)
3109987da915Sopenharmony_ci        f->conf.ac_attr_timeout = f->conf.attr_timeout;
3110987da915Sopenharmony_ci
3111987da915Sopenharmony_ci#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
3112987da915Sopenharmony_ci    /*
3113987da915Sopenharmony_ci     * In FreeBSD, we always use these settings as inode numbers are needed to
3114987da915Sopenharmony_ci     * make getcwd(3) work.
3115987da915Sopenharmony_ci     */
3116987da915Sopenharmony_ci    f->conf.readdir_ino = 1;
3117987da915Sopenharmony_ci#endif
3118987da915Sopenharmony_ci
3119987da915Sopenharmony_ci    f->se = fuse_lowlevel_new(args, &llop, sizeof(llop), f);
3120987da915Sopenharmony_ci
3121987da915Sopenharmony_ci    if (f->se == NULL) {
3122987da915Sopenharmony_ci#ifdef __SOLARIS__
3123987da915Sopenharmony_ci        if (f->conf.help)
3124987da915Sopenharmony_ci            fuse_lib_help_modules();
3125987da915Sopenharmony_ci#endif /* __SOLARIS__ */
3126987da915Sopenharmony_ci        goto out_free_fs;
3127987da915Sopenharmony_ci    }
3128987da915Sopenharmony_ci
3129987da915Sopenharmony_ci    fuse_session_add_chan(f->se, ch);
3130987da915Sopenharmony_ci
3131987da915Sopenharmony_ci    f->ctr = 0;
3132987da915Sopenharmony_ci    f->generation = 0;
3133987da915Sopenharmony_ci    /* FIXME: Dynamic hash table */
3134987da915Sopenharmony_ci    f->name_table_size = 14057;
3135987da915Sopenharmony_ci    f->name_table = (struct node **)
3136987da915Sopenharmony_ci        calloc(1, sizeof(struct node *) * f->name_table_size);
3137987da915Sopenharmony_ci    if (f->name_table == NULL) {
3138987da915Sopenharmony_ci        fprintf(stderr, "fuse: memory allocation failed\n");
3139987da915Sopenharmony_ci        goto out_free_session;
3140987da915Sopenharmony_ci    }
3141987da915Sopenharmony_ci
3142987da915Sopenharmony_ci    f->id_table_size = 14057;
3143987da915Sopenharmony_ci    f->id_table = (struct node **)
3144987da915Sopenharmony_ci        calloc(1, sizeof(struct node *) * f->id_table_size);
3145987da915Sopenharmony_ci    if (f->id_table == NULL) {
3146987da915Sopenharmony_ci        fprintf(stderr, "fuse: memory allocation failed\n");
3147987da915Sopenharmony_ci        goto out_free_name_table;
3148987da915Sopenharmony_ci    }
3149987da915Sopenharmony_ci
3150987da915Sopenharmony_ci    fuse_mutex_init(&f->lock);
3151987da915Sopenharmony_ci    pthread_rwlock_init(&f->tree_lock, NULL);
3152987da915Sopenharmony_ci
3153987da915Sopenharmony_ci    root = (struct node *) calloc(1, sizeof(struct node));
3154987da915Sopenharmony_ci    if (root == NULL) {
3155987da915Sopenharmony_ci        fprintf(stderr, "fuse: memory allocation failed\n");
3156987da915Sopenharmony_ci        goto out_free_id_table;
3157987da915Sopenharmony_ci    }
3158987da915Sopenharmony_ci
3159987da915Sopenharmony_ci    root->name = strdup("/");
3160987da915Sopenharmony_ci    if (root->name == NULL) {
3161987da915Sopenharmony_ci        fprintf(stderr, "fuse: memory allocation failed\n");
3162987da915Sopenharmony_ci        goto out_free_root;
3163987da915Sopenharmony_ci    }
3164987da915Sopenharmony_ci
3165987da915Sopenharmony_ci    if (f->conf.intr &&
3166987da915Sopenharmony_ci        fuse_init_intr_signal(f->conf.intr_signal, &f->intr_installed) == -1)
3167987da915Sopenharmony_ci        goto out_free_root_name;
3168987da915Sopenharmony_ci
3169987da915Sopenharmony_ci    root->parent = NULL;
3170987da915Sopenharmony_ci    root->nodeid = FUSE_ROOT_ID;
3171987da915Sopenharmony_ci    root->generation = 0;
3172987da915Sopenharmony_ci    root->refctr = 1;
3173987da915Sopenharmony_ci    root->nlookup = 1;
3174987da915Sopenharmony_ci    hash_id(f, root);
3175987da915Sopenharmony_ci
3176987da915Sopenharmony_ci    return f;
3177987da915Sopenharmony_ci
3178987da915Sopenharmony_ci out_free_root_name:
3179987da915Sopenharmony_ci    free(root->name);
3180987da915Sopenharmony_ci out_free_root:
3181987da915Sopenharmony_ci    free(root);
3182987da915Sopenharmony_ci out_free_id_table:
3183987da915Sopenharmony_ci    free(f->id_table);
3184987da915Sopenharmony_ci out_free_name_table:
3185987da915Sopenharmony_ci    free(f->name_table);
3186987da915Sopenharmony_ci out_free_session:
3187987da915Sopenharmony_ci    fuse_session_destroy(f->se);
3188987da915Sopenharmony_ci out_free_fs:
3189987da915Sopenharmony_ci    /* Horrible compatibility hack to stop the destructor from being
3190987da915Sopenharmony_ci       called on the filesystem without init being called first */
3191987da915Sopenharmony_ci    fs->op.destroy = NULL;
3192987da915Sopenharmony_ci    fuse_fs_destroy(f->fs);
3193987da915Sopenharmony_ci#ifdef __SOLARIS__
3194987da915Sopenharmony_ci    free(f->conf.modules);
3195987da915Sopenharmony_ci#endif /* __SOLARIS__ */
3196987da915Sopenharmony_ci out_free:
3197987da915Sopenharmony_ci    free(f);
3198987da915Sopenharmony_ci out_delete_context_key:
3199987da915Sopenharmony_ci    fuse_delete_context_key();
3200987da915Sopenharmony_ci out:
3201987da915Sopenharmony_ci    return NULL;
3202987da915Sopenharmony_ci}
3203987da915Sopenharmony_ci
3204987da915Sopenharmony_civoid fuse_destroy(struct fuse *f)
3205987da915Sopenharmony_ci{
3206987da915Sopenharmony_ci    size_t i;
3207987da915Sopenharmony_ci
3208987da915Sopenharmony_ci    if (f->conf.intr && f->intr_installed)
3209987da915Sopenharmony_ci        fuse_restore_intr_signal(f->conf.intr_signal);
3210987da915Sopenharmony_ci
3211987da915Sopenharmony_ci    if (f->fs) {
3212987da915Sopenharmony_ci        struct fuse_context_i *c = fuse_get_context_internal();
3213987da915Sopenharmony_ci
3214987da915Sopenharmony_ci        memset(c, 0, sizeof(*c));
3215987da915Sopenharmony_ci        c->ctx.fuse = f;
3216987da915Sopenharmony_ci
3217987da915Sopenharmony_ci        for (i = 0; i < f->id_table_size; i++) {
3218987da915Sopenharmony_ci            struct node *node;
3219987da915Sopenharmony_ci
3220987da915Sopenharmony_ci            for (node = f->id_table[i]; node != NULL; node = node->id_next) {
3221987da915Sopenharmony_ci                if (node->is_hidden) {
3222987da915Sopenharmony_ci                    char *path = get_path(f, node->nodeid);
3223987da915Sopenharmony_ci                    if (path) {
3224987da915Sopenharmony_ci                        fuse_fs_unlink(f->fs, path);
3225987da915Sopenharmony_ci                        free(path);
3226987da915Sopenharmony_ci                    }
3227987da915Sopenharmony_ci                }
3228987da915Sopenharmony_ci            }
3229987da915Sopenharmony_ci        }
3230987da915Sopenharmony_ci    }
3231987da915Sopenharmony_ci    for (i = 0; i < f->id_table_size; i++) {
3232987da915Sopenharmony_ci        struct node *node;
3233987da915Sopenharmony_ci        struct node *next;
3234987da915Sopenharmony_ci
3235987da915Sopenharmony_ci        for (node = f->id_table[i]; node != NULL; node = next) {
3236987da915Sopenharmony_ci            next = node->id_next;
3237987da915Sopenharmony_ci            free_node(node);
3238987da915Sopenharmony_ci        }
3239987da915Sopenharmony_ci    }
3240987da915Sopenharmony_ci    free(f->id_table);
3241987da915Sopenharmony_ci    free(f->name_table);
3242987da915Sopenharmony_ci    pthread_mutex_destroy(&f->lock);
3243987da915Sopenharmony_ci    pthread_rwlock_destroy(&f->tree_lock);
3244987da915Sopenharmony_ci    fuse_session_destroy(f->se);
3245987da915Sopenharmony_ci#ifdef __SOLARIS__
3246987da915Sopenharmony_ci    free(f->conf.modules);
3247987da915Sopenharmony_ci#endif /* __SOLARIS__ */
3248987da915Sopenharmony_ci    free(f);
3249987da915Sopenharmony_ci    fuse_delete_context_key();
3250987da915Sopenharmony_ci}
3251