GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: lib/libfuse/fuse_subr.c Lines: 0 88 0.0 %
Date: 2017-11-13 Branches: 0 76 0.0 %

Line Branch Exec Source
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
}