blob: 7f92d047ee1345259381d66af365976e40ef784b [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";
Miklos Szeredie3b83092005-07-22 17:24:30 +000081 case FUSE_GETLK: return "GETLK";
82 case FUSE_SETLK: return "SETLK";
83 case FUSE_SETLKW: return "SETLKW";
Miklos Szeredi12744942005-07-11 12:32:31 +000084 default: return "???";
85 }
86}
87
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000088static inline void fuse_dec_avail(struct fuse_ll *f)
89{
90 pthread_mutex_lock(&f->worker_lock);
91 f->numavail --;
92 pthread_mutex_unlock(&f->worker_lock);
93}
94
95static inline void fuse_inc_avail(struct fuse_ll *f)
96{
97 pthread_mutex_lock(&f->worker_lock);
98 f->numavail ++;
99 pthread_mutex_unlock(&f->worker_lock);
100}
101
Miklos Szeredi76c17522005-07-13 14:08:19 +0000102static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +0000103{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000104 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +0000105 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +0000106 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000107 attr->uid = stbuf->st_uid;
108 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +0000109 attr->rdev = stbuf->st_rdev;
110 attr->size = stbuf->st_size;
111 attr->blocks = stbuf->st_blocks;
112 attr->atime = stbuf->st_atime;
113 attr->mtime = stbuf->st_mtime;
114 attr->ctime = stbuf->st_ctime;
115#ifdef HAVE_STRUCT_STAT_ST_ATIM
116 attr->atimensec = stbuf->st_atim.tv_nsec;
117 attr->mtimensec = stbuf->st_mtim.tv_nsec;
118 attr->ctimensec = stbuf->st_ctim.tv_nsec;
119#endif
120}
121
Miklos Szeredi76c17522005-07-13 14:08:19 +0000122static void convert_attr(const struct fuse_attr *attr, struct stat *stbuf)
123{
124 stbuf->st_mode = attr->mode;
125 stbuf->st_uid = attr->uid;
126 stbuf->st_gid = attr->gid;
127 stbuf->st_size = attr->size;
128 stbuf->st_atime = attr->atime;
129 stbuf->st_mtime = attr->mtime;
130 stbuf->st_ctime = attr->ctime;
131#ifdef HAVE_STRUCT_STAT_ST_ATIM
132 stbuf->st_atim.tv_nsec = attr->atimensec;
133 stbuf->st_mtim.tv_nsec = attr->mtimensec;
134 stbuf->st_ctim.tv_nsec = attr->ctimensec;
135#endif
136}
137
Miklos Szeredie3b83092005-07-22 17:24:30 +0000138static void convert_file_lock(const struct fuse_file_lock *ffl,
139 struct fuse_lock_param *lk)
140{
141 lk->type = ffl->type;
142 lk->start = ffl->start;
143 lk->end = ffl->end;
144 lk->owner = ffl->owner;
145 lk->pid = ffl->pid;
146}
147
148static void convert_lock_param(const struct fuse_lock_param *lk,
149 struct fuse_file_lock *ffl)
150{
151 ffl->type = lk->type;
152 ffl->start = lk->start;
153 ffl->end = lk->end;
154 ffl->owner = lk->owner;
155 ffl->pid = lk->pid;
156}
157
Miklos Szeredi12744942005-07-11 12:32:31 +0000158static size_t iov_length(const struct iovec *iov, size_t count)
159{
160 size_t seg;
161 size_t ret = 0;
162
163 for (seg = 0; seg < count; seg++)
164 ret += iov[seg].iov_len;
165 return ret;
166}
167
168static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
169 size_t count)
170{
171 int res;
172 unsigned outsize = iov_length(iov, count);
173 struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
174 out->len = outsize;
175
Miklos Szeredi76c17522005-07-13 14:08:19 +0000176 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000177 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
178 out->unique, out->error, strerror(-out->error), outsize);
179 fflush(stdout);
180 }
181
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000182 /* This needs to be done before the reply, otherwise the scheduler
183 could play tricks with us, and only let the counter be
184 increased long after the operation is done */
185 fuse_inc_avail(f);
186
Miklos Szeredi12744942005-07-11 12:32:31 +0000187 res = writev(f->fd, iov, count);
188 if (res == -1) {
189 /* ENOENT means the operation was interrupted */
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000190 if (!fuse_ll_exited(f) && errno != ENOENT)
Miklos Szeredi12744942005-07-11 12:32:31 +0000191 perror("fuse: writing device");
192 return -errno;
193 }
194 return 0;
195}
196
Miklos Szeredi76c17522005-07-13 14:08:19 +0000197static int send_reply(struct fuse_ll *f, uint64_t unique, int error,
198 const void *arg, size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000199{
200 struct fuse_out_header out;
201 struct iovec iov[2];
202 size_t count;
203
204 if (error <= -1000 || error > 0) {
205 fprintf(stderr, "fuse: bad error value: %i\n", error);
206 error = -ERANGE;
207 }
208
Miklos Szeredi76c17522005-07-13 14:08:19 +0000209 out.unique = unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000210 out.error = error;
211 count = 1;
212 iov[0].iov_base = &out;
213 iov[0].iov_len = sizeof(struct fuse_out_header);
214 if (argsize && !error) {
215 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000216 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000217 iov[1].iov_len = argsize;
218 }
219 return send_reply_raw(f, iov, count);
220}
221
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000222size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000223{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000224 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000225}
226
Miklos Szeredi76c17522005-07-13 14:08:19 +0000227char *fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
228 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000229{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000230 unsigned namelen = strlen(name);
231 unsigned entlen = FUSE_NAME_OFFSET + namelen;
232 unsigned entsize = fuse_dirent_size(namelen);
233 unsigned padlen = entsize - entlen;
234 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000235
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000236 dirent->ino = stat->st_ino;
237 dirent->off = off;
238 dirent->namelen = namelen;
239 dirent->type = (stat->st_mode & 0170000) >> 12;
240 strncpy(dirent->name, name, namelen);
241 if (padlen)
242 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000243
Miklos Szeredi76c17522005-07-13 14:08:19 +0000244 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000245}
246
Miklos Szeredi76c17522005-07-13 14:08:19 +0000247static void convert_statfs(const struct statfs *statfs,
248 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000249{
250 kstatfs->bsize = statfs->f_bsize;
251 kstatfs->blocks = statfs->f_blocks;
252 kstatfs->bfree = statfs->f_bfree;
253 kstatfs->bavail = statfs->f_bavail;
254 kstatfs->files = statfs->f_files;
255 kstatfs->ffree = statfs->f_ffree;
256 kstatfs->namelen = statfs->f_namelen;
257}
258
Miklos Szeredi76c17522005-07-13 14:08:19 +0000259static void free_req(fuse_req_t req)
260{
261 free(req);
262}
263
264static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize)
265{
266 int res = send_reply(req->f, req->unique, 0, arg, argsize);
267 free_req(req);
268 return res;
269}
270
271int fuse_reply_err(fuse_req_t req, int err)
272{
273 int res = send_reply(req->f, req->unique, -err, NULL, 0);
274 free_req(req);
275 return res;
276}
277
278int fuse_reply_none(fuse_req_t req)
279{
280 free_req(req);
281 return 0;
282}
283
284static unsigned long calc_timeout_sec(double t)
285{
286 if (t > (double) ULONG_MAX)
287 return ULONG_MAX;
288 else if (t < 0.0)
289 return 0;
290 else
291 return (unsigned long) t;
292}
293
294static unsigned int calc_timeout_nsec(double t)
295{
296 double f = t - (double) calc_timeout_sec(t);
297 if (f < 0.0)
298 return 0;
299 else if (f >= 0.999999999)
300 return 999999999;
301 else
302 return (unsigned int) (f * 1.0e9);
303}
304
305int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
306{
307 struct fuse_entry_out arg;
308
309 memset(&arg, 0, sizeof(arg));
310 arg.nodeid = e->ino;
311 arg.generation = e->generation;
312 arg.entry_valid = calc_timeout_sec(e->entry_timeout);
313 arg.entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
314 arg.attr_valid = calc_timeout_sec(e->attr_timeout);
315 arg.attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
316 convert_stat(&e->attr, &arg.attr);
317
318 return send_reply_req(req, &arg, sizeof(arg));
319}
320
321int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
322 double attr_timeout)
323{
324 struct fuse_attr_out arg;
325
326 memset(&arg, 0, sizeof(arg));
327 arg.attr_valid = calc_timeout_sec(attr_timeout);
328 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
329 convert_stat(attr, &arg.attr);
330
331 return send_reply_req(req, &arg, sizeof(arg));
332}
333
334int fuse_reply_readlink(fuse_req_t req, const char *link)
335{
336 return send_reply_req(req, link, strlen(link));
337}
338
339int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
340{
341 struct fuse_open_out arg;
342
343 memset(&arg, 0, sizeof(arg));
344 arg.fh = f->fh;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000345
Miklos Szeredi76c17522005-07-13 14:08:19 +0000346 return send_reply_req(req, &arg, sizeof(arg));
347}
348
349int fuse_reply_write(fuse_req_t req, size_t count)
350{
351 struct fuse_write_out arg;
352
353 memset(&arg, 0, sizeof(arg));
354 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000355
Miklos Szeredi76c17522005-07-13 14:08:19 +0000356 return send_reply_req(req, &arg, sizeof(arg));
357}
358
359int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
360{
361 return send_reply_req(req, buf, size);
362}
363
364int fuse_reply_statfs(fuse_req_t req, const struct statfs *statfs)
365{
366 struct fuse_statfs_out arg;
367
368 memset(&arg, 0, sizeof(arg));
369 convert_statfs(statfs, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000370
Miklos Szeredi76c17522005-07-13 14:08:19 +0000371 return send_reply_req(req, &arg, sizeof(arg));
372}
373
374int fuse_reply_xattr(fuse_req_t req, size_t count)
375{
376 struct fuse_getxattr_out arg;
377
378 memset(&arg, 0, sizeof(arg));
379 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000380
Miklos Szeredi76c17522005-07-13 14:08:19 +0000381 return send_reply_req(req, &arg, sizeof(arg));
382}
383
Miklos Szeredie3b83092005-07-22 17:24:30 +0000384int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk)
385{
386 struct fuse_lk_in_out arg;
387
388 memset(&arg, 0, sizeof(arg));
389 convert_lock_param(lk, &arg.lk);
390
391 return send_reply_req(req, &arg, sizeof(arg));
392}
393
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000394static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000395{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000396 if (req->f->op.lookup)
397 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000398 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000399 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000400}
401
Miklos Szeredi76c17522005-07-13 14:08:19 +0000402static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
403 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000404{
405 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000406 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000407}
408
409static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
410{
411 if (req->f->op.getattr)
412 req->f->op.getattr(req, nodeid);
413 else
414 fuse_reply_err(req, ENOSYS);
415}
416
417static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
418 struct fuse_setattr_in *arg)
419{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000420 if (req->f->op.setattr) {
421 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000422 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000423 convert_attr(&arg->attr, &stbuf);
424 req->f->op.setattr(req, nodeid, &stbuf, arg->valid);
425 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000426 fuse_reply_err(req, ENOSYS);
427}
428
429static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
430{
431 if (req->f->op.readlink)
432 req->f->op.readlink(req, nodeid);
433 else
434 fuse_reply_err(req, ENOSYS);
435}
436
437static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
438 struct fuse_mknod_in *arg)
439{
440 if (req->f->op.mknod)
441 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
442 else
443 fuse_reply_err(req, ENOSYS);
444}
445
446static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
447 struct fuse_mkdir_in *arg)
448{
449 if (req->f->op.mkdir)
450 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
451 else
452 fuse_reply_err(req, ENOSYS);
453}
454
455static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
456{
457 if (req->f->op.unlink)
458 req->f->op.unlink(req, nodeid, name);
459 else
460 fuse_reply_err(req, ENOSYS);
461}
462
463static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
464{
465 if (req->f->op.rmdir)
466 req->f->op.rmdir(req, nodeid, name);
467 else
468 fuse_reply_err(req, ENOSYS);
469}
470
471static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
472 char *link)
473{
474 if (req->f->op.symlink)
475 req->f->op.symlink(req, link, nodeid, name);
476 else
477 fuse_reply_err(req, ENOSYS);
478}
479
480static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
481 struct fuse_rename_in *arg)
482{
483 char *oldname = PARAM(arg);
484 char *newname = oldname + strlen(oldname) + 1;
485
486 if (req->f->op.rename)
487 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
488 else
489 fuse_reply_err(req, ENOSYS);
490}
491
492static void do_link(fuse_req_t req, fuse_ino_t nodeid,
493 struct fuse_link_in *arg)
494{
495 if (req->f->op.link)
496 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
497 else
498 fuse_reply_err(req, ENOSYS);
499}
500
501static void do_open(fuse_req_t req, fuse_ino_t nodeid,
502 struct fuse_open_in *arg)
503{
504 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000505
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000506 memset(&fi, 0, sizeof(fi));
507 fi.flags = arg->flags;
508
509 if (req->f->op.open)
510 req->f->op.open(req, nodeid, &fi);
511 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000512 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000513}
514
515static void do_read(fuse_req_t req, fuse_ino_t nodeid,
516 struct fuse_read_in *arg)
517{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000518 if (req->f->op.read) {
519 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000520
Miklos Szeredi76c17522005-07-13 14:08:19 +0000521 memset(&fi, 0, sizeof(fi));
522 fi.fh = arg->fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000523 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000524 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000525 fuse_reply_err(req, ENOSYS);
526}
527
528static void do_write(fuse_req_t req, fuse_ino_t nodeid,
529 struct fuse_write_in *arg)
530{
531 struct fuse_file_info fi;
532
533 memset(&fi, 0, sizeof(fi));
534 fi.fh = arg->fh;
535 fi.writepage = arg->write_flags & 1;
536
537 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000538 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
539 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000540 else
541 fuse_reply_err(req, ENOSYS);
542}
543
544static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
545 struct fuse_flush_in *arg)
546{
547 struct fuse_file_info fi;
548
549 memset(&fi, 0, sizeof(fi));
550 fi.fh = arg->fh;
551
552 if (req->f->op.flush)
553 req->f->op.flush(req, nodeid, &fi);
554 else
555 fuse_reply_err(req, ENOSYS);
556}
557
558static void do_release(fuse_req_t req, fuse_ino_t nodeid,
559 struct fuse_release_in *arg)
560{
561 struct fuse_file_info fi;
562
563 memset(&fi, 0, sizeof(fi));
564 fi.flags = arg->flags;
565 fi.fh = arg->fh;
566
567 if (req->f->op.release)
568 req->f->op.release(req, nodeid, &fi);
569 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000570 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000571}
572
573static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000574 struct fuse_fsync_in *inarg)
575{
Miklos Szeredi12744942005-07-11 12:32:31 +0000576 struct fuse_file_info fi;
577
578 memset(&fi, 0, sizeof(fi));
579 fi.fh = inarg->fh;
580
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000581 if (req->f->op.fsync)
582 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
583 else
584 fuse_reply_err(req, ENOSYS);
585}
586
587static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
588 struct fuse_open_in *arg)
589{
590 struct fuse_file_info fi;
591
592 memset(&fi, 0, sizeof(fi));
593 fi.flags = arg->flags;
594
595 if (req->f->op.opendir)
596 req->f->op.opendir(req, nodeid, &fi);
597 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000598 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000599}
600
601static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
602 struct fuse_read_in *arg)
603{
604 struct fuse_file_info fi;
605
606 memset(&fi, 0, sizeof(fi));
607 fi.fh = arg->fh;
608
609 if (req->f->op.readdir)
610 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
611 else
612 fuse_reply_err(req, ENOSYS);
613}
614
615static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
616 struct fuse_release_in *arg)
617{
618 struct fuse_file_info fi;
619
620 memset(&fi, 0, sizeof(fi));
621 fi.flags = arg->flags;
622 fi.fh = arg->fh;
623
624 if (req->f->op.releasedir)
625 req->f->op.releasedir(req, nodeid, &fi);
626 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000627 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000628}
629
630static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
631 struct fuse_fsync_in *inarg)
632{
633 struct fuse_file_info fi;
634
635 memset(&fi, 0, sizeof(fi));
636 fi.fh = inarg->fh;
637
638 if (req->f->op.fsyncdir)
639 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
640 else
641 fuse_reply_err(req, ENOSYS);
642}
643
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000644static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000645{
646 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000647 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000648 else
649 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000650}
651
Miklos Szeredi4331a272005-07-12 14:51:04 +0000652static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000653 struct fuse_setxattr_in *arg)
654{
Miklos Szeredi12744942005-07-11 12:32:31 +0000655 char *name = PARAM(arg);
656 unsigned char *value = name + strlen(name) + 1;
657
Miklos Szeredi4331a272005-07-12 14:51:04 +0000658 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000659 req->f->op.setxattr(req, nodeid, name, value, arg->size,
660 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000661 else
662 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000663}
664
Miklos Szeredi4331a272005-07-12 14:51:04 +0000665static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000666 struct fuse_getxattr_in *arg)
667{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000668 if (req->f->op.getxattr)
669 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000670 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000671 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000672}
673
Miklos Szeredi4331a272005-07-12 14:51:04 +0000674static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000675 struct fuse_getxattr_in *arg)
676{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000677 if (req->f->op.listxattr)
678 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000679 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000680 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000681}
682
Miklos Szeredi4331a272005-07-12 14:51:04 +0000683static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000684{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000685 if (req->f->op.removexattr)
686 req->f->op.removexattr(req, nodeid, name);
687 else
688 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000689}
690
Miklos Szeredie3b83092005-07-22 17:24:30 +0000691static void do_getlk(fuse_req_t req, fuse_ino_t nodeid,
692 struct fuse_lk_in_out *arg)
693{
694 if (req->f->op.getlk) {
695 struct fuse_lock_param lk;
696
697 memset(&lk, 0, sizeof(lk));
698 convert_file_lock(&arg->lk, &lk);
699 req->f->op.getlk(req, nodeid, &lk);
700 } else
701 fuse_reply_err(req, ENOSYS);
702}
703
704static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, int sleep,
705 struct fuse_lk_in_out *arg)
706{
707 if (req->f->op.setlk) {
708 struct fuse_lock_param lk;
709
710 memset(&lk, 0, sizeof(lk));
711 convert_file_lock(&arg->lk, &lk);
712 req->f->op.setlk(req, nodeid, sleep, &lk);
713 } else
714 fuse_reply_err(req, ENOSYS);
715}
716
Miklos Szeredi76c17522005-07-13 14:08:19 +0000717static void do_init(struct fuse_ll *f, uint64_t unique,
Miklos Szeredi12744942005-07-11 12:32:31 +0000718 struct fuse_init_in_out *arg)
719{
720 struct fuse_init_in_out outarg;
721
Miklos Szeredi76c17522005-07-13 14:08:19 +0000722 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000723 printf("INIT: %u.%u\n", arg->major, arg->minor);
724 fflush(stdout);
725 }
726 f->got_init = 1;
727 if (f->op.init)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000728 f->userdata = f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000729
Miklos Szeredi76c17522005-07-13 14:08:19 +0000730 f->major = FUSE_KERNEL_VERSION;
731 f->minor = FUSE_KERNEL_MINOR_VERSION;
732
Miklos Szeredi12744942005-07-11 12:32:31 +0000733 memset(&outarg, 0, sizeof(outarg));
734 outarg.major = f->major;
735 outarg.minor = f->minor;
736
Miklos Szeredi76c17522005-07-13 14:08:19 +0000737 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000738 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
739 fflush(stdout);
740 }
741
Miklos Szeredi76c17522005-07-13 14:08:19 +0000742 send_reply(f, unique, 0, &outarg, sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000743}
744
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000745void *fuse_req_userdata(fuse_req_t req)
746{
747 return req->f->userdata;
748}
749
750const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
751{
752 return &req->ctx;
753}
754
Miklos Szeredi12744942005-07-11 12:32:31 +0000755static void free_cmd(struct fuse_cmd *cmd)
756{
757 free(cmd->buf);
758 free(cmd);
759}
760
Miklos Szeredi76c17522005-07-13 14:08:19 +0000761void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
Miklos Szeredi12744942005-07-11 12:32:31 +0000762{
763 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000764 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
765 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000766
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000767 fuse_dec_avail(f);
768
Miklos Szeredi76c17522005-07-13 14:08:19 +0000769 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000770 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
771 in->unique, opname(in->opcode), in->opcode,
772 (unsigned long) in->nodeid, cmd->buflen);
773 fflush(stdout);
774 }
775
Miklos Szeredi76c17522005-07-13 14:08:19 +0000776 if (!f->got_init) {
777 if (in->opcode != FUSE_INIT)
778 send_reply(f, in->unique, -EPROTO, NULL, 0);
779 else
780 do_init(f, in->unique, (struct fuse_init_in_out *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000781 goto out;
782 }
783
Miklos Szeredi76c17522005-07-13 14:08:19 +0000784 if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
Miklos Szeredi12744942005-07-11 12:32:31 +0000785 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
786 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
787 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
788 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
Miklos Szeredi76c17522005-07-13 14:08:19 +0000789 send_reply(f, in->unique, -EACCES, NULL, 0);
Miklos Szeredi12744942005-07-11 12:32:31 +0000790 goto out;
791 }
792
Miklos Szeredi76c17522005-07-13 14:08:19 +0000793 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
794 if (req == NULL) {
795 fprintf(stderr, "fuse: failed to allocate request\n");
796 goto out;
797 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000798
Miklos Szeredi76c17522005-07-13 14:08:19 +0000799 req->f = f;
800 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000801 req->ctx.uid = in->uid;
802 req->ctx.gid = in->gid;
803 req->ctx.pid = in->pid;
Miklos Szeredi12744942005-07-11 12:32:31 +0000804
805 switch (in->opcode) {
806 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000807 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000808 break;
809
Miklos Szeredi76c17522005-07-13 14:08:19 +0000810 case FUSE_FORGET:
811 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000812 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000813
Miklos Szeredi12744942005-07-11 12:32:31 +0000814 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000815 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000816 break;
817
818 case FUSE_SETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000819 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000820 break;
821
822 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000823 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000824 break;
825
826 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000827 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000828 break;
829
830 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000831 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000832 break;
833
834 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000835 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000836 break;
837
838 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000839 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000840 break;
841
842 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000843 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000844 ((char *) inarg) + strlen((char *) inarg) + 1);
845 break;
846
847 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000848 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000849 break;
850
851 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000852 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000853 break;
854
855 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000856 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000857 break;
858
859 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000860 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000861 break;
862
863 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000864 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000865 break;
866
867 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000868 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000869 break;
870
871 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000872 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000873 break;
874
875 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000876 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000877 break;
878
879 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000880 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000881 break;
882
883 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000884 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000885 break;
886
887 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000888 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000889 break;
890
891 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000892 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000893 break;
894
895 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000896 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000897 break;
898
899 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000900 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000901 break;
902
903 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000904 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000905 break;
906
907 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000908 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000909 break;
910
911 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000912 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000913 break;
914
Miklos Szeredie3b83092005-07-22 17:24:30 +0000915 case FUSE_GETLK:
916 do_getlk(req, in->nodeid, (struct fuse_lk_in_out *) inarg);
917 break;
918
919 case FUSE_SETLK:
920 do_setlk(req, in->nodeid, 0, (struct fuse_lk_in_out *) inarg);
921 break;
922
923 case FUSE_SETLKW:
924 do_setlk(req, in->nodeid, 1, (struct fuse_lk_in_out *) inarg);
925 break;
926
Miklos Szeredi12744942005-07-11 12:32:31 +0000927 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000928 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000929 }
930
931 out:
932 free_cmd(cmd);
933}
934
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000935void fuse_ll_exit(struct fuse_ll *f)
936{
937 f->exited = 1;
938}
939
Miklos Szeredi76c17522005-07-13 14:08:19 +0000940int fuse_ll_exited(struct fuse_ll* f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000941{
942 return f->exited;
943}
944
Miklos Szeredi76c17522005-07-13 14:08:19 +0000945struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000946{
947 ssize_t res;
948 struct fuse_cmd *cmd;
949 struct fuse_in_header *in;
950 void *inarg;
951
952 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
953 if (cmd == NULL) {
954 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
955 return NULL;
956 }
957 cmd->buf = (char *) malloc(FUSE_MAX_IN);
958 if (cmd->buf == NULL) {
959 fprintf(stderr, "fuse: failed to allocate read buffer\n");
960 free(cmd);
961 return NULL;
962 }
963 in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000964 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi12744942005-07-11 12:32:31 +0000965
966 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
967 if (res == -1) {
968 free_cmd(cmd);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000969 if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT)
Miklos Szeredi12744942005-07-11 12:32:31 +0000970 return NULL;
971
972 /* ENODEV means we got unmounted, so we silenty return failure */
973 if (errno != ENODEV) {
974 /* BAD... This will happen again */
975 perror("fuse: reading device");
976 }
977
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000978 fuse_ll_exit(f);
Miklos Szeredi12744942005-07-11 12:32:31 +0000979 return NULL;
980 }
Miklos Szeredi76c17522005-07-13 14:08:19 +0000981 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000982 free_cmd(cmd);
983 /* Cannot happen */
984 fprintf(stderr, "short read on fuse device\n");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000985 fuse_ll_exit(f);
Miklos Szeredi12744942005-07-11 12:32:31 +0000986 return NULL;
987 }
988 cmd->buflen = res;
989
Miklos Szeredi12744942005-07-11 12:32:31 +0000990
991 return cmd;
992}
993
Miklos Szeredi76c17522005-07-13 14:08:19 +0000994int fuse_ll_loop(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000995{
996 if (f == NULL)
997 return -1;
998
999 while (1) {
1000 struct fuse_cmd *cmd;
1001
Miklos Szeredi76c17522005-07-13 14:08:19 +00001002 if (fuse_ll_exited(f))
Miklos Szeredi12744942005-07-11 12:32:31 +00001003 break;
1004
Miklos Szeredi76c17522005-07-13 14:08:19 +00001005 cmd = fuse_ll_read_cmd(f);
Miklos Szeredi12744942005-07-11 12:32:31 +00001006 if (cmd == NULL)
1007 continue;
1008
Miklos Szeredi76c17522005-07-13 14:08:19 +00001009 fuse_ll_process_cmd(f, cmd);
Miklos Szeredi12744942005-07-11 12:32:31 +00001010 }
1011 f->exited = 0;
1012 return 0;
1013}
1014
Miklos Szeredi76c17522005-07-13 14:08:19 +00001015int fuse_ll_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +00001016{
1017 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredi76c17522005-07-13 14:08:19 +00001018 strcmp(opt, "allow_root") == 0)
Miklos Szeredi12744942005-07-11 12:32:31 +00001019 return 1;
1020 else
1021 return 0;
1022}
1023
Miklos Szeredi76c17522005-07-13 14:08:19 +00001024static int parse_ll_opts(struct fuse_ll *f, const char *opts)
Miklos Szeredi12744942005-07-11 12:32:31 +00001025{
1026 if (opts) {
1027 char *xopts = strdup(opts);
1028 char *s = xopts;
1029 char *opt;
1030
1031 if (xopts == NULL) {
1032 fprintf(stderr, "fuse: memory allocation failed\n");
1033 return -1;
1034 }
1035
1036 while((opt = strsep(&s, ","))) {
1037 if (strcmp(opt, "debug") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +00001038 f->debug = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +00001039 else if (strcmp(opt, "allow_root") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +00001040 f->allow_root = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +00001041 else
1042 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1043 }
1044 free(xopts);
1045 }
1046 return 0;
1047}
1048
Miklos Szeredi76c17522005-07-13 14:08:19 +00001049struct fuse_ll *fuse_ll_new(int fd, const char *opts,
1050 const struct fuse_ll_operations *op,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001051 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +00001052{
1053 struct fuse_ll *f;
1054
Miklos Szeredi76c17522005-07-13 14:08:19 +00001055 if (sizeof(struct fuse_ll_operations) < op_size) {
Miklos Szeredi12744942005-07-11 12:32:31 +00001056 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi76c17522005-07-13 14:08:19 +00001057 op_size = sizeof(struct fuse_ll_operations);
Miklos Szeredi12744942005-07-11 12:32:31 +00001058 }
1059
1060 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
1061 if (f == NULL) {
1062 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1063 goto out;
1064 }
1065
Miklos Szeredi76c17522005-07-13 14:08:19 +00001066 if (parse_ll_opts(f, opts) == -1)
Miklos Szeredi12744942005-07-11 12:32:31 +00001067 goto out_free;
1068
1069 f->fd = fd;
1070 memcpy(&f->op, op, op_size);
1071 f->exited = 0;
1072 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001073 f->userdata = userdata;
1074 mutex_init(&f->worker_lock);
Miklos Szeredi12744942005-07-11 12:32:31 +00001075
1076 return f;
1077
1078 out_free:
1079 free(f);
1080 out:
1081 return NULL;
1082}
1083
Miklos Szeredi76c17522005-07-13 14:08:19 +00001084void fuse_ll_destroy(struct fuse_ll *f)
1085{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001086 if (f->op.destroy)
1087 f->op.destroy(f->userdata);
1088
1089 pthread_mutex_destroy(&f->worker_lock);
Miklos Szeredi76c17522005-07-13 14:08:19 +00001090 free(f);
1091}
Miklos Szeredi12744942005-07-11 12:32:31 +00001092