1 /* $OpenBSD: fuse_subr.c,v 1.11 2016/09/07 17:53:35 natano Exp $ */ 2 /* 3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <errno.h> 19 #include <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 pino) 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->ref = 1; 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 (pino == (ino_t)0) 45 vn->parent = NULL; 46 else { 47 if ((vn->parent = tree_get(&f->vnode_tree, pino)) == NULL) { 48 DPRINTF("%s: parent vnode %llu not in the vnode tree\n", 49 __func__, pino); 50 free(vn); 51 errno = ENOENT; 52 return (NULL); 53 } 54 ref_vn(vn->parent); 55 } 56 57 if (ino == (ino_t)-1) { 58 f->max_ino++; 59 vn->ino = f->max_ino; 60 } 61 62 return (vn); 63 } 64 65 void 66 ref_vn(struct fuse_vnode *vn) 67 { 68 vn->ref++; 69 } 70 71 void 72 unref_vn(struct fuse *f, struct fuse_vnode *vn) 73 { 74 if (--vn->ref == 0) { 75 tree_pop(&f->vnode_tree, vn->ino); 76 remove_vnode_from_name_tree(f, vn); 77 if (vn->parent != NULL) 78 unref_vn(f, vn->parent); 79 free(vn); 80 } 81 } 82 83 int 84 set_vn(struct fuse *f, struct fuse_vnode *v) 85 { 86 struct fuse_vn_head *vn_head; 87 struct fuse_vnode *vn; 88 89 DPRINTF("%s: create or update vnode %llu@%llu = %s\n", __func__, 90 (unsigned long long)v->ino, 91 v->parent ? (unsigned long long)v->parent->ino : 0, 92 v->path); 93 94 if (tree_set(&f->vnode_tree, v->ino, v) == NULL) 95 return (0); 96 97 if (!dict_check(&f->name_tree, v->path)) { 98 vn_head = malloc(sizeof(*vn_head)); 99 if (vn_head == NULL) 100 return (0); 101 SIMPLEQ_INIT(vn_head); 102 } else { 103 vn_head = dict_get(&f->name_tree, v->path); 104 if (vn_head == NULL) 105 return (0); 106 } 107 108 SIMPLEQ_FOREACH(vn, vn_head, node) { 109 if (v->parent == vn->parent && v->ino == vn->ino) 110 return (1); 111 } 112 113 SIMPLEQ_INSERT_TAIL(vn_head, v, node); 114 dict_set(&f->name_tree, v->path, vn_head); 115 116 return (1); 117 } 118 119 void 120 remove_vnode_from_name_tree(struct fuse *f, struct fuse_vnode *vn) 121 { 122 struct fuse_vn_head *vn_head; 123 struct fuse_vnode *v; 124 struct fuse_vnode *lastv; 125 126 vn_head = dict_get(&f->name_tree, vn->path); 127 if (vn_head == NULL) 128 return; 129 130 lastv = NULL; 131 SIMPLEQ_FOREACH(v, vn_head, node) { 132 if (v->parent == vn->parent) 133 break; 134 135 lastv = v; 136 } 137 if (v == NULL) 138 return; 139 140 /* if we found the vnode remove it */ 141 if (v == SIMPLEQ_FIRST(vn_head)) 142 SIMPLEQ_REMOVE_HEAD(vn_head, node); 143 else 144 SIMPLEQ_REMOVE_AFTER(vn_head, lastv, node); 145 146 /* if the queue is empty we need to remove it from the dict */ 147 if (SIMPLEQ_EMPTY(vn_head)) { 148 vn_head = dict_pop(&f->name_tree, vn->path); 149 free(vn_head); 150 } 151 } 152 153 struct fuse_vnode * 154 get_vn_by_name_and_parent(struct fuse *f, uint8_t *xpath, ino_t pino) 155 { 156 struct fuse_vn_head *vn_head; 157 struct fuse_vnode *v = NULL; 158 const char *path = (const char *)xpath; 159 160 vn_head = dict_get(&f->name_tree, path); 161 162 if (vn_head == NULL) 163 goto fail; 164 165 SIMPLEQ_FOREACH(v, vn_head, node) 166 if (v->parent && v->parent->ino == pino) 167 return (v); 168 169 fail: 170 errno = ENOENT; 171 return (NULL); 172 } 173 174 char * 175 build_realname(struct fuse *f, ino_t ino) 176 { 177 struct fuse_vnode *vn; 178 char *name; 179 char *tmp = NULL; 180 int firstshot = 0, ret; 181 182 name = strdup("/"); 183 if (name == NULL) 184 return (NULL); 185 186 vn = tree_get(&f->vnode_tree, ino); 187 if (!vn || !name) { 188 free(name); 189 return (NULL); 190 } 191 192 while (vn->parent != NULL) { 193 if (firstshot++) 194 ret = asprintf(&tmp, "/%s%s", vn->path, name); 195 else 196 ret = asprintf(&tmp, "/%s", vn->path); 197 198 if (ret == -1) { 199 free(name); 200 return (NULL); 201 } 202 203 free(name); 204 name = tmp; 205 tmp = NULL; 206 vn = vn->parent; 207 } 208 209 if (ino == (ino_t)0) 210 DPRINTF("%s: NULL ino\n", __func__); 211 212 DPRINTF("realname %s\n", name); 213 return (name); 214 } 215