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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b5b5d84 was b5b5d84, checked in by Jakub Jermar <jakub@…>, 9 years ago

Rename statfs() to vfs_statfs_path() and provide relativized vfs_statfs()

  • 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 <sys/stat.h>
47#include <stdlib.h>
48#include <fibril_synch.h>
49#include <ipc/vfs.h>
50#include <vfs/vfs.h>
51
52#define on_error(rc, action) \
53 do { \
54 if ((rc) != EOK) \
55 action; \
56 } while (0)
57
58#define combine_rc(rc1, rc2) \
59 ((rc1) == EOK ? (rc2) : (rc1))
60
61#define answer_and_return(rid, rc) \
62 do { \
63 async_answer_0((rid), (rc)); \
64 return; \
65 } while (0)
66
67static fs_reg_t reg;
68
69static vfs_out_ops_t *vfs_out_ops = NULL;
70static libfs_ops_t *libfs_ops = NULL;
71
72static char fs_name[FS_NAME_MAXLEN + 1];
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 *);
81static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_callid_t,
82 ipc_call_t *);
83
84static void vfs_out_mounted(ipc_callid_t rid, ipc_call_t *req)
85{
86 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
87 char *opts;
88 int rc;
89
90 /* Accept the mount options. */
91 rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
92 if (rc != EOK) {
93 async_answer_0(rid, rc);
94 return;
95 }
96
97 fs_index_t index;
98 aoff64_t size;
99 unsigned lnkcnt;
100 rc = vfs_out_ops->mounted(service_id, opts, &index, &size, &lnkcnt);
101
102 if (rc == EOK)
103 async_answer_4(rid, EOK, index, LOWER32(size), UPPER32(size),
104 lnkcnt);
105 else
106 async_answer_0(rid, rc);
107
108 free(opts);
109}
110
111static void vfs_out_unmounted(ipc_callid_t rid, ipc_call_t *req)
112{
113 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
114 int rc;
115
116 rc = vfs_out_ops->unmounted(service_id);
117
118 async_answer_0(rid, rc);
119}
120
121static void vfs_out_link(ipc_callid_t rid, ipc_call_t *req)
122{
123 libfs_link(libfs_ops, reg.fs_handle, rid, req);
124}
125
126static void vfs_out_lookup(ipc_callid_t rid, ipc_call_t *req)
127{
128 libfs_lookup(libfs_ops, reg.fs_handle, rid, req);
129}
130
131static void vfs_out_read(ipc_callid_t rid, ipc_call_t *req)
132{
133 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
134 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
135 aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
136 IPC_GET_ARG4(*req));
137 size_t rbytes;
138 int rc;
139
140 rc = vfs_out_ops->read(service_id, index, pos, &rbytes);
141
142 if (rc == EOK)
143 async_answer_1(rid, EOK, rbytes);
144 else
145 async_answer_0(rid, rc);
146}
147
148static void vfs_out_write(ipc_callid_t rid, ipc_call_t *req)
149{
150 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
151 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
152 aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
153 IPC_GET_ARG4(*req));
154 size_t wbytes;
155 aoff64_t nsize;
156 int rc;
157
158 rc = vfs_out_ops->write(service_id, index, pos, &wbytes, &nsize);
159
160 if (rc == EOK) {
161 async_answer_3(rid, EOK, wbytes, LOWER32(nsize),
162 UPPER32(nsize));
163 } else
164 async_answer_0(rid, rc);
165}
166
167static void vfs_out_truncate(ipc_callid_t rid, ipc_call_t *req)
168{
169 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
170 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
171 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
172 IPC_GET_ARG4(*req));
173 int rc;
174
175 rc = vfs_out_ops->truncate(service_id, index, size);
176
177 async_answer_0(rid, rc);
178}
179
180static void vfs_out_close(ipc_callid_t rid, ipc_call_t *req)
181{
182 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
183 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
184 int rc;
185
186 rc = vfs_out_ops->close(service_id, index);
187
188 async_answer_0(rid, rc);
189}
190
191static void vfs_out_destroy(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
196 int rc;
197 fs_node_t *node = NULL;
198 rc = libfs_ops->node_get(&node, service_id, index);
199 if (rc == EOK && node != NULL) {
200 bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
201 libfs_ops->node_put(node);
202 if (destroy)
203 rc = vfs_out_ops->destroy(service_id, index);
204 }
205 async_answer_0(rid, rc);
206}
207
208static void vfs_out_open_node(ipc_callid_t rid, ipc_call_t *req)
209{
210 libfs_open_node(libfs_ops, reg.fs_handle, rid, req);
211}
212
213static void vfs_out_stat(ipc_callid_t rid, ipc_call_t *req)
214{
215 libfs_stat(libfs_ops, reg.fs_handle, rid, req);
216}
217
218static void vfs_out_sync(ipc_callid_t rid, ipc_call_t *req)
219{
220 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
221 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
222 int rc;
223
224 rc = vfs_out_ops->sync(service_id, index);
225
226 async_answer_0(rid, rc);
227}
228
229static void vfs_out_statfs(ipc_callid_t rid, ipc_call_t *req)
230{
231 libfs_statfs(libfs_ops, reg.fs_handle, rid, req);
232}
233
234static void vfs_out_get_size(ipc_callid_t rid, ipc_call_t *req)
235{
236 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
237 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
238 int rc;
239
240 fs_node_t *node = NULL;
241 rc = libfs_ops->node_get(&node, service_id, index);
242 if (rc != EOK)
243 async_answer_0(rid, rc);
244 if (node == NULL)
245 async_answer_0(rid, EINVAL);
246
247 uint64_t size = libfs_ops->size_get(node);
248 libfs_ops->node_put(node);
249
250 async_answer_2(rid, EOK, LOWER32(size), UPPER32(size));
251}
252
253static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req)
254{
255 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
256 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
257 int rc;
258
259 fs_node_t *node = NULL;
260 rc = libfs_ops->node_get(&node, service_id, index);
261 if (rc != EOK)
262 async_answer_0(rid, rc);
263 if (node == NULL)
264 async_answer_0(rid, EINVAL);
265
266 bool children = false;
267 rc = libfs_ops->has_children(&children, node);
268 libfs_ops->node_put(node);
269
270 if (rc != EOK)
271 async_answer_0(rid, rc);
272 async_answer_0(rid, children ? ENOTEMPTY : EOK);
273}
274
275static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg)
276{
277 if (iid) {
278 /*
279 * This only happens for connections opened by
280 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
281 * created by IPC_M_CONNECT_TO_ME.
282 */
283 async_answer_0(iid, EOK);
284 }
285
286 while (true) {
287 ipc_call_t call;
288 ipc_callid_t callid = async_get_call(&call);
289
290 if (!IPC_GET_IMETHOD(call))
291 return;
292
293 switch (IPC_GET_IMETHOD(call)) {
294 case VFS_OUT_MOUNTED:
295 vfs_out_mounted(callid, &call);
296 break;
297 case VFS_OUT_UNMOUNTED:
298 vfs_out_unmounted(callid, &call);
299 break;
300 case VFS_OUT_LINK:
301 vfs_out_link(callid, &call);
302 break;
303 case VFS_OUT_LOOKUP:
304 vfs_out_lookup(callid, &call);
305 break;
306 case VFS_OUT_READ:
307 vfs_out_read(callid, &call);
308 break;
309 case VFS_OUT_WRITE:
310 vfs_out_write(callid, &call);
311 break;
312 case VFS_OUT_TRUNCATE:
313 vfs_out_truncate(callid, &call);
314 break;
315 case VFS_OUT_CLOSE:
316 vfs_out_close(callid, &call);
317 break;
318 case VFS_OUT_DESTROY:
319 vfs_out_destroy(callid, &call);
320 break;
321 case VFS_OUT_OPEN_NODE:
322 vfs_out_open_node(callid, &call);
323 break;
324 case VFS_OUT_STAT:
325 vfs_out_stat(callid, &call);
326 break;
327 case VFS_OUT_SYNC:
328 vfs_out_sync(callid, &call);
329 break;
330 case VFS_OUT_STATFS:
331 vfs_out_statfs(callid, &call);
332 break;
333 case VFS_OUT_GET_SIZE:
334 vfs_out_get_size(callid, &call);
335 break;
336 case VFS_OUT_IS_EMPTY:
337 vfs_out_is_empty(callid, &call);
338 break;
339 default:
340 async_answer_0(callid, ENOTSUP);
341 break;
342 }
343 }
344}
345
346/** Register file system server.
347 *
348 * This function abstracts away the tedious registration protocol from
349 * file system implementations and lets them to reuse this registration glue
350 * code.
351 *
352 * @param sess Session for communication with VFS.
353 * @param info VFS info structure supplied by the file system
354 * implementation.
355 * @param vops Address of the vfs_out_ops_t structure.
356 * @param lops Address of the libfs_ops_t structure.
357 *
358 * @return EOK on success or a non-zero error code on errror.
359 *
360 */
361int fs_register(async_sess_t *sess, vfs_info_t *info, vfs_out_ops_t *vops,
362 libfs_ops_t *lops)
363{
364 /*
365 * Tell VFS that we are here and want to get registered.
366 * We use the async framework because VFS will answer the request
367 * out-of-order, when it knows that the operation succeeded or failed.
368 */
369
370 async_exch_t *exch = async_exchange_begin(sess);
371
372 ipc_call_t answer;
373 aid_t req = async_send_0(exch, VFS_IN_REGISTER, &answer);
374
375 /*
376 * Send our VFS info structure to VFS.
377 */
378 int rc = async_data_write_start(exch, info, sizeof(*info));
379
380 if (rc != EOK) {
381 async_exchange_end(exch);
382 async_forget(req);
383 return rc;
384 }
385
386 /*
387 * Set VFS_OUT and libfs operations.
388 */
389 vfs_out_ops = vops;
390 libfs_ops = lops;
391
392 str_cpy(fs_name, sizeof(fs_name), info->name);
393
394 /*
395 * Ask VFS for callback connection.
396 */
397 port_id_t port;
398 rc = async_create_callback_port(exch, INTERFACE_VFS_DRIVER_CB, 0, 0,
399 vfs_connection, NULL, &port);
400
401 /*
402 * Request sharing the Path Lookup Buffer with VFS.
403 */
404 rc = async_share_in_start_0_0(exch, PLB_SIZE, (void *) &reg.plb_ro);
405 if (reg.plb_ro == AS_MAP_FAILED) {
406 async_exchange_end(exch);
407 async_forget(req);
408 return ENOMEM;
409 }
410
411 async_exchange_end(exch);
412
413 if (rc) {
414 async_forget(req);
415 return rc;
416 }
417
418 /*
419 * Pick up the answer for the request to the VFS_IN_REQUEST call.
420 */
421 async_wait_for(req, NULL);
422 reg.fs_handle = (int) IPC_GET_ARG1(answer);
423
424 /*
425 * Tell the async framework that other connections are to be handled by
426 * the same connection fibril as well.
427 */
428 async_set_fallback_port_handler(vfs_connection, NULL);
429
430 return IPC_GET_RETVAL(answer);
431}
432
433void fs_node_initialize(fs_node_t *fn)
434{
435 memset(fn, 0, sizeof(fs_node_t));
436}
437
438static char plb_get_char(unsigned pos)
439{
440 return reg.plb_ro[pos % PLB_SIZE];
441}
442
443static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos,
444 unsigned last)
445{
446 unsigned pos = *ppos;
447 unsigned size = 0;
448
449 if (pos == last) {
450 *sz = 0;
451 return ERANGE;
452 }
453
454 char c = plb_get_char(pos);
455 if (c == '/')
456 pos++;
457
458 for (int i = 0; i <= NAME_MAX; i++) {
459 c = plb_get_char(pos);
460 if (pos == last || c == '/') {
461 dest[i] = 0;
462 *ppos = pos;
463 *sz = size;
464 return EOK;
465 }
466 dest[i] = c;
467 pos++;
468 size++;
469 }
470 return ENAMETOOLONG;
471}
472
473static int receive_fname(char *buffer)
474{
475 size_t size;
476 ipc_callid_t wcall;
477
478 if (!async_data_write_receive(&wcall, &size))
479 return ENOENT;
480 if (size > NAME_MAX + 1) {
481 async_answer_0(wcall, ERANGE);
482 return ERANGE;
483 }
484 return async_data_write_finalize(wcall, buffer, size);
485}
486
487/** Link a file at a path.
488 */
489void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
490 ipc_call_t *req)
491{
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);
495
496 char component[NAME_MAX + 1];
497 int rc = receive_fname(component);
498 if (rc != EOK) {
499 async_answer_0(rid, rc);
500 return;
501 }
502
503 fs_node_t *parent = NULL;
504 rc = ops->node_get(&parent, parent_sid, parent_index);
505 if (parent == NULL) {
506 async_answer_0(rid, rc == EOK ? EBADF : rc);
507 return;
508 }
509
510 fs_node_t *child = NULL;
511 rc = ops->node_get(&child, parent_sid, child_index);
512 if (child == NULL) {
513 async_answer_0(rid, rc == EOK ? EBADF : rc);
514 ops->node_put(parent);
515 return;
516 }
517
518 rc = ops->link(parent, child, component);
519 ops->node_put(parent);
520 ops->node_put(child);
521 async_answer_0(rid, rc);
522}
523
524/** Lookup VFS triplet by name in the file system name space.
525 *
526 * The path passed in the PLB must be in the canonical file system path format
527 * as returned by the canonify() function.
528 *
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 rid Request ID of the VFS_OUT_LOOKUP request.
534 * @param request VFS_OUT_LOOKUP request data itself.
535 *
536 */
537void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
538 ipc_call_t *req)
539{
540 unsigned first = IPC_GET_ARG1(*req);
541 unsigned len = IPC_GET_ARG2(*req);
542 service_id_t service_id = IPC_GET_ARG3(*req);
543 fs_index_t index = IPC_GET_ARG4(*req);
544 int lflag = IPC_GET_ARG5(*req);
545
546 assert((int) index != -1);
547
548 // TODO: Validate flags.
549
550 unsigned next = first;
551 unsigned last = first + len;
552
553 char component[NAME_MAX + 1];
554 int rc;
555
556 fs_node_t *par = NULL;
557 fs_node_t *cur = NULL;
558 fs_node_t *tmp = NULL;
559 unsigned clen = 0;
560
561 rc = ops->node_get(&cur, service_id, index);
562 if (rc != EOK) {
563 async_answer_0(rid, rc);
564 goto out;
565 }
566
567 assert(cur != NULL);
568
569 /* Find the file and its parent. */
570
571 unsigned last_next = 0;
572
573 while (next != last) {
574 if (cur == NULL) {
575 assert(par != NULL);
576 goto out1;
577 }
578
579 if (!ops->is_directory(cur)) {
580 async_answer_0(rid, ENOTDIR);
581 goto out;
582 }
583
584 last_next = next;
585 /* Collect the component */
586 rc = plb_get_component(component, &clen, &next, last);
587 assert(rc != ERANGE);
588 if (rc != EOK) {
589 async_answer_0(rid, rc);
590 goto out;
591 }
592
593 if (clen == 0) {
594 /* The path is just "/". */
595 break;
596 }
597
598 assert(component[clen] == 0);
599
600 /* Match the component */
601 rc = ops->match(&tmp, cur, component);
602 if (rc != EOK) {
603 async_answer_0(rid, rc);
604 goto out;
605 }
606
607 /* Descend one level */
608 if (par) {
609 rc = ops->node_put(par);
610 if (rc != EOK) {
611 async_answer_0(rid, rc);
612 goto out;
613 }
614 }
615
616 par = cur;
617 cur = tmp;
618 tmp = NULL;
619 }
620
621 /* At this point, par is either NULL or a directory.
622 * If cur is NULL, the looked up file does not exist yet.
623 */
624
625 assert(par == NULL || ops->is_directory(par));
626 assert(par != NULL || cur != NULL);
627
628 /* Check for some error conditions. */
629
630 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
631 async_answer_0(rid, EISDIR);
632 goto out;
633 }
634
635 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
636 async_answer_0(rid, ENOTDIR);
637 goto out;
638 }
639
640 /* Unlink. */
641
642 if (lflag & L_UNLINK) {
643 if (!cur) {
644 async_answer_0(rid, ENOENT);
645 goto out;
646 }
647 if (!par) {
648 async_answer_0(rid, EINVAL);
649 goto out;
650 }
651
652 rc = ops->unlink(par, cur, component);
653 if (rc == EOK) {
654 int64_t size = ops->size_get(cur);
655 int32_t lsize = LOWER32(size);
656 if (lsize != size)
657 lsize = -1;
658
659 async_answer_5(rid, fs_handle, service_id,
660 ops->index_get(cur), last, lsize,
661 ops->is_directory(cur));
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, fs_handle, service_id, ops->index_get(par),
702 last_next, -1, true);
703 goto out;
704 }
705
706 int64_t size = ops->size_get(cur);
707 int32_t lsize = LOWER32(size);
708 if (lsize != size)
709 lsize = -1;
710
711 async_answer_5(rid, fs_handle, service_id, ops->index_get(cur), last,
712 lsize, ops->is_directory(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, ipc_callid_t rid,
726 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 int rc = ops->node_get(&fn, service_id, index);
733 on_error(rc, answer_and_return(rid, rc));
734
735 ipc_callid_t callid;
736 size_t size;
737 if ((!async_data_read_receive(&callid, &size)) ||
738 (size != sizeof(struct stat))) {
739 ops->node_put(fn);
740 async_answer_0(callid, EINVAL);
741 async_answer_0(rid, EINVAL);
742 return;
743 }
744
745 struct stat stat;
746 memset(&stat, 0, sizeof(struct stat));
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(callid, &stat, sizeof(struct stat));
761 async_answer_0(rid, EOK);
762}
763
764void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
765 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 int rc = ops->node_get(&fn, service_id, index);
772 on_error(rc, answer_and_return(rid, rc));
773
774 ipc_callid_t callid;
775 size_t size;
776 if ((!async_data_read_receive(&callid, &size)) ||
777 (size != sizeof(struct statfs))) {
778 goto error;
779 }
780
781 struct statfs st;
782 memset(&st, 0, sizeof(struct statfs));
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(callid, &st, sizeof(struct statfs));
806 async_answer_0(rid, EOK);
807 return;
808
809error:
810 ops->node_put(fn);
811 async_answer_0(callid, EINVAL);
812 async_answer_0(rid, 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 rid Request ID 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, ipc_callid_t rid,
825 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 int rc = ops->node_get(&fn, service_id, index);
832 on_error(rc, answer_and_return(rid, rc));
833
834 if (fn == NULL) {
835 async_answer_0(rid, ENOENT);
836 return;
837 }
838
839 rc = ops->node_open(fn);
840 aoff64_t size = ops->size_get(fn);
841 async_answer_4(rid, 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
858int 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
889int 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
903int 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.