Subversion Repositories HelenOS

Rev

Rev 4581 | 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_lookup.c
  35.  * @brief
  36.  */
  37.  
  38. #include "vfs.h"
  39. #include <ipc/ipc.h>
  40. #include <async.h>
  41. #include <errno.h>
  42. #include <string.h>
  43. #include <stdarg.h>
  44. #include <bool.h>
  45. #include <fibril_sync.h>
  46. #include <adt/list.h>
  47. #include <vfs/canonify.h>
  48.  
  49. #define min(a, b)  ((a) < (b) ? (a) : (b))
  50.  
  51. FIBRIL_MUTEX_INITIALIZE(plb_mutex);
  52. LIST_INITIALIZE(plb_head);  /**< PLB entry ring buffer. */
  53. uint8_t *plb = NULL;
  54.  
  55. /** Perform a path lookup.
  56.  *
  57.  * @param path    Path to be resolved; it must be a NULL-terminated
  58.  *                string.
  59.  * @param lflag   Flags to be used during lookup.
  60.  * @param result  Empty structure where the lookup result will be stored.
  61.  *                Can be NULL.
  62.  * @param altroot If non-empty, will be used instead of rootfs as the root
  63.  *                of the whole VFS tree.
  64.  *
  65.  * @return EOK on success or an error code from errno.h.
  66.  *
  67.  */
  68. int vfs_lookup_internal(char *path, int lflag, vfs_lookup_res_t *result,
  69.     vfs_pair_t *altroot, ...)
  70. {
  71.     vfs_pair_t *root;
  72.  
  73.     if (altroot)
  74.         root = altroot;
  75.     else
  76.         root = &rootfs;
  77.  
  78.     if (!root->fs_handle)
  79.         return ENOENT;
  80.    
  81.     size_t len;
  82.     path = canonify(path, &len);
  83.     if (!path)
  84.         return EINVAL;
  85.    
  86.     fs_index_t index = 0;
  87.     if (lflag & L_LINK) {
  88.         va_list ap;
  89.  
  90.         va_start(ap, altroot);
  91.         index = va_arg(ap, fs_index_t);
  92.         va_end(ap);
  93.     }
  94.    
  95.     fibril_mutex_lock(&plb_mutex);
  96.  
  97.     plb_entry_t entry;
  98.     link_initialize(&entry.plb_link);
  99.     entry.len = len;
  100.  
  101.     off_t first;    /* the first free index */
  102.     off_t last; /* the last free index */
  103.  
  104.     if (list_empty(&plb_head)) {
  105.         first = 0;
  106.         last = PLB_SIZE - 1;
  107.     } else {
  108.         plb_entry_t *oldest = list_get_instance(plb_head.next,
  109.             plb_entry_t, plb_link);
  110.         plb_entry_t *newest = list_get_instance(plb_head.prev,
  111.             plb_entry_t, plb_link);
  112.  
  113.         first = (newest->index + newest->len) % PLB_SIZE;
  114.         last = (oldest->index - 1) % PLB_SIZE;
  115.     }
  116.  
  117.     if (first <= last) {
  118.         if ((last - first) + 1 < len) {
  119.             /*
  120.              * The buffer cannot absorb the path.
  121.              */
  122.             fibril_mutex_unlock(&plb_mutex);
  123.             return ELIMIT;
  124.         }
  125.     } else {
  126.         if (PLB_SIZE - ((first - last) + 1) < len) {
  127.             /*
  128.              * The buffer cannot absorb the path.
  129.              */
  130.             fibril_mutex_unlock(&plb_mutex);
  131.             return ELIMIT;
  132.         }
  133.     }
  134.  
  135.     /*
  136.      * We know the first free index in PLB and we also know that there is
  137.      * enough space in the buffer to hold our path.
  138.      */
  139.  
  140.     entry.index = first;
  141.     entry.len = len;
  142.  
  143.     /*
  144.      * Claim PLB space by inserting the entry into the PLB entry ring
  145.      * buffer.
  146.      */
  147.     list_append(&entry.plb_link, &plb_head);
  148.    
  149.     fibril_mutex_unlock(&plb_mutex);
  150.  
  151.     /*
  152.      * Copy the path into PLB.
  153.      */
  154.     size_t cnt1 = min(len, (PLB_SIZE - first) + 1);
  155.     size_t cnt2 = len - cnt1;
  156.    
  157.     memcpy(&plb[first], path, cnt1);
  158.     memcpy(plb, &path[cnt1], cnt2);
  159.  
  160.     ipc_call_t answer;
  161.     int phone = vfs_grab_phone(root->fs_handle);
  162.     aid_t req = async_send_5(phone, VFS_OUT_LOOKUP, (ipcarg_t) first,
  163.         (ipcarg_t) (first + len - 1) % PLB_SIZE,
  164.         (ipcarg_t) root->dev_handle, (ipcarg_t) lflag, (ipcarg_t) index,
  165.         &answer);
  166.    
  167.     ipcarg_t rc;
  168.     async_wait_for(req, &rc);
  169.     vfs_release_phone(phone);
  170.    
  171.     fibril_mutex_lock(&plb_mutex);
  172.     list_remove(&entry.plb_link);
  173.     /*
  174.      * Erasing the path from PLB will come handy for debugging purposes.
  175.      */
  176.     memset(&plb[first], 0, cnt1);
  177.     memset(plb, 0, cnt2);
  178.     fibril_mutex_unlock(&plb_mutex);
  179.  
  180.     if ((rc == EOK) && (result)) {
  181.         result->triplet.fs_handle = (fs_handle_t) IPC_GET_ARG1(answer);
  182.         result->triplet.dev_handle = (dev_handle_t) IPC_GET_ARG2(answer);
  183.         result->triplet.index = (fs_index_t) IPC_GET_ARG3(answer);
  184.         result->size = (size_t) IPC_GET_ARG4(answer);
  185.         result->lnkcnt = (unsigned) IPC_GET_ARG5(answer);
  186.         if (lflag & L_FILE)
  187.             result->type = VFS_NODE_FILE;
  188.         else if (lflag & L_DIRECTORY)
  189.             result->type = VFS_NODE_DIRECTORY;
  190.         else
  191.             result->type = VFS_NODE_UNKNOWN;
  192.     }
  193.  
  194.     return rc;
  195. }
  196.  
  197. /** Perform a node open operation.
  198.  *
  199.  * @return EOK on success or an error code from errno.h.
  200.  *
  201.  */
  202. int vfs_open_node_internal(vfs_lookup_res_t *result)
  203. {
  204.     int phone = vfs_grab_phone(result->triplet.fs_handle);
  205.    
  206.     ipc_call_t answer;
  207.     aid_t req = async_send_2(phone, VFS_OUT_OPEN_NODE,
  208.         (ipcarg_t) result->triplet.dev_handle,
  209.         (ipcarg_t) result->triplet.index, &answer);
  210.    
  211.    
  212.     ipcarg_t rc;
  213.     async_wait_for(req, &rc);
  214.     vfs_release_phone(phone);
  215.    
  216.     if (rc == EOK) {
  217.         result->size = (size_t) IPC_GET_ARG1(answer);
  218.         result->lnkcnt = (unsigned) IPC_GET_ARG2(answer);
  219.         if (IPC_GET_ARG3(answer) & L_FILE)
  220.             result->type = VFS_NODE_FILE;
  221.         else if (IPC_GET_ARG3(answer) & L_DIRECTORY)
  222.             result->type = VFS_NODE_DIRECTORY;
  223.         else
  224.             result->type = VFS_NODE_UNKNOWN;
  225.     }
  226.    
  227.     return rc;
  228. }
  229.  
  230. /**
  231.  * @}
  232.  */
  233.