xref: /openbsd-src/lib/libfuse/fuse_ops.c (revision 897fc685943471cf985a0fe38ba076ea6fe74fa5)
1 /* $OpenBSD: fuse_ops.c,v 1.28 2017/11/30 11:29:03 helg 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 *f;
221 	struct fuse_dirhandle *fd = dh;
222 	struct fuse_vnode *v;
223 	struct fusebuf *fbuf;
224 	struct dirent *dir;
225 	uint32_t namelen;
226 	uint32_t len;
227 
228 	f = fd->fuse;
229 	fbuf = fd->buf;
230 	namelen = strnlen(name, MAXNAMLEN);
231 	len = GENERIC_DIRSIZ(namelen);
232 
233 	if (fd->full || (fbuf->fb_len + len > fd->size)) {
234 		fd->full = 1;
235 		return (0);
236 	}
237 
238 	if (fd->start != 0 &&  fd->idx < fd->start) {
239 		fd->idx += len;
240 		return (0);
241 	}
242 
243 	dir = (struct dirent *) &fbuf->fb_dat[fbuf->fb_len];
244 
245 	if (off)
246 		fd->filled = 0;
247 
248 	/* TODO Add support for use_ino and readdir_ino */
249 	v = get_vn_by_name_and_parent(f, (uint8_t *)name, fbuf->fb_ino);
250 	if (v == NULL) {
251 		if (strcmp(name, ".") == 0)
252 			dir->d_fileno = fbuf->fb_ino;
253 		else
254 			dir->d_fileno = 0xffffffff;
255 	} else
256 		dir->d_fileno = v->ino;
257 
258 	if (stbuf)
259 		dir->d_type = IFTODT(stbuf->st_mode);
260 	else
261 		dir->d_type = DT_UNKNOWN;
262 
263 	dir->d_reclen = len;
264 	dir->d_off = off + len;		/* XXX */
265 	strlcpy(dir->d_name, name, sizeof(dir->d_name));
266 	dir->d_namlen = strlen(dir->d_name);
267 
268 	fbuf->fb_len += len;
269 	fd->start += len;
270 	fd->idx += len;
271 
272 	return (0);
273 }
274 
275 static int
276 ifuse_fill_getdir(fuse_dirh_t fd, const char *name, int type, ino_t ino)
277 {
278 	struct stat st;
279 
280 	bzero(&st, sizeof(st));
281 	st.st_mode = type << 12;
282 	if (ino == 0)
283 		st.st_ino = 0xffffffff;
284 	else
285 		st.st_ino = ino;
286 
287 	return (fd->filler(fd, name, &st, 0));
288 }
289 
290 static int
291 ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf)
292 {
293 	struct fuse_file_info ffi;
294 	struct fuse_vnode *vn;
295 	char *realname;
296 	uint64_t offset;
297 	uint32_t size;
298 	uint32_t startsave;
299 
300 	DPRINTF("Opcode:\treaddir\n");
301 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
302 	DPRINTF("Offset:\t%llu\n", fbuf->fb_io_off);
303 	DPRINTF("Size:\t%lu\n", fbuf->fb_io_len);
304 
305 	bzero(&ffi, sizeof(ffi));
306 	ffi.fh = fbuf->fb_io_fd;
307 	offset = fbuf->fb_io_off;
308 	size = fbuf->fb_io_len;
309 	startsave = offset;
310 
311 	fbuf->fb_dat = calloc(1, size);
312 
313 	if (fbuf->fb_dat == NULL) {
314 		fbuf->fb_err = -errno;
315 		return (0);
316 	}
317 
318 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
319 	if (vn == NULL) {
320 		fbuf->fb_err = -errno;
321 		free(fbuf->fb_dat);
322 		return (0);
323 	}
324 
325 	if (!vn->fd->filled) {
326 		vn->fd->filler = ifuse_fill_readdir;
327 		vn->fd->buf = fbuf;
328 		vn->fd->full = 0;
329 		vn->fd->size = size;
330 		vn->fd->off = offset;
331 		vn->fd->idx = 0;
332 		vn->fd->fuse = f;
333 		vn->fd->start = offset;
334 		startsave = vn->fd->start;
335 
336 		realname = build_realname(f, vn->ino);
337 		if (realname == NULL) {
338 			fbuf->fb_err = -errno;
339 			free(fbuf->fb_dat);
340 			return (0);
341 		}
342 
343 		if (f->op.readdir)
344 			fbuf->fb_err = f->op.readdir(realname, vn->fd,
345 			    ifuse_fill_readdir, offset, &ffi);
346 		else if (f->op.getdir)
347 			fbuf->fb_err = f->op.getdir(realname, vn->fd,
348 			    ifuse_fill_getdir);
349 		else
350 			fbuf->fb_err = -ENOSYS;
351 		free(realname);
352 	}
353 
354 	if (!vn->fd->full && vn->fd->start == startsave)
355 		vn->fd->filled = 1;
356 
357 	if (fbuf->fb_err) {
358 		fbuf->fb_len = 0;
359 		vn->fd->filled = 1;
360 	} else if (vn->fd->full && fbuf->fb_len == 0)
361 		fbuf->fb_err = -ENOBUFS;
362 
363 	if (fbuf->fb_len == 0)
364 		free(fbuf->fb_dat);
365 
366 	return (0);
367 }
368 
369 static int
370 ifuse_ops_releasedir(struct fuse *f, struct fusebuf *fbuf)
371 {
372 	struct fuse_file_info ffi;
373 	struct fuse_vnode *vn;
374 	char *realname;
375 
376 	DPRINTF("Opcode:\treleasedir\n");
377 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
378 
379 	bzero(&ffi, sizeof(ffi));
380 	ffi.fh = fbuf->fb_io_fd;
381 	ffi.fh_old = ffi.fh;
382 	ffi.flags = fbuf->fb_io_flags;
383 
384 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
385 	if (vn == NULL) {
386 		fbuf->fb_err = -errno;
387 		return (0);
388 	}
389 
390 	if (f->op.releasedir) {
391 		realname = build_realname(f, vn->ino);
392 		if (realname == NULL) {
393 			fbuf->fb_err = -errno;
394 			return (0);
395 		}
396 
397 		fbuf->fb_err = f->op.releasedir(realname, &ffi);
398 		free(realname);
399 	}
400 
401 	if (!fbuf->fb_err)
402 		free(vn->fd);
403 
404 	return (0);
405 }
406 
407 static int
408 ifuse_ops_release(struct fuse *f, struct fusebuf *fbuf)
409 {
410 	struct fuse_file_info ffi;
411 	struct fuse_vnode *vn;
412 	char *realname;
413 
414 	CHECK_OPT(release);
415 
416 	bzero(&ffi, sizeof(ffi));
417 	ffi.fh = fbuf->fb_io_fd;
418 	ffi.fh_old = ffi.fh;
419 	ffi.flags = fbuf->fb_io_flags;
420 
421 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
422 	if (vn == NULL) {
423 		fbuf->fb_err = -errno;
424 		return (0);
425 	}
426 
427 	realname = build_realname(f, vn->ino);
428 	if (realname == NULL) {
429 		fbuf->fb_err = -errno;
430 		return (0);
431 	}
432 	fbuf->fb_err = f->op.release(realname, &ffi);
433 	free(realname);
434 
435 	return (0);
436 }
437 
438 static int
439 ifuse_ops_lookup(struct fuse *f, struct fusebuf *fbuf)
440 {
441 	struct fuse_vnode *vn;
442 	char *realname;
443 
444 	DPRINTF("Opcode:\tlookup\n");
445 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
446 	DPRINTF("For file %s\n", fbuf->fb_dat);
447 
448 	if (strcmp((const char *)fbuf->fb_dat, "..") == 0) {
449 		vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
450 		if (vn == NULL || vn->parent == NULL) {
451 			fbuf->fb_err = -ENOENT;
452 			return (0);
453 		}
454 		vn = vn->parent;
455 		if (vn->ino != FUSE_ROOT_INO)
456 			ref_vn(vn);
457 	} else {
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,
461 			    fbuf->fb_ino);
462 			if (vn == NULL) {
463 				fbuf->fb_err = -errno;
464 				free(fbuf->fb_dat);
465 				return (0);
466 			}
467 			set_vn(f, vn); /*XXX*/
468 		} else if (vn->ino != FUSE_ROOT_INO)
469 			ref_vn(vn);
470 	}
471 
472 	DPRINTF("new ino %llu\n", (unsigned long long)vn->ino);
473 	realname = build_realname(f, vn->ino);
474 	if (realname == NULL) {
475 		fbuf->fb_err = -errno;
476 		free(fbuf->fb_dat);
477 		return (0);
478 	}
479 
480 	fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
481 	free(fbuf->fb_dat);
482 	free(realname);
483 
484 	return (0);
485 }
486 
487 static int
488 ifuse_ops_read(struct fuse *f, struct fusebuf *fbuf)
489 {
490 	struct fuse_file_info ffi;
491 	struct fuse_vnode *vn;
492 	char *realname;
493 	uint64_t offset;
494 	uint32_t size;
495 	int ret;
496 
497 	CHECK_OPT(read);
498 
499 	bzero(&ffi, sizeof(ffi));
500 	ffi.fh = fbuf->fb_io_fd;
501 	size = fbuf->fb_io_len;
502 	offset = fbuf->fb_io_off;
503 
504 	fbuf->fb_dat = malloc(size);
505 	if (fbuf->fb_dat == NULL) {
506 		fbuf->fb_err = -errno;
507 		return (0);
508 	}
509 
510 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
511 	if (vn == NULL) {
512 		fbuf->fb_err = -errno;
513 		free(fbuf->fb_dat);
514 		return (0);
515 	}
516 
517 	realname = build_realname(f, vn->ino);
518 	if (realname == NULL) {
519 		fbuf->fb_err = -errno;
520 		free(fbuf->fb_dat);
521 		return (0);
522 	}
523 
524 	ret = f->op.read(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
525 	free(realname);
526 	if (ret >= 0)
527 		fbuf->fb_len = ret;
528 	else
529 		fbuf->fb_err = ret;
530 
531 	if (fbuf->fb_len == 0)
532 		free(fbuf->fb_dat);
533 
534 	return (0);
535 }
536 
537 static int
538 ifuse_ops_write(struct fuse *f, struct fusebuf *fbuf)
539 {
540 	struct fuse_file_info ffi;
541 	struct fuse_vnode *vn;
542 	char *realname;
543 	uint64_t offset;
544 	uint32_t size;
545 	int ret;
546 
547 	CHECK_OPT(write);
548 
549 	bzero(&ffi, sizeof(ffi));
550 	ffi.fh = fbuf->fb_io_fd;
551 	ffi.fh_old = ffi.fh;
552 	ffi.writepage = fbuf->fb_io_flags & 1;
553 	size = fbuf->fb_io_len;
554 	offset = fbuf->fb_io_off;
555 
556 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
557 	if (vn == NULL) {
558 		fbuf->fb_err = -errno;
559 		free(fbuf->fb_dat);
560 		return (0);
561 	}
562 
563 	realname = build_realname(f, vn->ino);
564 	if (realname == NULL) {
565 		fbuf->fb_err = -errno;
566 		free(fbuf->fb_dat);
567 		return (0);
568 	}
569 
570 	ret = f->op.write(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
571 	free(realname);
572 	free(fbuf->fb_dat);
573 
574 	if (ret >= 0)
575 		fbuf->fb_io_len = ret;
576 	else
577 		fbuf->fb_err = ret;
578 
579 	return (0);
580 }
581 
582 static int
583 ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf)
584 {
585 	struct fuse_vnode *vn;
586 	char *realname;
587 	uint32_t mode;
588 
589 	CHECK_OPT(mkdir);
590 
591 	mode = fbuf->fb_io_mode;
592 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
593 	if (vn == NULL) {
594 		fbuf->fb_err = -errno;
595 		free(fbuf->fb_dat);
596 		return (0);
597 	}
598 
599 	free(fbuf->fb_dat);
600 	realname = build_realname(f, vn->ino);
601 	if (realname == NULL) {
602 		fbuf->fb_err = -errno;
603 		return (0);
604 	}
605 
606 	fbuf->fb_err = f->op.mkdir(realname, mode);
607 
608 	if (!fbuf->fb_err) {
609 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
610 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
611 		fbuf->fb_ino = vn->ino;
612 	}
613 	free(realname);
614 
615 	return (0);
616 }
617 
618 static int
619 ifuse_ops_rmdir(struct fuse *f, struct fusebuf *fbuf)
620 {
621 	struct fuse_vnode *vn;
622 	char *realname;
623 
624 	CHECK_OPT(rmdir);
625 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
626 	if (vn == NULL) {
627 		fbuf->fb_err = -errno;
628 		free(fbuf->fb_dat);
629 		return (0);
630 	}
631 
632 	free(fbuf->fb_dat);
633 	realname = build_realname(f, vn->ino);
634 	if (realname == NULL) {
635 		fbuf->fb_err = -errno;
636 		return (0);
637 	}
638 
639 	fbuf->fb_err = f->op.rmdir(realname);
640 	free(realname);
641 
642 	return (0);
643 }
644 
645 static int
646 ifuse_ops_readlink(struct fuse *f, struct fusebuf *fbuf)
647 {
648 	struct fuse_vnode *vn;
649 	char *realname;
650 	char name[PATH_MAX + 1];
651 	int len, ret;
652 
653 	DPRINTF("Opcode:\treadlink\n");
654 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
655 
656 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
657 	if (vn == NULL) {
658 		fbuf->fb_err = -errno;
659 		return (0);
660 	}
661 
662 	realname = build_realname(f, vn->ino);
663 	if (realname == NULL) {
664 		fbuf->fb_err = -errno;
665 		return (0);
666 	}
667 
668 	if (f->op.readlink)
669 		ret = f->op.readlink(realname, name, sizeof(name));
670 	else
671 		ret = -ENOSYS;
672 	free(realname);
673 
674 	fbuf->fb_err = ret;
675 	if (!ret) {
676 		len = strnlen(name, PATH_MAX);
677 		fbuf->fb_len = len;
678 		fbuf->fb_dat = malloc(fbuf->fb_len);
679 		if (fbuf->fb_dat == NULL) {
680 			fbuf->fb_err = -errno;
681 			return (0);
682 		}
683 		memcpy(fbuf->fb_dat, name, len);
684 	} else
685 		fbuf->fb_len = 0;
686 
687 	return (0);
688 }
689 
690 static int
691 ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf)
692 {
693 	struct fuse_vnode *vn;
694 	char *realname;
695 
696 	CHECK_OPT(unlink);
697 
698 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
699 	if (vn == NULL) {
700 		free(fbuf->fb_dat);
701 		fbuf->fb_err = -errno;
702 		return (0);
703 	}
704 
705 	free(fbuf->fb_dat);
706 	realname = build_realname(f, vn->ino);
707 	if (realname == NULL) {
708 		fbuf->fb_err = -errno;
709 		return (0);
710 	}
711 
712 	fbuf->fb_err = f->op.unlink(realname);
713 	free(realname);
714 
715 	return (0);
716 }
717 
718 static int
719 ifuse_ops_statfs(struct fuse *f, struct fusebuf *fbuf)
720 {
721 	struct fuse_vnode *vn;
722 	char *realname;
723 
724 	bzero(&fbuf->fb_stat, sizeof(fbuf->fb_stat));
725 
726 	CHECK_OPT(statfs);
727 
728 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
729 	if (vn == NULL) {
730 		fbuf->fb_err = -errno;
731 		return (0);
732 	}
733 
734 	realname = build_realname(f, vn->ino);
735 	if (realname == NULL) {
736 		fbuf->fb_err = -errno;
737 		return (0);
738 	}
739 
740 	fbuf->fb_err = f->op.statfs(realname, &fbuf->fb_stat);
741 	free(realname);
742 
743 	return (0);
744 }
745 
746 static int
747 ifuse_ops_link(struct fuse *f, struct fusebuf *fbuf)
748 {
749 	struct fuse_vnode *vn;
750 	char *realname;
751 	char *realname_ln;
752 	ino_t oldnodeid;
753 
754 	CHECK_OPT(link);
755 	oldnodeid = fbuf->fb_io_ino;
756 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
757 	if (vn == NULL) {
758 		fbuf->fb_err = -errno;
759 		free(fbuf->fb_dat);
760 		return (0);
761 	}
762 
763 	free(fbuf->fb_dat);
764 	realname = build_realname(f, oldnodeid);
765 	if (realname == NULL) {
766 		fbuf->fb_err = -errno;
767 		return (0);
768 	}
769 
770 	realname_ln = build_realname(f, vn->ino);
771 	if (realname_ln == NULL) {
772 		fbuf->fb_err = -errno;
773 		free(realname);
774 		return (0);
775 	}
776 
777 	fbuf->fb_err = f->op.link(realname, realname_ln);
778 	free(realname);
779 	free(realname_ln);
780 
781 	return (0);
782 }
783 
784 static int
785 ifuse_ops_setattr(struct fuse *f, struct fusebuf *fbuf)
786 {
787 	struct fuse_vnode *vn;
788 	struct timespec ts[2];
789 	struct utimbuf tbuf;
790 	struct fb_io *io;
791 	char *realname;
792 	uid_t uid;
793 	gid_t gid;
794 
795 	DPRINTF("Opcode:\tsetattr\n");
796 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
797 
798 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
799 	if (vn == NULL) {
800 		fbuf->fb_err = -errno;
801 		free(fbuf->fb_dat);
802 		return (0);
803 	}
804 
805 	realname = build_realname(f, vn->ino);
806 	if (realname == NULL) {
807 		fbuf->fb_err = -errno;
808 		free(fbuf->fb_dat);
809 		return (0);
810 	}
811 	io = fbtod(fbuf, struct fb_io *);
812 
813 	if (io->fi_flags & FUSE_FATTR_MODE) {
814 		if (f->op.chmod)
815 			fbuf->fb_err = f->op.chmod(realname,
816 			    fbuf->fb_attr.st_mode);
817 		else
818 			fbuf->fb_err = -ENOSYS;
819 	}
820 
821 	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_UID ||
822 	    io->fi_flags & FUSE_FATTR_GID) ) {
823 		uid = (io->fi_flags & FUSE_FATTR_UID) ?
824 		    fbuf->fb_attr.st_uid : (gid_t)-1;
825 		gid = (io->fi_flags & FUSE_FATTR_GID) ?
826 		    fbuf->fb_attr.st_gid : (uid_t)-1;
827 		if (f->op.chown)
828 			fbuf->fb_err = f->op.chown(realname, uid, gid);
829 		else
830 			fbuf->fb_err = -ENOSYS;
831 	}
832 
833 	if (!fbuf->fb_err && ( io->fi_flags & FUSE_FATTR_MTIME ||
834 		io->fi_flags & FUSE_FATTR_ATIME)) {
835 		ts[0] = fbuf->fb_attr.st_atim;
836 		ts[1] = fbuf->fb_attr.st_mtim;
837 		tbuf.actime = ts[0].tv_sec;
838 		tbuf.modtime = ts[1].tv_sec;
839 
840 		if (f->op.utimens)
841 			fbuf->fb_err = f->op.utimens(realname, ts);
842 		else if (f->op.utime)
843 			fbuf->fb_err = f->op.utime(realname, &tbuf);
844 		else
845 			fbuf->fb_err = -ENOSYS;
846 	}
847 
848 	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_SIZE)) {
849 		if (f->op.truncate)
850 			fbuf->fb_err = f->op.truncate(realname,
851 			    fbuf->fb_attr.st_size);
852 		else
853 			fbuf->fb_err = -ENOSYS;
854 	}
855 
856 	memset(&fbuf->fb_attr, 0, sizeof(struct stat));
857 
858 	if (!fbuf->fb_err)
859 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
860 	free(realname);
861 	free(fbuf->fb_dat);
862 
863 	return (0);
864 }
865 
866 static int
867 ifuse_ops_symlink(unused struct fuse *f, struct fusebuf *fbuf)
868 {
869 	struct fuse_vnode *vn;
870 	char *realname;
871 	int len;
872 
873 	CHECK_OPT(symlink);
874 
875 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
876 	if (vn == NULL) {
877 		fbuf->fb_err = -errno;
878 		free(fbuf->fb_dat);
879 		return (0);
880 	}
881 
882 	len = strlen((char *)fbuf->fb_dat);
883 
884 	realname = build_realname(f, vn->ino);
885 	if (realname == NULL) {
886 		fbuf->fb_err = -errno;
887 		free(fbuf->fb_dat);
888 		return (0);
889 	}
890 
891 	/* fuse invert the symlink params */
892 	fbuf->fb_err = f->op.symlink((const char *)&fbuf->fb_dat[len + 1],
893 	    realname);
894 	fbuf->fb_ino = vn->ino;
895 	free(fbuf->fb_dat);
896 	free(realname);
897 
898 	return (0);
899 }
900 
901 static int
902 ifuse_ops_rename(struct fuse *f, struct fusebuf *fbuf)
903 {
904 	struct fuse_vnode *vnt;
905 	struct fuse_vnode *vnf;
906 	char *realnamef;
907 	char *realnamet;
908 	int len;
909 
910 	CHECK_OPT(rename);
911 
912 	len = strlen((char *)fbuf->fb_dat);
913 	vnf = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
914 	if (vnf == NULL) {
915 		fbuf->fb_err = -errno;
916 		free(fbuf->fb_dat);
917 		return (0);
918 	}
919 
920 	vnt = get_vn_by_name_and_parent(f, &fbuf->fb_dat[len + 1],
921 	    fbuf->fb_io_ino);
922 	if (vnt == NULL) {
923 		fbuf->fb_err = -errno;
924 		free(fbuf->fb_dat);
925 		return (0);
926 	}
927 
928 	free(fbuf->fb_dat);
929 
930 	realnamef = build_realname(f, vnf->ino);
931 	if (realnamef == NULL) {
932 		fbuf->fb_err = -errno;
933 		return (0);
934 	}
935 
936 	realnamet = build_realname(f, vnt->ino);
937 	if (realnamet == NULL) {
938 		fbuf->fb_err = -errno;
939 		free(realnamef);
940 		return (0);
941 	}
942 
943 	fbuf->fb_err = f->op.rename(realnamef, realnamet);
944 	free(realnamef);
945 	free(realnamet);
946 
947 	return (0);
948 }
949 
950 static int
951 ifuse_ops_destroy(struct fuse *f)
952 {
953 	struct fuse_context *ctx;
954 
955 	DPRINTF("Opcode:\tdestroy\n");
956 
957 	if (f->op.destroy) {
958 		ctx = fuse_get_context();
959 
960 		f->op.destroy((ctx)?ctx->private_data:NULL);
961 	}
962 
963 	f->fc->dead = 1;
964 
965 	return (0);
966 }
967 
968 static int
969 ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf)
970 {
971 	struct fuse_vnode *vn;
972 
973 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
974 	if (vn != NULL)
975 		unref_vn(f, vn);
976 
977 	return (0);
978 }
979 
980 static int
981 ifuse_ops_mknod(struct fuse *f, struct fusebuf *fbuf)
982 {
983 	struct fuse_vnode *vn;
984 	char *realname;
985 	uint32_t mode;
986 	dev_t dev;
987 
988 	CHECK_OPT(mknod);
989 
990 	mode = fbuf->fb_io_mode;
991 	dev = fbuf->fb_io_rdev;
992 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
993 	if (vn == NULL) {
994 		fbuf->fb_err = -errno;
995 		free(fbuf->fb_dat);
996 		return (0);
997 	}
998 
999 	free(fbuf->fb_dat);
1000 	realname = build_realname(f, vn->ino);
1001 	if (realname == NULL) {
1002 		fbuf->fb_err = -errno;
1003 		return (0);
1004 	}
1005 
1006 	fbuf->fb_err = f->op.mknod(realname, mode, dev);
1007 
1008 	if (!fbuf->fb_err) {
1009 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
1010 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
1011 		fbuf->fb_ino = fbuf->fb_attr.st_ino;
1012 	}
1013 	free(realname);
1014 
1015 	return (0);
1016 }
1017 
1018 int
1019 ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
1020 {
1021 	int ret = 0;
1022 
1023 	fbuf->fb_len = 0;
1024 	fbuf->fb_err = 0;
1025 
1026 	switch (fbuf->fb_type) {
1027 	case FBT_LOOKUP:
1028 		ret = ifuse_ops_lookup(f, fbuf);
1029 		break;
1030 	case FBT_GETATTR:
1031 		ret = ifuse_ops_getattr(f, fbuf);
1032 		break;
1033 	case FBT_SETATTR:
1034 		ret = ifuse_ops_setattr(f, fbuf);
1035 		break;
1036 	case FBT_READLINK:
1037 		ret = ifuse_ops_readlink(f, fbuf);
1038 		break;
1039 	case FBT_MKDIR:
1040 		ret = ifuse_ops_mkdir(f, fbuf);
1041 		break;
1042 	case FBT_UNLINK:
1043 		ret = ifuse_ops_unlink(f, fbuf);
1044 		break;
1045 	case FBT_RMDIR:
1046 		ret = ifuse_ops_rmdir(f, fbuf);
1047 		break;
1048 	case FBT_LINK:
1049 		ret = ifuse_ops_link(f, fbuf);
1050 		break;
1051 	case FBT_OPEN:
1052 		ret = ifuse_ops_open(f, fbuf);
1053 		break;
1054 	case FBT_READ:
1055 		ret = ifuse_ops_read(f, fbuf);
1056 		break;
1057 	case FBT_WRITE:
1058 		ret = ifuse_ops_write(f, fbuf);
1059 		break;
1060 	case FBT_STATFS:
1061 		ret = ifuse_ops_statfs(f, fbuf);
1062 		break;
1063 	case FBT_RELEASE:
1064 		ret = ifuse_ops_release(f, fbuf);
1065 		break;
1066 	case FBT_INIT:
1067 		ret = ifuse_ops_init(f);
1068 		break;
1069 	case FBT_OPENDIR:
1070 		ret = ifuse_ops_opendir(f, fbuf);
1071 		break;
1072 	case FBT_READDIR:
1073 		ret = ifuse_ops_readdir(f, fbuf);
1074 		break;
1075 	case FBT_RELEASEDIR:
1076 		ret = ifuse_ops_releasedir(f, fbuf);
1077 		break;
1078 	case FBT_ACCESS:
1079 		ret = ifuse_ops_access(f, fbuf);
1080 		break;
1081 	case FBT_SYMLINK:
1082 		ret = ifuse_ops_symlink(f, fbuf);
1083 		break;
1084 	case FBT_RENAME:
1085 		ret = ifuse_ops_rename(f, fbuf);
1086 		break;
1087 	case FBT_DESTROY:
1088 		ret = ifuse_ops_destroy(f);
1089 		break;
1090 	case FBT_RECLAIM:
1091 		ret = ifuse_ops_reclaim(f, fbuf);
1092 		break;
1093 	case FBT_MKNOD:
1094 		ret = ifuse_ops_mknod(f, fbuf);
1095 		break;
1096 	default:
1097 		DPRINTF("Opcode:\t%i not supported\n", fbuf->fb_type);
1098 		DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
1099 
1100 		fbuf->fb_err = -ENOSYS;
1101 		fbuf->fb_len = 0;
1102 	}
1103 	DPRINTF("\n");
1104 
1105 	/* fuse api use negative errno */
1106 	fbuf->fb_err = -fbuf->fb_err;
1107 	return (ret);
1108 }
1109