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