source: mainline/uspace/srv/vfs/vfs_ops.c@ 54de4836

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

Cstyle fixes and cleanup.

  • Property mode set to 100644
File size: 32.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>
[861e7d1]46#include <bool.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>
[861e7d1]54
[7fe1f75]55/* Forward declarations of static functions. */
[15f3c3f]56static int vfs_truncate_internal(fs_handle_t, service_id_t, fs_index_t,
[8df8415]57 aoff64_t);
[7fe1f75]58
[861e7d1]59/**
60 * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
61 * concurrent VFS operation which modifies the file system namespace.
62 */
[230260ac]63FIBRIL_RWLOCK_INITIALIZE(namespace_rwlock);
[861e7d1]64
[f49b0ea]65vfs_pair_t rootfs = {
[861e7d1]66 .fs_handle = 0,
[15f3c3f]67 .service_id = 0
[861e7d1]68};
69
[15f3c3f]70static void vfs_mount_internal(ipc_callid_t rid, service_id_t service_id,
[594303b]71 fs_handle_t fs_handle, char *mp, char *opts)
[861e7d1]72{
[8dc72b64]73 vfs_lookup_res_t mp_res;
[83937ccd]74 vfs_lookup_res_t mr_res;
[861e7d1]75 vfs_node_t *mp_node = NULL;
[83937ccd]76 vfs_node_t *mr_node;
77 fs_index_t rindex;
[7eb0fed8]78 aoff64_t rsize;
[83937ccd]79 unsigned rlnkcnt;
[79ae36dd]80 async_exch_t *exch;
[96b02eb9]81 sysarg_t rc;
[594303b]82 aid_t msg;
83 ipc_call_t answer;
[05b9912]84
[594303b]85 /* Resolve the path to the mountpoint. */
[230260ac]86 fibril_rwlock_write_lock(&namespace_rwlock);
[861e7d1]87 if (rootfs.fs_handle) {
[72bde81]88 /* We already have the root FS. */
[92fd52d7]89 if (str_cmp(mp, "/") == 0) {
[2f60a529]90 /* Trying to mount root FS over root FS */
[230260ac]91 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]92 async_answer_0(rid, EBUSY);
[2f60a529]93 return;
94 }
[8dc72b64]95
[ea44bd1]96 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
[861e7d1]97 if (rc != EOK) {
[72bde81]98 /* The lookup failed for some reason. */
[230260ac]99 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]100 async_answer_0(rid, rc);
[861e7d1]101 return;
102 }
[8dc72b64]103
[eb27ce5a]104 mp_node = vfs_node_get(&mp_res);
[861e7d1]105 if (!mp_node) {
[230260ac]106 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]107 async_answer_0(rid, ENOMEM);
[861e7d1]108 return;
109 }
[8dc72b64]110
[861e7d1]111 /*
112 * Now we hold a reference to mp_node.
[4198f9c3]113 * It will be dropped upon the corresponding VFS_IN_UNMOUNT.
[861e7d1]114 * This prevents the mount point from being deleted.
115 */
116 } else {
[72bde81]117 /* We still don't have the root file system mounted. */
[92fd52d7]118 if (str_cmp(mp, "/") == 0) {
[64b67c3]119 /*
120 * For this simple, but important case,
121 * we are almost done.
122 */
123
[f49b0ea]124 /* Tell the mountee that it is being mounted. */
[79ae36dd]125 exch = vfs_exchange_grab(fs_handle);
126 msg = async_send_1(exch, VFS_OUT_MOUNTED,
[15f3c3f]127 (sysarg_t) service_id, &answer);
[79ae36dd]128 /* Send the mount options */
129 rc = async_data_write_start(exch, (void *)opts,
[594303b]130 str_size(opts));
[79ae36dd]131 vfs_exchange_release(exch);
132
[594303b]133 if (rc != EOK) {
[230260ac]134 async_wait_for(msg, NULL);
135 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]136 async_answer_0(rid, rc);
[594303b]137 return;
138 }
[230260ac]139 async_wait_for(msg, &rc);
[5ab597d]140
141 if (rc != EOK) {
[230260ac]142 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]143 async_answer_0(rid, rc);
[5ab597d]144 return;
[f49b0ea]145 }
[594303b]146
147 rindex = (fs_index_t) IPC_GET_ARG1(answer);
[286286c]148 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
149 IPC_GET_ARG3(answer));
[7eb0fed8]150 rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
[8dc72b64]151
[5ab597d]152 mr_res.triplet.fs_handle = fs_handle;
[15f3c3f]153 mr_res.triplet.service_id = service_id;
[594303b]154 mr_res.triplet.index = rindex;
155 mr_res.size = rsize;
156 mr_res.lnkcnt = rlnkcnt;
[b17186d]157 mr_res.type = VFS_NODE_DIRECTORY;
[8dc72b64]158
[5ab597d]159 rootfs.fs_handle = fs_handle;
[15f3c3f]160 rootfs.service_id = service_id;
[8dc72b64]161
[5ab597d]162 /* Add reference to the mounted root. */
163 mr_node = vfs_node_get(&mr_res);
164 assert(mr_node);
[8dc72b64]165
[230260ac]166 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]167 async_answer_0(rid, rc);
[861e7d1]168 return;
169 } else {
170 /*
171 * We can't resolve this without the root filesystem
172 * being mounted first.
173 */
[230260ac]174 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]175 async_answer_0(rid, ENOENT);
[861e7d1]176 return;
177 }
178 }
179
180 /*
[15f3c3f]181 * At this point, we have all necessary pieces: file system handle
182 * and service ID, and we know the mount point VFS node.
[861e7d1]183 */
[8dc72b64]184
[79ae36dd]185 async_exch_t *mountee_exch = vfs_exchange_grab(fs_handle);
186 assert(mountee_exch);
187
188 exch = vfs_exchange_grab(mp_res.triplet.fs_handle);
189 msg = async_send_4(exch, VFS_OUT_MOUNT,
[15f3c3f]190 (sysarg_t) mp_res.triplet.service_id,
[96b02eb9]191 (sysarg_t) mp_res.triplet.index,
192 (sysarg_t) fs_handle,
[15f3c3f]193 (sysarg_t) service_id, &answer);
[83937ccd]194
[79ae36dd]195 /* Send connection */
196 rc = async_exchange_clone(exch, mountee_exch);
197 vfs_exchange_release(mountee_exch);
198
[83937ccd]199 if (rc != EOK) {
[79ae36dd]200 vfs_exchange_release(exch);
[230260ac]201 async_wait_for(msg, NULL);
[79ae36dd]202
[83937ccd]203 /* Mount failed, drop reference to mp_node. */
204 if (mp_node)
205 vfs_node_put(mp_node);
[79ae36dd]206
[ffa2c8ef]207 async_answer_0(rid, rc);
[230260ac]208 fibril_rwlock_write_unlock(&namespace_rwlock);
[83937ccd]209 return;
210 }
211
[594303b]212 /* send the mount options */
[79ae36dd]213 rc = async_data_write_start(exch, (void *) opts, str_size(opts));
[594303b]214 if (rc != EOK) {
[79ae36dd]215 vfs_exchange_release(exch);
[230260ac]216 async_wait_for(msg, NULL);
[79ae36dd]217
[594303b]218 /* Mount failed, drop reference to mp_node. */
219 if (mp_node)
220 vfs_node_put(mp_node);
[79ae36dd]221
[230260ac]222 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]223 async_answer_0(rid, rc);
[594303b]224 return;
225 }
[79ae36dd]226
[c69646f8]227 /*
228 * Wait for the answer before releasing the exchange to avoid deadlock
229 * in case the answer depends on further calls to the same file system.
230 * Think of a case when mounting a FS on a file_bd backed by a file on
231 * the same FS.
232 */
[230260ac]233 async_wait_for(msg, &rc);
[c69646f8]234 vfs_exchange_release(exch);
[8dc72b64]235
[493853ec]236 if (rc == EOK) {
237 rindex = (fs_index_t) IPC_GET_ARG1(answer);
[7eb0fed8]238 rsize = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(answer),
239 IPC_GET_ARG3(answer));
240 rlnkcnt = (unsigned) IPC_GET_ARG4(answer);
[79ae36dd]241
[493853ec]242 mr_res.triplet.fs_handle = fs_handle;
[15f3c3f]243 mr_res.triplet.service_id = service_id;
[493853ec]244 mr_res.triplet.index = rindex;
245 mr_res.size = rsize;
246 mr_res.lnkcnt = rlnkcnt;
247 mr_res.type = VFS_NODE_DIRECTORY;
[79ae36dd]248
[493853ec]249 /* Add reference to the mounted root. */
250 mr_node = vfs_node_get(&mr_res);
251 assert(mr_node);
252 } else {
[f49b0ea]253 /* Mount failed, drop reference to mp_node. */
[861e7d1]254 if (mp_node)
255 vfs_node_put(mp_node);
256 }
[79ae36dd]257
[ffa2c8ef]258 async_answer_0(rid, rc);
[230260ac]259 fibril_rwlock_write_unlock(&namespace_rwlock);
[861e7d1]260}
261
[8dc72b64]262void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
263{
[15f3c3f]264 service_id_t service_id;
[8df8415]265
[8dc72b64]266 /*
267 * We expect the library to do the device-name to device-handle
268 * translation for us, thus the device handle will arrive as ARG1
269 * in the request.
270 */
[15f3c3f]271 service_id = (service_id_t) IPC_GET_ARG1(*request);
[8dc72b64]272
273 /*
274 * Mount flags are passed as ARG2.
275 */
276 unsigned int flags = (unsigned int) IPC_GET_ARG2(*request);
277
[4979403]278 /*
279 * Instance number is passed as ARG3.
280 */
281 unsigned int instance = IPC_GET_ARG3(*request);
282
[8dc72b64]283 /* We want the client to send us the mount point. */
[472c09d]284 char *mp;
[4cac2d69]285 int rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
[eda925a]286 0, NULL);
[472c09d]287 if (rc != EOK) {
[ffa2c8ef]288 async_answer_0(rid, rc);
[8dc72b64]289 return;
290 }
291
[594303b]292 /* Now we expect to receive the mount options. */
[472c09d]293 char *opts;
[4cac2d69]294 rc = async_data_write_accept((void **) &opts, true, 0, MAX_MNTOPTS_LEN,
[eda925a]295 0, NULL);
[472c09d]296 if (rc != EOK) {
[594303b]297 free(mp);
[ffa2c8ef]298 async_answer_0(rid, rc);
[594303b]299 return;
300 }
301
[8dc72b64]302 /*
303 * Now, we expect the client to send us data with the name of the file
304 * system.
305 */
[472c09d]306 char *fs_name;
[8df8415]307 rc = async_data_write_accept((void **) &fs_name, true, 0,
308 FS_NAME_MAXLEN, 0, NULL);
[472c09d]309 if (rc != EOK) {
[8dc72b64]310 free(mp);
[594303b]311 free(opts);
[ffa2c8ef]312 async_answer_0(rid, rc);
[8dc72b64]313 return;
314 }
315
[c08c355]316 /*
[79ae36dd]317 * Wait for VFS_IN_PING so that we can return an error if we don't know
[c08c355]318 * fs_name.
319 */
320 ipc_call_t data;
[472c09d]321 ipc_callid_t callid = async_get_call(&data);
[79ae36dd]322 if (IPC_GET_IMETHOD(data) != VFS_IN_PING) {
[ffa2c8ef]323 async_answer_0(callid, ENOTSUP);
324 async_answer_0(rid, ENOTSUP);
[c08c355]325 free(mp);
[594303b]326 free(opts);
[c08c355]327 free(fs_name);
328 return;
329 }
330
[8dc72b64]331 /*
332 * Check if we know a file system with the same name as is in fs_name.
333 * This will also give us its file system handle.
334 */
[b72efe8]335 fibril_mutex_lock(&fs_list_lock);
[7b47fa2]336 fs_handle_t fs_handle;
337recheck:
[4979403]338 fs_handle = fs_name_to_handle(instance, fs_name, false);
[8dc72b64]339 if (!fs_handle) {
340 if (flags & IPC_FLAG_BLOCKING) {
[b72efe8]341 fibril_condvar_wait(&fs_list_cv, &fs_list_lock);
[7b47fa2]342 goto recheck;
[8dc72b64]343 }
344
[b72efe8]345 fibril_mutex_unlock(&fs_list_lock);
[ffa2c8ef]346 async_answer_0(callid, ENOENT);
347 async_answer_0(rid, ENOENT);
[8dc72b64]348 free(mp);
349 free(fs_name);
[594303b]350 free(opts);
[8dc72b64]351 return;
352 }
[b72efe8]353 fibril_mutex_unlock(&fs_list_lock);
[8dc72b64]354
355 /* Acknowledge that we know fs_name. */
[ffa2c8ef]356 async_answer_0(callid, EOK);
[8dc72b64]357
358 /* Do the mount */
[15f3c3f]359 vfs_mount_internal(rid, service_id, fs_handle, mp, opts);
[8dc72b64]360 free(mp);
361 free(fs_name);
[594303b]362 free(opts);
[8dc72b64]363}
364
[7f5e070]365void vfs_unmount(ipc_callid_t rid, ipc_call_t *request)
366{
[ae75e2e3]367 int rc;
368 char *mp;
369 vfs_lookup_res_t mp_res;
370 vfs_lookup_res_t mr_res;
371 vfs_node_t *mr_node;
[79ae36dd]372 async_exch_t *exch;
373
[ae75e2e3]374 /*
375 * Receive the mount point path.
376 */
[4cac2d69]377 rc = async_data_write_accept((void **) &mp, true, 0, MAX_PATH_LEN,
[eda925a]378 0, NULL);
[ae75e2e3]379 if (rc != EOK)
[ffa2c8ef]380 async_answer_0(rid, rc);
[79ae36dd]381
[ae75e2e3]382 /*
383 * Taking the namespace lock will do two things for us. First, it will
384 * prevent races with other lookup operations. Second, it will stop new
385 * references to already existing VFS nodes and creation of new VFS
386 * nodes. This is because new references are added as a result of some
387 * lookup operation or at least of some operation which is protected by
388 * the namespace lock.
389 */
390 fibril_rwlock_write_lock(&namespace_rwlock);
391
392 /*
393 * Lookup the mounted root and instantiate it.
394 */
[f7376cbf]395 rc = vfs_lookup_internal(mp, L_ROOT, &mr_res, NULL);
[ae75e2e3]396 if (rc != EOK) {
397 fibril_rwlock_write_unlock(&namespace_rwlock);
398 free(mp);
[ffa2c8ef]399 async_answer_0(rid, rc);
[ae75e2e3]400 return;
401 }
402 mr_node = vfs_node_get(&mr_res);
403 if (!mr_node) {
404 fibril_rwlock_write_unlock(&namespace_rwlock);
405 free(mp);
[ffa2c8ef]406 async_answer_0(rid, ENOMEM);
[ae75e2e3]407 return;
408 }
[79ae36dd]409
[ae75e2e3]410 /*
411 * Count the total number of references for the mounted file system. We
412 * are expecting at least two. One which we got above and one which we
413 * got when the file system was mounted. If we find more, it means that
414 * the file system cannot be gracefully unmounted at the moment because
415 * someone is working with it.
416 */
417 if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
[15f3c3f]418 mr_node->service_id) != 2) {
[ae75e2e3]419 fibril_rwlock_write_unlock(&namespace_rwlock);
420 vfs_node_put(mr_node);
421 free(mp);
[ffa2c8ef]422 async_answer_0(rid, EBUSY);
[ae75e2e3]423 return;
424 }
[79ae36dd]425
[ae75e2e3]426 if (str_cmp(mp, "/") == 0) {
[79ae36dd]427
[ae75e2e3]428 /*
429 * Unmounting the root file system.
430 *
431 * In this case, there is no mount point node and we send
432 * VFS_OUT_UNMOUNTED directly to the mounted file system.
433 */
[79ae36dd]434
[ae75e2e3]435 free(mp);
[79ae36dd]436
437 exch = vfs_exchange_grab(mr_node->fs_handle);
438 rc = async_req_1_0(exch, VFS_OUT_UNMOUNTED,
[15f3c3f]439 mr_node->service_id);
[79ae36dd]440 vfs_exchange_release(exch);
441
[ae75e2e3]442 if (rc != EOK) {
443 fibril_rwlock_write_unlock(&namespace_rwlock);
444 vfs_node_put(mr_node);
[ffa2c8ef]445 async_answer_0(rid, rc);
[ae75e2e3]446 return;
447 }
[79ae36dd]448
[ae75e2e3]449 rootfs.fs_handle = 0;
[15f3c3f]450 rootfs.service_id = 0;
[ae75e2e3]451 } else {
[79ae36dd]452
[ae75e2e3]453 /*
454 * Unmounting a non-root file system.
455 *
456 * We have a regular mount point node representing the parent
457 * file system, so we delegate the operation to it.
458 */
[79ae36dd]459
[f7376cbf]460 rc = vfs_lookup_internal(mp, L_MP, &mp_res, NULL);
[ae75e2e3]461 free(mp);
462 if (rc != EOK) {
463 fibril_rwlock_write_unlock(&namespace_rwlock);
464 vfs_node_put(mr_node);
[ffa2c8ef]465 async_answer_0(rid, rc);
[ae75e2e3]466 return;
467 }
[79ae36dd]468
[ae75e2e3]469 vfs_node_t *mp_node = vfs_node_get(&mp_res);
470 if (!mp_node) {
471 fibril_rwlock_write_unlock(&namespace_rwlock);
472 vfs_node_put(mr_node);
[ffa2c8ef]473 async_answer_0(rid, ENOMEM);
[ae75e2e3]474 return;
475 }
[79ae36dd]476
477 exch = vfs_exchange_grab(mp_node->fs_handle);
478 rc = async_req_2_0(exch, VFS_OUT_UNMOUNT,
[15f3c3f]479 mp_node->service_id, mp_node->index);
[79ae36dd]480 vfs_exchange_release(exch);
481
[ae75e2e3]482 if (rc != EOK) {
483 fibril_rwlock_write_unlock(&namespace_rwlock);
484 vfs_node_put(mp_node);
485 vfs_node_put(mr_node);
[ffa2c8ef]486 async_answer_0(rid, rc);
[ae75e2e3]487 return;
488 }
[79ae36dd]489
[ae75e2e3]490 /* Drop the reference we got above. */
491 vfs_node_put(mp_node);
492 /* Drop the reference from when the file system was mounted. */
493 vfs_node_put(mp_node);
494 }
[79ae36dd]495
[ae75e2e3]496 /*
497 * All went well, the mounted file system was successfully unmounted.
498 * The only thing left is to forget the unmounted root VFS node.
499 */
500 vfs_node_forget(mr_node);
[79ae36dd]501
[ae75e2e3]502 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]503 async_answer_0(rid, EOK);
[7f5e070]504}
505
[861e7d1]506void vfs_open(ipc_callid_t rid, ipc_call_t *request)
507{
508 /*
[ae78b530]509 * The POSIX interface is open(path, oflag, mode).
[4198f9c3]510 * We can receive oflags and mode along with the VFS_IN_OPEN call;
511 * the path will need to arrive in another call.
[ae78b530]512 *
513 * We also receive one private, non-POSIX set of flags called lflag
514 * used to pass information to vfs_lookup_internal().
[861e7d1]515 */
[ae78b530]516 int lflag = IPC_GET_ARG1(*request);
517 int oflag = IPC_GET_ARG2(*request);
518 int mode = IPC_GET_ARG3(*request);
[dd2cfa7]519
520 /* Ignore mode for now. */
521 (void) mode;
[05b9912]522
[b17186d]523 /*
524 * Make sure that we are called with exactly one of L_FILE and
[f7376cbf]525 * L_DIRECTORY. Make sure that the user does not pass L_OPEN,
526 * L_ROOT or L_MP.
[b17186d]527 */
[230260ac]528 if (((lflag & (L_FILE | L_DIRECTORY)) == 0) ||
529 ((lflag & (L_FILE | L_DIRECTORY)) == (L_FILE | L_DIRECTORY)) ||
[f7376cbf]530 (lflag & (L_OPEN | L_ROOT | L_MP))) {
[ffa2c8ef]531 async_answer_0(rid, EINVAL);
[b17186d]532 return;
533 }
[05b9912]534
[2db4ac8]535 if (oflag & O_CREAT)
536 lflag |= L_CREATE;
537 if (oflag & O_EXCL)
538 lflag |= L_EXCLUSIVE;
[05b9912]539
[472c09d]540 char *path;
[4cac2d69]541 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
[472c09d]542 if (rc != EOK) {
[ffa2c8ef]543 async_answer_0(rid, rc);
[861e7d1]544 return;
545 }
546
547 /*
548 * Avoid the race condition in which the file can be deleted before we
549 * find/create-and-lock the VFS node corresponding to the looked-up
550 * triplet.
551 */
[2db4ac8]552 if (lflag & L_CREATE)
[230260ac]553 fibril_rwlock_write_lock(&namespace_rwlock);
[2db4ac8]554 else
[230260ac]555 fibril_rwlock_read_lock(&namespace_rwlock);
[05b9912]556
[72bde81]557 /* The path is now populated and we can call vfs_lookup_internal(). */
[eb27ce5a]558 vfs_lookup_res_t lr;
[05b9912]559 rc = vfs_lookup_internal(path, lflag | L_OPEN, &lr, NULL);
560 if (rc != EOK) {
[2db4ac8]561 if (lflag & L_CREATE)
[230260ac]562 fibril_rwlock_write_unlock(&namespace_rwlock);
[2db4ac8]563 else
[230260ac]564 fibril_rwlock_read_unlock(&namespace_rwlock);
[ffa2c8ef]565 async_answer_0(rid, rc);
[861e7d1]566 free(path);
567 return;
568 }
[05b9912]569
[7fe1f75]570 /* Path is no longer needed. */
[861e7d1]571 free(path);
[05b9912]572
[eb27ce5a]573 vfs_node_t *node = vfs_node_get(&lr);
[2db4ac8]574 if (lflag & L_CREATE)
[230260ac]575 fibril_rwlock_write_unlock(&namespace_rwlock);
[2db4ac8]576 else
[230260ac]577 fibril_rwlock_read_unlock(&namespace_rwlock);
[05b9912]578
[7fe1f75]579 /* Truncate the file if requested and if necessary. */
580 if (oflag & O_TRUNC) {
[230260ac]581 fibril_rwlock_write_lock(&node->contents_rwlock);
[7fe1f75]582 if (node->size) {
583 rc = vfs_truncate_internal(node->fs_handle,
[15f3c3f]584 node->service_id, node->index, 0);
[7fe1f75]585 if (rc) {
[230260ac]586 fibril_rwlock_write_unlock(&node->contents_rwlock);
[7fe1f75]587 vfs_node_put(node);
[ffa2c8ef]588 async_answer_0(rid, rc);
[7fe1f75]589 return;
590 }
591 node->size = 0;
592 }
[230260ac]593 fibril_rwlock_write_unlock(&node->contents_rwlock);
[7fe1f75]594 }
[05b9912]595
[861e7d1]596 /*
597 * Get ourselves a file descriptor and the corresponding vfs_file_t
598 * structure.
599 */
[2b88074b]600 int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
[861e7d1]601 if (fd < 0) {
602 vfs_node_put(node);
[ffa2c8ef]603 async_answer_0(rid, fd);
[861e7d1]604 return;
605 }
606 vfs_file_t *file = vfs_file_get(fd);
[179d052]607 assert(file);
[861e7d1]608 file->node = node;
[05b9912]609 if (oflag & O_APPEND)
[15b9970]610 file->append = true;
[05b9912]611
[861e7d1]612 /*
613 * The following increase in reference count is for the fact that the
614 * file is being opened and that a file structure is pointing to it.
615 * It is necessary so that the file will not disappear when
616 * vfs_node_put() is called. The reference will be dropped by the
[4198f9c3]617 * respective VFS_IN_CLOSE.
[861e7d1]618 */
619 vfs_node_addref(node);
620 vfs_node_put(node);
[4fe94c66]621 vfs_file_put(file);
[05b9912]622
623 /* Success! Return the new file descriptor to the client. */
[ffa2c8ef]624 async_answer_1(rid, EOK, fd);
[05b9912]625}
[861e7d1]626
[05b9912]627void vfs_sync(ipc_callid_t rid, ipc_call_t *request)
628{
629 int fd = IPC_GET_ARG1(*request);
630
631 /* Lookup the file structure corresponding to the file descriptor. */
632 vfs_file_t *file = vfs_file_get(fd);
633 if (!file) {
[ffa2c8ef]634 async_answer_0(rid, ENOENT);
[05b9912]635 return;
636 }
637
638 /*
639 * Lock the open file structure so that no other thread can manipulate
640 * the same open file at a time.
641 */
[230260ac]642 fibril_mutex_lock(&file->lock);
[79ae36dd]643 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
[05b9912]644
[4198f9c3]645 /* Make a VFS_OUT_SYMC request at the destination FS server. */
[05b9912]646 aid_t msg;
647 ipc_call_t answer;
[15f3c3f]648 msg = async_send_2(fs_exch, VFS_OUT_SYNC, file->node->service_id,
[4198f9c3]649 file->node->index, &answer);
[79ae36dd]650
651 vfs_exchange_release(fs_exch);
652
[05b9912]653 /* Wait for reply from the FS server. */
[96b02eb9]654 sysarg_t rc;
[05b9912]655 async_wait_for(msg, &rc);
656
[230260ac]657 fibril_mutex_unlock(&file->lock);
[79ae36dd]658
[4fe94c66]659 vfs_file_put(file);
[ffa2c8ef]660 async_answer_0(rid, rc);
[e704503]661}
662
[05b9912]663void vfs_close(ipc_callid_t rid, ipc_call_t *request)
664{
665 int fd = IPC_GET_ARG1(*request);
[79ae36dd]666 int ret = vfs_fd_free(fd);
[ffa2c8ef]667 async_answer_0(rid, ret);
[05b9912]668}
669
[861e7d1]670static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
671{
672 /*
673 * The following code strongly depends on the fact that the files data
674 * structure can be only accessed by a single fibril and all file
675 * operations are serialized (i.e. the reads and writes cannot
676 * interleave and a file cannot be closed while it is being read).
677 *
678 * Additional synchronization needs to be added once the table of
679 * open files supports parallel access!
680 */
[79ae36dd]681
[861e7d1]682 int fd = IPC_GET_ARG1(*request);
[6c89f20]683
[72bde81]684 /* Lookup the file structure corresponding to the file descriptor. */
[861e7d1]685 vfs_file_t *file = vfs_file_get(fd);
686 if (!file) {
[ffa2c8ef]687 async_answer_0(rid, ENOENT);
[861e7d1]688 return;
689 }
[6c89f20]690
[861e7d1]691 /*
692 * Lock the open file structure so that no other thread can manipulate
693 * the same open file at a time.
694 */
[230260ac]695 fibril_mutex_lock(&file->lock);
[79ae36dd]696
697 vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
698 assert(fs_info);
699
[861e7d1]700 /*
701 * Lock the file's node so that no other client can read/write to it at
[c2f4b6b]702 * the same time unless the FS supports concurrent reads/writes and its
703 * write implementation does not modify the file size.
[861e7d1]704 */
[79ae36dd]705 if ((read) ||
706 ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
[230260ac]707 fibril_rwlock_read_lock(&file->node->contents_rwlock);
[861e7d1]708 else
[230260ac]709 fibril_rwlock_write_lock(&file->node->contents_rwlock);
[79ae36dd]710
[b17186d]711 if (file->node->type == VFS_NODE_DIRECTORY) {
712 /*
713 * Make sure that no one is modifying the namespace
714 * while we are in readdir().
715 */
716 assert(read);
[230260ac]717 fibril_rwlock_read_lock(&namespace_rwlock);
[b17186d]718 }
[6c89f20]719
[79ae36dd]720 async_exch_t *fs_exch = vfs_exchange_grab(file->node->fs_handle);
[861e7d1]721
722 /*
[b4cbef1]723 * Make a VFS_READ/VFS_WRITE request at the destination FS server
724 * and forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
[861e7d1]725 * destination FS server. The call will be routed as if sent by
726 * ourselves. Note that call arguments are immutable in this case so we
727 * don't have to bother.
728 */
[96b02eb9]729 sysarg_t rc;
[b4cbef1]730 ipc_call_t answer;
731 if (read) {
[5bb9907]732 rc = async_data_read_forward_4_1(fs_exch, VFS_OUT_READ,
[86ffa27f]733 file->node->service_id, file->node->index,
[5bb9907]734 LOWER32(file->pos), UPPER32(file->pos), &answer);
[b4cbef1]735 } else {
[3a4b3ba]736 if (file->append)
737 file->pos = file->node->size;
738
[5bb9907]739 rc = async_data_write_forward_4_1(fs_exch, VFS_OUT_WRITE,
[86ffa27f]740 file->node->service_id, file->node->index,
[5bb9907]741 LOWER32(file->pos), UPPER32(file->pos), &answer);
[b4cbef1]742 }
[05b9912]743
[79ae36dd]744 vfs_exchange_release(fs_exch);
[34ca870]745
[861e7d1]746 size_t bytes = IPC_GET_ARG1(answer);
[b4cbef1]747
[b17186d]748 if (file->node->type == VFS_NODE_DIRECTORY)
[230260ac]749 fibril_rwlock_read_unlock(&namespace_rwlock);
[6c89f20]750
[72bde81]751 /* Unlock the VFS node. */
[79ae36dd]752 if ((read) ||
753 ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
[230260ac]754 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[861e7d1]755 else {
756 /* Update the cached version of node's size. */
[f7017572]757 if (rc == EOK)
[5bb9907]758 file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
759 IPC_GET_ARG3(answer));
[230260ac]760 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
[861e7d1]761 }
[6c89f20]762
[72bde81]763 /* Update the position pointer and unlock the open file. */
[f7017572]764 if (rc == EOK)
765 file->pos += bytes;
[230260ac]766 fibril_mutex_unlock(&file->lock);
[4fe94c66]767 vfs_file_put(file);
768
[861e7d1]769 /*
770 * FS server's reply is the final result of the whole operation we
771 * return to the client.
772 */
[ffa2c8ef]773 async_answer_1(rid, rc, bytes);
[861e7d1]774}
775
776void vfs_read(ipc_callid_t rid, ipc_call_t *request)
777{
778 vfs_rdwr(rid, request, true);
779}
780
781void vfs_write(ipc_callid_t rid, ipc_call_t *request)
782{
783 vfs_rdwr(rid, request, false);
784}
785
786void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
787{
788 int fd = (int) IPC_GET_ARG1(*request);
[8df8415]789 off64_t off = (off64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
790 IPC_GET_ARG3(*request));
[ed903174]791 int whence = (int) IPC_GET_ARG4(*request);
792
[72bde81]793 /* Lookup the file structure corresponding to the file descriptor. */
[861e7d1]794 vfs_file_t *file = vfs_file_get(fd);
795 if (!file) {
[ffa2c8ef]796 async_answer_0(rid, ENOENT);
[861e7d1]797 return;
798 }
[ed903174]799
[230260ac]800 fibril_mutex_lock(&file->lock);
[ed903174]801
802 off64_t newoff;
803 switch (whence) {
[8df8415]804 case SEEK_SET:
805 if (off >= 0) {
806 file->pos = (aoff64_t) off;
[230260ac]807 fibril_mutex_unlock(&file->lock);
[4fe94c66]808 vfs_file_put(file);
[ffa2c8ef]809 async_answer_1(rid, EOK, off);
[861e7d1]810 return;
[8df8415]811 }
812 break;
813 case SEEK_CUR:
814 if ((off >= 0) && (file->pos + off < file->pos)) {
815 fibril_mutex_unlock(&file->lock);
[4fe94c66]816 vfs_file_put(file);
[ffa2c8ef]817 async_answer_0(rid, EOVERFLOW);
[8df8415]818 return;
819 }
820
821 if ((off < 0) && (file->pos < (aoff64_t) -off)) {
822 fibril_mutex_unlock(&file->lock);
[4fe94c66]823 vfs_file_put(file);
[ffa2c8ef]824 async_answer_0(rid, EOVERFLOW);
[8df8415]825 return;
826 }
827
828 file->pos += off;
829 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos;
830
831 fibril_mutex_unlock(&file->lock);
[4fe94c66]832 vfs_file_put(file);
[ffa2c8ef]833 async_answer_2(rid, EOK, LOWER32(newoff),
[8df8415]834 UPPER32(newoff));
835 return;
836 case SEEK_END:
837 fibril_rwlock_read_lock(&file->node->contents_rwlock);
838 aoff64_t size = file->node->size;
839
840 if ((off >= 0) && (size + off < size)) {
[ed903174]841 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
[230260ac]842 fibril_mutex_unlock(&file->lock);
[4fe94c66]843 vfs_file_put(file);
[ffa2c8ef]844 async_answer_0(rid, EOVERFLOW);
[861e7d1]845 return;
[8df8415]846 }
847
848 if ((off < 0) && (size < (aoff64_t) -off)) {
849 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
850 fibril_mutex_unlock(&file->lock);
[4fe94c66]851 vfs_file_put(file);
[ffa2c8ef]852 async_answer_0(rid, EOVERFLOW);
[8df8415]853 return;
854 }
855
856 file->pos = size + off;
857 newoff = (file->pos > OFF64_MAX) ? OFF64_MAX : file->pos;
858
859 fibril_rwlock_read_unlock(&file->node->contents_rwlock);
860 fibril_mutex_unlock(&file->lock);
[4fe94c66]861 vfs_file_put(file);
[ffa2c8ef]862 async_answer_2(rid, EOK, LOWER32(newoff), UPPER32(newoff));
[8df8415]863 return;
[861e7d1]864 }
[ed903174]865
[230260ac]866 fibril_mutex_unlock(&file->lock);
[4fe94c66]867 vfs_file_put(file);
[ffa2c8ef]868 async_answer_0(rid, EINVAL);
[861e7d1]869}
870
[15f3c3f]871int vfs_truncate_internal(fs_handle_t fs_handle, service_id_t service_id,
[ed903174]872 fs_index_t index, aoff64_t size)
[7fe1f75]873{
[79ae36dd]874 async_exch_t *exch = vfs_exchange_grab(fs_handle);
875 sysarg_t rc = async_req_4_0(exch, VFS_OUT_TRUNCATE,
[15f3c3f]876 (sysarg_t) service_id, (sysarg_t) index, LOWER32(size),
[79ae36dd]877 UPPER32(size));
878 vfs_exchange_release(exch);
[7fe1f75]879
[79ae36dd]880 return (int) rc;
[7fe1f75]881}
882
[0ee4322]883void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
884{
885 int fd = IPC_GET_ARG1(*request);
[8df8415]886 aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG2(*request),
887 IPC_GET_ARG3(*request));
[7fe1f75]888 int rc;
[0ee4322]889
890 vfs_file_t *file = vfs_file_get(fd);
891 if (!file) {
[ffa2c8ef]892 async_answer_0(rid, ENOENT);
[0ee4322]893 return;
894 }
[230260ac]895 fibril_mutex_lock(&file->lock);
[0ee4322]896
[230260ac]897 fibril_rwlock_write_lock(&file->node->contents_rwlock);
[7fe1f75]898 rc = vfs_truncate_internal(file->node->fs_handle,
[15f3c3f]899 file->node->service_id, file->node->index, size);
[0ee4322]900 if (rc == EOK)
901 file->node->size = size;
[230260ac]902 fibril_rwlock_write_unlock(&file->node->contents_rwlock);
[0ee4322]903
[230260ac]904 fibril_mutex_unlock(&file->lock);
[4fe94c66]905 vfs_file_put(file);
[ffa2c8ef]906 async_answer_0(rid, (sysarg_t)rc);
[861e7d1]907}
908
[852b801]909void vfs_fstat(ipc_callid_t rid, ipc_call_t *request)
910{
911 int fd = IPC_GET_ARG1(*request);
[96b02eb9]912 sysarg_t rc;
[852b801]913
914 vfs_file_t *file = vfs_file_get(fd);
915 if (!file) {
[ffa2c8ef]916 async_answer_0(rid, ENOENT);
[852b801]917 return;
918 }
919
920 ipc_callid_t callid;
[0da4e41]921 if (!async_data_read_receive(&callid, NULL)) {
[4fe94c66]922 vfs_file_put(file);
[ffa2c8ef]923 async_answer_0(callid, EINVAL);
924 async_answer_0(rid, EINVAL);
[852b801]925 return;
926 }
927
928 fibril_mutex_lock(&file->lock);
929
[79ae36dd]930 async_exch_t *exch = vfs_exchange_grab(file->node->fs_handle);
[852b801]931
932 aid_t msg;
[15f3c3f]933 msg = async_send_3(exch, VFS_OUT_STAT, file->node->service_id,
[852b801]934 file->node->index, true, NULL);
[79ae36dd]935 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
936
937 vfs_exchange_release(exch);
938
[852b801]939 async_wait_for(msg, &rc);
[79ae36dd]940
[852b801]941 fibril_mutex_unlock(&file->lock);
[4fe94c66]942 vfs_file_put(file);
[ffa2c8ef]943 async_answer_0(rid, rc);
[852b801]944}
945
946void vfs_stat(ipc_callid_t rid, ipc_call_t *request)
947{
[472c09d]948 char *path;
[4cac2d69]949 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
[472c09d]950 if (rc != EOK) {
[ffa2c8ef]951 async_answer_0(rid, rc);
[415c7e0d]952 return;
953 }
[472c09d]954
955 ipc_callid_t callid;
[0da4e41]956 if (!async_data_read_receive(&callid, NULL)) {
[415c7e0d]957 free(path);
[ffa2c8ef]958 async_answer_0(callid, EINVAL);
959 async_answer_0(rid, EINVAL);
[415c7e0d]960 return;
961 }
962
963 vfs_lookup_res_t lr;
964 fibril_rwlock_read_lock(&namespace_rwlock);
965 rc = vfs_lookup_internal(path, L_NONE, &lr, NULL);
966 free(path);
967 if (rc != EOK) {
968 fibril_rwlock_read_unlock(&namespace_rwlock);
[ffa2c8ef]969 async_answer_0(callid, rc);
970 async_answer_0(rid, rc);
[415c7e0d]971 return;
972 }
973 vfs_node_t *node = vfs_node_get(&lr);
974 if (!node) {
975 fibril_rwlock_read_unlock(&namespace_rwlock);
[ffa2c8ef]976 async_answer_0(callid, ENOMEM);
977 async_answer_0(rid, ENOMEM);
[415c7e0d]978 return;
979 }
980
981 fibril_rwlock_read_unlock(&namespace_rwlock);
982
[79ae36dd]983 async_exch_t *exch = vfs_exchange_grab(node->fs_handle);
984
[415c7e0d]985 aid_t msg;
[15f3c3f]986 msg = async_send_3(exch, VFS_OUT_STAT, node->service_id,
[415c7e0d]987 node->index, false, NULL);
[79ae36dd]988 async_forward_fast(callid, exch, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
989
990 vfs_exchange_release(exch);
[057760d3]991
[96b02eb9]992 sysarg_t rv;
[057760d3]993 async_wait_for(msg, &rv);
[415c7e0d]994
[ffa2c8ef]995 async_answer_0(rid, rv);
[415c7e0d]996
997 vfs_node_put(node);
[852b801]998}
999
[72bde81]1000void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
1001{
1002 int mode = IPC_GET_ARG1(*request);
[472c09d]1003
1004 char *path;
[4cac2d69]1005 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
[472c09d]1006 if (rc != EOK) {
[ffa2c8ef]1007 async_answer_0(rid, rc);
[72bde81]1008 return;
1009 }
[472c09d]1010
[dd2cfa7]1011 /* Ignore mode for now. */
1012 (void) mode;
[72bde81]1013
[230260ac]1014 fibril_rwlock_write_lock(&namespace_rwlock);
[72bde81]1015 int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
[d6084ef]1016 rc = vfs_lookup_internal(path, lflag, NULL, NULL);
[230260ac]1017 fibril_rwlock_write_unlock(&namespace_rwlock);
[72bde81]1018 free(path);
[ffa2c8ef]1019 async_answer_0(rid, rc);
[72bde81]1020}
1021
[f15cf1a6]1022void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
1023{
1024 int lflag = IPC_GET_ARG1(*request);
[472c09d]1025
1026 char *path;
[4cac2d69]1027 int rc = async_data_write_accept((void **) &path, true, 0, 0, 0, NULL);
[472c09d]1028 if (rc != EOK) {
[ffa2c8ef]1029 async_answer_0(rid, rc);
[f15cf1a6]1030 return;
1031 }
1032
[230260ac]1033 fibril_rwlock_write_lock(&namespace_rwlock);
[f15cf1a6]1034 lflag &= L_DIRECTORY; /* sanitize lflag */
1035 vfs_lookup_res_t lr;
[a8e9ab8d]1036 rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
[f15cf1a6]1037 free(path);
1038 if (rc != EOK) {
[230260ac]1039 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]1040 async_answer_0(rid, rc);
[f15cf1a6]1041 return;
1042 }
1043
1044 /*
1045 * The name has already been unlinked by vfs_lookup_internal().
1046 * We have to get and put the VFS node to ensure that it is
[4198f9c3]1047 * VFS_OUT_DESTROY'ed after the last reference to it is dropped.
[f15cf1a6]1048 */
1049 vfs_node_t *node = vfs_node_get(&lr);
[553492be]1050 fibril_mutex_lock(&nodes_mutex);
[f15cf1a6]1051 node->lnkcnt--;
[553492be]1052 fibril_mutex_unlock(&nodes_mutex);
[230260ac]1053 fibril_rwlock_write_unlock(&namespace_rwlock);
[f15cf1a6]1054 vfs_node_put(node);
[ffa2c8ef]1055 async_answer_0(rid, EOK);
[f15cf1a6]1056}
1057
[a8e9ab8d]1058void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
1059{
1060 /* Retrieve the old path. */
[472c09d]1061 char *old;
[4cac2d69]1062 int rc = async_data_write_accept((void **) &old, true, 0, 0, 0, NULL);
[472c09d]1063 if (rc != EOK) {
[ffa2c8ef]1064 async_answer_0(rid, rc);
[a8e9ab8d]1065 return;
1066 }
1067
1068 /* Retrieve the new path. */
[472c09d]1069 char *new;
[4cac2d69]1070 rc = async_data_write_accept((void **) &new, true, 0, 0, 0, NULL);
[472c09d]1071 if (rc != EOK) {
[a8e9ab8d]1072 free(old);
[ffa2c8ef]1073 async_answer_0(rid, rc);
[a8e9ab8d]1074 return;
1075 }
[472c09d]1076
1077 size_t olen;
1078 size_t nlen;
[732bb0c]1079 char *oldc = canonify(old, &olen);
1080 char *newc = canonify(new, &nlen);
[472c09d]1081
1082 if ((!oldc) || (!newc)) {
[ffa2c8ef]1083 async_answer_0(rid, EINVAL);
[a8e9ab8d]1084 free(old);
1085 free(new);
1086 return;
1087 }
[472c09d]1088
[732bb0c]1089 oldc[olen] = '\0';
1090 newc[nlen] = '\0';
[472c09d]1091
[14040e5]1092 if ((!str_lcmp(newc, oldc, str_length(oldc))) &&
1093 ((newc[str_length(oldc)] == '/') ||
1094 (str_length(oldc) == 1) ||
1095 (str_length(oldc) == str_length(newc)))) {
1096 /*
1097 * oldc is a prefix of newc and either
1098 * - newc continues with a / where oldc ends, or
1099 * - oldc was / itself, or
1100 * - oldc and newc are equal.
1101 */
[ffa2c8ef]1102 async_answer_0(rid, EINVAL);
[a8e9ab8d]1103 free(old);
1104 free(new);
1105 return;
1106 }
1107
1108 vfs_lookup_res_t old_lr;
1109 vfs_lookup_res_t new_lr;
1110 vfs_lookup_res_t new_par_lr;
[230260ac]1111 fibril_rwlock_write_lock(&namespace_rwlock);
[472c09d]1112
[a8e9ab8d]1113 /* Lookup the node belonging to the old file name. */
1114 rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
1115 if (rc != EOK) {
[230260ac]1116 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]1117 async_answer_0(rid, rc);
[a8e9ab8d]1118 free(old);
1119 free(new);
1120 return;
1121 }
[472c09d]1122
[a8e9ab8d]1123 vfs_node_t *old_node = vfs_node_get(&old_lr);
1124 if (!old_node) {
[230260ac]1125 fibril_rwlock_write_unlock(&namespace_rwlock);
[ffa2c8ef]1126 async_answer_0(rid, ENOMEM);
[a8e9ab8d]1127 free(old);
1128 free(new);
1129 return;
1130 }
[472c09d]1131
[4f46695e]1132 /* Determine the path to the parent of the node with the new name. */
1133 char *parentc = str_dup(newc);
1134 if (!parentc) {
[230260ac]1135 fibril_rwlock_write_unlock(&namespace_rwlock);
[71af5a4]1136 vfs_node_put(old_node);
[ffa2c8ef]1137 async_answer_0(rid, rc);
[4f46695e]1138 free(old);
1139 free(new);
1140 return;
1141 }
[472c09d]1142
[ae55ee8]1143 char *lastsl = str_rchr(parentc + 1, '/');
[4f46695e]1144 if (lastsl)
1145 *lastsl = '\0';
1146 else
1147 parentc[1] = '\0';
[472c09d]1148
[a8e9ab8d]1149 /* Lookup parent of the new file name. */
[4f46695e]1150 rc = vfs_lookup_internal(parentc, L_NONE, &new_par_lr, NULL);
1151 free(parentc); /* not needed anymore */
[a8e9ab8d]1152 if (rc != EOK) {
[230260ac]1153 fibril_rwlock_write_unlock(&namespace_rwlock);
[71af5a4]1154 vfs_node_put(old_node);
[ffa2c8ef]1155 async_answer_0(rid, rc);
[a8e9ab8d]1156 free(old);
1157 free(new);
1158 return;
1159 }
[472c09d]1160
[a8e9ab8d]1161 /* Check whether linking to the same file system instance. */
1162 if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
[15f3c3f]1163 (old_node->service_id != new_par_lr.triplet.service_id)) {
[230260ac]1164 fibril_rwlock_write_unlock(&namespace_rwlock);
[71af5a4]1165 vfs_node_put(old_node);
[ffa2c8ef]1166 async_answer_0(rid, EXDEV); /* different file systems */
[a8e9ab8d]1167 free(old);
1168 free(new);
1169 return;
1170 }
[472c09d]1171
[a8e9ab8d]1172 /* Destroy the old link for the new name. */
1173 vfs_node_t *new_node = NULL;
1174 rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
[472c09d]1175
[a8e9ab8d]1176 switch (rc) {
1177 case ENOENT:
1178 /* simply not in our way */
1179 break;
1180 case EOK:
1181 new_node = vfs_node_get(&new_lr);
1182 if (!new_node) {
[230260ac]1183 fibril_rwlock_write_unlock(&namespace_rwlock);
[71af5a4]1184 vfs_node_put(old_node);
[ffa2c8ef]1185 async_answer_0(rid, ENOMEM);
[a8e9ab8d]1186 free(old);
1187 free(new);
1188 return;
1189 }
[553492be]1190 fibril_mutex_lock(&nodes_mutex);
[a8e9ab8d]1191 new_node->lnkcnt--;
[553492be]1192 fibril_mutex_unlock(&nodes_mutex);
[a8e9ab8d]1193 break;
1194 default:
[230260ac]1195 fibril_rwlock_write_unlock(&namespace_rwlock);
[71af5a4]1196 vfs_node_put(old_node);
[ffa2c8ef]1197 async_answer_0(rid, ENOTEMPTY);
[a8e9ab8d]1198 free(old);
1199 free(new);
1200 return;
1201 }
[472c09d]1202
[a8e9ab8d]1203 /* Create the new link for the new name. */
1204 rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
1205 if (rc != EOK) {
[230260ac]1206 fibril_rwlock_write_unlock(&namespace_rwlock);
[71af5a4]1207 vfs_node_put(old_node);
[a8e9ab8d]1208 if (new_node)
1209 vfs_node_put(new_node);
[ffa2c8ef]1210 async_answer_0(rid, rc);
[a8e9ab8d]1211 free(old);
1212 free(new);
1213 return;
1214 }
[472c09d]1215
[553492be]1216 fibril_mutex_lock(&nodes_mutex);
[a8e9ab8d]1217 old_node->lnkcnt++;
[553492be]1218 fibril_mutex_unlock(&nodes_mutex);
[472c09d]1219
[a8e9ab8d]1220 /* Destroy the link for the old name. */
1221 rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
1222 if (rc != EOK) {
[230260ac]1223 fibril_rwlock_write_unlock(&namespace_rwlock);
[a8e9ab8d]1224 vfs_node_put(old_node);
1225 if (new_node)
1226 vfs_node_put(new_node);
[ffa2c8ef]1227 async_answer_0(rid, rc);
[a8e9ab8d]1228 free(old);
1229 free(new);
1230 return;
1231 }
[472c09d]1232
[553492be]1233 fibril_mutex_lock(&nodes_mutex);
[a8e9ab8d]1234 old_node->lnkcnt--;
[553492be]1235 fibril_mutex_unlock(&nodes_mutex);
[230260ac]1236 fibril_rwlock_write_unlock(&namespace_rwlock);
[a8e9ab8d]1237 vfs_node_put(old_node);
[472c09d]1238
[a8e9ab8d]1239 if (new_node)
1240 vfs_node_put(new_node);
[472c09d]1241
[a8e9ab8d]1242 free(old);
1243 free(new);
[ffa2c8ef]1244 async_answer_0(rid, EOK);
[a8e9ab8d]1245}
1246
[2b88074b]1247void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
1248{
1249 int oldfd = IPC_GET_ARG1(*request);
1250 int newfd = IPC_GET_ARG2(*request);
1251
[4fe94c66]1252 /* If the file descriptors are the same, do nothing. */
1253 if (oldfd == newfd) {
[ffa2c8ef]1254 async_answer_1(rid, EOK, newfd);
[4fe94c66]1255 return;
1256 }
1257
[2b88074b]1258 /* Lookup the file structure corresponding to oldfd. */
1259 vfs_file_t *oldfile = vfs_file_get(oldfd);
1260 if (!oldfile) {
[ffa2c8ef]1261 async_answer_0(rid, EBADF);
[2b88074b]1262 return;
1263 }
1264
1265 /*
1266 * Lock the open file structure so that no other thread can manipulate
1267 * the same open file at a time.
1268 */
1269 fibril_mutex_lock(&oldfile->lock);
1270
[25bef0ff]1271 /* Make sure newfd is closed. */
1272 (void) vfs_fd_free(newfd);
[2b88074b]1273
1274 /* Assign the old file to newfd. */
1275 int ret = vfs_fd_assign(oldfile, newfd);
1276 fibril_mutex_unlock(&oldfile->lock);
[4fe94c66]1277 vfs_file_put(oldfile);
[2b88074b]1278
1279 if (ret != EOK)
[ffa2c8ef]1280 async_answer_0(rid, ret);
[2b88074b]1281 else
[ffa2c8ef]1282 async_answer_1(rid, EOK, newfd);
[2b88074b]1283}
1284
[27b76ca]1285void vfs_wait_handle(ipc_callid_t rid, ipc_call_t *request)
1286{
1287 int fd = vfs_wait_handle_internal();
1288 async_answer_1(rid, EOK, fd);
1289}
1290
[861e7d1]1291/**
1292 * @}
[05b9912]1293 */
Note: See TracBrowser for help on using the repository browser.