Subversion Repositories HelenOS

Rev

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