blob: b21a8fe3502ce149d585e1087393a8605315a969 [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
9#include "fuse_i.h"
10#include "fuse_compat.h"
11#include "fuse_kernel.h"
12#include "fuse_kernel_compat5.h"
13
14#include <stdio.h>
15#include <string.h>
16#include <stdlib.h>
17#include <unistd.h>
18#include <limits.h>
19#include <errno.h>
20#include <assert.h>
21#include <stdint.h>
22#include <sys/param.h>
23#include <sys/uio.h>
24
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000025#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
Miklos Szeredi12744942005-07-11 12:32:31 +000026
27struct fuse_ll {
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000028 unsigned int debug : 1;
29 unsigned int allow_root : 1;
Miklos Szeredi12744942005-07-11 12:32:31 +000030 int fd;
31 struct fuse_lowlevel_operations op;
32 volatile int exited;
33 int got_init;
34 void *user_data;
35 int major;
36 int minor;
37 uid_t owner;
Miklos Szeredi12744942005-07-11 12:32:31 +000038};
39
40struct fuse_cmd {
41 char *buf;
42 size_t buflen;
43};
44
45static const char *opname(enum fuse_opcode opcode)
46{
47 switch (opcode) {
48 case FUSE_LOOKUP: return "LOOKUP";
49 case FUSE_FORGET: return "FORGET";
50 case FUSE_GETATTR: return "GETATTR";
51 case FUSE_SETATTR: return "SETATTR";
52 case FUSE_READLINK: return "READLINK";
53 case FUSE_SYMLINK: return "SYMLINK";
54 case FUSE_MKNOD: return "MKNOD";
55 case FUSE_MKDIR: return "MKDIR";
56 case FUSE_UNLINK: return "UNLINK";
57 case FUSE_RMDIR: return "RMDIR";
58 case FUSE_RENAME: return "RENAME";
59 case FUSE_LINK: return "LINK";
60 case FUSE_OPEN: return "OPEN";
61 case FUSE_READ: return "READ";
62 case FUSE_WRITE: return "WRITE";
63 case FUSE_STATFS: return "STATFS";
64 case FUSE_FLUSH: return "FLUSH";
65 case FUSE_RELEASE: return "RELEASE";
66 case FUSE_FSYNC: return "FSYNC";
67 case FUSE_SETXATTR: return "SETXATTR";
68 case FUSE_GETXATTR: return "GETXATTR";
69 case FUSE_LISTXATTR: return "LISTXATTR";
70 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
71 case FUSE_INIT: return "INIT";
72 case FUSE_OPENDIR: return "OPENDIR";
73 case FUSE_READDIR: return "READDIR";
74 case FUSE_RELEASEDIR: return "RELEASEDIR";
75 case FUSE_FSYNCDIR: return "FSYNCDIR";
76 default: return "???";
77 }
78}
79
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000080static void convert_stat(struct stat *stbuf, struct fuse_attr *attr)
Miklos Szeredi12744942005-07-11 12:32:31 +000081{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000082 attr->ino = stbuf->st_ino;
Miklos Szeredi12744942005-07-11 12:32:31 +000083 attr->mode = stbuf->st_mode;
Miklos Szeredi12744942005-07-11 12:32:31 +000084 attr->nlink = stbuf->st_nlink;
Miklos Szeredi2482fdb2005-07-12 13:23:53 +000085 attr->uid = stbuf->st_uid;
86 attr->gid = stbuf->st_gid;
Miklos Szeredi12744942005-07-11 12:32:31 +000087 attr->rdev = stbuf->st_rdev;
88 attr->size = stbuf->st_size;
89 attr->blocks = stbuf->st_blocks;
90 attr->atime = stbuf->st_atime;
91 attr->mtime = stbuf->st_mtime;
92 attr->ctime = stbuf->st_ctime;
93#ifdef HAVE_STRUCT_STAT_ST_ATIM
94 attr->atimensec = stbuf->st_atim.tv_nsec;
95 attr->mtimensec = stbuf->st_mtim.tv_nsec;
96 attr->ctimensec = stbuf->st_ctim.tv_nsec;
97#endif
98}
99
100static size_t iov_length(const struct iovec *iov, size_t count)
101{
102 size_t seg;
103 size_t ret = 0;
104
105 for (seg = 0; seg < count; seg++)
106 ret += iov[seg].iov_len;
107 return ret;
108}
109
110static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
111 size_t count)
112{
113 int res;
114 unsigned outsize = iov_length(iov, count);
115 struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
116 out->len = outsize;
117
118 if ((f->flags & FUSE_DEBUG)) {
119 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
120 out->unique, out->error, strerror(-out->error), outsize);
121 fflush(stdout);
122 }
123
124 /* This needs to be done before the reply, otherwise the scheduler
125 could play tricks with us, and only let the counter be
126 increased long after the operation is done */
127 fuse_inc_avail(f);
128
129 res = writev(f->fd, iov, count);
130 if (res == -1) {
131 /* ENOENT means the operation was interrupted */
132 if (!f->exited && errno != ENOENT)
133 perror("fuse: writing device");
134 return -errno;
135 }
136 return 0;
137}
138
139static int send_reply(struct fuse_ll *f, struct fuse_in_header *in, int error,
140 void *arg, size_t argsize)
141{
142 struct fuse_out_header out;
143 struct iovec iov[2];
144 size_t count;
145
146 if (error <= -1000 || error > 0) {
147 fprintf(stderr, "fuse: bad error value: %i\n", error);
148 error = -ERANGE;
149 }
150
151 out.unique = in->unique;
152 out.error = error;
153 count = 1;
154 iov[0].iov_base = &out;
155 iov[0].iov_len = sizeof(struct fuse_out_header);
156 if (argsize && !error) {
157 count++;
158 iov[1].iov_base = arg;
159 iov[1].iov_len = argsize;
160 }
161 return send_reply_raw(f, iov, count);
162}
163
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000164size_t fuse_dirent_size(size_t namelen)
Miklos Szeredi12744942005-07-11 12:32:31 +0000165{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000166 return FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + namelen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000167}
168
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000169void fuse_add_dirent(char *buf, const char *name, const struct stat *stat,
170 off_t off)
Miklos Szeredi12744942005-07-11 12:32:31 +0000171{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000172 unsigned namelen = strlen(name);
173 unsigned entlen = FUSE_NAME_OFFSET + namelen;
174 unsigned entsize = fuse_dirent_size(namelen);
175 unsigned padlen = entsize - entlen;
176 struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
Miklos Szeredi12744942005-07-11 12:32:31 +0000177
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000178 dirent->ino = stat->st_ino;
179 dirent->off = off;
180 dirent->namelen = namelen;
181 dirent->type = (stat->st_mode & 0170000) >> 12;
182 strncpy(dirent->name, name, namelen);
183 if (padlen)
184 memset(buf + entlen, 0, padlen);
Miklos Szeredi12744942005-07-11 12:32:31 +0000185
Miklos Szeredi12744942005-07-11 12:32:31 +0000186 return 0;
187}
188
Miklos Szeredi12744942005-07-11 12:32:31 +0000189static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
190{
191 kstatfs->bsize = statfs->f_bsize;
192 kstatfs->blocks = statfs->f_blocks;
193 kstatfs->bfree = statfs->f_bfree;
194 kstatfs->bavail = statfs->f_bavail;
195 kstatfs->files = statfs->f_files;
196 kstatfs->ffree = statfs->f_ffree;
197 kstatfs->namelen = statfs->f_namelen;
198}
199
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000200static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, char *name)
Miklos Szeredi12744942005-07-11 12:32:31 +0000201{
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000202 if (req->f->op.lookup)
203 req->f->op.lookup(req, nodeid, name);
Miklos Szeredi12744942005-07-11 12:32:31 +0000204 else
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000205 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000206}
207
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000208static void do_forget(fuse_req_t req, fuse_ino_t nodeid)
209{
210 if (req->f->op.forget)
211 req->f->op.forget(req, nodeid);
212}
213
214static void do_getattr(fuse_req_t req, fuse_ino_t nodeid)
215{
216 if (req->f->op.getattr)
217 req->f->op.getattr(req, nodeid);
218 else
219 fuse_reply_err(req, ENOSYS);
220}
221
222static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
223 struct fuse_setattr_in *arg)
224{
225 if (req->f->op.setattr)
226 req->f->op.setattr(req, nodeid, &arg->attr, arg->valid);
227 else
228 fuse_reply_err(req, ENOSYS);
229}
230
231static void do_readlink(fuse_req_t req, fuse_ino_t nodeid)
232{
233 if (req->f->op.readlink)
234 req->f->op.readlink(req, nodeid);
235 else
236 fuse_reply_err(req, ENOSYS);
237}
238
239static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
240 struct fuse_mknod_in *arg)
241{
242 if (req->f->op.mknod)
243 req->f->op.mknod(req, nodeid, PARAM(arg), arg->mode, arg->rdev);
244 else
245 fuse_reply_err(req, ENOSYS);
246}
247
248static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
249 struct fuse_mkdir_in *arg)
250{
251 if (req->f->op.mkdir)
252 req->f->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
253 else
254 fuse_reply_err(req, ENOSYS);
255}
256
257static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, char *name)
258{
259 if (req->f->op.unlink)
260 req->f->op.unlink(req, nodeid, name);
261 else
262 fuse_reply_err(req, ENOSYS);
263}
264
265static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, char *name)
266{
267 if (req->f->op.rmdir)
268 req->f->op.rmdir(req, nodeid, name);
269 else
270 fuse_reply_err(req, ENOSYS);
271}
272
273static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, char *name,
274 char *link)
275{
276 if (req->f->op.symlink)
277 req->f->op.symlink(req, link, nodeid, name);
278 else
279 fuse_reply_err(req, ENOSYS);
280}
281
282static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
283 struct fuse_rename_in *arg)
284{
285 char *oldname = PARAM(arg);
286 char *newname = oldname + strlen(oldname) + 1;
287
288 if (req->f->op.rename)
289 req->f->op.rename(req, nodeid, oldname, arg->newdir, newname);
290 else
291 fuse_reply_err(req, ENOSYS);
292}
293
294static void do_link(fuse_req_t req, fuse_ino_t nodeid,
295 struct fuse_link_in *arg)
296{
297 if (req->f->op.link)
298 req->f->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
299 else
300 fuse_reply_err(req, ENOSYS);
301}
302
303static void do_open(fuse_req_t req, fuse_ino_t nodeid,
304 struct fuse_open_in *arg)
305{
306 struct fuse_file_info fi;
307
308 memset(&fi, 0, sizeof(fi));
309 fi.flags = arg->flags;
310
311 if (req->f->op.open)
312 req->f->op.open(req, nodeid, &fi);
313 else
314 fuse_reply_err(req, ENOSYS);
315}
316
317static void do_read(fuse_req_t req, fuse_ino_t nodeid,
318 struct fuse_read_in *arg)
319{
320 struct fuse_file_info fi;
321
322 memset(&fi, 0, sizeof(fi));
323 fi.fh = arg->fh;
324
325 if (req->f->op.read)
326 req->f->op.read(req, nodeid, arg->size, arg->offset, &fi);
327 else
328 fuse_reply_err(req, ENOSYS);
329}
330
331static void do_write(fuse_req_t req, fuse_ino_t nodeid,
332 struct fuse_write_in *arg)
333{
334 struct fuse_file_info fi;
335
336 memset(&fi, 0, sizeof(fi));
337 fi.fh = arg->fh;
338 fi.writepage = arg->write_flags & 1;
339
340 if (req->f->op.write)
341 req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
342 else
343 fuse_reply_err(req, ENOSYS);
344}
345
346static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
347 struct fuse_flush_in *arg)
348{
349 struct fuse_file_info fi;
350
351 memset(&fi, 0, sizeof(fi));
352 fi.fh = arg->fh;
353
354 if (req->f->op.flush)
355 req->f->op.flush(req, nodeid, &fi);
356 else
357 fuse_reply_err(req, ENOSYS);
358}
359
360static void do_release(fuse_req_t req, fuse_ino_t nodeid,
361 struct fuse_release_in *arg)
362{
363 struct fuse_file_info fi;
364
365 memset(&fi, 0, sizeof(fi));
366 fi.flags = arg->flags;
367 fi.fh = arg->fh;
368
369 if (req->f->op.release)
370 req->f->op.release(req, nodeid, &fi);
371 else
372 fuse_reply_err(req, ENOSYS);
373}
374
375static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
Miklos Szeredi12744942005-07-11 12:32:31 +0000376 struct fuse_fsync_in *inarg)
377{
Miklos Szeredi12744942005-07-11 12:32:31 +0000378 struct fuse_file_info fi;
379
380 memset(&fi, 0, sizeof(fi));
381 fi.fh = inarg->fh;
382
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000383 if (req->f->op.fsync)
384 req->f->op.fsync(req, nodeid, inarg->fsync_flags & 1, &fi);
385 else
386 fuse_reply_err(req, ENOSYS);
387}
388
389static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
390 struct fuse_open_in *arg)
391{
392 struct fuse_file_info fi;
393
394 memset(&fi, 0, sizeof(fi));
395 fi.flags = arg->flags;
396
397 if (req->f->op.opendir)
398 req->f->op.opendir(req, nodeid, &fi);
399 else
400 fuse_reply_err(req, ENOSYS);
401}
402
403static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
404 struct fuse_read_in *arg)
405{
406 struct fuse_file_info fi;
407
408 memset(&fi, 0, sizeof(fi));
409 fi.fh = arg->fh;
410
411 if (req->f->op.readdir)
412 req->f->op.readdir(req, nodeid, arg->size, arg->offset, &fi);
413 else
414 fuse_reply_err(req, ENOSYS);
415}
416
417static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
418 struct fuse_release_in *arg)
419{
420 struct fuse_file_info fi;
421
422 memset(&fi, 0, sizeof(fi));
423 fi.flags = arg->flags;
424 fi.fh = arg->fh;
425
426 if (req->f->op.releasedir)
427 req->f->op.releasedir(req, nodeid, &fi);
428 else
429 fuse_reply_err(req, ENOSYS);
430}
431
432static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
433 struct fuse_fsync_in *inarg)
434{
435 struct fuse_file_info fi;
436
437 memset(&fi, 0, sizeof(fi));
438 fi.fh = inarg->fh;
439
440 if (req->f->op.fsyncdir)
441 req->f->op.fsyncdir(req, nodeid, inarg->fsync_flags & 1, &fi);
442 else
443 fuse_reply_err(req, ENOSYS);
444}
445
446static void do_statfs(fuse_req_t req, fuse_ino_t nodeid)
447{
448 if (req->f->op.statfs)
449 res = req->f->op.statfs(req, nodeid);
450 else
451 fuse_reply_err(req, ENOSYS);
Miklos Szeredi12744942005-07-11 12:32:31 +0000452}
453
454static void do_setxattr(struct fuse_ll *f, struct fuse_in_header *in,
455 struct fuse_setxattr_in *arg)
456{
457 int res;
458 char *path;
459 char *name = PARAM(arg);
460 unsigned char *value = name + strlen(name) + 1;
461
462 res = -ENOENT;
463 pthread_rwlock_rdlock(&f->tree_lock);
464 path = get_path(f, in->nodeid);
465 if (path != NULL) {
466 res = -ENOSYS;
467 if (f->op.setxattr)
468 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
469 free(path);
470 }
471 pthread_rwlock_unlock(&f->tree_lock);
472 send_reply(f, in, res, NULL, 0);
473}
474
475static int common_getxattr(struct fuse_ll *f, struct fuse_in_header *in,
476 const char *name, char *value, size_t size)
477{
478 int res;
479 char *path;
480
481 res = -ENOENT;
482 pthread_rwlock_rdlock(&f->tree_lock);
483 path = get_path(f, in->nodeid);
484 if (path != NULL) {
485 res = -ENOSYS;
486 if (f->op.getxattr)
487 res = f->op.getxattr(path, name, value, size);
488 free(path);
489 }
490 pthread_rwlock_unlock(&f->tree_lock);
491 return res;
492}
493
494static void do_getxattr_read(struct fuse_ll *f, struct fuse_in_header *in,
495 const char *name, size_t size)
496{
497 int res;
498 char *value = (char *) malloc(size);
499 if (value == NULL) {
500 send_reply(f, in, -ENOMEM, NULL, 0);
501 return;
502 }
503 res = common_getxattr(f, in, name, value, size);
504 size = 0;
505 if (res > 0) {
506 size = res;
507 res = 0;
508 }
509 send_reply(f, in, res, value, size);
510 free(value);
511}
512
513static void do_getxattr_size(struct fuse_ll *f, struct fuse_in_header *in,
514 const char *name)
515{
516 int res;
517 struct fuse_getxattr_out arg;
518
519 memset(&arg, 0, sizeof(arg));
520 res = common_getxattr(f, in, name, NULL, 0);
521 if (res >= 0) {
522 arg.size = res;
523 res = 0;
524 }
525 send_reply(f, in, res, &arg, SIZEOF_COMPAT(f, fuse_getxattr_out));
526}
527
528static void do_getxattr(struct fuse_ll *f, struct fuse_in_header *in,
529 struct fuse_getxattr_in *arg)
530{
531 char *name = PARAM(arg);
532
533 if (arg->size)
534 do_getxattr_read(f, in, name, arg->size);
535 else
536 do_getxattr_size(f, in, name);
537}
538
539static int common_listxattr(struct fuse_ll *f, struct fuse_in_header *in,
540 char *list, size_t size)
541{
542 int res;
543 char *path;
544
545 res = -ENOENT;
546 pthread_rwlock_rdlock(&f->tree_lock);
547 path = get_path(f, in->nodeid);
548 if (path != NULL) {
549 res = -ENOSYS;
550 if (f->op.listxattr)
551 res = f->op.listxattr(path, list, size);
552 free(path);
553 }
554 pthread_rwlock_unlock(&f->tree_lock);
555 return res;
556}
557
558static void do_listxattr_read(struct fuse_ll *f, struct fuse_in_header *in,
559 size_t size)
560{
561 int res;
562 char *list = (char *) malloc(size);
563 if (list == NULL) {
564 send_reply(f, in, -ENOMEM, NULL, 0);
565 return;
566 }
567 res = common_listxattr(f, in, list, size);
568 size = 0;
569 if (res > 0) {
570 size = res;
571 res = 0;
572 }
573 send_reply(f, in, res, list, size);
574 free(list);
575}
576
577static void do_listxattr_size(struct fuse_ll *f, struct fuse_in_header *in)
578{
579 int res;
580 struct fuse_getxattr_out arg;
581
582 memset(&arg, 0, sizeof(arg));
583 res = common_listxattr(f, in, NULL, 0);
584 if (res >= 0) {
585 arg.size = res;
586 res = 0;
587 }
588 send_reply(f, in, res, &arg, SIZEOF_COMPAT(f, fuse_getxattr_out));
589}
590
591static void do_listxattr(struct fuse_ll *f, struct fuse_in_header *in,
592 struct fuse_getxattr_in *arg)
593{
594 if (arg->size)
595 do_listxattr_read(f, in, arg->size);
596 else
597 do_listxattr_size(f, in);
598}
599
600static void do_removexattr(struct fuse_ll *f, struct fuse_in_header *in,
601 char *name)
602{
603 int res;
604 char *path;
605
606 res = -ENOENT;
607 pthread_rwlock_rdlock(&f->tree_lock);
608 path = get_path(f, in->nodeid);
609 if (path != NULL) {
610 res = -ENOSYS;
611 if (f->op.removexattr)
612 res = f->op.removexattr(path, name);
613 free(path);
614 }
615 pthread_rwlock_unlock(&f->tree_lock);
616 send_reply(f, in, res, NULL, 0);
617}
618
619static void do_init(struct fuse_ll *f, struct fuse_in_header *in,
620 struct fuse_init_in_out *arg)
621{
622 struct fuse_init_in_out outarg;
623
624 if (in->padding == 5) {
625 arg->minor = arg->major;
626 arg->major = in->padding;
627 }
628
629 if (f->flags & FUSE_DEBUG) {
630 printf("INIT: %u.%u\n", arg->major, arg->minor);
631 fflush(stdout);
632 }
633 f->got_init = 1;
634 if (f->op.init)
635 f->user_data = f->op.init();
636
637 if (arg->major == 5) {
638 f->major = 5;
639 f->minor = 1;
640 } else if (arg->major == 6) {
641 f->major = 6;
642 f->minor = 1;
643 } else {
644 f->major = FUSE_KERNEL_VERSION;
645 f->minor = FUSE_KERNEL_MINOR_VERSION;
646 }
647 memset(&outarg, 0, sizeof(outarg));
648 outarg.major = f->major;
649 outarg.minor = f->minor;
650
651 if (f->flags & FUSE_DEBUG) {
652 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
653 fflush(stdout);
654 }
655
656 send_reply(f, in, 0, &outarg, sizeof(outarg));
657}
658
Miklos Szeredi12744942005-07-11 12:32:31 +0000659static void free_cmd(struct fuse_cmd *cmd)
660{
661 free(cmd->buf);
662 free(cmd);
663}
664
665void fuse_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
666{
667 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
668 void *inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
669 struct fuse_context *ctx = fuse_get_context();
670
671 fuse_dec_avail(f);
672
673 if ((f->flags & FUSE_DEBUG)) {
674 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
675 in->unique, opname(in->opcode), in->opcode,
676 (unsigned long) in->nodeid, cmd->buflen);
677 fflush(stdout);
678 }
679
680 if (!f->got_init && in->opcode != FUSE_INIT) {
681 /* Old kernel version probably */
682 send_reply(f, in, -EPROTO, NULL, 0);
683 goto out;
684 }
685
686 if ((f->flags & FUSE_ALLOW_ROOT) && in->uid != f->owner && in->uid != 0 &&
687 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
688 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
689 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
690 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
691 send_reply(f, in, -EACCES, NULL, 0);
692 goto out;
693 }
694
695 ctx->fuse = f;
696 ctx->uid = in->uid;
697 ctx->gid = in->gid;
698 ctx->pid = in->pid;
699 ctx->private_data = f->user_data;
700
701 switch (in->opcode) {
702 case FUSE_LOOKUP:
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000703 do_lookup(f, req, nodeid, (char *) inarg);
Miklos Szeredi12744942005-07-11 12:32:31 +0000704 break;
705
Miklos Szeredi2482fdb2005-07-12 13:23:53 +0000706 do_forget(f, in, (struct fuse_forget_in *) inarg);
707 break;
708 }
Miklos Szeredi12744942005-07-11 12:32:31 +0000709 case FUSE_GETATTR:
710 do_getattr(f, in);
711 break;
712
713 case FUSE_SETATTR:
714 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
715 break;
716
717 case FUSE_READLINK:
718 do_readlink(f, in);
719 break;
720
721 case FUSE_MKNOD:
722 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
723 break;
724
725 case FUSE_MKDIR:
726 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
727 break;
728
729 case FUSE_UNLINK:
730 do_unlink(f, in, (char *) inarg);
731 break;
732
733 case FUSE_RMDIR:
734 do_rmdir(f, in, (char *) inarg);
735 break;
736
737 case FUSE_SYMLINK:
738 do_symlink(f, in, (char *) inarg,
739 ((char *) inarg) + strlen((char *) inarg) + 1);
740 break;
741
742 case FUSE_RENAME:
743 do_rename(f, in, (struct fuse_rename_in *) inarg);
744 break;
745
746 case FUSE_LINK:
747 do_link(f, in, (struct fuse_link_in *) inarg);
748 break;
749
750 case FUSE_OPEN:
751 do_open(f, in, (struct fuse_open_in *) inarg);
752 break;
753
754 case FUSE_FLUSH:
755 do_flush(f, in, (struct fuse_flush_in *) inarg);
756 break;
757
758 case FUSE_RELEASE:
759 do_release(f, in, (struct fuse_release_in *) inarg);
760 break;
761
762 case FUSE_READ:
763 do_read(f, in, (struct fuse_read_in *) inarg);
764 break;
765
766 case FUSE_WRITE:
767 do_write(f, in, (struct fuse_write_in *) inarg);
768 break;
769
770 case FUSE_STATFS:
771 do_statfs(f, in);
772 break;
773
774 case FUSE_FSYNC:
775 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
776 break;
777
778 case FUSE_SETXATTR:
779 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
780 break;
781
782 case FUSE_GETXATTR:
783 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
784 break;
785
786 case FUSE_LISTXATTR:
787 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
788 break;
789
790 case FUSE_REMOVEXATTR:
791 do_removexattr(f, in, (char *) inarg);
792 break;
793
794 case FUSE_INIT:
795 do_init(f, in, (struct fuse_init_in_out *) inarg);
796 break;
797
798 case FUSE_OPENDIR:
799 do_opendir(f, in, (struct fuse_open_in *) inarg);
800 break;
801
802 case FUSE_READDIR:
803 do_readdir(f, in, (struct fuse_read_in *) inarg);
804 break;
805
806 case FUSE_RELEASEDIR:
807 do_releasedir(f, in, (struct fuse_release_in *) inarg);
808 break;
809
810 case FUSE_FSYNCDIR:
811 do_fsyncdir(f, in, (struct fuse_fsync_in *) inarg);
812 break;
813
814 default:
815 send_reply(f, in, -ENOSYS, NULL, 0);
816 }
817
818 out:
819 free_cmd(cmd);
820}
821
822int fuse_exited(struct fuse_ll* f)
823{
824 return f->exited;
825}
826
827struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f)
828{
829 ssize_t res;
830 struct fuse_cmd *cmd;
831 struct fuse_in_header *in;
832 void *inarg;
833
834 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
835 if (cmd == NULL) {
836 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
837 return NULL;
838 }
839 cmd->buf = (char *) malloc(FUSE_MAX_IN);
840 if (cmd->buf == NULL) {
841 fprintf(stderr, "fuse: failed to allocate read buffer\n");
842 free(cmd);
843 return NULL;
844 }
845 in = (struct fuse_in_header *) cmd->buf;
846 inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
847
848 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
849 if (res == -1) {
850 free_cmd(cmd);
851 if (fuse_exited(f) || errno == EINTR || errno == ENOENT)
852 return NULL;
853
854 /* ENODEV means we got unmounted, so we silenty return failure */
855 if (errno != ENODEV) {
856 /* BAD... This will happen again */
857 perror("fuse: reading device");
858 }
859
860 fuse_exit(f);
861 return NULL;
862 }
863 if ((size_t) res < SIZEOF_COMPAT(f, fuse_in_header)) {
864 free_cmd(cmd);
865 /* Cannot happen */
866 fprintf(stderr, "short read on fuse device\n");
867 fuse_exit(f);
868 return NULL;
869 }
870 cmd->buflen = res;
871
Miklos Szeredi12744942005-07-11 12:32:31 +0000872
873 return cmd;
874}
875
876int fuse_loop(struct fuse_ll *f)
877{
878 if (f == NULL)
879 return -1;
880
881 while (1) {
882 struct fuse_cmd *cmd;
883
884 if (fuse_exited(f))
885 break;
886
887 cmd = fuse_read_cmd(f);
888 if (cmd == NULL)
889 continue;
890
891 fuse_process_cmd(f, cmd);
892 }
893 f->exited = 0;
894 return 0;
895}
896
897int fuse_invalidate(struct fuse_ll *f, const char *path)
898{
899 (void) f;
900 (void) path;
901 return -EINVAL;
902}
903
904void fuse_exit(struct fuse_ll *f)
905{
906 f->exited = 1;
907}
908
909struct fuse_context *fuse_get_context()
910{
911 static struct fuse_context context;
912 if (fuse_getcontext)
913 return fuse_getcontext();
914 else
915 return &context;
916}
917
918void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
919{
920 fuse_getcontext = func;
921}
922
923static int begins_with(const char *s, const char *beg)
924{
925 if (strncmp(s, beg, strlen(beg)) == 0)
926 return 1;
927 else
928 return 0;
929}
930
931int fuse_is_lib_option(const char *opt)
932{
933 if (strcmp(opt, "debug") == 0 ||
934 strcmp(opt, "hard_remove") == 0 ||
935 strcmp(opt, "use_ino") == 0 ||
936 strcmp(opt, "allow_root") == 0 ||
937 strcmp(opt, "readdir_ino") == 0 ||
938 begins_with(opt, "umask=") ||
939 begins_with(opt, "uid=") ||
940 begins_with(opt, "gid="))
941 return 1;
942 else
943 return 0;
944}
945
946static int parse_lib_opts(struct fuse_ll *f, const char *opts)
947{
948 if (opts) {
949 char *xopts = strdup(opts);
950 char *s = xopts;
951 char *opt;
952
953 if (xopts == NULL) {
954 fprintf(stderr, "fuse: memory allocation failed\n");
955 return -1;
956 }
957
958 while((opt = strsep(&s, ","))) {
959 if (strcmp(opt, "debug") == 0)
960 f->flags |= FUSE_DEBUG;
961 else if (strcmp(opt, "hard_remove") == 0)
962 f->flags |= FUSE_HARD_REMOVE;
963 else if (strcmp(opt, "use_ino") == 0)
964 f->flags |= FUSE_USE_INO;
965 else if (strcmp(opt, "allow_root") == 0)
966 f->flags |= FUSE_ALLOW_ROOT;
967 else if (strcmp(opt, "readdir_ino") == 0)
968 f->flags |= FUSE_READDIR_INO;
969 else if (sscanf(opt, "umask=%o", &f->umask) == 1)
970 f->flags |= FUSE_SET_MODE;
971 else if (sscanf(opt, "uid=%u", &f->uid) == 1)
972 f->flags |= FUSE_SET_UID;
973 else if(sscanf(opt, "gid=%u", &f->gid) == 1)
974 f->flags |= FUSE_SET_GID;
975 else
976 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
977 }
978 free(xopts);
979 }
980 return 0;
981}
982
983struct fuse_ll *fuse_lowlevel_new(int fd, const char *opts,
984 const struct fuse_lowlevel_operations *op,
985 size_t op_size)
986{
987 struct fuse_ll *f;
988
989 if (sizeof(struct fuse_lowlevel_operations) < op_size) {
990 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
991 op_size = sizeof(struct fuse_lowlevel_operations);
992 }
993
994 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
995 if (f == NULL) {
996 fprintf(stderr, "fuse: failed to allocate fuse object\n");
997 goto out;
998 }
999
1000 if (parse_lib_opts(f, opts) == -1)
1001 goto out_free;
1002
1003 f->fd = fd;
1004 memcpy(&f->op, op, op_size);
1005 f->exited = 0;
1006 f->owner = getuid();
1007
1008 return f;
1009
1010 out_free:
1011 free(f);
1012 out:
1013 return NULL;
1014}
1015
1016