source: mainline/uspace/lib/fs/libfs.c@ 09ab0a9a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 09ab0a9a was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 20.2 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 return IPC_GET_RETVAL(answer);
427}
428
429void fs_node_initialize(fs_node_t *fn)
430{
431 memset(fn, 0, sizeof(fs_node_t));
432}
433
434static char plb_get_char(unsigned pos)
435{
436 return reg.plb_ro[pos % PLB_SIZE];
437}
438
439static errno_t plb_get_component(char *dest, unsigned *sz, unsigned *ppos,
440 unsigned last)
441{
442 unsigned pos = *ppos;
443 unsigned size = 0;
444
445 if (pos == last) {
446 *sz = 0;
447 return ERANGE;
448 }
449
450 char c = plb_get_char(pos);
451 if (c == '/')
452 pos++;
453
454 for (int i = 0; i <= NAME_MAX; i++) {
455 c = plb_get_char(pos);
456 if (pos == last || c == '/') {
457 dest[i] = 0;
458 *ppos = pos;
459 *sz = size;
460 return EOK;
461 }
462 dest[i] = c;
463 pos++;
464 size++;
465 }
466 return ENAMETOOLONG;
467}
468
469static errno_t receive_fname(char *buffer)
470{
471 ipc_call_t call;
472 size_t size;
473
474 if (!async_data_write_receive(&call, &size))
475 return ENOENT;
476
477 if (size > NAME_MAX + 1) {
478 async_answer_0(&call, ERANGE);
479 return ERANGE;
480 }
481
482 return async_data_write_finalize(&call, buffer, size);
483}
484
485/** Link a file at a path.
486 *
487 */
488void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
489{
490 service_id_t parent_sid = IPC_GET_ARG1(*req);
491 fs_index_t parent_index = IPC_GET_ARG2(*req);
492 fs_index_t child_index = IPC_GET_ARG3(*req);
493
494 char component[NAME_MAX + 1];
495 errno_t rc = receive_fname(component);
496 if (rc != EOK) {
497 async_answer_0(req, rc);
498 return;
499 }
500
501 fs_node_t *parent = NULL;
502 rc = ops->node_get(&parent, parent_sid, parent_index);
503 if (parent == NULL) {
504 async_answer_0(req, rc == EOK ? EBADF : rc);
505 return;
506 }
507
508 fs_node_t *child = NULL;
509 rc = ops->node_get(&child, parent_sid, child_index);
510 if (child == NULL) {
511 async_answer_0(req, rc == EOK ? EBADF : rc);
512 ops->node_put(parent);
513 return;
514 }
515
516 rc = ops->link(parent, child, component);
517 ops->node_put(parent);
518 ops->node_put(child);
519 async_answer_0(req, rc);
520}
521
522/** Lookup VFS triplet by name in the file system name space.
523 *
524 * The path passed in the PLB must be in the canonical file system path format
525 * as returned by the canonify() function.
526 *
527 * @param ops libfs operations structure with function pointers to
528 * file system implementation
529 * @param fs_handle File system handle of the file system where to perform
530 * the lookup.
531 * @param req VFS_OUT_LOOKUP request data itself.
532 *
533 */
534void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
535{
536 unsigned first = IPC_GET_ARG1(*req);
537 unsigned len = IPC_GET_ARG2(*req);
538 service_id_t service_id = IPC_GET_ARG3(*req);
539 fs_index_t index = IPC_GET_ARG4(*req);
540 int lflag = IPC_GET_ARG5(*req);
541
542 // TODO: Validate flags.
543
544 unsigned next = first;
545 unsigned last = first + len;
546
547 char component[NAME_MAX + 1];
548 errno_t rc;
549
550 fs_node_t *par = NULL;
551 fs_node_t *cur = NULL;
552 fs_node_t *tmp = NULL;
553 unsigned clen = 0;
554
555 rc = ops->node_get(&cur, service_id, index);
556 if (rc != EOK) {
557 async_answer_0(req, rc);
558 goto out;
559 }
560
561 assert(cur != NULL);
562
563 /* Find the file and its parent. */
564
565 unsigned last_next = 0;
566
567 while (next != last) {
568 if (cur == NULL) {
569 assert(par != NULL);
570 goto out1;
571 }
572
573 if (!ops->is_directory(cur)) {
574 async_answer_0(req, ENOTDIR);
575 goto out;
576 }
577
578 last_next = next;
579 /* Collect the component */
580 rc = plb_get_component(component, &clen, &next, last);
581 assert(rc != ERANGE);
582 if (rc != EOK) {
583 async_answer_0(req, rc);
584 goto out;
585 }
586
587 if (clen == 0) {
588 /* The path is just "/". */
589 break;
590 }
591
592 assert(component[clen] == 0);
593
594 /* Match the component */
595 rc = ops->match(&tmp, cur, component);
596 if (rc != EOK) {
597 async_answer_0(req, rc);
598 goto out;
599 }
600
601 /* Descend one level */
602 if (par) {
603 rc = ops->node_put(par);
604 if (rc != EOK) {
605 async_answer_0(req, rc);
606 goto out;
607 }
608 }
609
610 par = cur;
611 cur = tmp;
612 tmp = NULL;
613 }
614
615 /*
616 * At this point, par is either NULL or a directory.
617 * If cur is NULL, the looked up file does not exist yet.
618 */
619
620 assert(par == NULL || ops->is_directory(par));
621 assert(par != NULL || cur != NULL);
622
623 /* Check for some error conditions. */
624
625 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
626 async_answer_0(req, EISDIR);
627 goto out;
628 }
629
630 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
631 async_answer_0(req, ENOTDIR);
632 goto out;
633 }
634
635 /* Unlink. */
636
637 if (lflag & L_UNLINK) {
638 if (!cur) {
639 async_answer_0(req, ENOENT);
640 goto out;
641 }
642 if (!par) {
643 async_answer_0(req, EINVAL);
644 goto out;
645 }
646
647 rc = ops->unlink(par, cur, component);
648 if (rc == EOK) {
649 aoff64_t size = ops->size_get(cur);
650 async_answer_5(req, EOK, fs_handle,
651 ops->index_get(cur),
652 (ops->is_directory(cur) << 16) | last,
653 LOWER32(size), UPPER32(size));
654 } else {
655 async_answer_0(req, rc);
656 }
657 goto out;
658 }
659
660 /* Create. */
661
662 if (lflag & L_CREATE) {
663 if (cur && (lflag & L_EXCLUSIVE)) {
664 async_answer_0(req, EEXIST);
665 goto out;
666 }
667
668 if (!cur) {
669 rc = ops->create(&cur, service_id,
670 lflag & (L_FILE | L_DIRECTORY));
671 if (rc != EOK) {
672 async_answer_0(req, rc);
673 goto out;
674 }
675 if (!cur) {
676 async_answer_0(req, ENOSPC);
677 goto out;
678 }
679
680 rc = ops->link(par, cur, component);
681 if (rc != EOK) {
682 (void) ops->destroy(cur);
683 cur = NULL;
684 async_answer_0(req, rc);
685 goto out;
686 }
687 }
688 }
689
690 /* Return. */
691out1:
692 if (!cur) {
693 async_answer_5(req, EOK, fs_handle, ops->index_get(par),
694 (ops->is_directory(par) << 16) | last_next,
695 LOWER32(ops->size_get(par)), UPPER32(ops->size_get(par)));
696 goto out;
697 }
698
699 async_answer_5(req, EOK, fs_handle, ops->index_get(cur),
700 (ops->is_directory(cur) << 16) | last, LOWER32(ops->size_get(cur)),
701 UPPER32(ops->size_get(cur)));
702
703out:
704 if (par)
705 (void) ops->node_put(par);
706
707 if (cur)
708 (void) ops->node_put(cur);
709
710 if (tmp)
711 (void) ops->node_put(tmp);
712}
713
714void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
715{
716 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
717 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
718
719 fs_node_t *fn;
720 errno_t rc = ops->node_get(&fn, service_id, index);
721 on_error(rc, answer_and_return(req, rc));
722
723 ipc_call_t call;
724 size_t size;
725 if ((!async_data_read_receive(&call, &size)) ||
726 (size != sizeof(vfs_stat_t))) {
727 ops->node_put(fn);
728 async_answer_0(&call, EINVAL);
729 async_answer_0(req, EINVAL);
730 return;
731 }
732
733 vfs_stat_t stat;
734 memset(&stat, 0, sizeof(vfs_stat_t));
735
736 stat.fs_handle = fs_handle;
737 stat.service_id = service_id;
738 stat.index = index;
739 stat.lnkcnt = ops->lnkcnt_get(fn);
740 stat.is_file = ops->is_file(fn);
741 stat.is_directory = ops->is_directory(fn);
742 stat.size = ops->size_get(fn);
743 stat.service = ops->service_get(fn);
744
745 ops->node_put(fn);
746
747 async_data_read_finalize(&call, &stat, sizeof(vfs_stat_t));
748 async_answer_0(req, EOK);
749}
750
751void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
752{
753 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
754 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
755
756 fs_node_t *fn;
757 errno_t rc = ops->node_get(&fn, service_id, index);
758 on_error(rc, answer_and_return(req, rc));
759
760 ipc_call_t call;
761 size_t size;
762 if ((!async_data_read_receive(&call, &size)) ||
763 (size != sizeof(vfs_statfs_t))) {
764 goto error;
765 }
766
767 vfs_statfs_t st;
768 memset(&st, 0, sizeof(vfs_statfs_t));
769
770 str_cpy(st.fs_name, sizeof(st.fs_name), fs_name);
771
772 if (ops->size_block != NULL) {
773 rc = ops->size_block(service_id, &st.f_bsize);
774 if (rc != EOK)
775 goto error;
776 }
777
778 if (ops->total_block_count != NULL) {
779 rc = ops->total_block_count(service_id, &st.f_blocks);
780 if (rc != EOK)
781 goto error;
782 }
783
784 if (ops->free_block_count != NULL) {
785 rc = ops->free_block_count(service_id, &st.f_bfree);
786 if (rc != EOK)
787 goto error;
788 }
789
790 ops->node_put(fn);
791 async_data_read_finalize(&call, &st, sizeof(vfs_statfs_t));
792 async_answer_0(req, EOK);
793 return;
794
795error:
796 ops->node_put(fn);
797 async_answer_0(&call, EINVAL);
798 async_answer_0(req, EINVAL);
799}
800
801/** Open VFS triplet.
802 *
803 * @param ops libfs operations structure with function pointers to
804 * file system implementation
805 * @param req VFS_OUT_OPEN_NODE request data itself.
806 *
807 */
808void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
809{
810 service_id_t service_id = IPC_GET_ARG1(*req);
811 fs_index_t index = IPC_GET_ARG2(*req);
812
813 fs_node_t *fn;
814 errno_t rc = ops->node_get(&fn, service_id, index);
815 on_error(rc, answer_and_return(req, rc));
816
817 if (fn == NULL) {
818 async_answer_0(req, ENOENT);
819 return;
820 }
821
822 rc = ops->node_open(fn);
823 aoff64_t size = ops->size_get(fn);
824 async_answer_4(req, rc, LOWER32(size), UPPER32(size),
825 ops->lnkcnt_get(fn),
826 (ops->is_file(fn) ? L_FILE : 0) |
827 (ops->is_directory(fn) ? L_DIRECTORY : 0));
828
829 (void) ops->node_put(fn);
830}
831
832static FIBRIL_MUTEX_INITIALIZE(instances_mutex);
833static LIST_INITIALIZE(instances_list);
834
835typedef struct {
836 service_id_t service_id;
837 link_t link;
838 void *data;
839} fs_instance_t;
840
841errno_t fs_instance_create(service_id_t service_id, void *data)
842{
843 fs_instance_t *inst = malloc(sizeof(fs_instance_t));
844 if (!inst)
845 return ENOMEM;
846
847 link_initialize(&inst->link);
848 inst->service_id = service_id;
849 inst->data = data;
850
851 fibril_mutex_lock(&instances_mutex);
852 list_foreach(instances_list, link, fs_instance_t, cur) {
853 if (cur->service_id == service_id) {
854 fibril_mutex_unlock(&instances_mutex);
855 free(inst);
856 return EEXIST;
857 }
858
859 /* keep the list sorted */
860 if (cur->service_id < service_id) {
861 list_insert_before(&inst->link, &cur->link);
862 fibril_mutex_unlock(&instances_mutex);
863 return EOK;
864 }
865 }
866 list_append(&inst->link, &instances_list);
867 fibril_mutex_unlock(&instances_mutex);
868
869 return EOK;
870}
871
872errno_t fs_instance_get(service_id_t service_id, void **idp)
873{
874 fibril_mutex_lock(&instances_mutex);
875
876 list_foreach(instances_list, link, fs_instance_t, inst) {
877 if (inst->service_id == service_id) {
878 *idp = inst->data;
879 fibril_mutex_unlock(&instances_mutex);
880 return EOK;
881 }
882 }
883
884 fibril_mutex_unlock(&instances_mutex);
885 return ENOENT;
886}
887
888errno_t fs_instance_destroy(service_id_t service_id)
889{
890 fibril_mutex_lock(&instances_mutex);
891
892 list_foreach(instances_list, link, fs_instance_t, inst) {
893 if (inst->service_id == service_id) {
894 list_remove(&inst->link);
895 fibril_mutex_unlock(&instances_mutex);
896 free(inst);
897 return EOK;
898 }
899 }
900
901 fibril_mutex_unlock(&instances_mutex);
902 return ENOENT;
903}
904
905/** @}
906 */
Note: See TracBrowser for help on using the repository browser.