Subversion Repositories HelenOS

Rev

Rev 3282 | Rev 3308 | 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.             break;
  80.         if (d->name[i] == FAT_DENTRY_E5_ESC)
  81.             *buf++ = 0xe5;
  82.         else
  83.             *buf++ = d->name[i];
  84.     }
  85.     if (d->ext[0] != FAT_PAD)
  86.         *buf++ = '.';
  87.     for (i = 0; i < FAT_EXT_LEN; i++) {
  88.         if (d->ext[i] == FAT_PAD) {
  89.             *buf = '\0';
  90.             return;
  91.         }
  92.         if (d->ext[i] == FAT_DENTRY_E5_ESC)
  93.             *buf++ = 0xe5;
  94.         else
  95.             *buf++ = d->ext[i];
  96.     }
  97.     *buf = '\0';
  98. }
  99.  
  100. static int dev_phone = -1;      /* FIXME */
  101. static void *dev_buffer = NULL;     /* FIXME */
  102.  
  103. /* TODO move somewhere else */
  104. typedef struct {
  105.     void *data;
  106.     size_t size;
  107. } block_t;
  108.  
  109. static block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
  110. {
  111.     /* FIXME */
  112.     block_t *b;
  113.     off_t bufpos = 0;
  114.     size_t buflen = 0;
  115.     off_t pos = offset * bs;
  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, &pos,
  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.         /*
  360.          * TODO: determine the size by walking FAT. Surprisingly, the
  361.          * 'size' filed of the FAT dentry is not defined for the
  362.          * directory entry type.
  363.          */
  364.         nodep->size = 64 * sizeof(fat_dentry_t);
  365.     } else {
  366.         nodep->type = FAT_FILE;
  367.         nodep->size = uint32_t_le2host(d->size);
  368.     }
  369.     nodep->firstc = uint16_t_le2host(d->firstc);
  370.     nodep->lnkcnt = 1;
  371.     nodep->refcnt = 1;
  372.  
  373.     block_put(b);
  374.  
  375.     /* Link the idx structure with the node structure. */
  376.     nodep->idx = idxp;
  377.     idxp->nodep = nodep;
  378.  
  379.     return nodep;
  380. }
  381.  
  382. /** Instantiate a FAT in-core node. */
  383. static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  384. {
  385.     void *node;
  386.     fat_idx_t *idxp;
  387.  
  388.     idxp = fat_idx_get_by_index(dev_handle, index);
  389.     if (!idxp)
  390.         return NULL;
  391.     /* idxp->lock held */
  392.     node = fat_node_get_core(idxp);
  393.     futex_up(&idxp->lock);
  394.     return node;
  395. }
  396.  
  397. static void fat_node_put(void *node)
  398. {
  399.     fat_node_t *nodep = (fat_node_t *)node;
  400.  
  401.     futex_down(&nodep->lock);
  402.     if (!--nodep->refcnt) {
  403.         futex_down(&ffn_futex);
  404.         list_append(&nodep->ffn_link, &ffn_head);
  405.         futex_up(&ffn_futex);
  406.     }
  407.     futex_up(&nodep->lock);
  408. }
  409.  
  410. static void *fat_create(int flags)
  411. {
  412.     return NULL;    /* not supported at the moment */
  413. }
  414.  
  415. static int fat_destroy(void *node)
  416. {
  417.     return ENOTSUP; /* not supported at the moment */
  418. }
  419.  
  420. static bool fat_link(void *prnt, void *chld, const char *name)
  421. {
  422.     return false;   /* not supported at the moment */
  423. }
  424.  
  425. static int fat_unlink(void *prnt, void *chld)
  426. {
  427.     return ENOTSUP; /* not supported at the moment */
  428. }
  429.  
  430. static void *fat_match(void *prnt, const char *component)
  431. {
  432.     fat_node_t *parentp = (fat_node_t *)prnt;
  433.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  434.     unsigned i, j;
  435.     unsigned bps;       /* bytes per sector */
  436.     unsigned dps;       /* dentries per sector */
  437.     unsigned blocks;
  438.     fat_dentry_t *d;
  439.     block_t *b;
  440.  
  441.     futex_down(&parentp->idx->lock);
  442.     bps = fat_bps_get(parentp->idx->dev_handle);
  443.     dps = bps / sizeof(fat_dentry_t);
  444.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  445.     for (i = 0; i < blocks; i++) {
  446.         unsigned dentries;
  447.        
  448.         b = fat_block_get(parentp, i);
  449.         dentries = (i == blocks - 1) ?
  450.             parentp->size % sizeof(fat_dentry_t) :
  451.             dps;
  452.         for (j = 0; j < dentries; j++) {
  453.             d = ((fat_dentry_t *)b->data) + j;
  454.             switch (fat_classify_dentry(d)) {
  455.             case FAT_DENTRY_SKIP:
  456.                 continue;
  457.             case FAT_DENTRY_LAST:
  458.                 block_put(b);
  459.                 futex_up(&parentp->idx->lock);
  460.                 return NULL;
  461.             default:
  462.             case FAT_DENTRY_VALID:
  463.                 dentry_name_canonify(d, name);
  464.                 break;
  465.             }
  466.             if (stricmp(name, component) == 0) {
  467.                 /* hit */
  468.                 void *node;
  469.                 /*
  470.                  * Assume tree hierarchy for locking.  We
  471.                  * already have the parent and now we are going
  472.                  * to lock the child.  Never lock in the oposite
  473.                  * order.
  474.                  */
  475.                 fat_idx_t *idx = fat_idx_get_by_pos(
  476.                     parentp->idx->dev_handle, parentp->firstc,
  477.                     i * dps + j);
  478.                 futex_up(&parentp->idx->lock);
  479.                 if (!idx) {
  480.                     /*
  481.                      * Can happen if memory is low or if we
  482.                      * run out of 32-bit indices.
  483.                      */
  484.                     block_put(b);
  485.                     return NULL;
  486.                 }
  487.                 node = fat_node_get_core(idx);
  488.                 futex_up(&idx->lock);
  489.                 block_put(b);
  490.                 return node;
  491.             }
  492.         }
  493.         block_put(b);
  494.     }
  495.     futex_up(&parentp->idx->lock);
  496.     return NULL;
  497. }
  498.  
  499. static fs_index_t fat_index_get(void *node)
  500. {
  501.     fat_node_t *fnodep = (fat_node_t *)node;
  502.     if (!fnodep)
  503.         return 0;
  504.     return fnodep->idx->index;
  505. }
  506.  
  507. static size_t fat_size_get(void *node)
  508. {
  509.     return ((fat_node_t *)node)->size;
  510. }
  511.  
  512. static unsigned fat_lnkcnt_get(void *node)
  513. {
  514.     return ((fat_node_t *)node)->lnkcnt;
  515. }
  516.  
  517. static bool fat_has_children(void *node)
  518. {
  519.     fat_node_t *nodep = (fat_node_t *)node;
  520.     unsigned bps;
  521.     unsigned dps;
  522.     unsigned blocks;
  523.     block_t *b;
  524.     unsigned i, j;
  525.  
  526.     if (nodep->type != FAT_DIRECTORY)
  527.         return false;
  528.  
  529.     futex_down(&nodep->idx->lock);
  530.     bps = fat_bps_get(nodep->idx->dev_handle);
  531.     dps = bps / sizeof(fat_dentry_t);
  532.  
  533.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  534.  
  535.     for (i = 0; i < blocks; i++) {
  536.         unsigned dentries;
  537.         fat_dentry_t *d;
  538.    
  539.         b = fat_block_get(nodep, i);
  540.         dentries = (i == blocks - 1) ?
  541.             nodep->size % sizeof(fat_dentry_t) :
  542.             dps;
  543.         for (j = 0; j < dentries; j++) {
  544.             d = ((fat_dentry_t *)b->data) + j;
  545.             switch (fat_classify_dentry(d)) {
  546.             case FAT_DENTRY_SKIP:
  547.                 continue;
  548.             case FAT_DENTRY_LAST:
  549.                 block_put(b);
  550.                 futex_up(&nodep->idx->lock);
  551.                 return false;
  552.             default:
  553.             case FAT_DENTRY_VALID:
  554.                 block_put(b);
  555.                 futex_up(&nodep->idx->lock);
  556.                 return true;
  557.             }
  558.             block_put(b);
  559.             futex_up(&nodep->idx->lock);
  560.             return true;
  561.         }
  562.         block_put(b);
  563.     }
  564.  
  565.     futex_up(&nodep->idx->lock);
  566.     return false;
  567. }
  568.  
  569. static void *fat_root_get(dev_handle_t dev_handle)
  570. {
  571.     return fat_node_get(dev_handle, 0);
  572. }
  573.  
  574. static char fat_plb_get_char(unsigned pos)
  575. {
  576.     return fat_reg.plb_ro[pos % PLB_SIZE];
  577. }
  578.  
  579. static bool fat_is_directory(void *node)
  580. {
  581.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  582. }
  583.  
  584. static bool fat_is_file(void *node)
  585. {
  586.     return ((fat_node_t *)node)->type == FAT_FILE;
  587. }
  588.  
  589. /** libfs operations */
  590. libfs_ops_t fat_libfs_ops = {
  591.     .match = fat_match,
  592.     .node_get = fat_node_get,
  593.     .node_put = fat_node_put,
  594.     .create = fat_create,
  595.     .destroy = fat_destroy,
  596.     .link = fat_link,
  597.     .unlink = fat_unlink,
  598.     .index_get = fat_index_get,
  599.     .size_get = fat_size_get,
  600.     .lnkcnt_get = fat_lnkcnt_get,
  601.     .has_children = fat_has_children,
  602.     .root_get = fat_root_get,
  603.     .plb_get_char = fat_plb_get_char,
  604.     .is_directory = fat_is_directory,
  605.     .is_file = fat_is_file
  606. };
  607.  
  608. void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
  609. {
  610.     dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
  611.     block_t *bb;
  612.     uint16_t bps;
  613.     uint16_t rde;
  614.     int rc;
  615.  
  616.     /*
  617.      * For now, we don't bother to remember dev_handle, dev_phone or
  618.      * dev_buffer in some data structure. We use global variables because we
  619.      * know there will be at most one mount on this file system.
  620.      * Of course, this is a huge TODO item.
  621.      */
  622.     dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
  623.         MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  624.    
  625.     if (!dev_buffer) {
  626.         ipc_answer_0(rid, ENOMEM);
  627.         return;
  628.     }
  629.  
  630.     dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
  631.         DEVMAP_CONNECT_TO_DEVICE, dev_handle);
  632.  
  633.     if (dev_phone < 0) {
  634.         munmap(dev_buffer, BS_SIZE);
  635.         ipc_answer_0(rid, dev_phone);
  636.         return;
  637.     }
  638.  
  639.     rc = ipc_share_out_start(dev_phone, dev_buffer,
  640.         AS_AREA_READ | AS_AREA_WRITE);
  641.     if (rc != EOK) {
  642.             munmap(dev_buffer, BS_SIZE);
  643.         ipc_answer_0(rid, rc);
  644.         return;
  645.     }
  646.  
  647.     /* Read the number of root directory entries. */
  648.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  649.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  650.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  651.     block_put(bb);
  652.  
  653.     if (bps != BS_SIZE) {
  654.         munmap(dev_buffer, BS_SIZE);
  655.         ipc_answer_0(rid, ENOTSUP);
  656.         return;
  657.     }
  658.  
  659.     rc = fat_idx_init_by_dev_handle(dev_handle);
  660.     if (rc != EOK) {
  661.             munmap(dev_buffer, BS_SIZE);
  662.         ipc_answer_0(rid, rc);
  663.         return;
  664.     }
  665.  
  666.     /* Initialize the root node. */
  667.     fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
  668.     if (!rootp) {
  669.             munmap(dev_buffer, BS_SIZE);
  670.         fat_idx_fini_by_dev_handle(dev_handle);
  671.         ipc_answer_0(rid, ENOMEM);
  672.         return;
  673.     }
  674.     fat_node_initialize(rootp);
  675.  
  676.     fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
  677.     if (!ridxp) {
  678.             munmap(dev_buffer, BS_SIZE);
  679.         free(rootp);
  680.         fat_idx_fini_by_dev_handle(dev_handle);
  681.         ipc_answer_0(rid, ENOMEM);
  682.         return;
  683.     }
  684.     assert(ridxp->index == 0);
  685.     /* ridxp->lock held */
  686.  
  687.     rootp->type = FAT_DIRECTORY;
  688.     rootp->firstc = FAT_CLST_ROOT;
  689.     rootp->refcnt = 1;
  690.     rootp->size = rde * sizeof(fat_dentry_t);
  691.     rootp->idx = ridxp;
  692.     ridxp->nodep = rootp;
  693.    
  694.     futex_up(&ridxp->lock);
  695.  
  696.     ipc_answer_0(rid, EOK);
  697. }
  698.  
  699. void fat_mount(ipc_callid_t rid, ipc_call_t *request)
  700. {
  701.     ipc_answer_0(rid, ENOTSUP);
  702. }
  703.  
  704. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  705. {
  706.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  707. }
  708.  
  709. void fat_read(ipc_callid_t rid, ipc_call_t *request)
  710. {
  711.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  712.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  713.     off_t pos = (off_t)IPC_GET_ARG3(*request);
  714.     fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
  715.     if (!nodep) {
  716.         ipc_answer_0(rid, ENOENT);
  717.         return;
  718.     }
  719.  
  720.     ipc_callid_t callid;
  721.     size_t len;
  722.     if (!ipc_data_write_receive(&callid, &len)) {
  723.         fat_node_put(nodep);
  724.         ipc_answer_0(callid, EINVAL);
  725.         ipc_answer_0(rid, EINVAL);
  726.         return;
  727.     }
  728.  
  729.     if (nodep->type == FAT_FILE) {
  730.         /* TODO */
  731.         fat_node_put(nodep);
  732.         ipc_answer_0(callid, ENOTSUP);
  733.         ipc_answer_0(rid, ENOTSUP);
  734.         return;
  735.     } else {
  736.         assert(nodep->type == FAT_DIRECTORY);
  737.         /* TODO */
  738.         fat_node_put(nodep);
  739.         ipc_answer_0(callid, ENOTSUP);
  740.         ipc_answer_0(rid, ENOTSUP);
  741.         return;
  742.     }
  743.  
  744.     fat_node_put(nodep);
  745. }
  746.  
  747. /**
  748.  * @}
  749.  */
  750.