1 /* $OpenBSD: fuse_subr.c,v 1.10 2016/05/24 19:24:46 okan 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 <stdlib.h> 20 #include <string.h> 21 #include <unistd.h> 22 23 #include "fuse_private.h" 24 #include "debug.h" 25 26 struct fuse_vnode * 27 alloc_vn(struct fuse *f, const char *path, ino_t ino, ino_t parent) 28 { 29 struct fuse_vnode *vn; 30 31 if ((vn = malloc(sizeof(*vn))) == NULL) { 32 DPERROR(__func__); 33 return (NULL); 34 } 35 36 vn->ino = ino; 37 vn->parent = parent; 38 if (strlcpy(vn->path, path, sizeof(vn->path)) >= sizeof(vn->path)) { 39 DPRINTF("%s: strlcpy name too long\n", __func__); 40 free(vn); 41 return (NULL); 42 } 43 44 if (ino == (ino_t)-1) { 45 f->max_ino++; 46 vn->ino = f->max_ino; 47 } 48 49 return (vn); 50 } 51 52 int 53 set_vn(struct fuse *f, struct fuse_vnode *v) 54 { 55 struct fuse_vn_head *vn_head; 56 struct fuse_vnode *vn; 57 58 DPRINTF("%s: create or update vnode %llu@%llu = %s\n", __func__, 59 (unsigned long long)v->ino, (unsigned long long)v->parent, 60 v->path); 61 62 if (tree_set(&f->vnode_tree, v->ino, v) == NULL) 63 return (0); 64 65 if (!dict_check(&f->name_tree, v->path)) { 66 vn_head = malloc(sizeof(*vn_head)); 67 if (vn_head == NULL) 68 return (0); 69 SIMPLEQ_INIT(vn_head); 70 } else { 71 vn_head = dict_get(&f->name_tree, v->path); 72 if (vn_head == NULL) 73 return (0); 74 } 75 76 SIMPLEQ_FOREACH(vn, vn_head, node) { 77 if (v->parent == vn->parent && v->ino == vn->ino) 78 return (1); 79 } 80 81 SIMPLEQ_INSERT_TAIL(vn_head, v, node); 82 dict_set(&f->name_tree, v->path, vn_head); 83 84 return (1); 85 } 86 87 void 88 remove_vnode_from_name_tree(struct fuse *f, struct fuse_vnode *vn) 89 { 90 struct fuse_vn_head *vn_head; 91 struct fuse_vnode *v; 92 struct fuse_vnode *lastv; 93 94 vn_head = dict_get(&f->name_tree, vn->path); 95 if (vn_head == NULL) 96 return; 97 98 lastv = NULL; 99 SIMPLEQ_FOREACH(v, vn_head, node) { 100 if (v->parent == vn->parent) 101 break; 102 103 lastv = v; 104 } 105 if (v == NULL) 106 return; 107 108 /* if we found the vnode remove it */ 109 if (v == SIMPLEQ_FIRST(vn_head)) 110 SIMPLEQ_REMOVE_HEAD(vn_head, node); 111 else 112 SIMPLEQ_REMOVE_AFTER(vn_head, lastv, node); 113 114 /* if the queue is empty we need to remove it from the dict */ 115 if (SIMPLEQ_EMPTY(vn_head)) { 116 vn_head = dict_pop(&f->name_tree, vn->path); 117 free(vn_head); 118 } 119 } 120 121 struct fuse_vnode * 122 get_vn_by_name_and_parent(struct fuse *f, uint8_t *xpath, ino_t parent) 123 { 124 struct fuse_vn_head *vn_head; 125 struct fuse_vnode *v = NULL; 126 const char *path = (const char *)xpath; 127 128 vn_head = dict_get(&f->name_tree, path); 129 130 if (vn_head == NULL) 131 goto fail; 132 133 SIMPLEQ_FOREACH(v, vn_head, node) 134 if (v->parent == parent) 135 return (v); 136 137 fail: 138 errno = ENOENT; 139 return (NULL); 140 } 141 142 char * 143 build_realname(struct fuse *f, ino_t ino) 144 { 145 struct fuse_vnode *vn; 146 char *name; 147 char *tmp = NULL; 148 int firstshot = 0, ret; 149 150 name = strdup("/"); 151 if (name == NULL) 152 return (NULL); 153 154 vn = tree_get(&f->vnode_tree, ino); 155 if (!vn || !name) { 156 free(name); 157 return (NULL); 158 } 159 160 while (vn->parent != 0) { 161 if (firstshot++) 162 ret = asprintf(&tmp, "/%s%s", vn->path, name); 163 else 164 ret = asprintf(&tmp, "/%s", vn->path); 165 166 if (ret == -1) { 167 free(name); 168 return (NULL); 169 } 170 171 free(name); 172 name = tmp; 173 tmp = NULL; 174 vn = tree_get(&f->vnode_tree, vn->parent); 175 176 if (!vn) 177 return (NULL); 178 } 179 180 if (ino == (ino_t)0) 181 DPRINTF("%s: NULL ino\n", __func__); 182 183 DPRINTF("realname %s\n", name); 184 return (name); 185 } 186