source: mainline/uspace/srv/vfs/vfs_ops.c@ b19e892

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

Merge open() with posix_open() and provide vfs_lookup_open() instead

vfs_lookup_open() is really just a convenience wrapper around
vfs_lookup() and vfs_open().

  • Property mode set to 100644
File size: 20.4 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>
51#include <assert.h>
[a8e9ab8d]52#include <vfs/canonify.h>
[861e7d1]53
[7fe1f75]54/* Forward declarations of static functions. */
[15f3c3f]55static int vfs_truncate_internal(fs_handle_t, service_id_t, fs_index_t,
[8df8415]56 aoff64_t);
[7fe1f75]57
[861e7d1]58/**
59 * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
60 * concurrent VFS operation which modifies the file system namespace.
61 */
[230260ac]62FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
[861e7d1]63
[0d35511]64static size_t shared_path(char *a, char *b)
65{
66 size_t res = 0;
67
[61042de]68 while (a[res] == b[res] && a[res] != 0)
[0d35511]69 res++;
70
[61042de]71 if (a[res] == b[res])
[0d35511]72 return res;
73
74 res--;
[61042de]75 while (a[res] != '/')
[0d35511]76 res--;
77 return res;
78}
79
80/* This call destroys the file if and only if there are no hard links left. */
81static void out_destroy(vfs_triplet_t *file)
82{
83 async_exch_t *exch = vfs_exchange_grab(file->fs_handle);
[61042de]84 async_msg_2(exch, VFS_OUT_DESTROY, (sysarg_t) file->service_id,
85 (sysarg_t) file->index);
[0d35511]86 vfs_exchange_release(exch);
87}
88
[fcab7ef]89int vfs_op_clone(int oldfd, int newfd, bool desc)
[0d35511]90{
[fcab7ef]91 int rc;
92
93 /* If the file descriptors are the same, do nothing. */
94 if (oldfd == newfd)
95 return EOK;
96
[0d35511]97 /* Lookup the file structure corresponding to fd. */
98 vfs_file_t *oldfile = vfs_file_get(oldfd);
[61042de]99 if (oldfile == NULL)
[0d35511]100 return EBADF;
[61042de]101
[0d35511]102 assert(oldfile->node != NULL);
[fcab7ef]103
104 if (newfd != -1) {
105 /* Make sure newfd is closed. */
106 (void) vfs_fd_free(newfd);
107 /* Assign the old file to newfd. */
108 rc = vfs_fd_assign(oldfile, newfd);
109 } else {
110 vfs_file_t *newfile;
111 int newfd = vfs_fd_alloc(&newfile, desc);
112 if (newfd >= 0) {
113 newfile->node = oldfile->node;
114 newfile->permissions = oldfile->permissions;
115 vfs_node_addref(newfile->node);
[0d35511]116
[fcab7ef]117 vfs_file_put(newfile);
118 }
119 rc = newfd;
[0d35511]120 }
121 vfs_file_put(oldfile);
122
[fcab7ef]123 return rc;
[0d35511]124}
125
126int vfs_op_close(int fd)
127{
128 return vfs_fd_free(fd);
129}
130
131static int vfs_connect_internal(service_id_t service_id, unsigned flags,
132 unsigned instance, const char *options, const char *fsname,
133 vfs_node_t **root)
[861e7d1]134{
[4636a60]135 fs_handle_t fs_handle = 0;
[05b9912]136
[4636a60]137 fibril_mutex_lock(&fs_list_lock);
[61042de]138 while (true) {
[4636a60]139 fs_handle = fs_name_to_handle(instance, fsname, false);
[8dc72b64]140
[61042de]141 if (fs_handle != 0 || !(flags & VFS_MOUNT_BLOCKING))
[4636a60]142 break;
[8dc72b64]143
[4636a60]144 fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
145 }
146 fibril_mutex_unlock(&fs_list_lock);
147
[61042de]148 if (fs_handle == 0)
[4636a60]149 return ENOENT;
[5bcd5b7]150
[4636a60]151 /* Tell the mountee that it is being mounted. */
152 ipc_call_t answer;
153 async_exch_t *exch = vfs_exchange_grab(fs_handle);
[0d35511]154 aid_t msg = async_send_1(exch, VFS_OUT_MOUNTED, (sysarg_t) service_id,
155 &answer);
[4636a60]156 /* Send the mount options */
157 sysarg_t rc = async_data_write_start(exch, options, str_size(options));
158 if (rc != EOK) {
159 async_forget(msg);
160 vfs_exchange_release(exch);
161 return rc;
[5bcd5b7]162 }
[c990ee6]163
[4636a60]164 async_wait_for(msg, &rc);
[c990ee6]165 if (rc != EOK) {
166 vfs_exchange_release(exch);
[4636a60]167 return rc;
[c990ee6]168 }
[5bcd5b7]169
[4636a60]170 vfs_lookup_res_t res;
171 res.triplet.fs_handle = fs_handle;
172 res.triplet.service_id = service_id;
173 res.triplet.index = (fs_index_t) IPC_GET_ARG1(answer);
[0d35511]174 res.size = (int64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
175 IPC_GET_ARG3(answer));
[4636a60]176 res.type = VFS_NODE_DIRECTORY;
[5bcd5b7]177
[4636a60]178 /* Add reference to the mounted root. */
179 *root = vfs_node_get(&res);
[c990ee6]180 if (!*root) {
181 aid_t msg = async_send_1(exch, VFS_OUT_UNMOUNTED,
182 (sysarg_t) service_id, NULL);
183 async_forget(msg);
184 vfs_exchange_release(exch);
185 return ENOMEM;
186 }
[8dc72b64]187
[c990ee6]188 vfs_exchange_release(exch);
189
[4636a60]190 return EOK;
[5bcd5b7]191}
192
[0d35511]193int vfs_op_mount(int mpfd, unsigned service_id, unsigned flags,
194 unsigned instance, const char *opts, const char *fs_name, int *outfd)
[8dc72b64]195{
[0d35511]196 int rc;
[5126f80]197 vfs_file_t *mp = NULL;
198 vfs_file_t *file = NULL;
199 int fd = -1;
200
201 if (!(flags & VFS_MOUNT_CONNECT_ONLY)) {
202 mp = vfs_file_get(mpfd);
203 if (mp == NULL) {
204 rc = EBADF;
205 goto out;
206 }
207
208 if (mp->node->mount != NULL) {
209 rc = EBUSY;
210 goto out;
211 }
212
213 if (mp->node->type != VFS_NODE_DIRECTORY) {
214 rc = ENOTDIR;
215 goto out;
216 }
217
218 if (vfs_node_has_children(mp->node)) {
219 rc = ENOTEMPTY;
220 goto out;
221 }
222 }
223
224 if (!(flags & VFS_MOUNT_NO_REF)) {
225 fd = vfs_fd_alloc(&file, false);
226 if (fd < 0) {
227 rc = fd;
228 goto out;
229 }
[c08c355]230 }
[4636a60]231
[5126f80]232 vfs_node_t *root = NULL;
233
[4636a60]234 fibril_rwlock_write_lock(&namespace_rwlock);
[6f9ef87a]235
[0d35511]236 rc = vfs_connect_internal(service_id, flags, instance, opts, fs_name,
237 &root);
[5126f80]238 if (rc == EOK && !(flags & VFS_MOUNT_CONNECT_ONLY)) {
239 vfs_node_addref(mp->node);
240 vfs_node_addref(root);
241 mp->node->mount = root;
242 }
243
244 fibril_rwlock_write_unlock(&namespace_rwlock);
245
[61042de]246 if (rc != EOK)
[5126f80]247 goto out;
248
249 if (flags & VFS_MOUNT_NO_REF) {
250 vfs_node_delref(root);
251 } else {
252 assert(file != NULL);
253
254 file->node = root;
255 file->permissions = MODE_READ | MODE_WRITE | MODE_APPEND;
256 file->open_read = false;
257 file->open_write = false;
258 }
259
260out:
[61042de]261 if (mp)
[5126f80]262 vfs_file_put(mp);
[61042de]263 if (file)
[5126f80]264 vfs_file_put(file);
[61042de]265
[5126f80]266 if (rc != EOK && fd >= 0) {
267 vfs_fd_free(fd);
[0d35511]268 fd = 0;
[5126f80]269 }
[0d35511]270
271 *outfd = fd;
272 return rc;
[8dc72b64]273}
274
[b19e892]275int vfs_op_open(int fd, int mode)
[861e7d1]276{
[b19e892]277 if (mode == 0)
[0d35511]278 return EINVAL;
279
280 vfs_file_t *file = vfs_file_get(fd);
[61042de]281 if (!file)
[0d35511]282 return EBADF;
283
[b19e892]284 if ((mode & ~file->permissions) != 0) {
[0d35511]285 vfs_file_put(file);
286 return EPERM;
[0b18364]287 }
[0d35511]288
289 if (file->open_read || file->open_write) {
290 vfs_file_put(file);
291 return EBUSY;
[cb65bbe]292 }
293
[b19e892]294 file->open_read = (mode & MODE_READ) != 0;
295 file->open_write = (mode & (MODE_WRITE | MODE_APPEND)) != 0;
296 file->append = (mode & MODE_APPEND) != 0;
[05b9912]297
[cb65bbe]298 if (!file->open_read && !file->open_write) {
299 vfs_file_put(file);
[0d35511]300 return EINVAL;
[6f2c1ff]301 }
[05b9912]302
[cb65bbe]303 if (file->node->type == VFS_NODE_DIRECTORY && file->open_write) {
304 file->open_read = file->open_write = false;
305 vfs_file_put(file);
[0d35511]306 return EINVAL;
[7fe1f75]307 }
[05b9912]308
[cb65bbe]309 int rc = vfs_open_node_remote(file->node);
310 if (rc != EOK) {
311 file->open_read = file->open_write = false;
312 vfs_file_put(file);
[0d35511]313 return rc;
[05b9912]314 }
315
[4fe94c66]316 vfs_file_put(file);
[0d35511]317 return EOK;
[05b9912]318}
319
[58898d1d]320typedef int (* rdwr_ipc_cb_t)(async_exch_t *, vfs_file_t *, aoff64_t,
321 ipc_call_t *, bool, void *);
[42d08592]322
[58898d1d]323static int rdwr_ipc_client(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
[42d08592]324 ipc_call_t *answer, bool read, void *data)
325{
[e503517a]326 size_t *bytes = (size_t *) data;
327 int rc;
328
[42d08592]329 /*
330 * Make a VFS_READ/VFS_WRITE request at the destination FS server
331 * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
332 * destination FS server. The call will be routed as if sent by
333 * ourselves. Note that call arguments are immutable in this case so we
334 * don't have to bother.
335 */
336
337 if (read) {
[e503517a]338 rc = async_data_read_forward_4_1(exch, VFS_OUT_READ,
[42d08592]339 file->node->service_id, file->node->index,
[58898d1d]340 LOWER32(pos), UPPER32(pos), answer);
[42d08592]341 } else {
[e503517a]342 rc = async_data_write_forward_4_1(exch, VFS_OUT_WRITE,
[42d08592]343 file->node->service_id, file->node->index,
[58898d1d]344 LOWER32(pos), UPPER32(pos), answer);
[e503517a]345 }
346
347 *bytes = IPC_GET_ARG1(*answer);
348 return rc;
[42d08592]349}
[e503517a]350
[58898d1d]351static int rdwr_ipc_internal(async_exch_t *exch, vfs_file_t *file, aoff64_t pos,
[e503517a]352 ipc_call_t *answer, bool read, void *data)
353{
354 rdwr_io_chunk_t *chunk = (rdwr_io_chunk_t *) data;
355
356 if (exch == NULL)
357 return ENOENT;
[42d08592]358
[e503517a]359 aid_t msg = async_send_fast(exch, read ? VFS_OUT_READ : VFS_OUT_WRITE,
[58898d1d]360 file->node->service_id, file->node->index, LOWER32(pos),
361 UPPER32(pos), answer);
[e503517a]362 if (msg == 0)
363 return EINVAL;
364
365 int retval = async_data_read_start(exch, chunk->buffer, chunk->size);
366 if (retval != EOK) {
367 async_forget(msg);
368 return retval;
369 }
370
371 sysarg_t rc;
372 async_wait_for(msg, &rc);
373
374 chunk->size = IPC_GET_ARG1(*answer);
375
376 return (int) rc;
377}
378
[58898d1d]379static int vfs_rdwr(int fd, aoff64_t pos, bool read, rdwr_ipc_cb_t ipc_cb,
380 void *ipc_cb_data)
[861e7d1]381{
382 /*
383 * The following code strongly depends on the fact that the files data
384 * structure can be only accessed by a single fibril and all file
385 * operations are serialized (i.e. the reads and writes cannot
386 * interleave and a file cannot be closed while it is being read).
387 *
388 * Additional synchronization needs to be added once the table of
389 * open files supports parallel access!
390 */
[79ae36dd]391
[72bde81]392 /* Lookup the file structure corresponding to the file descriptor. */
[861e7d1]393 vfs_file_t *file = vfs_file_get(fd);
[e503517a]394 if (!file)
[354b642]395 return EBADF;
[6c89f20]396
[cb65bbe]397 if ((read && !file->open_read) || (!read && !file->open_write)) {
[c577a9a]398 vfs_file_put(file);
[1dff985]399 return EINVAL;
[cb65bbe]400 }
401
[79ae36dd]402 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
403 assert(fs_info);
404
[0d35511]405 bool rlock = read ||
406 (fs_info->concurrent_read_write && fs_info->write_retains_size);
[354b642]407
[861e7d1]408 /*
409 * Lock the file's node so that no other client can read/write to it at
[c2f4b6b]410 * the same time unless the FS supports concurrent reads/writes and its
411 * write implementation does not modify the file size.
[861e7d1]412 */
[61042de]413 if (rlock)
[230260ac]414 fibril_rwlock_read_lock(&file->node->contents_rwlock);
[61042de]415 else
[230260ac]416 fibril_rwlock_write_lock(&file->node->contents_rwlock);
[79ae36dd]417
[b17186d]418 if (file->node->type == VFS_NODE_DIRECTORY) {
419 /*
420 * Make sure that no one is modifying the namespace
421 * while we are in readdir().
422 */
[354b642]423
424 if (!read) {
425 if (rlock) {
[0d35511]426 fibril_rwlock_read_unlock(
427 &file->node->contents_rwlock);
[354b642]428 } else {
[0d35511]429 fibril_rwlock_write_unlock(
430 &file->node->contents_rwlock);
[354b642]431 }
432 vfs_file_put(file);
433 return EINVAL;
434 }
435
[230260ac]436 fibril_rwlock_read_lock(&namespace_rwlock);
[b17186d]437 }
[6c89f20]438
[79ae36dd]439 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
[861e7d1]440
[58898d1d]441 if (!read && file->append) {
442 if (file->node->size == -1)
443 file->node->size = vfs_node_get_size(file->node);
444 pos = file->node->size;
445 }
[42d08592]446
[861e7d1]447 /*
[42d08592]448 * Handle communication with the endpoint FS.
[861e7d1]449 */
[b4cbef1]450 ipc_call_t answer;
[58898d1d]451 int rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data);
[05b9912]452
[79ae36dd]453 vfs_exchange_release(fs_exch);
[34ca870]454
[61042de]455 if (file->node->type == VFS_NODE_DIRECTORY)
[230260ac]456 fibril_rwlock_read_unlock(&namespace_rwlock);
[6c89f20]457
[72bde81]458 /* Unlock the VFS node. */
[354b642]459 if (rlock) {
[230260ac]460 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[354b642]461 } else {
[861e7d1]462 /* Update the cached version of node's size. */
[354b642]463 if (rc == EOK) {
[5bb9907]464 file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
465 IPC_GET_ARG3(answer));
[354b642]466 }
[230260ac]467 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
[861e7d1]468 }
[6c89f20]469
[4fe94c66]470 vfs_file_put(file);
471
[e503517a]472 return rc;
473}
[861e7d1]474
[58898d1d]475int vfs_rdwr_internal(int fd, aoff64_t pos, bool read, rdwr_io_chunk_t *chunk)
[e503517a]476{
[58898d1d]477 return vfs_rdwr(fd, pos, read, rdwr_ipc_internal, chunk);
[e503517a]478}
479
[58898d1d]480int vfs_op_read(int fd, aoff64_t pos, size_t *out_bytes)
[861e7d1]481{
[58898d1d]482 return vfs_rdwr(fd, pos, true, rdwr_ipc_client, out_bytes);
[861e7d1]483}
484
[0d35511]485int vfs_op_rename(int basefd, char *old, char *new)
[861e7d1]486{
[0d35511]487 vfs_file_t *base_file = vfs_file_get(basefd);
[61042de]488 if (!base_file)
[0d35511]489 return EBADF;
[61042de]490
[0d35511]491 vfs_node_t *base = base_file->node;
492 vfs_node_addref(base);
493 vfs_file_put(base_file);
494
495 vfs_lookup_res_t base_lr;
496 vfs_lookup_res_t old_lr;
497 vfs_lookup_res_t new_lr_orig;
498 bool orig_unlinked = false;
499
500 int rc;
501
502 size_t shared = shared_path(old, new);
503
504 /* Do not allow one path to be a prefix of the other. */
505 if (old[shared] == 0 || new[shared] == 0) {
[7f59d6c]506 vfs_node_put(base);
[0d35511]507 return EINVAL;
508 }
509 assert(old[shared] == '/');
510 assert(new[shared] == '/');
511
512 fibril_rwlock_write_lock(&namespace_rwlock);
513
514 /* Resolve the shared portion of the path first. */
515 if (shared != 0) {
516 old[shared] = 0;
517 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
518 if (rc != EOK) {
[7f59d6c]519 vfs_node_put(base);
[0d35511]520 fibril_rwlock_write_unlock(&namespace_rwlock);
521 return rc;
522 }
523
524 vfs_node_put(base);
525 base = vfs_node_get(&base_lr);
[c990ee6]526 if (!base) {
527 fibril_rwlock_write_unlock(&namespace_rwlock);
528 return ENOMEM;
529 }
[0d35511]530 old[shared] = '/';
531 old += shared;
532 new += shared;
533 }
[7f59d6c]534
[61042de]535 rc = vfs_lookup_internal(base, old, L_DISABLE_MOUNTS, &old_lr);
[7f59d6c]536 if (rc != EOK) {
537 vfs_node_put(base);
538 fibril_rwlock_write_unlock(&namespace_rwlock);
539 return rc;
540 }
[0d35511]541
542 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS,
543 &new_lr_orig);
544 if (rc == EOK) {
545 orig_unlinked = true;
546 } else if (rc != ENOENT) {
547 vfs_node_put(base);
548 fibril_rwlock_write_unlock(&namespace_rwlock);
549 return rc;
550 }
[7f59d6c]551
552 rc = vfs_link_internal(base, new, &old_lr.triplet);
[0d35511]553 if (rc != EOK) {
[7f59d6c]554 vfs_link_internal(base, old, &old_lr.triplet);
[61042de]555 if (orig_unlinked)
[0d35511]556 vfs_link_internal(base, new, &new_lr_orig.triplet);
557 vfs_node_put(base);
558 fibril_rwlock_write_unlock(&namespace_rwlock);
559 return rc;
560 }
[7f59d6c]561
562 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS,
563 &old_lr);
[0d35511]564 if (rc != EOK) {
[61042de]565 if (orig_unlinked)
[0d35511]566 vfs_link_internal(base, new, &new_lr_orig.triplet);
567 vfs_node_put(base);
568 fibril_rwlock_write_unlock(&namespace_rwlock);
569 return rc;
570 }
571
572 /* If the node is not held by anyone, try to destroy it. */
[4f9ab1e]573 if (orig_unlinked) {
574 vfs_node_t *node = vfs_node_peek(&new_lr_orig);
575 if (!node)
576 out_destroy(&new_lr_orig.triplet);
577 else
578 vfs_node_put(node);
[0d35511]579 }
580
581 vfs_node_put(base);
582 fibril_rwlock_write_unlock(&namespace_rwlock);
583 return EOK;
[861e7d1]584}
585
[67e881c]586int vfs_op_resize(int fd, int64_t size)
587{
588 vfs_file_t *file = vfs_file_get(fd);
589 if (!file)
590 return EBADF;
591
592 fibril_rwlock_write_lock(&file->node->contents_rwlock);
593
594 int rc = vfs_truncate_internal(file->node->fs_handle,
595 file->node->service_id, file->node->index, size);
596 if (rc == EOK)
597 file->node->size = size;
598
599 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
600 vfs_file_put(file);
601 return rc;
602}
603
[fe91f66]604int vfs_op_stat(int fd)
605{
606 vfs_file_t *file = vfs_file_get(fd);
607 if (!file)
608 return EBADF;
609
610 vfs_node_t *node = file->node;
611
612 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
613 int rc = async_data_read_forward_fast(exch, VFS_OUT_STAT,
614 node->service_id, node->index, true, 0, NULL);
615 vfs_exchange_release(exch);
616
617 vfs_file_put(file);
618 return rc;
619}
620
[0d35511]621int vfs_op_statfs(int fd)
[7fe1f75]622{
[0ee4322]623 vfs_file_t *file = vfs_file_get(fd);
[35e81e2]624 if (!file)
[0d35511]625 return EBADF;
[0ee4322]626
[0d35511]627 vfs_node_t *node = file->node;
628
629 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
[35e81e2]630 int rc = async_data_read_forward_fast(exch, VFS_OUT_STATFS,
631 node->service_id, node->index, false, 0, NULL);
[0d35511]632 vfs_exchange_release(exch);
633
[4fe94c66]634 vfs_file_put(file);
[35e81e2]635 return rc;
[861e7d1]636}
637
[0d35511]638int vfs_op_sync(int fd)
[852b801]639{
640 vfs_file_t *file = vfs_file_get(fd);
[61042de]641 if (!file)
[0d35511]642 return EBADF;
643
644 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
[852b801]645
646 aid_t msg;
[0d35511]647 ipc_call_t answer;
648 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
[61042de]649 file->node->index, &answer);
[79ae36dd]650
[0d35511]651 vfs_exchange_release(fs_exch);
[79ae36dd]652
[0d35511]653 sysarg_t rc;
[852b801]654 async_wait_for(msg, &rc);
[79ae36dd]655
[4fe94c66]656 vfs_file_put(file);
[0d35511]657 return rc;
658
[852b801]659}
660
[0d35511]661static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
662 fs_index_t index, aoff64_t size)
[5bcd5b7]663{
[0d35511]664 async_exch_t *exch = vfs_exchange_grab(fs_handle);
665 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
666 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
667 UPPER32(size));
668 vfs_exchange_release(exch);
669
670 return (int) rc;
[5bcd5b7]671}
672
[79ea5af]673int vfs_op_unlink(int parentfd, int expectfd, char *path)
[0d35511]674{
675 int rc = EOK;
[20c071d]676 vfs_file_t *parent = NULL;
677 vfs_file_t *expect = NULL;
678
[61042de]679 if (parentfd == expectfd)
[0d35511]680 return EINVAL;
[472c09d]681
[20c071d]682 fibril_rwlock_write_lock(&namespace_rwlock);
683
[0d35511]684 /*
685 * Files are retrieved in order of file descriptors, to prevent
686 * deadlock.
687 */
[5126f80]688 if (parentfd < expectfd) {
[20c071d]689 parent = vfs_file_get(parentfd);
690 if (!parent) {
[5126f80]691 rc = EBADF;
[20c071d]692 goto exit;
693 }
694 }
695
696 if (expectfd >= 0) {
697 expect = vfs_file_get(expectfd);
698 if (!expect) {
[0d35511]699 rc = EBADF;
[20c071d]700 goto exit;
701 }
[c577a9a]702 }
703
[5126f80]704 if (parentfd > expectfd) {
[c577a9a]705 parent = vfs_file_get(parentfd);
706 if (!parent) {
[5126f80]707 rc = EBADF;
[c577a9a]708 goto exit;
709 }
710 }
711
[5126f80]712 assert(parent != NULL);
[c577a9a]713
714 if (expectfd >= 0) {
[20c071d]715 vfs_lookup_res_t lr;
[79ea5af]716 rc = vfs_lookup_internal(parent->node, path, 0, &lr);
[61042de]717 if (rc != EOK)
[20c071d]718 goto exit;
719
[4f9ab1e]720 vfs_node_t *found_node = vfs_node_peek(&lr);
721 vfs_node_put(found_node);
[a274a5f]722 if (expect->node != found_node) {
[20c071d]723 rc = ENOENT;
724 goto exit;
725 }
726
727 vfs_file_put(expect);
728 expect = NULL;
729 }
730
[415c7e0d]731 vfs_lookup_res_t lr;
[79ea5af]732 rc = vfs_lookup_internal(parent->node, path, L_UNLINK, &lr);
[61042de]733 if (rc != EOK)
[20c071d]734 goto exit;
735
[5bcd5b7]736 /* If the node is not held by anyone, try to destroy it. */
[4f9ab1e]737 vfs_node_t *node = vfs_node_peek(&lr);
738 if (!node)
[5bcd5b7]739 out_destroy(&lr.triplet);
[4f9ab1e]740 else
741 vfs_node_put(node);
[415c7e0d]742
[20c071d]743exit:
[61042de]744 if (path)
[20c071d]745 free(path);
[61042de]746 if (parent)
[20c071d]747 vfs_file_put(parent);
[61042de]748 if (expect)
[20c071d]749 vfs_file_put(expect);
750 fibril_rwlock_write_unlock(&namespace_rwlock);
[0d35511]751 return rc;
[20c071d]752}
[415c7e0d]753
[0d35511]754int vfs_op_unmount(int mpfd)
[a8e9ab8d]755{
[0d35511]756 vfs_file_t *mp = vfs_file_get(mpfd);
[61042de]757 if (mp == NULL)
[0d35511]758 return EBADF;
[472c09d]759
[0d35511]760 if (mp->node->mount == NULL) {
761 vfs_file_put(mp);
762 return ENOENT;
[a8e9ab8d]763 }
[72bde81]764
[230260ac]765 fibril_rwlock_write_lock(&namespace_rwlock);
[472c09d]766
[0d35511]767 /*
768 * Count the total number of references for the mounted file system. We
769 * are expecting at least one, which is held by the mount point.
770 * If we find more, it means that
771 * the file system cannot be gracefully unmounted at the moment because
772 * someone is working with it.
773 */
774 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle,
775 mp->node->mount->service_id) != 1) {
776 vfs_file_put(mp);
[230260ac]777 fibril_rwlock_write_unlock(&namespace_rwlock);
[0d35511]778 return EBUSY;
[a8e9ab8d]779 }
[472c09d]780
[0d35511]781 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
782 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
783 mp->node->mount->service_id);
784 vfs_exchange_release(exch);
[f15cf1a6]785
786 if (rc != EOK) {
[0d35511]787 vfs_file_put(mp);
[230260ac]788 fibril_rwlock_write_unlock(&namespace_rwlock);
[778d26d]789 return rc;
[f15cf1a6]790 }
[472c09d]791
[0d35511]792 vfs_node_forget(mp->node->mount);
793 vfs_node_put(mp->node);
794 mp->node->mount = NULL;
[472c09d]795
[230260ac]796 fibril_rwlock_write_unlock(&namespace_rwlock);
[0d35511]797
798 vfs_file_put(mp);
[778d26d]799 return EOK;
[f15cf1a6]800}
801
[0d35511]802int vfs_op_wait_handle(bool high_fd)
[a8e9ab8d]803{
[0d35511]804 return vfs_wait_handle_internal(high_fd);
805}
806
807static inline bool walk_flags_valid(int flags)
808{
[61042de]809 if ((flags & ~WALK_ALL_FLAGS) != 0)
[0d35511]810 return false;
[61042de]811 if ((flags & WALK_MAY_CREATE) && (flags & WALK_MUST_CREATE))
[0d35511]812 return false;
[61042de]813 if ((flags & WALK_REGULAR) && (flags & WALK_DIRECTORY))
[0d35511]814 return false;
[4809715]815 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) {
[61042de]816 if (!(flags & WALK_DIRECTORY) && !(flags & WALK_REGULAR))
[0d35511]817 return false;
[a8e9ab8d]818 }
[0d35511]819 return true;
820}
[778d26d]821
[0d35511]822static inline int walk_lookup_flags(int flags)
823{
824 int lflags = 0;
[61042de]825 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE))
[0d35511]826 lflags |= L_CREATE;
[61042de]827 if (flags & WALK_MUST_CREATE)
[0d35511]828 lflags |= L_EXCLUSIVE;
[61042de]829 if (flags & WALK_REGULAR)
[0d35511]830 lflags |= L_FILE;
[61042de]831 if (flags & WALK_DIRECTORY)
[0d35511]832 lflags |= L_DIRECTORY;
[61042de]833 if (flags & WALK_MOUNT_POINT)
[0d35511]834 lflags |= L_MP;
835 return lflags;
[a8e9ab8d]836}
837
[0d35511]838int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd)
[2b88074b]839{
[61042de]840 if (!walk_flags_valid(flags))
[0d35511]841 return EINVAL;
[4fe94c66]842
[0d35511]843 vfs_file_t *parent = vfs_file_get(parentfd);
[61042de]844 if (!parent)
[0d35511]845 return EBADF;
[2b88074b]846
[0d35511]847 fibril_rwlock_read_lock(&namespace_rwlock);
[2b88074b]848
[0d35511]849 vfs_lookup_res_t lr;
850 int rc = vfs_lookup_internal(parent->node, path,
851 walk_lookup_flags(flags), &lr);
852 if (rc != EOK) {
853 fibril_rwlock_read_unlock(&namespace_rwlock);
854 vfs_file_put(parent);
855 return rc;
[76a67ce]856 }
[9dc6083]857
[0d35511]858 vfs_node_t *node = vfs_node_get(&lr);
[c990ee6]859 if (!node) {
860 fibril_rwlock_read_unlock(&namespace_rwlock);
861 vfs_file_put(parent);
862 return ENOMEM;
863 }
[9dc6083]864
[0d35511]865 vfs_file_t *file;
866 int fd = vfs_fd_alloc(&file, false);
867 if (fd < 0) {
868 vfs_node_put(node);
869 vfs_file_put(parent);
870 return fd;
871 }
872 assert(file != NULL);
[9dc6083]873
[0d35511]874 file->node = node;
875 file->permissions = parent->permissions;
876 file->open_read = false;
877 file->open_write = false;
[9dc6083]878
[a737667e]879 vfs_file_put(file);
[0d35511]880 vfs_file_put(parent);
881
882 fibril_rwlock_read_unlock(&namespace_rwlock);
[9dc6083]883
[0d35511]884 *out_fd = fd;
885 return EOK;
[66366470]886}
887
[58898d1d]888int vfs_op_write(int fd, aoff64_t pos, size_t *out_bytes)
[354b642]889{
[58898d1d]890 return vfs_rdwr(fd, pos, false, rdwr_ipc_client, out_bytes);
[354b642]891}
892
[861e7d1]893/**
894 * @}
[05b9912]895 */
Note: See TracBrowser for help on using the repository browser.