Subversion Repositories HelenOS

Rev

Rev 3492 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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