source: mainline/uspace/lib/fs/libfs.c@ 51774cd

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

Reintroduce aoff64_t file sizes into VFS

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