1 /* $OpenBSD: fuse_subr.c,v 1.12 2018/05/21 11:47:46 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 <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 DPRINTF("New Inode: %llu\t", (unsigned long long)vn->ino); 61 } 62 63 return (vn); 64 } 65 66 void 67 ref_vn(struct fuse_vnode *vn) 68 { 69 vn->ref++; 70 } 71 72 void 73 unref_vn(struct fuse *f, struct fuse_vnode *vn) 74 { 75 if (--vn->ref == 0) { 76 tree_pop(&f->vnode_tree, vn->ino); 77 remove_vnode_from_name_tree(f, vn); 78 if (vn->parent != NULL) 79 unref_vn(f, vn->parent); 80 free(vn); 81 } 82 } 83 84 int 85 set_vn(struct fuse *f, struct fuse_vnode *v) 86 { 87 struct fuse_vn_head *vn_head; 88 struct fuse_vnode *vn; 89 90 if (tree_set(&f->vnode_tree, v->ino, v) == NULL) 91 return (0); 92 93 if (!dict_check(&f->name_tree, v->path)) { 94 vn_head = malloc(sizeof(*vn_head)); 95 if (vn_head == NULL) 96 return (0); 97 SIMPLEQ_INIT(vn_head); 98 } else { 99 vn_head = dict_get(&f->name_tree, v->path); 100 if (vn_head == NULL) 101 return (0); 102 } 103 104 SIMPLEQ_FOREACH(vn, vn_head, node) { 105 if (v->parent == vn->parent && v->ino == vn->ino) 106 return (1); 107 } 108 109 SIMPLEQ_INSERT_TAIL(vn_head, v, node); 110 dict_set(&f->name_tree, v->path, vn_head); 111 112 return (1); 113 } 114 115 void 116 remove_vnode_from_name_tree(struct fuse *f, struct fuse_vnode *vn) 117 { 118 struct fuse_vn_head *vn_head; 119 struct fuse_vnode *v; 120 struct fuse_vnode *lastv; 121 122 vn_head = dict_get(&f->name_tree, vn->path); 123 if (vn_head == NULL) 124 return; 125 126 lastv = NULL; 127 SIMPLEQ_FOREACH(v, vn_head, node) { 128 if (v->parent == vn->parent) 129 break; 130 131 lastv = v; 132 } 133 if (v == NULL) 134 return; 135 136 /* if we found the vnode remove it */ 137 if (v == SIMPLEQ_FIRST(vn_head)) 138 SIMPLEQ_REMOVE_HEAD(vn_head, node); 139 else 140 SIMPLEQ_REMOVE_AFTER(vn_head, lastv, node); 141 142 /* if the queue is empty we need to remove it from the dict */ 143 if (SIMPLEQ_EMPTY(vn_head)) { 144 vn_head = dict_pop(&f->name_tree, vn->path); 145 free(vn_head); 146 } 147 } 148 149 struct fuse_vnode * 150 get_vn_by_name_and_parent(struct fuse *f, uint8_t *xpath, ino_t pino) 151 { 152 struct fuse_vn_head *vn_head; 153 struct fuse_vnode *v = NULL; 154 const char *path = (const char *)xpath; 155 156 vn_head = dict_get(&f->name_tree, path); 157 158 if (vn_head == NULL) 159 goto fail; 160 161 SIMPLEQ_FOREACH(v, vn_head, node) 162 if (v->parent && v->parent->ino == pino) 163 return (v); 164 165 fail: 166 errno = ENOENT; 167 return (NULL); 168 } 169 170 char * 171 build_realname(struct fuse *f, ino_t ino) 172 { 173 struct fuse_vnode *vn; 174 char *name; 175 char *tmp = NULL; 176 int firstshot = 0, ret; 177 178 name = strdup("/"); 179 if (name == NULL) 180 return (NULL); 181 182 vn = tree_get(&f->vnode_tree, ino); 183 if (!vn || !name) { 184 free(name); 185 return (NULL); 186 } 187 188 while (vn->parent != NULL) { 189 if (firstshot++) 190 ret = asprintf(&tmp, "/%s%s", vn->path, name); 191 else 192 ret = asprintf(&tmp, "/%s", vn->path); 193 194 if (ret == -1) { 195 free(name); 196 return (NULL); 197 } 198 199 free(name); 200 name = tmp; 201 tmp = NULL; 202 vn = vn->parent; 203 } 204 205 if (ino == (ino_t)0) 206 DPRINTF("%s: NULL ino\t", __func__); 207 208 DPRINTF("%s", name); 209 return (name); 210 } 211