source: mainline/uspace/srv/vfs/vfs_register.c@ 08e103d4

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 9.4 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup vfs
30 * @{
31 */
32
33/**
34 * @file vfs_register.c
35 * @brief
36 */
37
38#include <ipc/services.h>
39#include <async.h>
40#include <fibril.h>
41#include <fibril_synch.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <str.h>
46#include <ctype.h>
47#include <stdbool.h>
48#include <adt/list.h>
49#include <as.h>
50#include <assert.h>
51#include <stdatomic.h>
52#include <vfs/vfs.h>
53#include "vfs.h"
54
55FIBRIL_CONDVAR_INITIALIZE(fs_list_cv);
56FIBRIL_MUTEX_INITIALIZE(fs_list_lock);
57LIST_INITIALIZE(fs_list);
58
59static atomic_int fs_handle_next = 1;
60
61/** Verify the VFS info structure.
62 *
63 * @param info Info structure to be verified.
64 *
65 * @return Non-zero if the info structure is sane, zero otherwise.
66 *
67 */
68static bool vfs_info_sane(vfs_info_t *info)
69{
70 int i;
71
72 /*
73 * Check if the name is non-empty and is composed solely of ASCII
74 * characters [a-z]+[a-z0-9_-]*.
75 */
76 if (!islower(info->name[0])) {
77 dprintf("The name doesn't start with a lowercase character.\n");
78 return false;
79 }
80
81 for (i = 1; i < FS_NAME_MAXLEN; i++) {
82 if (!(islower(info->name[i]) || isdigit(info->name[i])) &&
83 (info->name[i] != '-') && (info->name[i] != '_')) {
84 if (info->name[i] == '\0') {
85 break;
86 } else {
87 dprintf("The name contains illegal "
88 "characters.\n");
89 return false;
90 }
91 }
92 }
93
94 /*
95 * This check is not redundant. It ensures that the name is
96 * NULL-terminated, even if FS_NAME_MAXLEN characters are used.
97 */
98 if (info->name[i] != '\0') {
99 dprintf("The name is not properly NULL-terminated.\n");
100 return false;
101 }
102
103 return true;
104}
105
106/** VFS_REGISTER protocol function.
107 *
108 * @param req Call structure with the request.
109 *
110 */
111void vfs_register(ipc_call_t *req)
112{
113 vfs_info_t *vfs_info;
114 errno_t rc = async_data_write_accept((void **) &vfs_info, false,
115 sizeof(vfs_info_t), sizeof(vfs_info_t), 0, NULL);
116
117 if (rc != EOK) {
118 dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
119 rc);
120 async_answer_0(req, rc);
121 return;
122 }
123
124 /*
125 * Allocate and initialize a buffer for the fs_info structure.
126 */
127 fs_info_t *fs_info = (fs_info_t *) malloc(sizeof(fs_info_t));
128 if (!fs_info) {
129 dprintf("Could not allocate memory for FS info.\n");
130 async_answer_0(req, ENOMEM);
131 return;
132 }
133
134 link_initialize(&fs_info->fs_link);
135 fs_info->vfs_info = *vfs_info;
136 free(vfs_info);
137
138 dprintf("VFS info delivered.\n");
139
140 if (!vfs_info_sane(&fs_info->vfs_info)) {
141 free(fs_info);
142 async_answer_0(req, EINVAL);
143 return;
144 }
145
146 fibril_mutex_lock(&fs_list_lock);
147
148 /*
149 * Check for duplicit registrations.
150 */
151 if (fs_name_to_handle(fs_info->vfs_info.instance,
152 fs_info->vfs_info.name, false)) {
153 /*
154 * We already register a fs like this.
155 */
156 dprintf("FS is already registered.\n");
157 fibril_mutex_unlock(&fs_list_lock);
158 free(fs_info);
159 async_answer_0(req, EEXIST);
160 return;
161 }
162
163 /*
164 * Add fs_info to the list of registered FS's.
165 */
166 dprintf("Inserting FS into the list of registered file systems.\n");
167 list_append(&fs_info->fs_link, &fs_list);
168
169 /*
170 * Now we want the client to send us the IPC_M_CONNECT_TO_ME call so
171 * that a callback connection is created and we have a phone through
172 * which to forward VFS requests to it.
173 */
174 fs_info->sess = async_callback_receive(EXCHANGE_PARALLEL);
175 if (!fs_info->sess) {
176 dprintf("Callback connection expected\n");
177 list_remove(&fs_info->fs_link);
178 fibril_mutex_unlock(&fs_list_lock);
179 free(fs_info);
180 async_answer_0(req, EINVAL);
181 return;
182 }
183
184 /* FIXME: Work around problem with callback sessions */
185 async_sess_args_set(fs_info->sess, INTERFACE_VFS_DRIVER_CB, 0, 0);
186
187 dprintf("Callback connection to FS created.\n");
188
189 /*
190 * The client will want us to send him the address space area with PLB.
191 */
192
193 ipc_call_t call;
194 size_t size;
195 if (!async_share_in_receive(&call, &size)) {
196 dprintf("Unexpected call\n");
197 list_remove(&fs_info->fs_link);
198 fibril_mutex_unlock(&fs_list_lock);
199 async_hangup(fs_info->sess);
200 free(fs_info);
201 async_answer_0(&call, EINVAL);
202 async_answer_0(req, EINVAL);
203 return;
204 }
205
206 /*
207 * We can only send the client address space area PLB_SIZE bytes long.
208 */
209 if (size != PLB_SIZE) {
210 dprintf("Client suggests wrong size of PFB, size = %zu\n", size);
211 list_remove(&fs_info->fs_link);
212 fibril_mutex_unlock(&fs_list_lock);
213 async_hangup(fs_info->sess);
214 free(fs_info);
215 async_answer_0(&call, EINVAL);
216 async_answer_0(req, EINVAL);
217 return;
218 }
219
220 /*
221 * Commit to read-only sharing the PLB with the client.
222 */
223 (void) async_share_in_finalize(&call, plb,
224 AS_AREA_READ | AS_AREA_CACHEABLE);
225
226 dprintf("Sharing PLB.\n");
227
228 /*
229 * That was it. The FS has been registered.
230 * In reply to the VFS_REGISTER request, we assign the client file
231 * system a global file system handle.
232 */
233 fs_info->fs_handle = atomic_fetch_add(&fs_handle_next, 1);
234 async_answer_1(req, EOK, (sysarg_t) fs_info->fs_handle);
235
236 fibril_condvar_broadcast(&fs_list_cv);
237 fibril_mutex_unlock(&fs_list_lock);
238
239 dprintf("\"%.*s\" filesystem successfully registered, handle=%d.\n",
240 FS_NAME_MAXLEN, fs_info->vfs_info.name, fs_info->fs_handle);
241}
242
243/** Begin an exchange for a given file system handle
244 *
245 * @param handle File system handle.
246 *
247 * @return Exchange for a multi-call request.
248 * @return NULL if no such file exists.
249 *
250 */
251async_exch_t *vfs_exchange_grab(fs_handle_t handle)
252{
253 /*
254 * For now, we don't try to be very clever and very fast.
255 * We simply lookup the session in fs_list and
256 * begin an exchange.
257 */
258 fibril_mutex_lock(&fs_list_lock);
259
260 list_foreach(fs_list, fs_link, fs_info_t, fs) {
261 if (fs->fs_handle == handle) {
262 fibril_mutex_unlock(&fs_list_lock);
263
264 assert(fs->sess);
265 async_exch_t *exch = async_exchange_begin(fs->sess);
266
267 assert(exch);
268 return exch;
269 }
270 }
271
272 fibril_mutex_unlock(&fs_list_lock);
273
274 return NULL;
275}
276
277/** End VFS server exchange.
278 *
279 * @param exch VFS server exchange.
280 *
281 */
282void vfs_exchange_release(async_exch_t *exch)
283{
284 async_exchange_end(exch);
285}
286
287/** Convert file system name to its handle.
288 *
289 * @param name File system name.
290 * @param lock If true, the function will lock and unlock the
291 * fs_list_lock.
292 *
293 * @return File system handle or zero if file system not found.
294 *
295 */
296fs_handle_t fs_name_to_handle(unsigned int instance, const char *name, bool lock)
297{
298 int handle = 0;
299
300 if (lock)
301 fibril_mutex_lock(&fs_list_lock);
302
303 list_foreach(fs_list, fs_link, fs_info_t, fs) {
304 if (str_cmp(fs->vfs_info.name, name) == 0 &&
305 instance == fs->vfs_info.instance) {
306 handle = fs->fs_handle;
307 break;
308 }
309 }
310
311 if (lock)
312 fibril_mutex_unlock(&fs_list_lock);
313
314 return handle;
315}
316
317/** Find the VFS info structure.
318 *
319 * @param handle FS handle for which the VFS info structure is sought.
320 *
321 * @return VFS info structure on success or NULL otherwise.
322 *
323 */
324vfs_info_t *fs_handle_to_info(fs_handle_t handle)
325{
326 vfs_info_t *info = NULL;
327
328 fibril_mutex_lock(&fs_list_lock);
329 list_foreach(fs_list, fs_link, fs_info_t, fs) {
330 if (fs->fs_handle == handle) {
331 info = &fs->vfs_info;
332 break;
333 }
334 }
335 fibril_mutex_unlock(&fs_list_lock);
336
337 return info;
338}
339
340/** Get list of file system types.
341 *
342 * @param fstypes Place to store list of file system types. Free using
343 * vfs_fstypes_free().
344 *
345 * @return EOK on success or an error code
346 */
347errno_t vfs_get_fstypes(vfs_fstypes_t *fstypes)
348{
349 size_t size;
350 size_t count;
351 size_t l;
352
353 fibril_mutex_lock(&fs_list_lock);
354
355 size = 0;
356 count = 0;
357 list_foreach(fs_list, fs_link, fs_info_t, fs) {
358 size += str_bytes(fs->vfs_info.name) + 1;
359 count++;
360 }
361
362 if (size == 0)
363 size = 1;
364
365 fstypes->buf = calloc(1, size);
366 if (fstypes->buf == NULL) {
367 fibril_mutex_unlock(&fs_list_lock);
368 return ENOMEM;
369 }
370
371 fstypes->fstypes = calloc(sizeof(char *), count);
372 if (fstypes->fstypes == NULL) {
373 free(fstypes->buf);
374 fstypes->buf = NULL;
375 fibril_mutex_unlock(&fs_list_lock);
376 return ENOMEM;
377 }
378
379 fstypes->size = size;
380
381 size = 0;
382 count = 0;
383 list_foreach(fs_list, fs_link, fs_info_t, fs) {
384 l = str_bytes(fs->vfs_info.name) + 1;
385 memcpy(fstypes->buf + size, fs->vfs_info.name, l);
386 fstypes->fstypes[count] = &fstypes->buf[size];
387 size += l;
388 count++;
389 }
390
391 fibril_mutex_unlock(&fs_list_lock);
392 return EOK;
393}
394
395/**
396 * @}
397 */
Note: See TracBrowser for help on using the repository browser.