xref: /openbsd-src/lib/libfuse/fuse_subr.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
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