Home | History | Annotate | Line # | Download | only in refuse
      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 
     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
     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
    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. */
    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. */
    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*
    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
    221 fuse_chan_set_fuse(struct fuse_chan* chan, struct fuse* fuse) {
    222     chan->fuse = fuse;
    223 }
    224 
    225 void
    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*
    231 fuse_chan_mountpoint(const struct fuse_chan* chan) {
    232     return chan->mountpoint;
    233 }
    234 
    235 struct fuse_args*
    236 fuse_chan_args(struct fuse_chan* chan) {
    237     return chan->args;
    238 }
    239 
    240 struct fuse*
    241 fuse_chan_fuse(struct fuse_chan* chan) {
    242     return chan->fuse;
    243 }
    244 
    245 bool
    246 fuse_chan_is_to_be_destroyed(const struct fuse_chan* chan) {
    247     return chan->is_to_be_destroyed;
    248 }
    249