xref: /openbsd/lib/libfuse/fuse_ops.c (revision 9b7c3dbb)
1 /* $OpenBSD: fuse_ops.c,v 1.25 2016/08/30 16:45:54 natano Exp $ */
2 /*
3  * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <errno.h>
19 #include <string.h>
20 #include <stdlib.h>
21 
22 #include "fuse_private.h"
23 #include "debug.h"
24 
25 #define CHECK_OPT(opname)	DPRINTF("Opcode:\t%s\n", #opname);	\
26 				DPRINTF("Inode:\t%llu\n",		\
27 				    (unsigned long long)fbuf->fb_ino);	\
28 				if (!f->op.opname) {			\
29 					fbuf->fb_err = -ENOSYS;		\
30 					return (0);			\
31 				}
32 
33 static int
34 update_attr(struct fuse *f, struct stat *attr, const char *realname,
35     struct fuse_vnode *vn)
36 {
37 	int ret;
38 
39 	memset(attr, 0, sizeof(struct stat));
40 	ret = f->op.getattr(realname, attr);
41 
42 	if (attr->st_blksize == 0)
43 		attr->st_blksize = 512;
44 	if (attr->st_blocks == 0)
45 		attr->st_blocks = 4;
46 
47 	attr->st_ino = vn->ino;
48 
49 	if (f->conf.set_mode)
50 		attr->st_mode = (attr->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
51 
52 	if (f->conf.set_uid)
53 		attr->st_uid = f->conf.uid;
54 
55 	if (f->conf.set_gid)
56 		attr->st_gid = f->conf.gid;
57 
58 	return (ret);
59 }
60 
61 static int
62 ifuse_ops_init(struct fuse *f)
63 {
64 	struct fuse_conn_info fci;
65 
66 	DPRINTF("Opcode:\tinit\n");
67 
68 	if (f->op.init) {
69 		bzero(&fci, sizeof fci);
70 		fci.proto_minor = FUSE_MINOR_VERSION;
71 		fci.proto_major = FUSE_MAJOR_VERSION;
72 
73 		f->op.init(&fci);
74 	}
75 	return (0);
76 }
77 
78 static int
79 ifuse_ops_getattr(struct fuse *f, struct fusebuf *fbuf)
80 {
81 	struct fuse_vnode *vn;
82 	char *realname;
83 
84 	DPRINTF("Opcode:\tgetattr\n");
85 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
86 
87 	memset(&fbuf->fb_attr, 0, sizeof(struct stat));
88 
89 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
90 	if (vn == NULL) {
91 		fbuf->fb_err = -errno;
92 		return (0);
93 	}
94 
95 	realname = build_realname(f, vn->ino);
96 	if (realname == NULL) {
97 		fbuf->fb_err = -errno;
98 		return (0);
99 	}
100 
101 	fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
102 	free(realname);
103 
104 	return (0);
105 }
106 
107 static int
108 ifuse_ops_access(struct fuse *f, struct fusebuf *fbuf)
109 {
110 	struct fuse_vnode *vn;
111 	char *realname;
112 
113 	CHECK_OPT(access);
114 
115 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
116 	if (vn == NULL) {
117 		fbuf->fb_err = -errno;
118 		return (0);
119 	}
120 
121 	realname = build_realname(f, vn->ino);
122 	if (realname == NULL) {
123 		fbuf->fb_err = -errno;
124 		return (0);
125 	}
126 
127 	fbuf->fb_err = f->op.access(realname, fbuf->fb_io_mode);
128 	free(realname);
129 
130 	return (0);
131 }
132 
133 static int
134 ifuse_ops_open(struct fuse *f, struct fusebuf *fbuf)
135 {
136 	struct fuse_file_info ffi;
137 	struct fuse_vnode *vn;
138 	char *realname;
139 
140 	CHECK_OPT(open);
141 
142 	bzero(&ffi, sizeof(ffi));
143 	ffi.flags = fbuf->fb_io_flags;
144 
145 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
146 	if (vn == NULL) {
147 		fbuf->fb_err = -errno;
148 		return (0);
149 	}
150 
151 	realname = build_realname(f, vn->ino);
152 	if (realname == NULL) {
153 		fbuf->fb_err = -errno;
154 		return (0);
155 	}
156 
157 	fbuf->fb_err = f->op.open(realname, &ffi);
158 	free(realname);
159 
160 	if (!fbuf->fb_err)
161 		fbuf->fb_io_fd = ffi.fh;
162 
163 	return (0);
164 }
165 
166 static int
167 ifuse_ops_opendir(struct fuse *f, struct fusebuf *fbuf)
168 {
169 	struct fuse_file_info ffi;
170 	struct fuse_vnode *vn;
171 	char *realname;
172 
173 	DPRINTF("Opcode:\topendir\n");
174 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
175 
176 	memset(&ffi, 0, sizeof(ffi));
177 	ffi.flags = fbuf->fb_io_flags;
178 
179 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
180 	if (vn == NULL) {
181 		fbuf->fb_err = -errno;
182 		return (0);
183 	}
184 
185 	if (f->op.opendir) {
186 		realname = build_realname(f, vn->ino);
187 		if (realname == NULL) {
188 			fbuf->fb_err = -errno;
189 			return (0);
190 		}
191 
192 		fbuf->fb_err = f->op.opendir(realname, &ffi);
193 		free(realname);
194 	}
195 
196 	if (!fbuf->fb_err) {
197 		fbuf->fb_io_fd = ffi.fh;
198 
199 		vn->fd = calloc(1, sizeof(*vn->fd));
200 		if (vn->fd == NULL) {
201 			fbuf->fb_err = -errno;
202 			return (0);
203 		}
204 
205 		vn->fd->filled = 0;
206 		vn->fd->size = 0;
207 		vn->fd->start = 0;
208 	}
209 
210 	return (0);
211 }
212 
213 #define GENERIC_DIRSIZ(NLEN) \
214 ((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((NLEN+1 + 7) &~ 7))
215 
216 static int
217 ifuse_fill_readdir(void *dh, const char *name, const struct stat *stbuf,
218     off_t off)
219 {
220 	struct fuse_dirhandle *fd = dh;
221 	struct fusebuf *fbuf;
222 	struct dirent *dir;
223 	uint32_t namelen;
224 	uint32_t len;
225 
226 	fbuf = fd->buf;
227 	namelen = strnlen(name, MAXNAMLEN);
228 	len = GENERIC_DIRSIZ(namelen);
229 
230 	if (fd->full || (fbuf->fb_len + len > fd->size)) {
231 		fd->full = 1;
232 		return (0);
233 	}
234 
235 	if (fd->start != 0 &&  fd->idx < fd->start) {
236 		fd->idx += len;
237 		return (0);
238 	}
239 
240 	dir = (struct dirent *) &fbuf->fb_dat[fbuf->fb_len];
241 
242 	if (off)
243 		fd->filled = 0;
244 
245 	if (stbuf) {
246 		dir->d_fileno = stbuf->st_ino;
247 		dir->d_type = IFTODT(stbuf->st_mode);
248 	} else {
249 		dir->d_fileno = 0xffffffff;
250 		dir->d_type = DT_UNKNOWN;
251 	}
252 	dir->d_reclen = len;
253 	dir->d_off = off + len;		/* XXX */
254 	strlcpy(dir->d_name, name, sizeof(dir->d_name));
255 	dir->d_namlen = strlen(dir->d_name);
256 
257 	fbuf->fb_len += len;
258 	fd->start += len;
259 	fd->idx += len;
260 
261 	return (0);
262 }
263 
264 static int
265 ifuse_fill_getdir(fuse_dirh_t fd, const char *name, int type, ino_t ino)
266 {
267 	struct stat st;
268 
269 	bzero(&st, sizeof(st));
270 	st.st_mode = type << 12;
271 	if (ino == 0)
272 		st.st_ino = 0xffffffff;
273 	else
274 		st.st_ino = ino;
275 
276 	return (fd->filler(fd, name, &st, 0));
277 }
278 
279 static int
280 ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf)
281 {
282 	struct fuse_file_info ffi;
283 	struct fuse_vnode *vn;
284 	char *realname;
285 	uint64_t offset;
286 	uint32_t size;
287 	uint32_t startsave;
288 
289 	DPRINTF("Opcode:\treaddir\n");
290 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
291 	DPRINTF("Offset:\t%llu\n", fbuf->fb_io_off);
292 	DPRINTF("Size:\t%lu\n", fbuf->fb_io_len);
293 
294 	bzero(&ffi, sizeof(ffi));
295 	ffi.fh = fbuf->fb_io_fd;
296 	offset = fbuf->fb_io_off;
297 	size = fbuf->fb_io_len;
298 	startsave = 0;
299 
300 	fbuf->fb_dat = calloc(1, size);
301 
302 	if (fbuf->fb_dat == NULL) {
303 		fbuf->fb_err = -errno;
304 		return (0);
305 	}
306 
307 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
308 	if (vn == NULL) {
309 		fbuf->fb_err = -errno;
310 		free(fbuf->fb_dat);
311 		return (0);
312 	}
313 
314 	if (!vn->fd->filled) {
315 		vn->fd->filler = ifuse_fill_readdir;
316 		vn->fd->buf = fbuf;
317 		vn->fd->filled = 0;
318 		vn->fd->full = 0;
319 		vn->fd->size = size;
320 		vn->fd->off = offset;
321 		vn->fd->idx = 0;
322 		startsave = vn->fd->start;
323 
324 		realname = build_realname(f, vn->ino);
325 		if (realname == NULL) {
326 			fbuf->fb_err = -errno;
327 			free(fbuf->fb_dat);
328 			return (0);
329 		}
330 
331 		if (f->op.readdir)
332 			fbuf->fb_err = f->op.readdir(realname, vn->fd,
333 			    ifuse_fill_readdir, offset, &ffi);
334 		else if (f->op.getdir)
335 			fbuf->fb_err = f->op.getdir(realname, vn->fd,
336 			    ifuse_fill_getdir);
337 		else
338 			fbuf->fb_err = -ENOSYS;
339 		free(realname);
340 	}
341 
342 	if (!vn->fd->full && vn->fd->start == startsave)
343 		vn->fd->filled = 1;
344 
345 	if (fbuf->fb_err) {
346 		fbuf->fb_len = 0;
347 		vn->fd->filled = 1;
348 	}
349 
350 	if (fbuf->fb_len == 0)
351 		free(fbuf->fb_dat);
352 
353 	return (0);
354 }
355 
356 static int
357 ifuse_ops_releasedir(struct fuse *f, struct fusebuf *fbuf)
358 {
359 	struct fuse_file_info ffi;
360 	struct fuse_vnode *vn;
361 	char *realname;
362 
363 	DPRINTF("Opcode:\treleasedir\n");
364 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
365 
366 	bzero(&ffi, sizeof(ffi));
367 	ffi.fh = fbuf->fb_io_fd;
368 	ffi.fh_old = ffi.fh;
369 	ffi.flags = fbuf->fb_io_flags;
370 
371 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
372 	if (vn == NULL) {
373 		fbuf->fb_err = -errno;
374 		return (0);
375 	}
376 
377 	if (f->op.releasedir) {
378 		realname = build_realname(f, vn->ino);
379 		if (realname == NULL) {
380 			fbuf->fb_err = -errno;
381 			return (0);
382 		}
383 
384 		fbuf->fb_err = f->op.releasedir(realname, &ffi);
385 		free(realname);
386 	}
387 
388 	if (!fbuf->fb_err)
389 		free(vn->fd);
390 
391 	return (0);
392 }
393 
394 static int
395 ifuse_ops_release(struct fuse *f, struct fusebuf *fbuf)
396 {
397 	struct fuse_file_info ffi;
398 	struct fuse_vnode *vn;
399 	char *realname;
400 
401 	CHECK_OPT(release);
402 
403 	bzero(&ffi, sizeof(ffi));
404 	ffi.fh = fbuf->fb_io_fd;
405 	ffi.fh_old = ffi.fh;
406 	ffi.flags = fbuf->fb_io_flags;
407 
408 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
409 	if (vn == NULL) {
410 		fbuf->fb_err = -errno;
411 		return (0);
412 	}
413 
414 	realname = build_realname(f, vn->ino);
415 	if (realname == NULL) {
416 		fbuf->fb_err = -errno;
417 		return (0);
418 	}
419 	fbuf->fb_err = f->op.release(realname, &ffi);
420 	free(realname);
421 
422 	return (0);
423 }
424 
425 static int
426 ifuse_ops_lookup(struct fuse *f, struct fusebuf *fbuf)
427 {
428 	struct fuse_vnode *vn;
429 	char *realname;
430 
431 	DPRINTF("Opcode:\tlookup\n");
432 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
433 	DPRINTF("For file %s\n", fbuf->fb_dat);
434 
435 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
436 	if (vn == NULL) {
437 		vn = alloc_vn(f, (const char *)fbuf->fb_dat, -1, fbuf->fb_ino);
438 		if (vn == NULL) {
439 			fbuf->fb_err = -errno;
440 			free(fbuf->fb_dat);
441 			return (0);
442 		}
443 		set_vn(f, vn); /*XXX*/
444 	}
445 
446 	DPRINTF("new ino %llu\n", (unsigned long long)vn->ino);
447 	realname = build_realname(f, vn->ino);
448 	if (realname == NULL) {
449 		fbuf->fb_err = -errno;
450 		free(fbuf->fb_dat);
451 		return (0);
452 	}
453 
454 	fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
455 	free(fbuf->fb_dat);
456 	free(realname);
457 
458 	return (0);
459 }
460 
461 static int
462 ifuse_ops_read(struct fuse *f, struct fusebuf *fbuf)
463 {
464 	struct fuse_file_info ffi;
465 	struct fuse_vnode *vn;
466 	char *realname;
467 	uint64_t offset;
468 	uint32_t size;
469 	int ret;
470 
471 	CHECK_OPT(read);
472 
473 	bzero(&ffi, sizeof(ffi));
474 	ffi.fh = fbuf->fb_io_fd;
475 	size = fbuf->fb_io_len;
476 	offset = fbuf->fb_io_off;
477 
478 	fbuf->fb_dat = malloc(size);
479 	if (fbuf->fb_dat == NULL) {
480 		fbuf->fb_err = -errno;
481 		return (0);
482 	}
483 
484 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
485 	if (vn == NULL) {
486 		fbuf->fb_err = -errno;
487 		free(fbuf->fb_dat);
488 		return (0);
489 	}
490 
491 	realname = build_realname(f, vn->ino);
492 	if (realname == NULL) {
493 		fbuf->fb_err = -errno;
494 		free(fbuf->fb_dat);
495 		return (0);
496 	}
497 
498 	ret = f->op.read(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
499 	free(realname);
500 	if (ret >= 0)
501 		fbuf->fb_len = ret;
502 	else
503 		fbuf->fb_err = ret;
504 
505 	if (fbuf->fb_len == 0)
506 		free(fbuf->fb_dat);
507 
508 	return (0);
509 }
510 
511 static int
512 ifuse_ops_write(struct fuse *f, struct fusebuf *fbuf)
513 {
514 	struct fuse_file_info ffi;
515 	struct fuse_vnode *vn;
516 	char *realname;
517 	uint64_t offset;
518 	uint32_t size;
519 	int ret;
520 
521 	CHECK_OPT(write);
522 
523 	bzero(&ffi, sizeof(ffi));
524 	ffi.fh = fbuf->fb_io_fd;
525 	ffi.fh_old = ffi.fh;
526 	ffi.writepage = fbuf->fb_io_flags & 1;
527 	size = fbuf->fb_io_len;
528 	offset = fbuf->fb_io_off;
529 
530 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
531 	if (vn == NULL) {
532 		fbuf->fb_err = -errno;
533 		free(fbuf->fb_dat);
534 		return (0);
535 	}
536 
537 	realname = build_realname(f, vn->ino);
538 	if (realname == NULL) {
539 		fbuf->fb_err = -errno;
540 		free(fbuf->fb_dat);
541 		return (0);
542 	}
543 
544 	ret = f->op.write(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
545 	free(realname);
546 	free(fbuf->fb_dat);
547 
548 	if (ret >= 0)
549 		fbuf->fb_io_len = ret;
550 	else
551 		fbuf->fb_err = ret;
552 
553 	return (0);
554 }
555 
556 static int
557 ifuse_ops_create(struct fuse *f, struct fusebuf *fbuf)
558 {
559 	struct fuse_file_info ffi;
560 	struct fuse_vnode *vn;
561 	uint32_t mode;
562 
563 	char *realname;
564 
565 	DPRINTF("Opcode:\tcreate\n");
566 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
567 
568 	bzero(&ffi, sizeof(ffi));
569 	ffi.flags = fbuf->fb_io_flags;
570 	mode = fbuf->fb_io_mode;
571 
572 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
573 	if (vn == NULL) {
574 		fbuf->fb_err = -errno;
575 		free(fbuf->fb_dat);
576 		return (0);
577 	}
578 
579 	free(fbuf->fb_dat);
580 	realname = build_realname(f, vn->ino);
581 	if (realname == NULL) {
582 		fbuf->fb_err = -errno;
583 		return (0);
584 	}
585 
586 	if (f->op.create)
587 		fbuf->fb_err = f->op.create(realname, mode,  &ffi);
588 	else if (f->op.mknod)
589 		fbuf->fb_err = f->op.mknod(realname, S_IFREG | mode, 0);
590 	else
591 		fbuf->fb_err = -ENOSYS;
592 
593 	if (!fbuf->fb_err) {
594 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
595 		fbuf->fb_ino = fbuf->fb_attr.st_ino;
596 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
597 	}
598 	free(realname);
599 
600 	return (0);
601 }
602 
603 static int
604 ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf)
605 {
606 	struct fuse_vnode *vn;
607 	char *realname;
608 	uint32_t mode;
609 
610 	CHECK_OPT(mkdir);
611 
612 	mode = fbuf->fb_io_mode;
613 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
614 	if (vn == NULL) {
615 		fbuf->fb_err = -errno;
616 		free(fbuf->fb_dat);
617 		return (0);
618 	}
619 
620 	free(fbuf->fb_dat);
621 	realname = build_realname(f, vn->ino);
622 	if (realname == NULL) {
623 		fbuf->fb_err = -errno;
624 		return (0);
625 	}
626 
627 	fbuf->fb_err = f->op.mkdir(realname, mode);
628 
629 	if (!fbuf->fb_err) {
630 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
631 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
632 		fbuf->fb_ino = vn->ino;
633 	}
634 	free(realname);
635 
636 	return (0);
637 }
638 
639 static int
640 ifuse_ops_rmdir(struct fuse *f, struct fusebuf *fbuf)
641 {
642 	struct fuse_vnode *vn;
643 	char *realname;
644 
645 	CHECK_OPT(rmdir);
646 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
647 	if (vn == NULL) {
648 		fbuf->fb_err = -errno;
649 		free(fbuf->fb_dat);
650 		return (0);
651 	}
652 
653 	free(fbuf->fb_dat);
654 	realname = build_realname(f, vn->ino);
655 	if (realname == NULL) {
656 		fbuf->fb_err = -errno;
657 		return (0);
658 	}
659 
660 	fbuf->fb_err = f->op.rmdir(realname);
661 	free(realname);
662 
663 	return (0);
664 }
665 
666 static int
667 ifuse_ops_readlink(struct fuse *f, struct fusebuf *fbuf)
668 {
669 	struct fuse_vnode *vn;
670 	char *realname;
671 	char name[PATH_MAX + 1];
672 	int len, ret;
673 
674 	DPRINTF("Opcode:\treadlink\n");
675 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
676 
677 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
678 	if (vn == NULL) {
679 		fbuf->fb_err = -errno;
680 		return (0);
681 	}
682 
683 	realname = build_realname(f, vn->ino);
684 	if (realname == NULL) {
685 		fbuf->fb_err = -errno;
686 		return (0);
687 	}
688 
689 	if (f->op.readlink)
690 		ret = f->op.readlink(realname, name, sizeof(name));
691 	else
692 		ret = -ENOSYS;
693 	free(realname);
694 
695 	fbuf->fb_err = ret;
696 	if (!ret) {
697 		len = strnlen(name, PATH_MAX);
698 		fbuf->fb_len = len;
699 		fbuf->fb_dat = malloc(fbuf->fb_len);
700 		if (fbuf->fb_dat == NULL) {
701 			fbuf->fb_err = -errno;
702 			return (0);
703 		}
704 		memcpy(fbuf->fb_dat, name, len);
705 	} else
706 		fbuf->fb_len = 0;
707 
708 	return (0);
709 }
710 
711 static int
712 ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf)
713 {
714 	struct fuse_vnode *vn;
715 	char *realname;
716 
717 	CHECK_OPT(unlink);
718 
719 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
720 	if (vn == NULL) {
721 		free(fbuf->fb_dat);
722 		fbuf->fb_err = -errno;
723 		return (0);
724 	}
725 
726 	free(fbuf->fb_dat);
727 	realname = build_realname(f, vn->ino);
728 	if (realname == NULL) {
729 		fbuf->fb_err = -errno;
730 		return (0);
731 	}
732 
733 	fbuf->fb_err = f->op.unlink(realname);
734 	free(realname);
735 
736 	return (0);
737 }
738 
739 static int
740 ifuse_ops_statfs(struct fuse *f, struct fusebuf *fbuf)
741 {
742 	struct fuse_vnode *vn;
743 	char *realname;
744 
745 	bzero(&fbuf->fb_stat, sizeof(fbuf->fb_stat));
746 
747 	CHECK_OPT(statfs);
748 
749 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
750 	if (vn == NULL) {
751 		fbuf->fb_err = -errno;
752 		return (0);
753 	}
754 
755 	realname = build_realname(f, vn->ino);
756 	if (realname == NULL) {
757 		fbuf->fb_err = -errno;
758 		return (0);
759 	}
760 
761 	fbuf->fb_err = f->op.statfs(realname, &fbuf->fb_stat);
762 	free(realname);
763 
764 	return (0);
765 }
766 
767 static int
768 ifuse_ops_link(struct fuse *f, struct fusebuf *fbuf)
769 {
770 	struct fuse_vnode *vn;
771 	char *realname;
772 	char *realname_ln;
773 	ino_t oldnodeid;
774 
775 	CHECK_OPT(link);
776 	oldnodeid = fbuf->fb_io_ino;
777 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
778 	if (vn == NULL) {
779 		fbuf->fb_err = -errno;
780 		free(fbuf->fb_dat);
781 		return (0);
782 	}
783 
784 	free(fbuf->fb_dat);
785 	realname = build_realname(f, oldnodeid);
786 	if (realname == NULL) {
787 		fbuf->fb_err = -errno;
788 		return (0);
789 	}
790 
791 	realname_ln = build_realname(f, vn->ino);
792 	if (realname_ln == NULL) {
793 		fbuf->fb_err = -errno;
794 		free(realname);
795 		return (0);
796 	}
797 
798 	fbuf->fb_err = f->op.link(realname, realname_ln);
799 	free(realname);
800 	free(realname_ln);
801 
802 	return (0);
803 }
804 
805 static int
806 ifuse_ops_setattr(struct fuse *f, struct fusebuf *fbuf)
807 {
808 	struct fuse_vnode *vn;
809 	struct timespec ts[2];
810 	struct utimbuf tbuf;
811 	struct fb_io *io;
812 	char *realname;
813 	uid_t uid;
814 	gid_t gid;
815 
816 	DPRINTF("Opcode:\tsetattr\n");
817 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
818 
819 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
820 	if (vn == NULL) {
821 		fbuf->fb_err = -errno;
822 		free(fbuf->fb_dat);
823 		return (0);
824 	}
825 
826 	realname = build_realname(f, vn->ino);
827 	if (realname == NULL) {
828 		fbuf->fb_err = -errno;
829 		free(fbuf->fb_dat);
830 		return (0);
831 	}
832 	io = fbtod(fbuf, struct fb_io *);
833 
834 	if (io->fi_flags & FUSE_FATTR_MODE) {
835 		if (f->op.chmod)
836 			fbuf->fb_err = f->op.chmod(realname,
837 			    fbuf->fb_attr.st_mode);
838 		else
839 			fbuf->fb_err = -ENOSYS;
840 	}
841 
842 	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_UID ||
843 	    io->fi_flags & FUSE_FATTR_GID) ) {
844 		uid = (io->fi_flags & FUSE_FATTR_UID) ?
845 		    fbuf->fb_attr.st_uid : (gid_t)-1;
846 		gid = (io->fi_flags & FUSE_FATTR_GID) ?
847 		    fbuf->fb_attr.st_gid : (uid_t)-1;
848 		if (f->op.chown)
849 			fbuf->fb_err = f->op.chown(realname, uid, gid);
850 		else
851 			fbuf->fb_err = -ENOSYS;
852 	}
853 
854 	if (!fbuf->fb_err && ( io->fi_flags & FUSE_FATTR_MTIME ||
855 		io->fi_flags & FUSE_FATTR_ATIME)) {
856 		ts[0] = fbuf->fb_attr.st_atim;
857 		ts[1] = fbuf->fb_attr.st_mtim;
858 		tbuf.actime = ts[0].tv_sec;
859 		tbuf.modtime = ts[1].tv_sec;
860 
861 		if (f->op.utimens)
862 			fbuf->fb_err = f->op.utimens(realname, ts);
863 		else if (f->op.utime)
864 			fbuf->fb_err = f->op.utime(realname, &tbuf);
865 		else
866 			fbuf->fb_err = -ENOSYS;
867 	}
868 
869 	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_SIZE)) {
870 		if (f->op.truncate)
871 			fbuf->fb_err = f->op.truncate(realname,
872 			    fbuf->fb_attr.st_size);
873 		else
874 			fbuf->fb_err = -ENOSYS;
875 	}
876 
877 	memset(&fbuf->fb_attr, 0, sizeof(struct stat));
878 
879 	if (!fbuf->fb_err)
880 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
881 	free(realname);
882 	free(fbuf->fb_dat);
883 
884 	return (0);
885 }
886 
887 static int
888 ifuse_ops_symlink(unused struct fuse *f, struct fusebuf *fbuf)
889 {
890 	struct fuse_vnode *vn;
891 	char *realname;
892 	int len;
893 
894 	CHECK_OPT(symlink);
895 
896 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
897 	if (vn == NULL) {
898 		fbuf->fb_err = -errno;
899 		free(fbuf->fb_dat);
900 		return (0);
901 	}
902 
903 	len = strlen((char *)fbuf->fb_dat);
904 
905 	realname = build_realname(f, vn->ino);
906 	if (realname == NULL) {
907 		fbuf->fb_err = -errno;
908 		free(fbuf->fb_dat);
909 		return (0);
910 	}
911 
912 	/* fuse invert the symlink params */
913 	fbuf->fb_err = f->op.symlink((const char *)&fbuf->fb_dat[len + 1],
914 	    realname);
915 	fbuf->fb_ino = vn->ino;
916 	free(fbuf->fb_dat);
917 	free(realname);
918 
919 	return (0);
920 }
921 
922 static int
923 ifuse_ops_rename(struct fuse *f, struct fusebuf *fbuf)
924 {
925 	struct fuse_vnode *vnt;
926 	struct fuse_vnode *vnf;
927 	char *realnamef;
928 	char *realnamet;
929 	int len;
930 
931 	CHECK_OPT(rename);
932 
933 	len = strlen((char *)fbuf->fb_dat);
934 	vnf = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
935 	if (vnf == NULL) {
936 		fbuf->fb_err = -errno;
937 		free(fbuf->fb_dat);
938 		return (0);
939 	}
940 
941 	vnt = get_vn_by_name_and_parent(f, &fbuf->fb_dat[len + 1],
942 	    fbuf->fb_io_ino);
943 	if (vnt == NULL) {
944 		fbuf->fb_err = -errno;
945 		free(fbuf->fb_dat);
946 		return (0);
947 	}
948 
949 	free(fbuf->fb_dat);
950 
951 	realnamef = build_realname(f, vnf->ino);
952 	if (realnamef == NULL) {
953 		fbuf->fb_err = -errno;
954 		return (0);
955 	}
956 
957 	realnamet = build_realname(f, vnt->ino);
958 	if (realnamet == NULL) {
959 		fbuf->fb_err = -errno;
960 		free(realnamef);
961 		return (0);
962 	}
963 
964 	fbuf->fb_err = f->op.rename(realnamef, realnamet);
965 	free(realnamef);
966 	free(realnamet);
967 
968 	return (0);
969 }
970 
971 static int
972 ifuse_ops_destroy(struct fuse *f)
973 {
974 	struct fuse_context *ctx;
975 
976 	DPRINTF("Opcode:\tdestroy\n");
977 
978 	if (f->op.destroy) {
979 		ctx = fuse_get_context();
980 
981 		f->op.destroy((ctx)?ctx->private_data:NULL);
982 	}
983 
984 	f->fc->dead = 1;
985 
986 	return (0);
987 }
988 
989 static int
990 ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf)
991 {
992 	struct fuse_vnode *vn;
993 
994 	vn = tree_pop(&f->vnode_tree, fbuf->fb_ino);
995 	if (vn) {
996 		remove_vnode_from_name_tree(f, vn);
997 		free(vn);
998 	}
999 
1000 	return (0);
1001 }
1002 
1003 static int
1004 ifuse_ops_mknod(struct fuse *f, struct fusebuf *fbuf)
1005 {
1006 	struct fuse_vnode *vn;
1007 	char *realname;
1008 	uint32_t mode;
1009 	dev_t dev;
1010 
1011 	CHECK_OPT(mknod);
1012 
1013 	mode = fbuf->fb_io_mode;
1014 	dev = fbuf->fb_io_rdev;
1015 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
1016 	if (vn == NULL) {
1017 		fbuf->fb_err = -errno;
1018 		free(fbuf->fb_dat);
1019 		return (0);
1020 	}
1021 
1022 	free(fbuf->fb_dat);
1023 	realname = build_realname(f, vn->ino);
1024 	if (realname == NULL) {
1025 		fbuf->fb_err = -errno;
1026 		return (0);
1027 	}
1028 
1029 	fbuf->fb_err = f->op.mknod(realname, mode, dev);
1030 
1031 	if (!fbuf->fb_err) {
1032 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
1033 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
1034 		fbuf->fb_ino = fbuf->fb_attr.st_ino;
1035 	}
1036 	free(realname);
1037 
1038 	return (0);
1039 }
1040 
1041 int
1042 ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
1043 {
1044 	int ret = 0;
1045 
1046 	fbuf->fb_len = 0;
1047 	fbuf->fb_err = 0;
1048 
1049 	switch (fbuf->fb_type) {
1050 	case FBT_LOOKUP:
1051 		ret = ifuse_ops_lookup(f, fbuf);
1052 		break;
1053 	case FBT_GETATTR:
1054 		ret = ifuse_ops_getattr(f, fbuf);
1055 		break;
1056 	case FBT_SETATTR:
1057 		ret = ifuse_ops_setattr(f, fbuf);
1058 		break;
1059 	case FBT_READLINK:
1060 		ret = ifuse_ops_readlink(f, fbuf);
1061 		break;
1062 	case FBT_MKDIR:
1063 		ret = ifuse_ops_mkdir(f, fbuf);
1064 		break;
1065 	case FBT_UNLINK:
1066 		ret = ifuse_ops_unlink(f, fbuf);
1067 		break;
1068 	case FBT_RMDIR:
1069 		ret = ifuse_ops_rmdir(f, fbuf);
1070 		break;
1071 	case FBT_LINK:
1072 		ret = ifuse_ops_link(f, fbuf);
1073 		break;
1074 	case FBT_OPEN:
1075 		ret = ifuse_ops_open(f, fbuf);
1076 		break;
1077 	case FBT_READ:
1078 		ret = ifuse_ops_read(f, fbuf);
1079 		break;
1080 	case FBT_WRITE:
1081 		ret = ifuse_ops_write(f, fbuf);
1082 		break;
1083 	case FBT_STATFS:
1084 		ret = ifuse_ops_statfs(f, fbuf);
1085 		break;
1086 	case FBT_RELEASE:
1087 		ret = ifuse_ops_release(f, fbuf);
1088 		break;
1089 	case FBT_INIT:
1090 		ret = ifuse_ops_init(f);
1091 		break;
1092 	case FBT_OPENDIR:
1093 		ret = ifuse_ops_opendir(f, fbuf);
1094 		break;
1095 	case FBT_READDIR:
1096 		ret = ifuse_ops_readdir(f, fbuf);
1097 		break;
1098 	case FBT_RELEASEDIR:
1099 		ret = ifuse_ops_releasedir(f, fbuf);
1100 		break;
1101 	case FBT_ACCESS:
1102 		ret = ifuse_ops_access(f, fbuf);
1103 		break;
1104 	case FBT_CREATE:
1105 		ret = ifuse_ops_create(f, fbuf);
1106 		break;
1107 	case FBT_SYMLINK:
1108 		ret = ifuse_ops_symlink(f, fbuf);
1109 		break;
1110 	case FBT_RENAME:
1111 		ret = ifuse_ops_rename(f, fbuf);
1112 		break;
1113 	case FBT_DESTROY:
1114 		ret = ifuse_ops_destroy(f);
1115 		break;
1116 	case FBT_RECLAIM:
1117 		ret = ifuse_ops_reclaim(f, fbuf);
1118 		break;
1119 	case FBT_MKNOD:
1120 		ret = ifuse_ops_mknod(f, fbuf);
1121 		break;
1122 	default:
1123 		DPRINTF("Opcode:\t%i not supported\n", fbuf->fb_type);
1124 		DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
1125 
1126 		fbuf->fb_err = -ENOSYS;
1127 		fbuf->fb_len = 0;
1128 	}
1129 	DPRINTF("\n");
1130 
1131 	/* fuse api use negative errno */
1132 	fbuf->fb_err = -fbuf->fb_err;
1133 	return (ret);
1134 }
1135