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