Subversion Repositories HelenOS

Rev

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