source: mainline/uspace/srv/vfs/vfs_ops.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@…>, 8 years ago

Reintroduce aoff64_t file sizes into VFS

  • Property mode set to 100644
File size: 20.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>
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
[9c4cf0d]126int vfs_op_put(int fd)
[0d35511]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
[51774cd]441 if (!read && file->append)
[58898d1d]442 pos = file->node->size;
[42d08592]443
[861e7d1]444 /*
[42d08592]445 * Handle communication with the endpoint FS.
[861e7d1]446 */
[b4cbef1]447 ipc_call_t answer;
[58898d1d]448 int rc = ipc_cb(fs_exch, file, pos, &answer, read, ipc_cb_data);
[05b9912]449
[79ae36dd]450 vfs_exchange_release(fs_exch);
[34ca870]451
[61042de]452 if (file->node->type == VFS_NODE_DIRECTORY)
[230260ac]453 fibril_rwlock_read_unlock(&namespace_rwlock);
[6c89f20]454
[72bde81]455 /* Unlock the VFS node. */
[354b642]456 if (rlock) {
[230260ac]457 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[354b642]458 } else {
[861e7d1]459 /* Update the cached version of node's size. */
[354b642]460 if (rc == EOK) {
[5bb9907]461 file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
462 IPC_GET_ARG3(answer));
[354b642]463 }
[230260ac]464 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
[861e7d1]465 }
[6c89f20]466
[4fe94c66]467 vfs_file_put(file);
468
[e503517a]469 return rc;
470}
[861e7d1]471
[58898d1d]472int vfs_rdwr_internal(int fd, aoff64_t pos, bool read, rdwr_io_chunk_t *chunk)
[e503517a]473{
[58898d1d]474 return vfs_rdwr(fd, pos, read, rdwr_ipc_internal, chunk);
[e503517a]475}
476
[58898d1d]477int vfs_op_read(int fd, aoff64_t pos, size_t *out_bytes)
[861e7d1]478{
[58898d1d]479 return vfs_rdwr(fd, pos, true, rdwr_ipc_client, out_bytes);
[861e7d1]480}
481
[0d35511]482int vfs_op_rename(int basefd, char *old, char *new)
[861e7d1]483{
[0d35511]484 vfs_file_t *base_file = vfs_file_get(basefd);
[61042de]485 if (!base_file)
[0d35511]486 return EBADF;
[61042de]487
[0d35511]488 vfs_node_t *base = base_file->node;
489 vfs_node_addref(base);
490 vfs_file_put(base_file);
491
492 vfs_lookup_res_t base_lr;
493 vfs_lookup_res_t old_lr;
494 vfs_lookup_res_t new_lr_orig;
495 bool orig_unlinked = false;
496
497 int rc;
498
499 size_t shared = shared_path(old, new);
500
501 /* Do not allow one path to be a prefix of the other. */
502 if (old[shared] == 0 || new[shared] == 0) {
[7f59d6c]503 vfs_node_put(base);
[0d35511]504 return EINVAL;
505 }
506 assert(old[shared] == '/');
507 assert(new[shared] == '/');
508
509 fibril_rwlock_write_lock(&namespace_rwlock);
510
511 /* Resolve the shared portion of the path first. */
512 if (shared != 0) {
513 old[shared] = 0;
514 rc = vfs_lookup_internal(base, old, L_DIRECTORY, &base_lr);
515 if (rc != EOK) {
[7f59d6c]516 vfs_node_put(base);
[0d35511]517 fibril_rwlock_write_unlock(&namespace_rwlock);
518 return rc;
519 }
520
521 vfs_node_put(base);
522 base = vfs_node_get(&base_lr);
[c990ee6]523 if (!base) {
524 fibril_rwlock_write_unlock(&namespace_rwlock);
525 return ENOMEM;
526 }
[0d35511]527 old[shared] = '/';
528 old += shared;
529 new += shared;
530 }
[7f59d6c]531
[61042de]532 rc = vfs_lookup_internal(base, old, L_DISABLE_MOUNTS, &old_lr);
[7f59d6c]533 if (rc != EOK) {
534 vfs_node_put(base);
535 fibril_rwlock_write_unlock(&namespace_rwlock);
536 return rc;
537 }
[0d35511]538
539 rc = vfs_lookup_internal(base, new, L_UNLINK | L_DISABLE_MOUNTS,
540 &new_lr_orig);
541 if (rc == EOK) {
542 orig_unlinked = true;
543 } else if (rc != ENOENT) {
544 vfs_node_put(base);
545 fibril_rwlock_write_unlock(&namespace_rwlock);
546 return rc;
547 }
[7f59d6c]548
549 rc = vfs_link_internal(base, new, &old_lr.triplet);
[0d35511]550 if (rc != EOK) {
[7f59d6c]551 vfs_link_internal(base, old, &old_lr.triplet);
[61042de]552 if (orig_unlinked)
[0d35511]553 vfs_link_internal(base, new, &new_lr_orig.triplet);
554 vfs_node_put(base);
555 fibril_rwlock_write_unlock(&namespace_rwlock);
556 return rc;
557 }
[7f59d6c]558
559 rc = vfs_lookup_internal(base, old, L_UNLINK | L_DISABLE_MOUNTS,
560 &old_lr);
[0d35511]561 if (rc != EOK) {
[61042de]562 if (orig_unlinked)
[0d35511]563 vfs_link_internal(base, new, &new_lr_orig.triplet);
564 vfs_node_put(base);
565 fibril_rwlock_write_unlock(&namespace_rwlock);
566 return rc;
567 }
568
569 /* If the node is not held by anyone, try to destroy it. */
[4f9ab1e]570 if (orig_unlinked) {
571 vfs_node_t *node = vfs_node_peek(&new_lr_orig);
572 if (!node)
573 out_destroy(&new_lr_orig.triplet);
574 else
575 vfs_node_put(node);
[0d35511]576 }
577
578 vfs_node_put(base);
579 fibril_rwlock_write_unlock(&namespace_rwlock);
580 return EOK;
[861e7d1]581}
582
[67e881c]583int vfs_op_resize(int fd, int64_t size)
584{
585 vfs_file_t *file = vfs_file_get(fd);
586 if (!file)
587 return EBADF;
588
589 fibril_rwlock_write_lock(&file->node->contents_rwlock);
590
591 int rc = vfs_truncate_internal(file->node->fs_handle,
592 file->node->service_id, file->node->index, size);
593 if (rc == EOK)
594 file->node->size = size;
595
596 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
597 vfs_file_put(file);
598 return rc;
599}
600
[fe91f66]601int vfs_op_stat(int fd)
602{
603 vfs_file_t *file = vfs_file_get(fd);
604 if (!file)
605 return EBADF;
606
607 vfs_node_t *node = file->node;
608
609 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
610 int rc = async_data_read_forward_fast(exch, VFS_OUT_STAT,
611 node->service_id, node->index, true, 0, NULL);
612 vfs_exchange_release(exch);
613
614 vfs_file_put(file);
615 return rc;
616}
617
[0d35511]618int vfs_op_statfs(int fd)
[7fe1f75]619{
[0ee4322]620 vfs_file_t *file = vfs_file_get(fd);
[35e81e2]621 if (!file)
[0d35511]622 return EBADF;
[0ee4322]623
[0d35511]624 vfs_node_t *node = file->node;
625
626 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
[35e81e2]627 int rc = async_data_read_forward_fast(exch, VFS_OUT_STATFS,
628 node->service_id, node->index, false, 0, NULL);
[0d35511]629 vfs_exchange_release(exch);
630
[4fe94c66]631 vfs_file_put(file);
[35e81e2]632 return rc;
[861e7d1]633}
634
[0d35511]635int vfs_op_sync(int fd)
[852b801]636{
637 vfs_file_t *file = vfs_file_get(fd);
[61042de]638 if (!file)
[0d35511]639 return EBADF;
640
641 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
[852b801]642
643 aid_t msg;
[0d35511]644 ipc_call_t answer;
645 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
[61042de]646 file->node->index, &answer);
[79ae36dd]647
[0d35511]648 vfs_exchange_release(fs_exch);
[79ae36dd]649
[0d35511]650 sysarg_t rc;
[852b801]651 async_wait_for(msg, &rc);
[79ae36dd]652
[4fe94c66]653 vfs_file_put(file);
[0d35511]654 return rc;
655
[852b801]656}
657
[0d35511]658static int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
659 fs_index_t index, aoff64_t size)
[5bcd5b7]660{
[0d35511]661 async_exch_t *exch = vfs_exchange_grab(fs_handle);
662 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
663 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
664 UPPER32(size));
665 vfs_exchange_release(exch);
666
667 return (int) rc;
[5bcd5b7]668}
669
[79ea5af]670int vfs_op_unlink(int parentfd, int expectfd, char *path)
[0d35511]671{
672 int rc = EOK;
[20c071d]673 vfs_file_t *parent = NULL;
674 vfs_file_t *expect = NULL;
675
[61042de]676 if (parentfd == expectfd)
[0d35511]677 return EINVAL;
[472c09d]678
[20c071d]679 fibril_rwlock_write_lock(&namespace_rwlock);
680
[0d35511]681 /*
682 * Files are retrieved in order of file descriptors, to prevent
683 * deadlock.
684 */
[5126f80]685 if (parentfd < expectfd) {
[20c071d]686 parent = vfs_file_get(parentfd);
687 if (!parent) {
[5126f80]688 rc = EBADF;
[20c071d]689 goto exit;
690 }
691 }
692
693 if (expectfd >= 0) {
694 expect = vfs_file_get(expectfd);
695 if (!expect) {
[0d35511]696 rc = EBADF;
[20c071d]697 goto exit;
698 }
[c577a9a]699 }
700
[5126f80]701 if (parentfd > expectfd) {
[c577a9a]702 parent = vfs_file_get(parentfd);
703 if (!parent) {
[5126f80]704 rc = EBADF;
[c577a9a]705 goto exit;
706 }
707 }
708
[5126f80]709 assert(parent != NULL);
[c577a9a]710
711 if (expectfd >= 0) {
[20c071d]712 vfs_lookup_res_t lr;
[79ea5af]713 rc = vfs_lookup_internal(parent->node, path, 0, &lr);
[61042de]714 if (rc != EOK)
[20c071d]715 goto exit;
716
[4f9ab1e]717 vfs_node_t *found_node = vfs_node_peek(&lr);
718 vfs_node_put(found_node);
[a274a5f]719 if (expect->node != found_node) {
[20c071d]720 rc = ENOENT;
721 goto exit;
722 }
723
724 vfs_file_put(expect);
725 expect = NULL;
726 }
727
[415c7e0d]728 vfs_lookup_res_t lr;
[79ea5af]729 rc = vfs_lookup_internal(parent->node, path, L_UNLINK, &lr);
[61042de]730 if (rc != EOK)
[20c071d]731 goto exit;
732
[5bcd5b7]733 /* If the node is not held by anyone, try to destroy it. */
[4f9ab1e]734 vfs_node_t *node = vfs_node_peek(&lr);
735 if (!node)
[5bcd5b7]736 out_destroy(&lr.triplet);
[4f9ab1e]737 else
738 vfs_node_put(node);
[415c7e0d]739
[20c071d]740exit:
[61042de]741 if (path)
[20c071d]742 free(path);
[61042de]743 if (parent)
[20c071d]744 vfs_file_put(parent);
[61042de]745 if (expect)
[20c071d]746 vfs_file_put(expect);
747 fibril_rwlock_write_unlock(&namespace_rwlock);
[0d35511]748 return rc;
[20c071d]749}
[415c7e0d]750
[0d35511]751int vfs_op_unmount(int mpfd)
[a8e9ab8d]752{
[0d35511]753 vfs_file_t *mp = vfs_file_get(mpfd);
[61042de]754 if (mp == NULL)
[0d35511]755 return EBADF;
[472c09d]756
[0d35511]757 if (mp->node->mount == NULL) {
758 vfs_file_put(mp);
759 return ENOENT;
[a8e9ab8d]760 }
[72bde81]761
[230260ac]762 fibril_rwlock_write_lock(&namespace_rwlock);
[472c09d]763
[0d35511]764 /*
765 * Count the total number of references for the mounted file system. We
766 * are expecting at least one, which is held by the mount point.
767 * If we find more, it means that
768 * the file system cannot be gracefully unmounted at the moment because
769 * someone is working with it.
770 */
771 if (vfs_nodes_refcount_sum_get(mp->node->mount->fs_handle,
772 mp->node->mount->service_id) != 1) {
773 vfs_file_put(mp);
[230260ac]774 fibril_rwlock_write_unlock(&namespace_rwlock);
[0d35511]775 return EBUSY;
[a8e9ab8d]776 }
[472c09d]777
[0d35511]778 async_exch_t *exch = vfs_exchange_grab(mp->node->mount->fs_handle);
779 int rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
780 mp->node->mount->service_id);
781 vfs_exchange_release(exch);
[f15cf1a6]782
783 if (rc != EOK) {
[0d35511]784 vfs_file_put(mp);
[230260ac]785 fibril_rwlock_write_unlock(&namespace_rwlock);
[778d26d]786 return rc;
[f15cf1a6]787 }
[472c09d]788
[0d35511]789 vfs_node_forget(mp->node->mount);
790 vfs_node_put(mp->node);
791 mp->node->mount = NULL;
[472c09d]792
[230260ac]793 fibril_rwlock_write_unlock(&namespace_rwlock);
[0d35511]794
795 vfs_file_put(mp);
[778d26d]796 return EOK;
[f15cf1a6]797}
798
[0d35511]799int vfs_op_wait_handle(bool high_fd)
[a8e9ab8d]800{
[0d35511]801 return vfs_wait_handle_internal(high_fd);
802}
803
804static inline bool walk_flags_valid(int flags)
805{
[61042de]806 if ((flags & ~WALK_ALL_FLAGS) != 0)
[0d35511]807 return false;
[61042de]808 if ((flags & WALK_MAY_CREATE) && (flags & WALK_MUST_CREATE))
[0d35511]809 return false;
[61042de]810 if ((flags & WALK_REGULAR) && (flags & WALK_DIRECTORY))
[0d35511]811 return false;
[4809715]812 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE)) {
[61042de]813 if (!(flags & WALK_DIRECTORY) && !(flags & WALK_REGULAR))
[0d35511]814 return false;
[a8e9ab8d]815 }
[0d35511]816 return true;
817}
[778d26d]818
[0d35511]819static inline int walk_lookup_flags(int flags)
820{
821 int lflags = 0;
[61042de]822 if ((flags & WALK_MAY_CREATE) || (flags & WALK_MUST_CREATE))
[0d35511]823 lflags |= L_CREATE;
[61042de]824 if (flags & WALK_MUST_CREATE)
[0d35511]825 lflags |= L_EXCLUSIVE;
[61042de]826 if (flags & WALK_REGULAR)
[0d35511]827 lflags |= L_FILE;
[61042de]828 if (flags & WALK_DIRECTORY)
[0d35511]829 lflags |= L_DIRECTORY;
[61042de]830 if (flags & WALK_MOUNT_POINT)
[0d35511]831 lflags |= L_MP;
832 return lflags;
[a8e9ab8d]833}
834
[0d35511]835int vfs_op_walk(int parentfd, int flags, char *path, int *out_fd)
[2b88074b]836{
[61042de]837 if (!walk_flags_valid(flags))
[0d35511]838 return EINVAL;
[4fe94c66]839
[0d35511]840 vfs_file_t *parent = vfs_file_get(parentfd);
[61042de]841 if (!parent)
[0d35511]842 return EBADF;
[2b88074b]843
[0d35511]844 fibril_rwlock_read_lock(&namespace_rwlock);
[2b88074b]845
[0d35511]846 vfs_lookup_res_t lr;
847 int rc = vfs_lookup_internal(parent->node, path,
848 walk_lookup_flags(flags), &lr);
849 if (rc != EOK) {
850 fibril_rwlock_read_unlock(&namespace_rwlock);
851 vfs_file_put(parent);
852 return rc;
[76a67ce]853 }
[9dc6083]854
[0d35511]855 vfs_node_t *node = vfs_node_get(&lr);
[c990ee6]856 if (!node) {
857 fibril_rwlock_read_unlock(&namespace_rwlock);
858 vfs_file_put(parent);
859 return ENOMEM;
860 }
[9dc6083]861
[0d35511]862 vfs_file_t *file;
863 int fd = vfs_fd_alloc(&file, false);
864 if (fd < 0) {
865 vfs_node_put(node);
866 vfs_file_put(parent);
867 return fd;
868 }
869 assert(file != NULL);
[9dc6083]870
[0d35511]871 file->node = node;
872 file->permissions = parent->permissions;
873 file->open_read = false;
874 file->open_write = false;
[9dc6083]875
[a737667e]876 vfs_file_put(file);
[0d35511]877 vfs_file_put(parent);
878
879 fibril_rwlock_read_unlock(&namespace_rwlock);
[9dc6083]880
[0d35511]881 *out_fd = fd;
882 return EOK;
[66366470]883}
884
[58898d1d]885int vfs_op_write(int fd, aoff64_t pos, size_t *out_bytes)
[354b642]886{
[58898d1d]887 return vfs_rdwr(fd, pos, false, rdwr_ipc_client, out_bytes);
[354b642]888}
889
[861e7d1]890/**
891 * @}
[05b9912]892 */
Note: See TracBrowser for help on using the repository browser.