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

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

Fix block comment formatting (ccheck).

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