xref: /netbsd-src/lib/librefuse/refuse/chan.c (revision ec9afb42821c4c1dc720bf626e8bbd4d8ab9d6b4)
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