Subversion Repositories HelenOS

Rev

Rev 3109 | Rev 3352 | 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 <rwlock.h>
  48. #include <libadt/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. /**
  59.  * This rwlock prevents the race between a triplet-to-VFS-node resolution and a
  60.  * concurrent VFS operation which modifies the file system namespace.
  61.  */
  62. RWLOCK_INITIALIZE(namespace_rwlock);
  63.  
  64. futex_t rootfs_futex = FUTEX_INITIALIZER;
  65. vfs_pair_t rootfs = {
  66.     .fs_handle = 0,
  67.     .dev_handle = 0
  68. };
  69.  
  70. void vfs_mount(ipc_callid_t rid, ipc_call_t *request)
  71. {
  72.     dev_handle_t dev_handle;
  73.     vfs_node_t *mp_node = NULL;
  74.     int rc;
  75.     int phone;
  76.  
  77.     /*
  78.      * We expect the library to do the device-name to device-handle
  79.      * translation for us, thus the device handle will arrive as ARG1
  80.      * in the request.
  81.      */
  82.     dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  83.  
  84.     /*
  85.      * For now, don't make use of ARG2 and ARG3, but they can be used to
  86.      * carry mount options in the future.
  87.      */
  88.  
  89.     ipc_callid_t callid;
  90.     size_t size;
  91.  
  92.     /*
  93.      * Now, we expect the client to send us data with the name of the file
  94.      * system.
  95.      */
  96.     if (!ipc_data_write_receive(&callid, &size)) {
  97.         ipc_answer_0(callid, EINVAL);
  98.         ipc_answer_0(rid, EINVAL);
  99.         return;
  100.     }
  101.  
  102.     /*
  103.      * Don't receive more than is necessary for storing a full file system
  104.      * name.
  105.      */
  106.     if (size < 1 || size > FS_NAME_MAXLEN) {
  107.         ipc_answer_0(callid, EINVAL);
  108.         ipc_answer_0(rid, EINVAL);
  109.         return;
  110.     }
  111.  
  112.     /* Deliver the file system name. */
  113.     char fs_name[FS_NAME_MAXLEN + 1];
  114.     (void) ipc_data_write_finalize(callid, fs_name, size);
  115.     fs_name[size] = '\0';
  116.    
  117.     /*
  118.      * Check if we know a file system with the same name as is in fs_name.
  119.      * This will also give us its file system handle.
  120.      */
  121.     fs_handle_t fs_handle = fs_name_to_handle(fs_name, true);
  122.     if (!fs_handle) {
  123.         ipc_answer_0(rid, ENOENT);
  124.         return;
  125.     }
  126.  
  127.     /* Now, we want the client to send us the mount point. */
  128.     if (!ipc_data_write_receive(&callid, &size)) {
  129.         ipc_answer_0(callid, EINVAL);
  130.         ipc_answer_0(rid, EINVAL);
  131.         return;
  132.     }
  133.  
  134.     /* Check whether size is reasonable wrt. the mount point. */
  135.     if (size < 1 || size > MAX_PATH_LEN) {
  136.         ipc_answer_0(callid, EINVAL);
  137.         ipc_answer_0(rid, EINVAL);
  138.         return;
  139.     }
  140.     /* Allocate buffer for the mount point data being received. */
  141.     uint8_t *buf;
  142.     buf = malloc(size + 1);
  143.     if (!buf) {
  144.         ipc_answer_0(callid, ENOMEM);
  145.         ipc_answer_0(rid, ENOMEM);
  146.         return;
  147.     }
  148.  
  149.     /* Deliver the mount point. */
  150.     (void) ipc_data_write_finalize(callid, buf, size);
  151.     buf[size] = '\0';
  152.  
  153.     /* Resolve the path to the mountpoint. */
  154.     vfs_lookup_res_t mp_res;
  155.     futex_down(&rootfs_futex);
  156.     if (rootfs.fs_handle) {
  157.         /* We already have the root FS. */
  158.         rwlock_write_lock(&namespace_rwlock);
  159.         if ((size == 1) && (buf[0] == '/')) {
  160.             /* Trying to mount root FS over root FS */
  161.             rwlock_write_unlock(&namespace_rwlock);
  162.             futex_up(&rootfs_futex);
  163.             free(buf);
  164.             ipc_answer_0(rid, EBUSY);
  165.             return;
  166.         }
  167.         rc = vfs_lookup_internal(buf, L_DIRECTORY, &mp_res, NULL);
  168.         if (rc != EOK) {
  169.             /* The lookup failed for some reason. */
  170.             rwlock_write_unlock(&namespace_rwlock);
  171.             futex_up(&rootfs_futex);
  172.             free(buf);
  173.             ipc_answer_0(rid, rc);
  174.             return;
  175.         }
  176.         mp_node = vfs_node_get(&mp_res);
  177.         if (!mp_node) {
  178.             rwlock_write_unlock(&namespace_rwlock);
  179.             futex_up(&rootfs_futex);
  180.             free(buf);
  181.             ipc_answer_0(rid, ENOMEM);
  182.             return;
  183.         }
  184.         /*
  185.          * Now we hold a reference to mp_node.
  186.          * It will be dropped upon the corresponding VFS_UNMOUNT.
  187.          * This prevents the mount point from being deleted.
  188.          */
  189.         rwlock_write_unlock(&namespace_rwlock);
  190.     } else {
  191.         /* We still don't have the root file system mounted. */
  192.         if ((size == 1) && (buf[0] == '/')) {
  193.             /*
  194.              * For this simple, but important case,
  195.              * we are almost done.
  196.              */
  197.             free(buf);
  198.            
  199.             /* Tell the mountee that it is being mounted. */
  200.             phone = vfs_grab_phone(fs_handle);
  201.             rc = async_req_1_0(phone, VFS_MOUNTED,
  202.                 (ipcarg_t) dev_handle);
  203.             vfs_release_phone(phone);
  204.  
  205.             if (rc == EOK) {
  206.                 rootfs.fs_handle = fs_handle;
  207.                 rootfs.dev_handle = dev_handle;
  208.             }
  209.  
  210.             futex_up(&rootfs_futex);
  211.             ipc_answer_0(rid, rc);
  212.             return;
  213.         } else {
  214.             /*
  215.              * We can't resolve this without the root filesystem
  216.              * being mounted first.
  217.              */
  218.             futex_up(&rootfs_futex);
  219.             free(buf);
  220.             ipc_answer_0(rid, ENOENT);
  221.             return;
  222.         }
  223.     }
  224.     futex_up(&rootfs_futex);
  225.    
  226.     free(buf);  /* The buffer is not needed anymore. */
  227.    
  228.     /*
  229.      * At this point, we have all necessary pieces: file system and device
  230.      * handles, and we know the mount point VFS node.
  231.      */
  232.  
  233.     phone = vfs_grab_phone(mp_res.triplet.fs_handle);
  234.     rc = async_req_4_0(phone, VFS_MOUNT,
  235.         (ipcarg_t) mp_res.triplet.dev_handle,
  236.         (ipcarg_t) mp_res.triplet.index,
  237.         (ipcarg_t) fs_handle,
  238.         (ipcarg_t) dev_handle);
  239.     vfs_release_phone(phone);
  240.  
  241.     if (rc != EOK) {
  242.         /* Mount failed, drop reference to mp_node. */
  243.         if (mp_node)
  244.             vfs_node_put(mp_node);
  245.     }
  246.    
  247.     ipc_answer_0(rid, rc);
  248. }
  249.  
  250. void vfs_open(ipc_callid_t rid, ipc_call_t *request)
  251. {
  252.     if (!vfs_files_init()) {
  253.         ipc_answer_0(rid, ENOMEM);
  254.         return;
  255.     }
  256.  
  257.     /*
  258.      * The POSIX interface is open(path, oflag, mode).
  259.      * We can receive oflags and mode along with the VFS_OPEN call; the path
  260.      * will need to arrive in another call.
  261.      *
  262.      * We also receive one private, non-POSIX set of flags called lflag
  263.      * used to pass information to vfs_lookup_internal().
  264.      */
  265.     int lflag = IPC_GET_ARG1(*request);
  266.     int oflag = IPC_GET_ARG2(*request);
  267.     int mode = IPC_GET_ARG3(*request);
  268.     size_t len;
  269.  
  270.     if (oflag & O_CREAT)
  271.         lflag |= L_CREATE;
  272.     if (oflag & O_EXCL)
  273.         lflag |= L_EXCLUSIVE;
  274.  
  275.     ipc_callid_t callid;
  276.  
  277.     if (!ipc_data_write_receive(&callid, &len)) {
  278.         ipc_answer_0(callid, EINVAL);
  279.         ipc_answer_0(rid, EINVAL);
  280.         return;
  281.     }
  282.     char *path = malloc(len + 1);
  283.     if (!path) {
  284.         ipc_answer_0(callid, ENOMEM);
  285.         ipc_answer_0(rid, ENOMEM);
  286.         return;
  287.     }
  288.     int rc;
  289.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  290.         ipc_answer_0(rid, rc);
  291.         free(path);
  292.         return;
  293.     }
  294.     path[len] = '\0';
  295.    
  296.     /*
  297.      * Avoid the race condition in which the file can be deleted before we
  298.      * find/create-and-lock the VFS node corresponding to the looked-up
  299.      * triplet.
  300.      */
  301.     if (lflag & L_CREATE)
  302.         rwlock_write_lock(&namespace_rwlock);
  303.     else
  304.         rwlock_read_lock(&namespace_rwlock);
  305.  
  306.     /* The path is now populated and we can call vfs_lookup_internal(). */
  307.     vfs_lookup_res_t lr;
  308.     rc = vfs_lookup_internal(path, lflag, &lr, NULL);
  309.     if (rc) {
  310.         if (lflag & L_CREATE)
  311.             rwlock_write_unlock(&namespace_rwlock);
  312.         else
  313.             rwlock_read_unlock(&namespace_rwlock);
  314.         ipc_answer_0(rid, rc);
  315.         free(path);
  316.         return;
  317.     }
  318.  
  319.     /* Path is no longer needed. */
  320.     free(path);
  321.  
  322.     vfs_node_t *node = vfs_node_get(&lr);
  323.     if (lflag & L_CREATE)
  324.         rwlock_write_unlock(&namespace_rwlock);
  325.     else
  326.         rwlock_read_unlock(&namespace_rwlock);
  327.  
  328.     /* Truncate the file if requested and if necessary. */
  329.     if (oflag & O_TRUNC) {
  330.         rwlock_write_lock(&node->contents_rwlock);
  331.         if (node->size) {
  332.             rc = vfs_truncate_internal(node->fs_handle,
  333.                 node->dev_handle, node->index, 0);
  334.             if (rc) {
  335.                 rwlock_write_unlock(&node->contents_rwlock);
  336.                 vfs_node_put(node);
  337.                 ipc_answer_0(rid, rc);
  338.                 return;
  339.             }
  340.             node->size = 0;
  341.         }
  342.         rwlock_write_unlock(&node->contents_rwlock);
  343.     }
  344.  
  345.     /*
  346.      * Get ourselves a file descriptor and the corresponding vfs_file_t
  347.      * structure.
  348.      */
  349.     int fd = vfs_fd_alloc();
  350.     if (fd < 0) {
  351.         vfs_node_put(node);
  352.         ipc_answer_0(rid, fd);
  353.         return;
  354.     }
  355.     vfs_file_t *file = vfs_file_get(fd);
  356.     file->node = node;
  357.     if (oflag & O_APPEND)
  358.         file->append = true;
  359.  
  360.     /*
  361.      * The following increase in reference count is for the fact that the
  362.      * file is being opened and that a file structure is pointing to it.
  363.      * It is necessary so that the file will not disappear when
  364.      * vfs_node_put() is called. The reference will be dropped by the
  365.      * respective VFS_CLOSE.
  366.      */
  367.     vfs_node_addref(node);
  368.     vfs_node_put(node);
  369.  
  370.     /* Success! Return the new file descriptor to the client. */
  371.     ipc_answer_1(rid, EOK, fd);
  372. }
  373.  
  374. void vfs_close(ipc_callid_t rid, ipc_call_t *request)
  375. {
  376.     int fd = IPC_GET_ARG1(*request);
  377.     int rc = vfs_fd_free(fd);
  378.     ipc_answer_0(rid, rc);
  379. }
  380.  
  381. static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
  382. {
  383.  
  384.     /*
  385.      * The following code strongly depends on the fact that the files data
  386.      * structure can be only accessed by a single fibril and all file
  387.      * operations are serialized (i.e. the reads and writes cannot
  388.      * interleave and a file cannot be closed while it is being read).
  389.      *
  390.      * Additional synchronization needs to be added once the table of
  391.      * open files supports parallel access!
  392.      */
  393.  
  394.     int fd = IPC_GET_ARG1(*request);
  395.    
  396.     /* Lookup the file structure corresponding to the file descriptor. */
  397.     vfs_file_t *file = vfs_file_get(fd);
  398.     if (!file) {
  399.         ipc_answer_0(rid, ENOENT);
  400.         return;
  401.     }
  402.    
  403.     /*
  404.      * Now we need to receive a call with client's
  405.      * IPC_M_DATA_READ/IPC_M_DATA_WRITE request.
  406.      */
  407.     ipc_callid_t callid;
  408.     int res;
  409.     if (read)
  410.         res = ipc_data_read_receive(&callid, NULL);
  411.     else
  412.         res = ipc_data_write_receive(&callid, NULL);
  413.     if (!res) {
  414.         ipc_answer_0(callid, EINVAL);
  415.         ipc_answer_0(rid, EINVAL);
  416.         return;
  417.     }
  418.    
  419.     /*
  420.      * Lock the open file structure so that no other thread can manipulate
  421.      * the same open file at a time.
  422.      */
  423.     futex_down(&file->lock);
  424.    
  425.     /*
  426.      * Lock the file's node so that no other client can read/write to it at
  427.      * the same time.
  428.      */
  429.     if (read)
  430.         rwlock_read_lock(&file->node->contents_rwlock);
  431.     else
  432.         rwlock_write_lock(&file->node->contents_rwlock);
  433.    
  434.     int fs_phone = vfs_grab_phone(file->node->fs_handle);  
  435.    
  436.     /* Make a VFS_READ/VFS_WRITE request at the destination FS server. */
  437.     aid_t msg;
  438.     ipc_call_t answer;
  439.     if (!read && file->append)
  440.         file->pos = file->node->size;
  441.     msg = async_send_3(fs_phone, IPC_GET_METHOD(*request),
  442.         file->node->dev_handle, file->node->index, file->pos, &answer);
  443.    
  444.     /*
  445.      * Forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
  446.      * destination FS server. The call will be routed as if sent by
  447.      * ourselves. Note that call arguments are immutable in this case so we
  448.      * don't have to bother.
  449.      */
  450.     ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  451.    
  452.     vfs_release_phone(fs_phone);
  453.    
  454.     /* Wait for reply from the FS server. */
  455.     ipcarg_t rc;
  456.     async_wait_for(msg, &rc);
  457.     size_t bytes = IPC_GET_ARG1(answer);
  458.    
  459.     /* Unlock the VFS node. */
  460.     if (read)
  461.         rwlock_read_unlock(&file->node->contents_rwlock);
  462.     else {
  463.         /* Update the cached version of node's size. */
  464.         if (rc == EOK)
  465.             file->node->size = IPC_GET_ARG2(answer);
  466.         rwlock_write_unlock(&file->node->contents_rwlock);
  467.     }
  468.    
  469.     /* Update the position pointer and unlock the open file. */
  470.     if (rc == EOK)
  471.         file->pos += bytes;
  472.     futex_up(&file->lock);
  473.    
  474.     /*
  475.      * FS server's reply is the final result of the whole operation we
  476.      * return to the client.
  477.      */
  478.     ipc_answer_1(rid, rc, bytes);
  479. }
  480.  
  481. void vfs_read(ipc_callid_t rid, ipc_call_t *request)
  482. {
  483.     vfs_rdwr(rid, request, true);
  484. }
  485.  
  486. void vfs_write(ipc_callid_t rid, ipc_call_t *request)
  487. {
  488.     vfs_rdwr(rid, request, false);
  489. }
  490.  
  491. void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
  492. {
  493.     int fd = (int) IPC_GET_ARG1(*request);
  494.     off_t off = (off_t) IPC_GET_ARG2(*request);
  495.     int whence = (int) IPC_GET_ARG3(*request);
  496.  
  497.  
  498.     /* Lookup the file structure corresponding to the file descriptor. */
  499.     vfs_file_t *file = vfs_file_get(fd);
  500.     if (!file) {
  501.         ipc_answer_0(rid, ENOENT);
  502.         return;
  503.     }
  504.  
  505.     off_t newpos;
  506.     futex_down(&file->lock);
  507.     if (whence == SEEK_SET) {
  508.         file->pos = off;
  509.         futex_up(&file->lock);
  510.         ipc_answer_1(rid, EOK, off);
  511.         return;
  512.     }
  513.     if (whence == SEEK_CUR) {
  514.         if (file->pos + off < file->pos) {
  515.             futex_up(&file->lock);
  516.             ipc_answer_0(rid, EOVERFLOW);
  517.             return;
  518.         }
  519.         file->pos += off;
  520.         newpos = file->pos;
  521.         futex_up(&file->lock);
  522.         ipc_answer_1(rid, EOK, newpos);
  523.         return;
  524.     }
  525.     if (whence == SEEK_END) {
  526.         rwlock_read_lock(&file->node->contents_rwlock);
  527.         size_t size = file->node->size;
  528.         rwlock_read_unlock(&file->node->contents_rwlock);
  529.         if (size + off < size) {
  530.             futex_up(&file->lock);
  531.             ipc_answer_0(rid, EOVERFLOW);
  532.             return;
  533.         }
  534.         newpos = size + off;
  535.         futex_up(&file->lock);
  536.         ipc_answer_1(rid, EOK, newpos);
  537.         return;
  538.     }
  539.     futex_up(&file->lock);
  540.     ipc_answer_0(rid, EINVAL);
  541. }
  542.  
  543. int
  544. vfs_truncate_internal(fs_handle_t fs_handle, dev_handle_t dev_handle,
  545.     fs_index_t index, size_t size)
  546. {
  547.     ipcarg_t rc;
  548.     int fs_phone;
  549.    
  550.     fs_phone = vfs_grab_phone(fs_handle);
  551.     rc = async_req_3_0(fs_phone, VFS_TRUNCATE, (ipcarg_t)dev_handle,
  552.         (ipcarg_t)index, (ipcarg_t)size);
  553.     vfs_release_phone(fs_phone);
  554.     return (int)rc;
  555. }
  556.  
  557. void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
  558. {
  559.     int fd = IPC_GET_ARG1(*request);
  560.     size_t size = IPC_GET_ARG2(*request);
  561.     int rc;
  562.  
  563.     vfs_file_t *file = vfs_file_get(fd);
  564.     if (!file) {
  565.         ipc_answer_0(rid, ENOENT);
  566.         return;
  567.     }
  568.     futex_down(&file->lock);
  569.  
  570.     rwlock_write_lock(&file->node->contents_rwlock);
  571.     rc = vfs_truncate_internal(file->node->fs_handle,
  572.         file->node->dev_handle, file->node->index, size);
  573.     if (rc == EOK)
  574.         file->node->size = size;
  575.     rwlock_write_unlock(&file->node->contents_rwlock);
  576.  
  577.     futex_up(&file->lock);
  578.     ipc_answer_0(rid, (ipcarg_t)rc);
  579. }
  580.  
  581. void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
  582. {
  583.     int mode = IPC_GET_ARG1(*request);
  584.  
  585.     size_t len;
  586.     ipc_callid_t callid;
  587.  
  588.     if (!ipc_data_write_receive(&callid, &len)) {
  589.         ipc_answer_0(callid, EINVAL);
  590.         ipc_answer_0(rid, EINVAL);
  591.         return;
  592.     }
  593.     char *path = malloc(len + 1);
  594.     if (!path) {
  595.         ipc_answer_0(callid, ENOMEM);
  596.         ipc_answer_0(rid, ENOMEM);
  597.         return;
  598.     }
  599.     int rc;
  600.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  601.         ipc_answer_0(rid, rc);
  602.         free(path);
  603.         return;
  604.     }
  605.     path[len] = '\0';
  606.    
  607.     rwlock_write_lock(&namespace_rwlock);
  608.     int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
  609.     rc = vfs_lookup_internal(path, lflag, NULL, NULL);
  610.     rwlock_write_unlock(&namespace_rwlock);
  611.     free(path);
  612.     ipc_answer_0(rid, rc);
  613. }
  614.  
  615. void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
  616. {
  617.     int lflag = IPC_GET_ARG1(*request);
  618.  
  619.     size_t len;
  620.     ipc_callid_t callid;
  621.  
  622.     if (!ipc_data_write_receive(&callid, &len)) {
  623.         ipc_answer_0(callid, EINVAL);
  624.         ipc_answer_0(rid, EINVAL);
  625.         return;
  626.     }
  627.     char *path = malloc(len + 1);
  628.     if (!path) {
  629.         ipc_answer_0(callid, ENOMEM);
  630.         ipc_answer_0(rid, ENOMEM);
  631.         return;
  632.     }
  633.     int rc;
  634.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  635.         ipc_answer_0(rid, rc);
  636.         free(path);
  637.         return;
  638.     }
  639.     path[len] = '\0';
  640.    
  641.     rwlock_write_lock(&namespace_rwlock);
  642.     lflag &= L_DIRECTORY;   /* sanitize lflag */
  643.     vfs_lookup_res_t lr;
  644.     rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
  645.     free(path);
  646.     if (rc != EOK) {
  647.         rwlock_write_unlock(&namespace_rwlock);
  648.         ipc_answer_0(rid, rc);
  649.         return;
  650.     }
  651.  
  652.     /*
  653.      * The name has already been unlinked by vfs_lookup_internal().
  654.      * We have to get and put the VFS node to ensure that it is
  655.      * VFS_DESTROY'ed after the last reference to it is dropped.
  656.      */
  657.     vfs_node_t *node = vfs_node_get(&lr);
  658.     futex_down(&nodes_futex);
  659.     node->lnkcnt--;
  660.     futex_up(&nodes_futex);
  661.     rwlock_write_unlock(&namespace_rwlock);
  662.     vfs_node_put(node);
  663.     ipc_answer_0(rid, EOK);
  664. }
  665.  
  666. void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
  667. {
  668.     size_t len;
  669.     ipc_callid_t callid;
  670.     int rc;
  671.  
  672.     /* Retrieve the old path. */
  673.     if (!ipc_data_write_receive(&callid, &len)) {
  674.         ipc_answer_0(callid, EINVAL);
  675.         ipc_answer_0(rid, EINVAL);
  676.         return;
  677.     }
  678.     char *old = malloc(len + 1);
  679.     if (!old) {
  680.         ipc_answer_0(callid, ENOMEM);
  681.         ipc_answer_0(rid, ENOMEM);
  682.         return;
  683.     }
  684.     if ((rc = ipc_data_write_finalize(callid, old, len))) {
  685.         ipc_answer_0(rid, rc);
  686.         free(old);
  687.         return;
  688.     }
  689.     old[len] = '\0';
  690.    
  691.     /* Retrieve the new path. */
  692.     if (!ipc_data_write_receive(&callid, &len)) {
  693.         ipc_answer_0(callid, EINVAL);
  694.         ipc_answer_0(rid, EINVAL);
  695.         free(old);
  696.         return;
  697.     }
  698.     char *new = malloc(len + 1);
  699.     if (!new) {
  700.         ipc_answer_0(callid, ENOMEM);
  701.         ipc_answer_0(rid, ENOMEM);
  702.         free(old);
  703.         return;
  704.     }
  705.     if ((rc = ipc_data_write_finalize(callid, new, len))) {
  706.         ipc_answer_0(rid, rc);
  707.         free(old);
  708.         free(new);
  709.         return;
  710.     }
  711.     new[len] = '\0';
  712.  
  713.     char *oldc = canonify(old, &len);
  714.     char *newc = canonify(new, NULL);
  715.     if (!oldc || !newc) {
  716.         ipc_answer_0(rid, EINVAL);
  717.         free(old);
  718.         free(new);
  719.         return;
  720.     }
  721.     if (!strncmp(newc, oldc, len)) {
  722.         /* oldc is a prefix of newc */
  723.         ipc_answer_0(rid, EINVAL);
  724.         free(old);
  725.         free(new);
  726.         return;
  727.     }
  728.    
  729.     vfs_lookup_res_t old_lr;
  730.     vfs_lookup_res_t new_lr;
  731.     vfs_lookup_res_t new_par_lr;
  732.     rwlock_write_lock(&namespace_rwlock);
  733.     /* Lookup the node belonging to the old file name. */
  734.     rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
  735.     if (rc != EOK) {
  736.         rwlock_write_unlock(&namespace_rwlock);
  737.         ipc_answer_0(rid, rc);
  738.         free(old);
  739.         free(new);
  740.         return;
  741.     }
  742.     vfs_node_t *old_node = vfs_node_get(&old_lr);
  743.     if (!old_node) {
  744.         rwlock_write_unlock(&namespace_rwlock);
  745.         ipc_answer_0(rid, ENOMEM);
  746.         free(old);
  747.         free(new);
  748.         return;
  749.     }
  750.     /* Lookup parent of the new file name. */
  751.     rc = vfs_lookup_internal(newc, L_PARENT, &new_par_lr, NULL);
  752.     if (rc != EOK) {
  753.         rwlock_write_unlock(&namespace_rwlock);
  754.         ipc_answer_0(rid, rc);
  755.         free(old);
  756.         free(new);
  757.         return;
  758.     }
  759.     /* Check whether linking to the same file system instance. */
  760.     if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
  761.         (old_node->dev_handle != new_par_lr.triplet.dev_handle)) {
  762.         rwlock_write_unlock(&namespace_rwlock);
  763.         ipc_answer_0(rid, EXDEV);   /* different file systems */
  764.         free(old);
  765.         free(new);
  766.         return;
  767.     }
  768.     /* Destroy the old link for the new name. */
  769.     vfs_node_t *new_node = NULL;
  770.     rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
  771.     switch (rc) {
  772.     case ENOENT:
  773.         /* simply not in our way */
  774.         break;
  775.     case EOK:
  776.         new_node = vfs_node_get(&new_lr);
  777.         if (!new_node) {
  778.             rwlock_write_unlock(&namespace_rwlock);
  779.             ipc_answer_0(rid, ENOMEM);
  780.             free(old);
  781.             free(new);
  782.             return;
  783.         }
  784.         futex_down(&nodes_futex);
  785.         new_node->lnkcnt--;
  786.         futex_up(&nodes_futex);
  787.         break;
  788.     default:
  789.         rwlock_write_unlock(&namespace_rwlock);
  790.         ipc_answer_0(rid, ENOTEMPTY);
  791.         free(old);
  792.         free(new);
  793.         return;
  794.     }
  795.     /* Create the new link for the new name. */
  796.     rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
  797.     if (rc != EOK) {
  798.         rwlock_write_unlock(&namespace_rwlock);
  799.         if (new_node)
  800.             vfs_node_put(new_node);
  801.         ipc_answer_0(rid, rc);
  802.         free(old);
  803.         free(new);
  804.         return;
  805.     }
  806.     futex_down(&nodes_futex);
  807.     old_node->lnkcnt++;
  808.     futex_up(&nodes_futex);
  809.     /* Destroy the link for the old name. */
  810.     rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
  811.     if (rc != EOK) {
  812.         rwlock_write_unlock(&namespace_rwlock);
  813.         vfs_node_put(old_node);
  814.         if (new_node)
  815.             vfs_node_put(new_node);
  816.         ipc_answer_0(rid, rc);
  817.         free(old);
  818.         free(new);
  819.         return;
  820.     }
  821.     futex_down(&nodes_futex);
  822.     old_node->lnkcnt--;
  823.     futex_up(&nodes_futex);
  824.     rwlock_write_unlock(&namespace_rwlock);
  825.     vfs_node_put(old_node);
  826.     if (new_node)
  827.         vfs_node_put(new_node);
  828.     free(old);
  829.     free(new);
  830.     ipc_answer_0(rid, EOK);
  831. }
  832.  
  833. /**
  834.  * @}
  835.  */
  836.