Subversion Repositories HelenOS

Rev

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