Subversion Repositories HelenOS

Rev

Rev 2910 | Rev 3009 | 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 <async.h>
  43. #include <errno.h>
  44. #include <string.h>
  45. #include <byteorder.h>
  46. #include <libadt/hash_table.h>
  47. #include <libadt/list.h>
  48. #include <assert.h>
  49. #include <futex.h>
  50.  
  51. #define BS_BLOCK        0
  52.  
  53. /** List of free FAT nodes that still contain valid data. */
  54. LIST_INITIALIZE(ffn_head);
  55.  
  56. #define FAT_NAME_LEN        8
  57. #define FAT_EXT_LEN     3
  58.  
  59. #define FAT_PAD         ' '
  60.  
  61. #define FAT_DENTRY_UNUSED   0x00
  62. #define FAT_DENTRY_E5_ESC   0x05
  63. #define FAT_DENTRY_DOT      0x2e
  64. #define FAT_DENTRY_ERASED   0xe5
  65.  
  66. static void dentry_name_canonify(fat_dentry_t *d, char *buf)
  67. {
  68.     int i;
  69.  
  70.     for (i = 0; i < FAT_NAME_LEN; i++) {
  71.         if (d->name[i] == FAT_PAD) {
  72.             buf++;
  73.             break;
  74.         }
  75.         if (d->name[i] == FAT_DENTRY_E5_ESC)
  76.             *buf++ = 0xe5;
  77.         else
  78.             *buf++ = d->name[i];
  79.     }
  80.     if (d->ext[0] != FAT_PAD)
  81.         *buf++ = '.';
  82.     for (i = 0; i < FAT_EXT_LEN; i++) {
  83.         if (d->ext[i] == FAT_PAD) {
  84.             *buf = '\0';
  85.             return;
  86.         }
  87.         if (d->ext[i] == FAT_DENTRY_E5_ESC)
  88.             *buf++ = 0xe5;
  89.         else
  90.             *buf++ = d->ext[i];
  91.     }
  92. }
  93.  
  94. /* TODO move somewhere else */
  95. typedef struct {
  96.     void *data;
  97. } block_t;
  98.  
  99. static block_t *block_get(dev_handle_t dev_handle, off_t offset)
  100. {
  101.     return NULL;    /* TODO */
  102. }
  103.  
  104. static void block_put(block_t *block)
  105. {
  106.     /* TODO */
  107. }
  108.  
  109. #define FAT_BS(b)       ((fat_bs_t *)((b)->data))
  110.  
  111. #define FAT_CLST_RES0   0x0000
  112. #define FAT_CLST_RES1   0x0001  /* internally used to mark root directory */
  113. #define FAT_CLST_FIRST  0x0002
  114. #define FAT_CLST_BAD    0xfff7
  115. #define FAT_CLST_LAST1  0xfff8
  116. #define FAT_CLST_LAST8  0xffff
  117.  
  118. #define fat_block_get(np, off) \
  119.     _fat_block_get((np)->idx->dev_handle, (np)->firstc, (off))
  120.  
  121. static block_t *
  122. _fat_block_get(dev_handle_t dev_handle, fat_cluster_t firstc, off_t offset)
  123. {
  124.     block_t *bb;
  125.     block_t *b;
  126.     unsigned bps;
  127.     unsigned spc;
  128.     unsigned rscnt;     /* block address of the first FAT */
  129.     unsigned fatcnt;
  130.     unsigned rde;
  131.     unsigned rds;       /* root directory size */
  132.     unsigned sf;
  133.     unsigned ssa;       /* size of the system area */
  134.     unsigned clusters;
  135.     fat_cluster_t clst = firstc;
  136.     unsigned i;
  137.  
  138.     bb = block_get(dev_handle, BS_BLOCK);
  139.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  140.     spc = FAT_BS(bb)->spc;
  141.     rscnt = uint16_t_le2host(FAT_BS(bb)->rscnt);
  142.     fatcnt = FAT_BS(bb)->fatcnt;
  143.     rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max);
  144.     sf = uint16_t_le2host(FAT_BS(bb)->sec_per_fat);
  145.     block_put(bb);
  146.  
  147.     rds = (sizeof(fat_dentry_t) * rde) / bps;
  148.     rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
  149.     ssa = rscnt + fatcnt * sf + rds;
  150.  
  151.     if (firstc == FAT_CLST_RES1) {
  152.         /* root directory special case */
  153.         assert(offset < rds);
  154.         b = block_get(dev_handle, rscnt + fatcnt * sf + offset);
  155.         return b;
  156.     }
  157.  
  158.     clusters = offset / spc;
  159.     for (i = 0; i < clusters; i++) {
  160.         unsigned fsec;  /* sector offset relative to FAT1 */
  161.         unsigned fidx;  /* FAT1 entry index */
  162.  
  163.         assert(clst >= FAT_CLST_FIRST && clst < FAT_CLST_BAD);
  164.         fsec = (clst * sizeof(fat_cluster_t)) / bps;
  165.         fidx = clst % (bps / sizeof(fat_cluster_t));
  166.         /* read FAT1 */
  167.         b = block_get(dev_handle, rscnt + fsec);
  168.         clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
  169.         assert(clst != FAT_CLST_BAD);
  170.         assert(clst < FAT_CLST_LAST1);
  171.         block_put(b);
  172.     }
  173.  
  174.     b = block_get(dev_handle, ssa + (clst - FAT_CLST_FIRST) * spc +
  175.         offset % spc);
  176.  
  177.     return b;
  178. }
  179.  
  180. static void fat_node_initialize(fat_node_t *node)
  181. {
  182.     node->idx = NULL;
  183.     node->type = 0;
  184.     link_initialize(&node->ffn_link);
  185.     node->size = 0;
  186.     node->lnkcnt = 0;
  187.     node->refcnt = 0;
  188.     node->dirty = false;
  189. }
  190.  
  191. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  192. {
  193.     block_t *bb;
  194.     uint16_t bps;
  195.    
  196.     bb = block_get(dev_handle, BS_BLOCK);
  197.     assert(bb != NULL);
  198.     bps = uint16_t_le2host(FAT_BS(bb)->bps);
  199.     block_put(bb);
  200.  
  201.     return bps;
  202. }
  203.  
  204. typedef enum {
  205.     FAT_DENTRY_SKIP,
  206.     FAT_DENTRY_LAST,
  207.     FAT_DENTRY_VALID
  208. } fat_dentry_clsf_t;
  209.  
  210. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  211. {
  212.     if (d->attr & FAT_ATTR_VOLLABEL) {
  213.         /* volume label entry */
  214.         return FAT_DENTRY_SKIP;
  215.     }
  216.     if (d->name[0] == FAT_DENTRY_ERASED) {
  217.         /* not-currently-used entry */
  218.         return FAT_DENTRY_SKIP;
  219.     }
  220.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  221.         /* never used entry */
  222.         return FAT_DENTRY_LAST;
  223.     }
  224.     if (d->name[0] == FAT_DENTRY_DOT) {
  225.         /*
  226.          * Most likely '.' or '..'.
  227.          * It cannot occur in a regular file name.
  228.          */
  229.         return FAT_DENTRY_SKIP;
  230.     }
  231.     return FAT_DENTRY_VALID;
  232. }
  233.  
  234. static void fat_node_sync(fat_node_t *node)
  235. {
  236.     /* TODO */
  237. }
  238.  
  239. /** Instantiate a FAT in-core node. */
  240. static void *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
  241. {
  242.     fat_idx_t *idx;
  243.     block_t *b;
  244.     fat_dentry_t *d;
  245.     fat_node_t *nodep;
  246.     unsigned bps;
  247.     unsigned dps;
  248.  
  249.     idx = fat_idx_get_by_index(dev_handle, index);
  250.     if (!idx)
  251.         return NULL;
  252.  
  253.     if (idx->nodep) {
  254.         /*
  255.          * We are lucky.
  256.          * The node is already instantiated in memory.
  257.          */
  258.         if (!idx->nodep->refcnt++)
  259.             list_remove(&nodep->ffn_link);
  260.         return idx->nodep;
  261.     }
  262.  
  263.     /*
  264.      * We must instantiate the node from the file system.
  265.      */
  266.    
  267.     assert(idx->pfc);
  268.  
  269.     if (!list_empty(&ffn_head)) {
  270.         /* Try to use a cached unused node structure. */
  271.         nodep = list_get_instance(ffn_head.next, fat_node_t, ffn_link);
  272.         if (nodep->dirty)
  273.             fat_node_sync(nodep);
  274.         list_remove(&nodep->ffn_link);
  275.         nodep->idx->nodep = NULL;
  276.     } else {
  277.         /* Try to allocate a new node structure. */
  278.         nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
  279.         if (!nodep)
  280.             return NULL;
  281.     }
  282.     fat_node_initialize(nodep);
  283.  
  284.     bps = fat_bps_get(dev_handle);
  285.     dps = bps / sizeof(fat_dentry_t);
  286.  
  287.     /* Read the block that contains the dentry of interest. */
  288.     b = _fat_block_get(dev_handle, idx->pfc,
  289.         (idx->pdi * sizeof(fat_dentry_t)) / bps);
  290.     assert(b);
  291.  
  292.     d = ((fat_dentry_t *)b->data) + (idx->pdi % dps);
  293.     if (d->attr & FAT_ATTR_SUBDIR) {
  294.         /*
  295.          * The only directory which does not have this bit set is the
  296.          * root directory itself. The root directory node is handled
  297.          * and initialized elsewhere.
  298.          */
  299.         nodep->type = FAT_DIRECTORY;
  300.     } else {
  301.         nodep->type = FAT_FILE;
  302.     }
  303.     nodep->firstc = uint16_t_le2host(d->firstc);
  304.     nodep->size = uint32_t_le2host(d->size);
  305.     nodep->lnkcnt = 1;
  306.     nodep->refcnt = 1;
  307.  
  308.     block_put(b);
  309.  
  310.     /* Link the idx structure with the node structure. */
  311.     nodep->idx = idx;
  312.     idx->nodep = nodep;
  313.  
  314.     return nodep;
  315. }
  316.  
  317. static void fat_node_put(void *node)
  318. {
  319.     fat_node_t *nodep = (fat_node_t *)node;
  320.  
  321.     if (!--nodep->refcnt) {
  322.         list_append(&nodep->ffn_link, &ffn_head);
  323.     }
  324. }
  325.  
  326. static void *fat_create(int flags)
  327. {
  328.     return NULL;    /* not supported at the moment */
  329. }
  330.  
  331. static int fat_destroy(void *node)
  332. {
  333.     return ENOTSUP; /* not supported at the moment */
  334. }
  335.  
  336. static bool fat_link(void *prnt, void *chld, const char *name)
  337. {
  338.     return false;   /* not supported at the moment */
  339. }
  340.  
  341. static int fat_unlink(void *prnt, void *chld)
  342. {
  343.     return ENOTSUP; /* not supported at the moment */
  344. }
  345.  
  346. static void *fat_match(void *prnt, const char *component)
  347. {
  348.     fat_node_t *parentp = (fat_node_t *)prnt;
  349.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  350.     unsigned i, j;
  351.     unsigned bps;       /* bytes per sector */
  352.     unsigned dps;       /* dentries per sector */
  353.     unsigned blocks;
  354.     fat_dentry_t *d;
  355.     block_t *b;
  356.  
  357.     bps = fat_bps_get(parentp->idx->dev_handle);
  358.     dps = bps / sizeof(fat_dentry_t);
  359.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  360.     for (i = 0; i < blocks; i++) {
  361.         unsigned dentries;
  362.        
  363.         b = fat_block_get(parentp, i);
  364.         dentries = (i == blocks - 1) ?
  365.             parentp->size % sizeof(fat_dentry_t) :
  366.             dps;
  367.         for (j = 0; j < dentries; j++) {
  368.             d = ((fat_dentry_t *)b->data) + j;
  369.             switch (fat_classify_dentry(d)) {
  370.             case FAT_DENTRY_SKIP:
  371.                 continue;
  372.             case FAT_DENTRY_LAST:
  373.                 block_put(b);
  374.                 return NULL;
  375.             default:
  376.             case FAT_DENTRY_VALID:
  377.                 dentry_name_canonify(d, name);
  378.                 break;
  379.             }
  380.             if (strcmp(name, component) == 0) {
  381.                 /* hit */
  382.                 fat_idx_t *idx = fat_idx_get_by_pos(
  383.                     parentp->idx->dev_handle, parentp->firstc,
  384.                     i * dps + j);
  385.                 if (!idx) {
  386.                     /*
  387.                      * Can happen if memory is low or if we
  388.                      * run out of 32-bit indices.
  389.                      */
  390.                     block_put(b);
  391.                     return NULL;
  392.                 }
  393.                 void *node = fat_node_get(idx->dev_handle,
  394.                     idx->index);
  395.                 block_put(b);
  396.                 return node;
  397.             }
  398.         }
  399.         block_put(b);
  400.     }
  401.  
  402.     return NULL;
  403. }
  404.  
  405. static fs_index_t fat_index_get(void *node)
  406. {
  407.     fat_node_t *fnodep = (fat_node_t *)node;
  408.     if (!fnodep)
  409.         return 0;
  410.     return fnodep->idx->index;
  411. }
  412.  
  413. static size_t fat_size_get(void *node)
  414. {
  415.     return ((fat_node_t *)node)->size;
  416. }
  417.  
  418. static unsigned fat_lnkcnt_get(void *node)
  419. {
  420.     return ((fat_node_t *)node)->lnkcnt;
  421. }
  422.  
  423. static bool fat_has_children(void *node)
  424. {
  425.     fat_node_t *nodep = (fat_node_t *)node;
  426.     unsigned bps;
  427.     unsigned dps;
  428.     unsigned blocks;
  429.     block_t *b;
  430.     unsigned i, j;
  431.  
  432.     if (nodep->type != FAT_DIRECTORY)
  433.         return false;
  434.  
  435.     bps = fat_bps_get(nodep->idx->dev_handle);
  436.     dps = bps / sizeof(fat_dentry_t);
  437.  
  438.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  439.  
  440.     for (i = 0; i < blocks; i++) {
  441.         unsigned dentries;
  442.         fat_dentry_t *d;
  443.    
  444.         b = fat_block_get(nodep, i);
  445.         dentries = (i == blocks - 1) ?
  446.             nodep->size % sizeof(fat_dentry_t) :
  447.             dps;
  448.         for (j = 0; j < dentries; j++) {
  449.             d = ((fat_dentry_t *)b->data) + j;
  450.             switch (fat_classify_dentry(d)) {
  451.             case FAT_DENTRY_SKIP:
  452.                 continue;
  453.             case FAT_DENTRY_LAST:
  454.                 block_put(b);
  455.                 return false;
  456.             default:
  457.             case FAT_DENTRY_VALID:
  458.                 block_put(b);
  459.                 return true;
  460.             }
  461.             block_put(b);
  462.             return true;
  463.         }
  464.         block_put(b);
  465.     }
  466.  
  467.     return false;
  468. }
  469.  
  470. static void *fat_root_get(dev_handle_t dev_handle)
  471. {
  472.     return NULL;    /* TODO */
  473. }
  474.  
  475. static char fat_plb_get_char(unsigned pos)
  476. {
  477.     return fat_reg.plb_ro[pos % PLB_SIZE];
  478. }
  479.  
  480. static bool fat_is_directory(void *node)
  481. {
  482.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  483. }
  484.  
  485. static bool fat_is_file(void *node)
  486. {
  487.     return ((fat_node_t *)node)->type == FAT_FILE;
  488. }
  489.  
  490. /** libfs operations */
  491. libfs_ops_t fat_libfs_ops = {
  492.     .match = fat_match,
  493.     .node_get = fat_node_get,
  494.     .node_put = fat_node_put,
  495.     .create = fat_create,
  496.     .destroy = fat_destroy,
  497.     .link = fat_link,
  498.     .unlink = fat_unlink,
  499.     .index_get = fat_index_get,
  500.     .size_get = fat_size_get,
  501.     .lnkcnt_get = fat_lnkcnt_get,
  502.     .has_children = fat_has_children,
  503.     .root_get = fat_root_get,
  504.     .plb_get_char = fat_plb_get_char,
  505.     .is_directory = fat_is_directory,
  506.     .is_file = fat_is_file
  507. };
  508.  
  509. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  510. {
  511.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  512. }
  513.  
  514. /**
  515.  * @}
  516.  */
  517.