Subversion Repositories HelenOS

Rev

Rev 4377 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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