Subversion Repositories HelenOS

Rev

Rev 3501 | Rev 3505 | 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. #include <align.h>
  54.  
  55. #define BS_BLOCK        0
  56. #define BS_SIZE         512
  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. #define FAT_NAME_LEN        8
  65. #define FAT_EXT_LEN     3
  66.  
  67. #define FAT_PAD         ' '
  68.  
  69. #define FAT_DENTRY_UNUSED   0x00
  70. #define FAT_DENTRY_E5_ESC   0x05
  71. #define FAT_DENTRY_DOT      0x2e
  72. #define FAT_DENTRY_ERASED   0xe5
  73.  
  74. #define min(a, b)       ((a) < (b) ? (a) : (b))
  75.  
  76. static void dentry_name_canonify(fat_dentry_t *d, char *buf)
  77. {
  78.     int i;
  79.  
  80.     for (i = 0; i < FAT_NAME_LEN; i++) {
  81.         if (d->name[i] == FAT_PAD)
  82.             break;
  83.         if (d->name[i] == FAT_DENTRY_E5_ESC)
  84.             *buf++ = 0xe5;
  85.         else
  86.             *buf++ = d->name[i];
  87.     }
  88.     if (d->ext[0] != FAT_PAD)
  89.         *buf++ = '.';
  90.     for (i = 0; i < FAT_EXT_LEN; i++) {
  91.         if (d->ext[i] == FAT_PAD) {
  92.             *buf = '\0';
  93.             return;
  94.         }
  95.         if (d->ext[i] == FAT_DENTRY_E5_ESC)
  96.             *buf++ = 0xe5;
  97.         else
  98.             *buf++ = d->ext[i];
  99.     }
  100.     *buf = '\0';
  101. }
  102.  
  103. static int dev_phone = -1;      /* FIXME */
  104. static void *dev_buffer = NULL;     /* FIXME */
  105.  
  106. /* TODO move somewhere else */
  107. typedef struct {
  108.     void *data;
  109.     size_t size;
  110.     bool dirty;
  111. } block_t;
  112.  
  113. static block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
  114. {
  115.     /* FIXME */
  116.     block_t *b;
  117.     off_t bufpos = 0;
  118.     size_t buflen = 0;
  119.     off_t pos = offset * bs;
  120.  
  121.     assert(dev_phone != -1);
  122.     assert(dev_buffer);
  123.  
  124.     b = malloc(sizeof(block_t));
  125.     if (!b)
  126.         return NULL;
  127.    
  128.     b->data = malloc(bs);
  129.     if (!b->data) {
  130.         free(b);
  131.         return NULL;
  132.     }
  133.     b->size = bs;
  134.  
  135.     if (!libfs_blockread(dev_phone, dev_buffer, &bufpos, &buflen, &pos,
  136.         b->data, bs, bs)) {
  137.         free(b->data);
  138.         free(b);
  139.         return NULL;
  140.     }
  141.  
  142.     return b;
  143. }
  144.  
  145. static void block_put(block_t *block)
  146. {
  147.     /* FIXME */
  148.     free(block->data);
  149.     free(block);
  150. }
  151.  
  152. #define FAT1        0
  153.  
  154. #define FAT_BS(b)       ((fat_bs_t *)((b)->data))
  155.  
  156. #define FAT_CLST_RES0   0x0000
  157. #define FAT_CLST_RES1   0x0001
  158. #define FAT_CLST_FIRST  0x0002
  159. #define FAT_CLST_BAD    0xfff7
  160. #define FAT_CLST_LAST1  0xfff8
  161. #define FAT_CLST_LAST8  0xffff
  162.  
  163. /* internally used to mark root directory's parent */
  164. #define FAT_CLST_ROOTPAR    FAT_CLST_RES0
  165. /* internally used to mark root directory */
  166. #define FAT_CLST_ROOT       FAT_CLST_RES1
  167.  
  168. #define fat_block_get(np, off) \
  169.     _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
  170.  
  171. static block_t *
  172. _fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset)
  173. {
  174.     block_t *bb;
  175.     block_t *b;
  176.     unsigned bps;
  177.     unsigned spc;
  178.     unsigned rscnt;     /* block address of the first FAT */
  179.     unsigned fatcnt;
  180.     unsigned rde;
  181.     unsigned rds;       /* root directory size */
  182.     unsigned sf;
  183.     unsigned ssa;       /* size of the system area */
  184.     unsigned clusters;
  185.     fat_cluster_t clst = firstc;
  186.     unsigned i;
  187.  
  188.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  189.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  190.     spc = FAT_BS(bb)->spc;
  191.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  192.     fatcnt = FAT_BS(bb)->fatcnt;
  193.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  194.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  195.     block_put(bb);
  196.  
  197.     rds = (sizeof(fat_dentry_t) * rde) / bps;
  198.     rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
  199.     ssa = rscnt + fatcnt * sf + rds;
  200.  
  201.     if (firstc == FAT_CLST_ROOT) {
  202.         /* root directory special case */
  203.         assert(offset < rds);
  204.         b = block_get(dev_handle, rscnt + fatcnt * sf + offset, bps);
  205.         return b;
  206.     }
  207.  
  208.     clusters = offset / spc;
  209.     for (i = 0; i < clusters; i++) {
  210.         unsigned fsec;  /* sector offset relative to FAT1 */
  211.         unsigned fidx;  /* FAT1 entry index */
  212.  
  213.         assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
  214.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  215.         fidx = clst % (bps / sizeof(fat_cluster_t));
  216.         /* read FAT1 */
  217.         b = block_get(dev_handle, rscnt + fsec, bps);
  218.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  219.         assert(clst != FAT_CLST_BAD);
  220.         assert(clst < FAT_CLST_LAST1);
  221.         block_put(b);
  222.     }
  223.  
  224.     b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
  225.         offset % spc, bps);
  226.  
  227.     return b;
  228. }
  229.  
  230. /** Return number of blocks allocated to a file.
  231.  *
  232.  * @param dev_handle    Device handle of the device with the file.
  233.  * @param firstc    First cluster of the file.
  234.  *
  235.  * @return      Number of blocks allocated to the file.
  236.  */
  237. static uint16_t
  238. _fat_blcks_get(dev_handle_t dev_handle, fat_cluster_t firstc)
  239. {
  240.     block_t *bb;
  241.     block_t *b;
  242.     unsigned bps;
  243.     unsigned spc;
  244.     unsigned rscnt;     /* block address of the first FAT */
  245.     unsigned clusters = 0;
  246.     fat_cluster_t clst = firstc;
  247.  
  248.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  249.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  250.     spc = FAT_BS(bb)->spc;
  251.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  252.     block_put(bb);
  253.  
  254.     if (firstc == FAT_CLST_RES0) {
  255.         /* No space allocated to the file. */
  256.         return 0;
  257.     }
  258.  
  259.     while (clst < FAT_CLST_LAST1) {
  260.         unsigned fsec;  /* sector offset relative to FAT1 */
  261.         unsigned fidx;  /* FAT1 entry index */
  262.  
  263.         assert(clst >= FAT_CLST_FIRST);
  264.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  265.         fidx = clst % (bps / sizeof(fat_cluster_t));
  266.         /* read FAT1 */
  267.         b = block_get(dev_handle, rscnt + fsec, bps);
  268.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  269.         assert(clst != FAT_CLST_BAD);
  270.         block_put(b);
  271.         clusters++;
  272.     }
  273.  
  274.     return clusters * spc;
  275. }
  276.  
  277. static void fat_node_initialize(fat_node_t *node)
  278. {
  279.     futex_initialize(&node->lock, 1);
  280.     node->idx = NULL;
  281.     node->type = 0;
  282.     link_initialize(&node->ffn_link);
  283.     node->size = 0;
  284.     node->lnkcnt = 0;
  285.     node->refcnt = 0;
  286.     node->dirty = false;
  287. }
  288.  
  289. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  290. {
  291.     block_t *bb;
  292.     uint16_t bps;
  293.    
  294.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  295.     assert(bb != NULL);
  296.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  297.     block_put(bb);
  298.  
  299.     return bps;
  300. }
  301.  
  302. typedef enum {
  303.     FAT_DENTRY_SKIP,
  304.     FAT_DENTRY_LAST,
  305.     FAT_DENTRY_VALID
  306. } fat_dentry_clsf_t;
  307.  
  308. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  309. {
  310.     if (d->attr & FAT_ATTR_VOLLABEL) {
  311.         /* volume label entry */
  312.         return FAT_DENTRY_SKIP;
  313.     }
  314.     if (d->name[0] == FAT_DENTRY_ERASED) {
  315.         /* not-currently-used entry */
  316.         return FAT_DENTRY_SKIP;
  317.     }
  318.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  319.         /* never used entry */
  320.         return FAT_DENTRY_LAST;
  321.     }
  322.     if (d->name[0] == FAT_DENTRY_DOT) {
  323.         /*
  324.          * Most likely '.' or '..'.
  325.          * It cannot occur in a regular file name.
  326.          */
  327.         return FAT_DENTRY_SKIP;
  328.     }
  329.     return FAT_DENTRY_VALID;
  330. }
  331.  
  332. static void fat_node_sync(fat_node_t *node)
  333. {
  334.     /* TODO */
  335. }
  336.  
  337. /** Internal version of fat_node_get().
  338.  *
  339.  * @param idxp      Locked index structure.
  340.  */
  341. static void *fat_node_get_core(fat_idx_t *idxp)
  342. {
  343.     block_t *b;
  344.     fat_dentry_t *d;
  345.     fat_node_t *nodep = NULL;
  346.     unsigned bps;
  347.     unsigned dps;
  348.  
  349.     if (idxp->nodep) {
  350.         /*
  351.          * We are lucky.
  352.          * The node is already instantiated in memory.
  353.          */
  354.         futex_down(&idxp->nodep->lock);
  355.         if (!idxp->nodep->refcnt++)
  356.             list_remove(&idxp->nodep->ffn_link);
  357.         futex_up(&idxp->nodep->lock);
  358.         return idxp->nodep;
  359.     }
  360.  
  361.     /*
  362.      * We must instantiate the node from the file system.
  363.      */
  364.    
  365.     assert(idxp->pfc);
  366.  
  367.     futex_down(&ffn_futex);
  368.     if (!list_empty(&ffn_head)) {
  369.         /* Try to use a cached free node structure. */
  370.         fat_idx_t *idxp_tmp;
  371.         nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
  372.         if (futex_trydown(&nodep->lock) == ESYNCH_WOULD_BLOCK)
  373.             goto skip_cache;
  374.         idxp_tmp = nodep->idx;
  375.         if (futex_trydown(&idxp_tmp->lock) == ESYNCH_WOULD_BLOCK) {
  376.             futex_up(&nodep->lock);
  377.             goto skip_cache;
  378.         }
  379.         list_remove(&nodep->ffn_link);
  380.         futex_up(&ffn_futex);
  381.         if (nodep->dirty)
  382.             fat_node_sync(nodep);
  383.         idxp_tmp->nodep = NULL;
  384.         futex_up(&nodep->lock);
  385.         futex_up(&idxp_tmp->lock);
  386.     } else {
  387. skip_cache:
  388.         /* Try to allocate a new node structure. */
  389.         futex_up(&ffn_futex);
  390.         nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
  391.         if (!nodep)
  392.             return NULL;
  393.     }
  394.     fat_node_initialize(nodep);
  395.  
  396.     bps = fat_bps_get(idxp->dev_handle);
  397.     dps = bps / sizeof(fat_dentry_t);
  398.  
  399.     /* Read the block that contains the dentry of interest. */
  400.     b = _fat_block_get(idxp->dev_handle, idxp->pfc,
  401.         (idxp->pdi * sizeof(fat_dentry_t)) / bps);
  402.     assert(b);
  403.  
  404.     d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
  405.     if (d->attr & FAT_ATTR_SUBDIR) {
  406.         /*
  407.          * The only directory which does not have this bit set is the
  408.          * root directory itself. The root directory node is handled
  409.          * and initialized elsewhere.
  410.          */
  411.         nodep->type = FAT_DIRECTORY;
  412.         /*
  413.          * Unfortunately, the 'size' field of the FAT dentry is not
  414.          * defined for the directory entry type. We must determine the
  415.          * size of the directory by walking the FAT.
  416.          */
  417.         nodep->size = bps * _fat_blcks_get(idxp->dev_handle,
  418.             uint16_t_le2host(d->firstc));
  419.     } else {
  420.         nodep->type = FAT_FILE;
  421.         nodep->size = uint32_t_le2host(d->size);
  422.     }
  423.     nodep->firstc = uint16_t_le2host(d->firstc);
  424.     nodep->lnkcnt = 1;
  425.     nodep->refcnt = 1;
  426.  
  427.     block_put(b);
  428.  
  429.     /* Link the idx structure with the node structure. */
  430.     nodep->idx = idxp;
  431.     idxp->nodep = nodep;
  432.  
  433.     return nodep;
  434. }
  435.  
  436. /** Instantiate a FAT in-core node. */
  437. static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  438. {
  439.     void *node;
  440.     fat_idx_t *idxp;
  441.  
  442.     idxp = fat_idx_get_by_index(dev_handle, index);
  443.     if (!idxp)
  444.         return NULL;
  445.     /* idxp->lock held */
  446.     node = fat_node_get_core(idxp);
  447.     futex_up(&idxp->lock);
  448.     return node;
  449. }
  450.  
  451. static void fat_node_put(void *node)
  452. {
  453.     fat_node_t *nodep = (fat_node_t *)node;
  454.  
  455.     futex_down(&nodep->lock);
  456.     if (!--nodep->refcnt) {
  457.         futex_down(&ffn_futex);
  458.         list_append(&nodep->ffn_link, &ffn_head);
  459.         futex_up(&ffn_futex);
  460.     }
  461.     futex_up(&nodep->lock);
  462. }
  463.  
  464. static void *fat_create(int flags)
  465. {
  466.     return NULL;    /* not supported at the moment */
  467. }
  468.  
  469. static int fat_destroy(void *node)
  470. {
  471.     return ENOTSUP; /* not supported at the moment */
  472. }
  473.  
  474. static bool fat_link(void *prnt, void *chld, const char *name)
  475. {
  476.     return false;   /* not supported at the moment */
  477. }
  478.  
  479. static int fat_unlink(void *prnt, void *chld)
  480. {
  481.     return ENOTSUP; /* not supported at the moment */
  482. }
  483.  
  484. static void *fat_match(void *prnt, const char *component)
  485. {
  486.     fat_node_t *parentp = (fat_node_t *)prnt;
  487.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  488.     unsigned i, j;
  489.     unsigned bps;       /* bytes per sector */
  490.     unsigned dps;       /* dentries per sector */
  491.     unsigned blocks;
  492.     fat_dentry_t *d;
  493.     block_t *b;
  494.  
  495.     futex_down(&parentp->idx->lock);
  496.     bps = fat_bps_get(parentp->idx->dev_handle);
  497.     dps = bps / sizeof(fat_dentry_t);
  498.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  499.     for (i = 0; i < blocks; i++) {
  500.         unsigned dentries;
  501.        
  502.         b = fat_block_get(parentp, i);
  503.         dentries = (i == blocks - 1) ?
  504.             parentp->size % sizeof(fat_dentry_t) :
  505.             dps;
  506.         for (j = 0; j < dentries; j++) {
  507.             d = ((fat_dentry_t *)b->data) + j;
  508.             switch (fat_classify_dentry(d)) {
  509.             case FAT_DENTRY_SKIP:
  510.                 continue;
  511.             case FAT_DENTRY_LAST:
  512.                 block_put(b);
  513.                 futex_up(&parentp->idx->lock);
  514.                 return NULL;
  515.             default:
  516.             case FAT_DENTRY_VALID:
  517.                 dentry_name_canonify(d, name);
  518.                 break;
  519.             }
  520.             if (stricmp(name, component) == 0) {
  521.                 /* hit */
  522.                 void *node;
  523.                 /*
  524.                  * Assume tree hierarchy for locking.  We
  525.                  * already have the parent and now we are going
  526.                  * to lock the child.  Never lock in the oposite
  527.                  * order.
  528.                  */
  529.                 fat_idx_t *idx = fat_idx_get_by_pos(
  530.                     parentp->idx->dev_handle, parentp->firstc,
  531.                     i * dps + j);
  532.                 futex_up(&parentp->idx->lock);
  533.                 if (!idx) {
  534.                     /*
  535.                      * Can happen if memory is low or if we
  536.                      * run out of 32-bit indices.
  537.                      */
  538.                     block_put(b);
  539.                     return NULL;
  540.                 }
  541.                 node = fat_node_get_core(idx);
  542.                 futex_up(&idx->lock);
  543.                 block_put(b);
  544.                 return node;
  545.             }
  546.         }
  547.         block_put(b);
  548.     }
  549.     futex_up(&parentp->idx->lock);
  550.     return NULL;
  551. }
  552.  
  553. static fs_index_t fat_index_get(void *node)
  554. {
  555.     fat_node_t *fnodep = (fat_node_t *)node;
  556.     if (!fnodep)
  557.         return 0;
  558.     return fnodep->idx->index;
  559. }
  560.  
  561. static size_t fat_size_get(void *node)
  562. {
  563.     return ((fat_node_t *)node)->size;
  564. }
  565.  
  566. static unsigned fat_lnkcnt_get(void *node)
  567. {
  568.     return ((fat_node_t *)node)->lnkcnt;
  569. }
  570.  
  571. static bool fat_has_children(void *node)
  572. {
  573.     fat_node_t *nodep = (fat_node_t *)node;
  574.     unsigned bps;
  575.     unsigned dps;
  576.     unsigned blocks;
  577.     block_t *b;
  578.     unsigned i, j;
  579.  
  580.     if (nodep->type != FAT_DIRECTORY)
  581.         return false;
  582.  
  583.     futex_down(&nodep->idx->lock);
  584.     bps = fat_bps_get(nodep->idx->dev_handle);
  585.     dps = bps / sizeof(fat_dentry_t);
  586.  
  587.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  588.  
  589.     for (i = 0; i < blocks; i++) {
  590.         unsigned dentries;
  591.         fat_dentry_t *d;
  592.    
  593.         b = fat_block_get(nodep, i);
  594.         dentries = (i == blocks - 1) ?
  595.             nodep->size % sizeof(fat_dentry_t) :
  596.             dps;
  597.         for (j = 0; j < dentries; j++) {
  598.             d = ((fat_dentry_t *)b->data) + j;
  599.             switch (fat_classify_dentry(d)) {
  600.             case FAT_DENTRY_SKIP:
  601.                 continue;
  602.             case FAT_DENTRY_LAST:
  603.                 block_put(b);
  604.                 futex_up(&nodep->idx->lock);
  605.                 return false;
  606.             default:
  607.             case FAT_DENTRY_VALID:
  608.                 block_put(b);
  609.                 futex_up(&nodep->idx->lock);
  610.                 return true;
  611.             }
  612.             block_put(b);
  613.             futex_up(&nodep->idx->lock);
  614.             return true;
  615.         }
  616.         block_put(b);
  617.     }
  618.  
  619.     futex_up(&nodep->idx->lock);
  620.     return false;
  621. }
  622.  
  623. static void *fat_root_get(dev_handle_t dev_handle)
  624. {
  625.     return fat_node_get(dev_handle, 0);
  626. }
  627.  
  628. static char fat_plb_get_char(unsigned pos)
  629. {
  630.     return fat_reg.plb_ro[pos % PLB_SIZE];
  631. }
  632.  
  633. static bool fat_is_directory(void *node)
  634. {
  635.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  636. }
  637.  
  638. static bool fat_is_file(void *node)
  639. {
  640.     return ((fat_node_t *)node)->type == FAT_FILE;
  641. }
  642.  
  643. /** libfs operations */
  644. libfs_ops_t fat_libfs_ops = {
  645.     .match = fat_match,
  646.     .node_get = fat_node_get,
  647.     .node_put = fat_node_put,
  648.     .create = fat_create,
  649.     .destroy = fat_destroy,
  650.     .link = fat_link,
  651.     .unlink = fat_unlink,
  652.     .index_get = fat_index_get,
  653.     .size_get = fat_size_get,
  654.     .lnkcnt_get = fat_lnkcnt_get,
  655.     .has_children = fat_has_children,
  656.     .root_get = fat_root_get,
  657.     .plb_get_char = fat_plb_get_char,
  658.     .is_directory = fat_is_directory,
  659.     .is_file = fat_is_file
  660. };
  661.  
  662. void fat_mounted(ipc_callid_t rid, ipc_call_t *request)
  663. {
  664.     dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
  665.     block_t *bb;
  666.     uint16_t bps;
  667.     uint16_t rde;
  668.     int rc;
  669.  
  670.     /*
  671.      * For now, we don't bother to remember dev_handle, dev_phone or
  672.      * dev_buffer in some data structure. We use global variables because we
  673.      * know there will be at most one mount on this file system.
  674.      * Of course, this is a huge TODO item.
  675.      */
  676.     dev_buffer = mmap(NULL, BS_SIZE, PROTO_READ | PROTO_WRITE,
  677.         MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
  678.    
  679.     if (!dev_buffer) {
  680.         ipc_answer_0(rid, ENOMEM);
  681.         return;
  682.     }
  683.  
  684.     dev_phone = ipc_connect_me_to(PHONE_NS, SERVICE_DEVMAP,
  685.         DEVMAP_CONNECT_TO_DEVICE, dev_handle);
  686.  
  687.     if (dev_phone < 0) {
  688.         munmap(dev_buffer, BS_SIZE);
  689.         ipc_answer_0(rid, dev_phone);
  690.         return;
  691.     }
  692.  
  693.     rc = ipc_share_out_start(dev_phone, dev_buffer,
  694.         AS_AREA_READ | AS_AREA_WRITE);
  695.     if (rc != EOK) {
  696.             munmap(dev_buffer, BS_SIZE);
  697.         ipc_answer_0(rid, rc);
  698.         return;
  699.     }
  700.  
  701.     /* Read the number of root directory entries. */
  702.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  703.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  704.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  705.     block_put(bb);
  706.  
  707.     if (bps != BS_SIZE) {
  708.         munmap(dev_buffer, BS_SIZE);
  709.         ipc_answer_0(rid, ENOTSUP);
  710.         return;
  711.     }
  712.  
  713.     rc = fat_idx_init_by_dev_handle(dev_handle);
  714.     if (rc != EOK) {
  715.             munmap(dev_buffer, BS_SIZE);
  716.         ipc_answer_0(rid, rc);
  717.         return;
  718.     }
  719.  
  720.     /* Initialize the root node. */
  721.     fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t));
  722.     if (!rootp) {
  723.             munmap(dev_buffer, BS_SIZE);
  724.         fat_idx_fini_by_dev_handle(dev_handle);
  725.         ipc_answer_0(rid, ENOMEM);
  726.         return;
  727.     }
  728.     fat_node_initialize(rootp);
  729.  
  730.     fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0);
  731.     if (!ridxp) {
  732.             munmap(dev_buffer, BS_SIZE);
  733.         free(rootp);
  734.         fat_idx_fini_by_dev_handle(dev_handle);
  735.         ipc_answer_0(rid, ENOMEM);
  736.         return;
  737.     }
  738.     assert(ridxp->index == 0);
  739.     /* ridxp->lock held */
  740.  
  741.     rootp->type = FAT_DIRECTORY;
  742.     rootp->firstc = FAT_CLST_ROOT;
  743.     rootp->refcnt = 1;
  744.     rootp->lnkcnt = 0;  /* FS root is not linked */
  745.     rootp->size = rde * sizeof(fat_dentry_t);
  746.     rootp->idx = ridxp;
  747.     ridxp->nodep = rootp;
  748.    
  749.     futex_up(&ridxp->lock);
  750.  
  751.     ipc_answer_3(rid, EOK, ridxp->index, rootp->size, rootp->lnkcnt);
  752. }
  753.  
  754. void fat_mount(ipc_callid_t rid, ipc_call_t *request)
  755. {
  756.     ipc_answer_0(rid, ENOTSUP);
  757. }
  758.  
  759. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  760. {
  761.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  762. }
  763.  
  764. void fat_read(ipc_callid_t rid, ipc_call_t *request)
  765. {
  766.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  767.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  768.     off_t pos = (off_t)IPC_GET_ARG3(*request);
  769.     fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
  770.     uint16_t bps = fat_bps_get(dev_handle);
  771.     size_t bytes;
  772.     block_t *b;
  773.  
  774.     if (!nodep) {
  775.         ipc_answer_0(rid, ENOENT);
  776.         return;
  777.     }
  778.  
  779.     ipc_callid_t callid;
  780.     size_t len;
  781.     if (!ipc_data_read_receive(&callid, &len)) {
  782.         fat_node_put(nodep);
  783.         ipc_answer_0(callid, EINVAL);
  784.         ipc_answer_0(rid, EINVAL);
  785.         return;
  786.     }
  787.  
  788.     if (nodep->type == FAT_FILE) {
  789.         /*
  790.          * Our strategy for regular file reads is to read one block at
  791.          * most and make use of the possibility to return less data than
  792.          * requested. This keeps the code very simple.
  793.          */
  794.         bytes = min(len, bps - pos % bps);
  795.         b = fat_block_get(nodep, pos / bps);
  796.         (void) ipc_data_read_finalize(callid, b->data + pos % bps,
  797.             bytes);
  798.         block_put(b);
  799.     } else {
  800.         unsigned bnum;
  801.         off_t spos = pos;
  802.         char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  803.         fat_dentry_t *d;
  804.  
  805.         assert(nodep->type == FAT_DIRECTORY);
  806.         assert(nodep->size % bps == 0);
  807.         assert(bps % sizeof(fat_dentry_t) == 0);
  808.  
  809.         /*
  810.          * Our strategy for readdir() is to use the position pointer as
  811.          * an index into the array of all dentries. On entry, it points
  812.          * to the first unread dentry. If we skip any dentries, we bump
  813.          * the position pointer accordingly.
  814.          */
  815.         bnum = (pos * sizeof(fat_dentry_t)) / bps;
  816.         while (bnum < nodep->size / bps) {
  817.             off_t o;
  818.  
  819.             b = fat_block_get(nodep, bnum);
  820.             for (o = pos % (bps / sizeof(fat_dentry_t));
  821.                 o < bps / sizeof(fat_dentry_t);
  822.                 o++, pos++) {
  823.                 d = ((fat_dentry_t *)b->data) + o;
  824.                 switch (fat_classify_dentry(d)) {
  825.                 case FAT_DENTRY_SKIP:
  826.                     continue;
  827.                 case FAT_DENTRY_LAST:
  828.                     block_put(b);
  829.                     goto miss;
  830.                 default:
  831.                 case FAT_DENTRY_VALID:
  832.                     dentry_name_canonify(d, name);
  833.                     block_put(b);
  834.                     goto hit;
  835.                 }
  836.             }
  837.             block_put(b);
  838.             bnum++;
  839.         }
  840. miss:
  841.         fat_node_put(nodep);
  842.         ipc_answer_0(callid, ENOENT);
  843.         ipc_answer_1(rid, ENOENT, 0);
  844.         return;
  845. hit:
  846.         (void) ipc_data_read_finalize(callid, name, strlen(name) + 1);
  847.         bytes = (pos - spos) + 1;
  848.     }
  849.  
  850.     fat_node_put(nodep);
  851.     ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
  852. }
  853.  
  854. /** Fill the gap between EOF and a new file position.
  855.  *
  856.  * @param nodep     FAT node with the gap.
  857.  * @param mcl       First cluster in an independent cluster chain that will
  858.  *          be later appended to the end of the node's own cluster
  859.  *          chain. If pos is still in the last allocated cluster,
  860.  *          this argument is ignored.
  861.  * @param pos       Position in the last node block.
  862.  */
  863. static void
  864. fat_fill_gap(fat_node_t *nodep, fat_cluster_t mcl, off_t pos)
  865. {
  866.     uint16_t bps;
  867.     unsigned spc;
  868.     block_t *bb, *b;
  869.     off_t o, boundary;
  870.  
  871.     bb = block_get(nodep->idx->dev_handle, BS_BLOCK, BS_SIZE);
  872.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  873.     spc = FAT_BS(bb)->spc;
  874.     block_put(bb);
  875.    
  876.     boundary = ROUND_UP(nodep->size, bps * spc);
  877.  
  878.     /* zero out already allocated space */
  879.     for (o = nodep->size - 1; o < pos && o < boundary;
  880.         o = ALIGN_DOWN(o + bps, bps)) {
  881.         b = fat_block_get(nodep, o / bps);
  882.         memset(b->data + o % bps, 0, bps - o % bps);
  883.         b->dirty = true;        /* need to sync node */
  884.         block_put(b);
  885.     }
  886.    
  887.     if (o >= pos)
  888.         return;
  889.    
  890.     /* zero out the initial part of the new cluster chain */
  891.     for (o = boundary; o < pos; o += bps) {
  892.         b = _fat_block_get(nodep->idx->dev_handle, mcl,
  893.             (o - boundary) / bps);
  894.         memset(b->data, 0, min(bps, pos - o));
  895.         b->dirty = true;        /* need to sync node */
  896.         block_put(b);
  897.     }
  898. }
  899.  
  900. static void
  901. fat_mark_cluster(dev_handle_t dev_handle, unsigned fatno, fat_cluster_t clst,
  902.     fat_cluster_t value)
  903. {
  904.     /* TODO */
  905. }
  906.  
  907. static void
  908. fat_alloc_shadow_clusters(dev_handle_t dev_handle, fat_cluster_t *lifo,
  909.     unsigned nclsts)
  910. {
  911.     /* TODO */
  912. }
  913.  
  914. static int
  915. fat_alloc_clusters(dev_handle_t dev_handle, unsigned nclsts, fat_cluster_t *mcl,
  916.     fat_cluster_t *lcl)
  917. {
  918.     uint16_t bps;
  919.     uint16_t rscnt;
  920.     uint16_t sf;
  921.     block_t *bb, *blk;
  922.     fat_cluster_t *lifo;    /* stack for storing free cluster numbers */
  923.     unsigned found = 0; /* top of the free cluster number stack */
  924.     unsigned b, c, cl;
  925.  
  926.     lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
  927.     if (lifo)
  928.         return ENOMEM;
  929.    
  930.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  931.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  932.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  933.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  934.     block_put(bb);
  935.    
  936.     /*
  937.      * Search FAT1 for unused clusters.
  938.      */
  939.     for (b = 0, cl = 0; b < sf; blk++) {
  940.         blk = block_get(dev_handle, rscnt + b, bps);
  941.         for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
  942.             fat_cluster_t *clst = (fat_cluster_t *)blk->data + c;
  943.             if (*clst == FAT_CLST_RES0) {
  944.                 /*
  945.                  * The cluster is free. Put it into our stack
  946.                  * of found clusters and mark it as non-free.
  947.                  */
  948.                 lifo[found] = cl;
  949.                 if (found == 0)
  950.                     *clst = FAT_CLST_LAST1;
  951.                 else
  952.                     *clst = lifo[found - 1];
  953.                 blk->dirty = true;  /* need to sync block */
  954.                 if (++found == nclsts) {
  955.                     /* we are almost done */
  956.                     block_put(blk);
  957.                     /* update the shadow copies of FAT */
  958.                     fat_alloc_shadow_clusters(dev_handle,
  959.                         lifo, nclsts);
  960.                     *mcl = lifo[found - 1];
  961.                     *lcl = lifo[0];
  962.                     free(lifo);
  963.                     return EOK;
  964.                 }
  965.             }
  966.         }
  967.         block_put(blk);
  968.     }
  969.  
  970.     /*
  971.      * We could not find enough clusters. Now we need to free the clusters
  972.      * we have allocated so far.
  973.      */
  974.     while (found--)
  975.         fat_mark_cluster(dev_handle, FAT1, lifo[found], FAT_CLST_RES0);
  976.    
  977.     free(lifo);
  978.     return ENOSPC;
  979. }
  980.  
  981. static void
  982. fat_append_clusters(fat_node_t *nodep, fat_cluster_t mcl)
  983. {
  984. }
  985.  
  986. void fat_write(ipc_callid_t rid, ipc_call_t *request)
  987. {
  988.     dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
  989.     fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
  990.     off_t pos = (off_t)IPC_GET_ARG3(*request);
  991.     fat_node_t *nodep = (fat_node_t *)fat_node_get(dev_handle, index);
  992.     size_t bytes;
  993.     block_t *b, *bb;
  994.     uint16_t bps;
  995.     unsigned spc;
  996.     off_t boundary;
  997.    
  998.     if (!nodep) {
  999.         ipc_answer_0(rid, ENOENT);
  1000.         return;
  1001.     }
  1002.    
  1003.     /* XXX remove me when you are ready */
  1004.     {
  1005.         ipc_answer_0(rid, ENOTSUP);
  1006.         fat_node_put(nodep);
  1007.         return;
  1008.     }
  1009.  
  1010.     ipc_callid_t callid;
  1011.     size_t len;
  1012.     if (!ipc_data_write_receive(&callid, &len)) {
  1013.         fat_node_put(nodep);
  1014.         ipc_answer_0(callid, EINVAL);
  1015.         ipc_answer_0(rid, EINVAL);
  1016.         return;
  1017.     }
  1018.  
  1019.     /*
  1020.      * In all scenarios, we will attempt to write out only one block worth
  1021.      * of data at maximum. There might be some more efficient approaches,
  1022.      * but this one greatly simplifies fat_write(). Note that we can afford
  1023.      * to do this because the client must be ready to handle the return
  1024.      * value signalizing a smaller number of bytes written.
  1025.      */
  1026.     bytes = min(len, bps - pos % bps);
  1027.  
  1028.     bb = block_get(dev_handle, BS_BLOCK, BS_SIZE);
  1029.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  1030.     spc = FAT_BS(bb)->spc;
  1031.     block_put(bb);
  1032.    
  1033.     boundary = ROUND_UP(nodep->size, bps * spc);
  1034.     if (pos < boundary) {
  1035.         /*
  1036.          * This is the easier case - we are either overwriting already
  1037.          * existing contents or writing behind the EOF, but still within
  1038.          * the limits of the last cluster. The node size may grow to the
  1039.          * next block size boundary.
  1040.          */
  1041.         fat_fill_gap(nodep, FAT_CLST_RES0, pos);
  1042.         b = fat_block_get(nodep, pos / bps);
  1043.         (void) ipc_data_write_finalize(callid, b->data + pos % bps,
  1044.             bytes);
  1045.         b->dirty = true;        /* need to sync block */
  1046.         block_put(b);
  1047.         if (pos + bytes > nodep->size) {
  1048.             nodep->size = pos + bytes;
  1049.             nodep->dirty = true;    /* need to sync node */
  1050.         }
  1051.         fat_node_put(nodep);
  1052.         ipc_answer_1(rid, EOK, bytes); 
  1053.         return;
  1054.     } else {
  1055.         /*
  1056.          * This is the more difficult case. We must allocate new
  1057.          * clusters for the node and zero them out.
  1058.          */
  1059.         int status;
  1060.         unsigned nclsts;
  1061.         fat_cluster_t mcl, lcl;
  1062.    
  1063.         nclsts = (ROUND_UP(pos + bytes, bps * spc) - boundary) /
  1064.             bps * spc;
  1065.         /* create an independent chain of nclsts clusters in all FATs */
  1066.         status = fat_alloc_clusters(dev_handle, nclsts, &mcl, &lcl);
  1067.         if (status != EOK) {
  1068.             /* could not allocate a chain of nclsts clusters */
  1069.             fat_node_put(nodep);
  1070.             ipc_answer_0(callid, status);
  1071.             ipc_answer_0(rid, status);
  1072.             return;
  1073.         }
  1074.         /* zero fill any gaps */
  1075.         fat_fill_gap(nodep, mcl, pos);
  1076.         b = _fat_block_get(dev_handle, lcl, (pos / bps) % spc);
  1077.         (void) ipc_data_write_finalize(callid, b->data + pos % bps,
  1078.             bytes);
  1079.         b->dirty = true;        /* need to sync block */
  1080.         block_put(b);
  1081.         /*
  1082.          * Append the cluster chain starting in mcl to the end of the
  1083.          * node's cluster chain.
  1084.          */
  1085.         fat_append_clusters(nodep, mcl);
  1086.         nodep->size = pos + bytes;
  1087.         nodep->dirty = true;        /* need to sync node */
  1088.         fat_node_put(nodep);
  1089.         ipc_answer_1(rid, EOK, bytes);
  1090.         return;
  1091.     }
  1092. }
  1093.  
  1094. /**
  1095.  * @}
  1096.  */
  1097.