1 /* $NetBSD: chan.c,v 1.1 2022/01/22 08:09:40 pho Exp $ */
2
3 /*
4 * Copyright (c) 2021 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote
16 * products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #if !defined(lint)
34 __RCSID("$NetBSD: chan.c,v 1.1 2022/01/22 08:09:40 pho Exp $");
35 #endif /* !lint */
36
37 #include <assert.h>
38 #include <err.h>
39 #include <fuse_internal.h>
40 #if defined(MULTITHREADED_REFUSE)
41 # include <pthread.h>
42 #endif
43 #include <stdlib.h>
44 #include <string.h>
45
46 /* The communication channel API is a part of the public interface of
47 * FUSE. However, it is actually an implementation detail and we can't
48 * really emulate its semantics. We only use it for implementing
49 * pre-3.0 fuse_mount(), i.e. the mount-before-new thingy.
50 */
51
52 struct fuse_chan {
53 char* mountpoint;
54 struct fuse_args* args;
55 struct fuse* fuse;
56 bool is_to_be_destroyed;
57 };
58
59 struct refuse_chan_storage {
60 size_t n_alloc;
61 struct fuse_chan** vec;
62 };
63
64 #if defined(MULTITHREADED_REFUSE)
65 static pthread_mutex_t storage_mutex = PTHREAD_MUTEX_INITIALIZER;
66 #endif
67 static struct refuse_chan_storage storage;
68
69
fuse_chan_new(const char * mountpoint,const struct fuse_args * args)70 struct fuse_chan* fuse_chan_new(const char* mountpoint, const struct fuse_args* args) {
71 struct fuse_chan* chan;
72
73 chan = calloc(1, sizeof(*chan));
74 if (!chan) {
75 warn("%s", __func__);
76 return NULL;
77 }
78
79 chan->mountpoint = strdup(mountpoint);
80 if (!chan->mountpoint) {
81 warn("%s", __func__);
82 free(chan);
83 return NULL;
84 }
85
86 chan->args = fuse_opt_deep_copy_args(args->argc, args->argv);
87 if (!chan->args) {
88 warn("%s", __func__);
89 free(chan->mountpoint);
90 free(chan);
91 return NULL;
92 }
93
94 return chan;
95 }
96
97 void
fuse_chan_destroy(struct fuse_chan * chan)98 fuse_chan_destroy(struct fuse_chan* chan) {
99 free(chan->mountpoint);
100 fuse_opt_free_args(chan->args);
101 free(chan->args);
102 free(chan);
103 }
104
105 int
fuse_chan_stash(struct fuse_chan * chan)106 fuse_chan_stash(struct fuse_chan* chan) {
107 int idx;
108 #if defined(MULTITHREADED_REFUSE)
109 int rv;
110
111 rv = pthread_mutex_lock(&storage_mutex);
112 assert(rv == 0);
113 #endif
114
115 /* Find the first empty slot in the storage. */
116 for (idx = 0; idx < (int)storage.n_alloc; idx++) {
117 if (storage.vec[idx] == NULL) {
118 storage.vec[idx] = chan;
119 goto done;
120 }
121 }
122
123 /* Allocate more space */
124 storage.n_alloc = (storage.n_alloc + 8) * 2;
125 storage.vec = realloc(storage.vec, sizeof(struct fuse_chan*) * storage.n_alloc);
126 if (!storage.vec) {
127 warn("%s", __func__);
128 idx = -1;
129 goto done;
130 }
131
132 storage.vec[idx] = chan;
133 memset(&storage.vec[idx+1], 0, sizeof(struct fuse_chan*) * (storage.n_alloc - (size_t)idx - 1));
134
135 done:
136 #if defined(MULTITHREADED_REFUSE)
137 rv = pthread_mutex_unlock(&storage_mutex);
138 assert(rv == 0);
139 #endif
140 return idx;
141 }
142
143 /* Acquire a pointer to a stashed channel with a given index. */
fuse_chan_peek(int idx)144 struct fuse_chan* fuse_chan_peek(int idx) {
145 struct fuse_chan* chan = NULL;
146 #if defined(MULTITHREADED_REFUSE)
147 int rv;
148
149 rv = pthread_mutex_lock(&storage_mutex);
150 assert(rv == 0);
151 #endif
152
153 if (idx >= 0 && idx < (int)storage.n_alloc) {
154 chan = storage.vec[idx];
155 }
156
157 #if defined(MULTITHREADED_REFUSE)
158 rv = pthread_mutex_unlock(&storage_mutex);
159 assert(rv == 0);
160 #endif
161 return chan;
162 }
163
164 /* Like fuse_chan_peek() but also removes the channel from the
165 * storage. */
fuse_chan_take(int idx)166 struct fuse_chan* fuse_chan_take(int idx) {
167 struct fuse_chan* chan = NULL;
168 #if defined(MULTITHREADED_REFUSE)
169 int rv;
170
171 rv = pthread_mutex_lock(&storage_mutex);
172 assert(rv == 0);
173 #endif
174
175 if (idx >= 0 && idx < (int)storage.n_alloc) {
176 chan = storage.vec[idx];
177 storage.vec[idx] = NULL;
178 }
179
180 #if defined(MULTITHREADED_REFUSE)
181 rv = pthread_mutex_unlock(&storage_mutex);
182 assert(rv == 0);
183 #endif
184 return chan;
185 }
186
187 /* Find the first stashed channel satisfying a given predicate in the
188 * storage, or NULL if no channels satisfy it. */
189 struct fuse_chan*
fuse_chan_find(bool (* pred)(struct fuse_chan *,void *),int * found_idx,void * priv)190 fuse_chan_find(bool (*pred)(struct fuse_chan*, void*),
191 int* found_idx, void* priv) {
192 int idx;
193 struct fuse_chan* chan = NULL;
194 #if defined(MULTITHREADED_REFUSE)
195 int rv;
196
197 rv = pthread_mutex_lock(&storage_mutex);
198 assert(rv == 0);
199 #endif
200
201 for (idx = 0; idx < (int)storage.n_alloc; idx++) {
202 if (storage.vec[idx] != NULL) {
203 if (pred(storage.vec[idx], priv)) {
204 chan = storage.vec[idx];
205 if (found_idx)
206 *found_idx = idx;
207 goto done;
208 }
209 }
210 }
211
212 done:
213 #if defined(MULTITHREADED_REFUSE)
214 rv = pthread_mutex_unlock(&storage_mutex);
215 assert(rv == 0);
216 #endif
217 return chan;
218 }
219
220 void
fuse_chan_set_fuse(struct fuse_chan * chan,struct fuse * fuse)221 fuse_chan_set_fuse(struct fuse_chan* chan, struct fuse* fuse) {
222 chan->fuse = fuse;
223 }
224
225 void
fuse_chan_set_to_be_destroyed(struct fuse_chan * chan,bool is_to_be_destroyed)226 fuse_chan_set_to_be_destroyed(struct fuse_chan* chan, bool is_to_be_destroyed) {
227 chan->is_to_be_destroyed = is_to_be_destroyed;
228 }
229
230 const char*
fuse_chan_mountpoint(const struct fuse_chan * chan)231 fuse_chan_mountpoint(const struct fuse_chan* chan) {
232 return chan->mountpoint;
233 }
234
235 struct fuse_args*
fuse_chan_args(struct fuse_chan * chan)236 fuse_chan_args(struct fuse_chan* chan) {
237 return chan->args;
238 }
239
240 struct fuse*
fuse_chan_fuse(struct fuse_chan * chan)241 fuse_chan_fuse(struct fuse_chan* chan) {
242 return chan->fuse;
243 }
244
245 bool
fuse_chan_is_to_be_destroyed(const struct fuse_chan * chan)246 fuse_chan_is_to_be_destroyed(const struct fuse_chan* chan) {
247 return chan->is_to_be_destroyed;
248 }
249