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 *
alloc_vn(struct fuse * f,const char * path,ino_t ino,ino_t pino)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
ref_vn(struct fuse_vnode * vn)67 ref_vn(struct fuse_vnode *vn)
68 {
69 vn->ref++;
70 }
71
72 void
unref_vn(struct fuse * f,struct fuse_vnode * vn)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
set_vn(struct fuse * f,struct fuse_vnode * v)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
remove_vnode_from_name_tree(struct fuse * f,struct fuse_vnode * vn)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 *
get_vn_by_name_and_parent(struct fuse * f,uint8_t * xpath,ino_t pino)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 *
build_realname(struct fuse * f,ino_t ino)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