source: mainline/uspace/lib/fs/libfs.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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