source: mainline/uspace/lib/fs/libfs.c@ c20cccb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c20cccb was 984a9ba, checked in by Martin Decky <martin@…>, 7 years ago

do not expose the call capability handler from the async framework

Keep the call capability handler encapsulated within the async framework
and do not expose it explicitly via its API. Use the pointer to
ipc_call_t as the sole object identifying an IPC call in the code that
uses the async framework.

This plugs a major leak in the abstraction and also simplifies both the
async framework (slightly) and all IPC servers.

  • Property mode set to 100644
File size: 20.4 KB
Line 
1/*
2 * Copyright (c) 2009 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 libfs
30 * @{
31 */
32/**
33 * @file
34 * Glue code which is common to all FS implementations.
35 */
36
37#include "libfs.h"
38#include <macros.h>
39#include <errno.h>
40#include <async.h>
41#include <as.h>
42#include <assert.h>
43#include <dirent.h>
44#include <mem.h>
45#include <str.h>
46#include <stdlib.h>
47#include <fibril_synch.h>
48#include <ipc/vfs.h>
49#include <vfs/vfs.h>
50
51#define on_error(rc, action) \
52 do { \
53 if ((rc) != EOK) \
54 action; \
55 } while (0)
56
57#define combine_rc(rc1, rc2) \
58 ((rc1) == EOK ? (rc2) : (rc1))
59
60#define answer_and_return(call, rc) \
61 do { \
62 async_answer_0((call), (rc)); \
63 return; \
64 } while (0)
65
66static fs_reg_t reg;
67
68static vfs_out_ops_t *vfs_out_ops = NULL;
69static libfs_ops_t *libfs_ops = NULL;
70
71static char fs_name[FS_NAME_MAXLEN + 1];
72
73static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_call_t *);
74static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_call_t *);
75static void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_call_t *);
76static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_call_t *);
77static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_call_t *);
78
79static void vfs_out_fsprobe(ipc_call_t *req)
80{
81 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
82 errno_t rc;
83 vfs_fs_probe_info_t info;
84
85 ipc_call_t call;
86 size_t size;
87 if ((!async_data_read_receive(&call, &size)) ||
88 (size != sizeof(info))) {
89 async_answer_0(&call, EIO);
90 async_answer_0(req, EIO);
91 return;
92 }
93
94 memset(&info, 0, sizeof(info));
95 rc = vfs_out_ops->fsprobe(service_id, &info);
96 if (rc != EOK) {
97 async_answer_0(&call, EIO);
98 async_answer_0(req, rc);
99 return;
100 }
101
102 async_data_read_finalize(&call, &info, sizeof(info));
103 async_answer_0(req, EOK);
104}
105
106static void vfs_out_mounted(ipc_call_t *req)
107{
108 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
109 char *opts;
110 errno_t rc;
111
112 /* Accept the mount options. */
113 rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
114 if (rc != EOK) {
115 async_answer_0(req, rc);
116 return;
117 }
118
119 fs_index_t index;
120 aoff64_t size;
121 rc = vfs_out_ops->mounted(service_id, opts, &index, &size);
122
123 if (rc == EOK) {
124 async_answer_3(req, EOK, index, LOWER32(size),
125 UPPER32(size));
126 } else
127 async_answer_0(req, rc);
128
129 free(opts);
130}
131
132static void vfs_out_unmounted(ipc_call_t *req)
133{
134 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
135 errno_t rc;
136
137 rc = vfs_out_ops->unmounted(service_id);
138
139 async_answer_0(req, rc);
140}
141
142static void vfs_out_link(ipc_call_t *req)
143{
144 libfs_link(libfs_ops, reg.fs_handle, req);
145}
146
147static void vfs_out_lookup(ipc_call_t *req)
148{
149 libfs_lookup(libfs_ops, reg.fs_handle, req);
150}
151
152static void vfs_out_read(ipc_call_t *req)
153{
154 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
155 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
156 aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
157 IPC_GET_ARG4(*req));
158 size_t rbytes;
159 errno_t rc;
160
161 rc = vfs_out_ops->read(service_id, index, pos, &rbytes);
162
163 if (rc == EOK)
164 async_answer_1(req, EOK, rbytes);
165 else
166 async_answer_0(req, rc);
167}
168
169static void vfs_out_write(ipc_call_t *req)
170{
171 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
172 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
173 aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
174 IPC_GET_ARG4(*req));
175 size_t wbytes;
176 aoff64_t nsize;
177 errno_t rc;
178
179 rc = vfs_out_ops->write(service_id, index, pos, &wbytes, &nsize);
180
181 if (rc == EOK) {
182 async_answer_3(req, EOK, wbytes, LOWER32(nsize),
183 UPPER32(nsize));
184 } else
185 async_answer_0(req, rc);
186}
187
188static void vfs_out_truncate(ipc_call_t *req)
189{
190 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
191 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
192 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
193 IPC_GET_ARG4(*req));
194 errno_t rc;
195
196 rc = vfs_out_ops->truncate(service_id, index, size);
197
198 async_answer_0(req, rc);
199}
200
201static void vfs_out_close(ipc_call_t *req)
202{
203 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
204 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
205 errno_t rc;
206
207 rc = vfs_out_ops->close(service_id, index);
208
209 async_answer_0(req, rc);
210}
211
212static void vfs_out_destroy(ipc_call_t *req)
213{
214 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
215 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
216
217 errno_t rc;
218 fs_node_t *node = NULL;
219 rc = libfs_ops->node_get(&node, service_id, index);
220 if (rc == EOK && node != NULL) {
221 bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
222 libfs_ops->node_put(node);
223 if (destroy)
224 rc = vfs_out_ops->destroy(service_id, index);
225 }
226 async_answer_0(req, rc);
227}
228
229static void vfs_out_open_node(ipc_call_t *req)
230{
231 libfs_open_node(libfs_ops, reg.fs_handle, req);
232}
233
234static void vfs_out_stat(ipc_call_t *req)
235{
236 libfs_stat(libfs_ops, reg.fs_handle, req);
237}
238
239static void vfs_out_sync(ipc_call_t *req)
240{
241 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
242 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
243 errno_t rc;
244
245 rc = vfs_out_ops->sync(service_id, index);
246
247 async_answer_0(req, rc);
248}
249
250static void vfs_out_statfs(ipc_call_t *req)
251{
252 libfs_statfs(libfs_ops, reg.fs_handle, req);
253}
254
255static void vfs_out_is_empty(ipc_call_t *req)
256{
257 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
258 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
259 errno_t rc;
260
261 fs_node_t *node = NULL;
262 rc = libfs_ops->node_get(&node, service_id, index);
263 if (rc != EOK)
264 async_answer_0(req, rc);
265 if (node == NULL)
266 async_answer_0(req, EINVAL);
267
268 bool children = false;
269 rc = libfs_ops->has_children(&children, node);
270 libfs_ops->node_put(node);
271
272 if (rc != EOK)
273 async_answer_0(req, rc);
274 async_answer_0(req, children ? ENOTEMPTY : EOK);
275}
276
277static void vfs_connection(ipc_call_t *icall, void *arg)
278{
279 if (icall->cap_handle) {
280 /*
281 * This only happens for connections opened by
282 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
283 * created by IPC_M_CONNECT_TO_ME.
284 */
285 async_answer_0(icall, EOK);
286 }
287
288 while (true) {
289 ipc_call_t call;
290 async_get_call(&call);
291
292 if (!IPC_GET_IMETHOD(call))
293 return;
294
295 switch (IPC_GET_IMETHOD(call)) {
296 case VFS_OUT_FSPROBE:
297 vfs_out_fsprobe(&call);
298 break;
299 case VFS_OUT_MOUNTED:
300 vfs_out_mounted(&call);
301 break;
302 case VFS_OUT_UNMOUNTED:
303 vfs_out_unmounted(&call);
304 break;
305 case VFS_OUT_LINK:
306 vfs_out_link(&call);
307 break;
308 case VFS_OUT_LOOKUP:
309 vfs_out_lookup(&call);
310 break;
311 case VFS_OUT_READ:
312 vfs_out_read(&call);
313 break;
314 case VFS_OUT_WRITE:
315 vfs_out_write(&call);
316 break;
317 case VFS_OUT_TRUNCATE:
318 vfs_out_truncate(&call);
319 break;
320 case VFS_OUT_CLOSE:
321 vfs_out_close(&call);
322 break;
323 case VFS_OUT_DESTROY:
324 vfs_out_destroy(&call);
325 break;
326 case VFS_OUT_OPEN_NODE:
327 vfs_out_open_node(&call);
328 break;
329 case VFS_OUT_STAT:
330 vfs_out_stat(&call);
331 break;
332 case VFS_OUT_SYNC:
333 vfs_out_sync(&call);
334 break;
335 case VFS_OUT_STATFS:
336 vfs_out_statfs(&call);
337 break;
338 case VFS_OUT_IS_EMPTY:
339 vfs_out_is_empty(&call);
340 break;
341 default:
342 async_answer_0(&call, ENOTSUP);
343 break;
344 }
345 }
346}
347
348/** Register file system server.
349 *
350 * This function abstracts away the tedious registration protocol from
351 * file system implementations and lets them to reuse this registration glue
352 * code.
353 *
354 * @param sess Session for communication with VFS.
355 * @param info VFS info structure supplied by the file system
356 * implementation.
357 * @param vops Address of the vfs_out_ops_t structure.
358 * @param lops Address of the libfs_ops_t structure.
359 *
360 * @return EOK on success or a non-zero error code on errror.
361 *
362 */
363errno_t fs_register(async_sess_t *sess, vfs_info_t *info, vfs_out_ops_t *vops,
364 libfs_ops_t *lops)
365{
366 /*
367 * Tell VFS that we are here and want to get registered.
368 * We use the async framework because VFS will answer the request
369 * out-of-order, when it knows that the operation succeeded or failed.
370 */
371
372 async_exch_t *exch = async_exchange_begin(sess);
373
374 ipc_call_t answer;
375 aid_t req = async_send_0(exch, VFS_IN_REGISTER, &answer);
376
377 /*
378 * Send our VFS info structure to VFS.
379 */
380 errno_t rc = async_data_write_start(exch, info, sizeof(*info));
381
382 if (rc != EOK) {
383 async_exchange_end(exch);
384 async_forget(req);
385 return rc;
386 }
387
388 /*
389 * Set VFS_OUT and libfs operations.
390 */
391 vfs_out_ops = vops;
392 libfs_ops = lops;
393
394 str_cpy(fs_name, sizeof(fs_name), info->name);
395
396 /*
397 * Ask VFS for callback connection.
398 */
399 port_id_t port;
400 rc = async_create_callback_port(exch, INTERFACE_VFS_DRIVER_CB, 0, 0,
401 vfs_connection, NULL, &port);
402
403 /*
404 * Request sharing the Path Lookup Buffer with VFS.
405 */
406 rc = async_share_in_start_0_0(exch, PLB_SIZE, (void *) &reg.plb_ro);
407 if (reg.plb_ro == AS_MAP_FAILED) {
408 async_exchange_end(exch);
409 async_forget(req);
410 return ENOMEM;
411 }
412
413 async_exchange_end(exch);
414
415 if (rc) {
416 async_forget(req);
417 return rc;
418 }
419
420 /*
421 * Pick up the answer for the request to the VFS_IN_REQUEST call.
422 */
423 async_wait_for(req, NULL);
424 reg.fs_handle = (int) IPC_GET_ARG1(answer);
425
426 /*
427 * Tell the async framework that other connections are to be handled by
428 * the same connection fibril as well.
429 */
430 async_set_fallback_port_handler(vfs_connection, NULL);
431
432 return IPC_GET_RETVAL(answer);
433}
434
435void fs_node_initialize(fs_node_t *fn)
436{
437 memset(fn, 0, sizeof(fs_node_t));
438}
439
440static char plb_get_char(unsigned pos)
441{
442 return reg.plb_ro[pos % PLB_SIZE];
443}
444
445static errno_t plb_get_component(char *dest, unsigned *sz, unsigned *ppos,
446 unsigned last)
447{
448 unsigned pos = *ppos;
449 unsigned size = 0;
450
451 if (pos == last) {
452 *sz = 0;
453 return ERANGE;
454 }
455
456 char c = plb_get_char(pos);
457 if (c == '/')
458 pos++;
459
460 for (int i = 0; i <= NAME_MAX; i++) {
461 c = plb_get_char(pos);
462 if (pos == last || c == '/') {
463 dest[i] = 0;
464 *ppos = pos;
465 *sz = size;
466 return EOK;
467 }
468 dest[i] = c;
469 pos++;
470 size++;
471 }
472 return ENAMETOOLONG;
473}
474
475static errno_t receive_fname(char *buffer)
476{
477 ipc_call_t call;
478 size_t size;
479
480 if (!async_data_write_receive(&call, &size))
481 return ENOENT;
482
483 if (size > NAME_MAX + 1) {
484 async_answer_0(&call, ERANGE);
485 return ERANGE;
486 }
487
488 return async_data_write_finalize(&call, buffer, size);
489}
490
491/** Link a file at a path.
492 *
493 */
494void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
495{
496 service_id_t parent_sid = IPC_GET_ARG1(*req);
497 fs_index_t parent_index = IPC_GET_ARG2(*req);
498 fs_index_t child_index = IPC_GET_ARG3(*req);
499
500 char component[NAME_MAX + 1];
501 errno_t rc = receive_fname(component);
502 if (rc != EOK) {
503 async_answer_0(req, rc);
504 return;
505 }
506
507 fs_node_t *parent = NULL;
508 rc = ops->node_get(&parent, parent_sid, parent_index);
509 if (parent == NULL) {
510 async_answer_0(req, rc == EOK ? EBADF : rc);
511 return;
512 }
513
514 fs_node_t *child = NULL;
515 rc = ops->node_get(&child, parent_sid, child_index);
516 if (child == NULL) {
517 async_answer_0(req, rc == EOK ? EBADF : rc);
518 ops->node_put(parent);
519 return;
520 }
521
522 rc = ops->link(parent, child, component);
523 ops->node_put(parent);
524 ops->node_put(child);
525 async_answer_0(req, rc);
526}
527
528/** Lookup VFS triplet by name in the file system name space.
529 *
530 * The path passed in the PLB must be in the canonical file system path format
531 * as returned by the canonify() function.
532 *
533 * @param ops libfs operations structure with function pointers to
534 * file system implementation
535 * @param fs_handle File system handle of the file system where to perform
536 * the lookup.
537 * @param req VFS_OUT_LOOKUP request data itself.
538 *
539 */
540void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
541{
542 unsigned first = IPC_GET_ARG1(*req);
543 unsigned len = IPC_GET_ARG2(*req);
544 service_id_t service_id = IPC_GET_ARG3(*req);
545 fs_index_t index = IPC_GET_ARG4(*req);
546 int lflag = IPC_GET_ARG5(*req);
547
548 // TODO: Validate flags.
549
550 unsigned next = first;
551 unsigned last = first + len;
552
553 char component[NAME_MAX + 1];
554 errno_t rc;
555
556 fs_node_t *par = NULL;
557 fs_node_t *cur = NULL;
558 fs_node_t *tmp = NULL;
559 unsigned clen = 0;
560
561 rc = ops->node_get(&cur, service_id, index);
562 if (rc != EOK) {
563 async_answer_0(req, rc);
564 goto out;
565 }
566
567 assert(cur != NULL);
568
569 /* Find the file and its parent. */
570
571 unsigned last_next = 0;
572
573 while (next != last) {
574 if (cur == NULL) {
575 assert(par != NULL);
576 goto out1;
577 }
578
579 if (!ops->is_directory(cur)) {
580 async_answer_0(req, ENOTDIR);
581 goto out;
582 }
583
584 last_next = next;
585 /* Collect the component */
586 rc = plb_get_component(component, &clen, &next, last);
587 assert(rc != ERANGE);
588 if (rc != EOK) {
589 async_answer_0(req, rc);
590 goto out;
591 }
592
593 if (clen == 0) {
594 /* The path is just "/". */
595 break;
596 }
597
598 assert(component[clen] == 0);
599
600 /* Match the component */
601 rc = ops->match(&tmp, cur, component);
602 if (rc != EOK) {
603 async_answer_0(req, rc);
604 goto out;
605 }
606
607 /* Descend one level */
608 if (par) {
609 rc = ops->node_put(par);
610 if (rc != EOK) {
611 async_answer_0(req, rc);
612 goto out;
613 }
614 }
615
616 par = cur;
617 cur = tmp;
618 tmp = NULL;
619 }
620
621 /*
622 * At this point, par is either NULL or a directory.
623 * If cur is NULL, the looked up file does not exist yet.
624 */
625
626 assert(par == NULL || ops->is_directory(par));
627 assert(par != NULL || cur != NULL);
628
629 /* Check for some error conditions. */
630
631 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
632 async_answer_0(req, EISDIR);
633 goto out;
634 }
635
636 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
637 async_answer_0(req, ENOTDIR);
638 goto out;
639 }
640
641 /* Unlink. */
642
643 if (lflag & L_UNLINK) {
644 if (!cur) {
645 async_answer_0(req, ENOENT);
646 goto out;
647 }
648 if (!par) {
649 async_answer_0(req, EINVAL);
650 goto out;
651 }
652
653 rc = ops->unlink(par, cur, component);
654 if (rc == EOK) {
655 aoff64_t size = ops->size_get(cur);
656 async_answer_5(req, EOK, fs_handle,
657 ops->index_get(cur),
658 (ops->is_directory(cur) << 16) | last,
659 LOWER32(size), UPPER32(size));
660 } else {
661 async_answer_0(req, rc);
662 }
663 goto out;
664 }
665
666 /* Create. */
667
668 if (lflag & L_CREATE) {
669 if (cur && (lflag & L_EXCLUSIVE)) {
670 async_answer_0(req, EEXIST);
671 goto out;
672 }
673
674 if (!cur) {
675 rc = ops->create(&cur, service_id,
676 lflag & (L_FILE | L_DIRECTORY));
677 if (rc != EOK) {
678 async_answer_0(req, rc);
679 goto out;
680 }
681 if (!cur) {
682 async_answer_0(req, ENOSPC);
683 goto out;
684 }
685
686 rc = ops->link(par, cur, component);
687 if (rc != EOK) {
688 (void) ops->destroy(cur);
689 cur = NULL;
690 async_answer_0(req, rc);
691 goto out;
692 }
693 }
694 }
695
696 /* Return. */
697out1:
698 if (!cur) {
699 async_answer_5(req, EOK, fs_handle, ops->index_get(par),
700 (ops->is_directory(par) << 16) | last_next,
701 LOWER32(ops->size_get(par)), UPPER32(ops->size_get(par)));
702 goto out;
703 }
704
705 async_answer_5(req, EOK, fs_handle, ops->index_get(cur),
706 (ops->is_directory(cur) << 16) | last, LOWER32(ops->size_get(cur)),
707 UPPER32(ops->size_get(cur)));
708
709out:
710 if (par)
711 (void) ops->node_put(par);
712
713 if (cur)
714 (void) ops->node_put(cur);
715
716 if (tmp)
717 (void) ops->node_put(tmp);
718}
719
720void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
721{
722 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
723 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
724
725 fs_node_t *fn;
726 errno_t rc = ops->node_get(&fn, service_id, index);
727 on_error(rc, answer_and_return(req, rc));
728
729 ipc_call_t call;
730 size_t size;
731 if ((!async_data_read_receive(&call, &size)) ||
732 (size != sizeof(vfs_stat_t))) {
733 ops->node_put(fn);
734 async_answer_0(&call, EINVAL);
735 async_answer_0(req, EINVAL);
736 return;
737 }
738
739 vfs_stat_t stat;
740 memset(&stat, 0, sizeof(vfs_stat_t));
741
742 stat.fs_handle = fs_handle;
743 stat.service_id = service_id;
744 stat.index = index;
745 stat.lnkcnt = ops->lnkcnt_get(fn);
746 stat.is_file = ops->is_file(fn);
747 stat.is_directory = ops->is_directory(fn);
748 stat.size = ops->size_get(fn);
749 stat.service = ops->service_get(fn);
750
751 ops->node_put(fn);
752
753 async_data_read_finalize(&call, &stat, sizeof(vfs_stat_t));
754 async_answer_0(req, EOK);
755}
756
757void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
758{
759 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
760 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
761
762 fs_node_t *fn;
763 errno_t rc = ops->node_get(&fn, service_id, index);
764 on_error(rc, answer_and_return(req, rc));
765
766 ipc_call_t call;
767 size_t size;
768 if ((!async_data_read_receive(&call, &size)) ||
769 (size != sizeof(vfs_statfs_t))) {
770 goto error;
771 }
772
773 vfs_statfs_t st;
774 memset(&st, 0, sizeof(vfs_statfs_t));
775
776 str_cpy(st.fs_name, sizeof(st.fs_name), fs_name);
777
778 if (ops->size_block != NULL) {
779 rc = ops->size_block(service_id, &st.f_bsize);
780 if (rc != EOK)
781 goto error;
782 }
783
784 if (ops->total_block_count != NULL) {
785 rc = ops->total_block_count(service_id, &st.f_blocks);
786 if (rc != EOK)
787 goto error;
788 }
789
790 if (ops->free_block_count != NULL) {
791 rc = ops->free_block_count(service_id, &st.f_bfree);
792 if (rc != EOK)
793 goto error;
794 }
795
796 ops->node_put(fn);
797 async_data_read_finalize(&call, &st, sizeof(vfs_statfs_t));
798 async_answer_0(req, EOK);
799 return;
800
801error:
802 ops->node_put(fn);
803 async_answer_0(&call, EINVAL);
804 async_answer_0(req, EINVAL);
805}
806
807
808/** Open VFS triplet.
809 *
810 * @param ops libfs operations structure with function pointers to
811 * file system implementation
812 * @param req VFS_OUT_OPEN_NODE request data itself.
813 *
814 */
815void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
816{
817 service_id_t service_id = IPC_GET_ARG1(*req);
818 fs_index_t index = IPC_GET_ARG2(*req);
819
820 fs_node_t *fn;
821 errno_t rc = ops->node_get(&fn, service_id, index);
822 on_error(rc, answer_and_return(req, rc));
823
824 if (fn == NULL) {
825 async_answer_0(req, ENOENT);
826 return;
827 }
828
829 rc = ops->node_open(fn);
830 aoff64_t size = ops->size_get(fn);
831 async_answer_4(req, rc, LOWER32(size), UPPER32(size),
832 ops->lnkcnt_get(fn),
833 (ops->is_file(fn) ? L_FILE : 0) |
834 (ops->is_directory(fn) ? L_DIRECTORY : 0));
835
836 (void) ops->node_put(fn);
837}
838
839static FIBRIL_MUTEX_INITIALIZE(instances_mutex);
840static LIST_INITIALIZE(instances_list);
841
842typedef struct {
843 service_id_t service_id;
844 link_t link;
845 void *data;
846} fs_instance_t;
847
848errno_t fs_instance_create(service_id_t service_id, void *data)
849{
850 fs_instance_t *inst = malloc(sizeof(fs_instance_t));
851 if (!inst)
852 return ENOMEM;
853
854 link_initialize(&inst->link);
855 inst->service_id = service_id;
856 inst->data = data;
857
858 fibril_mutex_lock(&instances_mutex);
859 list_foreach(instances_list, link, fs_instance_t, cur) {
860 if (cur->service_id == service_id) {
861 fibril_mutex_unlock(&instances_mutex);
862 free(inst);
863 return EEXIST;
864 }
865
866 /* keep the list sorted */
867 if (cur->service_id < service_id) {
868 list_insert_before(&inst->link, &cur->link);
869 fibril_mutex_unlock(&instances_mutex);
870 return EOK;
871 }
872 }
873 list_append(&inst->link, &instances_list);
874 fibril_mutex_unlock(&instances_mutex);
875
876 return EOK;
877}
878
879errno_t fs_instance_get(service_id_t service_id, void **idp)
880{
881 fibril_mutex_lock(&instances_mutex);
882
883 list_foreach(instances_list, link, fs_instance_t, inst) {
884 if (inst->service_id == service_id) {
885 *idp = inst->data;
886 fibril_mutex_unlock(&instances_mutex);
887 return EOK;
888 }
889 }
890
891 fibril_mutex_unlock(&instances_mutex);
892 return ENOENT;
893}
894
895errno_t fs_instance_destroy(service_id_t service_id)
896{
897 fibril_mutex_lock(&instances_mutex);
898
899 list_foreach(instances_list, link, fs_instance_t, inst) {
900 if (inst->service_id == service_id) {
901 list_remove(&inst->link);
902 fibril_mutex_unlock(&instances_mutex);
903 free(inst);
904 return EOK;
905 }
906 }
907
908 fibril_mutex_unlock(&instances_mutex);
909 return ENOENT;
910}
911
912/** @}
913 */
Note: See TracBrowser for help on using the repository browser.