Subversion Repositories HelenOS

Rev

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