source: mainline/uspace/lib/fs/libfs.c@ 8d2dd7f2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8d2dd7f2 was d2c8533, checked in by Jiri Svoboda <jiri@…>, 9 years ago

File system probing groundwork. Only MFS can do it for now.

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