Subversion Repositories HelenOS

Rev

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