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

Last change on this file since bcd7775 was 7fa8589, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

Removing unneeded casts from errno_t to errno_t

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