blob: fce1d6dcd8401934167dc975d2d4ec02cebf5ed4 [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 Szeredi7b28eae2005-08-01 12:48:30 +000084 case FUSE_ACCESS: return "ACCESS";
Miklos Szeredi12744942005-07-11 12:32:31 +000085 default: return "???";
86 }
87}
88
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000089static inline void fuse_dec_avail(struct fuse_ll *f)
90{
91 pthread_mutex_lock(&f->worker_lock);
92 f->numavail --;
93 pthread_mutex_unlock(&f->worker_lock);
94}
95
96static inline void fuse_inc_avail(struct fuse_ll *f)
97{
98 pthread_mutex_lock(&f->worker_lock);
99 f->numavail ++;
100 pthread_mutex_unlock(&f->worker_lock);
101}
102
Miklos Szeredi76c17522005-07-13 14:08:19 +0000103static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +0000104{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000105 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +0000106 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +0000107 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000108 attr->uid = stbuf->st_uid;
109 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +0000110 attr->rdev = stbuf->st_rdev;
111 attr->size = stbuf->st_size;
112 attr->blocks = stbuf->st_blocks;
113 attr->atime = stbuf->st_atime;
114 attr->mtime = stbuf->st_mtime;
115 attr->ctime = stbuf->st_ctime;
116#ifdef HAVE_STRUCT_STAT_ST_ATIM
117 attr->atimensec = stbuf->st_atim.tv_nsec;
118 attr->mtimensec = stbuf->st_mtim.tv_nsec;
119 attr->ctimensec = stbuf->st_ctim.tv_nsec;
120#endif
121}
122
Miklos Szeredi76c17522005-07-13 14:08:19 +0000123static void convert_attr(const struct fuse_attr *attr, struct stat *stbuf)
124{
125 stbuf->st_mode = attr->mode;
126 stbuf->st_uid = attr->uid;
127 stbuf->st_gid = attr->gid;
128 stbuf->st_size = attr->size;
129 stbuf->st_atime = attr->atime;
130 stbuf->st_mtime = attr->mtime;
131 stbuf->st_ctime = attr->ctime;
132#ifdef HAVE_STRUCT_STAT_ST_ATIM
133 stbuf->st_atim.tv_nsec = attr->atimensec;
134 stbuf->st_mtim.tv_nsec = attr->mtimensec;
135 stbuf->st_ctim.tv_nsec = attr->ctimensec;
136#endif
137}
138
Miklos Szeredie3b83092005-07-22 17:24:30 +0000139static void convert_file_lock(const struct fuse_file_lock *ffl,
140 struct fuse_lock_param *lk)
141{
142 lk->type = ffl->type;
143 lk->start = ffl->start;
144 lk->end = ffl->end;
145 lk->owner = ffl->owner;
146 lk->pid = ffl->pid;
147}
148
149static void convert_lock_param(const struct fuse_lock_param *lk,
150 struct fuse_file_lock *ffl)
151{
152 ffl->type = lk->type;
153 ffl->start = lk->start;
154 ffl->end = lk->end;
155 ffl->owner = lk->owner;
156 ffl->pid = lk->pid;
157}
158
Miklos Szeredi12744942005-07-11 12:32:31 +0000159static size_t iov_length(const struct iovec *iov, size_t count)
160{
161 size_t seg;
162 size_t ret = 0;
163
164 for (seg = 0; seg < count; seg++)
165 ret += iov[seg].iov_len;
166 return ret;
167}
168
169static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
170 size_t count)
171{
172 int res;
173 unsigned outsize = iov_length(iov, count);
174 struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
175 out->len = outsize;
176
Miklos Szeredi76c17522005-07-13 14:08:19 +0000177 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000178 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
179 out->unique, out->error, strerror(-out->error), outsize);
180 fflush(stdout);
181 }
182
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000183 /* This needs to be done before the reply, otherwise the scheduler
184 could play tricks with us, and only let the counter be
185 increased long after the operation is done */
186 fuse_inc_avail(f);
187
Miklos Szeredi12744942005-07-11 12:32:31 +0000188 res = writev(f->fd, iov, count);
189 if (res == -1) {
190 /* ENOENT means the operation was interrupted */
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000191 if (!fuse_ll_exited(f) && errno != ENOENT)
Miklos Szeredi12744942005-07-11 12:32:31 +0000192 perror("fuse: writing device");
193 return -errno;
194 }
195 return 0;
196}
197
Miklos Szeredi76c17522005-07-13 14:08:19 +0000198static int send_reply(struct fuse_ll *f, uint64_t unique, int error,
199 const void *arg, size_t argsize)
Miklos Szeredi12744942005-07-11 12:32:31 +0000200{
201 struct fuse_out_header out;
202 struct iovec iov[2];
203 size_t count;
204
205 if (error <= -1000 || error > 0) {
206 fprintf(stderr, "fuse: bad error value: %i\n", error);
207 error = -ERANGE;
208 }
209
Miklos Szeredi76c17522005-07-13 14:08:19 +0000210 out.unique = unique;
Miklos Szeredi12744942005-07-11 12:32:31 +0000211 out.error = error;
212 count = 1;
213 iov[0].iov_base = &out;
214 iov[0].iov_len = sizeof(struct fuse_out_header);
215 if (argsize && !error) {
216 count++;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000217 iov[1].iov_base = (void *) arg;
Miklos Szeredi12744942005-07-11 12:32:31 +0000218 iov[1].iov_len = argsize;
219 }
220 return send_reply_raw(f, iov, count);
221}
222
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000223size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000224{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000225 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000226}
227
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000228char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000229 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000230{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000231 unsigned namelen = strlen(name);
232 unsigned entlen = FUSE_NAME_OFFSET + namelen;
233 unsigned entsize = fuse_dirent_size(namelen);
234 unsigned padlen = entsize - entlen;
235 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000236
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000237 dirent->ino = stbuf->st_ino;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000238 dirent->off = off;
239 dirent->namelen = namelen;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000240 dirent->type = (stbuf->st_mode & 0170000) >> 12;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000241 strncpy(dirent->name, name, namelen);
242 if (padlen)
243 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000244
Miklos Szeredi76c17522005-07-13 14:08:19 +0000245 return buf + entsize;
Miklos Szeredi12744942005-07-11 12:32:31 +0000246}
247
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000248static void convert_statfs(const struct statfs *stbuf,
Miklos Szeredi76c17522005-07-13 14:08:19 +0000249 struct fuse_kstatfs *kstatfs)
Miklos Szeredi12744942005-07-11 12:32:31 +0000250{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000251 kstatfs->bsize = stbuf->f_bsize;
252 kstatfs->blocks = stbuf->f_blocks;
253 kstatfs->bfree = stbuf->f_bfree;
254 kstatfs->bavail = stbuf->f_bavail;
255 kstatfs->files = stbuf->f_files;
256 kstatfs->ffree = stbuf->f_ffree;
257 kstatfs->namelen = stbuf->f_namelen;
Miklos Szeredi12744942005-07-11 12:32:31 +0000258}
259
Miklos Szeredi76c17522005-07-13 14:08:19 +0000260static void free_req(fuse_req_t req)
261{
262 free(req);
263}
264
265static int send_reply_req(fuse_req_t req, const void *arg, size_t argsize)
266{
267 int res = send_reply(req->f, req->unique, 0, arg, argsize);
268 free_req(req);
269 return res;
270}
271
272int fuse_reply_err(fuse_req_t req, int err)
273{
274 int res = send_reply(req->f, req->unique, -err, NULL, 0);
275 free_req(req);
276 return res;
277}
278
279int fuse_reply_none(fuse_req_t req)
280{
281 free_req(req);
282 return 0;
283}
284
285static unsigned long calc_timeout_sec(double t)
286{
287 if (t > (double) ULONG_MAX)
288 return ULONG_MAX;
289 else if (t < 0.0)
290 return 0;
291 else
292 return (unsigned long) t;
293}
294
295static unsigned int calc_timeout_nsec(double t)
296{
297 double f = t - (double) calc_timeout_sec(t);
298 if (f < 0.0)
299 return 0;
300 else if (f >= 0.999999999)
301 return 999999999;
302 else
303 return (unsigned int) (f * 1.0e9);
304}
305
306int fuse_reply_entry(fuse_req_t req, const struct fuse_entry_param *e)
307{
308 struct fuse_entry_out arg;
309
310 memset(&arg, 0, sizeof(arg));
311 arg.nodeid = e->ino;
312 arg.generation = e->generation;
313 arg.entry_valid = calc_timeout_sec(e->entry_timeout);
314 arg.entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
315 arg.attr_valid = calc_timeout_sec(e->attr_timeout);
316 arg.attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
317 convert_stat(&e->attr, &arg.attr);
318
319 return send_reply_req(req, &arg, sizeof(arg));
320}
321
322int fuse_reply_attr(fuse_req_t req, const struct stat *attr,
323 double attr_timeout)
324{
325 struct fuse_attr_out arg;
326
327 memset(&arg, 0, sizeof(arg));
328 arg.attr_valid = calc_timeout_sec(attr_timeout);
329 arg.attr_valid_nsec = calc_timeout_nsec(attr_timeout);
330 convert_stat(attr, &arg.attr);
331
332 return send_reply_req(req, &arg, sizeof(arg));
333}
334
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000335int fuse_reply_readlink(fuse_req_t req, const char *linkname)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000336{
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000337 return send_reply_req(req, linkname, strlen(linkname));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000338}
339
340int fuse_reply_open(fuse_req_t req, const struct fuse_file_info *f)
341{
342 struct fuse_open_out arg;
343
344 memset(&arg, 0, sizeof(arg));
345 arg.fh = f->fh;
Miklos Szeredie77cc072005-08-01 11:58:51 +0000346 if (f->direct_io)
347 arg.open_flags |= FOPEN_DIRECT_IO;
348 if (f->keep_cache)
349 arg.open_flags |= FOPEN_KEEP_CACHE;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000350
Miklos Szeredi76c17522005-07-13 14:08:19 +0000351 return send_reply_req(req, &arg, sizeof(arg));
352}
353
354int fuse_reply_write(fuse_req_t req, size_t count)
355{
356 struct fuse_write_out arg;
357
358 memset(&arg, 0, sizeof(arg));
359 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000360
Miklos Szeredi76c17522005-07-13 14:08:19 +0000361 return send_reply_req(req, &arg, sizeof(arg));
362}
363
364int fuse_reply_buf(fuse_req_t req, const char *buf, size_t size)
365{
366 return send_reply_req(req, buf, size);
367}
368
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000369int fuse_reply_statfs(fuse_req_t req, const struct statfs *stbuf)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000370{
371 struct fuse_statfs_out arg;
372
373 memset(&arg, 0, sizeof(arg));
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000374 convert_statfs(stbuf, &arg.st);
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000375
Miklos Szeredi76c17522005-07-13 14:08:19 +0000376 return send_reply_req(req, &arg, sizeof(arg));
377}
378
379int fuse_reply_xattr(fuse_req_t req, size_t count)
380{
381 struct fuse_getxattr_out arg;
382
383 memset(&arg, 0, sizeof(arg));
384 arg.size = count;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000385
Miklos Szeredi76c17522005-07-13 14:08:19 +0000386 return send_reply_req(req, &arg, sizeof(arg));
387}
388
Miklos Szeredie3b83092005-07-22 17:24:30 +0000389int fuse_reply_getlk(fuse_req_t req, const struct fuse_lock_param *lk)
390{
391 struct fuse_lk_in_out arg;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000392
Miklos Szeredie3b83092005-07-22 17:24:30 +0000393 memset(&arg, 0, sizeof(arg));
394 convert_lock_param(lk, &arg.lk);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000395
Miklos Szeredie3b83092005-07-22 17:24:30 +0000396 return send_reply_req(req, &arg, sizeof(arg));
397}
398
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000399static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000400{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000401 if (req->f->op.lookup)
402 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000403 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000404 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000405}
406
Miklos Szeredi76c17522005-07-13 14:08:19 +0000407static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
408 struct fuse_forget_in *arg)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000409{
410 if (req->f->op.forget)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000411 req->f->op.forget(req, nodeid, arg->nlookup);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000412}
413
414static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
415{
416 if (req->f->op.getattr)
417 req->f->op.getattr(req, nodeid);
418 else
419 fuse_reply_err(req, ENOSYS);
420}
421
422static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
423 struct fuse_setattr_in *arg)
424{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000425 if (req->f->op.setattr) {
426 struct stat stbuf;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000427 memset(&stbuf, 0, sizeof(stbuf));
Miklos Szeredi76c17522005-07-13 14:08:19 +0000428 convert_attr(&arg->attr, &stbuf);
429 req->f->op.setattr(req, nodeid, &stbuf, arg->valid);
430 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000431 fuse_reply_err(req, ENOSYS);
432}
433
Miklos Szeredi7b28eae2005-08-01 12:48:30 +0000434static void do_access(fuse_req_t req, fuse_ino_t nodeid,
435 struct fuse_access_in *arg)
436{
437 if (req->f->op.access)
438 req->f->op.access(req, nodeid, arg->mask);
439 else
440 fuse_reply_err(req, ENOSYS);
441}
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000442static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
443{
444 if (req->f->op.readlink)
445 req->f->op.readlink(req, nodeid);
446 else
447 fuse_reply_err(req, ENOSYS);
448}
449
450static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
451 struct fuse_mknod_in *arg)
452{
453 if (req->f->op.mknod)
454 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
455 else
456 fuse_reply_err(req, ENOSYS);
457}
458
459static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
460 struct fuse_mkdir_in *arg)
461{
462 if (req->f->op.mkdir)
463 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
464 else
465 fuse_reply_err(req, ENOSYS);
466}
467
468static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
469{
470 if (req->f->op.unlink)
471 req->f->op.unlink(req, nodeid, name);
472 else
473 fuse_reply_err(req, ENOSYS);
474}
475
476static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
477{
478 if (req->f->op.rmdir)
479 req->f->op.rmdir(req, nodeid, name);
480 else
481 fuse_reply_err(req, ENOSYS);
482}
483
484static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000485 char *linkname)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000486{
487 if (req->f->op.symlink)
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000488 req->f->op.symlink(req, linkname, nodeid, name);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000489 else
490 fuse_reply_err(req, ENOSYS);
491}
492
493static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
494 struct fuse_rename_in *arg)
495{
496 char *oldname = PARAM(arg);
497 char *newname = oldname + strlen(oldname) + 1;
498
499 if (req->f->op.rename)
500 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
501 else
502 fuse_reply_err(req, ENOSYS);
503}
504
505static void do_link(fuse_req_t req, fuse_ino_t nodeid,
506 struct fuse_link_in *arg)
507{
508 if (req->f->op.link)
509 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
510 else
511 fuse_reply_err(req, ENOSYS);
512}
513
514static void do_open(fuse_req_t req, fuse_ino_t nodeid,
515 struct fuse_open_in *arg)
516{
517 struct fuse_file_info fi;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000518
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000519 memset(&fi, 0, sizeof(fi));
520 fi.flags = arg->flags;
521
522 if (req->f->op.open)
523 req->f->op.open(req, nodeid, &fi);
524 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000525 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000526}
527
528static void do_read(fuse_req_t req, fuse_ino_t nodeid,
529 struct fuse_read_in *arg)
530{
Miklos Szeredi76c17522005-07-13 14:08:19 +0000531 if (req->f->op.read) {
532 struct fuse_file_info fi;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000533
Miklos Szeredi76c17522005-07-13 14:08:19 +0000534 memset(&fi, 0, sizeof(fi));
535 fi.fh = arg->fh;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000536 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000537 } else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000538 fuse_reply_err(req, ENOSYS);
539}
540
541static void do_write(fuse_req_t req, fuse_ino_t nodeid,
542 struct fuse_write_in *arg)
543{
544 struct fuse_file_info fi;
545
546 memset(&fi, 0, sizeof(fi));
547 fi.fh = arg->fh;
548 fi.writepage = arg->write_flags & 1;
549
550 if (req->f->op.write)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000551 req->f->op.write(req, nodeid, PARAM(arg), arg->size,
552 arg->offset, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000553 else
554 fuse_reply_err(req, ENOSYS);
555}
556
557static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
558 struct fuse_flush_in *arg)
559{
560 struct fuse_file_info fi;
561
562 memset(&fi, 0, sizeof(fi));
563 fi.fh = arg->fh;
564
565 if (req->f->op.flush)
566 req->f->op.flush(req, nodeid, &fi);
567 else
568 fuse_reply_err(req, ENOSYS);
569}
570
571static void do_release(fuse_req_t req, fuse_ino_t nodeid,
572 struct fuse_release_in *arg)
573{
574 struct fuse_file_info fi;
575
576 memset(&fi, 0, sizeof(fi));
577 fi.flags = arg->flags;
578 fi.fh = arg->fh;
579
580 if (req->f->op.release)
581 req->f->op.release(req, nodeid, &fi);
582 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000583 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000584}
585
586static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000587 struct fuse_fsync_in *inarg)
588{
Miklos Szeredi12744942005-07-11 12:32:31 +0000589 struct fuse_file_info fi;
590
591 memset(&fi, 0, sizeof(fi));
592 fi.fh = inarg->fh;
593
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000594 if (req->f->op.fsync)
595 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
596 else
597 fuse_reply_err(req, ENOSYS);
598}
599
600static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
601 struct fuse_open_in *arg)
602{
603 struct fuse_file_info fi;
604
605 memset(&fi, 0, sizeof(fi));
606 fi.flags = arg->flags;
607
608 if (req->f->op.opendir)
609 req->f->op.opendir(req, nodeid, &fi);
610 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000611 fuse_reply_open(req, &fi);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000612}
613
614static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
615 struct fuse_read_in *arg)
616{
617 struct fuse_file_info fi;
618
619 memset(&fi, 0, sizeof(fi));
620 fi.fh = arg->fh;
621
622 if (req->f->op.readdir)
623 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
624 else
625 fuse_reply_err(req, ENOSYS);
626}
627
628static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
629 struct fuse_release_in *arg)
630{
631 struct fuse_file_info fi;
632
633 memset(&fi, 0, sizeof(fi));
634 fi.flags = arg->flags;
635 fi.fh = arg->fh;
636
637 if (req->f->op.releasedir)
638 req->f->op.releasedir(req, nodeid, &fi);
639 else
Miklos Szeredi76c17522005-07-13 14:08:19 +0000640 fuse_reply_err(req, 0);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000641}
642
643static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
644 struct fuse_fsync_in *inarg)
645{
646 struct fuse_file_info fi;
647
648 memset(&fi, 0, sizeof(fi));
649 fi.fh = inarg->fh;
650
651 if (req->f->op.fsyncdir)
652 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
653 else
654 fuse_reply_err(req, ENOSYS);
655}
656
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000657static void do_statfs(fuse_req_t req)
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000658{
659 if (req->f->op.statfs)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000660 req->f->op.statfs(req);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +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_setxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000666 struct fuse_setxattr_in *arg)
667{
Miklos Szeredi12744942005-07-11 12:32:31 +0000668 char *name = PARAM(arg);
Miklos Szeredi1b188022005-07-28 11:07:29 +0000669 char *value = name + strlen(name) + 1;
Miklos Szeredi12744942005-07-11 12:32:31 +0000670
Miklos Szeredi4331a272005-07-12 14:51:04 +0000671 if (req->f->op.setxattr)
Miklos Szeredi76c17522005-07-13 14:08:19 +0000672 req->f->op.setxattr(req, nodeid, name, value, arg->size,
673 arg->flags);
Miklos Szeredi4331a272005-07-12 14:51:04 +0000674 else
675 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000676}
677
Miklos Szeredi4331a272005-07-12 14:51:04 +0000678static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000679 struct fuse_getxattr_in *arg)
680{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000681 if (req->f->op.getxattr)
682 req->f->op.getxattr(req, nodeid, PARAM(arg), arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000683 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000684 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000685}
686
Miklos Szeredi4331a272005-07-12 14:51:04 +0000687static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000688 struct fuse_getxattr_in *arg)
689{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000690 if (req->f->op.listxattr)
691 req->f->op.listxattr(req, nodeid, arg->size);
Miklos Szeredi12744942005-07-11 12:32:31 +0000692 else
Miklos Szeredi4331a272005-07-12 14:51:04 +0000693 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000694}
695
Miklos Szeredi4331a272005-07-12 14:51:04 +0000696static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000697{
Miklos Szeredi4331a272005-07-12 14:51:04 +0000698 if (req->f->op.removexattr)
699 req->f->op.removexattr(req, nodeid, name);
700 else
701 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000702}
703
Miklos Szeredie3b83092005-07-22 17:24:30 +0000704static void do_getlk(fuse_req_t req, fuse_ino_t nodeid,
705 struct fuse_lk_in_out *arg)
706{
707 if (req->f->op.getlk) {
708 struct fuse_lock_param lk;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000709
Miklos Szeredie3b83092005-07-22 17:24:30 +0000710 memset(&lk, 0, sizeof(lk));
711 convert_file_lock(&arg->lk, &lk);
712 req->f->op.getlk(req, nodeid, &lk);
713 } else
714 fuse_reply_err(req, ENOSYS);
715}
716
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000717static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, int issleep,
Miklos Szeredie3b83092005-07-22 17:24:30 +0000718 struct fuse_lk_in_out *arg)
719{
720 if (req->f->op.setlk) {
721 struct fuse_lock_param lk;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000722
Miklos Szeredie3b83092005-07-22 17:24:30 +0000723 memset(&lk, 0, sizeof(lk));
724 convert_file_lock(&arg->lk, &lk);
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000725 req->f->op.setlk(req, nodeid, issleep, &lk);
Miklos Szeredie3b83092005-07-22 17:24:30 +0000726 } else
727 fuse_reply_err(req, ENOSYS);
728}
729
Miklos Szeredi76c17522005-07-13 14:08:19 +0000730static void do_init(struct fuse_ll *f, uint64_t unique,
Miklos Szeredi12744942005-07-11 12:32:31 +0000731 struct fuse_init_in_out *arg)
732{
733 struct fuse_init_in_out outarg;
734
Miklos Szeredi76c17522005-07-13 14:08:19 +0000735 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000736 printf("INIT: %u.%u\n", arg->major, arg->minor);
737 fflush(stdout);
738 }
739 f->got_init = 1;
740 if (f->op.init)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000741 f->userdata = f->op.init(f->userdata);
Miklos Szeredi12744942005-07-11 12:32:31 +0000742
Miklos Szeredi76c17522005-07-13 14:08:19 +0000743 f->major = FUSE_KERNEL_VERSION;
744 f->minor = FUSE_KERNEL_MINOR_VERSION;
745
Miklos Szeredi12744942005-07-11 12:32:31 +0000746 memset(&outarg, 0, sizeof(outarg));
747 outarg.major = f->major;
748 outarg.minor = f->minor;
749
Miklos Szeredi76c17522005-07-13 14:08:19 +0000750 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000751 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
752 fflush(stdout);
753 }
754
Miklos Szeredi76c17522005-07-13 14:08:19 +0000755 send_reply(f, unique, 0, &outarg, sizeof(outarg));
Miklos Szeredi12744942005-07-11 12:32:31 +0000756}
757
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000758void *fuse_req_userdata(fuse_req_t req)
759{
760 return req->f->userdata;
761}
762
763const struct fuse_ctx *fuse_req_ctx(fuse_req_t req)
764{
765 return &req->ctx;
766}
767
Miklos Szeredi12744942005-07-11 12:32:31 +0000768static void free_cmd(struct fuse_cmd *cmd)
769{
770 free(cmd->buf);
771 free(cmd);
772}
773
Miklos Szeredi76c17522005-07-13 14:08:19 +0000774void fuse_ll_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
Miklos Szeredi12744942005-07-11 12:32:31 +0000775{
776 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000777 void *inarg = cmd->buf + sizeof(struct fuse_in_header);
778 struct fuse_req *req;
Miklos Szeredi12744942005-07-11 12:32:31 +0000779
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000780 fuse_dec_avail(f);
781
Miklos Szeredi76c17522005-07-13 14:08:19 +0000782 if (f->debug) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000783 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000784 in->unique, opname((enum fuse_opcode) in->opcode), in->opcode,
Miklos Szeredi12744942005-07-11 12:32:31 +0000785 (unsigned long) in->nodeid, cmd->buflen);
786 fflush(stdout);
787 }
788
Miklos Szeredi76c17522005-07-13 14:08:19 +0000789 if (!f->got_init) {
790 if (in->opcode != FUSE_INIT)
791 send_reply(f, in->unique, -EPROTO, NULL, 0);
792 else
793 do_init(f, in->unique, (struct fuse_init_in_out *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000794 goto out;
795 }
796
Miklos Szeredi76c17522005-07-13 14:08:19 +0000797 if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
Miklos Szeredi12744942005-07-11 12:32:31 +0000798 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
799 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
800 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
801 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
Miklos Szeredi76c17522005-07-13 14:08:19 +0000802 send_reply(f, in->unique, -EACCES, NULL, 0);
Miklos Szeredi12744942005-07-11 12:32:31 +0000803 goto out;
804 }
805
Miklos Szeredi76c17522005-07-13 14:08:19 +0000806 req = (struct fuse_req *) malloc(sizeof(struct fuse_req));
807 if (req == NULL) {
808 fprintf(stderr, "fuse: failed to allocate request\n");
809 goto out;
810 }
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000811
Miklos Szeredi76c17522005-07-13 14:08:19 +0000812 req->f = f;
813 req->unique = in->unique;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000814 req->ctx.uid = in->uid;
815 req->ctx.gid = in->gid;
816 req->ctx.pid = in->pid;
Miklos Szeredi12744942005-07-11 12:32:31 +0000817
818 switch (in->opcode) {
819 case FUSE_LOOKUP:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000820 do_lookup(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000821 break;
822
Miklos Szeredi76c17522005-07-13 14:08:19 +0000823 case FUSE_FORGET:
824 do_forget(req, in->nodeid, (struct fuse_forget_in *) inarg);
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000825 break;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000826
Miklos Szeredi12744942005-07-11 12:32:31 +0000827 case FUSE_GETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000828 do_getattr(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000829 break;
830
831 case FUSE_SETATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000832 do_setattr(req, in->nodeid, (struct fuse_setattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000833 break;
834
835 case FUSE_READLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000836 do_readlink(req, in->nodeid);
Miklos Szeredi12744942005-07-11 12:32:31 +0000837 break;
838
839 case FUSE_MKNOD:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000840 do_mknod(req, in->nodeid, (struct fuse_mknod_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000841 break;
842
843 case FUSE_MKDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000844 do_mkdir(req, in->nodeid, (struct fuse_mkdir_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000845 break;
846
847 case FUSE_UNLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000848 do_unlink(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000849 break;
850
851 case FUSE_RMDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000852 do_rmdir(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000853 break;
854
855 case FUSE_SYMLINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000856 do_symlink(req, in->nodeid, (char *) inarg,
Miklos Szeredi12744942005-07-11 12:32:31 +0000857 ((char *) inarg) + strlen((char *) inarg) + 1);
858 break;
859
860 case FUSE_RENAME:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000861 do_rename(req, in->nodeid, (struct fuse_rename_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000862 break;
863
864 case FUSE_LINK:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000865 do_link(req, in->nodeid, (struct fuse_link_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000866 break;
867
868 case FUSE_OPEN:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000869 do_open(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000870 break;
871
872 case FUSE_FLUSH:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000873 do_flush(req, in->nodeid, (struct fuse_flush_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000874 break;
875
876 case FUSE_RELEASE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000877 do_release(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000878 break;
879
880 case FUSE_READ:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000881 do_read(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000882 break;
883
884 case FUSE_WRITE:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000885 do_write(req, in->nodeid, (struct fuse_write_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000886 break;
887
888 case FUSE_STATFS:
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000889 do_statfs(req);
Miklos Szeredi12744942005-07-11 12:32:31 +0000890 break;
891
892 case FUSE_FSYNC:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000893 do_fsync(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000894 break;
895
896 case FUSE_SETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000897 do_setxattr(req, in->nodeid, (struct fuse_setxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000898 break;
899
900 case FUSE_GETXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000901 do_getxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000902 break;
903
904 case FUSE_LISTXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000905 do_listxattr(req, in->nodeid, (struct fuse_getxattr_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000906 break;
907
908 case FUSE_REMOVEXATTR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000909 do_removexattr(req, in->nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000910 break;
911
912 case FUSE_OPENDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000913 do_opendir(req, in->nodeid, (struct fuse_open_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000914 break;
915
916 case FUSE_READDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000917 do_readdir(req, in->nodeid, (struct fuse_read_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000918 break;
919
920 case FUSE_RELEASEDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000921 do_releasedir(req, in->nodeid, (struct fuse_release_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000922 break;
923
924 case FUSE_FSYNCDIR:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000925 do_fsyncdir(req, in->nodeid, (struct fuse_fsync_in *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000926 break;
927
Miklos Szeredie3b83092005-07-22 17:24:30 +0000928 case FUSE_GETLK:
929 do_getlk(req, in->nodeid, (struct fuse_lk_in_out *) inarg);
930 break;
931
932 case FUSE_SETLK:
933 do_setlk(req, in->nodeid, 0, (struct fuse_lk_in_out *) inarg);
934 break;
935
936 case FUSE_SETLKW:
937 do_setlk(req, in->nodeid, 1, (struct fuse_lk_in_out *) inarg);
938 break;
Miklos Szeredif6e0ec62005-08-03 09:11:06 +0000939
Miklos Szeredi7b28eae2005-08-01 12:48:30 +0000940 case FUSE_ACCESS:
941 do_access(req, in->nodeid, (struct fuse_access_in *) inarg);
942 break;
Miklos Szeredie3b83092005-07-22 17:24:30 +0000943
Miklos Szeredi12744942005-07-11 12:32:31 +0000944 default:
Miklos Szeredi76c17522005-07-13 14:08:19 +0000945 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000946 }
947
948 out:
949 free_cmd(cmd);
950}
951
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000952void fuse_ll_exit(struct fuse_ll *f)
953{
954 f->exited = 1;
955}
956
Miklos Szeredi76c17522005-07-13 14:08:19 +0000957int fuse_ll_exited(struct fuse_ll* f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000958{
959 return f->exited;
960}
961
Miklos Szeredi76c17522005-07-13 14:08:19 +0000962struct fuse_cmd *fuse_ll_read_cmd(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +0000963{
964 ssize_t res;
965 struct fuse_cmd *cmd;
966 struct fuse_in_header *in;
967 void *inarg;
968
969 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
970 if (cmd == NULL) {
971 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
972 return NULL;
973 }
974 cmd->buf = (char *) malloc(FUSE_MAX_IN);
975 if (cmd->buf == NULL) {
976 fprintf(stderr, "fuse: failed to allocate read buffer\n");
977 free(cmd);
978 return NULL;
979 }
980 in = (struct fuse_in_header *) cmd->buf;
Miklos Szeredi76c17522005-07-13 14:08:19 +0000981 inarg = cmd->buf + sizeof(struct fuse_in_header);
Miklos Szeredi12744942005-07-11 12:32:31 +0000982
983 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
984 if (res == -1) {
985 free_cmd(cmd);
Miklos Szeredi76c17522005-07-13 14:08:19 +0000986 if (fuse_ll_exited(f) || errno == EINTR || errno == ENOENT)
Miklos Szeredi12744942005-07-11 12:32:31 +0000987 return NULL;
988
989 /* ENODEV means we got unmounted, so we silenty return failure */
990 if (errno != ENODEV) {
991 /* BAD... This will happen again */
992 perror("fuse: reading device");
993 }
994
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000995 fuse_ll_exit(f);
Miklos Szeredi12744942005-07-11 12:32:31 +0000996 return NULL;
997 }
Miklos Szeredi76c17522005-07-13 14:08:19 +0000998 if ((size_t) res < sizeof(struct fuse_in_header)) {
Miklos Szeredi12744942005-07-11 12:32:31 +0000999 free_cmd(cmd);
1000 /* Cannot happen */
1001 fprintf(stderr, "short read on fuse device\n");
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001002 fuse_ll_exit(f);
Miklos Szeredi12744942005-07-11 12:32:31 +00001003 return NULL;
1004 }
1005 cmd->buflen = res;
1006
Miklos Szeredi12744942005-07-11 12:32:31 +00001007
1008 return cmd;
1009}
1010
Miklos Szeredi76c17522005-07-13 14:08:19 +00001011int fuse_ll_loop(struct fuse_ll *f)
Miklos Szeredi12744942005-07-11 12:32:31 +00001012{
1013 if (f == NULL)
1014 return -1;
1015
1016 while (1) {
1017 struct fuse_cmd *cmd;
1018
Miklos Szeredi76c17522005-07-13 14:08:19 +00001019 if (fuse_ll_exited(f))
Miklos Szeredi12744942005-07-11 12:32:31 +00001020 break;
1021
Miklos Szeredi76c17522005-07-13 14:08:19 +00001022 cmd = fuse_ll_read_cmd(f);
Miklos Szeredi12744942005-07-11 12:32:31 +00001023 if (cmd == NULL)
1024 continue;
1025
Miklos Szeredi76c17522005-07-13 14:08:19 +00001026 fuse_ll_process_cmd(f, cmd);
Miklos Szeredi12744942005-07-11 12:32:31 +00001027 }
1028 f->exited = 0;
1029 return 0;
1030}
1031
Miklos Szeredi76c17522005-07-13 14:08:19 +00001032int fuse_ll_is_lib_option(const char *opt)
Miklos Szeredi12744942005-07-11 12:32:31 +00001033{
1034 if (strcmp(opt, "debug") == 0 ||
Miklos Szeredi76c17522005-07-13 14:08:19 +00001035 strcmp(opt, "allow_root") == 0)
Miklos Szeredi12744942005-07-11 12:32:31 +00001036 return 1;
1037 else
1038 return 0;
1039}
1040
Miklos Szeredi76c17522005-07-13 14:08:19 +00001041static int parse_ll_opts(struct fuse_ll *f, const char *opts)
Miklos Szeredi12744942005-07-11 12:32:31 +00001042{
1043 if (opts) {
1044 char *xopts = strdup(opts);
1045 char *s = xopts;
1046 char *opt;
1047
1048 if (xopts == NULL) {
1049 fprintf(stderr, "fuse: memory allocation failed\n");
1050 return -1;
1051 }
1052
1053 while((opt = strsep(&s, ","))) {
1054 if (strcmp(opt, "debug") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +00001055 f->debug = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +00001056 else if (strcmp(opt, "allow_root") == 0)
Miklos Szeredi76c17522005-07-13 14:08:19 +00001057 f->allow_root = 1;
Miklos Szeredi12744942005-07-11 12:32:31 +00001058 else
1059 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1060 }
1061 free(xopts);
1062 }
1063 return 0;
1064}
1065
Miklos Szeredi76c17522005-07-13 14:08:19 +00001066struct fuse_ll *fuse_ll_new(int fd, const char *opts,
1067 const struct fuse_ll_operations *op,
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001068 size_t op_size, void *userdata)
Miklos Szeredi12744942005-07-11 12:32:31 +00001069{
1070 struct fuse_ll *f;
1071
Miklos Szeredi76c17522005-07-13 14:08:19 +00001072 if (sizeof(struct fuse_ll_operations) < op_size) {
Miklos Szeredi12744942005-07-11 12:32:31 +00001073 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
Miklos Szeredi76c17522005-07-13 14:08:19 +00001074 op_size = sizeof(struct fuse_ll_operations);
Miklos Szeredi12744942005-07-11 12:32:31 +00001075 }
1076
1077 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
1078 if (f == NULL) {
1079 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1080 goto out;
1081 }
1082
Miklos Szeredi76c17522005-07-13 14:08:19 +00001083 if (parse_ll_opts(f, opts) == -1)
Miklos Szeredi12744942005-07-11 12:32:31 +00001084 goto out_free;
1085
1086 f->fd = fd;
1087 memcpy(&f->op, op, op_size);
1088 f->exited = 0;
1089 f->owner = getuid();
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001090 f->userdata = userdata;
1091 mutex_init(&f->worker_lock);
Miklos Szeredi12744942005-07-11 12:32:31 +00001092
1093 return f;
1094
1095 out_free:
1096 free(f);
1097 out:
1098 return NULL;
1099}
1100
Miklos Szeredi76c17522005-07-13 14:08:19 +00001101void fuse_ll_destroy(struct fuse_ll *f)
1102{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +00001103 if (f->op.destroy)
1104 f->op.destroy(f->userdata);
1105
1106 pthread_mutex_destroy(&f->worker_lock);
Miklos Szeredi76c17522005-07-13 14:08:19 +00001107 free(f);
1108}
Miklos Szeredi12744942005-07-11 12:32:31 +00001109