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