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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1e4a937 was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

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