source: mainline/uspace/srv/vfs/vfs_ops.c@ 5126f80

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

Merge from lp:~zarevucky-jiri/helenos/vfs-2.5/ revision 1946

Original commit messages:

1946: Jiri Zarevucky 2013-08-06 Relativize mount, add root handle to libc and remove root from VFS server. This wraps up the "relativization" phase.

Breakage:

  • Dynamic builds broken
  • Mount table lookups by name
  • Property mode set to 100644
File size: 29.3 KB
RevLine 
[861e7d1]1/*
2 * Copyright (c) 2008 Jakub Jermar
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
29/** @addtogroup fs
30 * @{
[8dc72b64]31 */
[861e7d1]32
33/**
[8dc72b64]34 * @file vfs_ops.c
35 * @brief Operations that VFS offers to its clients.
[861e7d1]36 */
37
[a8e9ab8d]38#include "vfs.h"
[ed903174]39#include <macros.h>
[9539be6]40#include <stdint.h>
[861e7d1]41#include <async.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
[19f857a]45#include <str.h>
[3e6a98c5]46#include <stdbool.h>
[1e4cada]47#include <fibril_synch.h>
[d9c8c81]48#include <adt/list.h>
[861e7d1]49#include <unistd.h>
50#include <ctype.h>
[2db4ac8]51#include <fcntl.h>
[861e7d1]52#include <assert.h>
[a8e9ab8d]53#include <vfs/canonify.h>
[10e4cd7]54#include <vfs/vfs_mtab.h>
55
56FIBRIL_MUTEX_INITIALIZE(mtab_list_lock);
57LIST_INITIALIZE(mtab_list);
58static size_t mtab_size = 0;
[861e7d1]59
[7fe1f75]60/* Forward declarations of static functions. */
[15f3c3f]61static int vfs_truncate_internal(fs_handle_t, service_id_t, fs_index_t,
[8df8415]62 aoff64_t);
[7fe1f75]63
[861e7d1]64/**
65 * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
66 * concurrent VFS operation which modifies the file system namespace.
67 */
[230260ac]68FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
[861e7d1]69
[4636a60]70static int vfs_connect_internal(service_id_t service_id, unsigned flags, unsigned instance,
[5126f80]71 char *options, char *fsname, vfs_node_t **root)
[861e7d1]72{
[4636a60]73 fs_handle_t fs_handle = 0;
[05b9912]74
[4636a60]75 fibril_mutex_lock(&fs_list_lock);
76 while (1) {
77 fs_handle = fs_name_to_handle(instance, fsname, false);
[8dc72b64]78
[5126f80]79 if (fs_handle != 0 || !(flags & VFS_MOUNT_BLOCKING)) {
[4636a60]80 break;
[861e7d1]81 }
[8dc72b64]82
[4636a60]83 fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
84 }
85 fibril_mutex_unlock(&fs_list_lock);
86
87 if (fs_handle == 0) {
88 return ENOENT;
[5bcd5b7]89 }
90
[4636a60]91 /* Tell the mountee that it is being mounted. */
92 ipc_call_t answer;
93 async_exch_t *exch = vfs_exchange_grab(fs_handle);
94 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id, &answer);
95 /* Send the mount options */
96 sysarg_t rc = async_data_write_start(exch, options, str_size(options));
97 if (rc != EOK) {
98 async_forget(msg);
99 vfs_exchange_release(exch);
100 return rc;
[5bcd5b7]101 }
[4636a60]102 async_wait_for(msg, &rc);
103 vfs_exchange_release(exch);
[5bcd5b7]104
[4636a60]105 if (rc != EOK) {
106 return rc;
[5bcd5b7]107 }
108
[4636a60]109 vfs_lookup_res_t res;
110 res.triplet.fs_handle = fs_handle;
111 res.triplet.service_id = service_id;
112 res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer);
113 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer), IPC_GET_ARG3(answer));
114 res.type = VFS_NODE_DIRECTORY;
[5bcd5b7]115
[4636a60]116 /* Add reference to the mounted root. */
117 *root = vfs_node_get(&res);
118 assert(*root);
[8dc72b64]119
[4636a60]120 return EOK;
[5bcd5b7]121}
122
[6afc9d7]123void vfs_mount_srv(ipc_callid_t rid, ipc_call_t *request)
[8dc72b64]124{
[5126f80]125 int mpfd = IPC_GET_ARG1(*request);
126
[8dc72b64]127 /*
128 * We expect the library to do the device-name to device-handle
129 * translation for us, thus the device handle will arrive as ARG1
130 * in the request.
131 */
[5126f80]132 service_id_t service_id = (service_id_t) IPC_GET_ARG2(*request);
[8dc72b64]133
134 /*
135 * Mount flags are passed as ARG2.
136 */
[5126f80]137 unsigned int flags = (unsigned int) IPC_GET_ARG3(*request);
[8dc72b64]138
[4979403]139 /*
140 * Instance number is passed as ARG3.
141 */
[5126f80]142 unsigned int instance = IPC_GET_ARG4(*request);
[8dc72b64]143
[5126f80]144 char *opts = NULL;
145 char *fs_name = NULL;
146 vfs_file_t *mp = NULL;
147 vfs_file_t *file = NULL;
148 int fd = -1;
149 mtab_ent_t *mtab_ent = NULL;
150
[594303b]151 /* Now we expect to receive the mount options. */
[5126f80]152 int rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,
[eda925a]153 0, NULL);
[472c09d]154 if (rc != EOK) {
[5126f80]155 async_data_write_void(rc);
156 goto out;
[594303b]157 }
158
[8dc72b64]159 /*
160 * Now, we expect the client to send us data with the name of the file
161 * system.
162 */
[8df8415]163 rc = async_data_write_accept((void **) &fs_name, true, 0,
164 FS_NAME_MAXLEN, 0, NULL);
[472c09d]165 if (rc != EOK) {
[5126f80]166 goto out;
167 }
168
169 if (!(flags & VFS_MOUNT_CONNECT_ONLY)) {
170 mp = vfs_file_get(mpfd);
171 if (mp == NULL) {
172 rc = EBADF;
173 goto out;
174 }
175
176 if (mp->node->mount != NULL) {
177 rc = EBUSY;
178 goto out;
179 }
180
181 if (mp->node->type != VFS_NODE_DIRECTORY) {
182 rc = ENOTDIR;
183 goto out;
184 }
185
186 if (vfs_node_has_children(mp->node)) {
187 rc = ENOTEMPTY;
188 goto out;
189 }
190 }
191
192 if (!(flags & VFS_MOUNT_NO_REF)) {
193 fd = vfs_fd_alloc(&file, false);
194 if (fd < 0) {
195 rc = fd;
196 goto out;
197 }
[c08c355]198 }
[4636a60]199
[460514d]200 /* Add the filesystem info to the list of mounted filesystems */
[5126f80]201 mtab_ent = malloc(sizeof(mtab_ent_t));
[460514d]202 if (!mtab_ent) {
[5126f80]203 rc = ENOMEM;
204 goto out;
[460514d]205 }
[4636a60]206
[5126f80]207 vfs_node_t *root = NULL;
208
[4636a60]209 fibril_rwlock_write_lock(&namespace_rwlock);
[6f9ef87a]210
[5126f80]211 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name, &root);
212 if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) {
213 vfs_node_addref(mp->node);
214 vfs_node_addref(root);
215 mp->node->mount = root;
216 }
217
218 fibril_rwlock_write_unlock(&namespace_rwlock);
219
220 if (rc != EOK) {
221 goto out;
222 }
223
224
225 if (flags & VFS_MOUNT_NO_REF) {
226 vfs_node_delref(root);
227 } else {
228 assert(file != NULL);
229
230 file->node = root;
231 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
232 file->open_read = false;
233 file->open_write = false;
234 }
235
[10e4cd7]236 /* Add the filesystem info to the list of mounted filesystems */
[4636a60]237 if (rc == EOK) {
[5126f80]238 str_cpy(mtab_ent->mp, MAX_PATH_LEN, "fixme");
[4636a60]239 str_cpy(mtab_ent->fs_name, FS_NAME_MAXLEN, fs_name);
240 str_cpy(mtab_ent->opts, MAX_MNTOPTS_LEN, opts);
241 mtab_ent->instance = instance;
242 mtab_ent->service_id = service_id;
[10e4cd7]243
[4636a60]244 link_initialize(&mtab_ent->link);
[10e4cd7]245
[4636a60]246 fibril_mutex_lock(&mtab_list_lock);
247 list_append(&mtab_ent->link, &mtab_list);
248 mtab_size++;
249 fibril_mutex_unlock(&mtab_list_lock);
[5126f80]250 }
[4636a60]251
[5126f80]252 rc = EOK;
[10e4cd7]253
[5126f80]254out:
255 async_answer_1(rid, rc, rc == EOK ? fd : 0);
256
257 if (opts) {
258 free(opts);
259 }
260 if (fs_name) {
261 free(fs_name);
262 }
263 if (mp) {
264 vfs_file_put(mp);
265 }
266 if (file) {
267 vfs_file_put(file);
268 }
269 if (rc != EOK && fd >= 0) {
270 vfs_fd_free(fd);
271 }
[8dc72b64]272}
273
[6afc9d7]274void vfs_unmount_srv(ipc_callid_t rid, ipc_call_t *request)
[7f5e070]275{
[5126f80]276 int mpfd = IPC_GET_ARG1(*request);
[79ae36dd]277
[5126f80]278 vfs_file_t *mp = vfs_file_get(mpfd);
279 if (mp == NULL) {
280 async_answer_0(rid, EBADF);
[ae75e2e3]281 return;
282 }
[79ae36dd]283
[5126f80]284 if (mp->node->mount == NULL) {
[4636a60]285 async_answer_0(rid, ENOENT);
[5126f80]286 vfs_file_put(mp);
[4636a60]287 return;
288 }
289
[5126f80]290 fibril_rwlock_write_lock(&namespace_rwlock);
291
[ae75e2e3]292 /*
293 * Count the total number of references for the mounted file system. We
[5126f80]294 * are expecting at least one, which is held by the mount point.
[4636a60]295 * If we find more, it means that
[ae75e2e3]296 * the file system cannot be gracefully unmounted at the moment because
297 * someone is working with it.
298 */
[5126f80]299 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle, mp->node->mount->service_id) != 1) {
[ffa2c8ef]300 async_answer_0(rid, EBUSY);
[5126f80]301 vfs_file_put(mp);
302 fibril_rwlock_write_unlock(&namespace_rwlock);
[ae75e2e3]303 return;
304 }
[79ae36dd]305
[5126f80]306 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
307 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED, mp->node->mount->service_id);
[4636a60]308 vfs_exchange_release(exch);
[79ae36dd]309
[5126f80]310 if (rc != EOK) {
311 async_answer_0(rid, rc);
312 vfs_file_put(mp);
313 fibril_rwlock_write_unlock(&namespace_rwlock);
314 return;
315 }
316
317 vfs_node_forget(mp->node->mount);
318 vfs_node_put(mp->node);
319 mp->node->mount = NULL;
[4636a60]320
[ae75e2e3]321 fibril_rwlock_write_unlock(&namespace_rwlock);
[4636a60]322
[76a67ce]323 fibril_mutex_lock(&mtab_list_lock);
324 int found = 0;
325
[feeac0d]326 list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
[5126f80]327 // FIXME: mp name
328 if (str_cmp(mtab_ent->mp, "fixme") == 0) {
[8d6a41c]329 list_remove(&mtab_ent->link);
[76a67ce]330 mtab_size--;
[8d6a41c]331 free(mtab_ent);
[76a67ce]332 found = 1;
333 break;
334 }
335 }
336 assert(found);
[4af2f36]337 fibril_mutex_unlock(&mtab_list_lock);
[4636a60]338
[5126f80]339 vfs_file_put(mp);
[ffa2c8ef]340 async_answer_0(rid, EOK);
[7f5e070]341}
342
[0b18364]343static inline bool walk_flags_valid(int flags)
[861e7d1]344{
[0b18364]345 if ((flags&~WALK_ALL_FLAGS) != 0) {
346 return false;
347 }
348 if ((flags&WALK_MAY_CREATE) && (flags&WALK_MUST_CREATE)) {
349 return false;
350 }
351 if ((flags&WALK_REGULAR) && (flags&WALK_DIRECTORY)) {
352 return false;
353 }
354 if ((flags&WALK_MAY_CREATE) || (flags&WALK_MUST_CREATE)) {
355 if (!(flags&WALK_DIRECTORY) && !(flags&WALK_REGULAR)) {
356 return false;
357 }
358 }
359 return true;
360}
[dd2cfa7]361
[0b18364]362static inline int walk_lookup_flags(int flags)
363{
364 int lflags = 0;
365 if (flags&WALK_MAY_CREATE || flags&WALK_MUST_CREATE) {
366 lflags |= L_CREATE;
367 }
368 if (flags&WALK_MUST_CREATE) {
369 lflags |= L_EXCLUSIVE;
370 }
371 if (flags&WALK_REGULAR) {
372 lflags |= L_FILE;
373 }
374 if (flags&WALK_DIRECTORY) {
375 lflags |= L_DIRECTORY;
376 }
[5126f80]377 if (flags&WALK_MOUNT_POINT) {
378 lflags |= L_MP;
379 }
[0b18364]380 return lflags;
381}
382
[cb65bbe]383void vfs_walk(ipc_callid_t rid, ipc_call_t *request)
384{
[b17186d]385 /*
[cb65bbe]386 * Parent is our relative root for file lookup.
387 * For defined flags, see <ipc/vfs.h>.
[b17186d]388 */
[cb65bbe]389 int parentfd = IPC_GET_ARG1(*request);
390 int flags = IPC_GET_ARG2(*request);
391
[0b18364]392 if (!walk_flags_valid(flags)) {
[ffa2c8ef]393 async_answer_0(rid, EINVAL);
[b17186d]394 return;
395 }
[05b9912]396
[472c09d]397 char *path;
[cb65bbe]398 int rc = async_data_write_accept((void **)&path, true, 0, 0, 0, NULL);
399
400 /* Lookup the file structure corresponding to the file descriptor. */
[5126f80]401 vfs_file_t *parent = vfs_file_get(parentfd);
402 if (!parent) {
403 free(path);
404 async_answer_0(rid, EBADF);
405 return;
[861e7d1]406 }
407
[cb65bbe]408 fibril_rwlock_read_lock(&namespace_rwlock);
[05b9912]409
[eb27ce5a]410 vfs_lookup_res_t lr;
[5126f80]411 rc = vfs_lookup_internal(parent->node, path, walk_lookup_flags(flags), &lr);
[cb65bbe]412 free(path);
413
[05b9912]414 if (rc != EOK) {
[cb65bbe]415 fibril_rwlock_read_unlock(&namespace_rwlock);
416 if (parent) {
417 vfs_file_put(parent);
418 }
[ffa2c8ef]419 async_answer_0(rid, rc);
[861e7d1]420 return;
421 }
[05b9912]422
[cb65bbe]423 vfs_node_t *node = vfs_node_get(&lr);
424
[c577a9a]425 vfs_file_t *file;
426 int fd = vfs_fd_alloc(&file, false);
[cb65bbe]427 if (fd < 0) {
428 vfs_node_put(node);
429 if (parent) {
430 vfs_file_put(parent);
431 }
432 async_answer_0(rid, fd);
433 return;
434 }
435 assert(file != NULL);
436
437 file->node = node;
438 if (parent) {
439 file->permissions = parent->permissions;
440 } else {
441 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
442 }
443 file->open_read = false;
444 file->open_write = false;
445
446 vfs_file_put(file);
447 if (parent) {
448 vfs_file_put(parent);
449 }
450
451 fibril_rwlock_read_unlock(&namespace_rwlock);
452
453 async_answer_1(rid, EOK, fd);
454}
455
456void vfs_open2(ipc_callid_t rid, ipc_call_t *request)
457{
458 int fd = IPC_GET_ARG1(*request);
459 int flags = IPC_GET_ARG2(*request);
460
461 if (flags == 0) {
462 async_answer_0(rid, EINVAL);
463 return;
464 }
465
466 vfs_file_t *file = vfs_file_get(fd);
467 if (!file) {
468 async_answer_0(rid, EBADF);
469 return;
470 }
471
472 if ((flags & ~file->permissions) != 0) {
473 vfs_file_put(file);
474 async_answer_0(rid, EPERM);
475 return;
476 }
477
478 file->open_read = (flags & MODE_READ) != 0;
479 file->open_write = (flags & (MODE_WRITE | MODE_APPEND)) != 0;
480 file->append = (flags & MODE_APPEND) != 0;
[05b9912]481
[cb65bbe]482 if (!file->open_read && !file->open_write) {
483 vfs_file_put(file);
484 async_answer_0(rid, EINVAL);
[6f2c1ff]485 return;
486 }
[05b9912]487
[cb65bbe]488 if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) {
489 file->open_read = file->open_write = false;
490 vfs_file_put(file);
491 async_answer_0(rid, EINVAL);
492 return;
[7fe1f75]493 }
[05b9912]494
[cb65bbe]495 int rc = vfs_open_node_remote(file->node);
496 if (rc != EOK) {
497 file->open_read = file->open_write = false;
498 vfs_file_put(file);
499 async_answer_0(rid, rc);
[861e7d1]500 return;
501 }
[05b9912]502
[4fe94c66]503 vfs_file_put(file);
[cb65bbe]504 async_answer_0(rid, EOK);
[05b9912]505}
[861e7d1]506
[05b9912]507void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
508{
509 int fd = IPC_GET_ARG1(*request);
510
511 /* Lookup the file structure corresponding to the file descriptor. */
512 vfs_file_t *file = vfs_file_get(fd);
513 if (!file) {
[ffa2c8ef]514 async_answer_0(rid, ENOENT);
[05b9912]515 return;
516 }
517
518 /*
519 * Lock the open file structure so that no other thread can manipulate
520 * the same open file at a time.
521 */
[79ae36dd]522 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
[05b9912]523
[4198f9c3]524 /* Make a VFS_OUT_SYMC request at the destination FS server. */
[05b9912]525 aid_t msg;
526 ipc_call_t answer;
[15f3c3f]527 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
[4198f9c3]528 file->node->index, &answer);
[79ae36dd]529
530 vfs_exchange_release(fs_exch);
531
[05b9912]532 /* Wait for reply from the FS server. */
[96b02eb9]533 sysarg_t rc;
[05b9912]534 async_wait_for(msg, &rc);
535
[4fe94c66]536 vfs_file_put(file);
[ffa2c8ef]537 async_answer_0(rid, rc);
[e704503]538}
539
[05b9912]540void vfs_close(ipc_callid_t rid, ipc_call_t *request)
541{
542 int fd = IPC_GET_ARG1(*request);
[79ae36dd]543 int ret = vfs_fd_free(fd);
[ffa2c8ef]544 async_answer_0(rid, ret);
[05b9912]545}
546
[e503517a]547typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, ipc_call_t *,
[42d08592]548 bool, void *);
549
[e503517a]550static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file,
[42d08592]551 ipc_call_t *answer, bool read, void *data)
552{
[e503517a]553 size_t *bytes = (size_t *) data;
554 int rc;
555
[42d08592]556 /*
557 * Make a VFS_READ/VFS_WRITE request at the destination FS server
558 * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
559 * destination FS server. The call will be routed as if sent by
560 * ourselves. Note that call arguments are immutable in this case so we
561 * don't have to bother.
562 */
563
564 if (read) {
[e503517a]565 rc = async_data_read_forward_4_1(exch, VFS_OUT_READ,
[42d08592]566 file->node->service_id, file->node->index,
567 LOWER32(file->pos), UPPER32(file->pos), answer);
568 } else {
[e503517a]569 rc = async_data_write_forward_4_1(exch, VFS_OUT_WRITE,
[42d08592]570 file->node->service_id, file->node->index,
571 LOWER32(file->pos), UPPER32(file->pos), answer);
[e503517a]572 }
573
574 *bytes = IPC_GET_ARG1(*answer);
575 return rc;
[42d08592]576}
[e503517a]577
578static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file,
579 ipc_call_t *answer, bool read, void *data)
580{
581 rdwr_io_chunk_t *chunk = (rdwr_io_chunk_t *) data;
582
583 if (exch == NULL)
584 return ENOENT;
[42d08592]585
[e503517a]586 aid_t msg = async_send_fast(exch, read ? VFS_OUT_READ : VFS_OUT_WRITE,
587 file->node->service_id, file->node->index, LOWER32(file->pos),
588 UPPER32(file->pos), answer);
589 if (msg == 0)
590 return EINVAL;
591
592 int retval = async_data_read_start(exch, chunk->buffer, chunk->size);
593 if (retval != EOK) {
594 async_forget(msg);
595 return retval;
596 }
597
598 sysarg_t rc;
599 async_wait_for(msg, &rc);
600
601 chunk->size = IPC_GET_ARG1(*answer);
602
603 return (int) rc;
604}
605
606static int vfs_rdwr(int fd, bool read, rdwr_ipc_cb_t ipc_cb, void *ipc_cb_data)
[861e7d1]607{
608 /*
609 * The following code strongly depends on the fact that the files data
610 * structure can be only accessed by a single fibril and all file
611 * operations are serialized (i.e. the reads and writes cannot
612 * interleave and a file cannot be closed while it is being read).
613 *
614 * Additional synchronization needs to be added once the table of
615 * open files supports parallel access!
616 */
[79ae36dd]617
[72bde81]618 /* Lookup the file structure corresponding to the file descriptor. */
[861e7d1]619 vfs_file_t *file = vfs_file_get(fd);
[e503517a]620 if (!file)
[354b642]621 return EBADF;
[6c89f20]622
[cb65bbe]623 if ((read && !file->open_read) || (!read && !file->open_write)) {
[c577a9a]624 vfs_file_put(file);
[1dff985]625 return EINVAL;
[cb65bbe]626 }
627
[79ae36dd]628 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
629 assert(fs_info);
630
[354b642]631 bool rlock = read || ((fs_info->concurrent_read_write) && (fs_info->write_retains_size));
632
[861e7d1]633 /*
634 * Lock the file's node so that no other client can read/write to it at
[c2f4b6b]635 * the same time unless the FS supports concurrent reads/writes and its
636 * write implementation does not modify the file size.
[861e7d1]637 */
[354b642]638 if (rlock) {
[230260ac]639 fibril_rwlock_read_lock(&file->node->contents_rwlock);
[354b642]640 } else {
[230260ac]641 fibril_rwlock_write_lock(&file->node->contents_rwlock);
[354b642]642 }
[79ae36dd]643
[b17186d]644 if (file->node->type == VFS_NODE_DIRECTORY) {
645 /*
646 * Make sure that no one is modifying the namespace
647 * while we are in readdir().
648 */
[354b642]649
650 if (!read) {
651 if (rlock) {
652 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
653 } else {
654 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
655 }
656 vfs_file_put(file);
657 return EINVAL;
658 }
659
[230260ac]660 fibril_rwlock_read_lock(&namespace_rwlock);
[b17186d]661 }
[6c89f20]662
[79ae36dd]663 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
[861e7d1]664
[42d08592]665 if (!read && file->append)
666 file->pos = file->node->size;
667
[861e7d1]668 /*
[42d08592]669 * Handle communication with the endpoint FS.
[861e7d1]670 */
[b4cbef1]671 ipc_call_t answer;
[e503517a]672 int rc = ipc_cb(fs_exch, file, &answer, read, ipc_cb_data);
[05b9912]673
[79ae36dd]674 vfs_exchange_release(fs_exch);
[34ca870]675
[861e7d1]676 size_t bytes = IPC_GET_ARG1(answer);
[b4cbef1]677
[b7c62a9]678 if (file->node->type == VFS_NODE_DIRECTORY) {
[230260ac]679 fibril_rwlock_read_unlock(&namespace_rwlock);
[b7c62a9]680 }
[6c89f20]681
[72bde81]682 /* Unlock the VFS node. */
[354b642]683 if (rlock) {
[230260ac]684 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[354b642]685 } else {
[861e7d1]686 /* Update the cached version of node's size. */
[354b642]687 if (rc == EOK) {
[5bb9907]688 file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
689 IPC_GET_ARG3(answer));
[354b642]690 }
[230260ac]691 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
[861e7d1]692 }
[6c89f20]693
[72bde81]694 /* Update the position pointer and unlock the open file. */
[354b642]695 if (rc == EOK) {
[f7017572]696 file->pos += bytes;
[354b642]697 }
[4fe94c66]698 vfs_file_put(file);
699
[e503517a]700 return rc;
701}
702
703static void vfs_rdwr_client(ipc_callid_t rid, ipc_call_t *request, bool read)
704{
705 size_t bytes = 0;
706 int rc = vfs_rdwr(IPC_GET_ARG1(*request), read, rdwr_ipc_client,
707 &bytes);
[ffa2c8ef]708 async_answer_1(rid, rc, bytes);
[861e7d1]709}
710
[e503517a]711int vfs_rdwr_internal(int fd, bool read, rdwr_io_chunk_t *chunk)
712{
713 return vfs_rdwr(fd, read, rdwr_ipc_internal, chunk);
714}
715
[861e7d1]716void vfs_read(ipc_callid_t rid, ipc_call_t *request)
717{
[e503517a]718 vfs_rdwr_client(rid, request, true);
[861e7d1]719}
720
721void vfs_write(ipc_callid_t rid, ipc_call_t *request)
722{
[e503517a]723 vfs_rdwr_client(rid, request, false);
[861e7d1]724}
725
726void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
727{
728 int fd = (int) IPC_GET_ARG1(*request);
[8df8415]729 off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
730 IPC_GET_ARG3(*request));
[ed903174]731 int whence = (int) IPC_GET_ARG4(*request);
732
[72bde81]733 /* Lookup the file structure corresponding to the file descriptor. */
[861e7d1]734 vfs_file_t *file = vfs_file_get(fd);
735 if (!file) {
[ffa2c8ef]736 async_answer_0(rid, ENOENT);
[861e7d1]737 return;
738 }
[ed903174]739
740 off64_t newoff;
741 switch (whence) {
[8df8415]742 case SEEK_SET:
743 if (off >= 0) {
744 file->pos = (aoff64_t) off;
[4fe94c66]745 vfs_file_put(file);
[ffa2c8ef]746 async_answer_1(rid, EOK, off);
[861e7d1]747 return;
[8df8415]748 }
749 break;
750 case SEEK_CUR:
751 if ((off >= 0) && (file->pos + off < file->pos)) {
[4fe94c66]752 vfs_file_put(file);
[ffa2c8ef]753 async_answer_0(rid, EOVERFLOW);
[8df8415]754 return;
755 }
756
757 if ((off < 0) && (file->pos < (aoff64_t) -off)) {
[4fe94c66]758 vfs_file_put(file);
[ffa2c8ef]759 async_answer_0(rid, EOVERFLOW);
[8df8415]760 return;
761 }
762
763 file->pos += off;
[b1956e3]764 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos;
[8df8415]765
[4fe94c66]766 vfs_file_put(file);
[ffa2c8ef]767 async_answer_2(rid, EOK, LOWER32(newoff),
[8df8415]768 UPPER32(newoff));
769 return;
770 case SEEK_END:
771 fibril_rwlock_read_lock(&file->node->contents_rwlock);
[677745a]772 aoff64_t size = vfs_node_get_size(file->node);
[8df8415]773
774 if ((off >= 0) && (size + off < size)) {
[ed903174]775 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[4fe94c66]776 vfs_file_put(file);
[ffa2c8ef]777 async_answer_0(rid, EOVERFLOW);
[861e7d1]778 return;
[8df8415]779 }
780
781 if ((off < 0) && (size < (aoff64_t) -off)) {
782 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[4fe94c66]783 vfs_file_put(file);
[ffa2c8ef]784 async_answer_0(rid, EOVERFLOW);
[8df8415]785 return;
786 }
787
788 file->pos = size + off;
789 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos;
790
791 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[4fe94c66]792 vfs_file_put(file);
[ffa2c8ef]793 async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff));
[8df8415]794 return;
[861e7d1]795 }
[ed903174]796
[4fe94c66]797 vfs_file_put(file);
[ffa2c8ef]798 async_answer_0(rid, EINVAL);
[861e7d1]799}
800
[15f3c3f]801int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
[ed903174]802 fs_index_t index, aoff64_t size)
[7fe1f75]803{
[79ae36dd]804 async_exch_t *exch = vfs_exchange_grab(fs_handle);
805 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
[15f3c3f]806 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
[79ae36dd]807 UPPER32(size));
808 vfs_exchange_release(exch);
[7fe1f75]809
[79ae36dd]810 return (int) rc;
[7fe1f75]811}
812
[0ee4322]813void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
814{
815 int fd = IPC_GET_ARG1(*request);
[8df8415]816 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
817 IPC_GET_ARG3(*request));
[7fe1f75]818 int rc;
[0ee4322]819
820 vfs_file_t *file = vfs_file_get(fd);
821 if (!file) {
[ffa2c8ef]822 async_answer_0(rid, ENOENT);
[0ee4322]823 return;
824 }
825
[230260ac]826 fibril_rwlock_write_lock(&file->node->contents_rwlock);
[7fe1f75]827 rc = vfs_truncate_internal(file->node->fs_handle,
[15f3c3f]828 file->node->service_id, file->node->index, size);
[0ee4322]829 if (rc == EOK)
830 file->node->size = size;
[230260ac]831 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
[0ee4322]832
[4fe94c66]833 vfs_file_put(file);
[ffa2c8ef]834 async_answer_0(rid, (sysarg_t)rc);
[861e7d1]835}
836
[852b801]837void vfs_fstat(ipc_callid_t rid, ipc_call_t *request)
838{
839 int fd = IPC_GET_ARG1(*request);
[96b02eb9]840 sysarg_t rc;
[852b801]841
842 vfs_file_t *file = vfs_file_get(fd);
843 if (!file) {
[ffa2c8ef]844 async_answer_0(rid, ENOENT);
[852b801]845 return;
846 }
[c577a9a]847 assert(file->node);
[852b801]848
849 ipc_callid_t callid;
[0da4e41]850 if (!async_data_read_receive(&callid, NULL)) {
[4fe94c66]851 vfs_file_put(file);
[ffa2c8ef]852 async_answer_0(callid, EINVAL);
853 async_answer_0(rid, EINVAL);
[852b801]854 return;
855 }
856
[79ae36dd]857 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
[c577a9a]858 assert(exch);
[852b801]859
860 aid_t msg;
[15f3c3f]861 msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id,
[852b801]862 file->node->index, true, NULL);
[c577a9a]863 assert(msg);
[79ae36dd]864 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
865
866 vfs_exchange_release(exch);
867
[852b801]868 async_wait_for(msg, &rc);
[79ae36dd]869
[4fe94c66]870 vfs_file_put(file);
[ffa2c8ef]871 async_answer_0(rid, rc);
[852b801]872}
873
[5bcd5b7]874static void out_destroy(vfs_triplet_t *file)
875{
876 async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
877 async_msg_2(exch, VFS_OUT_DESTROY,
878 (sysarg_t) file->service_id, (sysarg_t) file->index);
879 vfs_exchange_release(exch);
880}
881
[20c071d]882void vfs_unlink2(ipc_callid_t rid, ipc_call_t *request)
[852b801]883{
[20c071d]884 int rc;
[472c09d]885 char *path;
[20c071d]886 vfs_file_t *parent = NULL;
887 vfs_file_t *expect = NULL;
888
889 int parentfd = IPC_GET_ARG1(*request);
890 int expectfd = IPC_GET_ARG2(*request);
891 int wflag = IPC_GET_ARG3(*request);
892
893 rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
[472c09d]894 if (rc != EOK) {
[ffa2c8ef]895 async_answer_0(rid, rc);
[415c7e0d]896 return;
897 }
[5126f80]898 if (parentfd == expectfd) {
899 async_answer_0(rid, EINVAL);
900 return;
901 }
[472c09d]902
[20c071d]903 fibril_rwlock_write_lock(&namespace_rwlock);
904
905 int lflag = (wflag&WALK_DIRECTORY) ? L_DIRECTORY: 0;
[415c7e0d]906
[c577a9a]907 /* Files are retrieved in order of file descriptors, to prevent deadlock. */
[5126f80]908 if (parentfd < expectfd) {
[20c071d]909 parent = vfs_file_get(parentfd);
910 if (!parent) {
[5126f80]911 rc = EBADF;
[20c071d]912 goto exit;
913 }
914 }
915
916 if (expectfd >= 0) {
917 expect = vfs_file_get(expectfd);
918 if (!expect) {
919 rc = ENOENT;
920 goto exit;
921 }
[c577a9a]922 }
923
[5126f80]924 if (parentfd > expectfd) {
[c577a9a]925 parent = vfs_file_get(parentfd);
926 if (!parent) {
[5126f80]927 rc = EBADF;
[c577a9a]928 goto exit;
929 }
930 }
931
[5126f80]932 assert(parent != NULL);
[c577a9a]933
934 if (expectfd >= 0) {
[20c071d]935 vfs_lookup_res_t lr;
[5126f80]936 rc = vfs_lookup_internal(parent->node, path, lflag, &lr);
[20c071d]937 if (rc != EOK) {
938 goto exit;
939 }
940
[a274a5f]941 vfs_node_t *found_node = vfs_node_peek(&lr);
942 if (expect->node != found_node) {
[20c071d]943 rc = ENOENT;
944 goto exit;
945 }
946
947 vfs_file_put(expect);
948 expect = NULL;
949 }
950
[415c7e0d]951 vfs_lookup_res_t lr;
[5126f80]952 rc = vfs_lookup_internal(parent->node, path, lflag | L_UNLINK, &lr);
[415c7e0d]953 if (rc != EOK) {
[20c071d]954 goto exit;
[415c7e0d]955 }
[20c071d]956
[5bcd5b7]957 /* If the node is not held by anyone, try to destroy it. */
958 if (vfs_node_peek(&lr) == NULL) {
959 out_destroy(&lr.triplet);
[415c7e0d]960 }
961
[20c071d]962exit:
963 if (path) {
964 free(path);
965 }
966 if (parent) {
967 vfs_file_put(parent);
968 }
969 if (expect) {
970 vfs_file_put(expect);
971 }
972 fibril_rwlock_write_unlock(&namespace_rwlock);
973 async_answer_0(rid, rc);
974}
[415c7e0d]975
[778d26d]976static size_t shared_path(char *a, char *b)
[a8e9ab8d]977{
[778d26d]978 size_t res = 0;
[79ae36dd]979
[778d26d]980 while (a[res] == b[res] && a[res] != 0) {
981 res++;
[a8e9ab8d]982 }
[79ae36dd]983
[778d26d]984 if (a[res] == b[res]) {
985 return res;
986 }
[057760d3]987
[778d26d]988 res--;
989 while (a[res] != '/') {
990 res--;
[a8e9ab8d]991 }
[778d26d]992 return res;
[852b801]993}
994
[5bcd5b7]995static int vfs_rename_internal(vfs_node_t *base, char *old, char *new)
[72bde81]996{
[778d26d]997 assert(base != NULL);
998 assert(old != NULL);
999 assert(new != NULL);
[472c09d]1000
[778d26d]1001 vfs_lookup_res_t base_lr;
1002 vfs_lookup_res_t old_lr;
1003 vfs_lookup_res_t new_lr_orig;
1004 bool orig_unlinked = false;
[472c09d]1005
[778d26d]1006 int rc;
1007
1008 size_t shared = shared_path(old, new);
[472c09d]1009
[778d26d]1010 /* Do not allow one path to be a prefix of the other. */
1011 if (old[shared] == 0 || new[shared] == 0) {
1012 return EINVAL;
[a8e9ab8d]1013 }
[778d26d]1014 assert(old[shared] == '/');
1015 assert(new[shared] == '/');
[72bde81]1016
[230260ac]1017 fibril_rwlock_write_lock(&namespace_rwlock);
[472c09d]1018
[778d26d]1019 /* Resolve the shared portion of the path first. */
1020 if (shared != 0) {
1021 old[shared] = 0;
1022 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
1023 if (rc != EOK) {
1024 fibril_rwlock_write_unlock(&namespace_rwlock);
1025 return rc;
1026 }
1027
[5bcd5b7]1028 base = vfs_node_get(&base_lr);
[778d26d]1029 old[shared] = '/';
1030 old += shared;
1031 new += shared;
[5bcd5b7]1032 } else {
1033 vfs_node_addref(base);
[a8e9ab8d]1034 }
[472c09d]1035
[778d26d]1036
1037 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS, &new_lr_orig);
1038 if (rc == EOK) {
1039 orig_unlinked = true;
1040 } else if (rc != ENOENT) {
[5bcd5b7]1041 vfs_node_put(base);
[230260ac]1042 fibril_rwlock_write_unlock(&namespace_rwlock);
[778d26d]1043 return rc;
[a8e9ab8d]1044 }
[472c09d]1045
[778d26d]1046 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS, &old_lr);
[472c09d]1047 if (rc != EOK) {
[778d26d]1048 if (orig_unlinked) {
1049 vfs_link_internal(base, new, &new_lr_orig.triplet);
1050 }
[5bcd5b7]1051 vfs_node_put(base);
[230260ac]1052 fibril_rwlock_write_unlock(&namespace_rwlock);
[778d26d]1053 return rc;
[f15cf1a6]1054 }
1055
[778d26d]1056 rc = vfs_link_internal(base, new, &old_lr.triplet);
[f15cf1a6]1057 if (rc != EOK) {
[778d26d]1058 vfs_link_internal(base, old, &old_lr.triplet);
1059 if (orig_unlinked) {
1060 vfs_link_internal(base, new, &new_lr_orig.triplet);
1061 }
[5bcd5b7]1062 vfs_node_put(base);
[230260ac]1063 fibril_rwlock_write_unlock(&namespace_rwlock);
[778d26d]1064 return rc;
[f15cf1a6]1065 }
[472c09d]1066
[5bcd5b7]1067 /* If the node is not held by anyone, try to destroy it. */
1068 if (orig_unlinked && vfs_node_peek(&new_lr_orig) == NULL) {
1069 out_destroy(&new_lr_orig.triplet);
[a8e9ab8d]1070 }
[472c09d]1071
[5bcd5b7]1072 vfs_node_put(base);
[230260ac]1073 fibril_rwlock_write_unlock(&namespace_rwlock);
[778d26d]1074 return EOK;
[f15cf1a6]1075}
1076
[a8e9ab8d]1077void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
1078{
[778d26d]1079 /* The common base directory. */
1080 int basefd;
1081 char *old = NULL;
1082 char *new = NULL;
1083 vfs_file_t *base = NULL;
1084 int rc;
[472c09d]1085
[778d26d]1086 basefd = IPC_GET_ARG1(*request);
1087
[a8e9ab8d]1088 /* Retrieve the old path. */
[778d26d]1089 rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
[472c09d]1090 if (rc != EOK) {
[778d26d]1091 goto out;
[a8e9ab8d]1092 }
1093
1094 /* Retrieve the new path. */
[4cac2d69]1095 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
[472c09d]1096 if (rc != EOK) {
[778d26d]1097 goto out;
[a8e9ab8d]1098 }
[472c09d]1099
1100 size_t olen;
1101 size_t nlen;
[732bb0c]1102 char *oldc = canonify(old, &olen);
1103 char *newc = canonify(new, &nlen);
[472c09d]1104
1105 if ((!oldc) || (!newc)) {
[778d26d]1106 rc = EINVAL;
1107 goto out;
[a8e9ab8d]1108 }
[472c09d]1109
[778d26d]1110 assert(oldc[olen] == '\0');
1111 assert(newc[nlen] == '\0');
[472c09d]1112
[778d26d]1113 /* Lookup the file structure corresponding to the file descriptor. */
[5126f80]1114 base = vfs_file_get(basefd);
1115 if (!base) {
1116 rc = EBADF;
1117 goto out;
[a8e9ab8d]1118 }
[472c09d]1119
[5126f80]1120 rc = vfs_rename_internal(base->node, oldc, newc);
[778d26d]1121
1122out:
1123 async_answer_0(rid, rc);
1124
1125 if (old) {
[a8e9ab8d]1126 free(old);
1127 }
[778d26d]1128 if (new) {
[a8e9ab8d]1129 free(new);
1130 }
[778d26d]1131 if (base) {
1132 vfs_file_put(base);
1133 }
[a8e9ab8d]1134}
1135
[2b88074b]1136void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
1137{
1138 int oldfd = IPC_GET_ARG1(*request);
1139 int newfd = IPC_GET_ARG2(*request);
1140
[4fe94c66]1141 /* If the file descriptors are the same, do nothing. */
1142 if (oldfd == newfd) {
[ffa2c8ef]1143 async_answer_1(rid, EOK, newfd);
[4fe94c66]1144 return;
1145 }
1146
[2b88074b]1147 /* Lookup the file structure corresponding to oldfd. */
1148 vfs_file_t *oldfile = vfs_file_get(oldfd);
1149 if (!oldfile) {
[ffa2c8ef]1150 async_answer_0(rid, EBADF);
[2b88074b]1151 return;
1152 }
1153
[25bef0ff]1154 /* Make sure newfd is closed. */
1155 (void) vfs_fd_free(newfd);
[2b88074b]1156
1157 /* Assign the old file to newfd. */
1158 int ret = vfs_fd_assign(oldfile, newfd);
[4fe94c66]1159 vfs_file_put(oldfile);
[2b88074b]1160
1161 if (ret != EOK)
[ffa2c8ef]1162 async_answer_0(rid, ret);
[2b88074b]1163 else
[ffa2c8ef]1164 async_answer_1(rid, EOK, newfd);
[2b88074b]1165}
1166
[27b76ca]1167void vfs_wait_handle(ipc_callid_t rid, ipc_call_t *request)
1168{
[bb9ec2d]1169 bool high_fd = IPC_GET_ARG1(*request);
1170 int fd = vfs_wait_handle_internal(high_fd);
[27b76ca]1171 async_answer_1(rid, EOK, fd);
1172}
1173
[76a67ce]1174void vfs_get_mtab(ipc_callid_t rid, ipc_call_t *request)
1175{
1176 ipc_callid_t callid;
1177 ipc_call_t data;
1178 sysarg_t rc = EOK;
1179 size_t len;
1180
1181 fibril_mutex_lock(&mtab_list_lock);
1182
1183 /* Send to the caller the number of mounted filesystems */
1184 callid = async_get_call(&data);
1185 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
1186 rc = ENOTSUP;
[7e8403b]1187 async_answer_0(callid, rc);
[76a67ce]1188 goto exit;
1189 }
1190 async_answer_1(callid, EOK, mtab_size);
1191
[feeac0d]1192 list_foreach(mtab_list, link, mtab_ent_t, mtab_ent) {
[76a67ce]1193 rc = ENOTSUP;
1194
[e6da6d5]1195 if (!async_data_read_receive(&callid, &len)) {
1196 async_answer_0(callid, rc);
[76a67ce]1197 goto exit;
[e6da6d5]1198 }
[76a67ce]1199
1200 (void) async_data_read_finalize(callid, mtab_ent->mp,
1201 str_size(mtab_ent->mp));
1202
[e6da6d5]1203 if (!async_data_read_receive(&callid, &len)) {
1204 async_answer_0(callid, rc);
[76a67ce]1205 goto exit;
[e6da6d5]1206 }
[76a67ce]1207
1208 (void) async_data_read_finalize(callid, mtab_ent->opts,
1209 str_size(mtab_ent->opts));
1210
[e6da6d5]1211 if (!async_data_read_receive(&callid, &len)) {
1212 async_answer_0(callid, rc);
[76a67ce]1213 goto exit;
[e6da6d5]1214 }
[76a67ce]1215
1216 (void) async_data_read_finalize(callid, mtab_ent->fs_name,
1217 str_size(mtab_ent->fs_name));
1218
[f8838b8]1219 callid = async_get_call(&data);
1220
1221 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
[7e8403b]1222 async_answer_0(callid, rc);
[f8838b8]1223 goto exit;
[76a67ce]1224 }
1225
1226 rc = EOK;
[6b8e5b74]1227 async_answer_2(callid, rc, mtab_ent->instance,
1228 mtab_ent->service_id);
[76a67ce]1229 }
1230
1231exit:
1232 fibril_mutex_unlock(&mtab_list_lock);
1233 async_answer_0(rid, rc);
1234}
1235
[66366470]1236void vfs_statfs(ipc_callid_t rid, ipc_call_t *request)
1237{
[a737667e]1238 int fd = IPC_GET_ARG1(*request);
[9dc6083]1239
1240 ipc_callid_t callid;
1241 if (!async_data_read_receive(&callid, NULL)) {
1242 async_answer_0(callid, EINVAL);
1243 async_answer_0(rid, EINVAL);
1244 return;
1245 }
1246
[a737667e]1247 vfs_file_t *file = vfs_file_get(fd);
1248 if (!file) {
1249 async_answer_0(callid, EBADF);
1250 async_answer_0(rid, EBADF);
[9dc6083]1251 }
1252
[a737667e]1253 vfs_node_t *node = file->node;
[9dc6083]1254
1255 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
1256
1257 aid_t msg;
1258 msg = async_send_3(exch, VFS_OUT_STATFS, node->service_id,
1259 node->index, false, NULL);
1260 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
1261
1262 vfs_exchange_release(exch);
1263
1264 sysarg_t rv;
1265 async_wait_for(msg, &rv);
[66366470]1266
[a737667e]1267 vfs_file_put(file);
[9dc6083]1268
[a737667e]1269 async_answer_0(rid, rv);
[66366470]1270}
1271
[354b642]1272void vfs_op_clone(ipc_callid_t rid, ipc_call_t *request)
1273{
1274 int oldfd = IPC_GET_ARG1(*request);
1275 bool desc = IPC_GET_ARG2(*request);
1276
1277 /* Lookup the file structure corresponding to fd. */
1278 vfs_file_t *oldfile = vfs_file_get(oldfd);
[5126f80]1279 if (oldfile == NULL) {
[354b642]1280 async_answer_0(rid, EBADF);
1281 return;
1282 }
1283
1284 vfs_file_t *newfile;
1285 int newfd = vfs_fd_alloc(&newfile, desc);
[5126f80]1286 async_answer_0(rid, newfd);
1287
[354b642]1288 if (newfd < 0) {
1289 vfs_file_put(oldfile);
1290 return;
1291 }
1292
1293 assert(oldfile->node != NULL);
1294
1295 newfile->node = oldfile->node;
1296 newfile->permissions = oldfile->permissions;
[930f5c3]1297 vfs_node_addref(newfile->node);
[354b642]1298
1299 vfs_file_put(oldfile);
1300 vfs_file_put(newfile);
1301}
1302
[861e7d1]1303/**
1304 * @}
[05b9912]1305 */
Note: See TracBrowser for help on using the repository browser.