Subversion Repositories HelenOS

Rev

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