Subversion Repositories HelenOS

Rev

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