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