Subversion Repositories HelenOS

Rev

Rev 3253 | Rev 3282 | 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 "../../vfs/vfs.h"
  40. #include <libfs.h>
  41. #include <ipc/ipc.h>
  42. #include <ipc/services.h>
  43. #include <ipc/devmap.h>
  44. #include <async.h>
  45. #include <errno.h>
  46. #include <string.h>
  47. #include <byteorder.h>
  48. #include <libadt/hash_table.h>
  49. #include <libadt/list.h>
  50. #include <assert.h>
  51. #include <futex.h>
  52. #include <sys/mman.h>
  53.  
  54. #define BS_BLOCK        0
  55. #define BS_SIZE         512
  56.  
  57. /** Futex protecting the list of cached free FAT nodes. */
  58. static futex_t ffn_futex = FUTEX_INITIALIZER;
  59.  
  60. /** List of cached free FAT nodes. */
  61. static LIST_INITIALIZE(ffn_head);
  62.  
  63. #define FAT_NAME_LEN        8
  64. #define FAT_EXT_LEN     3
  65.  
  66. #define FAT_PAD         ' '
  67.  
  68. #define FAT_DENTRY_UNUSED   0x00
  69. #define FAT_DENTRY_E5_ESC   0x05
  70. #define FAT_DENTRY_DOT      0x2e
  71. #define FAT_DENTRY_ERASED   0xe5
  72.  
  73. static void dentry_name_canonify(fat_dentry_t *d, char *buf)
  74. {
  75.     int i;
  76.  
  77.     for (i = 0; i < FAT_NAME_LEN; i++) {
  78.         if (d->name[i] == FAT_PAD) {
  79.             buf++;
  80.             break;
  81.         }
  82.         if (d->name[i] == FAT_DENTRY_E5_ESC)
  83.             *buf++ = 0xe5;
  84.         else
  85.             *buf++ = d->name[i];
  86.     }
  87.     if (d->ext[0] != FAT_PAD)
  88.         *buf++ = '.';
  89.     for (i = 0; i < FAT_EXT_LEN; i++) {
  90.         if (d->ext[i] == FAT_PAD) {
  91.             *buf = '\0';
  92.             return;
  93.         }
  94.         if (d->ext[i] == FAT_DENTRY_E5_ESC)
  95.             *buf++ = 0xe5;
  96.         else
  97.             *buf++ = d->ext[i];
  98.     }
  99. }
  100.  
  101. static int dev_phone = -1;      /* FIXME */
  102. static void *dev_buffer = NULL;     /* FIXME */
  103.  
  104. /* TODO move somewhere else */
  105. typedef struct {
  106.     void *data;
  107.     size_t size;
  108. } block_t;
  109.  
  110. static block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
  111. {
  112.     /* FIXME */
  113.     block_t *b;
  114.     off_t bufpos = 0;
  115.     size_t buflen = 0;
  116.  
  117.     assert(dev_phone != -1);
  118.     assert(dev_buffer);
  119.  
  120.     b = malloc(sizeof(block_t));
  121.     if (!b)
  122.         return NULL;
  123.    
  124.     b->data = malloc(bs);
  125.     if (!b->data) {
  126.         free(b);
  127.         return NULL;
  128.     }
  129.     b->size = bs;
  130.  
  131.     if (!libfs_blockread(dev_phone, dev_buffer, &bufpos, &buflen, &offset,
  132.         b->data, bs, bs)) {
  133.         free(b->data);
  134.         free(b);
  135.         return NULL;
  136.     }
  137.  
  138.     return b;
  139. }
  140.  
  141. static void block_put(block_t *block)
  142. {
  143.     /* FIXME */
  144.     free(block->data);
  145.     free(block);
  146. }
  147.  
  148. #define FAT_BS(b)       ((fat_bs_t *)((b)->data))
  149.  
  150. #define FAT_CLST_RES0   0x0000
  151. #define FAT_CLST_RES1   0x0001
  152. #define FAT_CLST_FIRST  0x0002
  153. #define FAT_CLST_BAD    0xfff7
  154. #define FAT_CLST_LAST1  0xfff8
  155. #define FAT_CLST_LAST8  0xffff
  156.  
  157. /* internally used to mark root directory's parent */
  158. #define FAT_CLST_ROOTPAR    FAT_CLST_RES0
  159. /* internally used to mark root directory */
  160. #define FAT_CLST_ROOT       FAT_CLST_RES1
  161.  
  162. #define fat_block_get(np, off) \
  163.     _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
  164.  
  165. static block_t *
  166. _fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset)
  167. {
  168.     block_t *bb;
  169.     block_t *b;
  170.     unsigned bps;
  171.     unsigned spc;
  172.     unsigned rscnt;     /* block address of the first FAT */
  173.     unsigned fatcnt;
  174.     unsigned rde;
  175.     unsigned rds;       /* root directory size */
  176.     unsigned sf;
  177.     unsigned ssa;       /* size of the system area */
  178.     unsigned clusters;
  179.     fat_cluster_t clst = firstc;
  180.     unsigned i;
  181.  
  182.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  183.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  184.     spc = FAT_BS(bb)->spc;
  185.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  186.     fatcnt = FAT_BS(bb)->fatcnt;
  187.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  188.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  189.     block_put(bb);
  190.  
  191.     rds = (sizeof(fat_dentry_t) * rde) / bps;
  192.     rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
  193.     ssa = rscnt + fatcnt * sf + rds;
  194.  
  195.     if (firstc == FAT_CLST_ROOT) {
  196.         /* root directory special case */
  197.         assert(offset < rds);
  198.         b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps);
  199.         return b;
  200.     }
  201.  
  202.     clusters = offset / spc;
  203.     for (i = 0; i < clusters; i++) {
  204.         unsigned fsec;  /* sector offset relative to FAT1 */
  205.         unsigned fidx;  /* FAT1 entry index */
  206.  
  207.         assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
  208.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  209.         fidx = clst % (bps / sizeof(fat_cluster_t));
  210.         /* read FAT1 */
  211.         b = block_get(dev_handle, rscnt + fsec, bps);
  212.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  213.         assert(clst != FAT_CLST_BAD);
  214.         assert(clst < FAT_CLST_LAST1);
  215.         block_put(b);
  216.     }
  217.  
  218.     b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
  219.         offset % spc, bps);
  220.  
  221.     return b;
  222. }
  223.  
  224. static void fat_node_initialize(fat_node_t *node)
  225. {
  226.     futex_initialize(&node->lock, 1);
  227.     node->idx = NULL;
  228.     node->type = 0;
  229.     link_initialize(&node->ffn_link);
  230.     node->size = 0;
  231.     node->lnkcnt = 0;
  232.     node->refcnt = 0;
  233.     node->dirty = false;
  234. }
  235.  
  236. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  237. {
  238.     block_t *bb;
  239.     uint16_t bps;
  240.    
  241.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  242.     assert(bb != NULL);
  243.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  244.     block_put(bb);
  245.  
  246.     return bps;
  247. }
  248.  
  249. typedef enum {
  250.     FAT_DENTRY_SKIP,
  251.     FAT_DENTRY_LAST,
  252.     FAT_DENTRY_VALID
  253. } fat_dentry_clsf_t;
  254.  
  255. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  256. {
  257.     if (d->attr & FAT_ATTR_VOLLABEL) {
  258.         /* volume label entry */
  259.         return FAT_DENTRY_SKIP;
  260.     }
  261.     if (d->name[0] == FAT_DENTRY_ERASED) {
  262.         /* not-currently-used entry */
  263.         return FAT_DENTRY_SKIP;
  264.     }
  265.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  266.         /* never used entry */
  267.         return FAT_DENTRY_LAST;
  268.     }
  269.     if (d->name[0] == FAT_DENTRY_DOT) {
  270.         /*
  271.          * Most likely '.' or '..'.
  272.          * It cannot occur in a regular file name.
  273.          */
  274.         return FAT_DENTRY_SKIP;
  275.     }
  276.     return FAT_DENTRY_VALID;
  277. }
  278.  
  279. static void fat_node_sync(fat_node_t *node)
  280. {
  281.     /* TODO */
  282. }
  283.  
  284. /** Internal version of fat_node_get().
  285.  *
  286.  * @param idxp      Locked index structure.
  287.  */
  288. static void *fat_node_get_core(fat_idx_t *idxp)
  289. {
  290.     block_t *b;
  291.     fat_dentry_t *d;
  292.     fat_node_t *nodep;
  293.     unsigned bps;
  294.     unsigned dps;
  295.  
  296.     if (idxp->nodep) {
  297.         /*
  298.          * We are lucky.
  299.          * The node is already instantiated in memory.
  300.          */
  301.         futex_down(&idxp->nodep->lock);
  302.         if (!idxp->nodep->refcnt++)
  303.             list_remove(&nodep->ffn_link);
  304.         futex_up(&idxp->nodep->lock);
  305.         return idxp->nodep;
  306.     }
  307.  
  308.     /*
  309.      * We must instantiate the node from the file system.
  310.      */
  311.    
  312.     assert(idxp->pfc);
  313.  
  314.     futex_down(&ffn_futex);
  315.     if (!list_empty(&ffn_head)) {
  316.         /* Try to use a cached free node structure. */
  317.         fat_idx_t *idxp_tmp;
  318.         nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
  319.         if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
  320.             goto skip_cache;
  321.         idxp_tmp = nodep->idx;
  322.         if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
  323.             futex_up(&nodep->lock);
  324.             goto skip_cache;
  325.         }
  326.         list_remove(&nodep->ffn_link);
  327.         futex_up(&ffn_futex);
  328.         if (nodep->dirty)
  329.             fat_node_sync(nodep);
  330.         idxp_tmp->nodep = NULL;
  331.         futex_up(&nodep->lock);
  332.         futex_up(&idxp_tmp->lock);
  333.     } else {
  334. skip_cache:
  335.         /* Try to allocate a new node structure. */
  336.         futex_up(&ffn_futex);
  337.         nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
  338.         if (!nodep)
  339.             return NULL;
  340.     }
  341.     fat_node_initialize(nodep);
  342.  
  343.     bps = fat_bps_get(idxp->dev_handle);
  344.     dps = bps / sizeof(fat_dentry_t);
  345.  
  346.     /* Read the block that contains the dentry of interest. */
  347.     b = _fat_block_get(idxp->dev_handle, idxp->pfc,
  348.         (idxp->pdi * sizeof(fat_dentry_t)) / bps);
  349.     assert(b);
  350.  
  351.     d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
  352.     if (d->attr & FAT_ATTR_SUBDIR) {
  353.         /*
  354.          * The only directory which does not have this bit set is the
  355.          * root directory itself. The root directory node is handled
  356.          * and initialized elsewhere.
  357.          */
  358.         nodep->type = FAT_DIRECTORY;
  359.     } else {
  360.         nodep->type = FAT_FILE;
  361.     }
  362.     nodep->firstc = uint16_t_le2host(d->firstc);
  363.     nodep->size = uint32_t_le2host(d->size);
  364.     nodep->lnkcnt = 1;
  365.     nodep->refcnt = 1;
  366.  
  367.     block_put(b);
  368.  
  369.     /* Link the idx structure with the node structure. */
  370.     nodep->idx = idxp;
  371.     idxp->nodep = nodep;
  372.  
  373.     return nodep;
  374. }
  375.  
  376. /** Instantiate a FAT in-core node. */
  377. static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  378. {
  379.     void *node;
  380.     fat_idx_t *idxp;
  381.  
  382.     idxp = fat_idx_get_by_index(dev_handle, index);
  383.     if (!idxp)
  384.         return NULL;
  385.     /* idxp->lock held */
  386.     node = fat_node_get_core(idxp);
  387.     futex_up(&idxp->lock);
  388.     return node;
  389. }
  390.  
  391. static void fat_node_put(void *node)
  392. {
  393.     fat_node_t *nodep = (fat_node_t *)node;
  394.  
  395.     futex_down(&nodep->lock);
  396.     if (!--nodep->refcnt) {
  397.         futex_down(&ffn_futex);
  398.         list_append(&nodep->ffn_link, &ffn_head);
  399.         futex_up(&ffn_futex);
  400.     }
  401.     futex_up(&nodep->lock);
  402. }
  403.  
  404. static void *fat_create(int flags)
  405. {
  406.     return NULL;    /* not supported at the moment */
  407. }
  408.  
  409. static int fat_destroy(void *node)
  410. {
  411.     return ENOTSUP; /* not supported at the moment */
  412. }
  413.  
  414. static bool fat_link(void *prnt, void *chld, const char *name)
  415. {
  416.     return false;   /* not supported at the moment */
  417. }
  418.  
  419. static int fat_unlink(void *prnt, void *chld)
  420. {
  421.     return ENOTSUP; /* not supported at the moment */
  422. }
  423.  
  424. static void *fat_match(void *prnt, const char *component)
  425. {
  426.     fat_node_t *parentp = (fat_node_t *)prnt;
  427.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  428.     unsigned i, j;
  429.     unsigned bps;       /* bytes per sector */
  430.     unsigned dps;       /* dentries per sector */
  431.     unsigned blocks;
  432.     fat_dentry_t *d;
  433.     block_t *b;
  434.  
  435.     futex_down(&parentp->idx->lock);
  436.     bps = fat_bps_get(parentp->idx->dev_handle);
  437.     dps = bps / sizeof(fat_dentry_t);
  438.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  439.     for (i = 0; i < blocks; i++) {
  440.         unsigned dentries;
  441.        
  442.         b = fat_block_get(parentp, i);
  443.         dentries = (i == blocks - 1) ?
  444.             parentp->size % sizeof(fat_dentry_t) :
  445.             dps;
  446.         for (j = 0; j < dentries; j++) {
  447.             d = ((fat_dentry_t *)b->data) + j;
  448.             switch (fat_classify_dentry(d)) {
  449.             case FAT_DENTRY_SKIP:
  450.                 continue;
  451.             case FAT_DENTRY_LAST:
  452.                 block_put(b);
  453.                 futex_up(&parentp->idx->lock);
  454.                 return NULL;
  455.             default:
  456.             case FAT_DENTRY_VALID:
  457.                 dentry_name_canonify(d, name);
  458.                 break;
  459.             }
  460.             if (strcmp(name, component) == 0) {
  461.                 /* hit */
  462.                 void *node;
  463.                 /*
  464.                  * Assume tree hierarchy for locking.  We
  465.                  * already have the parent and now we are going
  466.                  * to lock the child.  Never lock in the oposite
  467.                  * order.
  468.                  */
  469.                 fat_idx_t *idx = fat_idx_get_by_pos(
  470.                     parentp->idx->dev_handle, parentp->firstc,
  471.                     i * dps + j);
  472.                 futex_up(&parentp->idx->lock);
  473.                 if (!idx) {
  474.                     /*
  475.                      * Can happen if memory is low or if we
  476.                      * run out of 32-bit indices.
  477.                      */
  478.                     block_put(b);
  479.                     return NULL;
  480.                 }
  481.                 node = fat_node_get_core(idx);
  482.                 futex_up(&idx->lock);
  483.                 block_put(b);
  484.                 return node;
  485.             }
  486.         }
  487.         block_put(b);
  488.     }
  489.     futex_up(&parentp->idx->lock);
  490.     return NULL;
  491. }
  492.  
  493. static fs_index_t fat_index_get(void *node)
  494. {
  495.     fat_node_t *fnodep = (fat_node_t *)node;
  496.     if (!fnodep)
  497.         return 0;
  498.     return fnodep->idx->index;
  499. }
  500.  
  501. static size_t fat_size_get(void *node)
  502. {
  503.     return ((fat_node_t *)node)->size;
  504. }
  505.  
  506. static unsigned fat_lnkcnt_get(void *node)
  507. {
  508.     return ((fat_node_t *)node)->lnkcnt;
  509. }
  510.  
  511. static bool fat_has_children(void *node)
  512. {
  513.     fat_node_t *nodep = (fat_node_t *)node;
  514.     unsigned bps;
  515.     unsigned dps;
  516.     unsigned blocks;
  517.     block_t *b;
  518.     unsigned i, j;
  519.  
  520.     if (nodep->type != FAT_DIRECTORY)
  521.         return false;
  522.  
  523.     futex_down(&nodep->idx->lock);
  524.     bps = fat_bps_get(nodep->idx->dev_handle);
  525.     dps = bps / sizeof(fat_dentry_t);
  526.  
  527.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  528.  
  529.     for (i = 0; i < blocks; i++) {
  530.         unsigned dentries;
  531.         fat_dentry_t *d;
  532.    
  533.         b = fat_block_get(nodep, i);
  534.         dentries = (i == blocks - 1) ?
  535.             nodep->size % sizeof(fat_dentry_t) :
  536.             dps;
  537.         for (j = 0; j < dentries; j++) {
  538.             d = ((fat_dentry_t *)b->data) + j;
  539.             switch (fat_classify_dentry(d)) {
  540.             case FAT_DENTRY_SKIP:
  541.                 continue;
  542.             case FAT_DENTRY_LAST:
  543.                 block_put(b);
  544.                 futex_up(&nodep->idx->lock);
  545.                 return false;
  546.             default:
  547.             case FAT_DENTRY_VALID:
  548.                 block_put(b);
  549.                 futex_up(&nodep->idx->lock);
  550.                 return true;
  551.             }
  552.             block_put(b);
  553.             futex_up(&nodep->idx->lock);
  554.             return true;
  555.         }
  556.         block_put(b);
  557.     }
  558.  
  559.     futex_up(&nodep->idx->lock);
  560.     return false;
  561. }
  562.  
  563. static void *fat_root_get(dev_handle_t dev_handle)
  564. {
  565.     return fat_node_get(dev_handle, 0);
  566. }
  567.  
  568. static char fat_plb_get_char(unsigned pos)
  569. {
  570.     return fat_reg.plb_ro[pos % PLB_SIZE];
  571. }
  572.  
  573. static bool fat_is_directory(void *node)
  574. {
  575.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  576. }
  577.  
  578. static bool fat_is_file(void *node)
  579. {
  580.     return ((fat_node_t *)node)->type == FAT_FILE;
  581. }
  582.  
  583. /** libfs operations */
  584. libfs_ops_t fat_libfs_ops = {
  585.     .match = fat_match,
  586.     .node_get = fat_node_get,
  587.     .node_put = fat_node_put,
  588.     .create = fat_create,
  589.     .destroy = fat_destroy,
  590.     .link = fat_link,
  591.     .unlink = fat_unlink,
  592.     .index_get = fat_index_get,
  593.     .size_get = fat_size_get,
  594.     .lnkcnt_get = fat_lnkcnt_get,
  595.     .has_children = fat_has_children,
  596.     .root_get = fat_root_get,
  597.     .plb_get_char = fat_plb_get_char,
  598.     .is_directory = fat_is_directory,
  599.     .is_file = fat_is_file
  600. };
  601.  
  602. void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
  603. {
  604.     dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
  605.     block_t *bb;
  606.     uint16_t bps;
  607.     uint16_t rde;
  608.     int rc;
  609.  
  610.     /*
  611.      * For now, we don't bother to remember dev_handle, dev_phone or
  612.      * dev_buffer in some data structure. We use global variables because we
  613.      * know there will be at most one mount on this file system.
  614.      * Of course, this is a huge TODO item.
  615.      */
  616.     dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
  617.         MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  618.    
  619.     if (!dev_buffer) {
  620.         ipc_answer_0(rid, ENOMEM);
  621.         return;
  622.     }
  623.  
  624.     dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
  625.         DEVMAP_CONNECT_TO_DEVICE, dev_handle);
  626.  
  627.     if (dev_phone < 0) {
  628.         munmap(dev_buffer, BS_SIZE);
  629.         ipc_answer_0(rid, dev_phone);
  630.         return;
  631.     }
  632.  
  633.     rc = ipc_share_out_start(dev_phone, dev_buffer,
  634.         AS_AREA_READ | AS_AREA_WRITE);
  635.     if (rc != EOK) {
  636.             munmap(dev_buffer, BS_SIZE);
  637.         ipc_answer_0(rid, rc);
  638.         return;
  639.     }
  640.  
  641.     /* Read the number of root directory entries. */
  642.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  643.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  644.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  645.     block_put(bb);
  646.  
  647.     if (bps != BS_SIZE) {
  648.         munmap(dev_buffer, BS_SIZE);
  649.         ipc_answer_0(rid, ENOTSUP);
  650.         return;
  651.     }
  652.  
  653.     rc = fat_idx_init_by_dev_handle(dev_handle);
  654.     if (rc != EOK) {
  655.             munmap(dev_buffer, BS_SIZE);
  656.         ipc_answer_0(rid, rc);
  657.         return;
  658.     }
  659.  
  660.     /* Initialize the root node. */
  661.     fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
  662.     if (!rootp) {
  663.             munmap(dev_buffer, BS_SIZE);
  664.         fat_idx_fini_by_dev_handle(dev_handle);
  665.         ipc_answer_0(rid, ENOMEM);
  666.         return;
  667.     }
  668.     fat_node_initialize(rootp);
  669.  
  670.     fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
  671.     if (!ridxp) {
  672.             munmap(dev_buffer, BS_SIZE);
  673.         free(rootp);
  674.         fat_idx_fini_by_dev_handle(dev_handle);
  675.         ipc_answer_0(rid, ENOMEM);
  676.         return;
  677.     }
  678.     assert(ridxp->index == 0);
  679.     /* ridxp->lock held */
  680.  
  681.     rootp->type = FAT_DIRECTORY;
  682.     rootp->firstc = FAT_CLST_ROOT;
  683.     rootp->refcnt = 1;
  684.     rootp->size = rde * sizeof(fat_dentry_t);
  685.     rootp->idx = ridxp;
  686.     ridxp->nodep = rootp;
  687.    
  688.     futex_up(&ridxp->lock);
  689.  
  690.     ipc_answer_0(rid, EOK);
  691. }
  692.  
  693. void fat_mount(ipc_callid_t rid, ipc_call_t *request)
  694. {
  695.     ipc_answer_0(rid, ENOTSUP);
  696. }
  697.  
  698. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  699. {
  700.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  701. }
  702.  
  703. /**
  704.  * @}
  705.  */
  706.