1*0d644658Shelg /* $OpenBSD: fuse_ops.c,v 1.35 2018/07/16 13:10:53 helg Exp $ */
275af46c2Stedu /*
375af46c2Stedu * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
475af46c2Stedu *
575af46c2Stedu * Permission to use, copy, modify, and distribute this software for any
675af46c2Stedu * purpose with or without fee is hereby granted, provided that the above
775af46c2Stedu * copyright notice and this permission notice appear in all copies.
875af46c2Stedu *
975af46c2Stedu * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1075af46c2Stedu * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1175af46c2Stedu * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1275af46c2Stedu * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1375af46c2Stedu * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1475af46c2Stedu * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1575af46c2Stedu * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1675af46c2Stedu */
1775af46c2Stedu
1875af46c2Stedu #include <errno.h>
1975af46c2Stedu #include <string.h>
2075af46c2Stedu #include <stdlib.h>
2175af46c2Stedu
2275af46c2Stedu #include "fuse_private.h"
2375af46c2Stedu #include "debug.h"
2475af46c2Stedu
251f45a5acShelg #define CHECK_OPT(opname) DPRINTF("Opcode: %s\t", #opname); \
261f45a5acShelg DPRINTF("Inode: %llu\t", \
2736ac2e2aSguenther (unsigned long long)fbuf->fb_ino); \
2875af46c2Stedu if (!f->op.opname) { \
2975af46c2Stedu fbuf->fb_err = -ENOSYS; \
3075af46c2Stedu return (0); \
3175af46c2Stedu }
3275af46c2Stedu
3375af46c2Stedu static int
update_attr(struct fuse * f,struct stat * attr,const char * realname,struct fuse_vnode * vn)346f9b5942Snatano update_attr(struct fuse *f, struct stat *attr, const char *realname,
3575af46c2Stedu struct fuse_vnode *vn)
3675af46c2Stedu {
3775af46c2Stedu int ret;
3875af46c2Stedu
396f9b5942Snatano memset(attr, 0, sizeof(struct stat));
406f9b5942Snatano ret = f->op.getattr(realname, attr);
4175af46c2Stedu
426f9b5942Snatano if (attr->st_blksize == 0)
436f9b5942Snatano attr->st_blksize = 512;
446f9b5942Snatano if (attr->st_blocks == 0)
456f9b5942Snatano attr->st_blocks = 4;
46250f478bSsyl
47dae5ffecShelg if (!f->conf.use_ino)
486f9b5942Snatano attr->st_ino = vn->ino;
4975af46c2Stedu
5075af46c2Stedu if (f->conf.set_mode)
516f9b5942Snatano attr->st_mode = (attr->st_mode & S_IFMT) | (0777 & ~f->conf.umask);
5275af46c2Stedu
5375af46c2Stedu if (f->conf.set_uid)
546f9b5942Snatano attr->st_uid = f->conf.uid;
5575af46c2Stedu
5675af46c2Stedu if (f->conf.set_gid)
576f9b5942Snatano attr->st_gid = f->conf.gid;
5875af46c2Stedu
5975af46c2Stedu return (ret);
6075af46c2Stedu }
6175af46c2Stedu
6275af46c2Stedu static int
ifuse_ops_init(struct fuse * f)6354e529adSsyl ifuse_ops_init(struct fuse *f)
6475af46c2Stedu {
6554e529adSsyl struct fuse_conn_info fci;
6654e529adSsyl
671f45a5acShelg DPRINTF("Opcode: init\t");
6854e529adSsyl
6954e529adSsyl if (f->op.init) {
70bb72b40bShelg memset(&fci, 0, sizeof(fci));
7154e529adSsyl fci.proto_minor = FUSE_MINOR_VERSION;
7254e529adSsyl fci.proto_major = FUSE_MAJOR_VERSION;
7354e529adSsyl
7454e529adSsyl f->op.init(&fci);
7554e529adSsyl }
7675af46c2Stedu return (0);
7775af46c2Stedu }
7875af46c2Stedu
7975af46c2Stedu static int
ifuse_ops_getattr(struct fuse * f,struct fusebuf * fbuf)8075af46c2Stedu ifuse_ops_getattr(struct fuse *f, struct fusebuf *fbuf)
8175af46c2Stedu {
8275af46c2Stedu struct fuse_vnode *vn;
8375af46c2Stedu char *realname;
8475af46c2Stedu
851f45a5acShelg DPRINTF("Opcode: getattr\t");
861f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
8775af46c2Stedu
886f9b5942Snatano memset(&fbuf->fb_attr, 0, sizeof(struct stat));
8975af46c2Stedu
9075af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
9177cffba6Ssyl if (vn == NULL) {
9277cffba6Ssyl fbuf->fb_err = -errno;
9377cffba6Ssyl return (0);
9477cffba6Ssyl }
9575af46c2Stedu
9675af46c2Stedu realname = build_realname(f, vn->ino);
9777cffba6Ssyl if (realname == NULL) {
9877cffba6Ssyl fbuf->fb_err = -errno;
9977cffba6Ssyl return (0);
10077cffba6Ssyl }
10177cffba6Ssyl
1026f9b5942Snatano fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
10375af46c2Stedu free(realname);
10475af46c2Stedu
10575af46c2Stedu return (0);
10675af46c2Stedu }
10775af46c2Stedu
10875af46c2Stedu static int
ifuse_ops_access(struct fuse * f,struct fusebuf * fbuf)10975af46c2Stedu ifuse_ops_access(struct fuse *f, struct fusebuf *fbuf)
11075af46c2Stedu {
11175af46c2Stedu struct fuse_vnode *vn;
11275af46c2Stedu char *realname;
11375af46c2Stedu
11475af46c2Stedu CHECK_OPT(access);
11575af46c2Stedu
11675af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
11777cffba6Ssyl if (vn == NULL) {
11877cffba6Ssyl fbuf->fb_err = -errno;
11977cffba6Ssyl return (0);
12077cffba6Ssyl }
12175af46c2Stedu
12275af46c2Stedu realname = build_realname(f, vn->ino);
12377cffba6Ssyl if (realname == NULL) {
12477cffba6Ssyl fbuf->fb_err = -errno;
12577cffba6Ssyl return (0);
12677cffba6Ssyl }
12777cffba6Ssyl
12875af46c2Stedu fbuf->fb_err = f->op.access(realname, fbuf->fb_io_mode);
12975af46c2Stedu free(realname);
13075af46c2Stedu
13175af46c2Stedu return (0);
13275af46c2Stedu }
13375af46c2Stedu
13475af46c2Stedu static int
ifuse_ops_open(struct fuse * f,struct fusebuf * fbuf)13575af46c2Stedu ifuse_ops_open(struct fuse *f, struct fusebuf *fbuf)
13675af46c2Stedu {
13775af46c2Stedu struct fuse_file_info ffi;
13875af46c2Stedu struct fuse_vnode *vn;
13975af46c2Stedu char *realname;
14075af46c2Stedu
14175af46c2Stedu CHECK_OPT(open);
14275af46c2Stedu
143bb72b40bShelg memset(&ffi, 0, sizeof(ffi));
14475af46c2Stedu ffi.flags = fbuf->fb_io_flags;
14575af46c2Stedu
14675af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
14777cffba6Ssyl if (vn == NULL) {
14877cffba6Ssyl fbuf->fb_err = -errno;
14977cffba6Ssyl return (0);
15077cffba6Ssyl }
15175af46c2Stedu
15275af46c2Stedu realname = build_realname(f, vn->ino);
15377cffba6Ssyl if (realname == NULL) {
15477cffba6Ssyl fbuf->fb_err = -errno;
15577cffba6Ssyl return (0);
15677cffba6Ssyl }
15777cffba6Ssyl
15875af46c2Stedu fbuf->fb_err = f->op.open(realname, &ffi);
15975af46c2Stedu free(realname);
16075af46c2Stedu
16175af46c2Stedu if (!fbuf->fb_err)
16275af46c2Stedu fbuf->fb_io_fd = ffi.fh;
16375af46c2Stedu
16475af46c2Stedu return (0);
16575af46c2Stedu }
16675af46c2Stedu
16775af46c2Stedu static int
ifuse_ops_opendir(struct fuse * f,struct fusebuf * fbuf)16875af46c2Stedu ifuse_ops_opendir(struct fuse *f, struct fusebuf *fbuf)
16975af46c2Stedu {
17075af46c2Stedu struct fuse_file_info ffi;
17175af46c2Stedu struct fuse_vnode *vn;
17275af46c2Stedu char *realname;
17375af46c2Stedu
1741f45a5acShelg DPRINTF("Opcode: opendir\t");
1751f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
17675af46c2Stedu
17775af46c2Stedu memset(&ffi, 0, sizeof(ffi));
17875af46c2Stedu ffi.flags = fbuf->fb_io_flags;
17975af46c2Stedu
18075af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
18177cffba6Ssyl if (vn == NULL) {
18277cffba6Ssyl fbuf->fb_err = -errno;
18377cffba6Ssyl return (0);
18477cffba6Ssyl }
18575af46c2Stedu
18675af46c2Stedu if (f->op.opendir) {
18775af46c2Stedu realname = build_realname(f, vn->ino);
18877cffba6Ssyl if (realname == NULL) {
18977cffba6Ssyl fbuf->fb_err = -errno;
19077cffba6Ssyl return (0);
19177cffba6Ssyl }
19277cffba6Ssyl
19375af46c2Stedu fbuf->fb_err = f->op.opendir(realname, &ffi);
19475af46c2Stedu free(realname);
19575af46c2Stedu }
19675af46c2Stedu
197390f10b5Shelg if (!fbuf->fb_err)
19875af46c2Stedu fbuf->fb_io_fd = ffi.fh;
19975af46c2Stedu
20075af46c2Stedu return (0);
20175af46c2Stedu }
20275af46c2Stedu
20375af46c2Stedu #define GENERIC_DIRSIZ(NLEN) \
204f86cb379Sguenther ((sizeof (struct dirent) - (MAXNAMLEN+1)) + ((NLEN+1 + 7) &~ 7))
20575af46c2Stedu
2061f45a5acShelg /*
2071f45a5acShelg * This function adds one directory entry to the buffer.
2081f45a5acShelg * FUSE file systems can implement readdir in one of two ways.
2091f45a5acShelg *
2101f45a5acShelg * 1. Read all directory entries in one operation. The off parameter
2111f45a5acShelg * will always be 0 and this filler function always returns 0.
2121f45a5acShelg * 2. The file system keeps track of the directory entry offsets and
2131f45a5acShelg * this filler function returns 1 when the buffer is full.
2141f45a5acShelg *
2151f45a5acShelg * OpenBSD currently supports 1. but will still call the file system's
2161f45a5acShelg * readdir function multiple times if either the kernel buffer or the
2171f45a5acShelg * buffer supplied by the calling application is too small to fit all
2181f45a5acShelg * entries. Each call to the file system's readdir function will fill
2191f45a5acShelg * the buffer with the next set of entries.
2201f45a5acShelg */
22175af46c2Stedu static int
ifuse_fill_readdir(void * dh,const char * name,const struct stat * stbuf,off_t off)22275af46c2Stedu ifuse_fill_readdir(void *dh, const char *name, const struct stat *stbuf,
22375af46c2Stedu off_t off)
22475af46c2Stedu {
22516956dadShelg struct fuse *f;
22675af46c2Stedu struct fuse_dirhandle *fd = dh;
22716956dadShelg struct fuse_vnode *v;
22875af46c2Stedu struct fusebuf *fbuf;
22975af46c2Stedu struct dirent *dir;
23075af46c2Stedu uint32_t namelen;
23175af46c2Stedu uint32_t len;
23275af46c2Stedu
23316956dadShelg f = fd->fuse;
23475af46c2Stedu fbuf = fd->buf;
23575af46c2Stedu namelen = strnlen(name, MAXNAMLEN);
23675af46c2Stedu len = GENERIC_DIRSIZ(namelen);
23775af46c2Stedu
238390f10b5Shelg /* buffer is full so ignore the remaining entries */
239d3655159Ssyl if (fd->full || (fbuf->fb_len + len > fd->size)) {
24075af46c2Stedu fd->full = 1;
24175af46c2Stedu return (0);
24275af46c2Stedu }
24375af46c2Stedu
244390f10b5Shelg /* already returned these entries in a previous call so skip */
245d3655159Ssyl if (fd->start != 0 && fd->idx < fd->start) {
24675af46c2Stedu fd->idx += len;
24775af46c2Stedu return (0);
24875af46c2Stedu }
24975af46c2Stedu
2508dbfc628Ssyl dir = (struct dirent *) &fbuf->fb_dat[fbuf->fb_len];
25175af46c2Stedu
252dae5ffecShelg if (stbuf != NULL && f->conf.use_ino)
253dae5ffecShelg dir->d_fileno = stbuf->st_ino;
254dae5ffecShelg else {
255390f10b5Shelg /*
256dae5ffecShelg * This always behaves as if readdir_ino option is set so
257dae5ffecShelg * getcwd(3) works.
258390f10b5Shelg */
25916956dadShelg v = get_vn_by_name_and_parent(f, (uint8_t *)name, fbuf->fb_ino);
26016956dadShelg if (v == NULL) {
26116956dadShelg if (strcmp(name, ".") == 0)
26216956dadShelg dir->d_fileno = fbuf->fb_ino;
26316956dadShelg else
26475af46c2Stedu dir->d_fileno = 0xffffffff;
26516956dadShelg } else
26616956dadShelg dir->d_fileno = v->ino;
267dae5ffecShelg }
26816956dadShelg
269dae5ffecShelg if (stbuf != NULL)
27016956dadShelg dir->d_type = IFTODT(stbuf->st_mode);
27116956dadShelg else
272f86cb379Sguenther dir->d_type = DT_UNKNOWN;
27316956dadShelg
27475af46c2Stedu dir->d_reclen = len;
275f86cb379Sguenther dir->d_off = off + len; /* XXX */
2769eab7d68Sbeck strlcpy(dir->d_name, name, sizeof(dir->d_name));
2779eab7d68Sbeck dir->d_namlen = strlen(dir->d_name);
27875af46c2Stedu
27975af46c2Stedu fbuf->fb_len += len;
28075af46c2Stedu fd->idx += len;
281d3655159Ssyl
28275af46c2Stedu return (0);
28375af46c2Stedu }
28475af46c2Stedu
28575af46c2Stedu static int
ifuse_fill_getdir(fuse_dirh_t fd,const char * name,int type,ino_t ino)28675af46c2Stedu ifuse_fill_getdir(fuse_dirh_t fd, const char *name, int type, ino_t ino)
28775af46c2Stedu {
28875af46c2Stedu struct stat st;
28975af46c2Stedu
290bb72b40bShelg memset(&st, 0, sizeof(st));
29175af46c2Stedu st.st_mode = type << 12;
29275af46c2Stedu if (ino == 0)
29375af46c2Stedu st.st_ino = 0xffffffff;
29475af46c2Stedu else
29575af46c2Stedu st.st_ino = ino;
29675af46c2Stedu
29775af46c2Stedu return (fd->filler(fd, name, &st, 0));
29875af46c2Stedu }
29975af46c2Stedu
30075af46c2Stedu static int
ifuse_ops_readdir(struct fuse * f,struct fusebuf * fbuf)30175af46c2Stedu ifuse_ops_readdir(struct fuse *f, struct fusebuf *fbuf)
30275af46c2Stedu {
30375af46c2Stedu struct fuse_file_info ffi;
304390f10b5Shelg struct fuse_dirhandle fd;
30575af46c2Stedu struct fuse_vnode *vn;
30675af46c2Stedu char *realname;
30775af46c2Stedu uint64_t offset;
30875af46c2Stedu uint32_t size;
30975af46c2Stedu
3101f45a5acShelg DPRINTF("Opcode: readdir\t");
3111f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
3121f45a5acShelg DPRINTF("Offset: %llu\t", fbuf->fb_io_off);
3131f45a5acShelg DPRINTF("Size: %lu\t", fbuf->fb_io_len);
31475af46c2Stedu
315bb72b40bShelg memset(&ffi, 0, sizeof(ffi));
31675af46c2Stedu ffi.fh = fbuf->fb_io_fd;
31775af46c2Stedu offset = fbuf->fb_io_off;
31875af46c2Stedu size = fbuf->fb_io_len;
31975af46c2Stedu
3209eab7d68Sbeck fbuf->fb_dat = calloc(1, size);
3219eab7d68Sbeck
322e2d58cb2Ssyl if (fbuf->fb_dat == NULL) {
32377cffba6Ssyl fbuf->fb_err = -errno;
324e2d58cb2Ssyl return (0);
325e2d58cb2Ssyl }
32677cffba6Ssyl
32775af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
32877cffba6Ssyl if (vn == NULL) {
32977cffba6Ssyl fbuf->fb_err = -errno;
33077cffba6Ssyl free(fbuf->fb_dat);
33177cffba6Ssyl return (0);
33277cffba6Ssyl }
33375af46c2Stedu
334390f10b5Shelg memset(&fd, 0, sizeof(fd));
335390f10b5Shelg fd.filler = ifuse_fill_readdir;
336390f10b5Shelg fd.buf = fbuf;
337390f10b5Shelg fd.full = 0;
338390f10b5Shelg fd.size = size;
339390f10b5Shelg fd.off = offset;
340390f10b5Shelg fd.idx = 0;
341390f10b5Shelg fd.fuse = f;
342390f10b5Shelg fd.start = offset;
34375af46c2Stedu
34475af46c2Stedu realname = build_realname(f, vn->ino);
34577cffba6Ssyl if (realname == NULL) {
34677cffba6Ssyl fbuf->fb_err = -errno;
34777cffba6Ssyl free(fbuf->fb_dat);
34877cffba6Ssyl return (0);
34977cffba6Ssyl }
35077cffba6Ssyl
35175af46c2Stedu if (f->op.readdir)
352390f10b5Shelg fbuf->fb_err = f->op.readdir(realname, &fd, ifuse_fill_readdir,
353390f10b5Shelg offset, &ffi);
354d3655159Ssyl else if (f->op.getdir)
355390f10b5Shelg fbuf->fb_err = f->op.getdir(realname, &fd, ifuse_fill_getdir);
356d3655159Ssyl else
35775af46c2Stedu fbuf->fb_err = -ENOSYS;
35875af46c2Stedu free(realname);
35975af46c2Stedu
360390f10b5Shelg if (fbuf->fb_err)
36175af46c2Stedu fbuf->fb_len = 0;
362390f10b5Shelg else if (fd.full && fbuf->fb_len == 0)
36316956dadShelg fbuf->fb_err = -ENOBUFS;
36475af46c2Stedu
36577999297Ssyl if (fbuf->fb_len == 0)
36677999297Ssyl free(fbuf->fb_dat);
36777999297Ssyl
36875af46c2Stedu return (0);
36975af46c2Stedu }
37075af46c2Stedu
37175af46c2Stedu static int
ifuse_ops_releasedir(struct fuse * f,struct fusebuf * fbuf)37275af46c2Stedu ifuse_ops_releasedir(struct fuse *f, struct fusebuf *fbuf)
37375af46c2Stedu {
37475af46c2Stedu struct fuse_file_info ffi;
37575af46c2Stedu struct fuse_vnode *vn;
37675af46c2Stedu char *realname;
37775af46c2Stedu
3781f45a5acShelg DPRINTF("Opcode: releasedir\t");
3791f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
38075af46c2Stedu
381bb72b40bShelg memset(&ffi, 0, sizeof(ffi));
38275af46c2Stedu ffi.fh = fbuf->fb_io_fd;
38375af46c2Stedu ffi.fh_old = ffi.fh;
38475af46c2Stedu ffi.flags = fbuf->fb_io_flags;
38575af46c2Stedu
38675af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
38777cffba6Ssyl if (vn == NULL) {
38877cffba6Ssyl fbuf->fb_err = -errno;
38977cffba6Ssyl return (0);
39077cffba6Ssyl }
39175af46c2Stedu
39275af46c2Stedu if (f->op.releasedir) {
39375af46c2Stedu realname = build_realname(f, vn->ino);
39477cffba6Ssyl if (realname == NULL) {
39577cffba6Ssyl fbuf->fb_err = -errno;
39677cffba6Ssyl return (0);
39777cffba6Ssyl }
39877cffba6Ssyl
39975af46c2Stedu fbuf->fb_err = f->op.releasedir(realname, &ffi);
40075af46c2Stedu free(realname);
4016b2d4fe9Ssyl }
40275af46c2Stedu
40375af46c2Stedu return (0);
40475af46c2Stedu }
40575af46c2Stedu
40675af46c2Stedu static int
ifuse_ops_release(struct fuse * f,struct fusebuf * fbuf)40775af46c2Stedu ifuse_ops_release(struct fuse *f, struct fusebuf *fbuf)
40875af46c2Stedu {
40975af46c2Stedu struct fuse_file_info ffi;
41075af46c2Stedu struct fuse_vnode *vn;
41175af46c2Stedu char *realname;
41275af46c2Stedu
41375af46c2Stedu CHECK_OPT(release);
41475af46c2Stedu
415bb72b40bShelg memset(&ffi, 0, sizeof(ffi));
41675af46c2Stedu ffi.fh = fbuf->fb_io_fd;
41775af46c2Stedu ffi.fh_old = ffi.fh;
41875af46c2Stedu ffi.flags = fbuf->fb_io_flags;
41975af46c2Stedu
42075af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
42177cffba6Ssyl if (vn == NULL) {
42277cffba6Ssyl fbuf->fb_err = -errno;
42377cffba6Ssyl return (0);
42477cffba6Ssyl }
42575af46c2Stedu
42675af46c2Stedu realname = build_realname(f, vn->ino);
42777cffba6Ssyl if (realname == NULL) {
42877cffba6Ssyl fbuf->fb_err = -errno;
42977cffba6Ssyl return (0);
43077cffba6Ssyl }
43175af46c2Stedu fbuf->fb_err = f->op.release(realname, &ffi);
43275af46c2Stedu free(realname);
43375af46c2Stedu
43475af46c2Stedu return (0);
43575af46c2Stedu }
43675af46c2Stedu
43775af46c2Stedu static int
ifuse_ops_fsync(struct fuse * f,struct fusebuf * fbuf)438*0d644658Shelg ifuse_ops_fsync(struct fuse *f, struct fusebuf *fbuf)
439*0d644658Shelg {
440*0d644658Shelg struct fuse_file_info ffi;
441*0d644658Shelg struct fuse_vnode *vn;
442*0d644658Shelg char *realname;
443*0d644658Shelg int datasync;
444*0d644658Shelg
445*0d644658Shelg CHECK_OPT(fsync);
446*0d644658Shelg
447*0d644658Shelg memset(&ffi, 0, sizeof(ffi));
448*0d644658Shelg ffi.fh = fbuf->fb_io_fd;
449*0d644658Shelg
450*0d644658Shelg /*
451*0d644658Shelg * fdatasync(2) is just a wrapper around fsync(2) so datasync
452*0d644658Shelg * is always false.
453*0d644658Shelg */
454*0d644658Shelg datasync = 0;
455*0d644658Shelg
456*0d644658Shelg vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
457*0d644658Shelg if (vn == NULL) {
458*0d644658Shelg fbuf->fb_err = -errno;
459*0d644658Shelg return (0);
460*0d644658Shelg }
461*0d644658Shelg
462*0d644658Shelg realname = build_realname(f, vn->ino);
463*0d644658Shelg if (realname == NULL) {
464*0d644658Shelg fbuf->fb_err = -errno;
465*0d644658Shelg return (0);
466*0d644658Shelg }
467*0d644658Shelg fbuf->fb_err = f->op.fsync(realname, datasync, &ffi);
468*0d644658Shelg free(realname);
469*0d644658Shelg
470*0d644658Shelg return (0);
471*0d644658Shelg }
472*0d644658Shelg
473*0d644658Shelg static int
ifuse_ops_flush(struct fuse * f,struct fusebuf * fbuf)474e1487996Shelg ifuse_ops_flush(struct fuse *f, struct fusebuf *fbuf)
475e1487996Shelg {
476e1487996Shelg struct fuse_file_info ffi;
477e1487996Shelg struct fuse_vnode *vn;
478e1487996Shelg char *realname;
479e1487996Shelg
480e1487996Shelg CHECK_OPT(flush);
481e1487996Shelg
482e1487996Shelg memset(&ffi, 0, sizeof(ffi));
483e1487996Shelg ffi.fh = fbuf->fb_io_fd;
484e1487996Shelg ffi.fh_old = ffi.fh;
485e1487996Shelg ffi.flush = 1;
486e1487996Shelg
487e1487996Shelg vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
488e1487996Shelg if (vn == NULL) {
489e1487996Shelg fbuf->fb_err = -errno;
490e1487996Shelg return (0);
491e1487996Shelg }
492e1487996Shelg
493e1487996Shelg realname = build_realname(f, vn->ino);
494e1487996Shelg if (realname == NULL) {
495e1487996Shelg fbuf->fb_err = -errno;
496e1487996Shelg return (0);
497e1487996Shelg }
498e1487996Shelg fbuf->fb_err = f->op.flush(realname, &ffi);
499e1487996Shelg free(realname);
500e1487996Shelg
501e1487996Shelg return (0);
502e1487996Shelg }
503e1487996Shelg
504e1487996Shelg static int
ifuse_ops_lookup(struct fuse * f,struct fusebuf * fbuf)50575af46c2Stedu ifuse_ops_lookup(struct fuse *f, struct fusebuf *fbuf)
50675af46c2Stedu {
50775af46c2Stedu struct fuse_vnode *vn;
50875af46c2Stedu char *realname;
50975af46c2Stedu
5101f45a5acShelg DPRINTF("Opcode: lookup\t");
5111f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
51275af46c2Stedu
5135e69e0b6Snatano if (strcmp((const char *)fbuf->fb_dat, "..") == 0) {
5145e69e0b6Snatano vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
5155e69e0b6Snatano if (vn == NULL || vn->parent == NULL) {
5165e69e0b6Snatano fbuf->fb_err = -ENOENT;
5175e69e0b6Snatano return (0);
5185e69e0b6Snatano }
5195e69e0b6Snatano vn = vn->parent;
5205e69e0b6Snatano if (vn->ino != FUSE_ROOT_INO)
5215e69e0b6Snatano ref_vn(vn);
5225e69e0b6Snatano } else {
52375af46c2Stedu vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
52475af46c2Stedu if (vn == NULL) {
5255e69e0b6Snatano vn = alloc_vn(f, (const char *)fbuf->fb_dat, -1,
5265e69e0b6Snatano fbuf->fb_ino);
52775af46c2Stedu if (vn == NULL) {
52877cffba6Ssyl fbuf->fb_err = -errno;
5298dbfc628Ssyl free(fbuf->fb_dat);
53075af46c2Stedu return (0);
53175af46c2Stedu }
53275af46c2Stedu set_vn(f, vn); /*XXX*/
5335e69e0b6Snatano } else if (vn->ino != FUSE_ROOT_INO)
5345e69e0b6Snatano ref_vn(vn);
53575af46c2Stedu }
53675af46c2Stedu
53775af46c2Stedu realname = build_realname(f, vn->ino);
53877cffba6Ssyl if (realname == NULL) {
53977cffba6Ssyl fbuf->fb_err = -errno;
54077cffba6Ssyl free(fbuf->fb_dat);
54177cffba6Ssyl return (0);
54277cffba6Ssyl }
54377cffba6Ssyl
5446f9b5942Snatano fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
545dae5ffecShelg fbuf->fb_ino = vn->ino;
5468dbfc628Ssyl free(fbuf->fb_dat);
54775af46c2Stedu free(realname);
54875af46c2Stedu
54975af46c2Stedu return (0);
55075af46c2Stedu }
55175af46c2Stedu
55275af46c2Stedu static int
ifuse_ops_read(struct fuse * f,struct fusebuf * fbuf)55375af46c2Stedu ifuse_ops_read(struct fuse *f, struct fusebuf *fbuf)
55475af46c2Stedu {
55575af46c2Stedu struct fuse_file_info ffi;
55675af46c2Stedu struct fuse_vnode *vn;
55775af46c2Stedu char *realname;
55875af46c2Stedu uint64_t offset;
55975af46c2Stedu uint32_t size;
56075af46c2Stedu int ret;
56175af46c2Stedu
56275af46c2Stedu CHECK_OPT(read);
56375af46c2Stedu
564bb72b40bShelg memset(&ffi, 0, sizeof(ffi));
56575af46c2Stedu ffi.fh = fbuf->fb_io_fd;
56675af46c2Stedu size = fbuf->fb_io_len;
56775af46c2Stedu offset = fbuf->fb_io_off;
56875af46c2Stedu
5698dbfc628Ssyl fbuf->fb_dat = malloc(size);
570e2d58cb2Ssyl if (fbuf->fb_dat == NULL) {
57177cffba6Ssyl fbuf->fb_err = -errno;
572e2d58cb2Ssyl return (0);
573e2d58cb2Ssyl }
57475af46c2Stedu
57575af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
57677cffba6Ssyl if (vn == NULL) {
57777cffba6Ssyl fbuf->fb_err = -errno;
57877cffba6Ssyl free(fbuf->fb_dat);
57977cffba6Ssyl return (0);
58077cffba6Ssyl }
58175af46c2Stedu
58275af46c2Stedu realname = build_realname(f, vn->ino);
58377cffba6Ssyl if (realname == NULL) {
58477cffba6Ssyl fbuf->fb_err = -errno;
58577cffba6Ssyl free(fbuf->fb_dat);
58677cffba6Ssyl return (0);
58777cffba6Ssyl }
58877cffba6Ssyl
589dedc9797Ssyl ret = f->op.read(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
59075af46c2Stedu free(realname);
5916b2d4fe9Ssyl if (ret >= 0)
5928dbfc628Ssyl fbuf->fb_len = ret;
5936b2d4fe9Ssyl else
59475af46c2Stedu fbuf->fb_err = ret;
59575af46c2Stedu
59677999297Ssyl if (fbuf->fb_len == 0)
59777999297Ssyl free(fbuf->fb_dat);
59877999297Ssyl
59975af46c2Stedu return (0);
60075af46c2Stedu }
60175af46c2Stedu
60275af46c2Stedu static int
ifuse_ops_write(struct fuse * f,struct fusebuf * fbuf)60375af46c2Stedu ifuse_ops_write(struct fuse *f, struct fusebuf *fbuf)
60475af46c2Stedu {
60575af46c2Stedu struct fuse_file_info ffi;
60675af46c2Stedu struct fuse_vnode *vn;
60775af46c2Stedu char *realname;
60875af46c2Stedu uint64_t offset;
60975af46c2Stedu uint32_t size;
61075af46c2Stedu int ret;
61175af46c2Stedu
61275af46c2Stedu CHECK_OPT(write);
61375af46c2Stedu
614bb72b40bShelg memset(&ffi, 0, sizeof(ffi));
61575af46c2Stedu ffi.fh = fbuf->fb_io_fd;
61675af46c2Stedu ffi.fh_old = ffi.fh;
61775af46c2Stedu ffi.writepage = fbuf->fb_io_flags & 1;
61875af46c2Stedu size = fbuf->fb_io_len;
61975af46c2Stedu offset = fbuf->fb_io_off;
62075af46c2Stedu
62175af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
62277cffba6Ssyl if (vn == NULL) {
62377cffba6Ssyl fbuf->fb_err = -errno;
62477cffba6Ssyl free(fbuf->fb_dat);
62577cffba6Ssyl return (0);
62677cffba6Ssyl }
62775af46c2Stedu
62875af46c2Stedu realname = build_realname(f, vn->ino);
62977cffba6Ssyl if (realname == NULL) {
63077cffba6Ssyl fbuf->fb_err = -errno;
63177cffba6Ssyl free(fbuf->fb_dat);
63277cffba6Ssyl return (0);
63377cffba6Ssyl }
63477cffba6Ssyl
635dedc9797Ssyl ret = f->op.write(realname, (char *)fbuf->fb_dat, size, offset, &ffi);
63675af46c2Stedu free(realname);
6378dbfc628Ssyl free(fbuf->fb_dat);
63875af46c2Stedu
6396b2d4fe9Ssyl if (ret >= 0)
64075af46c2Stedu fbuf->fb_io_len = ret;
6416b2d4fe9Ssyl else
64275af46c2Stedu fbuf->fb_err = ret;
64375af46c2Stedu
64475af46c2Stedu return (0);
64575af46c2Stedu }
64675af46c2Stedu
64775af46c2Stedu static int
ifuse_ops_mkdir(struct fuse * f,struct fusebuf * fbuf)64875af46c2Stedu ifuse_ops_mkdir(struct fuse *f, struct fusebuf *fbuf)
64975af46c2Stedu {
65075af46c2Stedu struct fuse_vnode *vn;
65175af46c2Stedu char *realname;
65275af46c2Stedu uint32_t mode;
65375af46c2Stedu
65475af46c2Stedu CHECK_OPT(mkdir);
65575af46c2Stedu
65675af46c2Stedu mode = fbuf->fb_io_mode;
65775af46c2Stedu vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
65877cffba6Ssyl if (vn == NULL) {
65977cffba6Ssyl fbuf->fb_err = -errno;
66077cffba6Ssyl free(fbuf->fb_dat);
66177cffba6Ssyl return (0);
66277cffba6Ssyl }
66375af46c2Stedu
6648dbfc628Ssyl free(fbuf->fb_dat);
66575af46c2Stedu realname = build_realname(f, vn->ino);
66677cffba6Ssyl if (realname == NULL) {
66777cffba6Ssyl fbuf->fb_err = -errno;
66877cffba6Ssyl return (0);
66977cffba6Ssyl }
67077cffba6Ssyl
67175af46c2Stedu fbuf->fb_err = f->op.mkdir(realname, mode);
67275af46c2Stedu
67375af46c2Stedu if (!fbuf->fb_err) {
6746f9b5942Snatano fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
6756f9b5942Snatano fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
67675af46c2Stedu fbuf->fb_ino = vn->ino;
67775af46c2Stedu }
67875af46c2Stedu free(realname);
67975af46c2Stedu
68075af46c2Stedu return (0);
68175af46c2Stedu }
68275af46c2Stedu
68375af46c2Stedu static int
ifuse_ops_rmdir(struct fuse * f,struct fusebuf * fbuf)68475af46c2Stedu ifuse_ops_rmdir(struct fuse *f, struct fusebuf *fbuf)
68575af46c2Stedu {
68675af46c2Stedu struct fuse_vnode *vn;
68775af46c2Stedu char *realname;
68875af46c2Stedu
68975af46c2Stedu CHECK_OPT(rmdir);
69075af46c2Stedu vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
69177cffba6Ssyl if (vn == NULL) {
69277cffba6Ssyl fbuf->fb_err = -errno;
69377cffba6Ssyl free(fbuf->fb_dat);
69477cffba6Ssyl return (0);
69577cffba6Ssyl }
69675af46c2Stedu
6978dbfc628Ssyl free(fbuf->fb_dat);
69875af46c2Stedu realname = build_realname(f, vn->ino);
69977cffba6Ssyl if (realname == NULL) {
70077cffba6Ssyl fbuf->fb_err = -errno;
70177cffba6Ssyl return (0);
70277cffba6Ssyl }
70377cffba6Ssyl
70475af46c2Stedu fbuf->fb_err = f->op.rmdir(realname);
70575af46c2Stedu free(realname);
70675af46c2Stedu
70775af46c2Stedu return (0);
70875af46c2Stedu }
70975af46c2Stedu
71075af46c2Stedu static int
ifuse_ops_readlink(struct fuse * f,struct fusebuf * fbuf)71175af46c2Stedu ifuse_ops_readlink(struct fuse *f, struct fusebuf *fbuf)
71275af46c2Stedu {
71375af46c2Stedu struct fuse_vnode *vn;
71475af46c2Stedu char *realname;
71575af46c2Stedu char name[PATH_MAX + 1];
71675af46c2Stedu int len, ret;
71775af46c2Stedu
7181f45a5acShelg DPRINTF("Opcode: readlink\t");
7191f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
72075af46c2Stedu
72175af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
72277cffba6Ssyl if (vn == NULL) {
72377cffba6Ssyl fbuf->fb_err = -errno;
72477cffba6Ssyl return (0);
72577cffba6Ssyl }
72675af46c2Stedu
72775af46c2Stedu realname = build_realname(f, vn->ino);
72877cffba6Ssyl if (realname == NULL) {
72977cffba6Ssyl fbuf->fb_err = -errno;
73077cffba6Ssyl return (0);
73177cffba6Ssyl }
73277cffba6Ssyl
73375af46c2Stedu if (f->op.readlink)
73475af46c2Stedu ret = f->op.readlink(realname, name, sizeof(name));
73575af46c2Stedu else
73675af46c2Stedu ret = -ENOSYS;
73775af46c2Stedu free(realname);
73875af46c2Stedu
73975af46c2Stedu fbuf->fb_err = ret;
74075af46c2Stedu if (!ret) {
74177999297Ssyl len = strnlen(name, PATH_MAX);
742e2d58cb2Ssyl fbuf->fb_len = len;
7438dbfc628Ssyl fbuf->fb_dat = malloc(fbuf->fb_len);
744e2d58cb2Ssyl if (fbuf->fb_dat == NULL) {
74577cffba6Ssyl fbuf->fb_err = -errno;
746e2d58cb2Ssyl return (0);
747e2d58cb2Ssyl }
74875af46c2Stedu memcpy(fbuf->fb_dat, name, len);
74975af46c2Stedu } else
75075af46c2Stedu fbuf->fb_len = 0;
75175af46c2Stedu
75275af46c2Stedu return (0);
75375af46c2Stedu }
75475af46c2Stedu
75575af46c2Stedu static int
ifuse_ops_unlink(struct fuse * f,struct fusebuf * fbuf)75675af46c2Stedu ifuse_ops_unlink(struct fuse *f, struct fusebuf *fbuf)
75775af46c2Stedu {
75875af46c2Stedu struct fuse_vnode *vn;
75975af46c2Stedu char *realname;
76075af46c2Stedu
76175af46c2Stedu CHECK_OPT(unlink);
76275af46c2Stedu
76375af46c2Stedu vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
76477cffba6Ssyl if (vn == NULL) {
7658dbfc628Ssyl free(fbuf->fb_dat);
76677cffba6Ssyl fbuf->fb_err = -errno;
76777cffba6Ssyl return (0);
76877cffba6Ssyl }
76975af46c2Stedu
77077cffba6Ssyl free(fbuf->fb_dat);
77175af46c2Stedu realname = build_realname(f, vn->ino);
77277cffba6Ssyl if (realname == NULL) {
77377cffba6Ssyl fbuf->fb_err = -errno;
77477cffba6Ssyl return (0);
77577cffba6Ssyl }
77677cffba6Ssyl
77775af46c2Stedu fbuf->fb_err = f->op.unlink(realname);
77875af46c2Stedu free(realname);
77975af46c2Stedu
78075af46c2Stedu return (0);
78175af46c2Stedu }
78275af46c2Stedu
78375af46c2Stedu static int
ifuse_ops_statfs(struct fuse * f,struct fusebuf * fbuf)78475af46c2Stedu ifuse_ops_statfs(struct fuse *f, struct fusebuf *fbuf)
78575af46c2Stedu {
78675af46c2Stedu struct fuse_vnode *vn;
78775af46c2Stedu char *realname;
78875af46c2Stedu
789bb72b40bShelg memset(&fbuf->fb_stat, 0, sizeof(fbuf->fb_stat));
79075af46c2Stedu
79175af46c2Stedu CHECK_OPT(statfs);
79275af46c2Stedu
79375af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
79477cffba6Ssyl if (vn == NULL) {
79577cffba6Ssyl fbuf->fb_err = -errno;
79677cffba6Ssyl return (0);
79777cffba6Ssyl }
79875af46c2Stedu
79975af46c2Stedu realname = build_realname(f, vn->ino);
80077cffba6Ssyl if (realname == NULL) {
80177cffba6Ssyl fbuf->fb_err = -errno;
80277cffba6Ssyl return (0);
80377cffba6Ssyl }
80477cffba6Ssyl
80575af46c2Stedu fbuf->fb_err = f->op.statfs(realname, &fbuf->fb_stat);
80675af46c2Stedu free(realname);
80775af46c2Stedu
80875af46c2Stedu return (0);
80975af46c2Stedu }
81075af46c2Stedu
81175af46c2Stedu static int
ifuse_ops_link(struct fuse * f,struct fusebuf * fbuf)81275af46c2Stedu ifuse_ops_link(struct fuse *f, struct fusebuf *fbuf)
81375af46c2Stedu {
81475af46c2Stedu struct fuse_vnode *vn;
81575af46c2Stedu char *realname;
81675af46c2Stedu char *realname_ln;
81775af46c2Stedu ino_t oldnodeid;
81875af46c2Stedu
81975af46c2Stedu CHECK_OPT(link);
82075af46c2Stedu oldnodeid = fbuf->fb_io_ino;
82175af46c2Stedu vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
82277cffba6Ssyl if (vn == NULL) {
82377cffba6Ssyl fbuf->fb_err = -errno;
82477cffba6Ssyl free(fbuf->fb_dat);
82577cffba6Ssyl return (0);
82677cffba6Ssyl }
82775af46c2Stedu
8288dbfc628Ssyl free(fbuf->fb_dat);
82975af46c2Stedu realname = build_realname(f, oldnodeid);
83077cffba6Ssyl if (realname == NULL) {
83177cffba6Ssyl fbuf->fb_err = -errno;
83277cffba6Ssyl return (0);
83377cffba6Ssyl }
83477cffba6Ssyl
83575af46c2Stedu realname_ln = build_realname(f, vn->ino);
83677cffba6Ssyl if (realname_ln == NULL) {
83777cffba6Ssyl fbuf->fb_err = -errno;
83877cffba6Ssyl free(realname);
83977cffba6Ssyl return (0);
84077cffba6Ssyl }
84177cffba6Ssyl
84275af46c2Stedu fbuf->fb_err = f->op.link(realname, realname_ln);
84375af46c2Stedu free(realname);
84475af46c2Stedu free(realname_ln);
84575af46c2Stedu
84675af46c2Stedu return (0);
84775af46c2Stedu }
84875af46c2Stedu
84975af46c2Stedu static int
ifuse_ops_setattr(struct fuse * f,struct fusebuf * fbuf)85075af46c2Stedu ifuse_ops_setattr(struct fuse *f, struct fusebuf *fbuf)
85175af46c2Stedu {
85275af46c2Stedu struct fuse_vnode *vn;
85375af46c2Stedu struct timespec ts[2];
85475af46c2Stedu struct utimbuf tbuf;
85575af46c2Stedu struct fb_io *io;
85675af46c2Stedu char *realname;
85775af46c2Stedu uid_t uid;
85875af46c2Stedu gid_t gid;
85975af46c2Stedu
8601f45a5acShelg DPRINTF("Opcode: setattr\t");
8611f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
86275af46c2Stedu
86375af46c2Stedu vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
86477cffba6Ssyl if (vn == NULL) {
86577cffba6Ssyl fbuf->fb_err = -errno;
86677cffba6Ssyl free(fbuf->fb_dat);
86777cffba6Ssyl return (0);
86877cffba6Ssyl }
86977cffba6Ssyl
87075af46c2Stedu realname = build_realname(f, vn->ino);
87177cffba6Ssyl if (realname == NULL) {
87277cffba6Ssyl fbuf->fb_err = -errno;
87377cffba6Ssyl free(fbuf->fb_dat);
87477cffba6Ssyl return (0);
87577cffba6Ssyl }
87675af46c2Stedu io = fbtod(fbuf, struct fb_io *);
87775af46c2Stedu
87875af46c2Stedu if (io->fi_flags & FUSE_FATTR_MODE) {
87975af46c2Stedu if (f->op.chmod)
88075af46c2Stedu fbuf->fb_err = f->op.chmod(realname,
8816f9b5942Snatano fbuf->fb_attr.st_mode);
88275af46c2Stedu else
88375af46c2Stedu fbuf->fb_err = -ENOSYS;
88475af46c2Stedu }
88575af46c2Stedu
88675af46c2Stedu if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_UID ||
88775af46c2Stedu io->fi_flags & FUSE_FATTR_GID) ) {
88875af46c2Stedu uid = (io->fi_flags & FUSE_FATTR_UID) ?
8892670c02eShelg fbuf->fb_attr.st_uid : (uid_t)-1;
89075af46c2Stedu gid = (io->fi_flags & FUSE_FATTR_GID) ?
8912670c02eShelg fbuf->fb_attr.st_gid : (gid_t)-1;
89275af46c2Stedu if (f->op.chown)
89375af46c2Stedu fbuf->fb_err = f->op.chown(realname, uid, gid);
89475af46c2Stedu else
89575af46c2Stedu fbuf->fb_err = -ENOSYS;
89675af46c2Stedu }
89775af46c2Stedu
89875af46c2Stedu if (!fbuf->fb_err && ( io->fi_flags & FUSE_FATTR_MTIME ||
89975af46c2Stedu io->fi_flags & FUSE_FATTR_ATIME)) {
9002670c02eShelg
9012670c02eShelg if (f->op.utimens) {
9026f9b5942Snatano ts[0] = fbuf->fb_attr.st_atim;
9036f9b5942Snatano ts[1] = fbuf->fb_attr.st_mtim;
90475af46c2Stedu fbuf->fb_err = f->op.utimens(realname, ts);
9052670c02eShelg } else if (f->op.utime) {
9062670c02eShelg tbuf.actime = fbuf->fb_attr.st_atim.tv_sec;
9072670c02eShelg tbuf.modtime = fbuf->fb_attr.st_mtim.tv_sec;
90875af46c2Stedu fbuf->fb_err = f->op.utime(realname, &tbuf);
9092670c02eShelg } else
91075af46c2Stedu fbuf->fb_err = -ENOSYS;
91175af46c2Stedu }
91275af46c2Stedu
913aab5b16cSsyl if (!fbuf->fb_err && (io->fi_flags & FUSE_FATTR_SIZE)) {
914aab5b16cSsyl if (f->op.truncate)
915aab5b16cSsyl fbuf->fb_err = f->op.truncate(realname,
9166f9b5942Snatano fbuf->fb_attr.st_size);
917aab5b16cSsyl else
918aab5b16cSsyl fbuf->fb_err = -ENOSYS;
919aab5b16cSsyl }
920aab5b16cSsyl
9216f9b5942Snatano memset(&fbuf->fb_attr, 0, sizeof(struct stat));
92275af46c2Stedu
92375af46c2Stedu if (!fbuf->fb_err)
9246f9b5942Snatano fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
92575af46c2Stedu free(realname);
9268dbfc628Ssyl free(fbuf->fb_dat);
92775af46c2Stedu
92875af46c2Stedu return (0);
92975af46c2Stedu }
93075af46c2Stedu
93175af46c2Stedu static int
ifuse_ops_symlink(unused struct fuse * f,struct fusebuf * fbuf)93275af46c2Stedu ifuse_ops_symlink(unused struct fuse *f, struct fusebuf *fbuf)
93375af46c2Stedu {
93475af46c2Stedu struct fuse_vnode *vn;
93575af46c2Stedu char *realname;
93675af46c2Stedu int len;
93775af46c2Stedu
93875af46c2Stedu CHECK_OPT(symlink);
93975af46c2Stedu
94075af46c2Stedu vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
94177cffba6Ssyl if (vn == NULL) {
94277cffba6Ssyl fbuf->fb_err = -errno;
94377cffba6Ssyl free(fbuf->fb_dat);
94477cffba6Ssyl return (0);
94577cffba6Ssyl }
94677cffba6Ssyl
947dedc9797Ssyl len = strlen((char *)fbuf->fb_dat);
94875af46c2Stedu
94975af46c2Stedu realname = build_realname(f, vn->ino);
95077cffba6Ssyl if (realname == NULL) {
95177cffba6Ssyl fbuf->fb_err = -errno;
95277cffba6Ssyl free(fbuf->fb_dat);
95377cffba6Ssyl return (0);
95477cffba6Ssyl }
95577cffba6Ssyl
95675af46c2Stedu /* fuse invert the symlink params */
957dedc9797Ssyl fbuf->fb_err = f->op.symlink((const char *)&fbuf->fb_dat[len + 1],
958dedc9797Ssyl realname);
95975af46c2Stedu fbuf->fb_ino = vn->ino;
9608dbfc628Ssyl free(fbuf->fb_dat);
96175af46c2Stedu free(realname);
96275af46c2Stedu
96375af46c2Stedu return (0);
96475af46c2Stedu }
96575af46c2Stedu
96675af46c2Stedu static int
ifuse_ops_rename(struct fuse * f,struct fusebuf * fbuf)967204e8faeStedu ifuse_ops_rename(struct fuse *f, struct fusebuf *fbuf)
968204e8faeStedu {
969204e8faeStedu struct fuse_vnode *vnt;
970204e8faeStedu struct fuse_vnode *vnf;
971204e8faeStedu char *realnamef;
972204e8faeStedu char *realnamet;
973204e8faeStedu int len;
974204e8faeStedu
975204e8faeStedu CHECK_OPT(rename);
976204e8faeStedu
977dedc9797Ssyl len = strlen((char *)fbuf->fb_dat);
978204e8faeStedu vnf = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
97977cffba6Ssyl if (vnf == NULL) {
98077cffba6Ssyl fbuf->fb_err = -errno;
98177cffba6Ssyl free(fbuf->fb_dat);
98277cffba6Ssyl return (0);
98377cffba6Ssyl }
98477cffba6Ssyl
985204e8faeStedu vnt = get_vn_by_name_and_parent(f, &fbuf->fb_dat[len + 1],
986204e8faeStedu fbuf->fb_io_ino);
98777cffba6Ssyl if (vnt == NULL) {
98877cffba6Ssyl fbuf->fb_err = -errno;
98977cffba6Ssyl free(fbuf->fb_dat);
99077cffba6Ssyl return (0);
99177cffba6Ssyl }
99277cffba6Ssyl
9938dbfc628Ssyl free(fbuf->fb_dat);
994204e8faeStedu
995204e8faeStedu realnamef = build_realname(f, vnf->ino);
99677cffba6Ssyl if (realnamef == NULL) {
99777cffba6Ssyl fbuf->fb_err = -errno;
99877cffba6Ssyl return (0);
99977cffba6Ssyl }
100077cffba6Ssyl
1001204e8faeStedu realnamet = build_realname(f, vnt->ino);
100277cffba6Ssyl if (realnamet == NULL) {
100377cffba6Ssyl fbuf->fb_err = -errno;
100477cffba6Ssyl free(realnamef);
100577cffba6Ssyl return (0);
100677cffba6Ssyl }
100777cffba6Ssyl
1008204e8faeStedu fbuf->fb_err = f->op.rename(realnamef, realnamet);
1009204e8faeStedu free(realnamef);
1010204e8faeStedu free(realnamet);
1011204e8faeStedu
1012204e8faeStedu return (0);
1013204e8faeStedu }
1014204e8faeStedu
1015204e8faeStedu static int
ifuse_ops_destroy(struct fuse * f)10166b2d4fe9Ssyl ifuse_ops_destroy(struct fuse *f)
101775af46c2Stedu {
101854e529adSsyl struct fuse_context *ctx;
101954e529adSsyl
10201f45a5acShelg DPRINTF("Opcode: destroy\n");
102175af46c2Stedu
102254e529adSsyl if (f->op.destroy) {
102354e529adSsyl ctx = fuse_get_context();
102454e529adSsyl
102554e529adSsyl f->op.destroy((ctx)?ctx->private_data:NULL);
102654e529adSsyl }
102754e529adSsyl
102875af46c2Stedu f->fc->dead = 1;
102975af46c2Stedu
103075af46c2Stedu return (0);
103175af46c2Stedu }
103275af46c2Stedu
10330e0c4c5cSsyl static int
ifuse_ops_reclaim(struct fuse * f,struct fusebuf * fbuf)10340e0c4c5cSsyl ifuse_ops_reclaim(struct fuse *f, struct fusebuf *fbuf)
10350e0c4c5cSsyl {
10360e0c4c5cSsyl struct fuse_vnode *vn;
10370e0c4c5cSsyl
10381f45a5acShelg DPRINTF("Opcode: reclaim\t");
10391f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
10401f45a5acShelg
10415e69e0b6Snatano vn = tree_get(&f->vnode_tree, fbuf->fb_ino);
10425e69e0b6Snatano if (vn != NULL)
10435e69e0b6Snatano unref_vn(f, vn);
10440e0c4c5cSsyl
10450e0c4c5cSsyl return (0);
10460e0c4c5cSsyl }
10470e0c4c5cSsyl
10483a6f6456Ssyl static int
ifuse_ops_mknod(struct fuse * f,struct fusebuf * fbuf)10493a6f6456Ssyl ifuse_ops_mknod(struct fuse *f, struct fusebuf *fbuf)
10503a6f6456Ssyl {
10513a6f6456Ssyl struct fuse_vnode *vn;
10523a6f6456Ssyl char *realname;
10533a6f6456Ssyl uint32_t mode;
10543a6f6456Ssyl dev_t dev;
10553a6f6456Ssyl
10563a6f6456Ssyl CHECK_OPT(mknod);
10573a6f6456Ssyl
10583a6f6456Ssyl mode = fbuf->fb_io_mode;
10593a6f6456Ssyl dev = fbuf->fb_io_rdev;
10603a6f6456Ssyl vn = get_vn_by_name_and_parent(f, fbuf->fb_dat, fbuf->fb_ino);
106177cffba6Ssyl if (vn == NULL) {
106277cffba6Ssyl fbuf->fb_err = -errno;
106377cffba6Ssyl free(fbuf->fb_dat);
106477cffba6Ssyl return (0);
106577cffba6Ssyl }
10663a6f6456Ssyl
10673a6f6456Ssyl free(fbuf->fb_dat);
10683a6f6456Ssyl realname = build_realname(f, vn->ino);
106977cffba6Ssyl if (realname == NULL) {
107077cffba6Ssyl fbuf->fb_err = -errno;
107177cffba6Ssyl return (0);
107277cffba6Ssyl }
107377cffba6Ssyl
10743a6f6456Ssyl fbuf->fb_err = f->op.mknod(realname, mode, dev);
10753a6f6456Ssyl
10763a6f6456Ssyl if (!fbuf->fb_err) {
10776f9b5942Snatano fbuf->fb_err = update_attr(f, &fbuf->fb_attr, realname, vn);
10786f9b5942Snatano fbuf->fb_io_mode = fbuf->fb_attr.st_mode;
1079dae5ffecShelg fbuf->fb_ino = vn->ino;
10803a6f6456Ssyl }
10813a6f6456Ssyl free(realname);
10823a6f6456Ssyl
10833a6f6456Ssyl return (0);
10843a6f6456Ssyl }
10853a6f6456Ssyl
108675af46c2Stedu int
ifuse_exec_opcode(struct fuse * f,struct fusebuf * fbuf)108775af46c2Stedu ifuse_exec_opcode(struct fuse *f, struct fusebuf *fbuf)
108875af46c2Stedu {
108975af46c2Stedu int ret = 0;
109075af46c2Stedu
10916b2d4fe9Ssyl fbuf->fb_len = 0;
10926b2d4fe9Ssyl fbuf->fb_err = 0;
10936b2d4fe9Ssyl
109475af46c2Stedu switch (fbuf->fb_type) {
109575af46c2Stedu case FBT_LOOKUP:
109675af46c2Stedu ret = ifuse_ops_lookup(f, fbuf);
109775af46c2Stedu break;
109875af46c2Stedu case FBT_GETATTR:
109975af46c2Stedu ret = ifuse_ops_getattr(f, fbuf);
110075af46c2Stedu break;
110175af46c2Stedu case FBT_SETATTR:
110275af46c2Stedu ret = ifuse_ops_setattr(f, fbuf);
110375af46c2Stedu break;
110475af46c2Stedu case FBT_READLINK:
110575af46c2Stedu ret = ifuse_ops_readlink(f, fbuf);
110675af46c2Stedu break;
110775af46c2Stedu case FBT_MKDIR:
110875af46c2Stedu ret = ifuse_ops_mkdir(f, fbuf);
110975af46c2Stedu break;
111075af46c2Stedu case FBT_UNLINK:
111175af46c2Stedu ret = ifuse_ops_unlink(f, fbuf);
111275af46c2Stedu break;
111375af46c2Stedu case FBT_RMDIR:
111475af46c2Stedu ret = ifuse_ops_rmdir(f, fbuf);
111575af46c2Stedu break;
111675af46c2Stedu case FBT_LINK:
111775af46c2Stedu ret = ifuse_ops_link(f, fbuf);
111875af46c2Stedu break;
111975af46c2Stedu case FBT_OPEN:
112075af46c2Stedu ret = ifuse_ops_open(f, fbuf);
112175af46c2Stedu break;
112275af46c2Stedu case FBT_READ:
112375af46c2Stedu ret = ifuse_ops_read(f, fbuf);
112475af46c2Stedu break;
112575af46c2Stedu case FBT_WRITE:
112675af46c2Stedu ret = ifuse_ops_write(f, fbuf);
112775af46c2Stedu break;
112875af46c2Stedu case FBT_STATFS:
112975af46c2Stedu ret = ifuse_ops_statfs(f, fbuf);
113075af46c2Stedu break;
113175af46c2Stedu case FBT_RELEASE:
113275af46c2Stedu ret = ifuse_ops_release(f, fbuf);
113375af46c2Stedu break;
1134*0d644658Shelg case FBT_FSYNC:
1135*0d644658Shelg ret = ifuse_ops_fsync(f, fbuf);
1136*0d644658Shelg break;
1137e1487996Shelg case FBT_FLUSH:
1138e1487996Shelg ret = ifuse_ops_flush(f, fbuf);
1139e1487996Shelg break;
114075af46c2Stedu case FBT_INIT:
114154e529adSsyl ret = ifuse_ops_init(f);
114275af46c2Stedu break;
114375af46c2Stedu case FBT_OPENDIR:
114475af46c2Stedu ret = ifuse_ops_opendir(f, fbuf);
114575af46c2Stedu break;
114675af46c2Stedu case FBT_READDIR:
114775af46c2Stedu ret = ifuse_ops_readdir(f, fbuf);
114875af46c2Stedu break;
114975af46c2Stedu case FBT_RELEASEDIR:
115075af46c2Stedu ret = ifuse_ops_releasedir(f, fbuf);
115175af46c2Stedu break;
115275af46c2Stedu case FBT_ACCESS:
115375af46c2Stedu ret = ifuse_ops_access(f, fbuf);
115475af46c2Stedu break;
115575af46c2Stedu case FBT_SYMLINK:
115675af46c2Stedu ret = ifuse_ops_symlink(f, fbuf);
115775af46c2Stedu break;
1158204e8faeStedu case FBT_RENAME:
1159204e8faeStedu ret = ifuse_ops_rename(f, fbuf);
1160204e8faeStedu break;
116175af46c2Stedu case FBT_DESTROY:
11626b2d4fe9Ssyl ret = ifuse_ops_destroy(f);
116375af46c2Stedu break;
11640e0c4c5cSsyl case FBT_RECLAIM:
11650e0c4c5cSsyl ret = ifuse_ops_reclaim(f, fbuf);
11660e0c4c5cSsyl break;
11673a6f6456Ssyl case FBT_MKNOD:
11683a6f6456Ssyl ret = ifuse_ops_mknod(f, fbuf);
11693a6f6456Ssyl break;
117075af46c2Stedu default:
11711f45a5acShelg DPRINTF("Opcode: %i not supported\t", fbuf->fb_type);
11721f45a5acShelg DPRINTF("Inode: %llu\t", (unsigned long long)fbuf->fb_ino);
117375af46c2Stedu
117475af46c2Stedu fbuf->fb_err = -ENOSYS;
117575af46c2Stedu fbuf->fb_len = 0;
117675af46c2Stedu }
11771dbe4c45Ssyl DPRINTF("\n");
117875af46c2Stedu
117975af46c2Stedu /* fuse api use negative errno */
118075af46c2Stedu fbuf->fb_err = -fbuf->fb_err;
118175af46c2Stedu return (ret);
118275af46c2Stedu }
1183