Subversion Repositories HelenOS

Rev

Rev 4337 | Rev 4389 | 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    fat_ops.c
  35.  * @brief   Implementation of VFS operations for the FAT file system server.
  36.  */
  37.  
  38. #include "fat.h"
  39. #include "fat_dentry.h"
  40. #include "fat_fat.h"
  41. #include "../../vfs/vfs.h"
  42. #include <libfs.h>
  43. #include <libblock.h>
  44. #include <ipc/ipc.h>
  45. #include <ipc/services.h>
  46. #include <ipc/devmap.h>
  47. #include <async.h>
  48. #include <errno.h>
  49. #include <string.h>
  50. #include <byteorder.h>
  51. #include <libadt/hash_table.h>
  52. #include <libadt/list.h>
  53. #include <assert.h>
  54. #include <futex.h>
  55. #include <sys/mman.h>
  56. #include <align.h>
  57.  
  58. /** Futex protecting the list of cached free FAT nodes. */
  59. static futex_t ffn_futex = FUTEX_INITIALIZER;
  60.  
  61. /** List of cached free FAT nodes. */
  62. static LIST_INITIALIZE(ffn_head);
  63.  
  64. static void fat_node_initialize(fat_node_t *node)
  65. {
  66.     futex_initialize(&node->lock, 1);
  67.     node->idx = NULL;
  68.     node->type = 0;
  69.     link_initialize(&node->ffn_link);
  70.     node->size = 0;
  71.     node->lnkcnt = 0;
  72.     node->refcnt = 0;
  73.     node->dirty = false;
  74. }
  75.  
  76. static void fat_node_sync(fat_node_t *node)
  77. {
  78.     block_t *b;
  79.     fat_bs_t *bs;
  80.     fat_dentry_t *d;
  81.     uint16_t bps;
  82.     unsigned dps;
  83.    
  84.     assert(node->dirty);
  85.  
  86.     bs = block_bb_get(node->idx->dev_handle);
  87.     bps = uint16_t_le2host(bs->bps);
  88.     dps = bps / sizeof(fat_dentry_t);
  89.    
  90.     /* Read the block that contains the dentry of interest. */
  91.     b = _fat_block_get(bs, node->idx->dev_handle, node->idx->pfc,
  92.         (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
  93.  
  94.     d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
  95.  
  96.     d->firstc = host2uint16_t_le(node->firstc);
  97.     if (node->type == FAT_FILE) {
  98.         d->size = host2uint32_t_le(node->size);
  99.     } else if (node->type == FAT_DIRECTORY) {
  100.         d->attr = FAT_ATTR_SUBDIR;
  101.     }
  102.    
  103.     /* TODO: update other fields? (e.g time fields) */
  104.    
  105.     b->dirty = true;        /* need to sync block */
  106.     block_put(b);
  107. }
  108.  
  109. static fat_node_t *fat_node_get_new(void)
  110. {
  111.     fat_node_t *nodep;
  112.  
  113.     futex_down(&ffn_futex);
  114.     if (!list_empty(&ffn_head)) {
  115.         /* Try to use a cached free node structure. */
  116.         fat_idx_t *idxp_tmp;
  117.         nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
  118.         if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
  119.             goto skip_cache;
  120.         idxp_tmp = nodep->idx;
  121.         if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
  122.             futex_up(&nodep->lock);
  123.             goto skip_cache;
  124.         }
  125.         list_remove(&nodep->ffn_link);
  126.         futex_up(&ffn_futex);
  127.         if (nodep->dirty)
  128.             fat_node_sync(nodep);
  129.         idxp_tmp->nodep = NULL;
  130.         futex_up(&nodep->lock);
  131.         futex_up(&idxp_tmp->lock);
  132.     } else {
  133. skip_cache:
  134.         /* Try to allocate a new node structure. */
  135.         futex_up(&ffn_futex);
  136.         nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
  137.         if (!nodep)
  138.             return NULL;
  139.     }
  140.     fat_node_initialize(nodep);
  141.    
  142.     return nodep;
  143. }
  144.  
  145. /** Internal version of fat_node_get().
  146.  *
  147.  * @param idxp      Locked index structure.
  148.  */
  149. static void *fat_node_get_core(fat_idx_t *idxp)
  150. {
  151.     block_t *b;
  152.     fat_bs_t *bs;
  153.     fat_dentry_t *d;
  154.     fat_node_t *nodep = NULL;
  155.     unsigned bps;
  156.     unsigned spc;
  157.     unsigned dps;
  158.  
  159.     if (idxp->nodep) {
  160.         /*
  161.          * We are lucky.
  162.          * The node is already instantiated in memory.
  163.          */
  164.         futex_down(&idxp->nodep->lock);
  165.         if (!idxp->nodep->refcnt++)
  166.             list_remove(&idxp->nodep->ffn_link);
  167.         futex_up(&idxp->nodep->lock);
  168.         return idxp->nodep;
  169.     }
  170.  
  171.     /*
  172.      * We must instantiate the node from the file system.
  173.      */
  174.    
  175.     assert(idxp->pfc);
  176.  
  177.     nodep = fat_node_get_new();
  178.     if (!nodep)
  179.         return NULL;
  180.  
  181.     bs = block_bb_get(idxp->dev_handle);
  182.     bps = uint16_t_le2host(bs->bps);
  183.     spc = bs->spc;
  184.     dps = bps / sizeof(fat_dentry_t);
  185.  
  186.     /* Read the block that contains the dentry of interest. */
  187.     b = _fat_block_get(bs, idxp->dev_handle, idxp->pfc,
  188.         (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
  189.     assert(b);
  190.  
  191.     d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
  192.     if (d->attr & FAT_ATTR_SUBDIR) {
  193.         /*
  194.          * The only directory which does not have this bit set is the
  195.          * root directory itself. The root directory node is handled
  196.          * and initialized elsewhere.
  197.          */
  198.         nodep->type = FAT_DIRECTORY;
  199.         /*
  200.          * Unfortunately, the 'size' field of the FAT dentry is not
  201.          * defined for the directory entry type. We must determine the
  202.          * size of the directory by walking the FAT.
  203.          */
  204.         nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
  205.             uint16_t_le2host(d->firstc));
  206.     } else {
  207.         nodep->type = FAT_FILE;
  208.         nodep->size = uint32_t_le2host(d->size);
  209.     }
  210.     nodep->firstc = uint16_t_le2host(d->firstc);
  211.     nodep->lnkcnt = 1;
  212.     nodep->refcnt = 1;
  213.  
  214.     block_put(b);
  215.  
  216.     /* Link the idx structure with the node structure. */
  217.     nodep->idx = idxp;
  218.     idxp->nodep = nodep;
  219.  
  220.     return nodep;
  221. }
  222.  
  223. /*
  224.  * Forward declarations of FAT libfs operations.
  225.  */
  226. static void *fat_node_get(dev_handle_t, fs_index_t);
  227. static void fat_node_put(void *);
  228. static void *fat_create_node(dev_handle_t, int);
  229. static int fat_destroy_node(void *);
  230. static int fat_link(void *, void *, const char *);
  231. static int fat_unlink(void *, void *);
  232. static void *fat_match(void *, const char *);
  233. static fs_index_t fat_index_get(void *);
  234. static size_t fat_size_get(void *);
  235. static unsigned fat_lnkcnt_get(void *);
  236. static bool fat_has_children(void *);
  237. static void *fat_root_get(dev_handle_t);
  238. static char fat_plb_get_char(unsigned);
  239. static bool fat_is_directory(void *);
  240. static bool fat_is_file(void *node);
  241.  
  242. /*
  243.  * FAT libfs operations.
  244.  */
  245.  
  246. /** Instantiate a FAT in-core node. */
  247. void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  248. {
  249.     void *node;
  250.     fat_idx_t *idxp;
  251.  
  252.     idxp = fat_idx_get_by_index(dev_handle, index);
  253.     if (!idxp)
  254.         return NULL;
  255.     /* idxp->lock held */
  256.     node = fat_node_get_core(idxp);
  257.     futex_up(&idxp->lock);
  258.     return node;
  259. }
  260.  
  261. void fat_node_put(void *node)
  262. {
  263.     fat_node_t *nodep = (fat_node_t *)node;
  264.     bool destroy = false;
  265.  
  266.     futex_down(&nodep->lock);
  267.     if (!--nodep->refcnt) {
  268.         if (nodep->idx) {
  269.             futex_down(&ffn_futex);
  270.             list_append(&nodep->ffn_link, &ffn_head);
  271.             futex_up(&ffn_futex);
  272.         } else {
  273.             /*
  274.              * The node does not have any index structure associated
  275.              * with itself. This can only mean that we are releasing
  276.              * the node after a failed attempt to allocate the index
  277.              * structure for it.
  278.              */
  279.             destroy = true;
  280.         }
  281.     }
  282.     futex_up(&nodep->lock);
  283.     if (destroy)
  284.         free(node);
  285. }
  286.  
  287. void *fat_create_node(dev_handle_t dev_handle, int flags)
  288. {
  289.     fat_idx_t *idxp;
  290.     fat_node_t *nodep;
  291.     fat_bs_t *bs;
  292.     fat_cluster_t mcl, lcl;
  293.     uint16_t bps;
  294.     int rc;
  295.  
  296.     bs = block_bb_get(dev_handle);
  297.     bps = uint16_t_le2host(bs->bps);
  298.     if (flags & L_DIRECTORY) {
  299.         /* allocate a cluster */
  300.         rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
  301.         if (rc != EOK)
  302.             return NULL;
  303.     }
  304.  
  305.     nodep = fat_node_get_new();
  306.     if (!nodep) {
  307.         fat_free_clusters(bs, dev_handle, mcl);
  308.         return NULL;
  309.     }
  310.     idxp = fat_idx_get_new(dev_handle);
  311.     if (!idxp) {
  312.         fat_free_clusters(bs, dev_handle, mcl);
  313.         fat_node_put(nodep);
  314.         return NULL;
  315.     }
  316.     /* idxp->lock held */
  317.     if (flags & L_DIRECTORY) {
  318.         int i;
  319.         block_t *b;
  320.  
  321.         /*
  322.          * Populate the new cluster with unused dentries.
  323.          */
  324.         for (i = 0; i < bs->spc; i++) {
  325.             b = _fat_block_get(bs, dev_handle, mcl, i,
  326.                 BLOCK_FLAGS_NOREAD);
  327.             /* mark all dentries as never-used */
  328.             memset(b->data, 0, bps);
  329.             b->dirty = false;
  330.             block_put(b);
  331.         }
  332.         nodep->type = FAT_DIRECTORY;
  333.         nodep->firstc = mcl;
  334.         nodep->size = bps * bs->spc;
  335.     } else {
  336.         nodep->type = FAT_FILE;
  337.         nodep->firstc = FAT_CLST_RES0;
  338.         nodep->size = 0;
  339.     }
  340.     nodep->lnkcnt = 0;  /* not linked anywhere */
  341.     nodep->refcnt = 1;
  342.     nodep->dirty = true;
  343.  
  344.     nodep->idx = idxp;
  345.     idxp->nodep = nodep;
  346.  
  347.     futex_up(&idxp->lock);
  348.     return nodep;
  349. }
  350.  
  351. int fat_destroy_node(void *node)
  352. {
  353.     fat_node_t *nodep = (fat_node_t *)node;
  354.     fat_bs_t *bs;
  355.  
  356.     /*
  357.      * The node is not reachable from the file system. This means that the
  358.      * link count should be zero and that the index structure cannot be
  359.      * found in the position hash. Obviously, we don't need to lock the node
  360.      * nor its index structure.
  361.      */
  362.     assert(nodep->lnkcnt == 0);
  363.  
  364.     /*
  365.      * The node may not have any children.
  366.      */
  367.     assert(fat_has_children(node) == false);
  368.  
  369.     bs = block_bb_get(nodep->idx->dev_handle);
  370.     if (nodep->firstc != FAT_CLST_RES0) {
  371.         assert(nodep->size);
  372.         /* Free all clusters allocated to the node. */
  373.         fat_free_clusters(bs, nodep->idx->dev_handle, nodep->firstc);
  374.     }
  375.  
  376.     fat_idx_destroy(nodep->idx);
  377.     free(nodep);
  378.     return EOK;
  379. }
  380.  
  381. int fat_link(void *prnt, void *chld, const char *name)
  382. {
  383.     fat_node_t *parentp = (fat_node_t *)prnt;
  384.     fat_node_t *childp = (fat_node_t *)chld;
  385.     fat_dentry_t *d;
  386.     fat_bs_t *bs;
  387.     block_t *b;
  388.     int i, j;
  389.     uint16_t bps;
  390.     unsigned dps;
  391.     unsigned blocks;
  392.     fat_cluster_t mcl, lcl;
  393.     int rc;
  394.  
  395.     futex_down(&childp->lock);
  396.     if (childp->lnkcnt == 1) {
  397.         /*
  398.          * On FAT, we don't support multiple hard links.
  399.          */
  400.         futex_up(&childp->lock);
  401.         return EMLINK;
  402.     }
  403.     assert(childp->lnkcnt == 0);
  404.     futex_up(&childp->lock);
  405.  
  406.     if (!fat_dentry_name_verify(name)) {
  407.         /*
  408.          * Attempt to create unsupported name.
  409.          */
  410.         return ENOTSUP;
  411.     }
  412.  
  413.     /*
  414.      * Get us an unused parent node's dentry or grow the parent and allocate
  415.      * a new one.
  416.      */
  417.    
  418.     futex_down(&parentp->idx->lock);
  419.     bs = block_bb_get(parentp->idx->dev_handle);
  420.     bps = uint16_t_le2host(bs->bps);
  421.     dps = bps / sizeof(fat_dentry_t);
  422.  
  423.     blocks = parentp->size / bps;
  424.  
  425.     for (i = 0; i < blocks; i++) {
  426.         b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
  427.         for (j = 0; j < dps; j++) {
  428.             d = ((fat_dentry_t *)b->data) + j;
  429.             switch (fat_classify_dentry(d)) {
  430.             case FAT_DENTRY_SKIP:
  431.             case FAT_DENTRY_VALID:
  432.                 /* skipping used and meta entries */
  433.                 continue;
  434.             case FAT_DENTRY_FREE:
  435.             case FAT_DENTRY_LAST:
  436.                 /* found an empty slot */
  437.                 goto hit;
  438.             }
  439.         }
  440.         block_put(b);
  441.     }
  442.     j = 0;
  443.    
  444.     /*
  445.      * We need to grow the parent in order to create a new unused dentry.
  446.      */
  447.     if (parentp->idx->pfc == FAT_CLST_ROOT) {
  448.         /* Can't grow the root directory. */
  449.         futex_up(&parentp->idx->lock);
  450.         return ENOSPC;
  451.     }
  452.     rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
  453.     if (rc != EOK) {
  454.         futex_up(&parentp->idx->lock);
  455.         return rc;
  456.     }
  457.     fat_append_clusters(bs, parentp, mcl);
  458.     b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NOREAD);
  459.     d = (fat_dentry_t *)b->data;
  460.     /*
  461.      * Clear all dentries in the block except for the first one (the first
  462.      * dentry will be cleared in the next step).
  463.      */
  464.     memset(d + 1, 0, bps - sizeof(fat_dentry_t));
  465.  
  466. hit:
  467.     /*
  468.      * At this point we only establish the link between the parent and the
  469.      * child.  The dentry, except of the name and the extension, will remain
  470.      * uninitialized until the corresponding node is synced. Thus the valid
  471.      * dentry data is kept in the child node structure.
  472.      */
  473.     memset(d, 0, sizeof(fat_dentry_t));
  474.     fat_dentry_name_set(d, name);
  475.     b->dirty = true;        /* need to sync block */
  476.     block_put(b);
  477.     futex_up(&parentp->idx->lock);
  478.  
  479.     futex_down(&childp->idx->lock);
  480.    
  481.     /*
  482.      * If possible, create the Sub-directory Identifier Entry and the
  483.      * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
  484.      * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
  485.      * not use them anyway, so this is rather a sign of our good will.
  486.      */
  487.     b = fat_block_get(bs, childp, 0, BLOCK_FLAGS_NONE);
  488.     d = (fat_dentry_t *)b->data;
  489.     if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
  490.         str_cmp(d->name, FAT_NAME_DOT) == 0) {
  491.         memset(d, 0, sizeof(fat_dentry_t));
  492.         str_cpy(d->name, 8, FAT_NAME_DOT);
  493.         str_cpy(d->ext, 3, FAT_EXT_PAD);
  494.         d->attr = FAT_ATTR_SUBDIR;
  495.         d->firstc = host2uint16_t_le(childp->firstc);
  496.         /* TODO: initialize also the date/time members. */
  497.     }
  498.     d++;
  499.     if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
  500.         str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
  501.         memset(d, 0, sizeof(fat_dentry_t));
  502.         str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
  503.         str_cpy(d->ext, 3, FAT_EXT_PAD);
  504.         d->attr = FAT_ATTR_SUBDIR;
  505.         d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
  506.             host2uint16_t_le(FAT_CLST_RES0) :
  507.             host2uint16_t_le(parentp->firstc);
  508.         /* TODO: initialize also the date/time members. */
  509.     }
  510.     b->dirty = true;        /* need to sync block */
  511.     block_put(b);
  512.  
  513.     childp->idx->pfc = parentp->firstc;
  514.     childp->idx->pdi = i * dps + j;
  515.     futex_up(&childp->idx->lock);
  516.  
  517.     futex_down(&childp->lock);
  518.     childp->lnkcnt = 1;
  519.     childp->dirty = true;       /* need to sync node */
  520.     futex_up(&childp->lock);
  521.  
  522.     /*
  523.      * Hash in the index structure into the position hash.
  524.      */
  525.     fat_idx_hashin(childp->idx);
  526.  
  527.     return EOK;
  528. }
  529.  
  530. int fat_unlink(void *prnt, void *chld)
  531. {
  532.     fat_node_t *parentp = (fat_node_t *)prnt;
  533.     fat_node_t *childp = (fat_node_t *)chld;
  534.     fat_bs_t *bs;
  535.     fat_dentry_t *d;
  536.     uint16_t bps;
  537.     block_t *b;
  538.  
  539.     futex_down(&parentp->lock);
  540.     futex_down(&childp->lock);
  541.     assert(childp->lnkcnt == 1);
  542.     futex_down(&childp->idx->lock);
  543.     bs = block_bb_get(childp->idx->dev_handle);
  544.     bps = uint16_t_le2host(bs->bps);
  545.  
  546.     b = _fat_block_get(bs, childp->idx->dev_handle, childp->idx->pfc,
  547.         (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
  548.         BLOCK_FLAGS_NONE);
  549.     d = (fat_dentry_t *)b->data +
  550.         (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
  551.     /* mark the dentry as not-currently-used */
  552.     d->name[0] = FAT_DENTRY_ERASED;
  553.     b->dirty = true;        /* need to sync block */
  554.     block_put(b);
  555.  
  556.     /* remove the index structure from the position hash */
  557.     fat_idx_hashout(childp->idx);
  558.     /* clear position information */
  559.     childp->idx->pfc = FAT_CLST_RES0;
  560.     childp->idx->pdi = 0;
  561.     futex_up(&childp->idx->lock);
  562.     childp->lnkcnt = 0;
  563.     childp->dirty = true;
  564.     futex_up(&childp->lock);
  565.     futex_up(&parentp->lock);
  566.  
  567.     return EOK;
  568. }
  569.  
  570. void *fat_match(void *prnt, const char *component)
  571. {
  572.     fat_bs_t *bs;
  573.     fat_node_t *parentp = (fat_node_t *)prnt;
  574.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  575.     unsigned i, j;
  576.     unsigned bps;       /* bytes per sector */
  577.     unsigned dps;       /* dentries per sector */
  578.     unsigned blocks;
  579.     fat_dentry_t *d;
  580.     block_t *b;
  581.  
  582.     futex_down(&parentp->idx->lock);
  583.     bs = block_bb_get(parentp->idx->dev_handle);
  584.     bps = uint16_t_le2host(bs->bps);
  585.     dps = bps / sizeof(fat_dentry_t);
  586.     blocks = parentp->size / bps;
  587.     for (i = 0; i < blocks; i++) {
  588.         b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
  589.         for (j = 0; j < dps; j++) {
  590.             d = ((fat_dentry_t *)b->data) + j;
  591.             switch (fat_classify_dentry(d)) {
  592.             case FAT_DENTRY_SKIP:
  593.             case FAT_DENTRY_FREE:
  594.                 continue;
  595.             case FAT_DENTRY_LAST:
  596.                 block_put(b);
  597.                 futex_up(&parentp->idx->lock);
  598.                 return NULL;
  599.             default:
  600.             case FAT_DENTRY_VALID:
  601.                 fat_dentry_name_get(d, name);
  602.                 break;
  603.             }
  604.             if (fat_dentry_namecmp(name, component) == 0) {
  605.                 /* hit */
  606.                 void *node;
  607.                 /*
  608.                  * Assume tree hierarchy for locking.  We
  609.                  * already have the parent and now we are going
  610.                  * to lock the child.  Never lock in the oposite
  611.                  * order.
  612.                  */
  613.                 fat_idx_t *idx = fat_idx_get_by_pos(
  614.                     parentp->idx->dev_handle, parentp->firstc,
  615.                     i * dps + j);
  616.                 futex_up(&parentp->idx->lock);
  617.                 if (!idx) {
  618.                     /*
  619.                      * Can happen if memory is low or if we
  620.                      * run out of 32-bit indices.
  621.                      */
  622.                     block_put(b);
  623.                     return NULL;
  624.                 }
  625.                 node = fat_node_get_core(idx);
  626.                 futex_up(&idx->lock);
  627.                 block_put(b);
  628.                 return node;
  629.             }
  630.         }
  631.         block_put(b);
  632.     }
  633.  
  634.     futex_up(&parentp->idx->lock);
  635.     return NULL;
  636. }
  637.  
  638. fs_index_t fat_index_get(void *node)
  639. {
  640.     fat_node_t *fnodep = (fat_node_t *)node;
  641.     if (!fnodep)
  642.         return 0;
  643.     return fnodep->idx->index;
  644. }
  645.  
  646. size_t fat_size_get(void *node)
  647. {
  648.     return ((fat_node_t *)node)->size;
  649. }
  650.  
  651. unsigned fat_lnkcnt_get(void *node)
  652. {
  653.     return ((fat_node_t *)node)->lnkcnt;
  654. }
  655.  
  656. bool fat_has_children(void *node)
  657. {
  658.     fat_bs_t *bs;
  659.     fat_node_t *nodep = (fat_node_t *)node;
  660.     unsigned bps;
  661.     unsigned dps;
  662.     unsigned blocks;
  663.     block_t *b;
  664.     unsigned i, j;
  665.  
  666.     if (nodep->type != FAT_DIRECTORY)
  667.         return false;
  668.    
  669.     futex_down(&nodep->idx->lock);
  670.     bs = block_bb_get(nodep->idx->dev_handle);
  671.     bps = uint16_t_le2host(bs->bps);
  672.     dps = bps / sizeof(fat_dentry_t);
  673.  
  674.     blocks = nodep->size / bps;
  675.  
  676.     for (i = 0; i < blocks; i++) {
  677.         fat_dentry_t *d;
  678.    
  679.         b = fat_block_get(bs, nodep, i, BLOCK_FLAGS_NONE);
  680.         for (j = 0; j < dps; j++) {
  681.             d = ((fat_dentry_t *)b->data) + j;
  682.             switch (fat_classify_dentry(d)) {
  683.             case FAT_DENTRY_SKIP:
  684.             case FAT_DENTRY_FREE:
  685.                 continue;
  686.             case FAT_DENTRY_LAST:
  687.                 block_put(b);
  688.                 futex_up(&nodep->idx->lock);
  689.                 return false;
  690.             default:
  691.             case FAT_DENTRY_VALID:
  692.                 block_put(b);
  693.                 futex_up(&nodep->idx->lock);
  694.                 return true;
  695.             }
  696.             block_put(b);
  697.             futex_up(&nodep->idx->lock);
  698.             return true;
  699.         }
  700.         block_put(b);
  701.     }
  702.  
  703.     futex_up(&nodep->idx->lock);
  704.     return false;
  705. }
  706.  
  707. void *fat_root_get(dev_handle_t dev_handle)
  708. {
  709.     return fat_node_get(dev_handle, 0);
  710. }
  711.  
  712. char fat_plb_get_char(unsigned pos)
  713. {
  714.     return fat_reg.plb_ro[pos % PLB_SIZE];
  715. }
  716.  
  717. bool fat_is_directory(void *node)
  718. {
  719.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  720. }
  721.  
  722. bool fat_is_file(void *node)
  723. {
  724.     return ((fat_node_t *)node)->type == FAT_FILE;
  725. }
  726.  
  727. /** libfs operations */
  728. libfs_ops_t fat_libfs_ops = {
  729.     .match = fat_match,
  730.     .node_get = fat_node_get,
  731.     .node_put = fat_node_put,
  732.     .create = fat_create_node,
  733.     .destroy = fat_destroy_node,
  734.     .link = fat_link,
  735.     .unlink = fat_unlink,
  736.     .index_get = fat_index_get,
  737.     .size_get = fat_size_get,
  738.     .lnkcnt_get = fat_lnkcnt_get,
  739.     .has_children = fat_has_children,
  740.     .root_get = fat_root_get,
  741.     .plb_get_char = fat_plb_get_char,
  742.     .is_directory = fat_is_directory,
  743.     .is_file = fat_is_file
  744. };
  745.  
  746. /*
  747.  * VFS operations.
  748.  */
  749.  
  750. void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
  751. {
  752.     dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
  753.     fat_bs_t *bs;
  754.     uint16_t bps;
  755.     uint16_t rde;
  756.     int rc;
  757.  
  758.     /* accept the mount options */
  759.     ipc_callid_t callid;
  760.     size_t size;
  761.     if (!ipc_data_write_receive(&callid, &size)) {
  762.         ipc_answer_0(callid, EINVAL);
  763.         ipc_answer_0(rid, EINVAL);
  764.         return;
  765.     }
  766.     char *opts = malloc(size + 1);
  767.     if (!opts) {
  768.         ipc_answer_0(callid, ENOMEM);
  769.         ipc_answer_0(rid, ENOMEM);
  770.         return;
  771.     }
  772.     ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
  773.     if (retval != EOK) {
  774.         ipc_answer_0(rid, retval);
  775.         free(opts);
  776.         return;
  777.     }
  778.     opts[size] = '\0';
  779.  
  780.     /* initialize libblock */
  781.     rc = block_init(dev_handle, BS_SIZE);
  782.     if (rc != EOK) {
  783.         ipc_answer_0(rid, rc);
  784.         return;
  785.     }
  786.  
  787.     /* prepare the boot block */
  788.     rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
  789.     if (rc != EOK) {
  790.         block_fini(dev_handle);
  791.         ipc_answer_0(rid, rc);
  792.         return;
  793.     }
  794.  
  795.     /* get the buffer with the boot sector */
  796.     bs = block_bb_get(dev_handle);
  797.    
  798.     /* Read the number of root directory entries. */
  799.     bps = uint16_t_le2host(bs->bps);
  800.     rde = uint16_t_le2host(bs->root_ent_max);
  801.  
  802.     if (bps != BS_SIZE) {
  803.         block_fini(dev_handle);
  804.         ipc_answer_0(rid, ENOTSUP);
  805.         return;
  806.     }
  807.  
  808.     /* Initialize the block cache */
  809.     rc = block_cache_init(dev_handle, bps, 0 /* XXX */);
  810.     if (rc != EOK) {
  811.         block_fini(dev_handle);
  812.         ipc_answer_0(rid, rc);
  813.         return;
  814.     }
  815.  
  816.     rc = fat_idx_init_by_dev_handle(dev_handle);
  817.     if (rc != EOK) {
  818.         block_fini(dev_handle);
  819.         ipc_answer_0(rid, rc);
  820.         return;
  821.     }
  822.  
  823.     /* Initialize the root node. */
  824.     fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
  825.     if (!rootp) {
  826.         block_fini(dev_handle);
  827.         fat_idx_fini_by_dev_handle(dev_handle);
  828.         ipc_answer_0(rid, ENOMEM);
  829.         return;
  830.     }
  831.     fat_node_initialize(rootp);
  832.  
  833.     fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
  834.     if (!ridxp) {
  835.         block_fini(dev_handle);
  836.         free(rootp);
  837.         fat_idx_fini_by_dev_handle(dev_handle);
  838.         ipc_answer_0(rid, ENOMEM);
  839.         return;
  840.     }
  841.     assert(ridxp->index == 0);
  842.     /* ridxp->lock held */
  843.  
  844.     rootp->type = FAT_DIRECTORY;
  845.     rootp->firstc = FAT_CLST_ROOT;
  846.     rootp->refcnt = 1;
  847.     rootp->lnkcnt = 0;  /* FS root is not linked */
  848.     rootp->size = rde * sizeof(fat_dentry_t);
  849.     rootp->idx = ridxp;
  850.     ridxp->nodep = rootp;
  851.    
  852.     futex_up(&ridxp->lock);
  853.  
  854.     ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
  855. }
  856.  
  857. void fat_mount(ipc_callid_t rid, ipc_call_t *request)
  858. {
  859.     ipc_answer_0(rid, ENOTSUP);
  860. }
  861.  
  862. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  863. {
  864.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  865. }
  866.  
  867. void fat_read(ipc_callid_t rid, ipc_call_t *request)
  868. {
  869.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  870.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  871.     off_t pos = (off_t)IPC_GET_ARG3(*request);
  872.     fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
  873.     fat_bs_t *bs;
  874.     uint16_t bps;
  875.     size_t bytes;
  876.     block_t *b;
  877.  
  878.     if (!nodep) {
  879.         ipc_answer_0(rid, ENOENT);
  880.         return;
  881.     }
  882.  
  883.     ipc_callid_t callid;
  884.     size_t len;
  885.     if (!ipc_data_read_receive(&callid, &len)) {
  886.         fat_node_put(nodep);
  887.         ipc_answer_0(callid, EINVAL);
  888.         ipc_answer_0(rid, EINVAL);
  889.         return;
  890.     }
  891.  
  892.     bs = block_bb_get(dev_handle);
  893.     bps = uint16_t_le2host(bs->bps);
  894.  
  895.     if (nodep->type == FAT_FILE) {
  896.         /*
  897.          * Our strategy for regular file reads is to read one block at
  898.          * most and make use of the possibility to return less data than
  899.          * requested. This keeps the code very simple.
  900.          */
  901.         if (pos >= nodep->size) {
  902.             /* reading beyond the EOF */
  903.             bytes = 0;
  904.             (void) ipc_data_read_finalize(callid, NULL, 0);
  905.         } else {
  906.             bytes = min(len, bps - pos % bps);
  907.             bytes = min(bytes, nodep->size - pos);
  908.             b = fat_block_get(bs, nodep, pos / bps,
  909.                 BLOCK_FLAGS_NONE);
  910.             (void) ipc_data_read_finalize(callid, b->data + pos % bps,
  911.                 bytes);
  912.             block_put(b);
  913.         }
  914.     } else {
  915.         unsigned bnum;
  916.         off_t spos = pos;
  917.         char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  918.         fat_dentry_t *d;
  919.  
  920.         assert(nodep->type == FAT_DIRECTORY);
  921.         assert(nodep->size % bps == 0);
  922.         assert(bps % sizeof(fat_dentry_t) == 0);
  923.  
  924.         /*
  925.          * Our strategy for readdir() is to use the position pointer as
  926.          * an index into the array of all dentries. On entry, it points
  927.          * to the first unread dentry. If we skip any dentries, we bump
  928.          * the position pointer accordingly.
  929.          */
  930.         bnum = (pos * sizeof(fat_dentry_t)) / bps;
  931.         while (bnum < nodep->size / bps) {
  932.             off_t o;
  933.  
  934.             b = fat_block_get(bs, nodep, bnum, BLOCK_FLAGS_NONE);
  935.             for (o = pos % (bps / sizeof(fat_dentry_t));
  936.                 o < bps / sizeof(fat_dentry_t);
  937.                 o++, pos++) {
  938.                 d = ((fat_dentry_t *)b->data) + o;
  939.                 switch (fat_classify_dentry(d)) {
  940.                 case FAT_DENTRY_SKIP:
  941.                 case FAT_DENTRY_FREE:
  942.                     continue;
  943.                 case FAT_DENTRY_LAST:
  944.                     block_put(b);
  945.                     goto miss;
  946.                 default:
  947.                 case FAT_DENTRY_VALID:
  948.                     fat_dentry_name_get(d, name);
  949.                     block_put(b);
  950.                     goto hit;
  951.                 }
  952.             }
  953.             block_put(b);
  954.             bnum++;
  955.         }
  956. miss:
  957.         fat_node_put(nodep);
  958.         ipc_answer_0(callid, ENOENT);
  959.         ipc_answer_1(rid, ENOENT, 0);
  960.         return;
  961. hit:
  962.         (void) ipc_data_read_finalize(callid, name, str_size(name) + 1);
  963.         bytes = (pos - spos) + 1;
  964.     }
  965.  
  966.     fat_node_put(nodep);
  967.     ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
  968. }
  969.  
  970. void fat_write(ipc_callid_t rid, ipc_call_t *request)
  971. {
  972.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  973.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  974.     off_t pos = (off_t)IPC_GET_ARG3(*request);
  975.     fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
  976.     fat_bs_t *bs;
  977.     size_t bytes;
  978.     block_t *b;
  979.     uint16_t bps;
  980.     unsigned spc;
  981.     unsigned bpc;       /* bytes per cluster */
  982.     off_t boundary;
  983.     int flags = BLOCK_FLAGS_NONE;
  984.    
  985.     if (!nodep) {
  986.         ipc_answer_0(rid, ENOENT);
  987.         return;
  988.     }
  989.    
  990.     ipc_callid_t callid;
  991.     size_t len;
  992.     if (!ipc_data_write_receive(&callid, &len)) {
  993.         fat_node_put(nodep);
  994.         ipc_answer_0(callid, EINVAL);
  995.         ipc_answer_0(rid, EINVAL);
  996.         return;
  997.     }
  998.  
  999.     bs = block_bb_get(dev_handle);
  1000.     bps = uint16_t_le2host(bs->bps);
  1001.     spc = bs->spc;
  1002.     bpc = bps * spc;
  1003.  
  1004.     /*
  1005.      * In all scenarios, we will attempt to write out only one block worth
  1006.      * of data at maximum. There might be some more efficient approaches,
  1007.      * but this one greatly simplifies fat_write(). Note that we can afford
  1008.      * to do this because the client must be ready to handle the return
  1009.      * value signalizing a smaller number of bytes written.
  1010.      */
  1011.     bytes = min(len, bps - pos % bps);
  1012.     if (bytes == bps)
  1013.         flags |= BLOCK_FLAGS_NOREAD;
  1014.    
  1015.     boundary = ROUND_UP(nodep->size, bpc);
  1016.     if (pos < boundary) {
  1017.         /*
  1018.          * This is the easier case - we are either overwriting already
  1019.          * existing contents or writing behind the EOF, but still within
  1020.          * the limits of the last cluster. The node size may grow to the
  1021.          * next block size boundary.
  1022.          */
  1023.         fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
  1024.         b = fat_block_get(bs, nodep, pos / bps, flags);
  1025.         (void) ipc_data_write_finalize(callid, b->data + pos % bps,
  1026.             bytes);
  1027.         b->dirty = true;        /* need to sync block */
  1028.         block_put(b);
  1029.         if (pos + bytes > nodep->size) {
  1030.             nodep->size = pos + bytes;
  1031.             nodep->dirty = true;    /* need to sync node */
  1032.         }
  1033.         ipc_answer_2(rid, EOK, bytes, nodep->size);
  1034.         fat_node_put(nodep);
  1035.         return;
  1036.     } else {
  1037.         /*
  1038.          * This is the more difficult case. We must allocate new
  1039.          * clusters for the node and zero them out.
  1040.          */
  1041.         int status;
  1042.         unsigned nclsts;
  1043.         fat_cluster_t mcl, lcl;
  1044.  
  1045.         nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
  1046.         /* create an independent chain of nclsts clusters in all FATs */
  1047.         status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
  1048.         if (status != EOK) {
  1049.             /* could not allocate a chain of nclsts clusters */
  1050.             fat_node_put(nodep);
  1051.             ipc_answer_0(callid, status);
  1052.             ipc_answer_0(rid, status);
  1053.             return;
  1054.         }
  1055.         /* zero fill any gaps */
  1056.         fat_fill_gap(bs, nodep, mcl, pos);
  1057.         b = _fat_block_get(bs, dev_handle, lcl, (pos / bps) % spc,
  1058.             flags);
  1059.         (void) ipc_data_write_finalize(callid, b->data + pos % bps,
  1060.             bytes);
  1061.         b->dirty = true;        /* need to sync block */
  1062.         block_put(b);
  1063.         /*
  1064.          * Append the cluster chain starting in mcl to the end of the
  1065.          * node's cluster chain.
  1066.          */
  1067.         fat_append_clusters(bs, nodep, mcl);
  1068.         nodep->size = pos + bytes;
  1069.         nodep->dirty = true;        /* need to sync node */
  1070.         ipc_answer_2(rid, EOK, bytes, nodep->size);
  1071.         fat_node_put(nodep);
  1072.         return;
  1073.     }
  1074. }
  1075.  
  1076. void fat_truncate(ipc_callid_t rid, ipc_call_t *request)
  1077. {
  1078.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  1079.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  1080.     size_t size = (off_t)IPC_GET_ARG3(*request);
  1081.     fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
  1082.     fat_bs_t *bs;
  1083.     uint16_t bps;
  1084.     uint8_t spc;
  1085.     unsigned bpc;   /* bytes per cluster */
  1086.     int rc;
  1087.  
  1088.     if (!nodep) {
  1089.         ipc_answer_0(rid, ENOENT);
  1090.         return;
  1091.     }
  1092.  
  1093.     bs = block_bb_get(dev_handle);
  1094.     bps = uint16_t_le2host(bs->bps);
  1095.     spc = bs->spc;
  1096.     bpc = bps * spc;
  1097.  
  1098.     if (nodep->size == size) {
  1099.         rc = EOK;
  1100.     } else if (nodep->size < size) {
  1101.         /*
  1102.          * The standard says we have the freedom to grow the node.
  1103.          * For now, we simply return an error.
  1104.          */
  1105.         rc = EINVAL;
  1106.     } else if (ROUND_UP(nodep->size, bpc) == ROUND_UP(size, bpc)) {
  1107.         /*
  1108.          * The node will be shrunk, but no clusters will be deallocated.
  1109.          */
  1110.         nodep->size = size;
  1111.         nodep->dirty = true;        /* need to sync node */
  1112.         rc = EOK;  
  1113.     } else {
  1114.         /*
  1115.          * The node will be shrunk, clusters will be deallocated.
  1116.          */
  1117.         if (size == 0) {
  1118.             fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
  1119.         } else {
  1120.             fat_cluster_t lastc;
  1121.             (void) fat_cluster_walk(bs, dev_handle, nodep->firstc,
  1122.                 &lastc, (size - 1) / bpc);
  1123.             fat_chop_clusters(bs, nodep, lastc);
  1124.         }
  1125.         nodep->size = size;
  1126.         nodep->dirty = true;        /* need to sync node */
  1127.         rc = EOK;  
  1128.     }
  1129.     fat_node_put(nodep);
  1130.     ipc_answer_0(rid, rc);
  1131.     return;
  1132. }
  1133.  
  1134. void fat_destroy(ipc_callid_t rid, ipc_call_t *request)
  1135. {
  1136.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  1137.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  1138.     int rc;
  1139.  
  1140.     fat_node_t *nodep = fat_node_get(dev_handle, index);
  1141.     if (!nodep) {
  1142.         ipc_answer_0(rid, ENOENT);
  1143.         return;
  1144.     }
  1145.  
  1146.     rc = fat_destroy_node(nodep);
  1147.     ipc_answer_0(rid, rc);
  1148. }
  1149.  
  1150. /**
  1151.  * @}
  1152.  */
  1153.