Subversion Repositories HelenOS

Rev

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