source: mainline/uspace/lib/fs/libfs.c@ 099c834

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

Fix block comment formatting (ccheck).

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