source: mainline/uspace/lib/fs/libfs.c@ 06256b0

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 06256b0 was 06256b0, checked in by Jiri Zarevucky <zarevucky.jiri@…>, 12 years ago

Remove mounting support from the endpoints.

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