Subversion Repositories HelenOS

Rev

Rev 3352 | Rev 4153 | 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. #define min(a, b)       ((a) < (b) ? (a) : (b))
  74.  
  75. static void dentry_name_canonify(fat_dentry_t *d, char *buf)
  76. {
  77.     int i;
  78.  
  79.     for (i = 0; i < FAT_NAME_LEN; i++) {
  80.         if (d->name[i] == FAT_PAD)
  81.             break;
  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.     *buf = '\0';
  100. }
  101.  
  102. static int dev_phone = -1;      /* FIXME */
  103. static void *dev_buffer = NULL;     /* FIXME */
  104.  
  105. /* TODO move somewhere else */
  106. typedef struct {
  107.     void *data;
  108.     size_t size;
  109. } block_t;
  110.  
  111. static block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
  112. {
  113.     /* FIXME */
  114.     block_t *b;
  115.     off_t bufpos = 0;
  116.     size_t buflen = 0;
  117.     off_t pos = offset * bs;
  118.  
  119.     assert(dev_phone != -1);
  120.     assert(dev_buffer);
  121.  
  122.     b = malloc(sizeof(block_t));
  123.     if (!b)
  124.         return NULL;
  125.    
  126.     b->data = malloc(bs);
  127.     if (!b->data) {
  128.         free(b);
  129.         return NULL;
  130.     }
  131.     b->size = bs;
  132.  
  133.     if (!libfs_blockread(dev_phone, dev_buffer, &bufpos, &buflen, &pos,
  134.         b->data, bs, bs)) {
  135.         free(b->data);
  136.         free(b);
  137.         return NULL;
  138.     }
  139.  
  140.     return b;
  141. }
  142.  
  143. static void block_put(block_t *block)
  144. {
  145.     /* FIXME */
  146.     free(block->data);
  147.     free(block);
  148. }
  149.  
  150. #define FAT_BS(b)       ((fat_bs_t *)((b)->data))
  151.  
  152. #define FAT_CLST_RES0   0x0000
  153. #define FAT_CLST_RES1   0x0001
  154. #define FAT_CLST_FIRST  0x0002
  155. #define FAT_CLST_BAD    0xfff7
  156. #define FAT_CLST_LAST1  0xfff8
  157. #define FAT_CLST_LAST8  0xffff
  158.  
  159. /* internally used to mark root directory's parent */
  160. #define FAT_CLST_ROOTPAR    FAT_CLST_RES0
  161. /* internally used to mark root directory */
  162. #define FAT_CLST_ROOT       FAT_CLST_RES1
  163.  
  164. #define fat_block_get(np, off) \
  165.     _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
  166.  
  167. static block_t *
  168. _fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset)
  169. {
  170.     block_t *bb;
  171.     block_t *b;
  172.     unsigned bps;
  173.     unsigned spc;
  174.     unsigned rscnt;     /* block address of the first FAT */
  175.     unsigned fatcnt;
  176.     unsigned rde;
  177.     unsigned rds;       /* root directory size */
  178.     unsigned sf;
  179.     unsigned ssa;       /* size of the system area */
  180.     unsigned clusters;
  181.     fat_cluster_t clst = firstc;
  182.     unsigned i;
  183.  
  184.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  185.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  186.     spc = FAT_BS(bb)->spc;
  187.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  188.     fatcnt = FAT_BS(bb)->fatcnt;
  189.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  190.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  191.     block_put(bb);
  192.  
  193.     rds = (sizeof(fat_dentry_t) * rde) / bps;
  194.     rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
  195.     ssa = rscnt + fatcnt * sf + rds;
  196.  
  197.     if (firstc == FAT_CLST_ROOT) {
  198.         /* root directory special case */
  199.         assert(offset < rds);
  200.         b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps);
  201.         return b;
  202.     }
  203.  
  204.     clusters = offset / spc;
  205.     for (i = 0; i < clusters; i++) {
  206.         unsigned fsec;  /* sector offset relative to FAT1 */
  207.         unsigned fidx;  /* FAT1 entry index */
  208.  
  209.         assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
  210.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  211.         fidx = clst % (bps / sizeof(fat_cluster_t));
  212.         /* read FAT1 */
  213.         b = block_get(dev_handle, rscnt + fsec, bps);
  214.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  215.         assert(clst != FAT_CLST_BAD);
  216.         assert(clst < FAT_CLST_LAST1);
  217.         block_put(b);
  218.     }
  219.  
  220.     b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
  221.         offset % spc, bps);
  222.  
  223.     return b;
  224. }
  225.  
  226. /** Return number of blocks allocated to a file.
  227.  *
  228.  * @param dev_handle    Device handle of the device with the file.
  229.  * @param firstc    First cluster of the file.
  230.  *
  231.  * @return      Number of blocks allocated to the file.
  232.  */
  233. static uint16_t
  234. _fat_blcks_get(dev_handle_t dev_handle, fat_cluster_t firstc)
  235. {
  236.     block_t *bb;
  237.     block_t *b;
  238.     unsigned bps;
  239.     unsigned spc;
  240.     unsigned rscnt;     /* block address of the first FAT */
  241.     unsigned clusters = 0;
  242.     fat_cluster_t clst = firstc;
  243.  
  244.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  245.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  246.     spc = FAT_BS(bb)->spc;
  247.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  248.     block_put(bb);
  249.  
  250.     if (firstc == FAT_CLST_RES0) {
  251.         /* No space allocated to the file. */
  252.         return 0;
  253.     }
  254.  
  255.     while (clst < FAT_CLST_LAST1) {
  256.         unsigned fsec;  /* sector offset relative to FAT1 */
  257.         unsigned fidx;  /* FAT1 entry index */
  258.  
  259.         assert(clst >= FAT_CLST_FIRST);
  260.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  261.         fidx = clst % (bps / sizeof(fat_cluster_t));
  262.         /* read FAT1 */
  263.         b = block_get(dev_handle, rscnt + fsec, bps);
  264.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  265.         assert(clst != FAT_CLST_BAD);
  266.         block_put(b);
  267.         clusters++;
  268.     }
  269.  
  270.     return clusters * spc;
  271. }
  272.  
  273. static void fat_node_initialize(fat_node_t *node)
  274. {
  275.     futex_initialize(&node->lock, 1);
  276.     node->idx = NULL;
  277.     node->type = 0;
  278.     link_initialize(&node->ffn_link);
  279.     node->size = 0;
  280.     node->lnkcnt = 0;
  281.     node->refcnt = 0;
  282.     node->dirty = false;
  283. }
  284.  
  285. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  286. {
  287.     block_t *bb;
  288.     uint16_t bps;
  289.    
  290.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  291.     assert(bb != NULL);
  292.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  293.     block_put(bb);
  294.  
  295.     return bps;
  296. }
  297.  
  298. typedef enum {
  299.     FAT_DENTRY_SKIP,
  300.     FAT_DENTRY_LAST,
  301.     FAT_DENTRY_VALID
  302. } fat_dentry_clsf_t;
  303.  
  304. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  305. {
  306.     if (d->attr & FAT_ATTR_VOLLABEL) {
  307.         /* volume label entry */
  308.         return FAT_DENTRY_SKIP;
  309.     }
  310.     if (d->name[0] == FAT_DENTRY_ERASED) {
  311.         /* not-currently-used entry */
  312.         return FAT_DENTRY_SKIP;
  313.     }
  314.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  315.         /* never used entry */
  316.         return FAT_DENTRY_LAST;
  317.     }
  318.     if (d->name[0] == FAT_DENTRY_DOT) {
  319.         /*
  320.          * Most likely '.' or '..'.
  321.          * It cannot occur in a regular file name.
  322.          */
  323.         return FAT_DENTRY_SKIP;
  324.     }
  325.     return FAT_DENTRY_VALID;
  326. }
  327.  
  328. static void fat_node_sync(fat_node_t *node)
  329. {
  330.     /* TODO */
  331. }
  332.  
  333. /** Internal version of fat_node_get().
  334.  *
  335.  * @param idxp      Locked index structure.
  336.  */
  337. static void *fat_node_get_core(fat_idx_t *idxp)
  338. {
  339.     block_t *b;
  340.     fat_dentry_t *d;
  341.     fat_node_t *nodep = NULL;
  342.     unsigned bps;
  343.     unsigned dps;
  344.  
  345.     if (idxp->nodep) {
  346.         /*
  347.          * We are lucky.
  348.          * The node is already instantiated in memory.
  349.          */
  350.         futex_down(&idxp->nodep->lock);
  351.         if (!idxp->nodep->refcnt++)
  352.             list_remove(&idxp->nodep->ffn_link);
  353.         futex_up(&idxp->nodep->lock);
  354.         return idxp->nodep;
  355.     }
  356.  
  357.     /*
  358.      * We must instantiate the node from the file system.
  359.      */
  360.    
  361.     assert(idxp->pfc);
  362.  
  363.     futex_down(&ffn_futex);
  364.     if (!list_empty(&ffn_head)) {
  365.         /* Try to use a cached free node structure. */
  366.         fat_idx_t *idxp_tmp;
  367.         nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
  368.         if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
  369.             goto skip_cache;
  370.         idxp_tmp = nodep->idx;
  371.         if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
  372.             futex_up(&nodep->lock);
  373.             goto skip_cache;
  374.         }
  375.         list_remove(&nodep->ffn_link);
  376.         futex_up(&ffn_futex);
  377.         if (nodep->dirty)
  378.             fat_node_sync(nodep);
  379.         idxp_tmp->nodep = NULL;
  380.         futex_up(&nodep->lock);
  381.         futex_up(&idxp_tmp->lock);
  382.     } else {
  383. skip_cache:
  384.         /* Try to allocate a new node structure. */
  385.         futex_up(&ffn_futex);
  386.         nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
  387.         if (!nodep)
  388.             return NULL;
  389.     }
  390.     fat_node_initialize(nodep);
  391.  
  392.     bps = fat_bps_get(idxp->dev_handle);
  393.     dps = bps / sizeof(fat_dentry_t);
  394.  
  395.     /* Read the block that contains the dentry of interest. */
  396.     b = _fat_block_get(idxp->dev_handle, idxp->pfc,
  397.         (idxp->pdi * sizeof(fat_dentry_t)) / bps);
  398.     assert(b);
  399.  
  400.     d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
  401.     if (d->attr & FAT_ATTR_SUBDIR) {
  402.         /*
  403.          * The only directory which does not have this bit set is the
  404.          * root directory itself. The root directory node is handled
  405.          * and initialized elsewhere.
  406.          */
  407.         nodep->type = FAT_DIRECTORY;
  408.         /*
  409.          * Unfortunately, the 'size' field of the FAT dentry is not
  410.          * defined for the directory entry type. We must determine the
  411.          * size of the directory by walking the FAT.
  412.          */
  413.         nodep->size = bps * _fat_blcks_get(idxp->dev_handle,
  414.             uint16_t_le2host(d->firstc));
  415.     } else {
  416.         nodep->type = FAT_FILE;
  417.         nodep->size = uint32_t_le2host(d->size);
  418.     }
  419.     nodep->firstc = uint16_t_le2host(d->firstc);
  420.     nodep->lnkcnt = 1;
  421.     nodep->refcnt = 1;
  422.  
  423.     block_put(b);
  424.  
  425.     /* Link the idx structure with the node structure. */
  426.     nodep->idx = idxp;
  427.     idxp->nodep = nodep;
  428.  
  429.     return nodep;
  430. }
  431.  
  432. /** Instantiate a FAT in-core node. */
  433. static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  434. {
  435.     void *node;
  436.     fat_idx_t *idxp;
  437.  
  438.     idxp = fat_idx_get_by_index(dev_handle, index);
  439.     if (!idxp)
  440.         return NULL;
  441.     /* idxp->lock held */
  442.     node = fat_node_get_core(idxp);
  443.     futex_up(&idxp->lock);
  444.     return node;
  445. }
  446.  
  447. static void fat_node_put(void *node)
  448. {
  449.     fat_node_t *nodep = (fat_node_t *)node;
  450.  
  451.     futex_down(&nodep->lock);
  452.     if (!--nodep->refcnt) {
  453.         futex_down(&ffn_futex);
  454.         list_append(&nodep->ffn_link, &ffn_head);
  455.         futex_up(&ffn_futex);
  456.     }
  457.     futex_up(&nodep->lock);
  458. }
  459.  
  460. static void *fat_create(int flags)
  461. {
  462.     return NULL;    /* not supported at the moment */
  463. }
  464.  
  465. static int fat_destroy(void *node)
  466. {
  467.     return ENOTSUP; /* not supported at the moment */
  468. }
  469.  
  470. static bool fat_link(void *prnt, void *chld, const char *name)
  471. {
  472.     return false;   /* not supported at the moment */
  473. }
  474.  
  475. static int fat_unlink(void *prnt, void *chld)
  476. {
  477.     return ENOTSUP; /* not supported at the moment */
  478. }
  479.  
  480. static void *fat_match(void *prnt, const char *component)
  481. {
  482.     fat_node_t *parentp = (fat_node_t *)prnt;
  483.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  484.     unsigned i, j;
  485.     unsigned bps;       /* bytes per sector */
  486.     unsigned dps;       /* dentries per sector */
  487.     unsigned blocks;
  488.     fat_dentry_t *d;
  489.     block_t *b;
  490.  
  491.     futex_down(&parentp->idx->lock);
  492.     bps = fat_bps_get(parentp->idx->dev_handle);
  493.     dps = bps / sizeof(fat_dentry_t);
  494.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  495.     for (i = 0; i < blocks; i++) {
  496.         unsigned dentries;
  497.        
  498.         b = fat_block_get(parentp, i);
  499.         dentries = (i == blocks - 1) ?
  500.             parentp->size % sizeof(fat_dentry_t) :
  501.             dps;
  502.         for (j = 0; j < dentries; j++) {
  503.             d = ((fat_dentry_t *)b->data) + j;
  504.             switch (fat_classify_dentry(d)) {
  505.             case FAT_DENTRY_SKIP:
  506.                 continue;
  507.             case FAT_DENTRY_LAST:
  508.                 block_put(b);
  509.                 futex_up(&parentp->idx->lock);
  510.                 return NULL;
  511.             default:
  512.             case FAT_DENTRY_VALID:
  513.                 dentry_name_canonify(d, name);
  514.                 break;
  515.             }
  516.             if (stricmp(name, component) == 0) {
  517.                 /* hit */
  518.                 void *node;
  519.                 /*
  520.                  * Assume tree hierarchy for locking.  We
  521.                  * already have the parent and now we are going
  522.                  * to lock the child.  Never lock in the oposite
  523.                  * order.
  524.                  */
  525.                 fat_idx_t *idx = fat_idx_get_by_pos(
  526.                     parentp->idx->dev_handle, parentp->firstc,
  527.                     i * dps + j);
  528.                 futex_up(&parentp->idx->lock);
  529.                 if (!idx) {
  530.                     /*
  531.                      * Can happen if memory is low or if we
  532.                      * run out of 32-bit indices.
  533.                      */
  534.                     block_put(b);
  535.                     return NULL;
  536.                 }
  537.                 node = fat_node_get_core(idx);
  538.                 futex_up(&idx->lock);
  539.                 block_put(b);
  540.                 return node;
  541.             }
  542.         }
  543.         block_put(b);
  544.     }
  545.     futex_up(&parentp->idx->lock);
  546.     return NULL;
  547. }
  548.  
  549. static fs_index_t fat_index_get(void *node)
  550. {
  551.     fat_node_t *fnodep = (fat_node_t *)node;
  552.     if (!fnodep)
  553.         return 0;
  554.     return fnodep->idx->index;
  555. }
  556.  
  557. static size_t fat_size_get(void *node)
  558. {
  559.     return ((fat_node_t *)node)->size;
  560. }
  561.  
  562. static unsigned fat_lnkcnt_get(void *node)
  563. {
  564.     return ((fat_node_t *)node)->lnkcnt;
  565. }
  566.  
  567. static bool fat_has_children(void *node)
  568. {
  569.     fat_node_t *nodep = (fat_node_t *)node;
  570.     unsigned bps;
  571.     unsigned dps;
  572.     unsigned blocks;
  573.     block_t *b;
  574.     unsigned i, j;
  575.  
  576.     if (nodep->type != FAT_DIRECTORY)
  577.         return false;
  578.  
  579.     futex_down(&nodep->idx->lock);
  580.     bps = fat_bps_get(nodep->idx->dev_handle);
  581.     dps = bps / sizeof(fat_dentry_t);
  582.  
  583.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  584.  
  585.     for (i = 0; i < blocks; i++) {
  586.         unsigned dentries;
  587.         fat_dentry_t *d;
  588.    
  589.         b = fat_block_get(nodep, i);
  590.         dentries = (i == blocks - 1) ?
  591.             nodep->size % sizeof(fat_dentry_t) :
  592.             dps;
  593.         for (j = 0; j < dentries; j++) {
  594.             d = ((fat_dentry_t *)b->data) + j;
  595.             switch (fat_classify_dentry(d)) {
  596.             case FAT_DENTRY_SKIP:
  597.                 continue;
  598.             case FAT_DENTRY_LAST:
  599.                 block_put(b);
  600.                 futex_up(&nodep->idx->lock);
  601.                 return false;
  602.             default:
  603.             case FAT_DENTRY_VALID:
  604.                 block_put(b);
  605.                 futex_up(&nodep->idx->lock);
  606.                 return true;
  607.             }
  608.             block_put(b);
  609.             futex_up(&nodep->idx->lock);
  610.             return true;
  611.         }
  612.         block_put(b);
  613.     }
  614.  
  615.     futex_up(&nodep->idx->lock);
  616.     return false;
  617. }
  618.  
  619. static void *fat_root_get(dev_handle_t dev_handle)
  620. {
  621.     return fat_node_get(dev_handle, 0);
  622. }
  623.  
  624. static char fat_plb_get_char(unsigned pos)
  625. {
  626.     return fat_reg.plb_ro[pos % PLB_SIZE];
  627. }
  628.  
  629. static bool fat_is_directory(void *node)
  630. {
  631.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  632. }
  633.  
  634. static bool fat_is_file(void *node)
  635. {
  636.     return ((fat_node_t *)node)->type == FAT_FILE;
  637. }
  638.  
  639. /** libfs operations */
  640. libfs_ops_t fat_libfs_ops = {
  641.     .match = fat_match,
  642.     .node_get = fat_node_get,
  643.     .node_put = fat_node_put,
  644.     .create = fat_create,
  645.     .destroy = fat_destroy,
  646.     .link = fat_link,
  647.     .unlink = fat_unlink,
  648.     .index_get = fat_index_get,
  649.     .size_get = fat_size_get,
  650.     .lnkcnt_get = fat_lnkcnt_get,
  651.     .has_children = fat_has_children,
  652.     .root_get = fat_root_get,
  653.     .plb_get_char = fat_plb_get_char,
  654.     .is_directory = fat_is_directory,
  655.     .is_file = fat_is_file
  656. };
  657.  
  658. void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
  659. {
  660.     dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
  661.     block_t *bb;
  662.     uint16_t bps;
  663.     uint16_t rde;
  664.     int rc;
  665.  
  666.     /*
  667.      * For now, we don't bother to remember dev_handle, dev_phone or
  668.      * dev_buffer in some data structure. We use global variables because we
  669.      * know there will be at most one mount on this file system.
  670.      * Of course, this is a huge TODO item.
  671.      */
  672.     dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
  673.         MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  674.    
  675.     if (!dev_buffer) {
  676.         ipc_answer_0(rid, ENOMEM);
  677.         return;
  678.     }
  679.  
  680.     dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
  681.         DEVMAP_CONNECT_TO_DEVICE, dev_handle);
  682.  
  683.     if (dev_phone < 0) {
  684.         munmap(dev_buffer, BS_SIZE);
  685.         ipc_answer_0(rid, dev_phone);
  686.         return;
  687.     }
  688.  
  689.     rc = ipc_share_out_start(dev_phone, dev_buffer,
  690.         AS_AREA_READ | AS_AREA_WRITE);
  691.     if (rc != EOK) {
  692.             munmap(dev_buffer, BS_SIZE);
  693.         ipc_answer_0(rid, rc);
  694.         return;
  695.     }
  696.  
  697.     /* Read the number of root directory entries. */
  698.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  699.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  700.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  701.     block_put(bb);
  702.  
  703.     if (bps != BS_SIZE) {
  704.         munmap(dev_buffer, BS_SIZE);
  705.         ipc_answer_0(rid, ENOTSUP);
  706.         return;
  707.     }
  708.  
  709.     rc = fat_idx_init_by_dev_handle(dev_handle);
  710.     if (rc != EOK) {
  711.             munmap(dev_buffer, BS_SIZE);
  712.         ipc_answer_0(rid, rc);
  713.         return;
  714.     }
  715.  
  716.     /* Initialize the root node. */
  717.     fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
  718.     if (!rootp) {
  719.             munmap(dev_buffer, BS_SIZE);
  720.         fat_idx_fini_by_dev_handle(dev_handle);
  721.         ipc_answer_0(rid, ENOMEM);
  722.         return;
  723.     }
  724.     fat_node_initialize(rootp);
  725.  
  726.     fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
  727.     if (!ridxp) {
  728.             munmap(dev_buffer, BS_SIZE);
  729.         free(rootp);
  730.         fat_idx_fini_by_dev_handle(dev_handle);
  731.         ipc_answer_0(rid, ENOMEM);
  732.         return;
  733.     }
  734.     assert(ridxp->index == 0);
  735.     /* ridxp->lock held */
  736.  
  737.     rootp->type = FAT_DIRECTORY;
  738.     rootp->firstc = FAT_CLST_ROOT;
  739.     rootp->refcnt = 1;
  740.     rootp->lnkcnt = 0;  /* FS root is not linked */
  741.     rootp->size = rde * sizeof(fat_dentry_t);
  742.     rootp->idx = ridxp;
  743.     ridxp->nodep = rootp;
  744.    
  745.     futex_up(&ridxp->lock);
  746.  
  747.     ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
  748. }
  749.  
  750. void fat_mount(ipc_callid_t rid, ipc_call_t *request)
  751. {
  752.     ipc_answer_0(rid, ENOTSUP);
  753. }
  754.  
  755. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  756. {
  757.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  758. }
  759.  
  760. void fat_read(ipc_callid_t rid, ipc_call_t *request)
  761. {
  762.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  763.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  764.     off_t pos = (off_t)IPC_GET_ARG3(*request);
  765.     fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
  766.     uint16_t bps = fat_bps_get(dev_handle);
  767.     size_t bytes;
  768.     block_t *b;
  769.  
  770.     if (!nodep) {
  771.         ipc_answer_0(rid, ENOENT);
  772.         return;
  773.     }
  774.  
  775.     ipc_callid_t callid;
  776.     size_t len;
  777.     if (!ipc_data_read_receive(&callid, &len)) {
  778.         fat_node_put(nodep);
  779.         ipc_answer_0(callid, EINVAL);
  780.         ipc_answer_0(rid, EINVAL);
  781.         return;
  782.     }
  783.  
  784.     if (nodep->type == FAT_FILE) {
  785.         /*
  786.          * Our strategy for regular file reads is to read one block at
  787.          * most and make use of the possibility to return less data than
  788.          * requested. This keeps the code very simple.
  789.          */
  790.         bytes = min(len, bps - pos % bps);
  791.         b = fat_block_get(nodep, pos / bps);
  792.         (void) ipc_data_read_finalize(callid, b->data + pos % bps,
  793.             bytes);
  794.         block_put(b);
  795.     } else {
  796.         unsigned bnum;
  797.         off_t spos = pos;
  798.         char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  799.         fat_dentry_t *d;
  800.  
  801.         assert(nodep->type == FAT_DIRECTORY);
  802.         assert(nodep->size % bps == 0);
  803.         assert(bps % sizeof(fat_dentry_t) == 0);
  804.  
  805.         /*
  806.          * Our strategy for readdir() is to use the position pointer as
  807.          * an index into the array of all dentries. On entry, it points
  808.          * to the first unread dentry. If we skip any dentries, we bump
  809.          * the position pointer accordingly.
  810.          */
  811.         bnum = (pos * sizeof(fat_dentry_t)) / bps;
  812.         while (bnum < nodep->size / bps) {
  813.             off_t o;
  814.  
  815.             b = fat_block_get(nodep, bnum);
  816.             for (o = pos % (bps / sizeof(fat_dentry_t));
  817.                 o < bps / sizeof(fat_dentry_t);
  818.                 o++, pos++) {
  819.                 d = ((fat_dentry_t *)b->data) + o;
  820.                 switch (fat_classify_dentry(d)) {
  821.                 case FAT_DENTRY_SKIP:
  822.                     continue;
  823.                 case FAT_DENTRY_LAST:
  824.                     block_put(b);
  825.                     goto miss;
  826.                 default:
  827.                 case FAT_DENTRY_VALID:
  828.                     dentry_name_canonify(d, name);
  829.                     block_put(b);
  830.                     goto hit;
  831.                 }
  832.             }
  833.             block_put(b);
  834.             bnum++;
  835.         }
  836. miss:
  837.         fat_node_put(nodep);
  838.         ipc_answer_0(callid, ENOENT);
  839.         ipc_answer_1(rid, ENOENT, 0);
  840.         return;
  841. hit:
  842.         (void) ipc_data_read_finalize(callid, name, strlen(name) + 1);
  843.         bytes = (pos - spos) + 1;
  844.     }
  845.  
  846.     fat_node_put(nodep);
  847.     ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
  848. }
  849.  
  850. /**
  851.  * @}
  852.  */
  853.