source: mainline/uspace/lib/fs/libfs.c@ 1dff985

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

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5 up to revision 1926

  • Property mode set to 100644
File size: 21.6 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 <sys/stat.h>
46#include <sys/statfs.h>
47#include <stdlib.h>
48#include <fibril_synch.h>
49
50#define on_error(rc, action) \
51 do { \
52 if ((rc) != EOK) \
53 action; \
54 } while (0)
55
56#define combine_rc(rc1, rc2) \
57 ((rc1) == EOK ? (rc2) : (rc1))
58
59#define answer_and_return(rid, rc) \
60 do { \
61 async_answer_0((rid), (rc)); \
62 return; \
63 } while (0)
64
65#define DPRINTF(...)
66
67#define LOG_EXIT(rc) \
68 DPRINTF("Exiting %s() with rc = %d at line %d\n", __FUNC__, rc, __LINE__);
69
70static fs_reg_t reg;
71
72static vfs_out_ops_t *vfs_out_ops = NULL;
73static libfs_ops_t *libfs_ops = NULL;
74
75static void libfs_link(libfs_ops_t *, fs_handle_t, ipc_callid_t,
76 ipc_call_t *);
77static void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t,
78 ipc_call_t *);
79static void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
80static void libfs_open_node(libfs_ops_t *, fs_handle_t, ipc_callid_t,
81 ipc_call_t *);
82static void libfs_statfs(libfs_ops_t *, fs_handle_t, ipc_callid_t, 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), UPPER32(nsize));
162 else
163 async_answer_0(rid, rc);
164}
165
166static void vfs_out_truncate(ipc_callid_t rid, ipc_call_t *req)
167{
168 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
169 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
170 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*req),
171 IPC_GET_ARG4(*req));
172 int rc;
173
174 rc = vfs_out_ops->truncate(service_id, index, size);
175
176 async_answer_0(rid, rc);
177}
178
179static void vfs_out_close(ipc_callid_t rid, ipc_call_t *req)
180{
181 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
182 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
183 int rc;
184
185 rc = vfs_out_ops->close(service_id, index);
186
187 async_answer_0(rid, rc);
188}
189
190static void vfs_out_destroy(ipc_callid_t rid, ipc_call_t *req)
191{
192 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*req);
193 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*req);
194
195 int rc;
196 fs_node_t *node = NULL;
197 rc = libfs_ops->node_get(&node, service_id, index);
198 if (rc == EOK && node != NULL) {
199 bool destroy = (libfs_ops->lnkcnt_get(node) == 0);
200 libfs_ops->node_put(node);
201 if (destroy) {
202 rc = vfs_out_ops->destroy(service_id, index);
203 }
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 }
245 if (node == NULL) {
246 async_answer_0(rid, EINVAL);
247 }
248
249 uint64_t size = libfs_ops->size_get(node);
250 libfs_ops->node_put(node);
251
252 async_answer_2(rid, EOK, LOWER32(size), UPPER32(size));
253}
254
255static void vfs_out_is_empty(ipc_callid_t rid, ipc_call_t *req)
256{
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 int rc;
260
261 fs_node_t *node = NULL;
262 rc = libfs_ops->node_get(&node, service_id, index);
263 if (rc != EOK) {
264 async_answer_0(rid, rc);
265 }
266 if (node == NULL) {
267 async_answer_0(rid, EINVAL);
268 }
269
270 bool children = false;
271 rc = libfs_ops->has_children(&children, node);
272 libfs_ops->node_put(node);
273
274 if (rc != EOK) {
275 async_answer_0(rid, rc);
276 }
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_MOUNTED:
300 vfs_out_mounted(callid, &call);
301 break;
302 case VFS_OUT_UNMOUNTED:
303 vfs_out_unmounted(callid, &call);
304 break;
305 case VFS_OUT_LINK:
306 vfs_out_link(callid, &call);
307 break;
308 case VFS_OUT_LOOKUP:
309 vfs_out_lookup(callid, &call);
310 break;
311 case VFS_OUT_READ:
312 vfs_out_read(callid, &call);
313 break;
314 case VFS_OUT_WRITE:
315 vfs_out_write(callid, &call);
316 break;
317 case VFS_OUT_TRUNCATE:
318 vfs_out_truncate(callid, &call);
319 break;
320 case VFS_OUT_CLOSE:
321 vfs_out_close(callid, &call);
322 break;
323 case VFS_OUT_DESTROY:
324 vfs_out_destroy(callid, &call);
325 break;
326 case VFS_OUT_OPEN_NODE:
327 vfs_out_open_node(callid, &call);
328 break;
329 case VFS_OUT_STAT:
330 vfs_out_stat(callid, &call);
331 break;
332 case VFS_OUT_SYNC:
333 vfs_out_sync(callid, &call);
334 break;
335 case VFS_OUT_STATFS:
336 vfs_out_statfs(callid, &call);
337 break;
338 case VFS_OUT_GET_SIZE:
339 vfs_out_get_size(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 */
366int 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 int 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 /*
398 * Ask VFS for callback connection.
399 */
400 port_id_t port;
401 rc = async_create_callback_port(exch, INTERFACE_VFS_DRIVER_CB, 0, 0,
402 vfs_connection, NULL, &port);
403
404 /*
405 * Request sharing the Path Lookup Buffer with VFS.
406 */
407 rc = async_share_in_start_0_0(exch, PLB_SIZE, (void *) &reg.plb_ro);
408 if (reg.plb_ro == AS_MAP_FAILED) {
409 async_exchange_end(exch);
410 async_forget(req);
411 return ENOMEM;
412 }
413
414 async_exchange_end(exch);
415
416 if (rc) {
417 async_forget(req);
418 return rc;
419 }
420
421 /*
422 * Pick up the answer for the request to the VFS_IN_REQUEST call.
423 */
424 async_wait_for(req, NULL);
425 reg.fs_handle = (int) IPC_GET_ARG1(answer);
426
427 /*
428 * Tell the async framework that other connections are to be handled by
429 * the same connection fibril as well.
430 */
431 async_set_fallback_port_handler(vfs_connection, NULL);
432
433 return IPC_GET_RETVAL(answer);
434}
435
436void fs_node_initialize(fs_node_t *fn)
437{
438 memset(fn, 0, sizeof(fs_node_t));
439}
440
441static char plb_get_char(unsigned pos)
442{
443 return reg.plb_ro[pos % PLB_SIZE];
444}
445
446static int plb_get_component(char *dest, unsigned *sz, unsigned *ppos, unsigned last)
447{
448 unsigned pos = *ppos;
449 unsigned size = 0;
450
451 if (pos == last) {
452 *sz = 0;
453 return ERANGE;
454 }
455
456 char c = plb_get_char(pos);
457 if (c == '/') {
458 pos++;
459 }
460
461 for (int i = 0; i <= NAME_MAX; i++) {
462 c = plb_get_char(pos);
463 if (pos == last || c == '/') {
464 dest[i] = 0;
465 *ppos = pos;
466 *sz = size;
467 return EOK;
468 }
469 dest[i] = c;
470 pos++;
471 size++;
472 }
473 return ENAMETOOLONG;
474}
475
476static int receive_fname(char *buffer)
477{
478 size_t size;
479 ipc_callid_t wcall;
480
481 if (!async_data_write_receive(&wcall, &size)) {
482 return ENOENT;
483 }
484 if (size > NAME_MAX + 1) {
485 async_answer_0(wcall, ERANGE);
486 return ERANGE;
487 }
488 return async_data_write_finalize(wcall, buffer, size);
489}
490
491/** Link a file at a path.
492 */
493void libfs_link(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid, ipc_call_t *req)
494{
495 service_id_t parent_sid = IPC_GET_ARG1(*req);
496 fs_index_t parent_index = IPC_GET_ARG2(*req);
497 fs_index_t child_index = IPC_GET_ARG3(*req);
498
499 char component[NAME_MAX + 1];
500 int rc = receive_fname(component);
501 if (rc != EOK) {
502 async_answer_0(rid, rc);
503 return;
504 }
505
506 fs_node_t *parent = NULL;
507 rc = ops->node_get(&parent, parent_sid, parent_index);
508 if (parent == NULL) {
509 async_answer_0(rid, rc == EOK ? EBADF : rc);
510 return;
511 }
512
513 fs_node_t *child = NULL;
514 rc = ops->node_get(&child, parent_sid, child_index);
515 if (child == NULL) {
516 async_answer_0(rid, rc == EOK ? EBADF : rc);
517 ops->node_put(parent);
518 return;
519 }
520
521 rc = ops->link(parent, child, component);
522 ops->node_put(parent);
523 ops->node_put(child);
524 async_answer_0(rid, rc);
525}
526
527/** Lookup VFS triplet by name in the file system name space.
528 *
529 * The path passed in the PLB must be in the canonical file system path format
530 * as returned by the canonify() function.
531 *
532 * @param ops libfs operations structure with function pointers to
533 * file system implementation
534 * @param fs_handle File system handle of the file system where to perform
535 * the lookup.
536 * @param rid Request ID of the VFS_OUT_LOOKUP request.
537 * @param request VFS_OUT_LOOKUP request data itself.
538 *
539 */
540void libfs_lookup(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
541 ipc_call_t *req)
542{
543 unsigned first = IPC_GET_ARG1(*req);
544 unsigned len = IPC_GET_ARG2(*req);
545 service_id_t service_id = IPC_GET_ARG3(*req);
546 fs_index_t index = IPC_GET_ARG4(*req);
547 int lflag = IPC_GET_ARG5(*req);
548
549 assert((int) index != -1);
550
551 DPRINTF("Entered libfs_lookup()\n");
552
553 // TODO: Validate flags.
554
555 unsigned next = first;
556 unsigned last = first + len;
557
558 char component[NAME_MAX + 1];
559 int rc;
560
561 fs_node_t *par = NULL;
562 fs_node_t *cur = NULL;
563 fs_node_t *tmp = NULL;
564 unsigned clen = 0;
565
566 rc = ops->node_get(&cur, service_id, index);
567 if (rc != EOK) {
568 async_answer_0(rid, rc);
569 LOG_EXIT(rc);
570 goto out;
571 }
572
573 assert(cur != NULL);
574
575 /* Find the file and its parent. */
576
577 unsigned last_next = 0;
578
579 while (next != last) {
580 if (cur == NULL) {
581 assert(par != NULL);
582 goto out1;
583 }
584
585 if (!ops->is_directory(cur)) {
586 async_answer_0(rid, ENOTDIR);
587 LOG_EXIT(ENOTDIR);
588 goto out;
589 }
590
591 last_next = next;
592 /* Collect the component */
593 rc = plb_get_component(component, &clen, &next, last);
594 assert(rc != ERANGE);
595 if (rc != EOK) {
596 async_answer_0(rid, rc);
597 LOG_EXIT(rc);
598 goto out;
599 }
600
601 if (clen == 0) {
602 /* The path is just "/". */
603 break;
604 }
605
606 assert(component[clen] == 0);
607
608 /* Match the component */
609 rc = ops->match(&tmp, cur, component);
610 if (rc != EOK) {
611 async_answer_0(rid, rc);
612 LOG_EXIT(rc);
613 goto out;
614 }
615
616 /* Descend one level */
617 if (par) {
618 rc = ops->node_put(par);
619 if (rc != EOK) {
620 async_answer_0(rid, rc);
621 LOG_EXIT(rc);
622 goto out;
623 }
624 }
625
626 par = cur;
627 cur = tmp;
628 tmp = NULL;
629 }
630
631 /* At this point, par is either NULL or a directory.
632 * If cur is NULL, the looked up file does not exist yet.
633 */
634
635 assert(par == NULL || ops->is_directory(par));
636 assert(par != NULL || cur != NULL);
637
638 /* Check for some error conditions. */
639
640 if (cur && (lflag & L_FILE) && (ops->is_directory(cur))) {
641 async_answer_0(rid, EISDIR);
642 LOG_EXIT(EISDIR);
643 goto out;
644 }
645
646 if (cur && (lflag & L_DIRECTORY) && (ops->is_file(cur))) {
647 async_answer_0(rid, ENOTDIR);
648 LOG_EXIT(ENOTDIR);
649 goto out;
650 }
651
652 /* Unlink. */
653
654 if (lflag & L_UNLINK) {
655 if (!cur) {
656 async_answer_0(rid, ENOENT);
657 LOG_EXIT(ENOENT);
658 goto out;
659 }
660 if (!par) {
661 async_answer_0(rid, EINVAL);
662 LOG_EXIT(EINVAL);
663 goto out;
664 }
665
666 rc = ops->unlink(par, cur, component);
667 if (rc == EOK) {
668 int64_t size = ops->size_get(cur);
669 int32_t lsize = LOWER32(size);
670 if (lsize != size) {
671 lsize = -1;
672 }
673
674 async_answer_5(rid, fs_handle, service_id,
675 ops->index_get(cur), last, lsize,
676 ops->is_directory(cur));
677 LOG_EXIT(EOK);
678 } else {
679 async_answer_0(rid, rc);
680 LOG_EXIT(rc);
681 }
682 goto out;
683 }
684
685 /* Create. */
686
687 if (lflag & L_CREATE) {
688 if (cur && (lflag & L_EXCLUSIVE)) {
689 async_answer_0(rid, EEXIST);
690 LOG_EXIT(EEXIST);
691 goto out;
692 }
693
694 if (!cur) {
695 rc = ops->create(&cur, service_id, lflag & (L_FILE|L_DIRECTORY));
696 if (rc != EOK) {
697 async_answer_0(rid, rc);
698 LOG_EXIT(rc);
699 goto out;
700 }
701 if (!cur) {
702 async_answer_0(rid, ENOSPC);
703 LOG_EXIT(ENOSPC);
704 goto out;
705 }
706
707 rc = ops->link(par, cur, component);
708 if (rc != EOK) {
709 (void) ops->destroy(cur);
710 cur = NULL;
711 async_answer_0(rid, rc);
712 LOG_EXIT(rc);
713 goto out;
714 }
715 }
716 }
717
718 /* Return. */
719out1:
720 if (!cur) {
721 async_answer_5(rid, fs_handle, service_id,
722 ops->index_get(par), last_next, -1, true);
723 LOG_EXIT(EOK);
724 goto out;
725 }
726
727 if (lflag & L_OPEN) {
728 rc = ops->node_open(cur);
729 if (rc != EOK) {
730 async_answer_0(rid, rc);
731 LOG_EXIT(rc);
732 goto out;
733 }
734 }
735
736 int64_t size = ops->size_get(cur);
737 int32_t lsize = LOWER32(size);
738 if (lsize != size) {
739 lsize = -1;
740 }
741
742 async_answer_5(rid, fs_handle, service_id, ops->index_get(cur), last,
743 lsize, ops->is_directory(cur));
744
745 LOG_EXIT(EOK);
746out:
747 if (par) {
748 (void) ops->node_put(par);
749 }
750
751 if (cur) {
752 (void) ops->node_put(cur);
753 }
754
755 if (tmp) {
756 (void) ops->node_put(tmp);
757 }
758}
759
760void libfs_stat(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
761 ipc_call_t *request)
762{
763 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
764 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
765
766 fs_node_t *fn;
767 int rc = ops->node_get(&fn, service_id, index);
768 on_error(rc, answer_and_return(rid, rc));
769
770 ipc_callid_t callid;
771 size_t size;
772 if ((!async_data_read_receive(&callid, &size)) ||
773 (size != sizeof(struct stat))) {
774 ops->node_put(fn);
775 async_answer_0(callid, EINVAL);
776 async_answer_0(rid, EINVAL);
777 return;
778 }
779
780 struct stat stat;
781 memset(&stat, 0, sizeof(struct stat));
782
783 stat.fs_handle = fs_handle;
784 stat.service_id = service_id;
785 stat.index = index;
786 stat.lnkcnt = ops->lnkcnt_get(fn);
787 stat.is_file = ops->is_file(fn);
788 stat.is_directory = ops->is_directory(fn);
789 stat.size = ops->size_get(fn);
790 stat.service = ops->service_get(fn);
791
792 ops->node_put(fn);
793
794
795 async_data_read_finalize(callid, &stat, sizeof(struct stat));
796 async_answer_0(rid, EOK);
797}
798
799void libfs_statfs(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
800 ipc_call_t *request)
801{
802 service_id_t service_id = (service_id_t) IPC_GET_ARG1(*request);
803 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
804
805 fs_node_t *fn;
806 int rc = ops->node_get(&fn, service_id, index);
807 on_error(rc, answer_and_return(rid, rc));
808
809 ipc_callid_t callid;
810 size_t size;
811 if ((!async_data_read_receive(&callid, &size)) ||
812 (size != sizeof(struct statfs))) {
813 goto error;
814 }
815
816 struct statfs st;
817 memset(&st, 0, sizeof(struct statfs));
818
819 if (ops->size_block != NULL) {
820 rc = ops->size_block(service_id, &st.f_bsize);
821 if (rc != EOK)
822 goto error;
823 }
824
825 if (ops->total_block_count != NULL) {
826 rc = ops->total_block_count(service_id, &st.f_blocks);
827 if (rc != EOK)
828 goto error;
829 }
830
831 if (ops->free_block_count != NULL) {
832 rc = ops->free_block_count(service_id, &st.f_bfree);
833 if (rc != EOK)
834 goto error;
835 }
836
837 ops->node_put(fn);
838 async_data_read_finalize(callid, &st, sizeof(struct statfs));
839 async_answer_0(rid, EOK);
840 return;
841
842error:
843 ops->node_put(fn);
844 async_answer_0(callid, EINVAL);
845 async_answer_0(rid, EINVAL);
846}
847
848
849/** Open VFS triplet.
850 *
851 * @param ops libfs operations structure with function pointers to
852 * file system implementation
853 * @param rid Request ID of the VFS_OUT_OPEN_NODE request.
854 * @param request VFS_OUT_OPEN_NODE request data itself.
855 *
856 */
857void libfs_open_node(libfs_ops_t *ops, fs_handle_t fs_handle, ipc_callid_t rid,
858 ipc_call_t *request)
859{
860 service_id_t service_id = IPC_GET_ARG1(*request);
861 fs_index_t index = IPC_GET_ARG2(*request);
862
863 fs_node_t *fn;
864 int rc = ops->node_get(&fn, service_id, index);
865 on_error(rc, answer_and_return(rid, rc));
866
867 if (fn == NULL) {
868 async_answer_0(rid, ENOENT);
869 return;
870 }
871
872 rc = ops->node_open(fn);
873 aoff64_t size = ops->size_get(fn);
874 async_answer_4(rid, rc, LOWER32(size), UPPER32(size),
875 ops->lnkcnt_get(fn),
876 (ops->is_file(fn) ? L_FILE : 0) | (ops->is_directory(fn) ? L_DIRECTORY : 0));
877
878 (void) ops->node_put(fn);
879}
880
881static FIBRIL_MUTEX_INITIALIZE(instances_mutex);
882static LIST_INITIALIZE(instances_list);
883
884typedef struct {
885 service_id_t service_id;
886 link_t link;
887 void *data;
888} fs_instance_t;
889
890int fs_instance_create(service_id_t service_id, void *data)
891{
892 fs_instance_t *inst = malloc(sizeof(fs_instance_t));
893 if (!inst)
894 return ENOMEM;
895
896 link_initialize(&inst->link);
897 inst->service_id = service_id;
898 inst->data = data;
899
900 fibril_mutex_lock(&instances_mutex);
901 list_foreach(instances_list, link, fs_instance_t, cur) {
902 if (cur->service_id == service_id) {
903 fibril_mutex_unlock(&instances_mutex);
904 free(inst);
905 return EEXIST;
906 }
907
908 /* keep the list sorted */
909 if (cur->service_id < service_id) {
910 list_insert_before(&inst->link, &cur->link);
911 fibril_mutex_unlock(&instances_mutex);
912 return EOK;
913 }
914 }
915 list_append(&inst->link, &instances_list);
916 fibril_mutex_unlock(&instances_mutex);
917
918 return EOK;
919}
920
921int fs_instance_get(service_id_t service_id, void **idp)
922{
923 fibril_mutex_lock(&instances_mutex);
924 list_foreach(instances_list, link, fs_instance_t, inst) {
925 if (inst->service_id == service_id) {
926 *idp = inst->data;
927 fibril_mutex_unlock(&instances_mutex);
928 return EOK;
929 }
930 }
931 fibril_mutex_unlock(&instances_mutex);
932 return ENOENT;
933}
934
935int fs_instance_destroy(service_id_t service_id)
936{
937 fibril_mutex_lock(&instances_mutex);
938 list_foreach(instances_list, link, fs_instance_t, inst) {
939 if (inst->service_id == service_id) {
940 list_remove(&inst->link);
941 fibril_mutex_unlock(&instances_mutex);
942 free(inst);
943 return EOK;
944 }
945 }
946 fibril_mutex_unlock(&instances_mutex);
947 return ENOENT;
948}
949
950/** @}
951 */
Note: See TracBrowser for help on using the repository browser.