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

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

Prefer handle over ID in naming handle variables

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