Do not send press event to focused window obscured by popup window
[helenos.git] / uspace / lib / fs / libfs.c
blob9dd37bb2c456a7ca419c8933f5a3a7c2b7ff99a6
1 /*
2 * Copyright (c) 2009 Jakub Jermar
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
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.
29 /** @addtogroup libfs
30 * @{
32 /**
33 * @file
34 * Glue code which is common to all FS implementations.
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>
51 #define on_error(rc, action) \
52 do { \
53 if ((rc) != EOK) \
54 action; \
55 } while (0)
57 #define combine_rc(rc1, rc2) \
58 ((rc1) == EOK ? (rc2) : (rc1))
60 #define answer_and_return(call, rc) \
61 do { \
62 async_answer_0((call), (rc)); \
63 return; \
64 } while (0)
66 static fs_reg_t reg;
68 static vfs_out_ops_t *vfs_out_ops = NULL;
69 static libfs_ops_t *libfs_ops = NULL;
71 static char fs_name[FS_NAME_MAXLEN + 1];
73 static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_call_t *);
74 static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_call_t *);
75 static void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_call_t *);
76 static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_call_t *);
77 static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_call_t *);
79 static void vfs_out_fsprobe(ipc_call_t *req)
81 service_id_t service_id = (service_id_t) ipc_get_arg1(req);
82 errno_t rc;
83 vfs_fs_probe_info_t info;
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;
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;
102 async_data_read_finalize(&call, &info, sizeof(info));
103 async_answer_0(req, EOK);
106 static void vfs_out_mounted(ipc_call_t *req)
108 service_id_t service_id = (service_id_t) ipc_get_arg1(req);
109 char *opts;
110 errno_t rc;
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;
119 fs_index_t index;
120 aoff64_t size;
121 rc = vfs_out_ops->mounted(service_id, opts, &index, &size);
123 if (rc == EOK) {
124 async_answer_3(req, EOK, index, LOWER32(size),
125 UPPER32(size));
126 } else
127 async_answer_0(req, rc);
129 free(opts);
132 static void vfs_out_unmounted(ipc_call_t *req)
134 service_id_t service_id = (service_id_t) ipc_get_arg1(req);
135 errno_t rc;
137 rc = vfs_out_ops->unmounted(service_id);
139 async_answer_0(req, rc);
142 static void vfs_out_link(ipc_call_t *req)
144 libfs_link(libfs_ops, reg.fs_handle, req);
147 static void vfs_out_lookup(ipc_call_t *req)
149 libfs_lookup(libfs_ops, reg.fs_handle, req);
152 static void vfs_out_read(ipc_call_t *req)
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;
161 rc = vfs_out_ops->read(service_id, index, pos, &rbytes);
163 if (rc == EOK)
164 async_answer_1(req, EOK, rbytes);
165 else
166 async_answer_0(req, rc);
169 static void vfs_out_write(ipc_call_t *req)
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;
179 rc = vfs_out_ops->write(service_id, index, pos, &wbytes, &nsize);
181 if (rc == EOK) {
182 async_answer_3(req, EOK, wbytes, LOWER32(nsize),
183 UPPER32(nsize));
184 } else
185 async_answer_0(req, rc);
188 static void vfs_out_truncate(ipc_call_t *req)
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;
196 rc = vfs_out_ops->truncate(service_id, index, size);
198 async_answer_0(req, rc);
201 static void vfs_out_close(ipc_call_t *req)
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;
207 rc = vfs_out_ops->close(service_id, index);
209 async_answer_0(req, rc);
212 static void vfs_out_destroy(ipc_call_t *req)
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);
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);
226 async_answer_0(req, rc);
229 static void vfs_out_open_node(ipc_call_t *req)
231 libfs_open_node(libfs_ops, reg.fs_handle, req);
234 static void vfs_out_stat(ipc_call_t *req)
236 libfs_stat(libfs_ops, reg.fs_handle, req);
239 static void vfs_out_sync(ipc_call_t *req)
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;
245 rc = vfs_out_ops->sync(service_id, index);
247 async_answer_0(req, rc);
250 static void vfs_out_statfs(ipc_call_t *req)
252 libfs_statfs(libfs_ops, reg.fs_handle, req);
255 static void vfs_out_is_empty(ipc_call_t *req)
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;
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);
268 bool children = false;
269 rc = libfs_ops->has_children(&children, node);
270 libfs_ops->node_put(node);
272 if (rc != EOK)
273 async_answer_0(req, rc);
274 async_answer_0(req, children ? ENOTEMPTY : EOK);
277 static void vfs_connection(ipc_call_t *icall, void *arg)
279 if (icall->cap_handle) {
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.
285 async_accept_0(icall);
288 while (true) {
289 ipc_call_t call;
290 async_get_call(&call);
292 if (!ipc_get_imethod(&call)) {
293 async_answer_0(&call, EOK);
294 return;
297 switch (ipc_get_imethod(&call)) {
298 case VFS_OUT_FSPROBE:
299 vfs_out_fsprobe(&call);
300 break;
301 case VFS_OUT_MOUNTED:
302 vfs_out_mounted(&call);
303 break;
304 case VFS_OUT_UNMOUNTED:
305 vfs_out_unmounted(&call);
306 break;
307 case VFS_OUT_LINK:
308 vfs_out_link(&call);
309 break;
310 case VFS_OUT_LOOKUP:
311 vfs_out_lookup(&call);
312 break;
313 case VFS_OUT_READ:
314 vfs_out_read(&call);
315 break;
316 case VFS_OUT_WRITE:
317 vfs_out_write(&call);
318 break;
319 case VFS_OUT_TRUNCATE:
320 vfs_out_truncate(&call);
321 break;
322 case VFS_OUT_CLOSE:
323 vfs_out_close(&call);
324 break;
325 case VFS_OUT_DESTROY:
326 vfs_out_destroy(&call);
327 break;
328 case VFS_OUT_OPEN_NODE:
329 vfs_out_open_node(&call);
330 break;
331 case VFS_OUT_STAT:
332 vfs_out_stat(&call);
333 break;
334 case VFS_OUT_SYNC:
335 vfs_out_sync(&call);
336 break;
337 case VFS_OUT_STATFS:
338 vfs_out_statfs(&call);
339 break;
340 case VFS_OUT_IS_EMPTY:
341 vfs_out_is_empty(&call);
342 break;
343 default:
344 async_answer_0(&call, ENOTSUP);
345 break;
350 /** Register file system server.
352 * This function abstracts away the tedious registration protocol from
353 * file system implementations and lets them to reuse this registration glue
354 * code.
356 * @param sess Session for communication with VFS.
357 * @param info VFS info structure supplied by the file system
358 * implementation.
359 * @param vops Address of the vfs_out_ops_t structure.
360 * @param lops Address of the libfs_ops_t structure.
362 * @return EOK on success or a non-zero error code on errror.
365 errno_t fs_register(async_sess_t *sess, vfs_info_t *info, vfs_out_ops_t *vops,
366 libfs_ops_t *lops)
369 * Tell VFS that we are here and want to get registered.
370 * We use the async framework because VFS will answer the request
371 * out-of-order, when it knows that the operation succeeded or failed.
374 async_exch_t *exch = async_exchange_begin(sess);
376 ipc_call_t answer;
377 aid_t req = async_send_0(exch, VFS_IN_REGISTER, &answer);
380 * Send our VFS info structure to VFS.
382 errno_t rc = async_data_write_start(exch, info, sizeof(*info));
384 if (rc != EOK) {
385 async_exchange_end(exch);
386 async_forget(req);
387 return rc;
391 * Set VFS_OUT and libfs operations.
393 vfs_out_ops = vops;
394 libfs_ops = lops;
396 str_cpy(fs_name, sizeof(fs_name), info->name);
399 * Ask VFS for callback connection.
401 port_id_t port;
402 rc = async_create_callback_port(exch, INTERFACE_VFS_DRIVER_CB, 0, 0,
403 vfs_connection, NULL, &port);
406 * Request sharing the Path Lookup Buffer with VFS.
408 rc = async_share_in_start_0_0(exch, PLB_SIZE, (void *) &reg.plb_ro);
409 if (reg.plb_ro == AS_MAP_FAILED) {
410 async_exchange_end(exch);
411 async_forget(req);
412 return ENOMEM;
415 async_exchange_end(exch);
417 if (rc) {
418 async_forget(req);
419 return rc;
423 * Pick up the answer for the request to the VFS_IN_REQUEST call.
425 async_wait_for(req, NULL);
426 reg.fs_handle = (int) ipc_get_arg1(&answer);
428 return ipc_get_retval(&answer);
431 void fs_node_initialize(fs_node_t *fn)
433 memset(fn, 0, sizeof(fs_node_t));
436 static char plb_get_char(unsigned pos)
438 return reg.plb_ro[pos % PLB_SIZE];
441 static errno_t plb_get_component(char *dest, unsigned *sz, unsigned *ppos,
442 unsigned last)
444 unsigned pos = *ppos;
445 unsigned size = 0;
447 if (pos == last) {
448 *sz = 0;
449 return ERANGE;
452 char c = plb_get_char(pos);
453 if (c == '/')
454 pos++;
456 for (int i = 0; i <= NAME_MAX; i++) {
457 c = plb_get_char(pos);
458 if (pos == last || c == '/') {
459 dest[i] = 0;
460 *ppos = pos;
461 *sz = size;
462 return EOK;
464 dest[i] = c;
465 pos++;
466 size++;
468 return ENAMETOOLONG;
471 static errno_t receive_fname(char *buffer)
473 ipc_call_t call;
474 size_t size;
476 if (!async_data_write_receive(&call, &size))
477 return ENOENT;
479 if (size > NAME_MAX + 1) {
480 async_answer_0(&call, ERANGE);
481 return ERANGE;
484 return async_data_write_finalize(&call, buffer, size);
487 /** Link a file at a path.
490 void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
492 service_id_t parent_sid = ipc_get_arg1(req);
493 fs_index_t parent_index = ipc_get_arg2(req);
494 fs_index_t child_index = ipc_get_arg3(req);
496 char component[NAME_MAX + 1];
497 errno_t rc = receive_fname(component);
498 if (rc != EOK) {
499 async_answer_0(req, rc);
500 return;
503 fs_node_t *parent = NULL;
504 rc = ops->node_get(&parent, parent_sid, parent_index);
505 if (parent == NULL) {
506 async_answer_0(req, rc == EOK ? EBADF : rc);
507 return;
510 fs_node_t *child = NULL;
511 rc = ops->node_get(&child, parent_sid, child_index);
512 if (child == NULL) {
513 async_answer_0(req, rc == EOK ? EBADF : rc);
514 ops->node_put(parent);
515 return;
518 rc = ops->link(parent, child, component);
519 ops->node_put(parent);
520 ops->node_put(child);
521 async_answer_0(req, rc);
524 /** Lookup VFS triplet by name in the file system name space.
526 * The path passed in the PLB must be in the canonical file system path format
527 * as returned by the canonify() function.
529 * @param ops libfs operations structure with function pointers to
530 * file system implementation
531 * @param fs_handle File system handle of the file system where to perform
532 * the lookup.
533 * @param req VFS_OUT_LOOKUP request data itself.
536 void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
538 unsigned first = ipc_get_arg1(req);
539 unsigned len = ipc_get_arg2(req);
540 service_id_t service_id = ipc_get_arg3(req);
541 fs_index_t index = ipc_get_arg4(req);
542 int lflag = ipc_get_arg5(req);
544 // TODO: Validate flags.
546 unsigned next = first;
547 unsigned last = first + len;
549 char component[NAME_MAX + 1];
550 errno_t rc;
552 fs_node_t *par = NULL;
553 fs_node_t *cur = NULL;
554 fs_node_t *tmp = NULL;
555 unsigned clen = 0;
557 rc = ops->node_get(&cur, service_id, index);
558 if (rc != EOK) {
559 async_answer_0(req, rc);
560 goto out;
563 assert(cur != NULL);
565 /* Find the file and its parent. */
567 unsigned last_next = 0;
569 while (next != last) {
570 if (cur == NULL) {
571 assert(par != NULL);
572 goto out1;
575 if (!ops->is_directory(cur)) {
576 async_answer_0(req, ENOTDIR);
577 goto out;
580 last_next = next;
581 /* Collect the component */
582 rc = plb_get_component(component, &clen, &next, last);
583 assert(rc != ERANGE);
584 if (rc != EOK) {
585 async_answer_0(req, rc);
586 goto out;
589 if (clen == 0) {
590 /* The path is just "/". */
591 break;
594 assert(component[clen] == 0);
596 /* Match the component */
597 rc = ops->match(&tmp, cur, component);
598 if (rc != EOK) {
599 async_answer_0(req, rc);
600 goto out;
603 /* Descend one level */
604 if (par) {
605 rc = ops->node_put(par);
606 if (rc != EOK) {
607 async_answer_0(req, rc);
608 goto out;
612 par = cur;
613 cur = tmp;
614 tmp = NULL;
618 * At this point, par is either NULL or a directory.
619 * If cur is NULL, the looked up file does not exist yet.
622 assert(par == NULL || ops->is_directory(par));
623 assert(par != NULL || cur != NULL);
625 /* Check for some error conditions. */
627 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
628 async_answer_0(req, EISDIR);
629 goto out;
632 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
633 async_answer_0(req, ENOTDIR);
634 goto out;
637 /* Unlink. */
639 if (lflag & L_UNLINK) {
640 if (!cur) {
641 async_answer_0(req, ENOENT);
642 goto out;
644 if (!par) {
645 async_answer_0(req, EINVAL);
646 goto out;
649 rc = ops->unlink(par, cur, component);
650 if (rc == EOK) {
651 aoff64_t size = ops->size_get(cur);
652 async_answer_5(req, EOK, fs_handle,
653 ops->index_get(cur),
654 (ops->is_directory(cur) << 16) | last,
655 LOWER32(size), UPPER32(size));
656 } else {
657 async_answer_0(req, rc);
659 goto out;
662 /* Create. */
664 if (lflag & L_CREATE) {
665 if (cur && (lflag & L_EXCLUSIVE)) {
666 async_answer_0(req, EEXIST);
667 goto out;
670 if (!cur) {
671 rc = ops->create(&cur, service_id,
672 lflag & (L_FILE | L_DIRECTORY));
673 if (rc != EOK) {
674 async_answer_0(req, rc);
675 goto out;
677 if (!cur) {
678 async_answer_0(req, ENOSPC);
679 goto out;
682 rc = ops->link(par, cur, component);
683 if (rc != EOK) {
684 (void) ops->destroy(cur);
685 cur = NULL;
686 async_answer_0(req, rc);
687 goto out;
692 /* Return. */
693 out1:
694 if (!cur) {
695 async_answer_5(req, EOK, fs_handle, ops->index_get(par),
696 (ops->is_directory(par) << 16) | last_next,
697 LOWER32(ops->size_get(par)), UPPER32(ops->size_get(par)));
698 goto out;
701 async_answer_5(req, EOK, fs_handle, ops->index_get(cur),
702 (ops->is_directory(cur) << 16) | last, LOWER32(ops->size_get(cur)),
703 UPPER32(ops->size_get(cur)));
705 out:
706 if (par)
707 (void) ops->node_put(par);
709 if (cur)
710 (void) ops->node_put(cur);
712 if (tmp)
713 (void) ops->node_put(tmp);
716 void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
718 service_id_t service_id = (service_id_t) ipc_get_arg1(req);
719 fs_index_t index = (fs_index_t) ipc_get_arg2(req);
721 fs_node_t *fn;
722 errno_t rc = ops->node_get(&fn, service_id, index);
723 on_error(rc, answer_and_return(req, rc));
725 ipc_call_t call;
726 size_t size;
727 if ((!async_data_read_receive(&call, &size)) ||
728 (size != sizeof(vfs_stat_t))) {
729 ops->node_put(fn);
730 async_answer_0(&call, EINVAL);
731 async_answer_0(req, EINVAL);
732 return;
735 vfs_stat_t stat;
736 memset(&stat, 0, sizeof(vfs_stat_t));
738 stat.fs_handle = fs_handle;
739 stat.service_id = service_id;
740 stat.index = index;
741 stat.lnkcnt = ops->lnkcnt_get(fn);
742 stat.is_file = ops->is_file(fn);
743 stat.is_directory = ops->is_directory(fn);
744 stat.size = ops->size_get(fn);
745 stat.service = ops->service_get(fn);
747 ops->node_put(fn);
749 async_data_read_finalize(&call, &stat, sizeof(vfs_stat_t));
750 async_answer_0(req, EOK);
753 void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
755 service_id_t service_id = (service_id_t) ipc_get_arg1(req);
756 fs_index_t index = (fs_index_t) ipc_get_arg2(req);
758 fs_node_t *fn;
759 errno_t rc = ops->node_get(&fn, service_id, index);
760 on_error(rc, answer_and_return(req, rc));
762 ipc_call_t call;
763 size_t size;
764 if ((!async_data_read_receive(&call, &size)) ||
765 (size != sizeof(vfs_statfs_t))) {
766 goto error;
769 vfs_statfs_t st;
770 memset(&st, 0, sizeof(vfs_statfs_t));
772 str_cpy(st.fs_name, sizeof(st.fs_name), fs_name);
774 if (ops->size_block != NULL) {
775 rc = ops->size_block(service_id, &st.f_bsize);
776 if (rc != EOK)
777 goto error;
780 if (ops->total_block_count != NULL) {
781 rc = ops->total_block_count(service_id, &st.f_blocks);
782 if (rc != EOK)
783 goto error;
786 if (ops->free_block_count != NULL) {
787 rc = ops->free_block_count(service_id, &st.f_bfree);
788 if (rc != EOK)
789 goto error;
792 ops->node_put(fn);
793 async_data_read_finalize(&call, &st, sizeof(vfs_statfs_t));
794 async_answer_0(req, EOK);
795 return;
797 error:
798 ops->node_put(fn);
799 async_answer_0(&call, EINVAL);
800 async_answer_0(req, EINVAL);
803 /** Open VFS triplet.
805 * @param ops libfs operations structure with function pointers to
806 * file system implementation
807 * @param req VFS_OUT_OPEN_NODE request data itself.
810 void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_call_t *req)
812 service_id_t service_id = ipc_get_arg1(req);
813 fs_index_t index = ipc_get_arg2(req);
815 fs_node_t *fn;
816 errno_t rc = ops->node_get(&fn, service_id, index);
817 on_error(rc, answer_and_return(req, rc));
819 if (fn == NULL) {
820 async_answer_0(req, ENOENT);
821 return;
824 rc = ops->node_open(fn);
825 aoff64_t size = ops->size_get(fn);
826 async_answer_4(req, rc, LOWER32(size), UPPER32(size),
827 ops->lnkcnt_get(fn),
828 (ops->is_file(fn) ? L_FILE : 0) |
829 (ops->is_directory(fn) ? L_DIRECTORY : 0));
831 (void) ops->node_put(fn);
834 static FIBRIL_MUTEX_INITIALIZE(instances_mutex);
835 static LIST_INITIALIZE(instances_list);
837 typedef struct {
838 service_id_t service_id;
839 link_t link;
840 void *data;
841 } fs_instance_t;
843 errno_t fs_instance_create(service_id_t service_id, void *data)
845 fs_instance_t *inst = malloc(sizeof(fs_instance_t));
846 if (!inst)
847 return ENOMEM;
849 link_initialize(&inst->link);
850 inst->service_id = service_id;
851 inst->data = data;
853 fibril_mutex_lock(&instances_mutex);
854 list_foreach(instances_list, link, fs_instance_t, cur) {
855 if (cur->service_id == service_id) {
856 fibril_mutex_unlock(&instances_mutex);
857 free(inst);
858 return EEXIST;
861 /* keep the list sorted */
862 if (cur->service_id < service_id) {
863 list_insert_before(&inst->link, &cur->link);
864 fibril_mutex_unlock(&instances_mutex);
865 return EOK;
868 list_append(&inst->link, &instances_list);
869 fibril_mutex_unlock(&instances_mutex);
871 return EOK;
874 errno_t fs_instance_get(service_id_t service_id, void **idp)
876 fibril_mutex_lock(&instances_mutex);
878 list_foreach(instances_list, link, fs_instance_t, inst) {
879 if (inst->service_id == service_id) {
880 *idp = inst->data;
881 fibril_mutex_unlock(&instances_mutex);
882 return EOK;
886 fibril_mutex_unlock(&instances_mutex);
887 return ENOENT;
890 errno_t fs_instance_destroy(service_id_t service_id)
892 fibril_mutex_lock(&instances_mutex);
894 list_foreach(instances_list, link, fs_instance_t, inst) {
895 if (inst->service_id == service_id) {
896 list_remove(&inst->link);
897 fibril_mutex_unlock(&instances_mutex);
898 free(inst);
899 return EOK;
903 fibril_mutex_unlock(&instances_mutex);
904 return ENOENT;
907 /** @}