source: mainline/uspace/lib/fs/libfs.c@ 99013b84

Last change on this file since 99013b84 was 77f0a1d, checked in by Jakub Jermar <jakub@…>, 7 years ago

Get rid of rid in favor of req_handle

  • 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 /* At this point, par is either NULL or a directory.
628 * If cur is NULL, the looked up file does not exist yet.
629 */
630
631 assert(par == NULL || ops->is_directory(par));
632 assert(par != NULL || cur != NULL);
633
634 /* Check for some error conditions. */
635
636 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
637 async_answer_0(req_handle, EISDIR);
638 goto out;
639 }
640
641 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
642 async_answer_0(req_handle, ENOTDIR);
643 goto out;
644 }
645
646 /* Unlink. */
647
648 if (lflag & L_UNLINK) {
649 if (!cur) {
650 async_answer_0(req_handle, ENOENT);
651 goto out;
652 }
653 if (!par) {
654 async_answer_0(req_handle, EINVAL);
655 goto out;
656 }
657
658 rc = ops->unlink(par, cur, component);
659 if (rc == EOK) {
660 aoff64_t size = ops->size_get(cur);
661 async_answer_5(req_handle, EOK, fs_handle,
662 ops->index_get(cur),
663 (ops->is_directory(cur) << 16) | last,
664 LOWER32(size), UPPER32(size));
665 } else {
666 async_answer_0(req_handle, rc);
667 }
668 goto out;
669 }
670
671 /* Create. */
672
673 if (lflag & L_CREATE) {
674 if (cur && (lflag & L_EXCLUSIVE)) {
675 async_answer_0(req_handle, EEXIST);
676 goto out;
677 }
678
679 if (!cur) {
680 rc = ops->create(&cur, service_id,
681 lflag & (L_FILE | L_DIRECTORY));
682 if (rc != EOK) {
683 async_answer_0(req_handle, rc);
684 goto out;
685 }
686 if (!cur) {
687 async_answer_0(req_handle, ENOSPC);
688 goto out;
689 }
690
691 rc = ops->link(par, cur, component);
692 if (rc != EOK) {
693 (void) ops->destroy(cur);
694 cur = NULL;
695 async_answer_0(req_handle, rc);
696 goto out;
697 }
698 }
699 }
700
701 /* Return. */
702out1:
703 if (!cur) {
704 async_answer_5(req_handle, EOK, fs_handle, ops->index_get(par),
705 (ops->is_directory(par) << 16) | last_next,
706 LOWER32(ops->size_get(par)), UPPER32(ops->size_get(par)));
707 goto out;
708 }
709
710 async_answer_5(req_handle, EOK, fs_handle, ops->index_get(cur),
711 (ops->is_directory(cur) << 16) | last, LOWER32(ops->size_get(cur)),
712 UPPER32(ops->size_get(cur)));
713
714out:
715 if (par)
716 (void) ops->node_put(par);
717
718 if (cur)
719 (void) ops->node_put(cur);
720
721 if (tmp)
722 (void) ops->node_put(tmp);
723}
724
725void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle,
726 cap_call_handle_t req_handle, ipc_call_t *request)
727{
728 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
729 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
730
731 fs_node_t *fn;
732 errno_t rc = ops->node_get(&fn, service_id, index);
733 on_error(rc, answer_and_return(req_handle, rc));
734
735 cap_call_handle_t chandle;
736 size_t size;
737 if ((!async_data_read_receive(&chandle, &size)) ||
738 (size != sizeof(vfs_stat_t))) {
739 ops->node_put(fn);
740 async_answer_0(chandle, EINVAL);
741 async_answer_0(req_handle, EINVAL);
742 return;
743 }
744
745 vfs_stat_t stat;
746 memset(&stat, 0, sizeof(vfs_stat_t));
747
748 stat.fs_handle = fs_handle;
749 stat.service_id = service_id;
750 stat.index = index;
751 stat.lnkcnt = ops->lnkcnt_get(fn);
752 stat.is_file = ops->is_file(fn);
753 stat.is_directory = ops->is_directory(fn);
754 stat.size = ops->size_get(fn);
755 stat.service = ops->service_get(fn);
756
757 ops->node_put(fn);
758
759
760 async_data_read_finalize(chandle, &stat, sizeof(vfs_stat_t));
761 async_answer_0(req_handle, EOK);
762}
763
764void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle,
765 cap_call_handle_t req_handle, ipc_call_t *request)
766{
767 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
768 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
769
770 fs_node_t *fn;
771 errno_t rc = ops->node_get(&fn, service_id, index);
772 on_error(rc, answer_and_return(req_handle, rc));
773
774 cap_call_handle_t chandle;
775 size_t size;
776 if ((!async_data_read_receive(&chandle, &size)) ||
777 (size != sizeof(vfs_statfs_t))) {
778 goto error;
779 }
780
781 vfs_statfs_t st;
782 memset(&st, 0, sizeof(vfs_statfs_t));
783
784 str_cpy(st.fs_name, sizeof(st.fs_name), fs_name);
785
786 if (ops->size_block != NULL) {
787 rc = ops->size_block(service_id, &st.f_bsize);
788 if (rc != EOK)
789 goto error;
790 }
791
792 if (ops->total_block_count != NULL) {
793 rc = ops->total_block_count(service_id, &st.f_blocks);
794 if (rc != EOK)
795 goto error;
796 }
797
798 if (ops->free_block_count != NULL) {
799 rc = ops->free_block_count(service_id, &st.f_bfree);
800 if (rc != EOK)
801 goto error;
802 }
803
804 ops->node_put(fn);
805 async_data_read_finalize(chandle, &st, sizeof(vfs_statfs_t));
806 async_answer_0(req_handle, EOK);
807 return;
808
809error:
810 ops->node_put(fn);
811 async_answer_0(chandle, EINVAL);
812 async_answer_0(req_handle, EINVAL);
813}
814
815
816/** Open VFS triplet.
817 *
818 * @param ops libfs operations structure with function pointers to
819 * file system implementation
820 * @param req_handle Call handle of the VFS_OUT_OPEN_NODE request.
821 * @param request VFS_OUT_OPEN_NODE request data itself.
822 *
823 */
824void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle,
825 cap_call_handle_t req_handle, ipc_call_t *request)
826{
827 service_id_t service_id = IPC_GET_ARG1(*request);
828 fs_index_t index = IPC_GET_ARG2(*request);
829
830 fs_node_t *fn;
831 errno_t rc = ops->node_get(&fn, service_id, index);
832 on_error(rc, answer_and_return(req_handle, rc));
833
834 if (fn == NULL) {
835 async_answer_0(req_handle, ENOENT);
836 return;
837 }
838
839 rc = ops->node_open(fn);
840 aoff64_t size = ops->size_get(fn);
841 async_answer_4(req_handle, rc, LOWER32(size), UPPER32(size),
842 ops->lnkcnt_get(fn),
843 (ops->is_file(fn) ? L_FILE : 0) |
844 (ops->is_directory(fn) ? L_DIRECTORY : 0));
845
846 (void) ops->node_put(fn);
847}
848
849static FIBRIL_MUTEX_INITIALIZE(instances_mutex);
850static LIST_INITIALIZE(instances_list);
851
852typedef struct {
853 service_id_t service_id;
854 link_t link;
855 void *data;
856} fs_instance_t;
857
858errno_t fs_instance_create(service_id_t service_id, void *data)
859{
860 fs_instance_t *inst = malloc(sizeof(fs_instance_t));
861 if (!inst)
862 return ENOMEM;
863
864 link_initialize(&inst->link);
865 inst->service_id = service_id;
866 inst->data = data;
867
868 fibril_mutex_lock(&instances_mutex);
869 list_foreach(instances_list, link, fs_instance_t, cur) {
870 if (cur->service_id == service_id) {
871 fibril_mutex_unlock(&instances_mutex);
872 free(inst);
873 return EEXIST;
874 }
875
876 /* keep the list sorted */
877 if (cur->service_id < service_id) {
878 list_insert_before(&inst->link, &cur->link);
879 fibril_mutex_unlock(&instances_mutex);
880 return EOK;
881 }
882 }
883 list_append(&inst->link, &instances_list);
884 fibril_mutex_unlock(&instances_mutex);
885
886 return EOK;
887}
888
889errno_t fs_instance_get(service_id_t service_id, void **idp)
890{
891 fibril_mutex_lock(&instances_mutex);
892 list_foreach(instances_list, link, fs_instance_t, inst) {
893 if (inst->service_id == service_id) {
894 *idp = inst->data;
895 fibril_mutex_unlock(&instances_mutex);
896 return EOK;
897 }
898 }
899 fibril_mutex_unlock(&instances_mutex);
900 return ENOENT;
901}
902
903errno_t fs_instance_destroy(service_id_t service_id)
904{
905 fibril_mutex_lock(&instances_mutex);
906 list_foreach(instances_list, link, fs_instance_t, inst) {
907 if (inst->service_id == service_id) {
908 list_remove(&inst->link);
909 fibril_mutex_unlock(&instances_mutex);
910 free(inst);
911 return EOK;
912 }
913 }
914 fibril_mutex_unlock(&instances_mutex);
915 return ENOENT;
916}
917
918/** @}
919 */
Note: See TracBrowser for help on using the repository browser.