blob: 4635e326fac768911c2e6a4a2103d9e0abfadd5d [file] [log] [blame]
Miklos Szeredi12744942005-07-11 12:32:31 +00001/*
2 FUSE: Filesystem in Userspace
3 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
4
5 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB
7*/
8
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00009#include <config.h>
10#include "fuse_lowlevel_i.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000011#include "fuse_kernel.h"
Miklos Szeredi12744942005-07-11 12:32:31 +000012
13#include <stdio.h>
14#include <string.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <limits.h>
18#include <errno.h>
19#include <assert.h>
20#include <stdint.h>
21#include <sys/param.h>
22#include <sys/uio.h>
23
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000024#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000025
Miklos Szeredi12744942005-07-11 12:32:31 +000026struct fuse_cmd {
27 char *buf;
28 size_t buflen;
29};
30
Miklos Szeredi76c17522005-07-13 14:08:19 +000031struct fuse_req {
32 struct fuse_ll *f;
33 uint64_t unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000034 struct fuse_ctx ctx;
Miklos Szeredi76c17522005-07-13 14:08:19 +000035};
36
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000037#ifndef USE_UCLIBC
38#define mutex_init(mut) pthread_mutex_init(mut, NULL)
39#else
40static void mutex_init(pthread_mutex_t *mut)
41{
42 pthread_mutexattr_t attr;
43 pthread_mutexattr_init(&attr);
44 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
45 pthread_mutex_init(mut, &attr);
46 pthread_mutexattr_destroy(&attr);
47}
48#endif
49
Miklos Szeredi12744942005-07-11 12:32:31 +000050static const char *opname(enum fuse_opcode opcode)
51{
52 switch (opcode) {
53 case FUSE_LOOKUP: return "LOOKUP";
54 case FUSE_FORGET: return "FORGET";
55 case FUSE_GETATTR: return "GETATTR";
56 case FUSE_SETATTR: return "SETATTR";
57 case FUSE_READLINK: return "READLINK";
58 case FUSE_SYMLINK: return "SYMLINK";
59 case FUSE_MKNOD: return "MKNOD";
60 case FUSE_MKDIR: return "MKDIR";
61 case FUSE_UNLINK: return "UNLINK";
62 case FUSE_RMDIR: return "RMDIR";
63 case FUSE_RENAME: return "RENAME";
64 case FUSE_LINK: return "LINK";
65 case FUSE_OPEN: return "OPEN";
66 case FUSE_READ: return "READ";
67 case FUSE_WRITE: return "WRITE";
68 case FUSE_STATFS: return "STATFS";
69 case FUSE_FLUSH: return "FLUSH";
70 case FUSE_RELEASE: return "RELEASE";
71 case FUSE_FSYNC: return "FSYNC";
72 case FUSE_SETXATTR: return "SETXATTR";
73 case FUSE_GETXATTR: return "GETXATTR";
74 case FUSE_LISTXATTR: return "LISTXATTR";
75 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
76 case FUSE_INIT: return "INIT";
77 case FUSE_OPENDIR: return "OPENDIR";
78 case FUSE_READDIR: return "READDIR";
79 case FUSE_RELEASEDIR: return "RELEASEDIR";
80 case FUSE_FSYNCDIR: return "FSYNCDIR";
81 default: return "???";
82 }
83}
84
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000085static inline void fuse_dec_avail(struct fuse_ll *f)
86{
87 pthread_mutex_lock(&f->worker_lock);
88 f->numavail --;
89 pthread_mutex_unlock(&f->worker_lock);
90}
91
92static inline void fuse_inc_avail(struct fuse_ll *f)
93{
94 pthread_mutex_lock(&f->worker_lock);
95 f->numavail ++;
96 pthread_mutex_unlock(&f->worker_lock);
97}
98
Miklos Szeredi76c17522005-07-13 14:08:19 +000099static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +0000100{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000101 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +0000102 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +0000103 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000104 attr->uid = stbuf->st_uid;
105 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +0000106 attr->rdev = stbuf->st_rdev;
107 attr->size = stbuf->st_size;
108 attr->blocks = stbuf->st_blocks;
109 attr->atime = stbuf->st_atime;
110 attr->mtime = stbuf->st_mtime;
111 attr->ctime = stbuf->st_ctime;
112#ifdef HAVE_STRUCT_STAT_ST_ATIM
113 attr->atimensec = stbuf->st_atim.tv_nsec;
114 attr->mtimensec = stbuf->st_mtim.tv_nsec;
115 attr->ctimensec = stbuf->st_ctim.tv_nsec;
116#endif
117}
118
Miklos Szeredi76c17522005-07-13 14:08:19 +0000119static void convert_attr(const struct fuse_attr *attr, struct stat *stbuf)
120{
121 stbuf->st_mode = attr->mode;
122 stbuf->st_uid = attr->uid;
123 stbuf->st_gid = attr->gid;
124 stbuf->st_size = attr->size;
125 stbuf->st_atime = attr->atime;
126 stbuf->st_mtime = attr->mtime;
127 stbuf->st_ctime = attr->ctime;
128#ifdef HAVE_STRUCT_STAT_ST_ATIM
129 stbuf->st_atim.tv_nsec = attr->atimensec;
130 stbuf->st_mtim.tv_nsec = attr->mtimensec;
131 stbuf->st_ctim.tv_nsec = attr->ctimensec;
132#endif
133}
134
Miklos Szeredi12744942005-07-11 12:32:31 +0000135static size_t iov_length(const struct iovec *iov, size_t count)
136{
137 size_t seg;
138 size_t ret = 0;
139
140 for (seg = 0; seg < count; seg++)
141 ret += iov[seg].iov_len;
142 return ret;
143}
144
145static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
146 size_t count)
147{
148 int res;
149 unsigned outsize = iov_length(iov, count);
150 struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
151 out->len = outsize;
152
Miklos Szeredi76c17522005-07-13 14:08:19 +0000153 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000154 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
155 out->unique, out->error, strerror(-out->error), outsize);
156 fflush(stdout);
157 }
158
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000159 /* This needs to be done before the reply, otherwise the scheduler
160 could play tricks with us, and only let the counter be
161 increased long after the operation is done */
162 fuse_inc_avail(f);
163
Miklos Szeredi12744942005-07-11 12:32:31 +0000164 res = writev(f->fd, iov, count);
165 if (res == -1) {
166 /* ENOENT means the operation was interrupted */
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000167 if (!fuse_ll_exited(f) && errno != ENOENT)
Miklos Szeredi12744942005-07-11 12:32:31 +0000168 perror("fuse: writing device");
169 return -errno;
170 }
171 return 0;
172}
173
Miklos Szeredi76c17522005-07-13 14:08:19 +0000174static int send_reply(struct fuse_ll *f, uint64_t unique, int error,
175 const void *arg, size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000176{
177 struct fuse_out_header out;
178 struct iovec iov[2];
179 size_t count;
180
181 if (error <= -1000 || error > 0) {
182 fprintf(stderr, "fuse: bad error value: %i\n", error);
183 error = -ERANGE;
184 }
185
Miklos Szeredi76c17522005-07-13 14:08:19 +0000186 out.unique = unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000187 out.error = error;
188 count = 1;
189 iov[0].iov_base = &out;
190 iov[0].iov_len = sizeof(struct fuse_out_header);
191 if (argsize && !error) {
192 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000193 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000194 iov[1].iov_len = argsize;
195 }
196 return send_reply_raw(f, iov, count);
197}
198
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000199size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000200{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000201 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000202}
203
Miklos Szeredi76c17522005-07-13 14:08:19 +0000204char *fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
205 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000206{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000207 unsigned namelen = strlen(name);
208 unsigned entlen = FUSE_NAME_OFFSET + namelen;
209 unsigned entsize = fuse_dirent_size(namelen);
210 unsigned padlen = entsize - entlen;
211 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000212
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000213 dirent->ino = stat->st_ino;
214 dirent->off = off;
215 dirent->namelen = namelen;
216 dirent->type = (stat->st_mode & 0170000) >> 12;
217 strncpy(dirent->name, name, namelen);
218 if (padlen)
219 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000220
Miklos Szeredi76c17522005-07-13 14:08:19 +0000221 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000222}
223
Miklos Szeredi76c17522005-07-13 14:08:19 +0000224static void convert_statfs(const struct statfs *statfs,
225 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000226{
227 kstatfs->bsize = statfs->f_bsize;
228 kstatfs->blocks = statfs->f_blocks;
229 kstatfs->bfree = statfs->f_bfree;
230 kstatfs->bavail = statfs->f_bavail;
231 kstatfs->files = statfs->f_files;
232 kstatfs->ffree = statfs->f_ffree;
233 kstatfs->namelen = statfs->f_namelen;
234}
235
Miklos Szeredi76c17522005-07-13 14:08:19 +0000236static void free_req(fuse_req_t req)
237{
238 free(req);
239}
240
241static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize)
242{
243 int res = send_reply(req->f, req->unique, 0, arg, argsize);
244 free_req(req);
245 return res;
246}
247
248int fuse_reply_err(fuse_req_t req, int err)
249{
250 int res = send_reply(req->f, req->unique, -err, NULL, 0);
251 free_req(req);
252 return res;
253}
254
255int fuse_reply_none(fuse_req_t req)
256{
257 free_req(req);
258 return 0;
259}
260
261static unsigned long calc_timeout_sec(double t)
262{
263 if (t > (double) ULONG_MAX)
264 return ULONG_MAX;
265 else if (t < 0.0)
266 return 0;
267 else
268 return (unsigned long) t;
269}
270
271static unsigned int calc_timeout_nsec(double t)
272{
273 double f = t - (double) calc_timeout_sec(t);
274 if (f < 0.0)
275 return 0;
276 else if (f >= 0.999999999)
277 return 999999999;
278 else
279 return (unsigned int) (f * 1.0e9);
280}
281
282int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
283{
284 struct fuse_entry_out arg;
285
286 memset(&arg, 0, sizeof(arg));
287 arg.nodeid = e->ino;
288 arg.generation = e->generation;
289 arg.entry_valid = calc_timeout_sec(e->entry_timeout);
290 arg.entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
291 arg.attr_valid = calc_timeout_sec(e->attr_timeout);
292 arg.attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
293 convert_stat(&e->attr, &arg.attr);
294
295 return send_reply_req(req, &arg, sizeof(arg));
296}
297
298int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
299 double attr_timeout)
300{
301 struct fuse_attr_out arg;
302
303 memset(&arg, 0, sizeof(arg));
304 arg.attr_valid = calc_timeout_sec(attr_timeout);
305 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
306 convert_stat(attr, &arg.attr);
307
308 return send_reply_req(req, &arg, sizeof(arg));
309}
310
311int fuse_reply_readlink(fuse_req_t req, const char *link)
312{
313 return send_reply_req(req, link, strlen(link));
314}
315
316int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
317{
318 struct fuse_open_out arg;
319
320 memset(&arg, 0, sizeof(arg));
321 arg.fh = f->fh;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000322
Miklos Szeredi76c17522005-07-13 14:08:19 +0000323 return send_reply_req(req, &arg, sizeof(arg));
324}
325
326int fuse_reply_write(fuse_req_t req, size_t count)
327{
328 struct fuse_write_out arg;
329
330 memset(&arg, 0, sizeof(arg));
331 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000332
Miklos Szeredi76c17522005-07-13 14:08:19 +0000333 return send_reply_req(req, &arg, sizeof(arg));
334}
335
336int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
337{
338 return send_reply_req(req, buf, size);
339}
340
341int fuse_reply_statfs(fuse_req_t req, const struct statfs *statfs)
342{
343 struct fuse_statfs_out arg;
344
345 memset(&arg, 0, sizeof(arg));
346 convert_statfs(statfs, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000347
Miklos Szeredi76c17522005-07-13 14:08:19 +0000348 return send_reply_req(req, &arg, sizeof(arg));
349}
350
351int fuse_reply_xattr(fuse_req_t req, size_t count)
352{
353 struct fuse_getxattr_out arg;
354
355 memset(&arg, 0, sizeof(arg));
356 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000357
Miklos Szeredi76c17522005-07-13 14:08:19 +0000358 return send_reply_req(req, &arg, sizeof(arg));
359}
360
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000361static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000362{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000363 if (req->f->op.lookup)
364 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000365 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000366 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000367}
368
Miklos Szeredi76c17522005-07-13 14:08:19 +0000369static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
370 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000371{
372 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000373 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000374}
375
376static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
377{
378 if (req->f->op.getattr)
379 req->f->op.getattr(req, nodeid);
380 else
381 fuse_reply_err(req, ENOSYS);
382}
383
384static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
385 struct fuse_setattr_in *arg)
386{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000387 if (req->f->op.setattr) {
388 struct stat stbuf;
389 convert_attr(&arg->attr, &stbuf);
390 req->f->op.setattr(req, nodeid, &stbuf, arg->valid);
391 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000392 fuse_reply_err(req, ENOSYS);
393}
394
395static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
396{
397 if (req->f->op.readlink)
398 req->f->op.readlink(req, nodeid);
399 else
400 fuse_reply_err(req, ENOSYS);
401}
402
403static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
404 struct fuse_mknod_in *arg)
405{
406 if (req->f->op.mknod)
407 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
408 else
409 fuse_reply_err(req, ENOSYS);
410}
411
412static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
413 struct fuse_mkdir_in *arg)
414{
415 if (req->f->op.mkdir)
416 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
417 else
418 fuse_reply_err(req, ENOSYS);
419}
420
421static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
422{
423 if (req->f->op.unlink)
424 req->f->op.unlink(req, nodeid, name);
425 else
426 fuse_reply_err(req, ENOSYS);
427}
428
429static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
430{
431 if (req->f->op.rmdir)
432 req->f->op.rmdir(req, nodeid, name);
433 else
434 fuse_reply_err(req, ENOSYS);
435}
436
437static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
438 char *link)
439{
440 if (req->f->op.symlink)
441 req->f->op.symlink(req, link, nodeid, name);
442 else
443 fuse_reply_err(req, ENOSYS);
444}
445
446static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
447 struct fuse_rename_in *arg)
448{
449 char *oldname = PARAM(arg);
450 char *newname = oldname + strlen(oldname) + 1;
451
452 if (req->f->op.rename)
453 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
454 else
455 fuse_reply_err(req, ENOSYS);
456}
457
458static void do_link(fuse_req_t req, fuse_ino_t nodeid,
459 struct fuse_link_in *arg)
460{
461 if (req->f->op.link)
462 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
463 else
464 fuse_reply_err(req, ENOSYS);
465}
466
467static void do_open(fuse_req_t req, fuse_ino_t nodeid,
468 struct fuse_open_in *arg)
469{
470 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000471
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000472 memset(&fi, 0, sizeof(fi));
473 fi.flags = arg->flags;
474
475 if (req->f->op.open)
476 req->f->op.open(req, nodeid, &fi);
477 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000478 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000479}
480
481static void do_read(fuse_req_t req, fuse_ino_t nodeid,
482 struct fuse_read_in *arg)
483{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000484 if (req->f->op.read) {
485 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000486
Miklos Szeredi76c17522005-07-13 14:08:19 +0000487 memset(&fi, 0, sizeof(fi));
488 fi.fh = arg->fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000489 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000490 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000491 fuse_reply_err(req, ENOSYS);
492}
493
494static void do_write(fuse_req_t req, fuse_ino_t nodeid,
495 struct fuse_write_in *arg)
496{
497 struct fuse_file_info fi;
498
499 memset(&fi, 0, sizeof(fi));
500 fi.fh = arg->fh;
501 fi.writepage = arg->write_flags & 1;
502
503 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000504 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
505 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000506 else
507 fuse_reply_err(req, ENOSYS);
508}
509
510static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
511 struct fuse_flush_in *arg)
512{
513 struct fuse_file_info fi;
514
515 memset(&fi, 0, sizeof(fi));
516 fi.fh = arg->fh;
517
518 if (req->f->op.flush)
519 req->f->op.flush(req, nodeid, &fi);
520 else
521 fuse_reply_err(req, ENOSYS);
522}
523
524static void do_release(fuse_req_t req, fuse_ino_t nodeid,
525 struct fuse_release_in *arg)
526{
527 struct fuse_file_info fi;
528
529 memset(&fi, 0, sizeof(fi));
530 fi.flags = arg->flags;
531 fi.fh = arg->fh;
532
533 if (req->f->op.release)
534 req->f->op.release(req, nodeid, &fi);
535 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000536 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000537}
538
539static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000540 struct fuse_fsync_in *inarg)
541{
Miklos Szeredi12744942005-07-11 12:32:31 +0000542 struct fuse_file_info fi;
543
544 memset(&fi, 0, sizeof(fi));
545 fi.fh = inarg->fh;
546
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000547 if (req->f->op.fsync)
548 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
549 else
550 fuse_reply_err(req, ENOSYS);
551}
552
553static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
554 struct fuse_open_in *arg)
555{
556 struct fuse_file_info fi;
557
558 memset(&fi, 0, sizeof(fi));
559 fi.flags = arg->flags;
560
561 if (req->f->op.opendir)
562 req->f->op.opendir(req, nodeid, &fi);
563 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000564 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000565}
566
567static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
568 struct fuse_read_in *arg)
569{
570 struct fuse_file_info fi;
571
572 memset(&fi, 0, sizeof(fi));
573 fi.fh = arg->fh;
574
575 if (req->f->op.readdir)
576 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
577 else
578 fuse_reply_err(req, ENOSYS);
579}
580
581static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
582 struct fuse_release_in *arg)
583{
584 struct fuse_file_info fi;
585
586 memset(&fi, 0, sizeof(fi));
587 fi.flags = arg->flags;
588 fi.fh = arg->fh;
589
590 if (req->f->op.releasedir)
591 req->f->op.releasedir(req, nodeid, &fi);
592 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000593 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000594}
595
596static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
597 struct fuse_fsync_in *inarg)
598{
599 struct fuse_file_info fi;
600
601 memset(&fi, 0, sizeof(fi));
602 fi.fh = inarg->fh;
603
604 if (req->f->op.fsyncdir)
605 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
606 else
607 fuse_reply_err(req, ENOSYS);
608}
609
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000610static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000611{
612 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000613 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000614 else
615 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000616}
617
Miklos Szeredi4331a272005-07-12 14:51:04 +0000618static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000619 struct fuse_setxattr_in *arg)
620{
Miklos Szeredi12744942005-07-11 12:32:31 +0000621 char *name = PARAM(arg);
622 unsigned char *value = name + strlen(name) + 1;
623
Miklos Szeredi4331a272005-07-12 14:51:04 +0000624 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000625 req->f->op.setxattr(req, nodeid, name, value, arg->size,
626 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000627 else
628 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000629}
630
Miklos Szeredi4331a272005-07-12 14:51:04 +0000631static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000632 struct fuse_getxattr_in *arg)
633{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000634 if (req->f->op.getxattr)
635 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000636 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000637 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000638}
639
Miklos Szeredi4331a272005-07-12 14:51:04 +0000640static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000641 struct fuse_getxattr_in *arg)
642{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000643 if (req->f->op.listxattr)
644 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000645 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000646 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000647}
648
Miklos Szeredi4331a272005-07-12 14:51:04 +0000649static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000650{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000651 if (req->f->op.removexattr)
652 req->f->op.removexattr(req, nodeid, name);
653 else
654 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000655}
656
Miklos Szeredi76c17522005-07-13 14:08:19 +0000657static void do_init(struct fuse_ll *f, uint64_t unique,
Miklos Szeredi12744942005-07-11 12:32:31 +0000658 struct fuse_init_in_out *arg)
659{
660 struct fuse_init_in_out outarg;
661
Miklos Szeredi76c17522005-07-13 14:08:19 +0000662 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000663 printf("INIT: %u.%u\n", arg->major, arg->minor);
664 fflush(stdout);
665 }
666 f->got_init = 1;
667 if (f->op.init)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000668 f->userdata = f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000669
Miklos Szeredi76c17522005-07-13 14:08:19 +0000670 f->major = FUSE_KERNEL_VERSION;
671 f->minor = FUSE_KERNEL_MINOR_VERSION;
672
Miklos Szeredi12744942005-07-11 12:32:31 +0000673 memset(&outarg, 0, sizeof(outarg));
674 outarg.major = f->major;
675 outarg.minor = f->minor;
676
Miklos Szeredi76c17522005-07-13 14:08:19 +0000677 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000678 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
679 fflush(stdout);
680 }
681
Miklos Szeredi76c17522005-07-13 14:08:19 +0000682 send_reply(f, unique, 0, &outarg, sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000683}
684
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000685void *fuse_req_userdata(fuse_req_t req)
686{
687 return req->f->userdata;
688}
689
690const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
691{
692 return &req->ctx;
693}
694
Miklos Szeredi12744942005-07-11 12:32:31 +0000695static void free_cmd(struct fuse_cmd *cmd)
696{
697 free(cmd->buf);
698 free(cmd);
699}
700
Miklos Szeredi76c17522005-07-13 14:08:19 +0000701void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
Miklos Szeredi12744942005-07-11 12:32:31 +0000702{
703 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000704 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
705 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000706
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000707 fuse_dec_avail(f);
708
Miklos Szeredi76c17522005-07-13 14:08:19 +0000709 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000710 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
711 in->unique, opname(in->opcode), in->opcode,
712 (unsigned long) in->nodeid, cmd->buflen);
713 fflush(stdout);
714 }
715
Miklos Szeredi76c17522005-07-13 14:08:19 +0000716 if (!f->got_init) {
717 if (in->opcode != FUSE_INIT)
718 send_reply(f, in->unique, -EPROTO, NULL, 0);
719 else
720 do_init(f, in->unique, (struct fuse_init_in_out *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000721 goto out;
722 }
723
Miklos Szeredi76c17522005-07-13 14:08:19 +0000724 if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
Miklos Szeredi12744942005-07-11 12:32:31 +0000725 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
726 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
727 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
728 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
Miklos Szeredi76c17522005-07-13 14:08:19 +0000729 send_reply(f, in->unique, -EACCES, NULL, 0);
Miklos Szeredi12744942005-07-11 12:32:31 +0000730 goto out;
731 }
732
Miklos Szeredi76c17522005-07-13 14:08:19 +0000733 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
734 if (req == NULL) {
735 fprintf(stderr, "fuse: failed to allocate request\n");
736 goto out;
737 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000738
Miklos Szeredi76c17522005-07-13 14:08:19 +0000739 req->f = f;
740 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000741 req->ctx.uid = in->uid;
742 req->ctx.gid = in->gid;
743 req->ctx.pid = in->pid;
Miklos Szeredi12744942005-07-11 12:32:31 +0000744
745 switch (in->opcode) {
746 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000747 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000748 break;
749
Miklos Szeredi76c17522005-07-13 14:08:19 +0000750 case FUSE_FORGET:
751 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000752 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000753
Miklos Szeredi12744942005-07-11 12:32:31 +0000754 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000755 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000756 break;
757
758 case FUSE_SETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000759 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000760 break;
761
762 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000763 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000764 break;
765
766 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000767 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000768 break;
769
770 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000771 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000772 break;
773
774 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000775 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000776 break;
777
778 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000779 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000780 break;
781
782 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000783 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000784 ((char *) inarg) + strlen((char *) inarg) + 1);
785 break;
786
787 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000788 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000789 break;
790
791 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000792 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000793 break;
794
795 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000796 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000797 break;
798
799 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000800 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000801 break;
802
803 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000804 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000805 break;
806
807 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000808 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000809 break;
810
811 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000812 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000813 break;
814
815 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000816 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000817 break;
818
819 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000820 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000821 break;
822
823 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000824 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000825 break;
826
827 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000828 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000829 break;
830
831 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000832 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000833 break;
834
835 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000836 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000837 break;
838
839 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000840 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000841 break;
842
843 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000844 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000845 break;
846
847 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000848 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000849 break;
850
851 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000852 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000853 break;
854
855 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000856 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000857 }
858
859 out:
860 free_cmd(cmd);
861}
862
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000863void fuse_ll_exit(struct fuse_ll *f)
864{
865 f->exited = 1;
866}
867
Miklos Szeredi76c17522005-07-13 14:08:19 +0000868int fuse_ll_exited(struct fuse_ll* f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000869{
870 return f->exited;
871}
872
Miklos Szeredi76c17522005-07-13 14:08:19 +0000873struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000874{
875 ssize_t res;
876 struct fuse_cmd *cmd;
877 struct fuse_in_header *in;
878 void *inarg;
879
880 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
881 if (cmd == NULL) {
882 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
883 return NULL;
884 }
885 cmd->buf = (char *) malloc(FUSE_MAX_IN);
886 if (cmd->buf == NULL) {
887 fprintf(stderr, "fuse: failed to allocate read buffer\n");
888 free(cmd);
889 return NULL;
890 }
891 in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000892 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi12744942005-07-11 12:32:31 +0000893
894 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
895 if (res == -1) {
896 free_cmd(cmd);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000897 if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT)
Miklos Szeredi12744942005-07-11 12:32:31 +0000898 return NULL;
899
900 /* ENODEV means we got unmounted, so we silenty return failure */
901 if (errno != ENODEV) {
902 /* BAD... This will happen again */
903 perror("fuse: reading device");
904 }
905
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000906 fuse_ll_exit(f);
Miklos Szeredi12744942005-07-11 12:32:31 +0000907 return NULL;
908 }
Miklos Szeredi76c17522005-07-13 14:08:19 +0000909 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000910 free_cmd(cmd);
911 /* Cannot happen */
912 fprintf(stderr, "short read on fuse device\n");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000913 fuse_ll_exit(f);
Miklos Szeredi12744942005-07-11 12:32:31 +0000914 return NULL;
915 }
916 cmd->buflen = res;
917
Miklos Szeredi12744942005-07-11 12:32:31 +0000918
919 return cmd;
920}
921
Miklos Szeredi76c17522005-07-13 14:08:19 +0000922int fuse_ll_loop(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000923{
924 if (f == NULL)
925 return -1;
926
927 while (1) {
928 struct fuse_cmd *cmd;
929
Miklos Szeredi76c17522005-07-13 14:08:19 +0000930 if (fuse_ll_exited(f))
Miklos Szeredi12744942005-07-11 12:32:31 +0000931 break;
932
Miklos Szeredi76c17522005-07-13 14:08:19 +0000933 cmd = fuse_ll_read_cmd(f);
Miklos Szeredi12744942005-07-11 12:32:31 +0000934 if (cmd == NULL)
935 continue;
936
Miklos Szeredi76c17522005-07-13 14:08:19 +0000937 fuse_ll_process_cmd(f, cmd);
Miklos Szeredi12744942005-07-11 12:32:31 +0000938 }
939 f->exited = 0;
940 return 0;
941}
942
Miklos Szeredi76c17522005-07-13 14:08:19 +0000943int fuse_ll_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +0000944{
945 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredi76c17522005-07-13 14:08:19 +0000946 strcmp(opt, "allow_root") == 0)
Miklos Szeredi12744942005-07-11 12:32:31 +0000947 return 1;
948 else
949 return 0;
950}
951
Miklos Szeredi76c17522005-07-13 14:08:19 +0000952static int parse_ll_opts(struct fuse_ll *f, const char *opts)
Miklos Szeredi12744942005-07-11 12:32:31 +0000953{
954 if (opts) {
955 char *xopts = strdup(opts);
956 char *s = xopts;
957 char *opt;
958
959 if (xopts == NULL) {
960 fprintf(stderr, "fuse: memory allocation failed\n");
961 return -1;
962 }
963
964 while((opt = strsep(&s, ","))) {
965 if (strcmp(opt, "debug") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000966 f->debug = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000967 else if (strcmp(opt, "allow_root") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000968 f->allow_root = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000969 else
970 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
971 }
972 free(xopts);
973 }
974 return 0;
975}
976
Miklos Szeredi76c17522005-07-13 14:08:19 +0000977struct fuse_ll *fuse_ll_new(int fd, const char *opts,
978 const struct fuse_ll_operations *op,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000979 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +0000980{
981 struct fuse_ll *f;
982
Miklos Szeredi76c17522005-07-13 14:08:19 +0000983 if (sizeof(struct fuse_ll_operations) < op_size) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000984 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi76c17522005-07-13 14:08:19 +0000985 op_size = sizeof(struct fuse_ll_operations);
Miklos Szeredi12744942005-07-11 12:32:31 +0000986 }
987
988 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
989 if (f == NULL) {
990 fprintf(stderr, "fuse: failed to allocate fuse object\n");
991 goto out;
992 }
993
Miklos Szeredi76c17522005-07-13 14:08:19 +0000994 if (parse_ll_opts(f, opts) == -1)
Miklos Szeredi12744942005-07-11 12:32:31 +0000995 goto out_free;
996
997 f->fd = fd;
998 memcpy(&f->op, op, op_size);
999 f->exited = 0;
1000 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001001 f->userdata = userdata;
1002 mutex_init(&f->worker_lock);
Miklos Szeredi12744942005-07-11 12:32:31 +00001003
1004 return f;
1005
1006 out_free:
1007 free(f);
1008 out:
1009 return NULL;
1010}
1011
Miklos Szeredi76c17522005-07-13 14:08:19 +00001012void fuse_ll_destroy(struct fuse_ll *f)
1013{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001014 if (f->op.destroy)
1015 f->op.destroy(f->userdata);
1016
1017 pthread_mutex_destroy(&f->worker_lock);
Miklos Szeredi76c17522005-07-13 14:08:19 +00001018 free(f);
1019}
Miklos Szeredi12744942005-07-11 12:32:31 +00001020