source: mainline/uspace/lib/fs/libfs.c@ 39c3b7f9

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

Add the FS name field to struct statfs

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