xref: /openbsd-src/lib/libfuse/fuse_ops.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /* $OpenBSD: fuse_ops.c,v 1.26 2016/09/07 17:53:35 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 	if (strcmp((const char *)fbuf->fb_dat, "..") == 0) {
436 		vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
437 		if (vn == NULL || vn->parent == NULL) {
438 			fbuf->fb_err = -ENOENT;
439 			return (0);
440 		}
441 		vn = vn->parent;
442 		if (vn->ino != FUSE_ROOT_INO)
443 			ref_vn(vn);
444 	} else {
445 		vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
446 		if (vn == NULL) {
447 			vn = alloc_vn(f, (const char *)fbuf->fb_dat, -1,
448 			    fbuf->fb_ino);
449 			if (vn == NULL) {
450 				fbuf->fb_err = -errno;
451 				free(fbuf->fb_dat);
452 				return (0);
453 			}
454 			set_vn(f, vn); /*XXX*/
455 		} else if (vn->ino != FUSE_ROOT_INO)
456 			ref_vn(vn);
457 	}
458 
459 	DPRINTF("new ino %llu\n", (unsigned long long)vn->ino);
460 	realname = build_realname(f, vn->ino);
461 	if (realname == NULL) {
462 		fbuf->fb_err = -errno;
463 		free(fbuf->fb_dat);
464 		return (0);
465 	}
466 
467 	fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
468 	free(fbuf->fb_dat);
469 	free(realname);
470 
471 	return (0);
472 }
473 
474 static int
475 ifuse_ops_read(struct fuse *f, struct fusebuf *fbuf)
476 {
477 	struct fuse_file_info ffi;
478 	struct fuse_vnode *vn;
479 	char *realname;
480 	uint64_t offset;
481 	uint32_t size;
482 	int ret;
483 
484 	CHECK_OPT(read);
485 
486 	bzero(&ffi, sizeof(ffi));
487 	ffi.fh = fbuf->fb_io_fd;
488 	size = fbuf->fb_io_len;
489 	offset = fbuf->fb_io_off;
490 
491 	fbuf->fb_dat = malloc(size);
492 	if (fbuf->fb_dat == NULL) {
493 		fbuf->fb_err = -errno;
494 		return (0);
495 	}
496 
497 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
498 	if (vn == NULL) {
499 		fbuf->fb_err = -errno;
500 		free(fbuf->fb_dat);
501 		return (0);
502 	}
503 
504 	realname = build_realname(f, vn->ino);
505 	if (realname == NULL) {
506 		fbuf->fb_err = -errno;
507 		free(fbuf->fb_dat);
508 		return (0);
509 	}
510 
511 	ret = f->op.read(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
512 	free(realname);
513 	if (ret >= 0)
514 		fbuf->fb_len = ret;
515 	else
516 		fbuf->fb_err = ret;
517 
518 	if (fbuf->fb_len == 0)
519 		free(fbuf->fb_dat);
520 
521 	return (0);
522 }
523 
524 static int
525 ifuse_ops_write(struct fuse *f, struct fusebuf *fbuf)
526 {
527 	struct fuse_file_info ffi;
528 	struct fuse_vnode *vn;
529 	char *realname;
530 	uint64_t offset;
531 	uint32_t size;
532 	int ret;
533 
534 	CHECK_OPT(write);
535 
536 	bzero(&ffi, sizeof(ffi));
537 	ffi.fh = fbuf->fb_io_fd;
538 	ffi.fh_old = ffi.fh;
539 	ffi.writepage = fbuf->fb_io_flags & 1;
540 	size = fbuf->fb_io_len;
541 	offset = fbuf->fb_io_off;
542 
543 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
544 	if (vn == NULL) {
545 		fbuf->fb_err = -errno;
546 		free(fbuf->fb_dat);
547 		return (0);
548 	}
549 
550 	realname = build_realname(f, vn->ino);
551 	if (realname == NULL) {
552 		fbuf->fb_err = -errno;
553 		free(fbuf->fb_dat);
554 		return (0);
555 	}
556 
557 	ret = f->op.write(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
558 	free(realname);
559 	free(fbuf->fb_dat);
560 
561 	if (ret >= 0)
562 		fbuf->fb_io_len = ret;
563 	else
564 		fbuf->fb_err = ret;
565 
566 	return (0);
567 }
568 
569 static int
570 ifuse_ops_create(struct fuse *f, struct fusebuf *fbuf)
571 {
572 	struct fuse_file_info ffi;
573 	struct fuse_vnode *vn;
574 	uint32_t mode;
575 
576 	char *realname;
577 
578 	DPRINTF("Opcode:\tcreate\n");
579 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
580 
581 	bzero(&ffi, sizeof(ffi));
582 	ffi.flags = fbuf->fb_io_flags;
583 	mode = fbuf->fb_io_mode;
584 
585 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
586 	if (vn == NULL) {
587 		fbuf->fb_err = -errno;
588 		free(fbuf->fb_dat);
589 		return (0);
590 	}
591 
592 	free(fbuf->fb_dat);
593 	realname = build_realname(f, vn->ino);
594 	if (realname == NULL) {
595 		fbuf->fb_err = -errno;
596 		return (0);
597 	}
598 
599 	if (f->op.create)
600 		fbuf->fb_err = f->op.create(realname, mode,  &ffi);
601 	else if (f->op.mknod)
602 		fbuf->fb_err = f->op.mknod(realname, S_IFREG | mode, 0);
603 	else
604 		fbuf->fb_err = -ENOSYS;
605 
606 	if (!fbuf->fb_err) {
607 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
608 		fbuf->fb_ino = fbuf->fb_attr.st_ino;
609 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
610 	}
611 	free(realname);
612 
613 	return (0);
614 }
615 
616 static int
617 ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf)
618 {
619 	struct fuse_vnode *vn;
620 	char *realname;
621 	uint32_t mode;
622 
623 	CHECK_OPT(mkdir);
624 
625 	mode = fbuf->fb_io_mode;
626 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
627 	if (vn == NULL) {
628 		fbuf->fb_err = -errno;
629 		free(fbuf->fb_dat);
630 		return (0);
631 	}
632 
633 	free(fbuf->fb_dat);
634 	realname = build_realname(f, vn->ino);
635 	if (realname == NULL) {
636 		fbuf->fb_err = -errno;
637 		return (0);
638 	}
639 
640 	fbuf->fb_err = f->op.mkdir(realname, mode);
641 
642 	if (!fbuf->fb_err) {
643 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
644 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
645 		fbuf->fb_ino = vn->ino;
646 	}
647 	free(realname);
648 
649 	return (0);
650 }
651 
652 static int
653 ifuse_ops_rmdir(struct fuse *f, struct fusebuf *fbuf)
654 {
655 	struct fuse_vnode *vn;
656 	char *realname;
657 
658 	CHECK_OPT(rmdir);
659 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
660 	if (vn == NULL) {
661 		fbuf->fb_err = -errno;
662 		free(fbuf->fb_dat);
663 		return (0);
664 	}
665 
666 	free(fbuf->fb_dat);
667 	realname = build_realname(f, vn->ino);
668 	if (realname == NULL) {
669 		fbuf->fb_err = -errno;
670 		return (0);
671 	}
672 
673 	fbuf->fb_err = f->op.rmdir(realname);
674 	free(realname);
675 
676 	return (0);
677 }
678 
679 static int
680 ifuse_ops_readlink(struct fuse *f, struct fusebuf *fbuf)
681 {
682 	struct fuse_vnode *vn;
683 	char *realname;
684 	char name[PATH_MAX + 1];
685 	int len, ret;
686 
687 	DPRINTF("Opcode:\treadlink\n");
688 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
689 
690 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
691 	if (vn == NULL) {
692 		fbuf->fb_err = -errno;
693 		return (0);
694 	}
695 
696 	realname = build_realname(f, vn->ino);
697 	if (realname == NULL) {
698 		fbuf->fb_err = -errno;
699 		return (0);
700 	}
701 
702 	if (f->op.readlink)
703 		ret = f->op.readlink(realname, name, sizeof(name));
704 	else
705 		ret = -ENOSYS;
706 	free(realname);
707 
708 	fbuf->fb_err = ret;
709 	if (!ret) {
710 		len = strnlen(name, PATH_MAX);
711 		fbuf->fb_len = len;
712 		fbuf->fb_dat = malloc(fbuf->fb_len);
713 		if (fbuf->fb_dat == NULL) {
714 			fbuf->fb_err = -errno;
715 			return (0);
716 		}
717 		memcpy(fbuf->fb_dat, name, len);
718 	} else
719 		fbuf->fb_len = 0;
720 
721 	return (0);
722 }
723 
724 static int
725 ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf)
726 {
727 	struct fuse_vnode *vn;
728 	char *realname;
729 
730 	CHECK_OPT(unlink);
731 
732 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
733 	if (vn == NULL) {
734 		free(fbuf->fb_dat);
735 		fbuf->fb_err = -errno;
736 		return (0);
737 	}
738 
739 	free(fbuf->fb_dat);
740 	realname = build_realname(f, vn->ino);
741 	if (realname == NULL) {
742 		fbuf->fb_err = -errno;
743 		return (0);
744 	}
745 
746 	fbuf->fb_err = f->op.unlink(realname);
747 	free(realname);
748 
749 	return (0);
750 }
751 
752 static int
753 ifuse_ops_statfs(struct fuse *f, struct fusebuf *fbuf)
754 {
755 	struct fuse_vnode *vn;
756 	char *realname;
757 
758 	bzero(&fbuf->fb_stat, sizeof(fbuf->fb_stat));
759 
760 	CHECK_OPT(statfs);
761 
762 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
763 	if (vn == NULL) {
764 		fbuf->fb_err = -errno;
765 		return (0);
766 	}
767 
768 	realname = build_realname(f, vn->ino);
769 	if (realname == NULL) {
770 		fbuf->fb_err = -errno;
771 		return (0);
772 	}
773 
774 	fbuf->fb_err = f->op.statfs(realname, &fbuf->fb_stat);
775 	free(realname);
776 
777 	return (0);
778 }
779 
780 static int
781 ifuse_ops_link(struct fuse *f, struct fusebuf *fbuf)
782 {
783 	struct fuse_vnode *vn;
784 	char *realname;
785 	char *realname_ln;
786 	ino_t oldnodeid;
787 
788 	CHECK_OPT(link);
789 	oldnodeid = fbuf->fb_io_ino;
790 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
791 	if (vn == NULL) {
792 		fbuf->fb_err = -errno;
793 		free(fbuf->fb_dat);
794 		return (0);
795 	}
796 
797 	free(fbuf->fb_dat);
798 	realname = build_realname(f, oldnodeid);
799 	if (realname == NULL) {
800 		fbuf->fb_err = -errno;
801 		return (0);
802 	}
803 
804 	realname_ln = build_realname(f, vn->ino);
805 	if (realname_ln == NULL) {
806 		fbuf->fb_err = -errno;
807 		free(realname);
808 		return (0);
809 	}
810 
811 	fbuf->fb_err = f->op.link(realname, realname_ln);
812 	free(realname);
813 	free(realname_ln);
814 
815 	return (0);
816 }
817 
818 static int
819 ifuse_ops_setattr(struct fuse *f, struct fusebuf *fbuf)
820 {
821 	struct fuse_vnode *vn;
822 	struct timespec ts[2];
823 	struct utimbuf tbuf;
824 	struct fb_io *io;
825 	char *realname;
826 	uid_t uid;
827 	gid_t gid;
828 
829 	DPRINTF("Opcode:\tsetattr\n");
830 	DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
831 
832 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
833 	if (vn == NULL) {
834 		fbuf->fb_err = -errno;
835 		free(fbuf->fb_dat);
836 		return (0);
837 	}
838 
839 	realname = build_realname(f, vn->ino);
840 	if (realname == NULL) {
841 		fbuf->fb_err = -errno;
842 		free(fbuf->fb_dat);
843 		return (0);
844 	}
845 	io = fbtod(fbuf, struct fb_io *);
846 
847 	if (io->fi_flags & FUSE_FATTR_MODE) {
848 		if (f->op.chmod)
849 			fbuf->fb_err = f->op.chmod(realname,
850 			    fbuf->fb_attr.st_mode);
851 		else
852 			fbuf->fb_err = -ENOSYS;
853 	}
854 
855 	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_UID ||
856 	    io->fi_flags & FUSE_FATTR_GID) ) {
857 		uid = (io->fi_flags & FUSE_FATTR_UID) ?
858 		    fbuf->fb_attr.st_uid : (gid_t)-1;
859 		gid = (io->fi_flags & FUSE_FATTR_GID) ?
860 		    fbuf->fb_attr.st_gid : (uid_t)-1;
861 		if (f->op.chown)
862 			fbuf->fb_err = f->op.chown(realname, uid, gid);
863 		else
864 			fbuf->fb_err = -ENOSYS;
865 	}
866 
867 	if (!fbuf->fb_err && ( io->fi_flags & FUSE_FATTR_MTIME ||
868 		io->fi_flags & FUSE_FATTR_ATIME)) {
869 		ts[0] = fbuf->fb_attr.st_atim;
870 		ts[1] = fbuf->fb_attr.st_mtim;
871 		tbuf.actime = ts[0].tv_sec;
872 		tbuf.modtime = ts[1].tv_sec;
873 
874 		if (f->op.utimens)
875 			fbuf->fb_err = f->op.utimens(realname, ts);
876 		else if (f->op.utime)
877 			fbuf->fb_err = f->op.utime(realname, &tbuf);
878 		else
879 			fbuf->fb_err = -ENOSYS;
880 	}
881 
882 	if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_SIZE)) {
883 		if (f->op.truncate)
884 			fbuf->fb_err = f->op.truncate(realname,
885 			    fbuf->fb_attr.st_size);
886 		else
887 			fbuf->fb_err = -ENOSYS;
888 	}
889 
890 	memset(&fbuf->fb_attr, 0, sizeof(struct stat));
891 
892 	if (!fbuf->fb_err)
893 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
894 	free(realname);
895 	free(fbuf->fb_dat);
896 
897 	return (0);
898 }
899 
900 static int
901 ifuse_ops_symlink(unused struct fuse *f, struct fusebuf *fbuf)
902 {
903 	struct fuse_vnode *vn;
904 	char *realname;
905 	int len;
906 
907 	CHECK_OPT(symlink);
908 
909 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
910 	if (vn == NULL) {
911 		fbuf->fb_err = -errno;
912 		free(fbuf->fb_dat);
913 		return (0);
914 	}
915 
916 	len = strlen((char *)fbuf->fb_dat);
917 
918 	realname = build_realname(f, vn->ino);
919 	if (realname == NULL) {
920 		fbuf->fb_err = -errno;
921 		free(fbuf->fb_dat);
922 		return (0);
923 	}
924 
925 	/* fuse invert the symlink params */
926 	fbuf->fb_err = f->op.symlink((const char *)&fbuf->fb_dat[len + 1],
927 	    realname);
928 	fbuf->fb_ino = vn->ino;
929 	free(fbuf->fb_dat);
930 	free(realname);
931 
932 	return (0);
933 }
934 
935 static int
936 ifuse_ops_rename(struct fuse *f, struct fusebuf *fbuf)
937 {
938 	struct fuse_vnode *vnt;
939 	struct fuse_vnode *vnf;
940 	char *realnamef;
941 	char *realnamet;
942 	int len;
943 
944 	CHECK_OPT(rename);
945 
946 	len = strlen((char *)fbuf->fb_dat);
947 	vnf = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
948 	if (vnf == NULL) {
949 		fbuf->fb_err = -errno;
950 		free(fbuf->fb_dat);
951 		return (0);
952 	}
953 
954 	vnt = get_vn_by_name_and_parent(f, &fbuf->fb_dat[len + 1],
955 	    fbuf->fb_io_ino);
956 	if (vnt == NULL) {
957 		fbuf->fb_err = -errno;
958 		free(fbuf->fb_dat);
959 		return (0);
960 	}
961 
962 	free(fbuf->fb_dat);
963 
964 	realnamef = build_realname(f, vnf->ino);
965 	if (realnamef == NULL) {
966 		fbuf->fb_err = -errno;
967 		return (0);
968 	}
969 
970 	realnamet = build_realname(f, vnt->ino);
971 	if (realnamet == NULL) {
972 		fbuf->fb_err = -errno;
973 		free(realnamef);
974 		return (0);
975 	}
976 
977 	fbuf->fb_err = f->op.rename(realnamef, realnamet);
978 	free(realnamef);
979 	free(realnamet);
980 
981 	return (0);
982 }
983 
984 static int
985 ifuse_ops_destroy(struct fuse *f)
986 {
987 	struct fuse_context *ctx;
988 
989 	DPRINTF("Opcode:\tdestroy\n");
990 
991 	if (f->op.destroy) {
992 		ctx = fuse_get_context();
993 
994 		f->op.destroy((ctx)?ctx->private_data:NULL);
995 	}
996 
997 	f->fc->dead = 1;
998 
999 	return (0);
1000 }
1001 
1002 static int
1003 ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf)
1004 {
1005 	struct fuse_vnode *vn;
1006 
1007 	vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
1008 	if (vn != NULL)
1009 		unref_vn(f, vn);
1010 
1011 	return (0);
1012 }
1013 
1014 static int
1015 ifuse_ops_mknod(struct fuse *f, struct fusebuf *fbuf)
1016 {
1017 	struct fuse_vnode *vn;
1018 	char *realname;
1019 	uint32_t mode;
1020 	dev_t dev;
1021 
1022 	CHECK_OPT(mknod);
1023 
1024 	mode = fbuf->fb_io_mode;
1025 	dev = fbuf->fb_io_rdev;
1026 	vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
1027 	if (vn == NULL) {
1028 		fbuf->fb_err = -errno;
1029 		free(fbuf->fb_dat);
1030 		return (0);
1031 	}
1032 
1033 	free(fbuf->fb_dat);
1034 	realname = build_realname(f, vn->ino);
1035 	if (realname == NULL) {
1036 		fbuf->fb_err = -errno;
1037 		return (0);
1038 	}
1039 
1040 	fbuf->fb_err = f->op.mknod(realname, mode, dev);
1041 
1042 	if (!fbuf->fb_err) {
1043 		fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
1044 		fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
1045 		fbuf->fb_ino = fbuf->fb_attr.st_ino;
1046 	}
1047 	free(realname);
1048 
1049 	return (0);
1050 }
1051 
1052 int
1053 ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
1054 {
1055 	int ret = 0;
1056 
1057 	fbuf->fb_len = 0;
1058 	fbuf->fb_err = 0;
1059 
1060 	switch (fbuf->fb_type) {
1061 	case FBT_LOOKUP:
1062 		ret = ifuse_ops_lookup(f, fbuf);
1063 		break;
1064 	case FBT_GETATTR:
1065 		ret = ifuse_ops_getattr(f, fbuf);
1066 		break;
1067 	case FBT_SETATTR:
1068 		ret = ifuse_ops_setattr(f, fbuf);
1069 		break;
1070 	case FBT_READLINK:
1071 		ret = ifuse_ops_readlink(f, fbuf);
1072 		break;
1073 	case FBT_MKDIR:
1074 		ret = ifuse_ops_mkdir(f, fbuf);
1075 		break;
1076 	case FBT_UNLINK:
1077 		ret = ifuse_ops_unlink(f, fbuf);
1078 		break;
1079 	case FBT_RMDIR:
1080 		ret = ifuse_ops_rmdir(f, fbuf);
1081 		break;
1082 	case FBT_LINK:
1083 		ret = ifuse_ops_link(f, fbuf);
1084 		break;
1085 	case FBT_OPEN:
1086 		ret = ifuse_ops_open(f, fbuf);
1087 		break;
1088 	case FBT_READ:
1089 		ret = ifuse_ops_read(f, fbuf);
1090 		break;
1091 	case FBT_WRITE:
1092 		ret = ifuse_ops_write(f, fbuf);
1093 		break;
1094 	case FBT_STATFS:
1095 		ret = ifuse_ops_statfs(f, fbuf);
1096 		break;
1097 	case FBT_RELEASE:
1098 		ret = ifuse_ops_release(f, fbuf);
1099 		break;
1100 	case FBT_INIT:
1101 		ret = ifuse_ops_init(f);
1102 		break;
1103 	case FBT_OPENDIR:
1104 		ret = ifuse_ops_opendir(f, fbuf);
1105 		break;
1106 	case FBT_READDIR:
1107 		ret = ifuse_ops_readdir(f, fbuf);
1108 		break;
1109 	case FBT_RELEASEDIR:
1110 		ret = ifuse_ops_releasedir(f, fbuf);
1111 		break;
1112 	case FBT_ACCESS:
1113 		ret = ifuse_ops_access(f, fbuf);
1114 		break;
1115 	case FBT_CREATE:
1116 		ret = ifuse_ops_create(f, fbuf);
1117 		break;
1118 	case FBT_SYMLINK:
1119 		ret = ifuse_ops_symlink(f, fbuf);
1120 		break;
1121 	case FBT_RENAME:
1122 		ret = ifuse_ops_rename(f, fbuf);
1123 		break;
1124 	case FBT_DESTROY:
1125 		ret = ifuse_ops_destroy(f);
1126 		break;
1127 	case FBT_RECLAIM:
1128 		ret = ifuse_ops_reclaim(f, fbuf);
1129 		break;
1130 	case FBT_MKNOD:
1131 		ret = ifuse_ops_mknod(f, fbuf);
1132 		break;
1133 	default:
1134 		DPRINTF("Opcode:\t%i not supported\n", fbuf->fb_type);
1135 		DPRINTF("Inode:\t%llu\n", (unsigned long long)fbuf->fb_ino);
1136 
1137 		fbuf->fb_err = -ENOSYS;
1138 		fbuf->fb_len = 0;
1139 	}
1140 	DPRINTF("\n");
1141 
1142 	/* fuse api use negative errno */
1143 	fbuf->fb_err = -fbuf->fb_err;
1144 	return (ret);
1145 }
1146