Subversion Repositories HelenOS

Rev

Rev 3079 | Rev 3215 | 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.     if (fd >= MAX_OPEN_FILES) {
  378.         ipc_answer_0(rid, EBADF);
  379.         return;
  380.     }
  381.     vfs_fd_free(fd);
  382.     ipc_answer_0(rid, EOK);
  383. }
  384.  
  385. static void vfs_rdwr(ipc_callid_t rid, ipc_call_t *request, bool read)
  386. {
  387.  
  388.     /*
  389.      * The following code strongly depends on the fact that the files data
  390.      * structure can be only accessed by a single fibril and all file
  391.      * operations are serialized (i.e. the reads and writes cannot
  392.      * interleave and a file cannot be closed while it is being read).
  393.      *
  394.      * Additional synchronization needs to be added once the table of
  395.      * open files supports parallel access!
  396.      */
  397.  
  398.     int fd = IPC_GET_ARG1(*request);
  399.    
  400.     /* Lookup the file structure corresponding to the file descriptor. */
  401.     vfs_file_t *file = vfs_file_get(fd);
  402.     if (!file) {
  403.         ipc_answer_0(rid, ENOENT);
  404.         return;
  405.     }
  406.    
  407.     /*
  408.      * Now we need to receive a call with client's
  409.      * IPC_M_DATA_READ/IPC_M_DATA_WRITE request.
  410.      */
  411.     ipc_callid_t callid;
  412.     int res;
  413.     if (read)
  414.         res = ipc_data_read_receive(&callid, NULL);
  415.     else
  416.         res = ipc_data_write_receive(&callid, NULL);
  417.     if (!res) {
  418.         ipc_answer_0(callid, EINVAL);
  419.         ipc_answer_0(rid, EINVAL);
  420.         return;
  421.     }
  422.    
  423.     /*
  424.      * Lock the open file structure so that no other thread can manipulate
  425.      * the same open file at a time.
  426.      */
  427.     futex_down(&file->lock);
  428.    
  429.     /*
  430.      * Lock the file's node so that no other client can read/write to it at
  431.      * the same time.
  432.      */
  433.     if (read)
  434.         rwlock_read_lock(&file->node->contents_rwlock);
  435.     else
  436.         rwlock_write_lock(&file->node->contents_rwlock);
  437.    
  438.     int fs_phone = vfs_grab_phone(file->node->fs_handle);  
  439.    
  440.     /* Make a VFS_READ/VFS_WRITE request at the destination FS server. */
  441.     aid_t msg;
  442.     ipc_call_t answer;
  443.     if (!read && file->append)
  444.         file->pos = file->node->size;
  445.     msg = async_send_3(fs_phone, IPC_GET_METHOD(*request),
  446.         file->node->dev_handle, file->node->index, file->pos, &answer);
  447.    
  448.     /*
  449.      * Forward the IPC_M_DATA_READ/IPC_M_DATA_WRITE request to the
  450.      * destination FS server. The call will be routed as if sent by
  451.      * ourselves. Note that call arguments are immutable in this case so we
  452.      * don't have to bother.
  453.      */
  454.     ipc_forward_fast(callid, fs_phone, 0, 0, 0, IPC_FF_ROUTE_FROM_ME);
  455.    
  456.     vfs_release_phone(fs_phone);
  457.    
  458.     /* Wait for reply from the FS server. */
  459.     ipcarg_t rc;
  460.     async_wait_for(msg, &rc);
  461.     size_t bytes = IPC_GET_ARG1(answer);
  462.    
  463.     /* Unlock the VFS node. */
  464.     if (read)
  465.         rwlock_read_unlock(&file->node->contents_rwlock);
  466.     else {
  467.         /* Update the cached version of node's size. */
  468.         if (rc == EOK)
  469.             file->node->size = IPC_GET_ARG2(answer);
  470.         rwlock_write_unlock(&file->node->contents_rwlock);
  471.     }
  472.    
  473.     /* Update the position pointer and unlock the open file. */
  474.     if (rc == EOK)
  475.         file->pos += bytes;
  476.     futex_up(&file->lock);
  477.    
  478.     /*
  479.      * FS server's reply is the final result of the whole operation we
  480.      * return to the client.
  481.      */
  482.     ipc_answer_1(rid, rc, bytes);
  483. }
  484.  
  485. void vfs_read(ipc_callid_t rid, ipc_call_t *request)
  486. {
  487.     vfs_rdwr(rid, request, true);
  488. }
  489.  
  490. void vfs_write(ipc_callid_t rid, ipc_call_t *request)
  491. {
  492.     vfs_rdwr(rid, request, false);
  493. }
  494.  
  495. void vfs_seek(ipc_callid_t rid, ipc_call_t *request)
  496. {
  497.     int fd = (int) IPC_GET_ARG1(*request);
  498.     off_t off = (off_t) IPC_GET_ARG2(*request);
  499.     int whence = (int) IPC_GET_ARG3(*request);
  500.  
  501.  
  502.     /* Lookup the file structure corresponding to the file descriptor. */
  503.     vfs_file_t *file = vfs_file_get(fd);
  504.     if (!file) {
  505.         ipc_answer_0(rid, ENOENT);
  506.         return;
  507.     }
  508.  
  509.     off_t newpos;
  510.     futex_down(&file->lock);
  511.     if (whence == SEEK_SET) {
  512.         file->pos = off;
  513.         futex_up(&file->lock);
  514.         ipc_answer_1(rid, EOK, off);
  515.         return;
  516.     }
  517.     if (whence == SEEK_CUR) {
  518.         if (file->pos + off < file->pos) {
  519.             futex_up(&file->lock);
  520.             ipc_answer_0(rid, EOVERFLOW);
  521.             return;
  522.         }
  523.         file->pos += off;
  524.         newpos = file->pos;
  525.         futex_up(&file->lock);
  526.         ipc_answer_1(rid, EOK, newpos);
  527.         return;
  528.     }
  529.     if (whence == SEEK_END) {
  530.         rwlock_read_lock(&file->node->contents_rwlock);
  531.         size_t size = file->node->size;
  532.         rwlock_read_unlock(&file->node->contents_rwlock);
  533.         if (size + off < size) {
  534.             futex_up(&file->lock);
  535.             ipc_answer_0(rid, EOVERFLOW);
  536.             return;
  537.         }
  538.         newpos = size + off;
  539.         futex_up(&file->lock);
  540.         ipc_answer_1(rid, EOK, newpos);
  541.         return;
  542.     }
  543.     futex_up(&file->lock);
  544.     ipc_answer_0(rid, EINVAL);
  545. }
  546.  
  547. int
  548. vfs_truncate_internal(fs_handle_t fs_handle, dev_handle_t dev_handle,
  549.     fs_index_t index, size_t size)
  550. {
  551.     ipcarg_t rc;
  552.     int fs_phone;
  553.    
  554.     fs_phone = vfs_grab_phone(fs_handle);
  555.     rc = async_req_3_0(fs_phone, VFS_TRUNCATE, (ipcarg_t)dev_handle,
  556.         (ipcarg_t)index, (ipcarg_t)size);
  557.     vfs_release_phone(fs_phone);
  558.     return (int)rc;
  559. }
  560.  
  561. void vfs_truncate(ipc_callid_t rid, ipc_call_t *request)
  562. {
  563.     int fd = IPC_GET_ARG1(*request);
  564.     size_t size = IPC_GET_ARG2(*request);
  565.     int rc;
  566.  
  567.     vfs_file_t *file = vfs_file_get(fd);
  568.     if (!file) {
  569.         ipc_answer_0(rid, ENOENT);
  570.         return;
  571.     }
  572.     futex_down(&file->lock);
  573.  
  574.     rwlock_write_lock(&file->node->contents_rwlock);
  575.     rc = vfs_truncate_internal(file->node->fs_handle,
  576.         file->node->dev_handle, file->node->index, size);
  577.     if (rc == EOK)
  578.         file->node->size = size;
  579.     rwlock_write_unlock(&file->node->contents_rwlock);
  580.  
  581.     futex_up(&file->lock);
  582.     ipc_answer_0(rid, (ipcarg_t)rc);
  583. }
  584.  
  585. void vfs_mkdir(ipc_callid_t rid, ipc_call_t *request)
  586. {
  587.     int mode = IPC_GET_ARG1(*request);
  588.  
  589.     size_t len;
  590.     ipc_callid_t callid;
  591.  
  592.     if (!ipc_data_write_receive(&callid, &len)) {
  593.         ipc_answer_0(callid, EINVAL);
  594.         ipc_answer_0(rid, EINVAL);
  595.         return;
  596.     }
  597.     char *path = malloc(len + 1);
  598.     if (!path) {
  599.         ipc_answer_0(callid, ENOMEM);
  600.         ipc_answer_0(rid, ENOMEM);
  601.         return;
  602.     }
  603.     int rc;
  604.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  605.         ipc_answer_0(rid, rc);
  606.         free(path);
  607.         return;
  608.     }
  609.     path[len] = '\0';
  610.    
  611.     rwlock_write_lock(&namespace_rwlock);
  612.     int lflag = L_DIRECTORY | L_CREATE | L_EXCLUSIVE;
  613.     rc = vfs_lookup_internal(path, lflag, NULL, NULL);
  614.     rwlock_write_unlock(&namespace_rwlock);
  615.     free(path);
  616.     ipc_answer_0(rid, rc);
  617. }
  618.  
  619. void vfs_unlink(ipc_callid_t rid, ipc_call_t *request)
  620. {
  621.     int lflag = IPC_GET_ARG1(*request);
  622.  
  623.     size_t len;
  624.     ipc_callid_t callid;
  625.  
  626.     if (!ipc_data_write_receive(&callid, &len)) {
  627.         ipc_answer_0(callid, EINVAL);
  628.         ipc_answer_0(rid, EINVAL);
  629.         return;
  630.     }
  631.     char *path = malloc(len + 1);
  632.     if (!path) {
  633.         ipc_answer_0(callid, ENOMEM);
  634.         ipc_answer_0(rid, ENOMEM);
  635.         return;
  636.     }
  637.     int rc;
  638.     if ((rc = ipc_data_write_finalize(callid, path, len))) {
  639.         ipc_answer_0(rid, rc);
  640.         free(path);
  641.         return;
  642.     }
  643.     path[len] = '\0';
  644.    
  645.     rwlock_write_lock(&namespace_rwlock);
  646.     lflag &= L_DIRECTORY;   /* sanitize lflag */
  647.     vfs_lookup_res_t lr;
  648.     rc = vfs_lookup_internal(path, lflag | L_UNLINK, &lr, NULL);
  649.     free(path);
  650.     if (rc != EOK) {
  651.         rwlock_write_unlock(&namespace_rwlock);
  652.         ipc_answer_0(rid, rc);
  653.         return;
  654.     }
  655.  
  656.     /*
  657.      * The name has already been unlinked by vfs_lookup_internal().
  658.      * We have to get and put the VFS node to ensure that it is
  659.      * VFS_DESTROY'ed after the last reference to it is dropped.
  660.      */
  661.     vfs_node_t *node = vfs_node_get(&lr);
  662.     futex_down(&nodes_futex);
  663.     node->lnkcnt--;
  664.     futex_up(&nodes_futex);
  665.     rwlock_write_unlock(&namespace_rwlock);
  666.     vfs_node_put(node);
  667.     ipc_answer_0(rid, EOK);
  668. }
  669.  
  670. void vfs_rename(ipc_callid_t rid, ipc_call_t *request)
  671. {
  672.     size_t len;
  673.     ipc_callid_t callid;
  674.     int rc;
  675.  
  676.     /* Retrieve the old path. */
  677.     if (!ipc_data_write_receive(&callid, &len)) {
  678.         ipc_answer_0(callid, EINVAL);
  679.         ipc_answer_0(rid, EINVAL);
  680.         return;
  681.     }
  682.     char *old = malloc(len + 1);
  683.     if (!old) {
  684.         ipc_answer_0(callid, ENOMEM);
  685.         ipc_answer_0(rid, ENOMEM);
  686.         return;
  687.     }
  688.     if ((rc = ipc_data_write_finalize(callid, old, len))) {
  689.         ipc_answer_0(rid, rc);
  690.         free(old);
  691.         return;
  692.     }
  693.     old[len] = '\0';
  694.    
  695.     /* Retrieve the new path. */
  696.     if (!ipc_data_write_receive(&callid, &len)) {
  697.         ipc_answer_0(callid, EINVAL);
  698.         ipc_answer_0(rid, EINVAL);
  699.         free(old);
  700.         return;
  701.     }
  702.     char *new = malloc(len + 1);
  703.     if (!new) {
  704.         ipc_answer_0(callid, ENOMEM);
  705.         ipc_answer_0(rid, ENOMEM);
  706.         free(old);
  707.         return;
  708.     }
  709.     if ((rc = ipc_data_write_finalize(callid, new, len))) {
  710.         ipc_answer_0(rid, rc);
  711.         free(old);
  712.         free(new);
  713.         return;
  714.     }
  715.     new[len] = '\0';
  716.  
  717.     char *oldc = canonify(old, &len);
  718.     char *newc = canonify(new, NULL);
  719.     if (!oldc || !newc) {
  720.         ipc_answer_0(rid, EINVAL);
  721.         free(old);
  722.         free(new);
  723.         return;
  724.     }
  725.     if (!strncmp(newc, oldc, len)) {
  726.         /* oldc is a prefix of newc */
  727.         ipc_answer_0(rid, EINVAL);
  728.         free(old);
  729.         free(new);
  730.         return;
  731.     }
  732.    
  733.     vfs_lookup_res_t old_lr;
  734.     vfs_lookup_res_t new_lr;
  735.     vfs_lookup_res_t new_par_lr;
  736.     rwlock_write_lock(&namespace_rwlock);
  737.     /* Lookup the node belonging to the old file name. */
  738.     rc = vfs_lookup_internal(oldc, L_NONE, &old_lr, NULL);
  739.     if (rc != EOK) {
  740.         rwlock_write_unlock(&namespace_rwlock);
  741.         ipc_answer_0(rid, rc);
  742.         free(old);
  743.         free(new);
  744.         return;
  745.     }
  746.     vfs_node_t *old_node = vfs_node_get(&old_lr);
  747.     if (!old_node) {
  748.         rwlock_write_unlock(&namespace_rwlock);
  749.         ipc_answer_0(rid, ENOMEM);
  750.         free(old);
  751.         free(new);
  752.         return;
  753.     }
  754.     /* Lookup parent of the new file name. */
  755.     rc = vfs_lookup_internal(newc, L_PARENT, &new_par_lr, NULL);
  756.     if (rc != EOK) {
  757.         rwlock_write_unlock(&namespace_rwlock);
  758.         ipc_answer_0(rid, rc);
  759.         free(old);
  760.         free(new);
  761.         return;
  762.     }
  763.     /* Check whether linking to the same file system instance. */
  764.     if ((old_node->fs_handle != new_par_lr.triplet.fs_handle) ||
  765.         (old_node->dev_handle != new_par_lr.triplet.dev_handle)) {
  766.         rwlock_write_unlock(&namespace_rwlock);
  767.         ipc_answer_0(rid, EXDEV);   /* different file systems */
  768.         free(old);
  769.         free(new);
  770.         return;
  771.     }
  772.     /* Destroy the old link for the new name. */
  773.     vfs_node_t *new_node = NULL;
  774.     rc = vfs_lookup_internal(newc, L_UNLINK, &new_lr, NULL);
  775.     switch (rc) {
  776.     case ENOENT:
  777.         /* simply not in our way */
  778.         break;
  779.     case EOK:
  780.         new_node = vfs_node_get(&new_lr);
  781.         if (!new_node) {
  782.             rwlock_write_unlock(&namespace_rwlock);
  783.             ipc_answer_0(rid, ENOMEM);
  784.             free(old);
  785.             free(new);
  786.             return;
  787.         }
  788.         futex_down(&nodes_futex);
  789.         new_node->lnkcnt--;
  790.         futex_up(&nodes_futex);
  791.         break;
  792.     default:
  793.         rwlock_write_unlock(&namespace_rwlock);
  794.         ipc_answer_0(rid, ENOTEMPTY);
  795.         free(old);
  796.         free(new);
  797.         return;
  798.     }
  799.     /* Create the new link for the new name. */
  800.     rc = vfs_lookup_internal(newc, L_LINK, NULL, NULL, old_node->index);
  801.     if (rc != EOK) {
  802.         rwlock_write_unlock(&namespace_rwlock);
  803.         if (new_node)
  804.             vfs_node_put(new_node);
  805.         ipc_answer_0(rid, rc);
  806.         free(old);
  807.         free(new);
  808.         return;
  809.     }
  810.     futex_down(&nodes_futex);
  811.     old_node->lnkcnt++;
  812.     futex_up(&nodes_futex);
  813.     /* Destroy the link for the old name. */
  814.     rc = vfs_lookup_internal(oldc, L_UNLINK, NULL, NULL);
  815.     if (rc != EOK) {
  816.         rwlock_write_unlock(&namespace_rwlock);
  817.         vfs_node_put(old_node);
  818.         if (new_node)
  819.             vfs_node_put(new_node);
  820.         ipc_answer_0(rid, rc);
  821.         free(old);
  822.         free(new);
  823.         return;
  824.     }
  825.     futex_down(&nodes_futex);
  826.     old_node->lnkcnt--;
  827.     futex_up(&nodes_futex);
  828.     rwlock_write_unlock(&namespace_rwlock);
  829.     vfs_node_put(old_node);
  830.     if (new_node)
  831.         vfs_node_put(new_node);
  832.     free(old);
  833.     free(new);
  834.     ipc_answer_0(rid, EOK);
  835. }
  836.  
  837. /**
  838.  * @}
  839.  */
  840.