blob: c5e1bf79404bca2f8df803019734158e98d768c8 [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
25/* FUSE flags: */
26
27/** Enable debuging output */
28#define FUSE_DEBUG (1 << 1)
29
30/** If a file is removed but it's still open, don't hide the file but
31 remove it immediately */
32#define FUSE_HARD_REMOVE (1 << 2)
33
34/** Use st_ino field in getattr instead of generating inode numbers */
35#define FUSE_USE_INO (1 << 3)
36
37/** Only allow root or the owner to access the filesystem */
38#define FUSE_ALLOW_ROOT (1 << 4)
39
40/** Make a best effort to fill in inode number in a readdir **/
41#define FUSE_READDIR_INO (1 << 5)
42
43/** Ignore file mode supplied by the filesystem, and create one based
44 on the 'umask' option */
45#define FUSE_SET_MODE (1 << 6)
46
47/** Ignore st_uid supplied by the filesystem and set it based on the
48 'uid' option*/
49#define FUSE_SET_UID (1 << 7)
50
51/** Ignore st_gid supplied by the filesystem and set it based on the
52 'gid' option*/
53#define FUSE_SET_GID (1 << 8)
54
55
56struct fuse_ll {
57 int flags;
58 int fd;
59 struct fuse_lowlevel_operations op;
60 volatile int exited;
61 int got_init;
62 void *user_data;
63 int major;
64 int minor;
65 uid_t owner;
66 uid_t uid;
67 gid_t gid;
68 mode_t umask;
69};
70
71struct fuse_cmd {
72 char *buf;
73 size_t buflen;
74};
75
76static const char *opname(enum fuse_opcode opcode)
77{
78 switch (opcode) {
79 case FUSE_LOOKUP: return "LOOKUP";
80 case FUSE_FORGET: return "FORGET";
81 case FUSE_GETATTR: return "GETATTR";
82 case FUSE_SETATTR: return "SETATTR";
83 case FUSE_READLINK: return "READLINK";
84 case FUSE_SYMLINK: return "SYMLINK";
85 case FUSE_MKNOD: return "MKNOD";
86 case FUSE_MKDIR: return "MKDIR";
87 case FUSE_UNLINK: return "UNLINK";
88 case FUSE_RMDIR: return "RMDIR";
89 case FUSE_RENAME: return "RENAME";
90 case FUSE_LINK: return "LINK";
91 case FUSE_OPEN: return "OPEN";
92 case FUSE_READ: return "READ";
93 case FUSE_WRITE: return "WRITE";
94 case FUSE_STATFS: return "STATFS";
95 case FUSE_FLUSH: return "FLUSH";
96 case FUSE_RELEASE: return "RELEASE";
97 case FUSE_FSYNC: return "FSYNC";
98 case FUSE_SETXATTR: return "SETXATTR";
99 case FUSE_GETXATTR: return "GETXATTR";
100 case FUSE_LISTXATTR: return "LISTXATTR";
101 case FUSE_REMOVEXATTR: return "REMOVEXATTR";
102 case FUSE_INIT: return "INIT";
103 case FUSE_OPENDIR: return "OPENDIR";
104 case FUSE_READDIR: return "READDIR";
105 case FUSE_RELEASEDIR: return "RELEASEDIR";
106 case FUSE_FSYNCDIR: return "FSYNCDIR";
107 default: return "???";
108 }
109}
110
111
112static void convert_stat(struct fuse_ll *f, nodeid_t nodeid, struct stat *stbuf,
113 struct fuse_attr *attr)
114{
115 attr->ino = (f->flags & FUSE_USE_INO) ? stbuf->st_ino : nodeid;
116 attr->mode = stbuf->st_mode;
117 if (f->flags & FUSE_SET_MODE)
118 attr->mode = (attr->mode & S_IFMT) | (0777 & ~f->umask);
119 attr->nlink = stbuf->st_nlink;
120 attr->uid = (f->flags & FUSE_SET_UID) ? f->uid : stbuf->st_uid;
121 attr->gid = (f->flags & FUSE_SET_GID) ? f->gid : stbuf->st_gid;
122 attr->rdev = stbuf->st_rdev;
123 attr->size = stbuf->st_size;
124 attr->blocks = stbuf->st_blocks;
125 attr->atime = stbuf->st_atime;
126 attr->mtime = stbuf->st_mtime;
127 attr->ctime = stbuf->st_ctime;
128#ifdef HAVE_STRUCT_STAT_ST_ATIM
129 attr->atimensec = stbuf->st_atim.tv_nsec;
130 attr->mtimensec = stbuf->st_mtim.tv_nsec;
131 attr->ctimensec = stbuf->st_ctim.tv_nsec;
132#endif
133}
134
135static size_t iov_length(const struct iovec *iov, size_t count)
136{
137 size_t seg;
138 size_t ret = 0;
139
140 for (seg = 0; seg < count; seg++)
141 ret += iov[seg].iov_len;
142 return ret;
143}
144
145static int send_reply_raw(struct fuse_ll *f, const struct iovec iov[],
146 size_t count)
147{
148 int res;
149 unsigned outsize = iov_length(iov, count);
150 struct fuse_out_header *out = (struct fuse_out_header *) iov[0].iov_base;
151 out->len = outsize;
152
153 if ((f->flags & FUSE_DEBUG)) {
154 printf(" unique: %llu, error: %i (%s), outsize: %i\n",
155 out->unique, out->error, strerror(-out->error), outsize);
156 fflush(stdout);
157 }
158
159 /* This needs to be done before the reply, otherwise the scheduler
160 could play tricks with us, and only let the counter be
161 increased long after the operation is done */
162 fuse_inc_avail(f);
163
164 res = writev(f->fd, iov, count);
165 if (res == -1) {
166 /* ENOENT means the operation was interrupted */
167 if (!f->exited && errno != ENOENT)
168 perror("fuse: writing device");
169 return -errno;
170 }
171 return 0;
172}
173
174static int send_reply(struct fuse_ll *f, struct fuse_in_header *in, int error,
175 void *arg, size_t argsize)
176{
177 struct fuse_out_header out;
178 struct iovec iov[2];
179 size_t count;
180
181 if (error <= -1000 || error > 0) {
182 fprintf(stderr, "fuse: bad error value: %i\n", error);
183 error = -ERANGE;
184 }
185
186 out.unique = in->unique;
187 out.error = error;
188 count = 1;
189 iov[0].iov_base = &out;
190 iov[0].iov_len = sizeof(struct fuse_out_header);
191 if (argsize && !error) {
192 count++;
193 iov[1].iov_base = arg;
194 iov[1].iov_len = argsize;
195 }
196 return send_reply_raw(f, iov, count);
197}
198
199static void do_lookup(struct fuse_ll *f, struct fuse_in_header *in, char *name)
200{
201 int res;
202 int res2;
203 char *path;
204 struct fuse_entry_out arg;
205
206 res = -ENOENT;
207 pthread_rwlock_rdlock(&f->tree_lock);
208 path = get_path_name(f, in->nodeid, name);
209 if (path != NULL) {
210 if (f->flags & FUSE_DEBUG) {
211 printf("LOOKUP %s\n", path);
212 fflush(stdout);
213 }
214 res = -ENOSYS;
215 if (f->op.getattr)
216 res = lookup_path(f, in->nodeid, in->unique, name, path, &arg);
217 free(path);
218 }
219 pthread_rwlock_unlock(&f->tree_lock);
220 res2 = send_reply(f, in, res, &arg, sizeof(arg));
221 if (res == 0 && res2 == -ENOENT)
222 cancel_lookup(f, arg.nodeid, in->unique);
223}
224
225static void do_forget(struct fuse_ll *f, struct fuse_in_header *in,
226 struct fuse_forget_in *arg)
227{
228 if (f->flags & FUSE_DEBUG) {
229 printf("FORGET %lu/%llu\n", (unsigned long) in->nodeid,
230 arg->nlookup);
231 fflush(stdout);
232 }
233 if (f->major <= 6)
234 forget_node_old(f, in->nodeid, arg->nlookup);
235 else
236 forget_node(f, in->nodeid, arg->nlookup);
237}
238
239static void do_getattr(struct fuse_ll *f, struct fuse_in_header *in)
240{
241 int res;
242 char *path;
243 struct stat buf;
244 struct fuse_attr_out arg;
245
246 res = -ENOENT;
247 pthread_rwlock_rdlock(&f->tree_lock);
248 path = get_path(f, in->nodeid);
249 if (path != NULL) {
250 res = -ENOSYS;
251 if (f->op.getattr)
252 res = f->op.getattr(path, &buf);
253 free(path);
254 }
255 pthread_rwlock_unlock(&f->tree_lock);
256
257 if (res == 0) {
258 memset(&arg, 0, sizeof(struct fuse_attr_out));
259 arg.attr_valid = ATTR_REVALIDATE_TIME;
260 arg.attr_valid_nsec = 0;
261 convert_stat(f, in->nodeid, &buf, &arg.attr);
262 }
263
264 send_reply(f, in, res, &arg, sizeof(arg));
265}
266
267static int do_chmod(struct fuse_ll *f, const char *path, struct fuse_attr *attr)
268{
269 int res;
270
271 res = -ENOSYS;
272 if (f->op.chmod)
273 res = f->op.chmod(path, attr->mode);
274
275 return res;
276}
277
278static int do_chown(struct fuse_ll *f, const char *path, struct fuse_attr *attr,
279 int valid)
280{
281 int res;
282 uid_t uid = (valid & FATTR_UID) ? attr->uid : (uid_t) -1;
283 gid_t gid = (valid & FATTR_GID) ? attr->gid : (gid_t) -1;
284
285 res = -ENOSYS;
286 if (f->op.chown)
287 res = f->op.chown(path, uid, gid);
288
289 return res;
290}
291
292static int do_truncate(struct fuse_ll *f, const char *path,
293 struct fuse_attr *attr)
294{
295 int res;
296
297 res = -ENOSYS;
298 if (f->op.truncate)
299 res = f->op.truncate(path, attr->size);
300
301 return res;
302}
303
304static int do_utime(struct fuse_ll *f, const char *path, struct fuse_attr *attr)
305{
306 int res;
307 struct utimbuf buf;
308 buf.actime = attr->atime;
309 buf.modtime = attr->mtime;
310 res = -ENOSYS;
311 if (f->op.utime)
312 res = f->op.utime(path, &buf);
313
314 return res;
315}
316
317static void do_setattr(struct fuse_ll *f, struct fuse_in_header *in,
318 struct fuse_setattr_in *arg)
319{
320 int res;
321 char *path;
322 int valid = arg->valid;
323 struct fuse_attr *attr = MEMBER_COMPAT(f, arg, attr, fuse_setattr_in);
324 struct fuse_attr_out outarg;
325
326 res = -ENOENT;
327 pthread_rwlock_rdlock(&f->tree_lock);
328 path = get_path(f, in->nodeid);
329 if (path != NULL) {
330 res = -ENOSYS;
331 if (f->op.getattr) {
332 res = 0;
333 if (!res && (valid & FATTR_MODE))
334 res = do_chmod(f, path, attr);
335 if (!res && (valid & (FATTR_UID | FATTR_GID)))
336 res = do_chown(f, path, attr, valid);
337 if (!res && (valid & FATTR_SIZE))
338 res = do_truncate(f, path, attr);
339 if (!res && (valid & (FATTR_ATIME | FATTR_MTIME)) ==
340 (FATTR_ATIME | FATTR_MTIME))
341 res = do_utime(f, path, attr);
342 if (!res) {
343 struct stat buf;
344 res = f->op.getattr(path, &buf);
345 if (!res) {
346 memset(&outarg, 0, sizeof(struct fuse_attr_out));
347 outarg.attr_valid = ATTR_REVALIDATE_TIME;
348 outarg.attr_valid_nsec = 0;
349 convert_stat(f, in->nodeid, &buf, &outarg.attr);
350 }
351 }
352 }
353 free(path);
354 }
355 pthread_rwlock_unlock(&f->tree_lock);
356 send_reply(f, in, res, &outarg, sizeof(outarg));
357}
358
359static void do_readlink(struct fuse_ll *f, struct fuse_in_header *in)
360{
361 int res;
362 char link[PATH_MAX + 1];
363 char *path;
364
365 res = -ENOENT;
366 pthread_rwlock_rdlock(&f->tree_lock);
367 path = get_path(f, in->nodeid);
368 if (path != NULL) {
369 res = -ENOSYS;
370 if (f->op.readlink)
371 res = f->op.readlink(path, link, sizeof(link));
372 free(path);
373 }
374 pthread_rwlock_unlock(&f->tree_lock);
375 link[PATH_MAX] = '\0';
376 send_reply(f, in, res, link, res == 0 ? strlen(link) : 0);
377}
378
379static void do_mknod(struct fuse_ll *f, struct fuse_in_header *in,
380 struct fuse_mknod_in *inarg)
381{
382 int res;
383 int res2;
384 char *path;
385 char *name = PARAM(inarg);
386 struct fuse_entry_out outarg;
387
388 res = -ENOENT;
389 pthread_rwlock_rdlock(&f->tree_lock);
390 path = get_path_name(f, in->nodeid, name);
391 if (path != NULL) {
392 if (f->flags & FUSE_DEBUG) {
393 printf("MKNOD %s\n", path);
394 fflush(stdout);
395 }
396 res = -ENOSYS;
397 if (f->op.mknod && f->op.getattr) {
398 res = f->op.mknod(path, inarg->mode, inarg->rdev);
399 if (res == 0)
400 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
401 }
402 free(path);
403 }
404 pthread_rwlock_unlock(&f->tree_lock);
405 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
406 if (res == 0 && res2 == -ENOENT)
407 cancel_lookup(f, outarg.nodeid, in->unique);
408}
409
410static void do_mkdir(struct fuse_ll *f, struct fuse_in_header *in,
411 struct fuse_mkdir_in *inarg)
412{
413 int res;
414 int res2;
415 char *path;
416 char *name = PARAM_COMPAT(f, inarg, fuse_mkdir_in);
417 struct fuse_entry_out outarg;
418
419 res = -ENOENT;
420 pthread_rwlock_rdlock(&f->tree_lock);
421 path = get_path_name(f, in->nodeid, name);
422 if (path != NULL) {
423 if (f->flags & FUSE_DEBUG) {
424 printf("MKDIR %s\n", path);
425 fflush(stdout);
426 }
427 res = -ENOSYS;
428 if (f->op.mkdir && f->op.getattr) {
429 res = f->op.mkdir(path, inarg->mode);
430 if (res == 0)
431 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
432 }
433 free(path);
434 }
435 pthread_rwlock_unlock(&f->tree_lock);
436 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
437 if (res == 0 && res2 == -ENOENT)
438 cancel_lookup(f, outarg.nodeid, in->unique);
439}
440
441static void do_unlink(struct fuse_ll *f, struct fuse_in_header *in, char *name)
442{
443 int res;
444 char *path;
445
446 res = -ENOENT;
447 pthread_rwlock_wrlock(&f->tree_lock);
448 path = get_path_name(f, in->nodeid, name);
449 if (path != NULL) {
450 if (f->flags & FUSE_DEBUG) {
451 printf("UNLINK %s\n", path);
452 fflush(stdout);
453 }
454 res = -ENOSYS;
455 if (f->op.unlink) {
456 if (!(f->flags & FUSE_HARD_REMOVE) && is_open(f, in->nodeid, name))
457 res = hide_node(f, path, in->nodeid, name);
458 else {
459 res = f->op.unlink(path);
460 if (res == 0)
461 remove_node(f, in->nodeid, name);
462
463 }
464 }
465 free(path);
466 }
467 pthread_rwlock_unlock(&f->tree_lock);
468 send_reply(f, in, res, NULL, 0);
469}
470
471static void do_rmdir(struct fuse_ll *f, struct fuse_in_header *in, char *name)
472{
473 int res;
474 char *path;
475
476 res = -ENOENT;
477 pthread_rwlock_wrlock(&f->tree_lock);
478 path = get_path_name(f, in->nodeid, name);
479 if (path != NULL) {
480 if (f->flags & FUSE_DEBUG) {
481 printf("RMDIR %s\n", path);
482 fflush(stdout);
483 }
484 res = -ENOSYS;
485 if (f->op.rmdir) {
486 res = f->op.rmdir(path);
487 if (res == 0)
488 remove_node(f, in->nodeid, name);
489 }
490 free(path);
491 }
492 pthread_rwlock_unlock(&f->tree_lock);
493 send_reply(f, in, res, NULL, 0);
494}
495
496static void do_symlink(struct fuse_ll *f, struct fuse_in_header *in, char *name,
497 char *link)
498{
499 int res;
500 int res2;
501 char *path;
502 struct fuse_entry_out outarg;
503
504 res = -ENOENT;
505 pthread_rwlock_rdlock(&f->tree_lock);
506 path = get_path_name(f, in->nodeid, name);
507 if (path != NULL) {
508 if (f->flags & FUSE_DEBUG) {
509 printf("SYMLINK %s\n", path);
510 fflush(stdout);
511 }
512 res = -ENOSYS;
513 if (f->op.symlink && f->op.getattr) {
514 res = f->op.symlink(link, path);
515 if (res == 0)
516 res = lookup_path(f, in->nodeid, in->unique, name, path, &outarg);
517 }
518 free(path);
519 }
520 pthread_rwlock_unlock(&f->tree_lock);
521 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
522 if (res == 0 && res2 == -ENOENT)
523 cancel_lookup(f, outarg.nodeid, in->unique);
524
525}
526
527static void do_rename(struct fuse_ll *f, struct fuse_in_header *in,
528 struct fuse_rename_in *inarg)
529{
530 int res;
531 nodeid_t olddir = in->nodeid;
532 nodeid_t newdir = inarg->newdir;
533 char *oldname = PARAM(inarg);
534 char *newname = oldname + strlen(oldname) + 1;
535 char *oldpath;
536 char *newpath;
537
538 res = -ENOENT;
539 pthread_rwlock_wrlock(&f->tree_lock);
540 oldpath = get_path_name(f, olddir, oldname);
541 if (oldpath != NULL) {
542 newpath = get_path_name(f, newdir, newname);
543 if (newpath != NULL) {
544 if (f->flags & FUSE_DEBUG) {
545 printf("RENAME %s -> %s\n", oldpath, newpath);
546 fflush(stdout);
547 }
548 res = -ENOSYS;
549 if (f->op.rename) {
550 res = 0;
551 if (!(f->flags & FUSE_HARD_REMOVE) &&
552 is_open(f, newdir, newname))
553 res = hide_node(f, newpath, newdir, newname);
554 if (res == 0) {
555 res = f->op.rename(oldpath, newpath);
556 if (res == 0)
557 res = rename_node(f, olddir, oldname, newdir, newname, 0);
558 }
559 }
560 free(newpath);
561 }
562 free(oldpath);
563 }
564 pthread_rwlock_unlock(&f->tree_lock);
565 send_reply(f, in, res, NULL, 0);
566}
567
568static void do_link(struct fuse_ll *f, struct fuse_in_header *in,
569 struct fuse_link_in *arg)
570{
571 int res;
572 int res2;
573 char *oldpath;
574 char *newpath;
575 char *name = PARAM(arg);
576 struct fuse_entry_out outarg;
577
578 res = -ENOENT;
579 pthread_rwlock_rdlock(&f->tree_lock);
580 oldpath = get_path(f, arg->oldnodeid);
581 if (oldpath != NULL) {
582 newpath = get_path_name(f, in->nodeid, name);
583 if (newpath != NULL) {
584 if (f->flags & FUSE_DEBUG) {
585 printf("LINK %s\n", newpath);
586 fflush(stdout);
587 }
588 res = -ENOSYS;
589 if (f->op.link && f->op.getattr) {
590 res = f->op.link(oldpath, newpath);
591 if (res == 0)
592 res = lookup_path(f, in->nodeid, in->unique, name,
593 newpath, &outarg);
594 }
595 free(newpath);
596 }
597 free(oldpath);
598 }
599 pthread_rwlock_unlock(&f->tree_lock);
600 res2 = send_reply(f, in, res, &outarg, sizeof(outarg));
601 if (res == 0 && res2 == -ENOENT)
602 cancel_lookup(f, outarg.nodeid, in->unique);
603}
604
605static void do_open(struct fuse_ll *f, struct fuse_in_header *in,
606 struct fuse_open_in *arg)
607{
608 int res;
609 char *path;
610 struct fuse_open_out outarg;
611 struct fuse_file_info fi;
612
613 memset(&outarg, 0, sizeof(outarg));
614 memset(&fi, 0, sizeof(fi));
615 fi.flags = arg->flags;
616 res = -ENOENT;
617 pthread_rwlock_rdlock(&f->tree_lock);
618 path = get_path(f, in->nodeid);
619 if (path != NULL) {
620 res = -ENOSYS;
621 if (f->op.open) {
622 if (!f->compat)
623 res = f->op.open(path, &fi);
624 else
625 res = ((struct fuse_operations_compat2 *) &f->op)->open(path, fi.flags);
626 }
627 }
628 if (res == 0) {
629 int res2;
630 outarg.fh = fi.fh;
631 if (f->flags & FUSE_DEBUG) {
632 printf("OPEN[%lu] flags: 0x%x\n", fi.fh, arg->flags);
633 fflush(stdout);
634 }
635
636 pthread_mutex_lock(&f->lock);
637 res2 = send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
638 if(res2 == -ENOENT) {
639 /* The open syscall was interrupted, so it must be cancelled */
640 if(f->op.release) {
641 if (!f->compat)
642 f->op.release(path, &fi);
643 else
644 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
645 }
646 } else {
647 struct node *node = get_node(f, in->nodeid);
648 node->open_count ++;
649 }
650 pthread_mutex_unlock(&f->lock);
651 } else
652 send_reply(f, in, res, NULL, 0);
653
654 if (path)
655 free(path);
656 pthread_rwlock_unlock(&f->tree_lock);
657}
658
659static void do_flush(struct fuse_ll *f, struct fuse_in_header *in,
660 struct fuse_flush_in *arg)
661{
662 char *path;
663 int res;
664 struct fuse_file_info fi;
665
666 memset(&fi, 0, sizeof(fi));
667 fi.fh = arg->fh;
668 res = -ENOENT;
669 pthread_rwlock_rdlock(&f->tree_lock);
670 path = get_path(f, in->nodeid);
671 if (path != NULL) {
672 if (f->flags & FUSE_DEBUG) {
673 printf("FLUSH[%lu]\n", (unsigned long) arg->fh);
674 fflush(stdout);
675 }
676 res = -ENOSYS;
677 if (f->op.flush)
678 res = f->op.flush(path, &fi);
679 free(path);
680 }
681 pthread_rwlock_unlock(&f->tree_lock);
682 send_reply(f, in, res, NULL, 0);
683}
684
685static void do_release(struct fuse_ll *f, struct fuse_in_header *in,
686 struct fuse_release_in *arg)
687{
688 struct node *node;
689 char *path;
690 struct fuse_file_info fi;
691 int unlink_hidden;
692
693 memset(&fi, 0, sizeof(fi));
694 fi.flags = arg->flags;
695 fi.fh = arg->fh;
696
697 pthread_mutex_lock(&f->lock);
698 node = get_node(f, in->nodeid);
699 assert(node->open_count > 0);
700 --node->open_count;
701 unlink_hidden = (node->is_hidden && !node->open_count);
702 pthread_mutex_unlock(&f->lock);
703
704 pthread_rwlock_rdlock(&f->tree_lock);
705 path = get_path(f, in->nodeid);
706 if (f->flags & FUSE_DEBUG) {
707 printf("RELEASE[%lu] flags: 0x%x\n", fi.fh, fi.flags);
708 fflush(stdout);
709 }
710 if (f->op.release) {
711 if (!f->compat)
712 f->op.release(path ? path : "-", &fi);
713 else if (path)
714 ((struct fuse_operations_compat2 *) &f->op)->release(path, fi.flags);
715 }
716
717 if(unlink_hidden && path)
718 f->op.unlink(path);
719
720 if (path)
721 free(path);
722 pthread_rwlock_unlock(&f->tree_lock);
723
724 send_reply(f, in, 0, NULL, 0);
725}
726
727static void do_read(struct fuse_ll *f, struct fuse_in_header *in,
728 struct fuse_read_in *arg)
729{
730 int res;
731 char *path;
732 size_t size;
733 char *buf;
734 struct fuse_file_info fi;
735
736 buf = (char *) malloc(arg->size);
737 if (buf == NULL) {
738 send_reply(f, in, -ENOMEM, NULL, 0);
739 return;
740 }
741
742 memset(&fi, 0, sizeof(fi));
743 fi.fh = arg->fh;
744
745 res = -ENOENT;
746 pthread_rwlock_rdlock(&f->tree_lock);
747 path = get_path(f, in->nodeid);
748 if (path != NULL) {
749 if (f->flags & FUSE_DEBUG) {
750 printf("READ[%lu] %u bytes from %llu\n",
751 (unsigned long) arg->fh, arg->size, arg->offset);
752 fflush(stdout);
753 }
754
755 res = -ENOSYS;
756 if (f->op.read)
757 res = f->op.read(path, buf, arg->size, arg->offset, &fi);
758 free(path);
759 }
760 pthread_rwlock_unlock(&f->tree_lock);
761
762 size = 0;
763 if (res >= 0) {
764 size = res;
765 res = 0;
766 if (f->flags & FUSE_DEBUG) {
767 printf(" READ[%lu] %u bytes\n", (unsigned long) arg->fh,
768 size);
769 fflush(stdout);
770 }
771 }
772
773 send_reply(f, in, res, buf, size);
774 free(buf);
775}
776
777static void do_write(struct fuse_ll *f, struct fuse_in_header *in,
778 struct fuse_write_in *arg)
779{
780 int res;
781 char *path;
782 struct fuse_write_out outarg;
783 struct fuse_file_info fi;
784
785 memset(&fi, 0, sizeof(fi));
786 fi.fh = arg->fh;
787 fi.writepage = arg->write_flags & 1;
788
789 res = -ENOENT;
790 pthread_rwlock_rdlock(&f->tree_lock);
791 path = get_path(f, in->nodeid);
792 if (path != NULL) {
793 if (f->flags & FUSE_DEBUG) {
794 printf("WRITE%s[%lu] %u bytes to %llu\n",
795 (arg->write_flags & 1) ? "PAGE" : "",
796 (unsigned long) arg->fh, arg->size, arg->offset);
797 fflush(stdout);
798 }
799
800 res = -ENOSYS;
801 if (f->op.write)
802 res = f->op.write(path, PARAM(arg), arg->size, arg->offset, &fi);
803 free(path);
804 }
805 pthread_rwlock_unlock(&f->tree_lock);
806
807 memset(&outarg, 0, sizeof(outarg));
808 if (res >= 0) {
809 outarg.size = res;
810 res = 0;
811 }
812
813 send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_write_out));
814}
815
816static int default_statfs(struct statfs *buf)
817{
818 buf->f_namelen = 255;
819 buf->f_bsize = 512;
820 return 0;
821}
822
823static void convert_statfs_compat(struct fuse_statfs_compat1 *compatbuf,
824 struct statfs *statfs)
825{
826 statfs->f_bsize = compatbuf->block_size;
827 statfs->f_blocks = compatbuf->blocks;
828 statfs->f_bfree = compatbuf->blocks_free;
829 statfs->f_bavail = compatbuf->blocks_free;
830 statfs->f_files = compatbuf->files;
831 statfs->f_ffree = compatbuf->files_free;
832 statfs->f_namelen = compatbuf->namelen;
833}
834
835static void convert_statfs(struct statfs *statfs, struct fuse_kstatfs *kstatfs)
836{
837 kstatfs->bsize = statfs->f_bsize;
838 kstatfs->blocks = statfs->f_blocks;
839 kstatfs->bfree = statfs->f_bfree;
840 kstatfs->bavail = statfs->f_bavail;
841 kstatfs->files = statfs->f_files;
842 kstatfs->ffree = statfs->f_ffree;
843 kstatfs->namelen = statfs->f_namelen;
844}
845
846static void do_statfs(struct fuse_ll *f, struct fuse_in_header *in)
847{
848 int res;
849 struct fuse_statfs_out arg;
850 struct statfs buf;
851
852 memset(&buf, 0, sizeof(struct statfs));
853 if (f->op.statfs) {
854 if (!f->compat || f->compat > 11)
855 res = f->op.statfs("/", &buf);
856 else {
857 struct fuse_statfs_compat1 compatbuf;
858 memset(&compatbuf, 0, sizeof(struct fuse_statfs_compat1));
859 res = ((struct fuse_operations_compat1 *) &f->op)->statfs(&compatbuf);
860 if (res == 0)
861 convert_statfs_compat(&compatbuf, &buf);
862 }
863 }
864 else
865 res = default_statfs(&buf);
866
867 if (res == 0)
868 convert_statfs(&buf, &arg.st);
869
870 send_reply(f, in, res, &arg, sizeof(arg));
871}
872
873static void do_fsync(struct fuse_ll *f, struct fuse_in_header *in,
874 struct fuse_fsync_in *inarg)
875{
876 int res;
877 char *path;
878 struct fuse_file_info fi;
879
880 memset(&fi, 0, sizeof(fi));
881 fi.fh = inarg->fh;
882
883 res = -ENOENT;
884 pthread_rwlock_rdlock(&f->tree_lock);
885 path = get_path(f, in->nodeid);
886 if (path != NULL) {
887 if (f->flags & FUSE_DEBUG) {
888 printf("FSYNC[%lu]\n", (unsigned long) inarg->fh);
889 fflush(stdout);
890 }
891 res = -ENOSYS;
892 if (f->op.fsync)
893 res = f->op.fsync(path, inarg->fsync_flags & 1, &fi);
894 free(path);
895 }
896 pthread_rwlock_unlock(&f->tree_lock);
897 send_reply(f, in, res, NULL, 0);
898}
899
900static void do_setxattr(struct fuse_ll *f, struct fuse_in_header *in,
901 struct fuse_setxattr_in *arg)
902{
903 int res;
904 char *path;
905 char *name = PARAM(arg);
906 unsigned char *value = name + strlen(name) + 1;
907
908 res = -ENOENT;
909 pthread_rwlock_rdlock(&f->tree_lock);
910 path = get_path(f, in->nodeid);
911 if (path != NULL) {
912 res = -ENOSYS;
913 if (f->op.setxattr)
914 res = f->op.setxattr(path, name, value, arg->size, arg->flags);
915 free(path);
916 }
917 pthread_rwlock_unlock(&f->tree_lock);
918 send_reply(f, in, res, NULL, 0);
919}
920
921static int common_getxattr(struct fuse_ll *f, struct fuse_in_header *in,
922 const char *name, char *value, size_t size)
923{
924 int res;
925 char *path;
926
927 res = -ENOENT;
928 pthread_rwlock_rdlock(&f->tree_lock);
929 path = get_path(f, in->nodeid);
930 if (path != NULL) {
931 res = -ENOSYS;
932 if (f->op.getxattr)
933 res = f->op.getxattr(path, name, value, size);
934 free(path);
935 }
936 pthread_rwlock_unlock(&f->tree_lock);
937 return res;
938}
939
940static void do_getxattr_read(struct fuse_ll *f, struct fuse_in_header *in,
941 const char *name, size_t size)
942{
943 int res;
944 char *value = (char *) malloc(size);
945 if (value == NULL) {
946 send_reply(f, in, -ENOMEM, NULL, 0);
947 return;
948 }
949 res = common_getxattr(f, in, name, value, size);
950 size = 0;
951 if (res > 0) {
952 size = res;
953 res = 0;
954 }
955 send_reply(f, in, res, value, size);
956 free(value);
957}
958
959static void do_getxattr_size(struct fuse_ll *f, struct fuse_in_header *in,
960 const char *name)
961{
962 int res;
963 struct fuse_getxattr_out arg;
964
965 memset(&arg, 0, sizeof(arg));
966 res = common_getxattr(f, in, name, NULL, 0);
967 if (res >= 0) {
968 arg.size = res;
969 res = 0;
970 }
971 send_reply(f, in, res, &arg, SIZEOF_COMPAT(f, fuse_getxattr_out));
972}
973
974static void do_getxattr(struct fuse_ll *f, struct fuse_in_header *in,
975 struct fuse_getxattr_in *arg)
976{
977 char *name = PARAM(arg);
978
979 if (arg->size)
980 do_getxattr_read(f, in, name, arg->size);
981 else
982 do_getxattr_size(f, in, name);
983}
984
985static int common_listxattr(struct fuse_ll *f, struct fuse_in_header *in,
986 char *list, size_t size)
987{
988 int res;
989 char *path;
990
991 res = -ENOENT;
992 pthread_rwlock_rdlock(&f->tree_lock);
993 path = get_path(f, in->nodeid);
994 if (path != NULL) {
995 res = -ENOSYS;
996 if (f->op.listxattr)
997 res = f->op.listxattr(path, list, size);
998 free(path);
999 }
1000 pthread_rwlock_unlock(&f->tree_lock);
1001 return res;
1002}
1003
1004static void do_listxattr_read(struct fuse_ll *f, struct fuse_in_header *in,
1005 size_t size)
1006{
1007 int res;
1008 char *list = (char *) malloc(size);
1009 if (list == NULL) {
1010 send_reply(f, in, -ENOMEM, NULL, 0);
1011 return;
1012 }
1013 res = common_listxattr(f, in, list, size);
1014 size = 0;
1015 if (res > 0) {
1016 size = res;
1017 res = 0;
1018 }
1019 send_reply(f, in, res, list, size);
1020 free(list);
1021}
1022
1023static void do_listxattr_size(struct fuse_ll *f, struct fuse_in_header *in)
1024{
1025 int res;
1026 struct fuse_getxattr_out arg;
1027
1028 memset(&arg, 0, sizeof(arg));
1029 res = common_listxattr(f, in, NULL, 0);
1030 if (res >= 0) {
1031 arg.size = res;
1032 res = 0;
1033 }
1034 send_reply(f, in, res, &arg, SIZEOF_COMPAT(f, fuse_getxattr_out));
1035}
1036
1037static void do_listxattr(struct fuse_ll *f, struct fuse_in_header *in,
1038 struct fuse_getxattr_in *arg)
1039{
1040 if (arg->size)
1041 do_listxattr_read(f, in, arg->size);
1042 else
1043 do_listxattr_size(f, in);
1044}
1045
1046static void do_removexattr(struct fuse_ll *f, struct fuse_in_header *in,
1047 char *name)
1048{
1049 int res;
1050 char *path;
1051
1052 res = -ENOENT;
1053 pthread_rwlock_rdlock(&f->tree_lock);
1054 path = get_path(f, in->nodeid);
1055 if (path != NULL) {
1056 res = -ENOSYS;
1057 if (f->op.removexattr)
1058 res = f->op.removexattr(path, name);
1059 free(path);
1060 }
1061 pthread_rwlock_unlock(&f->tree_lock);
1062 send_reply(f, in, res, NULL, 0);
1063}
1064
1065static void do_init(struct fuse_ll *f, struct fuse_in_header *in,
1066 struct fuse_init_in_out *arg)
1067{
1068 struct fuse_init_in_out outarg;
1069
1070 if (in->padding == 5) {
1071 arg->minor = arg->major;
1072 arg->major = in->padding;
1073 }
1074
1075 if (f->flags & FUSE_DEBUG) {
1076 printf("INIT: %u.%u\n", arg->major, arg->minor);
1077 fflush(stdout);
1078 }
1079 f->got_init = 1;
1080 if (f->op.init)
1081 f->user_data = f->op.init();
1082
1083 if (arg->major == 5) {
1084 f->major = 5;
1085 f->minor = 1;
1086 } else if (arg->major == 6) {
1087 f->major = 6;
1088 f->minor = 1;
1089 } else {
1090 f->major = FUSE_KERNEL_VERSION;
1091 f->minor = FUSE_KERNEL_MINOR_VERSION;
1092 }
1093 memset(&outarg, 0, sizeof(outarg));
1094 outarg.major = f->major;
1095 outarg.minor = f->minor;
1096
1097 if (f->flags & FUSE_DEBUG) {
1098 printf(" INIT: %u.%u\n", outarg.major, outarg.minor);
1099 fflush(stdout);
1100 }
1101
1102 send_reply(f, in, 0, &outarg, sizeof(outarg));
1103}
1104
1105static struct fuse_dirhandle *get_dirhandle(unsigned long fh)
1106{
1107 return (struct fuse_dirhandle *) fh;
1108}
1109
1110static void do_opendir(struct fuse_ll *f, struct fuse_in_header *in,
1111 struct fuse_open_in *arg)
1112{
1113 int res;
1114 struct fuse_open_out outarg;
1115 struct fuse_dirhandle *dh;
1116
1117 dh = (struct fuse_dirhandle *) malloc(sizeof(struct fuse_dirhandle));
1118 if (dh == NULL) {
1119 send_reply(f, in, -ENOMEM, NULL, 0);
1120 return;
1121 }
1122 memset(dh, 0, sizeof(struct fuse_dirhandle));
1123 dh->fuse = f;
1124 dh->contents = NULL;
1125 dh->len = 0;
1126 dh->filled = 0;
1127 dh->nodeid = in->nodeid;
1128 mutex_init(&dh->lock);
1129
1130 memset(&outarg, 0, sizeof(outarg));
1131 outarg.fh = (unsigned long) dh;
1132
1133 if (f->op.opendir) {
1134 struct fuse_file_info fi;
1135 char *path;
1136
1137 memset(&fi, 0, sizeof(fi));
1138 fi.flags = arg->flags;
1139
1140 res = -ENOENT;
1141 pthread_rwlock_rdlock(&f->tree_lock);
1142 path = get_path(f, in->nodeid);
1143 if (path != NULL) {
1144 res = f->op.opendir(path, &fi);
1145 dh->fh = fi.fh;
1146 }
1147 if (res == 0) {
1148 int res2;
1149 pthread_mutex_lock(&f->lock);
1150 res2 = send_reply(f, in, res, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
1151 if(res2 == -ENOENT) {
1152 /* The opendir syscall was interrupted, so it must be
1153 cancelled */
1154 if(f->op.releasedir)
1155 f->op.releasedir(path, &fi);
1156 pthread_mutex_destroy(&dh->lock);
1157 free(dh);
1158 }
1159 pthread_mutex_unlock(&f->lock);
1160 } else {
1161 send_reply(f, in, res, NULL, 0);
1162 free(dh);
1163 }
1164 free(path);
1165 pthread_rwlock_unlock(&f->tree_lock);
1166 } else
1167 send_reply(f, in, 0, &outarg, SIZEOF_COMPAT(f, fuse_open_out));
1168}
1169
1170static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
1171 int type, ino_t ino, off_t off)
1172{
1173 unsigned namelen = strlen(name);
1174 unsigned entlen;
1175 unsigned entsize;
1176 unsigned padlen;
1177 unsigned newlen;
1178 unsigned char *newptr;
1179
1180 if (!(dh->fuse->flags & FUSE_USE_INO)) {
1181 ino = (ino_t) -1;
1182 if (dh->fuse->flags & FUSE_READDIR_INO) {
1183 struct node *node;
1184 pthread_mutex_lock(&dh->fuse->lock);
1185 node = lookup_node(dh->fuse, dh->nodeid, name);
1186 if (node)
1187 ino = (ino_t) node->nodeid;
1188 pthread_mutex_unlock(&dh->fuse->lock);
1189 }
1190 }
1191
1192 if (namelen > FUSE_NAME_MAX)
1193 namelen = FUSE_NAME_MAX;
1194 else if (!namelen) {
1195 dh->error = -EIO;
1196 return 1;
1197 }
1198
1199 entlen = (dh->fuse->major == 5 ?
1200 FUSE_NAME_OFFSET_COMPAT5 : FUSE_NAME_OFFSET) + namelen;
1201 entsize = FUSE_DIRENT_ALIGN(entlen);
1202 padlen = entsize - entlen;
1203 newlen = dh->len + entsize;
1204 if (off && dh->fuse->major != 5) {
1205 dh->filled = 0;
1206 if (newlen > dh->needlen)
1207 return 1;
1208 }
1209
1210 newptr = realloc(dh->contents, newlen);
1211 if (!newptr) {
1212 dh->error = -ENOMEM;
1213 return 1;
1214 }
1215 dh->contents = newptr;
1216 if (dh->fuse->major == 5) {
1217 struct fuse_dirent_compat5 *dirent;
1218 dirent = (struct fuse_dirent_compat5 *) (dh->contents + dh->len);
1219 dirent->ino = ino;
1220 dirent->namelen = namelen;
1221 dirent->type = type;
1222 strncpy(dirent->name, name, namelen);
1223 } else {
1224 struct fuse_dirent *dirent;
1225 dirent = (struct fuse_dirent *) (dh->contents + dh->len);
1226 dirent->ino = ino;
1227 dirent->off = off ? off : newlen;
1228 dirent->namelen = namelen;
1229 dirent->type = type;
1230 strncpy(dirent->name, name, namelen);
1231 }
1232 if (padlen)
1233 memset(dh->contents + dh->len + entlen, 0, padlen);
1234 dh->len = newlen;
1235 return 0;
1236}
1237
1238static int fill_dir(void *buf, const char *name, const struct stat *stat,
1239 off_t off)
1240{
1241 int type = stat ? (stat->st_mode & 0170000) >> 12 : 0;
1242 ino_t ino = stat ? stat->st_ino : (ino_t) -1;
1243 return fill_dir_common(buf, name, type, ino, off);
1244}
1245
1246static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
1247 ino_t ino)
1248{
1249 fill_dir_common(dh, name, type, ino, 0);
1250 return dh->error;
1251}
1252
1253static int readdir_fill(struct fuse_ll *f, struct fuse_in_header *in,
1254 struct fuse_read_in *arg, struct fuse_dirhandle *dh)
1255{
1256 int err = -ENOENT;
1257 char *path;
1258 pthread_rwlock_rdlock(&f->tree_lock);
1259 path = get_path(f, in->nodeid);
1260 if (path != NULL) {
1261 struct fuse_file_info fi;
1262
1263 memset(&fi, 0, sizeof(fi));
1264 fi.fh = dh->fh;
1265
1266 dh->len = 0;
1267 dh->error = 0;
1268 dh->needlen = arg->size;
1269 dh->filled = 1;
1270 err = -ENOSYS;
1271 if (f->op.readdir) {
1272 off_t offset = f->major == 5 ? 0 : arg->offset;
1273 err = f->op.readdir(path, dh, fill_dir, offset, &fi);
1274 } else if (f->op.getdir)
1275 err = f->op.getdir(path, dh, fill_dir_old);
1276 if (!err)
1277 err = dh->error;
1278 if (err)
1279 dh->filled = 0;
1280 free(path);
1281 }
1282 pthread_rwlock_unlock(&f->tree_lock);
1283 return err;
1284}
1285
1286static void do_readdir(struct fuse_ll *f, struct fuse_in_header *in,
1287 struct fuse_read_in *arg)
1288{
1289 int err = 0;
1290 struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
1291 size_t size = 0;
1292 unsigned char *buf = NULL;
1293
1294 pthread_mutex_lock(&dh->lock);
1295 if (!dh->filled) {
1296 err = readdir_fill(f, in, arg, dh);
1297 if (err)
1298 goto out;
1299 }
1300 if (dh->filled) {
1301 if (arg->offset < dh->len) {
1302 size = arg->size;
1303 if (arg->offset + size > dh->len)
1304 size = dh->len - arg->offset;
1305 buf = dh->contents + arg->offset;
1306 }
1307 } else {
1308 size = dh->len;
1309 buf = dh->contents;
1310 }
1311
1312 out:
1313 send_reply(f, in, err, buf, size);
1314 pthread_mutex_unlock(&dh->lock);
1315}
1316
1317static void do_releasedir(struct fuse_ll *f, struct fuse_in_header *in,
1318 struct fuse_release_in *arg)
1319{
1320 struct fuse_dirhandle *dh = get_dirhandle(arg->fh);
1321 if (f->op.releasedir) {
1322 char *path;
1323 struct fuse_file_info fi;
1324
1325 memset(&fi, 0, sizeof(fi));
1326 fi.fh = dh->fh;
1327
1328 pthread_rwlock_rdlock(&f->tree_lock);
1329 path = get_path(f, in->nodeid);
1330 f->op.releasedir(path ? path : "-", &fi);
1331 free(path);
1332 pthread_rwlock_unlock(&f->tree_lock);
1333 }
1334 pthread_mutex_lock(&dh->lock);
1335 pthread_mutex_unlock(&dh->lock);
1336 pthread_mutex_destroy(&dh->lock);
1337 free(dh->contents);
1338 free(dh);
1339 send_reply(f, in, 0, NULL, 0);
1340}
1341
1342static void do_fsyncdir(struct fuse_ll *f, struct fuse_in_header *in,
1343 struct fuse_fsync_in *inarg)
1344{
1345 int res;
1346 char *path;
1347 struct fuse_dirhandle *dh = get_dirhandle(inarg->fh);
1348 struct fuse_file_info fi;
1349
1350 memset(&fi, 0, sizeof(fi));
1351 fi.fh = dh->fh;
1352
1353 res = -ENOENT;
1354 pthread_rwlock_rdlock(&f->tree_lock);
1355 path = get_path(f, in->nodeid);
1356 if (path != NULL) {
1357 res = -ENOSYS;
1358 if (f->op.fsyncdir)
1359 res = f->op.fsyncdir(path, inarg->fsync_flags & 1, &fi);
1360 free(path);
1361 }
1362 pthread_rwlock_unlock(&f->tree_lock);
1363 send_reply(f, in, res, NULL, 0);
1364}
1365
1366static void free_cmd(struct fuse_cmd *cmd)
1367{
1368 free(cmd->buf);
1369 free(cmd);
1370}
1371
1372void fuse_process_cmd(struct fuse_ll *f, struct fuse_cmd *cmd)
1373{
1374 struct fuse_in_header *in = (struct fuse_in_header *) cmd->buf;
1375 void *inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
1376 struct fuse_context *ctx = fuse_get_context();
1377
1378 fuse_dec_avail(f);
1379
1380 if ((f->flags & FUSE_DEBUG)) {
1381 printf("unique: %llu, opcode: %s (%i), nodeid: %lu, insize: %i\n",
1382 in->unique, opname(in->opcode), in->opcode,
1383 (unsigned long) in->nodeid, cmd->buflen);
1384 fflush(stdout);
1385 }
1386
1387 if (!f->got_init && in->opcode != FUSE_INIT) {
1388 /* Old kernel version probably */
1389 send_reply(f, in, -EPROTO, NULL, 0);
1390 goto out;
1391 }
1392
1393 if ((f->flags & FUSE_ALLOW_ROOT) && in->uid != f->owner && in->uid != 0 &&
1394 in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
1395 in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
1396 in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
1397 in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR) {
1398 send_reply(f, in, -EACCES, NULL, 0);
1399 goto out;
1400 }
1401
1402 ctx->fuse = f;
1403 ctx->uid = in->uid;
1404 ctx->gid = in->gid;
1405 ctx->pid = in->pid;
1406 ctx->private_data = f->user_data;
1407
1408 switch (in->opcode) {
1409 case FUSE_LOOKUP:
1410 do_lookup(f, in, (char *) inarg);
1411 break;
1412
1413 case FUSE_GETATTR:
1414 do_getattr(f, in);
1415 break;
1416
1417 case FUSE_SETATTR:
1418 do_setattr(f, in, (struct fuse_setattr_in *) inarg);
1419 break;
1420
1421 case FUSE_READLINK:
1422 do_readlink(f, in);
1423 break;
1424
1425 case FUSE_MKNOD:
1426 do_mknod(f, in, (struct fuse_mknod_in *) inarg);
1427 break;
1428
1429 case FUSE_MKDIR:
1430 do_mkdir(f, in, (struct fuse_mkdir_in *) inarg);
1431 break;
1432
1433 case FUSE_UNLINK:
1434 do_unlink(f, in, (char *) inarg);
1435 break;
1436
1437 case FUSE_RMDIR:
1438 do_rmdir(f, in, (char *) inarg);
1439 break;
1440
1441 case FUSE_SYMLINK:
1442 do_symlink(f, in, (char *) inarg,
1443 ((char *) inarg) + strlen((char *) inarg) + 1);
1444 break;
1445
1446 case FUSE_RENAME:
1447 do_rename(f, in, (struct fuse_rename_in *) inarg);
1448 break;
1449
1450 case FUSE_LINK:
1451 do_link(f, in, (struct fuse_link_in *) inarg);
1452 break;
1453
1454 case FUSE_OPEN:
1455 do_open(f, in, (struct fuse_open_in *) inarg);
1456 break;
1457
1458 case FUSE_FLUSH:
1459 do_flush(f, in, (struct fuse_flush_in *) inarg);
1460 break;
1461
1462 case FUSE_RELEASE:
1463 do_release(f, in, (struct fuse_release_in *) inarg);
1464 break;
1465
1466 case FUSE_READ:
1467 do_read(f, in, (struct fuse_read_in *) inarg);
1468 break;
1469
1470 case FUSE_WRITE:
1471 do_write(f, in, (struct fuse_write_in *) inarg);
1472 break;
1473
1474 case FUSE_STATFS:
1475 do_statfs(f, in);
1476 break;
1477
1478 case FUSE_FSYNC:
1479 do_fsync(f, in, (struct fuse_fsync_in *) inarg);
1480 break;
1481
1482 case FUSE_SETXATTR:
1483 do_setxattr(f, in, (struct fuse_setxattr_in *) inarg);
1484 break;
1485
1486 case FUSE_GETXATTR:
1487 do_getxattr(f, in, (struct fuse_getxattr_in *) inarg);
1488 break;
1489
1490 case FUSE_LISTXATTR:
1491 do_listxattr(f, in, (struct fuse_getxattr_in *) inarg);
1492 break;
1493
1494 case FUSE_REMOVEXATTR:
1495 do_removexattr(f, in, (char *) inarg);
1496 break;
1497
1498 case FUSE_INIT:
1499 do_init(f, in, (struct fuse_init_in_out *) inarg);
1500 break;
1501
1502 case FUSE_OPENDIR:
1503 do_opendir(f, in, (struct fuse_open_in *) inarg);
1504 break;
1505
1506 case FUSE_READDIR:
1507 do_readdir(f, in, (struct fuse_read_in *) inarg);
1508 break;
1509
1510 case FUSE_RELEASEDIR:
1511 do_releasedir(f, in, (struct fuse_release_in *) inarg);
1512 break;
1513
1514 case FUSE_FSYNCDIR:
1515 do_fsyncdir(f, in, (struct fuse_fsync_in *) inarg);
1516 break;
1517
1518 default:
1519 send_reply(f, in, -ENOSYS, NULL, 0);
1520 }
1521
1522 out:
1523 free_cmd(cmd);
1524}
1525
1526int fuse_exited(struct fuse_ll* f)
1527{
1528 return f->exited;
1529}
1530
1531struct fuse_cmd *fuse_read_cmd(struct fuse_ll *f)
1532{
1533 ssize_t res;
1534 struct fuse_cmd *cmd;
1535 struct fuse_in_header *in;
1536 void *inarg;
1537
1538 cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
1539 if (cmd == NULL) {
1540 fprintf(stderr, "fuse: failed to allocate cmd in read\n");
1541 return NULL;
1542 }
1543 cmd->buf = (char *) malloc(FUSE_MAX_IN);
1544 if (cmd->buf == NULL) {
1545 fprintf(stderr, "fuse: failed to allocate read buffer\n");
1546 free(cmd);
1547 return NULL;
1548 }
1549 in = (struct fuse_in_header *) cmd->buf;
1550 inarg = cmd->buf + SIZEOF_COMPAT(f, fuse_in_header);
1551
1552 res = read(f->fd, cmd->buf, FUSE_MAX_IN);
1553 if (res == -1) {
1554 free_cmd(cmd);
1555 if (fuse_exited(f) || errno == EINTR || errno == ENOENT)
1556 return NULL;
1557
1558 /* ENODEV means we got unmounted, so we silenty return failure */
1559 if (errno != ENODEV) {
1560 /* BAD... This will happen again */
1561 perror("fuse: reading device");
1562 }
1563
1564 fuse_exit(f);
1565 return NULL;
1566 }
1567 if ((size_t) res < SIZEOF_COMPAT(f, fuse_in_header)) {
1568 free_cmd(cmd);
1569 /* Cannot happen */
1570 fprintf(stderr, "short read on fuse device\n");
1571 fuse_exit(f);
1572 return NULL;
1573 }
1574 cmd->buflen = res;
1575
1576 /* Forget is special, it can be done without messing with threads. */
1577 if (in->opcode == FUSE_FORGET) {
1578 do_forget(f, in, (struct fuse_forget_in *) inarg);
1579 free_cmd(cmd);
1580 return NULL;
1581 }
1582
1583 return cmd;
1584}
1585
1586int fuse_loop(struct fuse_ll *f)
1587{
1588 if (f == NULL)
1589 return -1;
1590
1591 while (1) {
1592 struct fuse_cmd *cmd;
1593
1594 if (fuse_exited(f))
1595 break;
1596
1597 cmd = fuse_read_cmd(f);
1598 if (cmd == NULL)
1599 continue;
1600
1601 fuse_process_cmd(f, cmd);
1602 }
1603 f->exited = 0;
1604 return 0;
1605}
1606
1607int fuse_invalidate(struct fuse_ll *f, const char *path)
1608{
1609 (void) f;
1610 (void) path;
1611 return -EINVAL;
1612}
1613
1614void fuse_exit(struct fuse_ll *f)
1615{
1616 f->exited = 1;
1617}
1618
1619struct fuse_context *fuse_get_context()
1620{
1621 static struct fuse_context context;
1622 if (fuse_getcontext)
1623 return fuse_getcontext();
1624 else
1625 return &context;
1626}
1627
1628void fuse_set_getcontext_func(struct fuse_context *(*func)(void))
1629{
1630 fuse_getcontext = func;
1631}
1632
1633static int begins_with(const char *s, const char *beg)
1634{
1635 if (strncmp(s, beg, strlen(beg)) == 0)
1636 return 1;
1637 else
1638 return 0;
1639}
1640
1641int fuse_is_lib_option(const char *opt)
1642{
1643 if (strcmp(opt, "debug") == 0 ||
1644 strcmp(opt, "hard_remove") == 0 ||
1645 strcmp(opt, "use_ino") == 0 ||
1646 strcmp(opt, "allow_root") == 0 ||
1647 strcmp(opt, "readdir_ino") == 0 ||
1648 begins_with(opt, "umask=") ||
1649 begins_with(opt, "uid=") ||
1650 begins_with(opt, "gid="))
1651 return 1;
1652 else
1653 return 0;
1654}
1655
1656static int parse_lib_opts(struct fuse_ll *f, const char *opts)
1657{
1658 if (opts) {
1659 char *xopts = strdup(opts);
1660 char *s = xopts;
1661 char *opt;
1662
1663 if (xopts == NULL) {
1664 fprintf(stderr, "fuse: memory allocation failed\n");
1665 return -1;
1666 }
1667
1668 while((opt = strsep(&s, ","))) {
1669 if (strcmp(opt, "debug") == 0)
1670 f->flags |= FUSE_DEBUG;
1671 else if (strcmp(opt, "hard_remove") == 0)
1672 f->flags |= FUSE_HARD_REMOVE;
1673 else if (strcmp(opt, "use_ino") == 0)
1674 f->flags |= FUSE_USE_INO;
1675 else if (strcmp(opt, "allow_root") == 0)
1676 f->flags |= FUSE_ALLOW_ROOT;
1677 else if (strcmp(opt, "readdir_ino") == 0)
1678 f->flags |= FUSE_READDIR_INO;
1679 else if (sscanf(opt, "umask=%o", &f->umask) == 1)
1680 f->flags |= FUSE_SET_MODE;
1681 else if (sscanf(opt, "uid=%u", &f->uid) == 1)
1682 f->flags |= FUSE_SET_UID;
1683 else if(sscanf(opt, "gid=%u", &f->gid) == 1)
1684 f->flags |= FUSE_SET_GID;
1685 else
1686 fprintf(stderr, "fuse: warning: unknown option `%s'\n", opt);
1687 }
1688 free(xopts);
1689 }
1690 return 0;
1691}
1692
1693struct fuse_ll *fuse_lowlevel_new(int fd, const char *opts,
1694 const struct fuse_lowlevel_operations *op,
1695 size_t op_size)
1696{
1697 struct fuse_ll *f;
1698
1699 if (sizeof(struct fuse_lowlevel_operations) < op_size) {
1700 fprintf(stderr, "fuse: warning: library too old, some operations may not not work\n");
1701 op_size = sizeof(struct fuse_lowlevel_operations);
1702 }
1703
1704 f = (struct fuse_ll *) calloc(1, sizeof(struct fuse_ll));
1705 if (f == NULL) {
1706 fprintf(stderr, "fuse: failed to allocate fuse object\n");
1707 goto out;
1708 }
1709
1710 if (parse_lib_opts(f, opts) == -1)
1711 goto out_free;
1712
1713 f->fd = fd;
1714 memcpy(&f->op, op, op_size);
1715 f->exited = 0;
1716 f->owner = getuid();
1717
1718 return f;
1719
1720 out_free:
1721 free(f);
1722 out:
1723 return NULL;
1724}
1725
1726