Subversion Repositories HelenOS

Rev

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