Subversion Repositories HelenOS

Rev

Rev 2845 | Rev 2855 | 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.  
  50. #define BS_BLOCK        0
  51.  
  52. #define FIN_KEY_DEV_HANDLE  0
  53. #define FIN_KEY_INDEX       1
  54.  
  55. /** Hash table of FAT in-core nodes. */
  56. hash_table_t fin_hash;
  57.  
  58. /** List of free FAT in-core nodes. */
  59. link_t ffn_head;
  60.  
  61. #define FAT_NAME_LEN        8
  62. #define FAT_EXT_LEN     3
  63.  
  64. #define FAT_PAD         ' '
  65.  
  66. #define FAT_DENTRY_UNUSED   0x00
  67. #define FAT_DENTRY_E5_ESC   0x05
  68. #define FAT_DENTRY_DOT      0x2e
  69. #define FAT_DENTRY_ERASED   0xe5
  70.  
  71. static void dentry_name_canonify(fat_dentry_t *d, char *buf)
  72. {
  73.     int i;
  74.  
  75.     for (i = 0; i < FAT_NAME_LEN; i++) {
  76.         if (d->name[i] == FAT_PAD) {
  77.             buf++;
  78.             break;
  79.         }
  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. }
  98.  
  99. /* TODO and also move somewhere else */
  100. typedef struct {
  101.     void *data;
  102. } block_t;
  103.  
  104. static block_t *block_get(dev_handle_t dev_handle, off_t offset)
  105. {
  106.     return NULL;    /* TODO */
  107. }
  108.  
  109. static block_t *fat_block_get(dev_handle_t dev_handle, fs_index_t index,
  110.     off_t offset) {
  111.     return NULL;    /* TODO */
  112. }
  113.  
  114. static void block_put(block_t *block)
  115. {
  116.     /* TODO */
  117. }
  118.  
  119. static void fat_node_initialize(fat_node_t *node)
  120. {
  121.     node->type = 0;
  122.     node->index = 0;
  123.     node->pindex = 0;
  124.     node->dev_handle = 0;
  125.     link_initialize(&node->fin_link);
  126.     link_initialize(&node->ffn_link);
  127.     node->size = 0;
  128.     node->lnkcnt = 0;
  129.     node->refcnt = 0;
  130.     node->dirty = false;
  131. }
  132.  
  133. static uint16_t fat_bps_get(dev_handle_t dev_handle)
  134. {
  135.     block_t *bb;
  136.     uint16_t bps;
  137.    
  138.     bb = block_get(dev_handle, BS_BLOCK);
  139.     assert(bb != NULL);
  140.     bps = uint16_t_le2host(((fat_bs_t *)bb->data)->bps);
  141.     block_put(bb);
  142.  
  143.     return bps;
  144. }
  145.  
  146. typedef enum {
  147.     FAT_DENTRY_SKIP,
  148.     FAT_DENTRY_LAST,
  149.     FAT_DENTRY_VALID
  150. } fat_dentry_clsf_t;
  151.  
  152. static fat_dentry_clsf_t fat_classify_dentry(fat_dentry_t *d)
  153. {
  154.     if (d->attr & FAT_ATTR_VOLLABEL) {
  155.         /* volume label entry */
  156.         return FAT_DENTRY_SKIP;
  157.     }
  158.     if (d->name[0] == FAT_DENTRY_ERASED) {
  159.         /* not-currently-used entry */
  160.         return FAT_DENTRY_SKIP;
  161.     }
  162.     if (d->name[0] == FAT_DENTRY_UNUSED) {
  163.         /* never used entry */
  164.         return FAT_DENTRY_LAST;
  165.     }
  166.     if (d->name[0] == FAT_DENTRY_DOT) {
  167.         /*
  168.          * Most likely '.' or '..'.
  169.          * It cannot occur in a regular file name.
  170.          */
  171.         return FAT_DENTRY_SKIP;
  172.     }
  173.     return FAT_DENTRY_VALID;
  174. }
  175.  
  176. static void fat_sync_node(fat_node_t *node)
  177. {
  178.     /* TODO */
  179. }
  180.  
  181. /** Instantiate a FAT in-core node.
  182.  *
  183.  * FAT stores the info necessary for instantiation of a node in the parent of
  184.  * that node.  This design necessitated the addition of the parent node index
  185.  * parameter to this otherwise generic libfs API.
  186.  */
  187. static void *
  188. fat_node_get(dev_handle_t dev_handle, fs_index_t index, fs_index_t pindex)
  189. {
  190.     link_t *lnk;
  191.     fat_node_t *node = NULL;
  192.     block_t *b;
  193.     unsigned bps;
  194.     unsigned dps;
  195.     fat_dentry_t *d;
  196.     unsigned i, j;
  197.  
  198.     unsigned long key[] = {
  199.         [FIN_KEY_DEV_HANDLE] = dev_handle,
  200.         [FIN_KEY_INDEX] = index
  201.     };
  202.  
  203.     lnk = hash_table_find(&fin_hash, key);
  204.     if (lnk) {
  205.         /*
  206.          * The in-core node was found in the hash table.
  207.          */
  208.         node = hash_table_get_instance(lnk, fat_node_t, fin_link);
  209.         if (!node->refcnt++)
  210.             list_remove(&node->ffn_link);
  211.         return (void *) node;  
  212.     }
  213.  
  214.     bps = fat_bps_get(dev_handle);
  215.     dps = bps / sizeof(fat_dentry_t);
  216.    
  217.     if (!list_empty(&ffn_head)) {
  218.         /*
  219.          * We are going to reuse a node from the free list.
  220.          */
  221.         lnk = ffn_head.next;
  222.         list_remove(lnk);
  223.         node = list_get_instance(lnk, fat_node_t, ffn_link);
  224.         assert(!node->refcnt);
  225.         if (node->dirty)
  226.             fat_sync_node(node);
  227.         key[FIN_KEY_DEV_HANDLE] = node->dev_handle;
  228.         key[FIN_KEY_INDEX] = node->index;
  229.         hash_table_remove(&fin_hash, key, sizeof(key)/sizeof(*key));
  230.     } else {
  231.         /*
  232.          * We need to allocate a new node.
  233.          */
  234.         node = malloc(sizeof(fat_node_t));
  235.         if (!node)
  236.             return NULL;
  237.     }
  238.     fat_node_initialize(node);
  239.     node->refcnt++;
  240.     node->lnkcnt++;
  241.     node->dev_handle = dev_handle;
  242.     node->index = index;
  243.     node->pindex = pindex;
  244.  
  245.     /*
  246.      * Because of the design of the FAT file system, we have no clue about
  247.      * how big (i.e. how many directory entries it contains) is the parent
  248.      * of the node we are trying to instantiate.  However, we know that it
  249.      * must contain a directory entry for our node of interest.  We simply
  250.      * scan the parent until we find it.
  251.      */
  252.     for (i = 0; ; i++) {
  253.         b = fat_block_get(node->dev_handle, node->pindex, i);
  254.         for (j = 0; j < dps; j++) {
  255.             d = ((fat_dentry_t *)b->data) + j;
  256.             if (d->firstc == node->index)
  257.                 goto found;
  258.         }
  259.         block_put(b);
  260.     }
  261.    
  262. found:
  263.     if (!(d->attr & (FAT_ATTR_SUBDIR | FAT_ATTR_VOLLABEL)))
  264.         node->type = FAT_FILE;
  265.     if ((d->attr & FAT_ATTR_SUBDIR) || !index)
  266.         node->type = FAT_DIRECTORY;
  267.     assert((node->type == FAT_FILE) || (node->type == FAT_DIRECTORY));
  268.    
  269.     node->size = uint32_t_le2host(d->size);
  270.     block_put(b);
  271.    
  272.     key[FIN_KEY_DEV_HANDLE] = node->dev_handle;
  273.     key[FIN_KEY_INDEX] = node->index;
  274.     hash_table_insert(&fin_hash, key, &node->fin_link);
  275.  
  276.     return node;
  277. }
  278.  
  279. static void fat_node_put(void *node)
  280. {
  281.     /* TODO */
  282. }
  283.  
  284. static void *fat_match(void *prnt, const char *component)
  285. {
  286.     fat_node_t *parentp = (fat_node_t *)prnt;
  287.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  288.     unsigned i, j;
  289.     unsigned bps;       /* bytes per sector */
  290.     unsigned dps;       /* dentries per sector */
  291.     unsigned blocks;
  292.     fat_dentry_t *d;
  293.     block_t *b;
  294.  
  295.     bps = fat_bps_get(parentp->dev_handle);
  296.     dps = bps / sizeof(fat_dentry_t);
  297.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  298.     for (i = 0; i < blocks; i++) {
  299.         unsigned dentries;
  300.        
  301.         b = fat_block_get(parentp->dev_handle, parentp->index, i);
  302.         dentries = (i == blocks - 1) ?
  303.             parentp->size % sizeof(fat_dentry_t) :
  304.             dps;
  305.         for (j = 0; j < dentries; j++) {
  306.             d = ((fat_dentry_t *)b->data) + j;
  307.             switch (fat_classify_dentry(d)) {
  308.             case FAT_DENTRY_SKIP:
  309.                 continue;
  310.             case FAT_DENTRY_LAST:
  311.                 block_put(b);
  312.                 return NULL;
  313.             default:
  314.             case FAT_DENTRY_VALID:
  315.                 dentry_name_canonify(d, name);
  316.                 break;
  317.             }
  318.             if (strcmp(name, component) == 0) {
  319.                 /* hit */
  320.                 void *node = fat_node_get(parentp->dev_handle,
  321.                     (fs_index_t)uint16_t_le2host(d->firstc),
  322.                     parentp->index);
  323.                 block_put(b);
  324.                 return node;
  325.             }
  326.         }
  327.         block_put(b);
  328.     }
  329.  
  330.     return NULL;
  331. }
  332.  
  333. static fs_index_t fat_index_get(void *node)
  334. {
  335.     fat_node_t *fnodep = (fat_node_t *)node;
  336.     if (!fnodep)
  337.         return 0;
  338.     return fnodep->index;
  339. }
  340.  
  341. static size_t fat_size_get(void *node)
  342. {
  343.     return ((fat_node_t *)node)->size;
  344. }
  345.  
  346. static unsigned fat_lnkcnt_get(void *node)
  347. {
  348.     return ((fat_node_t *)node)->lnkcnt;
  349. }
  350.  
  351. static bool fat_has_children(void *node)
  352. {
  353.     fat_node_t *nodep = (fat_node_t *)node;
  354.     unsigned bps;
  355.     unsigned dps;
  356.     unsigned blocks;
  357.     block_t *b;
  358.     unsigned i, j;
  359.  
  360.     if (nodep->type != FAT_DIRECTORY)
  361.         return false;
  362.  
  363.     bps = fat_bps_get(nodep->dev_handle);
  364.     dps = bps / sizeof(fat_dentry_t);
  365.  
  366.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  367.  
  368.     for (i = 0; i < blocks; i++) {
  369.         unsigned dentries;
  370.         fat_dentry_t *d;
  371.    
  372.         b = fat_block_get(nodep->dev_handle, nodep->index, i);
  373.         dentries = (i == blocks - 1) ?
  374.             nodep->size % sizeof(fat_dentry_t) :
  375.             dps;
  376.         for (j = 0; j < dentries; j++) {
  377.             d = ((fat_dentry_t *)b->data) + j;
  378.             switch (fat_classify_dentry(d)) {
  379.             case FAT_DENTRY_SKIP:
  380.                 continue;
  381.             case FAT_DENTRY_LAST:
  382.                 block_put(b);
  383.                 return false;
  384.             default:
  385.             case FAT_DENTRY_VALID:
  386.                 block_put(b);
  387.                 return true;
  388.             }
  389.             block_put(b);
  390.             return true;
  391.         }
  392.         block_put(b);
  393.     }
  394.  
  395.     return false;
  396. }
  397.  
  398. static void *fat_root_get(dev_handle_t dev_handle)
  399. {
  400.     return fat_node_get(dev_handle, 0, 0); 
  401. }
  402.  
  403. static char fat_plb_get_char(unsigned pos)
  404. {
  405.     return fat_reg.plb_ro[pos % PLB_SIZE];
  406. }
  407.  
  408. static bool fat_is_directory(void *node)
  409. {
  410.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  411. }
  412.  
  413. static bool fat_is_file(void *node)
  414. {
  415.     return ((fat_node_t *)node)->type == FAT_FILE;
  416. }
  417.  
  418. /** libfs operations */
  419. libfs_ops_t fat_libfs_ops = {
  420.     .match = fat_match,
  421.     .node_get = fat_node_get,
  422.     .node_put = fat_node_put,
  423.     .create = NULL,
  424.     .destroy = NULL,
  425.     .link = NULL,
  426.     .unlink = NULL,
  427.     .index_get = fat_index_get,
  428.     .size_get = fat_size_get,
  429.     .lnkcnt_get = fat_lnkcnt_get,
  430.     .has_children = fat_has_children,
  431.     .root_get = fat_root_get,
  432.     .plb_get_char = fat_plb_get_char,
  433.     .is_directory = fat_is_directory,
  434.     .is_file = fat_is_file
  435. };
  436.  
  437. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  438. {
  439.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  440. }
  441.  
  442. /**
  443.  * @}
  444.  */
  445.