Subversion Repositories HelenOS

Rev

Rev 2844 | Rev 2852 | 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_match(void *prnt, const char *component)
  280. {
  281.     fat_node_t *parentp = (fat_node_t *)prnt;
  282.     char name[FAT_NAME_LEN + 1 + FAT_EXT_LEN + 1];
  283.     unsigned i, j;
  284.     unsigned bps;       /* bytes per sector */
  285.     unsigned dps;       /* dentries per sector */
  286.     unsigned blocks;
  287.     fat_dentry_t *d;
  288.     block_t *b;
  289.  
  290.     bps = fat_bps_get(parentp->dev_handle);
  291.     dps = bps / sizeof(fat_dentry_t);
  292.     blocks = parentp->size / bps + (parentp->size % bps != 0);
  293.     for (i = 0; i < blocks; i++) {
  294.         unsigned dentries;
  295.        
  296.         b = fat_block_get(parentp->dev_handle, parentp->index, i);
  297.         dentries = (i == blocks - 1) ?
  298.             parentp->size % sizeof(fat_dentry_t) :
  299.             dps;
  300.         for (j = 0; j < dentries; j++) {
  301.             d = ((fat_dentry_t *)b->data) + j;
  302.             switch (fat_classify_dentry(d)) {
  303.             case FAT_DENTRY_SKIP:
  304.                 continue;
  305.             case FAT_DENTRY_LAST:
  306.                 block_put(b);
  307.                 return NULL;
  308.             default:
  309.             case FAT_DENTRY_VALID:
  310.                 dentry_name_canonify(d, name);
  311.                 break;
  312.             }
  313.             if (strcmp(name, component) == 0) {
  314.                 /* hit */
  315.                 void *node = fat_node_get(parentp->dev_handle,
  316.                     (fs_index_t)uint16_t_le2host(d->firstc),
  317.                     parentp->index);
  318.                 block_put(b);
  319.                 return node;
  320.             }
  321.         }
  322.         block_put(b);
  323.     }
  324.  
  325.     return NULL;
  326. }
  327.  
  328. static fs_index_t fat_index_get(void *node)
  329. {
  330.     fat_node_t *fnodep = (fat_node_t *)node;
  331.     if (!fnodep)
  332.         return 0;
  333.     return fnodep->index;
  334. }
  335.  
  336. static size_t fat_size_get(void *node)
  337. {
  338.     return ((fat_node_t *)node)->size;
  339. }
  340.  
  341. static unsigned fat_lnkcnt_get(void *node)
  342. {
  343.     return ((fat_node_t *)node)->lnkcnt;
  344. }
  345.  
  346. static bool fat_has_children(void *node)
  347. {
  348.     fat_node_t *nodep = (fat_node_t *)node;
  349.     unsigned bps;
  350.     unsigned dps;
  351.     unsigned blocks;
  352.     block_t *b;
  353.     unsigned i, j;
  354.  
  355.     if (nodep->type != FAT_DIRECTORY)
  356.         return false;
  357.  
  358.     bps = fat_bps_get(nodep->dev_handle);
  359.     dps = bps / sizeof(fat_dentry_t);
  360.  
  361.     blocks = nodep->size / bps + (nodep->size % bps != 0);
  362.  
  363.     for (i = 0; i < blocks; i++) {
  364.         unsigned dentries;
  365.         fat_dentry_t *d;
  366.    
  367.         b = fat_block_get(nodep->dev_handle, nodep->index, i);
  368.         dentries = (i == blocks - 1) ?
  369.             nodep->size % sizeof(fat_dentry_t) :
  370.             dps;
  371.         for (j = 0; j < dentries; j++) {
  372.             d = ((fat_dentry_t *)b->data) + j;
  373.             switch (fat_classify_dentry(d)) {
  374.             case FAT_DENTRY_SKIP:
  375.                 continue;
  376.             case FAT_DENTRY_LAST:
  377.                 block_put(b);
  378.                 return false;
  379.             default:
  380.             case FAT_DENTRY_VALID:
  381.                 block_put(b);
  382.                 return true;
  383.             }
  384.             block_put(b);
  385.             return true;
  386.         }
  387.         block_put(b);
  388.     }
  389.  
  390.     return false;
  391. }
  392.  
  393. static void *fat_root_get(dev_handle_t dev_handle)
  394. {
  395.     return fat_node_get(dev_handle, 0, 0); 
  396. }
  397.  
  398. static char fat_plb_get_char(unsigned pos)
  399. {
  400.     return fat_reg.plb_ro[pos % PLB_SIZE];
  401. }
  402.  
  403. static bool fat_is_directory(void *node)
  404. {
  405.     return ((fat_node_t *)node)->type == FAT_DIRECTORY;
  406. }
  407.  
  408. static bool fat_is_file(void *node)
  409. {
  410.     return ((fat_node_t *)node)->type == FAT_FILE;
  411. }
  412.  
  413. /** libfs operations */
  414. libfs_ops_t fat_libfs_ops = {
  415.     .match = fat_match,
  416.     .node_get = fat_node_get,
  417.     .create = NULL,
  418.     .destroy = NULL,
  419.     .link = NULL,
  420.     .unlink = NULL,
  421.     .index_get = fat_index_get,
  422.     .size_get = fat_size_get,
  423.     .lnkcnt_get = fat_lnkcnt_get,
  424.     .has_children = fat_has_children,
  425.     .root_get = fat_root_get,
  426.     .plb_get_char = fat_plb_get_char,
  427.     .is_directory = fat_is_directory,
  428.     .is_file = fat_is_file
  429. };
  430.  
  431. void fat_lookup(ipc_callid_t rid, ipc_call_t *request)
  432. {
  433.     libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request);
  434. }
  435.  
  436. /**
  437.  * @}
  438.  */
  439.