Subversion Repositories HelenOS

Rev

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