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

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

Introduce vfs_link_path() and replace mkdir() with it

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